This commit is contained in:
hy001 2026-04-23 16:04:18 +08:00
parent 4fb7d8af04
commit 5951344b1e
15 changed files with 660 additions and 246 deletions

View File

@ -87,6 +87,11 @@ spring:
predicates: predicates:
- Path=/game/baishun/** - Path=/game/baishun/**
- id: game-open-callback
uri: ${LIKEI_GATEWAY_ROUTE_GO_URI}
predicates:
- Path=/game/open/**
- id: service-gateway - id: service-gateway
uri: ${LIKEI_GATEWAY_ROUTE_FORWARD_URI} uri: ${LIKEI_GATEWAY_ROUTE_FORWARD_URI}
predicates: predicates:
@ -132,6 +137,7 @@ gateway:
- /game/hkys/**/* - /game/hkys/**/*
- /game/lxwl/**/* - /game/lxwl/**/*
- /game/hot/**/* - /game/hot/**/*
- /game/open/**/*
- /game/baishun/**/* - /game/baishun/**/*
- /game/test/bet - /game/test/bet
- /room-setting/client/restapi/**/* - /room-setting/client/restapi/**/*

View File

@ -60,6 +60,13 @@ public interface RoomManagerClientApi {
ResultResponse<RoomProfileManagerDTO> getRoomProfileManagerById( ResultResponse<RoomProfileManagerDTO> getRoomProfileManagerById(
@RequestParam("roomId") Long roomId); @RequestParam("roomId") Long roomId);
/**
* 通过房间账号获取资料详情.
*/
@GetMapping("/getRoomProfileManagerByRoomAccount")
ResultResponse<RoomProfileManagerDTO> getRoomProfileManagerByRoomAccount(
@RequestParam("roomAccount") String roomAccount);
/** /**
* 获取房间资料. * 获取房间资料.
*/ */

View File

@ -20,6 +20,12 @@
<artifactId>external-inner-api</artifactId> <artifactId>external-inner-api</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<parent> <parent>

View File

@ -10,6 +10,7 @@ import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.group
import com.red.circle.component.instant.msg.tencet.service.endpoint.impl.TencentIMStatusUtils; import com.red.circle.component.instant.msg.tencet.service.endpoint.impl.TencentIMStatusUtils;
import com.red.circle.component.instant.msg.tencet.service.enums.GroupType; import com.red.circle.component.instant.msg.tencet.service.enums.GroupType;
import com.red.circle.component.instant.msg.tencet.service.param.CreateGroupParam; import com.red.circle.component.instant.msg.tencet.service.param.CreateGroupParam;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.external.infra.props.RcMessageProperties; import com.red.circle.external.infra.props.RcMessageProperties;
import com.red.circle.external.inner.model.cmd.message.BroadcastGroupMsgBodyCmd; import com.red.circle.external.inner.model.cmd.message.BroadcastGroupMsgBodyCmd;
import com.red.circle.external.inner.model.cmd.message.CreateGroupAddMemberCmd; import com.red.circle.external.inner.model.cmd.message.CreateGroupAddMemberCmd;
@ -18,6 +19,8 @@ import com.red.circle.external.inner.model.cmd.message.CustomGroupMsgBodyCmd;
import com.red.circle.external.inner.model.cmd.message.GroupBanCmd; import com.red.circle.external.inner.model.cmd.message.GroupBanCmd;
import com.red.circle.external.inner.model.cmd.message.GroupUnbanCmd; import com.red.circle.external.inner.model.cmd.message.GroupUnbanCmd;
import com.red.circle.external.inner.service.message.ImGroupClientService; import com.red.circle.external.inner.service.message.ImGroupClientService;
import com.red.circle.other.inner.endpoint.live.RoomManagerClient;
import com.red.circle.other.inner.model.dto.live.RoomProfileManagerDTO;
import com.red.circle.tool.core.collection.CollectionUtils; import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.http.RcHttpClient; import com.red.circle.tool.core.http.RcHttpClient;
import com.red.circle.tool.core.json.JacksonUtils; import com.red.circle.tool.core.json.JacksonUtils;
@ -42,6 +45,7 @@ public class ImGroupClientServiceImpl implements ImGroupClientService {
private final ImGroupMemberService imGroupMemberService; private final ImGroupMemberService imGroupMemberService;
private final ImGroupMessageService imGroupMessageService; private final ImGroupMessageService imGroupMessageService;
private final ImGroupManagerService imGroupManagerService; private final ImGroupManagerService imGroupManagerService;
private final RoomManagerClient roomManagerClient;
@Override @Override
@ -99,15 +103,20 @@ public class ImGroupClientServiceImpl implements ImGroupClientService {
return; return;
} }
JsonObject jsonObject = JsonParser.parseString(res).getAsJsonObject(); Integer errorCode = parseErrorCode(res);
if (Objects.nonNull(jsonObject) && Objects if (Objects.equals(errorCode, 80002)) {
.equals(jsonObject.get("ErrorCode").getAsInt(), 80002)) {
log.warn("sendCustomMessage 80002 groupId={}, res={}", groupId, log.warn("sendCustomMessage 80002 groupId={}, res={}", groupId,
JacksonUtils.toJson(res)); JacksonUtils.toJson(res));
return; return;
} }
if (Objects.equals(errorCode, 10015) && recoverRoomGroup(groupId)) {
log.warn("sendCustomMessage recover groupId={}, retry={}", groupId, newRetrySize);
sendCustomMessage(groupId, cmd, newRetrySize);
return;
}
log.warn("sendCustomMessage retry: {}, {}", newRetrySize, JacksonUtils.toJson(res)); log.warn("sendCustomMessage retry: {}, {}", newRetrySize, JacksonUtils.toJson(res));
sendCustomMessage(groupId, cmd, newRetrySize); sendCustomMessage(groupId, cmd, newRetrySize);
}, er -> { }, er -> {
@ -180,4 +189,47 @@ public class ImGroupClientServiceImpl implements ImGroupClientService {
imGroupManagerService.destroyGroup(groupId).subscribe(); imGroupManagerService.destroyGroup(groupId).subscribe();
} }
Integer parseErrorCode(String res) {
try {
JsonObject jsonObject = JsonParser.parseString(res).getAsJsonObject();
if (Objects.isNull(jsonObject) || !jsonObject.has("ErrorCode")
|| jsonObject.get("ErrorCode").isJsonNull()) {
return null;
}
return jsonObject.get("ErrorCode").getAsInt();
} catch (Exception ex) {
log.warn("parseErrorCode fail res={}", res, ex);
return null;
}
}
boolean recoverRoomGroup(String groupId) {
String normalizedGroupId = Objects.isNull(groupId) ? null : groupId.trim();
if (!isRecoverableRoomGroupId(normalizedGroupId)) {
return false;
}
try {
RoomProfileManagerDTO roomProfileManagerDTO = ResponseAssert.requiredSuccess(
roomManagerClient.getRoomProfileManagerByRoomAccount(normalizedGroupId));
if (Objects.isNull(roomProfileManagerDTO) || Objects.isNull(roomProfileManagerDTO.getUserId())
|| StringUtils.isBlank(roomProfileManagerDTO.getRoomAccount())) {
return false;
}
return createAVChatRoomGroup(new CreateGroupCmd()
.setOwnerAccount(Objects.toString(roomProfileManagerDTO.getUserId()))
.setGroupId(roomProfileManagerDTO.getRoomAccount())
.setFaceUrl(roomProfileManagerDTO.getRoomCover())
.setName(roomProfileManagerDTO.getRoomName()));
} catch (Exception ex) {
log.warn("recoverRoomGroup fail groupId={}", normalizedGroupId, ex);
return false;
}
}
boolean isRecoverableRoomGroupId(String groupId) {
return StringUtils.isNotBlank(groupId) && groupId.chars().allMatch(Character::isDigit);
}
} }

View File

@ -0,0 +1,98 @@
package com.red.circle.external.inner.service.message.impl;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.group.ImGroupManagerService;
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.group.ImGroupMemberService;
import com.red.circle.component.instant.msg.tencet.service.endpoint.api.im.group.ImGroupMessageService;
import com.red.circle.external.infra.props.RcMessageProperties;
import com.red.circle.external.inner.model.cmd.message.CreateGroupCmd;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.other.inner.endpoint.live.RoomManagerClient;
import com.red.circle.other.inner.model.dto.live.RoomProfileManagerDTO;
import org.junit.jupiter.api.Test;
class ImGroupClientServiceImplTest {
@Test
void recoverRoomGroupShouldCreateAvChatRoomForNumericRoomAccount() {
RoomManagerClient roomManagerClient = mock(RoomManagerClient.class);
RoomProfileManagerDTO roomProfileManagerDTO = new RoomProfileManagerDTO();
roomProfileManagerDTO.setUserId(2045510007037947905L);
roomProfileManagerDTO.setRoomAccount("1001417");
roomProfileManagerDTO.setRoomCover("https://cdn.example.com/room.png");
roomProfileManagerDTO.setRoomName("Lucky Room");
when(roomManagerClient.getRoomProfileManagerByRoomAccount("1001417"))
.thenReturn(ResultResponse.success(roomProfileManagerDTO));
TestableImGroupClientServiceImpl service = new TestableImGroupClientServiceImpl(
mock(RcMessageProperties.class),
mock(ImGroupMemberService.class),
mock(ImGroupMessageService.class),
mock(ImGroupManagerService.class),
roomManagerClient
);
service.createResult = true;
boolean recovered = service.recoverRoomGroup("1001417");
assertTrue(recovered);
assertEquals("2045510007037947905", service.createdCmd.getOwnerAccount());
assertEquals("1001417", service.createdCmd.getGroupId());
assertEquals("https://cdn.example.com/room.png", service.createdCmd.getFaceUrl());
assertEquals("Lucky Room", service.createdCmd.getName());
}
@Test
void recoverRoomGroupShouldIgnoreNonRoomGroupId() {
RoomManagerClient roomManagerClient = mock(RoomManagerClient.class);
TestableImGroupClientServiceImpl service = new TestableImGroupClientServiceImpl(
mock(RcMessageProperties.class),
mock(ImGroupMemberService.class),
mock(ImGroupMessageService.class),
mock(ImGroupManagerService.class),
roomManagerClient
);
boolean recovered = service.recoverRoomGroup("@TGS#2RUK4PK5C2");
assertFalse(recovered);
assertNull(service.createdCmd);
verifyNoInteractions(roomManagerClient);
}
private static final class TestableImGroupClientServiceImpl extends ImGroupClientServiceImpl {
private boolean createResult;
private CreateGroupCmd createdCmd;
private TestableImGroupClientServiceImpl(
RcMessageProperties rcMessageProperties,
ImGroupMemberService imGroupMemberService,
ImGroupMessageService imGroupMessageService,
ImGroupManagerService imGroupManagerService,
RoomManagerClient roomManagerClient
) {
super(
rcMessageProperties,
imGroupMemberService,
imGroupMessageService,
imGroupManagerService,
roomManagerClient
);
}
@Override
public boolean createAVChatRoomGroup(CreateGroupCmd cmd) {
this.createdCmd = cmd;
return createResult;
}
}
}

View File

@ -28,7 +28,7 @@ import com.red.circle.other.infra.database.rds.service.team.BusinessDevelopmentB
import com.red.circle.other.infra.database.rds.service.team.RoomBdLeadService; import com.red.circle.other.infra.database.rds.service.team.RoomBdLeadService;
import com.red.circle.other.inner.asserts.team.TeamErrorCode; import com.red.circle.other.inner.asserts.team.TeamErrorCode;
import com.red.circle.other.inner.asserts.user.UserErrorCode; import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.enums.config.EnumConfigKey; import com.red.circle.other.inner.enums.team.TeamApplicationProcessStatus;
import com.red.circle.other.inner.enums.team.TeamMemberRole; import com.red.circle.other.inner.enums.team.TeamMemberRole;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO; import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.collection.CollectionUtils; import com.red.circle.tool.core.collection.CollectionUtils;
@ -53,6 +53,7 @@ public class AgentInviteHostExe {
private final TeamProfileService teamProfileService; private final TeamProfileService teamProfileService;
private final OfficialNoticeClient officialNoticeClient; private final OfficialNoticeClient officialNoticeClient;
private final RegisterDeviceGateway registerDeviceGateway; private final RegisterDeviceGateway registerDeviceGateway;
private final TeamHandleUserApplyExe teamHandleUserApplyExe;
private final UserProfileAppConvertor userProfileAppConvertor; private final UserProfileAppConvertor userProfileAppConvertor;
private final BdInviteAgentMessageService bdInviteAgentMessageService; private final BdInviteAgentMessageService bdInviteAgentMessageService;
@ -147,6 +148,10 @@ public class AgentInviteHostExe {
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getStatus() > 0); ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getStatus() > 0);
BdInviteAgentMessage message = bdInviteAgentMessageService.getById(cmd.getId()); BdInviteAgentMessage message = bdInviteAgentMessageService.getById(cmd.getId());
if (message == null) {
processTeamApply(cmd);
return;
}
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, message); ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, message);
ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE, message.getStatus() == 0); ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE, message.getStatus() == 0);
@ -198,6 +203,29 @@ public class AgentInviteHostExe {
sendMessage(message, OfficialNoticeTypeEnum.REFUSE_AGENT_INVITE_HOST); sendMessage(message, OfficialNoticeTypeEnum.REFUSE_AGENT_INVITE_HOST);
} }
private void processTeamApply(AgentInviteMessageProcessCmd cmd) {
Long applyId;
try {
applyId = Long.parseLong(cmd.getId());
} catch (NumberFormatException ex) {
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, null);
return;
}
TeamHandleUserApplyCmd applyCmd = new TeamHandleUserApplyCmd();
applyCmd.setId(applyId);
applyCmd.setStatus(
Objects.equals(cmd.getStatus(), 1)
? TeamApplicationProcessStatus.AGREE.name()
: TeamApplicationProcessStatus.REJECT.name()
);
applyCmd.setReqUserId(cmd.getReqUserId());
applyCmd.setReqSysOrigin(cmd.getReqSysOrigin());
applyCmd.setReqAppIntel(cmd.getReqAppIntel());
applyCmd.setReqTime(cmd.getReqTime());
teamHandleUserApplyExe.execute(applyCmd);
}
private void sendMessage(BdInviteAgentMessage message, OfficialNoticeTypeEnum noticeTypeEnum) { private void sendMessage(BdInviteAgentMessage message, OfficialNoticeTypeEnum noticeTypeEnum) {
UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO( UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(

View File

@ -1,17 +1,18 @@
package com.red.circle.other.app.command.team; package com.red.circle.other.app.command.team;
import com.alibaba.fastjson.JSON;
import com.red.circle.common.business.enums.OperationUserOrigin; import com.red.circle.common.business.enums.OperationUserOrigin;
import com.red.circle.external.inner.endpoint.message.OfficialNoticeClient; import com.red.circle.external.inner.endpoint.message.OfficialNoticeClient;
import com.red.circle.external.inner.model.cmd.message.notice.official.NoticeExtTemplateTypeCmd; import com.red.circle.external.inner.model.cmd.message.notice.official.NoticeExtTemplateCustomizeCmd;
import com.red.circle.external.inner.model.enums.message.OfficialNoticeTypeEnum; import com.red.circle.external.inner.model.enums.message.OfficialNoticeTypeEnum;
import com.red.circle.framework.core.asserts.ResponseAssert; import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode; import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor; import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.cmd.team.TeamUserApplyCmd; import com.red.circle.other.app.dto.cmd.team.TeamUserApplyCmd;
import com.red.circle.other.app.util.OfficialNoticeUtils;
import com.red.circle.other.domain.gateway.user.UserProfileGateway; import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.RegisterDeviceGateway; import com.red.circle.other.domain.gateway.user.ability.RegisterDeviceGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway; import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamApplicationProcess; import com.red.circle.other.infra.database.mongo.entity.team.team.TeamApplicationProcess;
import com.red.circle.other.infra.database.mongo.entity.team.team.TeamProfile; import com.red.circle.other.infra.database.mongo.entity.team.team.TeamProfile;
import com.red.circle.other.infra.database.mongo.service.team.team.TeamApplicationProcessService; import com.red.circle.other.infra.database.mongo.service.team.team.TeamApplicationProcessService;
@ -20,7 +21,6 @@ import com.red.circle.other.infra.database.mongo.service.team.team.TeamProfileSe
import com.red.circle.other.infra.database.rds.service.user.device.LatestMobileDeviceService; import com.red.circle.other.infra.database.rds.service.user.device.LatestMobileDeviceService;
import com.red.circle.other.inner.asserts.user.UserErrorCode; import com.red.circle.other.inner.asserts.user.UserErrorCode;
import com.red.circle.other.inner.asserts.user.UserRelationErrorCode; import com.red.circle.other.inner.asserts.user.UserRelationErrorCode;
import com.red.circle.other.inner.enums.config.EnumConfigKey;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO; import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.other.inner.asserts.team.TeamErrorCode; import com.red.circle.other.inner.asserts.team.TeamErrorCode;
import com.red.circle.other.inner.model.dto.agency.agency.TeamStatus; import com.red.circle.other.inner.model.dto.agency.agency.TeamStatus;
@ -28,13 +28,11 @@ import com.red.circle.other.inner.enums.team.TeamAppProcessReason;
import com.red.circle.other.inner.enums.team.TeamApplicationProcessStatus; import com.red.circle.other.inner.enums.team.TeamApplicationProcessStatus;
import com.red.circle.other.inner.enums.team.TeamApplicationType; import com.red.circle.other.inner.enums.team.TeamApplicationType;
import com.red.circle.tool.core.collection.CollectionUtils; import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.collection.MapBuilder;
import com.red.circle.tool.core.date.TimestampUtils; import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils; import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.text.StringUtils; import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient; import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -50,7 +48,7 @@ import org.springframework.stereotype.Component;
@RequiredArgsConstructor @RequiredArgsConstructor
public class TeamUserApplyJoinExe { public class TeamUserApplyJoinExe {
private static final String TEAM_APPLY_MESSAGE_PATH = "/message"; private static final String TEAM_APPLY_NOTICE_TITLE = "apply agent";
private final WalletGoldClient walletGoldClient; private final WalletGoldClient walletGoldClient;
private final UserRegionGateway userRegionGateway; private final UserRegionGateway userRegionGateway;
@ -62,7 +60,6 @@ public class TeamUserApplyJoinExe {
private final LatestMobileDeviceService latestMobileDeviceService; private final LatestMobileDeviceService latestMobileDeviceService;
private final TeamApplicationProcessService teamApplicationProcessService; private final TeamApplicationProcessService teamApplicationProcessService;
private final RegisterDeviceGateway registerDeviceGateway; private final RegisterDeviceGateway registerDeviceGateway;
private final EnumConfigCacheService enumConfigCacheService;
public String execute(TeamUserApplyCmd cmd) { public String execute(TeamUserApplyCmd cmd) {
@ -114,7 +111,7 @@ public class TeamUserApplyJoinExe {
.setExpiredTime(TimestampUtils.nowPlusDays(60)) .setExpiredTime(TimestampUtils.nowPlusDays(60))
); );
sendMessage(cmd, teamProfile); sendMessage(cmd, teamProfile, messageId);
return Objects.toString(messageId); return Objects.toString(messageId);
} }
@ -165,31 +162,19 @@ public class TeamUserApplyJoinExe {
return teamIds.contains(cmd.getTeamId()); return teamIds.contains(cmd.getTeamId());
} }
private void sendMessage(TeamUserApplyCmd cmd, TeamProfile teamProfile) { private void sendMessage(TeamUserApplyCmd cmd, TeamProfile teamProfile, Long messageId) {
UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO( UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(
userProfileGateway.getByUserId(cmd.requiredReqUserId()) userProfileGateway.getByUserId(cmd.requiredReqUserId())
); );
ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, userProfile); ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, userProfile);
String h5Url = enumConfigCacheService.getValue(EnumConfigKey.H5_DOMAIN_BASE_URL_V2,
cmd.requireReqSysOrigin());
String expand = null;
if (StringUtils.isNotBlank(h5Url)) {
expand = (h5Url.endsWith("/") ? h5Url.substring(0, h5Url.length() - 1) : h5Url)
+ TEAM_APPLY_MESSAGE_PATH;
}
NoticeExtTemplateTypeCmd.NoticeExtTemplateTypeCmdBuilder builder = officialNoticeClient.send(NoticeExtTemplateCustomizeCmd.builder()
NoticeExtTemplateTypeCmd.builder() .toAccount(teamProfile.getOwnUserId())
.toAccount(teamProfile.getOwnUserId()) .noticeType(OfficialNoticeTypeEnum.AGENT_SEND_INVITE_HOST)
.noticeType(OfficialNoticeTypeEnum.USER_SEND_APPLY_TEAM) .title(TEAM_APPLY_NOTICE_TITLE)
.templateParam(MapBuilder.builder() .content(JSON.toJSONString(OfficialNoticeUtils.buildUserProfile(userProfile)))
.put("userProfile", String.format("%s(%s)", userProfile.getUserNickname(), .expand(Objects.toString(messageId))
userProfile.actualAccount())) .build());
.build());
if (StringUtils.isNotBlank(expand)) {
builder.expand(expand);
}
officialNoticeClient.send(builder.build());
} }
} }

View File

@ -114,6 +114,7 @@ public class UpdateUserProfileCmdExe {
processAge(updateUserProfile); processAge(updateUserProfile);
processCountry(cmd, userProfile); processCountry(cmd, userProfile);
syncCountry(updateUserProfile, userProfile);
// 处理照片状态 // 处理照片状态
processPhotoStatus(updateUserProfile.getBackgroundPhotos(), userProfile.getBackgroundPhotos()); processPhotoStatus(updateUserProfile.getBackgroundPhotos(), userProfile.getBackgroundPhotos());
@ -156,6 +157,21 @@ public class UpdateUserProfileCmdExe {
baseInfoService.updateSelectiveById(baseInfo); baseInfoService.updateSelectiveById(baseInfo);
} }
private void syncCountry(UserProfile updateUserProfile, UserProfile userProfile) {
if (Objects.isNull(updateUserProfile) || Objects.isNull(userProfile)) {
return;
}
if (Objects.nonNull(userProfile.getCountryId())) {
updateUserProfile.setCountryId(userProfile.getCountryId());
}
if (StringUtils.isNotBlank(userProfile.getCountryCode())) {
updateUserProfile.setCountryCode(userProfile.getCountryCode());
}
if (StringUtils.isNotBlank(userProfile.getCountryName())) {
updateUserProfile.setCountryName(userProfile.getCountryName());
}
}
private void submitApproval(UserProfile updateUserProfile, UserProfile originalUserProfile) { private void submitApproval(UserProfile updateUserProfile, UserProfile originalUserProfile) {
List<ProfileApprovalContent> approvalParam = CollectionUtils.newArrayList(); List<ProfileApprovalContent> approvalParam = CollectionUtils.newArrayList();
if (StringUtils.isNotBlank(updateUserProfile.getUserAvatar())) { if (StringUtils.isNotBlank(updateUserProfile.getUserAvatar())) {

View File

@ -0,0 +1,81 @@
package com.red.circle.other.app.command.user;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;
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.framework.core.dto.ReqSysOrigin;
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.domain.gateway.approval.ProfileApprovalGateway;
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.cache.service.cp.CpRelationshipCacheService;
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 com.red.circle.other.infra.database.rds.service.user.user.BaseInfoService;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.component.redis.service.RedisService;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
class UpdateUserProfileCmdExeTest {
@Test
void execute_shouldSyncCountryToUpdateUserProfileWhenCountryChanges() {
OssServiceClient ossServiceClient = mock(OssServiceClient.class);
UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
RedisService redisService = mock(RedisService.class);
BaseInfoService baseInfoService = mock(BaseInfoService.class);
SysCountryCodeService sysCountryCodeService = mock(SysCountryCodeService.class);
ProfileApprovalGateway profileApprovalGateway = mock(ProfileApprovalGateway.class);
UserProfileAppConvertor userProfileAppConvertor = mock(UserProfileAppConvertor.class);
RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
CpRelationshipCacheService cpRelationshipCacheService = mock(CpRelationshipCacheService.class);
UpdateUserProfileCmdExe exe = new UpdateUserProfileCmdExe(
ossServiceClient,
userProfileGateway,
redisService,
baseInfoService,
sysCountryCodeService,
profileApprovalGateway,
userProfileAppConvertor,
roomProfileManagerService,
cpRelationshipCacheService
);
UserProfileModifyCmd cmd = new UserProfileModifyCmd();
cmd.setReqUserId(1L);
cmd.setReqSysOrigin(ReqSysOrigin.of("LIKEI", "LIKEI"));
cmd.setCountryId(2L);
UserProfile currentUserProfile = new UserProfile()
.setId(1L)
.setCountryId(1L)
.setCountryCode("KSA")
.setCountryName("KSA");
UserProfile updateUserProfile = new UserProfile();
SysCountryCode newCountry = new SysCountryCode()
.setId(2L)
.setAlphaTwo("JP")
.setCountryName("Japan");
when(userProfileGateway.getByUserId(1L)).thenReturn(currentUserProfile);
when(userProfileAppConvertor.toUserProfile(cmd)).thenReturn(updateUserProfile);
when(sysCountryCodeService.getById(2L)).thenReturn(newCountry);
when(userProfileAppConvertor.toUserProfileDTO(currentUserProfile)).thenReturn(new UserProfileDTO());
exe.execute(cmd);
ArgumentCaptor<UserProfile> updateCaptor = ArgumentCaptor.forClass(UserProfile.class);
verify(userProfileGateway).updateSelectiveById(updateCaptor.capture());
UserProfile persistedUpdate = updateCaptor.getValue();
assertEquals(2L, persistedUpdate.getCountryId());
assertEquals("JP", persistedUpdate.getCountryCode());
assertEquals("Japan", persistedUpdate.getCountryName());
verify(roomProfileManagerService).updateUserCountry(1L, "JP", "Japan");
}
}

View File

@ -184,37 +184,10 @@ public class UserRegionGatewayImpl implements UserRegionGateway {
continue; continue;
} }
// 2.1 国家匹配 UserRegionDTO userRegion = createUserRegionDTO(
if (StringUtils.isNotBlank(userProfile.getCountryCode())) { userProfile,
SysRegionConfig regionConfig = configs.stream() matchCountryRegionOrDefault(configs, userProfile.getCountryCode())
.filter(region -> countryCodeAliasSupport.containsCode(region.getCountryCodes(), );
userProfile.getCountryCode()))
.findFirst().orElse(null);
UserRegionDTO userRegion = createUserRegionDTO(userProfile, regionConfig);
if (Objects.nonNull(userRegion)) {
userRegions.add(userRegion);
continue;
}
}
// 2.2 语言匹配
String langeCode = userProfileGateway.getLanguage(userProfile.getId());
if (StringUtils.isNotBlank(langeCode)) {
SysRegionConfig regionConfig = configs.stream()
.filter(region -> StringUtils.containsIgnoreCase(region.getLangeCodes(),
langeCode.toLowerCase())
).findFirst().orElse(null);
UserRegionDTO userRegion = createUserRegionDTO(userProfile,
regionConfig);
if (Objects.nonNull(userRegion)) {
userRegions.add(userRegion);
continue;
}
}
// 填充默认值
UserRegionDTO userRegion = createUserRegionDTO(userProfile,
getSysOriginDefaultRegion(configs));
if (Objects.nonNull(userRegion)) { if (Objects.nonNull(userRegion)) {
userRegions.add(userRegion); userRegions.add(userRegion);
} }
@ -275,6 +248,25 @@ public class UserRegionGatewayImpl implements UserRegionGateway {
return sysOriginRegionConf; return sysOriginRegionConf;
} }
private SysRegionConfig matchCountryRegionOrDefault(List<SysRegionConfig> configs, String countryCode) {
if (CollectionUtils.isEmpty(configs)) {
return null;
}
if (StringUtils.isNotBlank(countryCode)) {
SysRegionConfig matchedRegion = configs.stream()
.filter(region -> StringUtils.isNotBlank(region.getCountryCodes())
&& countryCodeAliasSupport.containsCode(region.getCountryCodes(), countryCode))
.findFirst()
.orElse(null);
if (Objects.nonNull(matchedRegion)) {
return matchedRegion;
}
}
return getSysOriginDefaultRegion(configs);
}
/** /**
* 检查两个用户在业务分区是否一致. * 检查两个用户在业务分区是否一致.
* <p>在一些特效情况下 运营对当前区域进行整合 阿拉伯+土耳其可以互相访问</p> * <p>在一些特效情况下 运营对当前区域进行整合 阿拉伯+土耳其可以互相访问</p>
@ -903,41 +895,13 @@ public class UserRegionGatewayImpl implements UserRegionGateway {
Map<Long, SysRegionConfig> resultMap = Maps.newHashMap(); Map<Long, SysRegionConfig> resultMap = Maps.newHashMap();
for (UserProfile userProfile : userProfiles) { for (UserProfile userProfile : userProfiles) {
resultMap.put(
if (StringUtils.isNotBlank(userProfile.getCountryCode())) { userProfile.getId(),
matchCountryRegionOrDefault(configs, userProfile.getCountryCode())
SysRegionConfig sysRegionConfig = configs.stream() );
.filter(region -> StringUtils.isNotBlank(region.getCountryCodes())
&& StringUtils.isNotBlank(userProfile.getCountryCode())
&& countryCodeAliasSupport.containsCode(region.getCountryCodes(),
userProfile.getCountryCode())).findFirst()
.orElse(null);
if (Objects.nonNull(sysRegionConfig)) {
resultMap.put(userProfile.getId(), sysRegionConfig);
continue;
}
}
String langeCode = getLanguage(userProfile.getId());
if (StringUtils.isBlank(langeCode)) {
resultMap.put(userProfile.getId(), getSysOriginDefaultRegion(configs));
continue;
}
resultMap.put(userProfile.getId(), configs.stream()
.filter(region -> StringUtils.isNotBlank(region.getLangeCodes())
&& StringUtils.isNotBlank(langeCode)
&& region.getLangeCodes().toLowerCase()
.contains(langeCode.toLowerCase())).findFirst()
.orElse(getSysOriginDefaultRegion(configs)));
} }
return resultMap; return resultMap;
} }
private String getLanguage(Long userId) {
return userProfileGateway.getLanguage(userId);
}
} }

View File

@ -0,0 +1,111 @@
package com.red.circle.other.infra.gateway.user;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.anyMap;
import static org.mockito.Mockito.mock;
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.domain.model.user.ability.RegionConfig;
import com.red.circle.other.infra.common.sys.CountryCodeAliasSupport;
import com.red.circle.other.infra.convertor.user.UserRegionInfraConvertor;
import com.red.circle.other.infra.database.cache.service.user.SysRegionCacheService;
import com.red.circle.other.infra.database.cache.service.user.UserRegionCacheService;
import com.red.circle.other.infra.database.mongo.entity.user.region.SysRegionConfig;
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.mongo.service.user.region.SysRegionAssistConfigService;
import com.red.circle.other.infra.database.mongo.service.user.region.SysRegionConfigService;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class UserRegionGatewayImplTest {
private static final long USER_ID = 2047206645188063233L;
private static final String SYS_ORIGIN = "LIKEI";
private TeamMemberService teamMemberService;
private TeamProfileService teamProfileService;
private UserProfileGateway userProfileGateway;
private SysRegionCacheService sysRegionCacheService;
private SysRegionConfigService sysRegionConfigService;
private UserRegionInfraConvertor userRegionInfraConvertor;
private UserRegionGatewayImpl userRegionGateway;
@BeforeEach
void setUp() {
teamMemberService = mock(TeamMemberService.class);
teamProfileService = mock(TeamProfileService.class);
userProfileGateway = mock(UserProfileGateway.class);
sysRegionCacheService = mock(SysRegionCacheService.class);
sysRegionConfigService = mock(SysRegionConfigService.class);
userRegionInfraConvertor = mock(UserRegionInfraConvertor.class);
SysRegionAssistConfigService sysRegionAssistConfigService = mock(SysRegionAssistConfigService.class);
UserRegionCacheService userRegionCacheService = mock(UserRegionCacheService.class);
CountryCodeAliasSupport countryCodeAliasSupport = mock(CountryCodeAliasSupport.class);
userRegionGateway = new UserRegionGatewayImpl(
teamMemberService,
teamProfileService,
userProfileGateway,
sysRegionCacheService,
sysRegionConfigService,
userRegionInfraConvertor,
sysRegionAssistConfigService,
userRegionCacheService,
countryCodeAliasSupport
);
when(teamMemberService.listByMemberIds(Set.of(USER_ID))).thenReturn(List.of());
when(sysRegionCacheService.getCache(SYS_ORIGIN)).thenReturn(List.of(
region("SA", "IN,BD", "en,hi"),
region("OTHER", "", "")
));
when(userProfileGateway.listByUserIds(Set.of(USER_ID))).thenReturn(List.of(
new UserProfile().setId(USER_ID).setOriginSys(SYS_ORIGIN).setCountryCode("JP")
));
when(countryCodeAliasSupport.containsCode("IN,BD", "JP")).thenReturn(false);
}
@Test
void mapRegionCode_shouldFallbackToOtherWhenCountryDoesNotMatchEvenIfLanguageWouldMatch() {
Map<Long, String> result = userRegionGateway.mapRegionCode(Set.of(USER_ID));
assertEquals(Map.of(USER_ID, "OTHER"), result);
verify(userProfileGateway, never()).getLanguage(USER_ID);
}
@Test
void mapUserRegionConfig_shouldFallbackToOtherWhenCountryDoesNotMatchEvenIfLanguageWouldMatch() {
when(userRegionInfraConvertor.toMapRegionConfig(anyMap())).thenAnswer(invocation -> {
Map<Long, SysRegionConfig> regionMap = invocation.getArgument(0);
Map<Long, RegionConfig> result = new LinkedHashMap<>();
regionMap.forEach((userId, regionConfig) -> result.put(
userId,
new RegionConfig().setId(regionConfig.getId()).setRegionCode(regionConfig.getRegionCode())
));
return result;
});
Map<Long, RegionConfig> result = userRegionGateway.mapUserRegionConfig(SYS_ORIGIN, Set.of(USER_ID));
assertEquals("OTHER", result.get(USER_ID).getRegionCode());
verify(userProfileGateway, never()).getLanguage(USER_ID);
}
private SysRegionConfig region(String regionCode, String countryCodes, String langeCodes) {
return new SysRegionConfig()
.setId(regionCode)
.setSysOrigin(SYS_ORIGIN)
.setRegionCode(regionCode)
.setCountryCodes(countryCodes)
.setLangeCodes(langeCodes);
}
}

View File

@ -59,6 +59,13 @@ public class RoomManagerClientEndpoint implements RoomManagerClientApi {
return ResultResponse.success(roomManagerClientService.getRoomProfileManagerById(roomId)); return ResultResponse.success(roomManagerClientService.getRoomProfileManagerById(roomId));
} }
@Override
public ResultResponse<RoomProfileManagerDTO> getRoomProfileManagerByRoomAccount(
String roomAccount) {
return ResultResponse.success(
roomManagerClientService.getRoomProfileManagerByRoomAccount(roomAccount));
}
@Override @Override
public ResultResponse<RoomProfileDTO> getById(Long roomId) { public ResultResponse<RoomProfileDTO> getById(Long roomId) {
return ResultResponse.success(roomManagerClientService.getById(roomId)); return ResultResponse.success(roomManagerClientService.getById(roomId));

View File

@ -40,6 +40,11 @@ public interface RoomManagerClientService {
*/ */
RoomProfileManagerDTO getRoomProfileManagerById(Long roomId); RoomProfileManagerDTO getRoomProfileManagerById(Long roomId);
/**
* 通过房间账号获取资料详情.
*/
RoomProfileManagerDTO getRoomProfileManagerByRoomAccount(String roomAccount);
/** /**
* 获取房间资料-详情. * 获取房间资料-详情.
*/ */

View File

@ -60,6 +60,12 @@ public class RoomManagerClientServiceImpl implements RoomManagerClientService {
roomProfileManagerService.getById(roomId)); roomProfileManagerService.getById(roomId));
} }
@Override
public RoomProfileManagerDTO getRoomProfileManagerByRoomAccount(String roomAccount) {
return roomProfileInnerConvertor.toRoomProfileManagerDTO(
roomProfileManagerService.getByRoomAccount(roomAccount));
}
@Override @Override
public RoomProfileDTO getById(Long roomId) { public RoomProfileDTO getById(Long roomId) {
return roomProfileInnerConvertor.toRoomProfileManagerDTO( return roomProfileInnerConvertor.toRoomProfileManagerDTO(

View File

@ -0,0 +1,42 @@
package com.red.circle.other.app.inner.service.live.impl;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.red.circle.other.app.inner.convertor.live.RoomProfileInnerConvertor;
import com.red.circle.other.infra.database.cache.service.other.RoomManagerCacheService;
import com.red.circle.other.infra.database.mongo.entity.live.RoomProfileManager;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.inner.model.dto.live.RoomProfileManagerDTO;
import org.junit.jupiter.api.Test;
class RoomManagerClientServiceImplTest {
@Test
void getRoomProfileManagerByRoomAccountShouldConvertProfile() {
RoomManagerCacheService roomManagerCacheService = mock(RoomManagerCacheService.class);
RoomProfileInnerConvertor roomProfileInnerConvertor = mock(RoomProfileInnerConvertor.class);
RoomProfileManagerService roomProfileManagerService = mock(RoomProfileManagerService.class);
RoomManagerClientServiceImpl service = new RoomManagerClientServiceImpl(
roomManagerCacheService,
roomProfileInnerConvertor,
roomProfileManagerService
);
RoomProfileManager roomProfileManager = new RoomProfileManager();
RoomProfileManagerDTO roomProfileManagerDTO = new RoomProfileManagerDTO();
when(roomProfileManagerService.getByRoomAccount("1001417")).thenReturn(roomProfileManager);
when(roomProfileInnerConvertor.toRoomProfileManagerDTO(roomProfileManager))
.thenReturn(roomProfileManagerDTO);
RoomProfileManagerDTO result = service.getRoomProfileManagerByRoomAccount("1001417");
assertSame(roomProfileManagerDTO, result);
verify(roomProfileManagerService).getByRoomAccount("1001417");
verify(roomProfileInnerConvertor).toRoomProfileManagerDTO(roomProfileManager);
}
}