diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/UpdateUserProfileCmdExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/UpdateUserProfileCmdExe.java index 71fc4156..0aa4165b 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/UpdateUserProfileCmdExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/UpdateUserProfileCmdExe.java @@ -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 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); diff --git a/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/user/UpdateUserProfileCmdExeTest.java b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/user/UpdateUserProfileCmdExeTest.java new file mode 100644 index 00000000..1bcc5a66 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/user/UpdateUserProfileCmdExeTest.java @@ -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; + } +}