fix: adjust admin invite country guard
This commit is contained in:
parent
f16cf81a77
commit
2ef0ac87d5
@ -55,12 +55,17 @@ public class AgentInviteHostExe {
|
||||
private final RegisterDeviceGateway registerDeviceGateway;
|
||||
private final UserProfileAppConvertor userProfileAppConvertor;
|
||||
private final BdInviteAgentMessageService bdInviteAgentMessageService;
|
||||
private final TeamInviteGuard teamInviteGuard;
|
||||
|
||||
public void execute(AgentInviteHostCmd cmd) {
|
||||
// 检查权限
|
||||
boolean teamOwn = teamProfileService.existsOwnUserId(cmd.getReqUserId());
|
||||
ResponseAssert.isTrue(TeamErrorCode.USER_AGENT_ROLE_INVALID_ERROR, teamOwn);
|
||||
|
||||
// 只有APP管理员发起邀请时才强制同国家;非管理员保留原邀请规则.
|
||||
teamInviteGuard.assertSameCountryWhenAdminInviter(cmd.requiredReqUserId(),
|
||||
cmd.getInviteUserId());
|
||||
|
||||
UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(
|
||||
userProfileGateway.getByUserId(cmd.getInviteUserId()));
|
||||
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, userProfile);
|
||||
|
||||
@ -19,7 +19,6 @@ import com.red.circle.other.infra.database.mongo.service.team.bd.BdInviteAgentMe
|
||||
import com.red.circle.other.infra.database.mongo.service.team.team.TeamApplicationProcessService;
|
||||
import com.red.circle.other.infra.database.mongo.service.team.team.TeamMemberService;
|
||||
import com.red.circle.other.infra.database.mongo.service.team.team.TeamProfileService;
|
||||
import com.red.circle.other.infra.database.rds.service.sys.AdministratorService;
|
||||
import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentBaseInfoService;
|
||||
import com.red.circle.other.infra.database.rds.service.user.device.LatestMobileDeviceService;
|
||||
import com.red.circle.other.inner.asserts.user.UserErrorCode;
|
||||
@ -62,17 +61,21 @@ public class BdAgentInviteExe {
|
||||
private final BdInviteAgentMessageService bdInviteAgentMessageService;
|
||||
private final TeamApplicationProcessService teamApplicationProcessService;
|
||||
private final BusinessDevelopmentBaseInfoService businessDevelopmentBaseInfoService;
|
||||
private final AdministratorService administratorService;
|
||||
private final TeamInviteGuard teamInviteGuard;
|
||||
|
||||
public void execute(DbInviteAgentCmd cmd) {
|
||||
|
||||
ResponseAssert.isFalse(TeamErrorCode.USER_IS_A_ADMIN,
|
||||
administratorService.existsAdmin(cmd.getInviteUserId()));
|
||||
teamInviteGuard.assertInviteeIsNotAdminUnlessSelf(cmd.requiredReqUserId(),
|
||||
cmd.getInviteUserId());
|
||||
|
||||
// 权限不足
|
||||
ResponseAssert.isTrue(CommonErrorCode.INSUFFICIENT_PERMISSION,
|
||||
businessDevelopmentBaseInfoService.checkBD(cmd.requiredReqUserId()));
|
||||
|
||||
// APP管理员发起邀请时只能邀请同国家用户;普通BD继续沿用原有区域和余额规则.
|
||||
boolean adminCountryChecked = teamInviteGuard.assertSameCountryWhenAdminInviter(
|
||||
cmd.requiredReqUserId(), cmd.getInviteUserId());
|
||||
|
||||
// 用户已经是主播
|
||||
ResponseAssert.isFalse(TeamErrorCode.USER_IS_ALREADY_A_ANCHOR,
|
||||
teamMemberService.existsMember(cmd.getInviteUserId()));
|
||||
@ -94,8 +97,9 @@ public class BdAgentInviteExe {
|
||||
bdInviteAgentMessageService.existsWaitMessage(cmd.requiredReqUserId(),
|
||||
cmd.getInviteUserId(), MessageInviteGroup.BD_INVITE_TEAM.name()));
|
||||
|
||||
// 校验邀请人与被邀请人的区域
|
||||
checkInvite(cmd);
|
||||
if (!adminCountryChecked) {
|
||||
checkInvite(cmd);
|
||||
}
|
||||
|
||||
String messageId = IdWorkerUtils.getIdStr();
|
||||
bdInviteAgentMessageService.add(new BdInviteAgentMessage()
|
||||
@ -139,7 +143,7 @@ public class BdAgentInviteExe {
|
||||
|
||||
private void checkInvite(DbInviteAgentCmd cmd) {
|
||||
|
||||
// 验证BD区域(如BD是代理则按照代理的区域来否则用BD本身指定的区域)与被邀请人区域是不是一致,
|
||||
// 普通BD保持旧规则:同区域直接放行;不同区域但被邀请人余额低于100也放行.
|
||||
Boolean eqRegion = userRegionGateway.checkEqRegion(cmd.requiredReqUserId(),
|
||||
cmd.getInviteUserId());
|
||||
|
||||
|
||||
@ -15,7 +15,6 @@ import com.red.circle.other.infra.database.mongo.entity.team.bd.BdInviteAgentMes
|
||||
import com.red.circle.other.infra.database.mongo.entity.team.bd.MessageInviteGroup;
|
||||
import com.red.circle.other.infra.database.mongo.service.team.bd.BdInviteAgentMessageService;
|
||||
import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentBaseInfo;
|
||||
import com.red.circle.other.infra.database.rds.service.sys.AdministratorService;
|
||||
import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentBaseInfoService;
|
||||
import com.red.circle.other.infra.database.rds.service.team.RoomBdLeadService;
|
||||
import com.red.circle.other.inner.asserts.user.UserErrorCode;
|
||||
@ -50,7 +49,7 @@ public class BdLeaderInviteBdExe {
|
||||
private final UserProfileAppConvertor userProfileAppConvertor;
|
||||
private final BdInviteAgentMessageService bdInviteAgentMessageService;
|
||||
private final BusinessDevelopmentBaseInfoService businessDevelopmentBaseInfoService;
|
||||
private final AdministratorService administratorService;
|
||||
private final TeamInviteGuard teamInviteGuard;
|
||||
|
||||
public void execute(DbLeaderInviteBdCmd cmd) {
|
||||
|
||||
@ -65,9 +64,12 @@ public class BdLeaderInviteBdExe {
|
||||
ResponseAssert.isFalse(TeamErrorCode.USER_IS_ALREADY_A_BD,
|
||||
businessDevelopmentBaseInfoService.checkBD(cmd.getInviteUserId()));
|
||||
|
||||
ResponseAssert.isFalse(TeamErrorCode.USER_IS_A_ADMIN,
|
||||
administratorService.existsAdmin(cmd.getInviteUserId()));
|
||||
teamInviteGuard.assertInviteeIsNotAdminUnlessSelf(cmd.requiredReqUserId(),
|
||||
cmd.getInviteUserId());
|
||||
|
||||
// 只有APP管理员发起邀请时才强制同国家;非管理员保留原邀请规则.
|
||||
teamInviteGuard.assertSameCountryWhenAdminInviter(cmd.requiredReqUserId(),
|
||||
cmd.getInviteUserId());
|
||||
|
||||
// 权限不足
|
||||
BusinessDevelopmentBaseInfo bd = getDevelopmentBaseInfoServiceByUserId(cmd);
|
||||
@ -117,9 +119,12 @@ public class BdLeaderInviteBdExe {
|
||||
ResponseAssert.isFalse(TeamErrorCode.USER_IS_ALREADY_A_BDLEADER,
|
||||
roomBdLeadService.checkBdLeader(cmd.getInviteUserId()));
|
||||
|
||||
ResponseAssert.isFalse(TeamErrorCode.USER_IS_A_ADMIN,
|
||||
administratorService.existsAdmin(cmd.getInviteUserId()));
|
||||
teamInviteGuard.assertInviteeIsNotAdminUnlessSelf(cmd.requiredReqUserId(),
|
||||
cmd.getInviteUserId());
|
||||
|
||||
// 只有APP管理员发起邀请时才强制同国家;非管理员保留原邀请规则.
|
||||
teamInviteGuard.assertSameCountryWhenAdminInviter(cmd.requiredReqUserId(),
|
||||
cmd.getInviteUserId());
|
||||
|
||||
List<Long> bdUserIds = businessDevelopmentBaseInfoService.listBdUserIdsByLeaderId(cmd.requiredReqUserId());
|
||||
ResponseAssert.isFalse(CommonErrorCode.INSUFFICIENT_PERMISSION, bdUserIds.contains(cmd.getInviteUserId()));
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
package com.red.circle.other.app.command.team;
|
||||
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||
import com.red.circle.other.domain.model.user.UserProfile;
|
||||
import com.red.circle.other.infra.database.rds.service.sys.AdministratorService;
|
||||
import com.red.circle.other.inner.asserts.team.TeamErrorCode;
|
||||
import com.red.circle.other.inner.asserts.user.UserErrorCode;
|
||||
import com.red.circle.tool.core.text.StringUtils;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 团队邀请的公共身份和国家校验.
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class TeamInviteGuard {
|
||||
|
||||
private static final Map<String, String> COUNTRY_CODE_ALIASES = Map.of(
|
||||
"IA", "ID",
|
||||
"EY", "EG",
|
||||
"AB", "AE",
|
||||
"MB", "MA",
|
||||
"SP", "SA"
|
||||
);
|
||||
|
||||
private final AdministratorService administratorService;
|
||||
private final UserProfileGateway userProfileGateway;
|
||||
|
||||
public void assertInviteeIsNotAdminUnlessSelf(Long reqUserId, Long inviteUserId) {
|
||||
if (Objects.equals(reqUserId, inviteUserId)) {
|
||||
return;
|
||||
}
|
||||
ResponseAssert.isFalse(TeamErrorCode.USER_IS_A_ADMIN,
|
||||
administratorService.existsAdmin(inviteUserId));
|
||||
}
|
||||
|
||||
public boolean assertSameCountryWhenAdminInviter(Long reqUserId, Long inviteUserId) {
|
||||
if (!isAdminInviteScope(reqUserId, inviteUserId)) {
|
||||
return false;
|
||||
}
|
||||
UserProfile reqUser = userProfileGateway.getByUserId(reqUserId);
|
||||
UserProfile inviteUser = userProfileGateway.getByUserId(inviteUserId);
|
||||
ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, reqUser);
|
||||
ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, inviteUser);
|
||||
ResponseAssert.isTrue(TeamErrorCode.NOT_INVITE_USER_ERROR, isSameCountry(reqUser, inviteUser));
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean isAdminInviteScope(Long reqUserId, Long inviteUserId) {
|
||||
return !Objects.equals(reqUserId, inviteUserId) && administratorService.existsAdmin(reqUserId);
|
||||
}
|
||||
|
||||
private boolean isSameCountry(UserProfile reqUser, UserProfile inviteUser) {
|
||||
String reqCountryCode = normalizeCountryCode(reqUser.getCountryCode());
|
||||
String inviteCountryCode = normalizeCountryCode(inviteUser.getCountryCode());
|
||||
if (StringUtils.isNotBlank(reqCountryCode) && StringUtils.isNotBlank(inviteCountryCode)) {
|
||||
return Objects.equals(reqCountryCode, inviteCountryCode);
|
||||
}
|
||||
return Objects.nonNull(reqUser.getCountryId())
|
||||
&& Objects.equals(reqUser.getCountryId(), inviteUser.getCountryId());
|
||||
}
|
||||
|
||||
private String normalizeCountryCode(String countryCode) {
|
||||
if (StringUtils.isBlank(countryCode)) {
|
||||
return null;
|
||||
}
|
||||
String normalized = countryCode.trim().toUpperCase(Locale.ROOT);
|
||||
return COUNTRY_CODE_ALIASES.getOrDefault(normalized, normalized);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,82 @@
|
||||
package com.red.circle.other.app.command.team;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||
import com.red.circle.other.domain.model.user.UserProfile;
|
||||
import com.red.circle.other.infra.database.rds.service.sys.AdministratorService;
|
||||
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 TeamInviteGuardTest {
|
||||
|
||||
@Mock
|
||||
private AdministratorService administratorService;
|
||||
@Mock
|
||||
private UserProfileGateway userProfileGateway;
|
||||
|
||||
private TeamInviteGuard teamInviteGuard;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
teamInviteGuard = new TeamInviteGuard(administratorService, userProfileGateway);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldNotBlockAdminWhenInviteSelf() {
|
||||
assertDoesNotThrow(() -> teamInviteGuard.assertInviteeIsNotAdminUnlessSelf(1L, 1L));
|
||||
|
||||
verify(administratorService, never()).existsAdmin(1L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBlockAdminWhenInviteOtherUser() {
|
||||
when(administratorService.existsAdmin(2L)).thenReturn(true);
|
||||
|
||||
assertThrows(RuntimeException.class,
|
||||
() -> teamInviteGuard.assertInviteeIsNotAdminUnlessSelf(1L, 2L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAllowLegacyAliasCountryCode() {
|
||||
when(administratorService.existsAdmin(1L)).thenReturn(true);
|
||||
when(userProfileGateway.getByUserId(1L)).thenReturn(profile(1L, "SP"));
|
||||
when(userProfileGateway.getByUserId(2L)).thenReturn(profile(2L, "SA"));
|
||||
|
||||
assertDoesNotThrow(() -> teamInviteGuard.assertSameCountryWhenAdminInviter(1L, 2L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBlockDifferentCountryForAdminInviter() {
|
||||
when(administratorService.existsAdmin(1L)).thenReturn(true);
|
||||
when(userProfileGateway.getByUserId(1L)).thenReturn(profile(1L, "BD"));
|
||||
when(userProfileGateway.getByUserId(2L)).thenReturn(profile(2L, "PK"));
|
||||
|
||||
assertThrows(RuntimeException.class,
|
||||
() -> teamInviteGuard.assertSameCountryWhenAdminInviter(1L, 2L));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldSkipCountryCheckForNonAdminInviter() {
|
||||
when(administratorService.existsAdmin(1L)).thenReturn(false);
|
||||
|
||||
assertDoesNotThrow(() -> teamInviteGuard.assertSameCountryWhenAdminInviter(1L, 2L));
|
||||
verify(userProfileGateway, never()).getByUserId(1L);
|
||||
verify(userProfileGateway, never()).getByUserId(2L);
|
||||
}
|
||||
|
||||
private UserProfile profile(Long countryId, String countryCode) {
|
||||
UserProfile profile = new UserProfile();
|
||||
profile.setCountryId(countryId);
|
||||
profile.setCountryCode(countryCode);
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user