fix(other): allow avatar updates for country-locked users

This commit is contained in:
ZuoZuo 2026-07-15 00:21:31 +08:00
parent 1f2f8b0f6d
commit 2a6599cd5a
2 changed files with 110 additions and 7 deletions

View File

@ -134,25 +134,27 @@ public class UpdateUserProfileCmdExe {
return userProfileAppConvertor.toUserProfileDTO(userProfile);
}
private SysCountryCode getChangeCountry(UserProfileModifyCmd cmd, UserProfile userProfile) {
SysCountryCode getChangeCountry(UserProfileModifyCmd cmd, UserProfile userProfile) {
// App 保存资料可能会携带当前国家 id只拦截真实变更避免昵称头像等普通资料保存被误伤
if (Objects.isNull(cmd.getCountryId())
|| Objects.equals(userProfile.getCountryId(), cmd.getCountryId())) {
return null;
}
// 客户端保存头像等资料时会回传整份资料国家 id 可能来自 IP 定位或旧缓存
// 对国家锁定用户只忽略国家字段不能让它阻断头像昵称等无关资料更新
if (userIdentityService.hasCountryLockedIdentity(userProfile.getId())) {
log.warn("ignore country change from profile update userId={}, currentCountryId={}, requestCountryId={}",
userProfile.getId(), userProfile.getCountryId(), cmd.getCountryId());
return null;
}
Map<Long, SysCountryCode> countryMap = sysCountryCodeService.mapByIdes(Set.of(cmd.getCountryId()));
SysCountryCode country = countryMap.get(cmd.getCountryId());
ResponseAssert.notNull(UserErrorCode.SYS_REGION_NOT_EXIST_ERROR, country);
assertAllowCountryChange(userProfile.getId());
return country;
}
private void assertAllowCountryChange(Long userId) {
ResponseAssert.isFalse(UserErrorCode.USER_COUNTRY_UPDATE_NOT_ALLOWED,
userIdentityService.hasCountryLockedIdentity(userId));
}
private void syncRoomCountry(Long userId, SysCountryCode country) {
userProfileGateway.removeCacheAll(userId);
String regionCode = userRegionGateway.getRegionCode(userId);

View File

@ -0,0 +1,101 @@
package com.red.circle.other.app.command.user;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.ArgumentMatchers.anySet;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.red.circle.external.inner.endpoint.oss.OssServiceClient;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.cmd.user.user.UserProfileModifyCmd;
import com.red.circle.other.app.service.user.user.UserIdentityService;
import com.red.circle.other.domain.gateway.approval.ProfileApprovalGateway;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.cache.service.cp.CpRelationshipCacheService;
import com.red.circle.other.infra.database.mongo.service.live.ActiveVoiceRoomService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.rds.entity.sys.SysCountryCode;
import com.red.circle.other.infra.database.rds.service.sys.SysCountryCodeService;
import java.util.Map;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
@ExtendWith(MockitoExtension.class)
class UpdateUserProfileCmdExeTest {
@Mock private OssServiceClient ossServiceClient;
@Mock private UserProfileGateway userProfileGateway;
@Mock private ProfileApprovalGateway profileApprovalGateway;
@Mock private UserProfileAppConvertor userProfileAppConvertor;
@Mock private CpRelationshipCacheService cpRelationshipCacheService;
@Mock private UserIdentityService userIdentityService;
@Mock private SysCountryCodeService sysCountryCodeService;
@Mock private RoomProfileManagerService roomProfileManagerService;
@Mock private ActiveVoiceRoomService activeVoiceRoomService;
@Mock private UserRegionGateway userRegionGateway;
private UpdateUserProfileCmdExe executor;
@BeforeEach
void setUp() {
executor = new UpdateUserProfileCmdExe(
ossServiceClient,
userProfileGateway,
profileApprovalGateway,
userProfileAppConvertor,
cpRelationshipCacheService,
userIdentityService,
sysCountryCodeService,
roomProfileManagerService,
activeVoiceRoomService,
userRegionGateway);
}
@Test
void shouldIgnoreDifferentCountryForLockedUserSoOtherProfileFieldsCanUpdate() {
UserProfile profile = profile(10L, 100L);
UserProfileModifyCmd cmd = new UserProfileModifyCmd().setCountryId(200L);
when(userIdentityService.hasCountryLockedIdentity(10L)).thenReturn(true);
assertNull(executor.getChangeCountry(cmd, profile));
verify(sysCountryCodeService, never()).mapByIdes(anySet());
}
@Test
void shouldResolveDifferentCountryForUnlockedUser() {
UserProfile profile = profile(10L, 100L);
UserProfileModifyCmd cmd = new UserProfileModifyCmd().setCountryId(200L);
SysCountryCode target = new SysCountryCode().setId(200L).setAlphaTwo("EG")
.setCountryName("Egypt");
when(userIdentityService.hasCountryLockedIdentity(10L)).thenReturn(false);
when(sysCountryCodeService.mapByIdes(anySet())).thenReturn(Map.of(200L, target));
assertSame(target, executor.getChangeCountry(cmd, profile));
}
@Test
void shouldSkipCountryChecksWhenRequestCarriesCurrentCountry() {
UserProfile profile = profile(10L, 100L);
UserProfileModifyCmd cmd = new UserProfileModifyCmd().setCountryId(100L);
assertNull(executor.getChangeCountry(cmd, profile));
verify(userIdentityService, never()).hasCountryLockedIdentity(10L);
verify(sysCountryCodeService, never()).mapByIdes(anySet());
}
private UserProfile profile(Long userId, Long countryId) {
UserProfile profile = new UserProfile();
profile.setId(userId);
profile.setCountryId(countryId);
return profile;
}
}