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

View File

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

View File

@ -15,12 +15,18 @@
<artifactId>external-application</artifactId>
</dependency>
<dependency>
<groupId>com.red.circle</groupId>
<artifactId>external-inner-api</artifactId>
</dependency>
</dependencies>
<dependency>
<groupId>com.red.circle</groupId>
<artifactId>external-inner-api</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<parent>
<artifactId>rc-service-external</artifactId>

View File

@ -1,28 +1,31 @@
package com.red.circle.external.inner.service.message.impl;
import com.alibaba.fastjson.JSON;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
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.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.param.CreateGroupParam;
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.CreateGroupAddMemberCmd;
import com.red.circle.external.inner.model.cmd.message.CreateGroupCmd;
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.GroupUnbanCmd;
import com.red.circle.external.inner.service.message.ImGroupClientService;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.http.RcHttpClient;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.util.Map;
import com.alibaba.fastjson.JSON;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
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.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.param.CreateGroupParam;
import com.red.circle.framework.core.asserts.ResponseAssert;
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.CreateGroupAddMemberCmd;
import com.red.circle.external.inner.model.cmd.message.CreateGroupCmd;
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.GroupUnbanCmd;
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.http.RcHttpClient;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.util.Map;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -38,10 +41,11 @@ import org.springframework.stereotype.Service;
@RequiredArgsConstructor
public class ImGroupClientServiceImpl implements ImGroupClientService {
private final RcMessageProperties rcMessageProperties;
private final ImGroupMemberService imGroupMemberService;
private final ImGroupMessageService imGroupMessageService;
private final ImGroupManagerService imGroupManagerService;
private final RcMessageProperties rcMessageProperties;
private final ImGroupMemberService imGroupMemberService;
private final ImGroupMessageService imGroupMessageService;
private final ImGroupManagerService imGroupManagerService;
private final RoomManagerClient roomManagerClient;
@Override
@ -93,25 +97,30 @@ public class ImGroupClientServiceImpl implements ImGroupClientService {
}
int newRetrySize = retrySize - 1;
imGroupMessageService.sendCustomMessage(groupId.trim(), cmd)
.subscribe(res -> {
if (TencentIMStatusUtils.isSuccess(res)) {
return;
}
JsonObject jsonObject = JsonParser.parseString(res).getAsJsonObject();
if (Objects.nonNull(jsonObject) && Objects
.equals(jsonObject.get("ErrorCode").getAsInt(), 80002)) {
log.warn("sendCustomMessage 80002 groupId={}, res={}", groupId,
JacksonUtils.toJson(res));
return;
}
log.warn("sendCustomMessage retry: {}, {}", newRetrySize, JacksonUtils.toJson(res));
sendCustomMessage(groupId, cmd, newRetrySize);
}, er -> {
log.warn("sendCustomMessage fail: {}-{}", groupId, JacksonUtils.toJson(er));
imGroupMessageService.sendCustomMessage(groupId.trim(), cmd)
.subscribe(res -> {
if (TencentIMStatusUtils.isSuccess(res)) {
return;
}
Integer errorCode = parseErrorCode(res);
if (Objects.equals(errorCode, 80002)) {
log.warn("sendCustomMessage 80002 groupId={}, res={}", groupId,
JacksonUtils.toJson(res));
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));
sendCustomMessage(groupId, cmd, newRetrySize);
}, er -> {
log.warn("sendCustomMessage fail: {}-{}", groupId, JacksonUtils.toJson(er));
sendCustomMessage(groupId, cmd, newRetrySize);
});
}
@ -176,8 +185,51 @@ public class ImGroupClientServiceImpl implements ImGroupClientService {
}
@Override
public void destroyGroup(String groupId) {
imGroupManagerService.destroyGroup(groupId).subscribe();
}
}
public void destroyGroup(String groupId) {
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

@ -5,9 +5,9 @@ import com.red.circle.common.business.enums.OperationUserOrigin;
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.enums.message.OfficialNoticeTypeEnum;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.framework.core.response.ResponseErrorCode;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.framework.core.response.ResponseErrorCode;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.app.dto.clientobject.team.BdInviteMessageCO;
import com.red.circle.other.app.dto.cmd.team.*;
@ -26,11 +26,11 @@ import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentBa
import com.red.circle.other.infra.database.rds.entity.team.BusinessDevelopmentTeam;
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.team.TeamErrorCode;
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.TeamMemberRole;
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.user.UserErrorCode;
import com.red.circle.other.inner.enums.team.TeamApplicationProcessStatus;
import com.red.circle.other.inner.enums.team.TeamMemberRole;
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.MapBuilder;
import com.red.circle.tool.core.date.TimestampUtils;
@ -51,10 +51,11 @@ public class AgentInviteHostExe {
private final UserProfileGateway userProfileGateway;
private final TeamMemberService teamMemberService;
private final TeamProfileService teamProfileService;
private final OfficialNoticeClient officialNoticeClient;
private final RegisterDeviceGateway registerDeviceGateway;
private final UserProfileAppConvertor userProfileAppConvertor;
private final BdInviteAgentMessageService bdInviteAgentMessageService;
private final OfficialNoticeClient officialNoticeClient;
private final RegisterDeviceGateway registerDeviceGateway;
private final TeamHandleUserApplyExe teamHandleUserApplyExe;
private final UserProfileAppConvertor userProfileAppConvertor;
private final BdInviteAgentMessageService bdInviteAgentMessageService;
public void execute(AgentInviteHostCmd cmd) {
// 检查权限
@ -147,6 +148,10 @@ public class AgentInviteHostExe {
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR, cmd.getStatus() > 0);
BdInviteAgentMessage message = bdInviteAgentMessageService.getById(cmd.getId());
if (message == null) {
processTeamApply(cmd);
return;
}
ResponseAssert.notNull(CommonErrorCode.NOT_FOUND_RECORD_INFO, message);
ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE, message.getStatus() == 0);
@ -194,12 +199,35 @@ public class AgentInviteHostExe {
sendMessage(message, OfficialNoticeTypeEnum.AGREE_AGENT_INVITE_HOST);
return;
}
sendMessage(message, OfficialNoticeTypeEnum.REFUSE_AGENT_INVITE_HOST);
}
private void sendMessage(BdInviteAgentMessage message, OfficialNoticeTypeEnum noticeTypeEnum) {
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) {
UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(
userProfileGateway.getByUserId(message.getInviteUserId()));
ResponseAssert.notNull(UserErrorCode.USER_INFO_NOT_FOUND, userProfile);

View File

@ -1,40 +1,38 @@
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.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.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
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.util.OfficialNoticeUtils;
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.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.TeamProfile;
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.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.user.device.LatestMobileDeviceService;
import com.red.circle.other.inner.asserts.user.UserErrorCode;
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.asserts.team.TeamErrorCode;
import com.red.circle.other.inner.model.dto.agency.agency.TeamStatus;
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.TeamApplicationType;
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.sequence.IdWorkerUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import java.util.List;
import java.util.Map;
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.enums.team.TeamAppProcessReason;
import com.red.circle.other.inner.enums.team.TeamApplicationProcessStatus;
import com.red.circle.other.inner.enums.team.TeamApplicationType;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.text.StringUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@ -46,11 +44,11 @@ import org.springframework.stereotype.Component;
*
* @author pengshigang on 2022/12/20
*/
@Component
@RequiredArgsConstructor
@Component
@RequiredArgsConstructor
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 UserRegionGateway userRegionGateway;
@ -62,9 +60,8 @@ public class TeamUserApplyJoinExe {
private final LatestMobileDeviceService latestMobileDeviceService;
private final TeamApplicationProcessService teamApplicationProcessService;
private final RegisterDeviceGateway registerDeviceGateway;
private final EnumConfigCacheService enumConfigCacheService;
public String execute(TeamUserApplyCmd cmd) {
public String execute(TeamUserApplyCmd cmd) {
UserProfileDTO userProfile = userProfileAppConvertor.toUserProfileDTO(
userProfileGateway.getByUserId(cmd.getReqUserId()));
@ -110,14 +107,14 @@ public class TeamUserApplyJoinExe {
.setStatus(TeamApplicationProcessStatus.WAIT)
.setCreateTime(TimestampUtils.now())
.setCreateUser(cmd.getReqUserId())
.setCreateUserOrigin(OperationUserOrigin.APP.getValue())
.setExpiredTime(TimestampUtils.nowPlusDays(60))
);
sendMessage(cmd, teamProfile);
return Objects.toString(messageId);
}
.setCreateUserOrigin(OperationUserOrigin.APP.getValue())
.setExpiredTime(TimestampUtils.nowPlusDays(60))
);
sendMessage(cmd, teamProfile, messageId);
return Objects.toString(messageId);
}
private void checkApply(TeamUserApplyCmd cmd, TeamProfile teamProfile) {
@ -165,31 +162,19 @@ public class TeamUserApplyJoinExe {
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(
userProfileGateway.getByUserId(cmd.requiredReqUserId())
);
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 =
NoticeExtTemplateTypeCmd.builder()
.toAccount(teamProfile.getOwnUserId())
.noticeType(OfficialNoticeTypeEnum.USER_SEND_APPLY_TEAM)
.templateParam(MapBuilder.builder()
.put("userProfile", String.format("%s(%s)", userProfile.getUserNickname(),
userProfile.actualAccount()))
.build());
if (StringUtils.isNotBlank(expand)) {
builder.expand(expand);
}
officialNoticeClient.send(builder.build());
officialNoticeClient.send(NoticeExtTemplateCustomizeCmd.builder()
.toAccount(teamProfile.getOwnUserId())
.noticeType(OfficialNoticeTypeEnum.AGENT_SEND_INVITE_HOST)
.title(TEAM_APPLY_NOTICE_TITLE)
.content(JSON.toJSONString(OfficialNoticeUtils.buildUserProfile(userProfile)))
.expand(Objects.toString(messageId))
.build());
}
}

View File

@ -113,7 +113,8 @@ public class UpdateUserProfileCmdExe {
// 计算年龄
processAge(updateUserProfile);
processCountry(cmd, userProfile);
processCountry(cmd, userProfile);
syncCountry(updateUserProfile, userProfile);
// 处理照片状态
processPhotoStatus(updateUserProfile.getBackgroundPhotos(), userProfile.getBackgroundPhotos());
@ -147,14 +148,29 @@ public class UpdateUserProfileCmdExe {
return userProfileAppConvertor.toUserProfileDTO(userProfile);
}
private void updateBaseInfo(UserProfileModifyCmd cmd, UserProfile userProfile) {
BaseInfo baseInfo = new BaseInfo();
baseInfo.setId(cmd.requiredReqUserId());
baseInfo.setCountryId(userProfile.getCountryId());
baseInfo.setCountryCode(userProfile.getCountryCode());
private void updateBaseInfo(UserProfileModifyCmd cmd, UserProfile userProfile) {
BaseInfo baseInfo = new BaseInfo();
baseInfo.setId(cmd.requiredReqUserId());
baseInfo.setCountryId(userProfile.getCountryId());
baseInfo.setCountryCode(userProfile.getCountryCode());
baseInfo.setCountryName(userProfile.getCountryName());
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) {
List<ProfileApprovalContent> approvalParam = CollectionUtils.newArrayList();

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,40 +184,13 @@ public class UserRegionGatewayImpl implements UserRegionGateway {
continue;
}
// 2.1 国家匹配
if (StringUtils.isNotBlank(userProfile.getCountryCode())) {
SysRegionConfig regionConfig = configs.stream()
.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)) {
userRegions.add(userRegion);
}
UserRegionDTO userRegion = createUserRegionDTO(
userProfile,
matchCountryRegionOrDefault(configs, userProfile.getCountryCode())
);
if (Objects.nonNull(userRegion)) {
userRegions.add(userRegion);
}
}
return userRegions;
}
@ -258,7 +231,7 @@ public class UserRegionGatewayImpl implements UserRegionGateway {
return null;
}
private Map<String, List<SysRegionConfig>> mapOriginSysRegionConfigs(List<UserProfile> userProfiles) {
private Map<String, List<SysRegionConfig>> mapOriginSysRegionConfigs(List<UserProfile> userProfiles) {
Set<String> allSysOrigin = userProfiles.stream().map(UserProfile::getOriginSys).collect(Collectors.toSet());
@ -272,8 +245,27 @@ public class UserRegionGatewayImpl implements UserRegionGateway {
).orElseGet(CollectionUtils::newArrayList);
sysOriginRegionConf.put(sysOrigin, configs);
}
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);
}
/**
* 检查两个用户在业务分区是否一致.
@ -901,43 +893,15 @@ public class UserRegionGatewayImpl implements UserRegionGateway {
return Maps.newHashMap();
}
Map<Long, SysRegionConfig> resultMap = Maps.newHashMap();
for (UserProfile userProfile : userProfiles) {
if (StringUtils.isNotBlank(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;
}
private String getLanguage(Long userId) {
return userProfileGateway.getLanguage(userId);
}
}
Map<Long, SysRegionConfig> resultMap = Maps.newHashMap();
for (UserProfile userProfile : userProfiles) {
resultMap.put(
userProfile.getId(),
matchCountryRegionOrDefault(configs, userProfile.getCountryCode())
);
}
return resultMap;
}
}

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

@ -55,14 +55,21 @@ public class RoomManagerClientEndpoint implements RoomManagerClientApi {
}
@Override
public ResultResponse<RoomProfileManagerDTO> getRoomProfileManagerById(Long roomId) {
return ResultResponse.success(roomManagerClientService.getRoomProfileManagerById(roomId));
}
@Override
public ResultResponse<RoomProfileDTO> getById(Long roomId) {
return ResultResponse.success(roomManagerClientService.getById(roomId));
}
public ResultResponse<RoomProfileManagerDTO> getRoomProfileManagerById(Long roomId) {
return ResultResponse.success(roomManagerClientService.getRoomProfileManagerById(roomId));
}
@Override
public ResultResponse<RoomProfileManagerDTO> getRoomProfileManagerByRoomAccount(
String roomAccount) {
return ResultResponse.success(
roomManagerClientService.getRoomProfileManagerByRoomAccount(roomAccount));
}
@Override
public ResultResponse<RoomProfileDTO> getById(Long roomId) {
return ResultResponse.success(roomManagerClientService.getById(roomId));
}
@Override
public ResultResponse<List<RoomProfileDTO>> listByIds(Set<Long> userIds) {

View File

@ -35,15 +35,20 @@ public interface RoomManagerClientService {
*/
RoomProfileDTO getProfileById(Long roomId);
/**
* 获取资料详情.
*/
RoomProfileManagerDTO getRoomProfileManagerById(Long roomId);
/**
* 获取房间资料-详情.
*/
RoomProfileDTO getById(Long roomId);
/**
* 获取资料详情.
*/
RoomProfileManagerDTO getRoomProfileManagerById(Long roomId);
/**
* 通过房间账号获取资料详情.
*/
RoomProfileManagerDTO getRoomProfileManagerByRoomAccount(String roomAccount);
/**
* 获取房间资料-详情.
*/
RoomProfileDTO getById(Long roomId);
/**
* 获取房间计数器.

View File

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

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);
}
}