修复一些问题

This commit is contained in:
hy001 2026-05-23 14:54:40 +08:00
parent fa6b9be148
commit 5359be337d
19 changed files with 504 additions and 97 deletions

View File

@ -29,6 +29,8 @@ public class CustomC2cMsgBodyCmd extends Command {
@NotNull(message = "data required.")
private Object data;
private Integer syncOtherMachine;
public static CustomC2cMsgBodyBuilder builder() {
return new CustomC2cMsgBodyBuilder();
}
@ -39,6 +41,7 @@ public class CustomC2cMsgBodyCmd extends Command {
private String toAccount;
private String desc;
private Object data;
private Integer syncOtherMachine;
public CustomC2cMsgBodyBuilder fromAccount(String fromAccount) {
this.fromAccount = fromAccount;
@ -70,12 +73,18 @@ public class CustomC2cMsgBodyCmd extends Command {
return this;
}
public CustomC2cMsgBodyBuilder syncOtherMachine(Integer syncOtherMachine) {
this.syncOtherMachine = syncOtherMachine;
return this;
}
public CustomC2cMsgBodyCmd build() {
CustomC2cMsgBodyCmd cmd = new CustomC2cMsgBodyCmd();
cmd.setFromAccount(this.fromAccount);
cmd.setToAccount(this.toAccount);
cmd.setDesc(this.desc);
cmd.setData(this.data);
cmd.setSyncOtherMachine(this.syncOtherMachine);
return cmd;
}
}

View File

@ -32,6 +32,7 @@ public class ImMessageClientServiceImpl implements ImMessageClientService {
@Override
public void sendCustomMessage(CustomC2cMsgBodyCmd cmd) {
ImMessageParam param = ImMessageParam.builder()
.syncOtherMachine(cmd.getSyncOtherMachine())
.fromAccount(cmd.getFromAccount())
.toAccount(cmd.getToAccount())
.offlinePushInfo(OfflinePushInfo.builder()

View File

@ -10,6 +10,7 @@ import com.red.circle.other.domain.model.cp.loveletter.LoveLetterWallCO;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyIdQueryCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyDismissCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyStatusQueryCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpRelationshipQueryCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.ProcessApplyCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.loveletter.SendLoveLetterCmd;
@ -104,12 +105,25 @@ public class CpRelationshipRestController extends BaseController {
* @eo.method get
* @eo.request-type formdata
*/
@GetMapping("/apply-id")
@GetMapping("/apply-id")
public String getCpApplyId(@Validated CpApplyIdQueryCmd cmd) {
return userCpRelationService.getCpApplyId(cmd);
}
/**
/**
* 获取用户cp申请状态.
*
* @eo.name 获取用户cp申请状态.
* @eo.url /apply-status
* @eo.method get
* @eo.request-type formdata
*/
@GetMapping("/apply-status")
public String getCpApplyStatus(@Validated CpApplyStatusQueryCmd cmd) {
return userCpRelationService.getCpApplyStatus(cmd);
}
/**
* 发送CP告白信封.
*
* @eo.name 发送CP告白信封

View File

@ -126,6 +126,11 @@ public class ProcessCpApplyCmd {
imMessageClient.sendCustomMessage(agree
? CpRelationC2cNoticeUtils.buildAccepted(cpApply, senderProfile, acceptProfile)
: CpRelationC2cNoticeUtils.buildRejected(cpApply, senderProfile, acceptProfile));
imMessageClient.sendCustomMessage(agree
? CpRelationC2cNoticeUtils.buildAcceptedToAcceptUser(cpApply, senderProfile,
acceptProfile)
: CpRelationC2cNoticeUtils.buildRejectedToAcceptUser(cpApply, senderProfile,
acceptProfile));
} catch (Exception ex) {
log.warn("[CP] send process c2c notice failed, applyId={}, agree={}, reason={}",
cpApply.getId(), agree, ex.getMessage(), ex);

View File

@ -0,0 +1,23 @@
package com.red.circle.other.app.command.user.query;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyStatusQueryCmd;
import com.red.circle.other.infra.database.rds.entity.user.user.CpApply;
import com.red.circle.other.infra.database.rds.service.user.user.CpApplyService;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* CP apply status query.
*/
@Component
@RequiredArgsConstructor
public class CpApplyStatusQryExe {
private final CpApplyService cpApplyService;
public String execute(CpApplyStatusQueryCmd cmd) {
CpApply cpApply = cpApplyService.getById(cmd.getApplyId());
return Objects.nonNull(cpApply) ? cpApply.getStatus() : null;
}
}

View File

@ -39,6 +39,18 @@ public final class CpRelationC2cNoticeUtils {
public static CustomC2cMsgBodyCmd buildAccepted(CpApply cpApply, UserProfile senderProfile,
UserProfile acceptProfile) {
return buildAccepted(cpApply, senderProfile, acceptProfile, cpApply.getAcceptApplyUserId(),
cpApply.getSendApplyUserId());
}
public static CustomC2cMsgBodyCmd buildAcceptedToAcceptUser(CpApply cpApply,
UserProfile senderProfile, UserProfile acceptProfile) {
return buildAccepted(cpApply, senderProfile, acceptProfile, cpApply.getSendApplyUserId(),
cpApply.getAcceptApplyUserId());
}
private static CustomC2cMsgBodyCmd buildAccepted(CpApply cpApply, UserProfile senderProfile,
UserProfile acceptProfile, Long fromUserId, Long toUserId) {
String relationType = CpRelationshipType.normalize(cpApply.getRelationType());
String title = "User " + displayName(acceptProfile) + " accepted your "
+ relationType.toLowerCase() + " invitation.";
@ -52,11 +64,23 @@ public final class CpRelationC2cNoticeUtils {
payload.put("agree", true);
putSenderProfile(payload, senderProfile);
putAcceptProfile(payload, acceptProfile);
return buildMessage(cpApply.getAcceptApplyUserId(), cpApply.getSendApplyUserId(), payload);
return buildMessage(fromUserId, toUserId, payload);
}
public static CustomC2cMsgBodyCmd buildRejected(CpApply cpApply, UserProfile senderProfile,
UserProfile acceptProfile) {
return buildRejected(cpApply, senderProfile, acceptProfile, cpApply.getAcceptApplyUserId(),
cpApply.getSendApplyUserId());
}
public static CustomC2cMsgBodyCmd buildRejectedToAcceptUser(CpApply cpApply,
UserProfile senderProfile, UserProfile acceptProfile) {
return buildRejected(cpApply, senderProfile, acceptProfile, cpApply.getSendApplyUserId(),
cpApply.getAcceptApplyUserId());
}
private static CustomC2cMsgBodyCmd buildRejected(CpApply cpApply, UserProfile senderProfile,
UserProfile acceptProfile, Long fromUserId, Long toUserId) {
String relationType = CpRelationshipType.normalize(cpApply.getRelationType());
String title = "User " + displayName(acceptProfile) + " declined your "
+ relationType.toLowerCase() + " invitation.";
@ -70,7 +94,7 @@ public final class CpRelationC2cNoticeUtils {
payload.put("agree", false);
putSenderProfile(payload, senderProfile);
putAcceptProfile(payload, acceptProfile);
return buildMessage(cpApply.getAcceptApplyUserId(), cpApply.getSendApplyUserId(), payload);
return buildMessage(fromUserId, toUserId, payload);
}
public static CustomC2cMsgBodyCmd buildExpiredToAcceptUser(CpApply cpApply,
@ -127,11 +151,14 @@ public final class CpRelationC2cNoticeUtils {
.toAccount(toUserId)
.desc(NOTICE_TYPE)
.data(payload)
.syncOtherMachine(1)
.build();
}
private static Map<String, Object> senderContent(UserProfileDTO userProfile) {
Map<String, Object> content = new LinkedHashMap<>();
content.put("userId", userProfile.getId());
content.put("senderUserId", userProfile.getId());
content.put("userNickname", userProfile.getUserNickname());
content.put("account", userProfile.getAccount());
content.put("actualAccount", userProfile.actualAccount());
@ -143,6 +170,8 @@ public final class CpRelationC2cNoticeUtils {
private static Map<String, Object> senderContent(UserProfile userProfile) {
Map<String, Object> content = new LinkedHashMap<>();
content.put("userId", Objects.nonNull(userProfile) ? userProfile.getId() : null);
content.put("senderUserId", Objects.nonNull(userProfile) ? userProfile.getId() : null);
content.put("userNickname", Objects.nonNull(userProfile) ? userProfile.getUserNickname() : null);
content.put("account", Objects.nonNull(userProfile) ? userProfile.getAccount() : null);
content.put("actualAccount", Objects.nonNull(userProfile) ? userProfile.getActualAccount() : null);
@ -153,6 +182,8 @@ public final class CpRelationC2cNoticeUtils {
}
private static void putSenderProfile(Map<String, Object> payload, UserProfileDTO userProfile) {
payload.put("userId", userProfile.getId());
payload.put("senderUserId", userProfile.getId());
payload.put("account", userProfile.getAccount());
payload.put("actualAccount", userProfile.actualAccount());
payload.put("userNickname", userProfile.getUserNickname());
@ -163,6 +194,8 @@ public final class CpRelationC2cNoticeUtils {
if (Objects.isNull(userProfile)) {
return;
}
payload.put("userId", userProfile.getId());
payload.put("senderUserId", userProfile.getId());
payload.put("account", userProfile.getAccount());
payload.put("actualAccount", userProfile.getActualAccount());
payload.put("userNickname", userProfile.getUserNickname());

View File

@ -140,10 +140,8 @@ public class RankCountStrategy implements GiftStrategy {
// 新排行榜累计数据
accumulateNewRankingData(runningWater, giftRatio);
// cp
if (isCpGift(giftValue)) {
countCpValue(runningWater);
}
// 已建立关系后普通金币礼物也累计亲密值关系礼物自动申请逻辑仍在 GiftCountStrategy 中处理
countCpValue(runningWater);
// 首页排行榜
homeRank(runningWater, giftRatio);
@ -285,7 +283,8 @@ public class RankCountStrategy implements GiftStrategy {
}
private void countCpValue(GiftGiveRunningWater runningWater) {
List<CpRelationship> cpRelationshipList = cpRelationshipService.getByUserId(runningWater.getUserId());
List<CpRelationship> cpRelationshipList = cpRelationshipService.getByUserId(
runningWater.getUserId(), (String) null);
if (cpRelationshipList.isEmpty()) {
return;
}

View File

@ -7,8 +7,9 @@ import com.red.circle.other.app.command.user.LoveLetterQueryCmdExe;
import com.red.circle.other.app.command.user.ProcessCpApplyCmd;
import com.red.circle.other.app.command.user.SendCpApplyCmdExe;
import com.red.circle.other.app.command.user.SendLoveLetterCmdExe;
import com.red.circle.other.app.command.user.query.CpApplyIdQryExe;
import com.red.circle.other.app.command.user.query.UserCpPairUserProfileQryExe;
import com.red.circle.other.app.command.user.query.CpApplyIdQryExe;
import com.red.circle.other.app.command.user.query.CpApplyStatusQryExe;
import com.red.circle.other.app.command.user.query.UserCpPairUserProfileQryExe;
import com.red.circle.other.app.command.user.query.UserCpRelationQryExe;
import com.red.circle.other.app.command.user.query.UserCpRelationQueryV4Exe;
import com.red.circle.other.app.dto.clientobject.user.relation.cp.CpCabinUserProfileCO;
@ -16,6 +17,7 @@ import com.red.circle.other.app.dto.clientobject.user.relation.cp.CpDismissApply
import com.red.circle.other.app.dto.clientobject.user.relation.cp.CpPairUserProfileCO;
import com.red.circle.other.app.dto.clientobject.user.relation.cp.CpUserProfileCO;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyIdQueryCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyStatusQueryCmd;
import com.red.circle.other.domain.model.cp.loveletter.LoveLetterDetailCO;
import com.red.circle.other.domain.model.cp.loveletter.LoveLetterWallCO;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyCmd;
@ -39,8 +41,9 @@ import java.util.Objects;
@RequiredArgsConstructor
public class UserCpRelationServiceImpl implements UserCpRelationService {
private final CpApplyIdQryExe cpApplyIdQryExe;
private final SendCpApplyCmdExe sendCpApplyCmdExe;
private final CpApplyIdQryExe cpApplyIdQryExe;
private final CpApplyStatusQryExe cpApplyStatusQryExe;
private final SendCpApplyCmdExe sendCpApplyCmdExe;
private final ProcessCpApplyCmd processCpApplyCmd;
private final DismissCpApplyCmdExe dismissCpApplyCmdExe;
private final UserCpRelationQryExe userCpRelationQryExe;
@ -86,8 +89,13 @@ public class UserCpRelationServiceImpl implements UserCpRelationService {
public String getCpApplyId(CpApplyIdQueryCmd cmd) {
return cpApplyIdQryExe.execute(cmd);
}
@Override
@Override
public String getCpApplyStatus(CpApplyStatusQueryCmd cmd) {
return cpApplyStatusQryExe.execute(cmd);
}
@Override
public CpCabinUserProfileCO getCpUserV4(UserIdCommonCmd cmd) {
return userCpRelationQueryV4Exe.execute(cmd);
}

View File

@ -40,8 +40,8 @@ class ProcessCpApplyCmdTest {
nullable(Long.class), eq("LIKEI"), eq("BROTHER"));
verify(fixture.cpRelationBroadcastMqClient).publish("LIKEI", 3001L, 1001L, 2001L,
"BROTHER");
assertProcessMessage(fixture.sentCustomMessage(), "RELATION_ESTABLISHED", "ACCEPTED",
true, "BROTHER");
assertProcessMessagesToBothUsers(fixture.sentCustomMessages(2), 0,
"RELATION_ESTABLISHED", "ACCEPTED", true, "BROTHER", 3001L, 1001L, 2001L);
}
@Test
@ -54,8 +54,8 @@ class ProcessCpApplyCmdTest {
nullable(Long.class), eq("LIKEI"), eq("SISTERS"));
verify(fixture.cpRelationBroadcastMqClient).publish("LIKEI", 3001L, 1001L, 2001L,
"SISTERS");
assertProcessMessage(fixture.sentCustomMessage(), "RELATION_ESTABLISHED", "ACCEPTED",
true, "SISTERS");
assertProcessMessagesToBothUsers(fixture.sentCustomMessages(2), 0,
"RELATION_ESTABLISHED", "ACCEPTED", true, "SISTERS", 3001L, 1001L, 2001L);
}
@Test
@ -64,8 +64,8 @@ class ProcessCpApplyCmdTest {
fixture.exe.execute(processCmd(false));
assertProcessMessage(fixture.sentCustomMessage(), "RELATION_REJECTED", "REJECTED",
false, "CP");
assertProcessMessagesToBothUsers(fixture.sentCustomMessages(2), 0,
"RELATION_REJECTED", "REJECTED", false, "CP", 3001L, 1001L, 2001L);
}
@Test
@ -93,13 +93,13 @@ class ProcessCpApplyCmdTest {
fixture.exe.execute(processCmd(true));
verify(fixture.cpApplyService).refuseOtherWaitAppliesBetweenUsers(3001L, 1001L, 2001L);
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(3);
assertProcessMessage(messages.get(0), "RELATION_REJECTED", "REJECTED", false, "BROTHER",
3002L);
assertProcessMessage(messages.get(1), "RELATION_REJECTED", "REJECTED", false, "SISTERS",
3003L);
assertProcessMessage(messages.get(2), "RELATION_ESTABLISHED", "ACCEPTED", true, "CP",
3001L);
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(6);
assertProcessMessagesToBothUsers(messages, 0, "RELATION_REJECTED", "REJECTED", false,
"BROTHER", 3002L, 1001L, 2001L);
assertProcessMessagesToBothUsers(messages, 2, "RELATION_REJECTED", "REJECTED", false,
"SISTERS", 3003L, 1001L, 2001L);
assertProcessMessagesToBothUsers(messages, 4, "RELATION_ESTABLISHED", "ACCEPTED", true,
"CP", 3001L, 1001L, 2001L);
}
@Test
@ -118,17 +118,17 @@ class ProcessCpApplyCmdTest {
fixture.exe.execute(processCmd(true));
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(5);
assertProcessMessage(messages.get(0), "RELATION_REJECTED", "REJECTED", false, "BROTHER",
3002L);
assertProcessMessage(messages.get(1), "RELATION_REJECTED", "REJECTED", false, "SISTERS",
3003L);
assertProcessMessage(messages.get(2), "RELATION_REJECTED", "REJECTED", false, "CP",
3004L, "4001", "1001");
assertProcessMessage(messages.get(3), "RELATION_REJECTED", "REJECTED", false, "CP",
3005L, "4002", "1001");
assertProcessMessage(messages.get(4), "RELATION_ESTABLISHED", "ACCEPTED", true, "CP",
3001L);
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(10);
assertProcessMessagesToBothUsers(messages, 0, "RELATION_REJECTED", "REJECTED", false,
"BROTHER", 3002L, 1001L, 2001L);
assertProcessMessagesToBothUsers(messages, 2, "RELATION_REJECTED", "REJECTED", false,
"SISTERS", 3003L, 1001L, 2001L);
assertProcessMessagesToBothUsers(messages, 4, "RELATION_REJECTED", "REJECTED", false,
"CP", 3004L, 1001L, 4001L);
assertProcessMessagesToBothUsers(messages, 6, "RELATION_REJECTED", "REJECTED", false,
"CP", 3005L, 1001L, 4002L);
assertProcessMessagesToBothUsers(messages, 8, "RELATION_ESTABLISHED", "ACCEPTED", true,
"CP", 3001L, 1001L, 2001L);
}
@Test
@ -145,13 +145,13 @@ class ProcessCpApplyCmdTest {
fixture.exe.execute(processCmd(true));
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(3);
assertProcessMessage(messages.get(0), "RELATION_REJECTED", "REJECTED", false, "CP",
3002L, "4001", "1001");
assertProcessMessage(messages.get(1), "RELATION_REJECTED", "REJECTED", false, "CP",
3003L, "4002", "1001");
assertProcessMessage(messages.get(2), "RELATION_ESTABLISHED", "ACCEPTED", true, "CP",
3001L);
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(6);
assertProcessMessagesToBothUsers(messages, 0, "RELATION_REJECTED", "REJECTED", false,
"CP", 3002L, 1001L, 4001L);
assertProcessMessagesToBothUsers(messages, 2, "RELATION_REJECTED", "REJECTED", false,
"CP", 3003L, 1001L, 4002L);
assertProcessMessagesToBothUsers(messages, 4, "RELATION_ESTABLISHED", "ACCEPTED", true,
"CP", 3001L, 1001L, 2001L);
}
@Test
@ -164,8 +164,8 @@ class ProcessCpApplyCmdTest {
verify(fixture.cpApplyService, never()).refuseWaitAppliesByUserAndRelation(
any(Long.class), eq(1001L), eq("BROTHER"));
assertProcessMessage(fixture.sentCustomMessage(), "RELATION_ESTABLISHED", "ACCEPTED",
true, "BROTHER");
assertProcessMessagesToBothUsers(fixture.sentCustomMessages(2), 0,
"RELATION_ESTABLISHED", "ACCEPTED", true, "BROTHER", 3001L, 1001L, 2001L);
}
@Test
@ -182,13 +182,13 @@ class ProcessCpApplyCmdTest {
fixture.exe.execute(processCmd(true));
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(3);
assertProcessMessage(messages.get(0), "RELATION_REJECTED", "REJECTED", false, "BROTHER",
3002L, "4001", "1001");
assertProcessMessage(messages.get(1), "RELATION_REJECTED", "REJECTED", false, "BROTHER",
3003L, "4002", "1001");
assertProcessMessage(messages.get(2), "RELATION_ESTABLISHED", "ACCEPTED", true, "BROTHER",
3001L);
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(6);
assertProcessMessagesToBothUsers(messages, 0, "RELATION_REJECTED", "REJECTED", false,
"BROTHER", 3002L, 1001L, 4001L);
assertProcessMessagesToBothUsers(messages, 2, "RELATION_REJECTED", "REJECTED", false,
"BROTHER", 3003L, 1001L, 4002L);
assertProcessMessagesToBothUsers(messages, 4, "RELATION_ESTABLISHED", "ACCEPTED", true,
"BROTHER", 3001L, 1001L, 2001L);
}
private static ProcessApplyCmd processCmd(boolean agree) {
@ -251,6 +251,15 @@ class ProcessCpApplyCmdTest {
.contains("\"relationType\":\"" + relationType + "\""));
}
private static void assertProcessMessagesToBothUsers(List<CustomC2cMsgBodyCmd> messages,
int startIndex, String action, String status, Boolean agree, String relationType,
Long applyId, Long sendUserId, Long acceptUserId) {
assertProcessMessage(messages.get(startIndex), action, status, agree, relationType, applyId,
String.valueOf(acceptUserId), String.valueOf(sendUserId));
assertProcessMessage(messages.get(startIndex + 1), action, status, agree, relationType,
applyId, String.valueOf(sendUserId), String.valueOf(acceptUserId));
}
private static class Fixture {
private final CpApplyService cpApplyService = mock(CpApplyService.class);

View File

@ -10,6 +10,7 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.fasterxml.jackson.core.type.TypeReference;
import com.red.circle.external.inner.endpoint.message.ImMessageClient;
import com.red.circle.external.inner.model.cmd.message.CustomC2cMsgBodyCmd;
import com.red.circle.framework.dto.ResultResponse;
@ -24,6 +25,7 @@ import com.red.circle.other.infra.database.rds.entity.user.user.CpApply;
import com.red.circle.other.infra.database.rds.service.user.user.CpApplyService;
import com.red.circle.other.infra.database.rds.service.user.user.CpRelationshipService;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import java.sql.Timestamp;
import java.util.List;
@ -100,13 +102,20 @@ class SendCpApplyCmdExeTest {
private static void assertCpBuildMessage(CustomC2cMsgBodyCmd message, String relationType,
Long applyId) {
assertEquals("CP_BUILD", message.getDesc());
assertEquals(1, message.getSyncOtherMachine());
Map<String, Object> data = (Map<String, Object>) message.getData();
assertEquals("CP_BUILD", data.get("noticeType"));
assertEquals("CP_BUILD", data.get("type"));
assertEquals(applyId, data.get("expand"));
assertEquals(applyId, data.get("applyId"));
assertEquals(1001L, data.get("userId"));
assertEquals(1001L, data.get("senderUserId"));
assertEquals(relationType, data.get("relationType"));
assertTrue(data.get("content").toString().contains("\"relationType\":\"" + relationType + "\""));
Map<String, Object> content = JacksonUtils.readValue(data.get("content").toString(),
new TypeReference<>() {});
assertEquals("1001", content.get("userId"));
assertEquals("1001", content.get("senderUserId"));
assertEquals(relationType, content.get("relationType"));
}
@Test

View File

@ -0,0 +1,38 @@
package com.red.circle.other.app.command.user.query;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyStatusQueryCmd;
import com.red.circle.other.infra.database.rds.entity.user.user.CpApply;
import com.red.circle.other.infra.database.rds.service.user.user.CpApplyService;
import org.junit.jupiter.api.Test;
class CpApplyStatusQryExeTest {
@Test
void shouldReturnCurrentApplyStatusByApplyId() {
CpApplyService cpApplyService = mock(CpApplyService.class);
when(cpApplyService.getById(3001L)).thenReturn(new CpApply().setStatus("AGREE"));
CpApplyStatusQryExe exe = new CpApplyStatusQryExe(cpApplyService);
assertEquals("AGREE", exe.execute(cmd(3001L)));
}
@Test
void shouldReturnNullWhenApplyNotFound() {
CpApplyService cpApplyService = mock(CpApplyService.class);
CpApplyStatusQryExe exe = new CpApplyStatusQryExe(cpApplyService);
assertNull(exe.execute(cmd(3001L)));
}
private static CpApplyStatusQueryCmd cmd(Long applyId) {
CpApplyStatusQueryCmd cmd = new CpApplyStatusQueryCmd();
cmd.setApplyId(applyId);
return cmd;
}
}

View File

@ -0,0 +1,114 @@
package com.red.circle.other.app.listener.gift.strategy;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.red.circle.mq.business.model.event.gift.OfflineProcessGiftEvent;
import com.red.circle.other.app.common.gift.GameLuckyGiftCommon;
import com.red.circle.other.app.service.activity.RankingActivityService;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.infra.common.game.GameKtvCommon;
import com.red.circle.other.infra.database.cache.service.cp.CpRelationshipCacheService;
import com.red.circle.other.infra.database.cache.service.other.ActivityConfigCacheService;
import com.red.circle.other.infra.database.cache.service.user.UserCpValueCacheService;
import com.red.circle.other.infra.database.mongo.entity.gift.GiftAcceptUser;
import com.red.circle.other.infra.database.mongo.entity.gift.GiftGiveRunningWater;
import com.red.circle.other.infra.database.mongo.entity.gift.GiftValue;
import com.red.circle.other.infra.database.mongo.service.activity.AppRankCountService;
import com.red.circle.other.infra.database.mongo.service.activity.TemporaryActivityCountService;
import com.red.circle.other.infra.database.mongo.service.activity.WeekKingQueenCountService;
import com.red.circle.other.infra.database.mongo.service.activity.WeekStarGiftCountService;
import com.red.circle.other.infra.database.mongo.service.gift.GiftGiveRunningWaterService;
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
import com.red.circle.other.infra.database.mongo.service.sys.SysActivityCountService;
import com.red.circle.other.infra.database.mongo.service.user.count.WeekCpValueCountService;
import com.red.circle.other.infra.database.rds.entity.user.user.CpRelationship;
import com.red.circle.other.infra.database.rds.service.user.user.CpRelationshipService;
import com.red.circle.other.infra.database.rds.service.user.user.CpValueService;
import com.red.circle.other.infra.enums.user.user.CpRelationshipType;
import com.red.circle.other.inner.enums.material.GiftCurrencyType;
import java.math.BigDecimal;
import java.util.List;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EnumSource;
class RankCountStrategyTest {
private final CpValueService cpValueService = mock(CpValueService.class);
private final UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
private final AppRankCountService appRankCountService = mock(AppRankCountService.class);
private final CpRelationshipService cpRelationshipService = mock(CpRelationshipService.class);
private final UserCpValueCacheService userCpValueCacheService = mock(
UserCpValueCacheService.class);
private final WeekCpValueCountService weekCpValueCountService = mock(
WeekCpValueCountService.class);
private final GiftGiveRunningWaterService giftGiveRunningWaterService = mock(
GiftGiveRunningWaterService.class);
private final CpRelationshipCacheService cpRelationshipCacheService = mock(
CpRelationshipCacheService.class);
private final ActivityConfigCacheService activityConfigCacheService = mock(
ActivityConfigCacheService.class);
private final RankCountStrategy strategy = new RankCountStrategy(
mock(GameKtvCommon.class),
cpValueService,
userProfileGateway,
mock(UserRegionGateway.class),
appRankCountService,
mock(GameLuckyGiftCommon.class),
cpRelationshipService,
userCpValueCacheService,
weekCpValueCountService,
mock(SysActivityCountService.class),
mock(WeekStarGiftCountService.class),
mock(RoomProfileManagerService.class),
mock(WeekKingQueenCountService.class),
giftGiveRunningWaterService,
mock(TemporaryActivityCountService.class),
mock(RankingActivityService.class),
cpRelationshipCacheService,
activityConfigCacheService);
@ParameterizedTest
@EnumSource(CpRelationshipType.class)
void processorShouldIncreaseRelationValueForNormalGoldGift(CpRelationshipType relationType) {
GiftGiveRunningWater runningWater = runningWater("NORMAL");
CpRelationship relationship = new CpRelationship()
.setCpValId(3003L)
.setUserId(1001L)
.setCpUserId(2002L)
.setRelationType(relationType.name());
when(giftGiveRunningWaterService.getByIdPrimary(9009L)).thenReturn(runningWater);
when(cpRelationshipService.getByUserId(1001L, (String) null))
.thenReturn(List.of(relationship));
when(activityConfigCacheService.listOngoing("LIKEI")).thenReturn(List.of());
strategy.processor(new OfflineProcessGiftEvent().setRunningWaterId(9009L));
verify(cpRelationshipService).getByUserId(1001L, (String) null);
verify(cpValueService).incrValue(3003L, new BigDecimal("25"));
verify(userCpValueCacheService).incr(1001L, 2002L, 25L);
verify(cpRelationshipCacheService).remove(List.of(1001L, 2002L));
verify(weekCpValueCountService).incrThisWeekQuantity("LIKEI", 1001L, 2002L, 25L);
verify(weekCpValueCountService).incrThisSeasonQuantity("LIKEI", 1001L, 2002L, 25L);
}
private GiftGiveRunningWater runningWater(String giftType) {
return new GiftGiveRunningWater()
.setId(9009L)
.setSysOrigin("LIKEI")
.setOriginId("chat")
.setUserId(1001L)
.setGiftId(5005L)
.setGiftValue(new GiftValue()
.setCurrencyType(GiftCurrencyType.GOLD.name())
.setGiftType(giftType)
.setGiftValue(new BigDecimal("25"))
.setActualAmount(new BigDecimal("25")))
.setAcceptUsers(List.of(new GiftAcceptUser()
.setAcceptUserId(2002L)));
}
}

View File

@ -0,0 +1,20 @@
package com.red.circle.other.app.dto.cmd.user.relation.cp;
import com.red.circle.common.business.dto.cmd.AppExtCommand;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* CP apply status query.
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class CpApplyStatusQueryCmd extends AppExtCommand {
/**
* 申请记录 ID.
*/
@NotNull(message = "applyId required.")
private Long applyId;
}

View File

@ -9,6 +9,7 @@ import com.red.circle.other.app.dto.clientobject.user.relation.cp.CpUserProfileC
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyIdQueryCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyDismissCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpApplyStatusQueryCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpRelationshipQueryCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.ProcessApplyCmd;
import com.red.circle.other.app.dto.cmd.user.relation.cp.loveletter.SendLoveLetterCmd;
@ -33,8 +34,10 @@ public interface UserCpRelationService {
CpDismissApplyCO dismissApply(CpApplyDismissCmd cmd);
String getCpApplyId(CpApplyIdQueryCmd cmd);
CpCabinUserProfileCO getCpUserV4(UserIdCommonCmd cmd);
String getCpApplyStatus(CpApplyStatusQueryCmd cmd);
CpCabinUserProfileCO getCpUserV4(UserIdCommonCmd cmd);
void sendLoveLetter(SendLoveLetterCmd cmd);

View File

@ -2,6 +2,7 @@ package com.red.circle.other.infra.database.rds.service.vip;
import com.red.circle.framework.mybatis.service.BaseService;
import com.red.circle.other.infra.database.rds.entity.vip.VipLevelConfig;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -11,5 +12,7 @@ public interface VipLevelConfigService extends BaseService<VipLevelConfig> {
Map<Long, VipLevelConfig> mapBySysOriginAndIds(String sysOrigin, Set<Long> ids);
List<VipLevelConfig> listBySysOrigin(String sysOrigin);
VipLevelConfig getEnabledById(String sysOrigin, Long id);
}

View File

@ -6,6 +6,7 @@ import com.red.circle.other.infra.database.rds.dao.vip.VipLevelConfigDAO;
import com.red.circle.other.infra.database.rds.entity.vip.VipLevelConfig;
import com.red.circle.other.infra.database.rds.service.vip.VipLevelConfigService;
import com.red.circle.tool.core.collection.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@ -44,6 +45,17 @@ public class VipLevelConfigServiceImpl extends BaseServiceImpl<VipLevelConfigDAO
.orElseGet(CollectionUtils::newHashMap);
}
@Override
public List<VipLevelConfig> listBySysOrigin(String sysOrigin) {
if (Objects.isNull(sysOrigin)) {
return CollectionUtils.newArrayList();
}
return Optional.ofNullable(query()
.eq(VipLevelConfig::getSysOrigin, sysOrigin)
.list())
.orElseGet(CollectionUtils::newArrayList);
}
@Override
public VipLevelConfig getEnabledById(String sysOrigin, Long id) {
if (Objects.isNull(id) || Objects.isNull(sysOrigin)) {

View File

@ -2,9 +2,10 @@ package com.red.circle.other.infra.gateway.props;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.common.business.enums.PropsActivityRewardEnum;
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.other.domain.gateway.props.ActivitySourceGroupGateway;
import com.red.circle.other.infra.common.activity.VipActivityRewardCommon;
import com.red.circle.other.infra.common.props.PropsResourcesCommon;
import com.red.circle.other.infra.convertor.material.PropsActivityInfraConvertor;
import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRewardConfig;
@ -28,14 +29,16 @@ import com.red.circle.other.inner.model.dto.material.EmojiGroupDTO;
import com.red.circle.other.inner.model.dto.material.GiftConfigDTO;
import com.red.circle.other.inner.model.dto.material.PropsResourcesDTO;
import com.red.circle.other.inner.model.dto.material.PropsResourcesMergeDTO;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.num.ArithmeticUtils;
import com.red.circle.tool.core.parse.DataTypeUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.num.ArithmeticUtils;
import com.red.circle.tool.core.parse.DataTypeUtils;
import com.red.circle.tool.core.text.StringUtils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@ -52,8 +55,10 @@ import org.springframework.stereotype.Component;
*/
@Component
@RequiredArgsConstructor
public class ActivitySourceGroupGatewayImpl implements ActivitySourceGroupGateway {
public class ActivitySourceGroupGatewayImpl implements ActivitySourceGroupGateway {
private static final long VIP_ID_ROUNDING_TOLERANCE = 512L;
private final PropsResourcesCommon propsResourcesCommon;
private final PropsActivityInfraConvertor propsActivityInfraConvertor;
private final PropsSourceRecordService propsSourceRecordService;
@ -131,8 +136,9 @@ public class ActivitySourceGroupGatewayImpl implements ActivitySourceGroupGatewa
Map<Long, List<PropsActivityRewardConfig>> rewardGroupConfigMap = propsActivityRewardConfigService
.mapGroupByIds(groupIds);
Map<Long, VipLevelConfig> vipConfigMap = vipLevelConfigService.mapBySysOriginAndIds(sysOrigin,
getVipLevelConfigIds(rewardGroupConfigMap));
Map<Long, VipLevelConfig> vipConfigMap = loadVipConfigMap(sysOrigin,
getVipLevelConfigIds(rewardGroupConfigMap),
getRoundedVipLevelConfigIds(rewardGroupConfigMap));
Map<Long, PropsSourceRecord> vipCoverMap = propsSourceRecordService.mapByIds(
getVipCoverResourceIds(vipConfigMap.values()));
@ -387,6 +393,52 @@ public class ActivitySourceGroupGatewayImpl implements ActivitySourceGroupGatewa
.collect(Collectors.toSet());
}
private Set<Long> getRoundedVipLevelConfigIds(
Map<Long, List<PropsActivityRewardConfig>> rewardGroupConfigMap) {
return rewardGroupConfigMap.values().stream()
.flatMap(Collection::stream)
.filter(config -> PropsActivityRewardEnum.PROPS.eq(config.getType()))
.filter(config -> Objects.equals(config.getDetailType(),
VipActivityRewardCommon.VIP_DETAIL_TYPE))
.map(config -> DataTypeUtils.toLong(config.getContent()))
.filter(Objects::nonNull)
.collect(Collectors.toSet());
}
private Map<Long, VipLevelConfig> loadVipConfigMap(String sysOrigin,
Set<Long> vipLevelConfigIds, Set<Long> roundedVipLevelConfigIds) {
Map<Long, VipLevelConfig> vipConfigMap = vipLevelConfigService.mapBySysOriginAndIds(sysOrigin,
vipLevelConfigIds);
if (StringUtils.isBlank(sysOrigin) || CollectionUtils.isEmpty(roundedVipLevelConfigIds)) {
return vipConfigMap;
}
Set<Long> missingIds = roundedVipLevelConfigIds.stream()
.filter(id -> !vipConfigMap.containsKey(id))
.collect(Collectors.toSet());
if (CollectionUtils.isEmpty(missingIds)) {
return vipConfigMap;
}
List<VipLevelConfig> sysVipConfigs = vipLevelConfigService.listBySysOrigin(sysOrigin);
missingIds.forEach(id -> findClosestVipConfig(id, sysVipConfigs)
.ifPresent(vipConfig -> vipConfigMap.put(id, vipConfig)));
return vipConfigMap;
}
private Optional<VipLevelConfig> findClosestVipConfig(Long id,
List<VipLevelConfig> vipConfigs) {
if (Objects.isNull(id) || CollectionUtils.isEmpty(vipConfigs)) {
return Optional.empty();
}
return vipConfigs.stream()
.filter(config -> Objects.nonNull(config.getId()))
.filter(config -> vipIdDistance(id, config.getId()) <= VIP_ID_ROUNDING_TOLERANCE)
.min(Comparator.comparingLong(config -> vipIdDistance(id, config.getId())));
}
private long vipIdDistance(Long left, Long right) {
return Math.abs(left - right);
}
private Set<Long> getVipCoverResourceIds(Collection<VipLevelConfig> vipConfigs) {
if (CollectionUtils.isEmpty(vipConfigs)) {
return CollectionUtils.newHashSet();

View File

@ -6,6 +6,7 @@ import com.red.circle.common.business.enums.PropsActivityRewardEnum;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.other.app.inner.convertor.material.PropsInnerConvertor;
import com.red.circle.other.app.inner.service.material.props.PropsActivityRewardGroupClientService;
import com.red.circle.other.infra.common.activity.VipActivityRewardCommon;
import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRewardConfig;
import com.red.circle.other.infra.database.rds.entity.activity.PropsActivityRewardGroup;
import com.red.circle.other.infra.database.rds.entity.badge.BadgeConfig;
@ -55,9 +56,11 @@ import org.springframework.transaction.annotation.Transactional;
@Slf4j
@Service
@RequiredArgsConstructor
public class PropsActivityRewardGroupClientServiceImpl implements
PropsActivityRewardGroupClientService {
public class PropsActivityRewardGroupClientServiceImpl implements
PropsActivityRewardGroupClientService {
private static final long VIP_ID_ROUNDING_TOLERANCE = 512L;
private final EmojiGroupService emojiGroupService;
private final GiftConfigService giftConfigService;
private final BadgeConfigService badgeConfigService;
@ -95,8 +98,8 @@ public class PropsActivityRewardGroupClientServiceImpl implements
return new PropsActivityRewardGroupDTO();
}
List<PropsActivityRewardConfigInfoDTO> propsActivityRewards = listGroupDTO(
List.of(group.getId()));
List<PropsActivityRewardConfigInfoDTO> propsActivityRewards = listGroupDTO(
List.of(group.getId()), group.getSysOrigin());
if (CollectionUtils.isEmpty(propsActivityRewards)) {
return new PropsActivityRewardGroupDTO();
@ -167,9 +170,9 @@ public class PropsActivityRewardGroupClientServiceImpl implements
propsActivityRewardGroups.stream().map(PropsActivityRewardGroupDTO::getId)
.collect(Collectors.toSet()));
}
List<PropsActivityRewardConfigInfoDTO> propsActivityRewards = listGroupDTO(
propsActivityRewardGroups.stream().map(PropsActivityRewardGroupDTO::getId)
.collect(Collectors.toList()));
List<PropsActivityRewardConfigInfoDTO> propsActivityRewards = listGroupDTO(
propsActivityRewardGroups.stream().map(PropsActivityRewardGroupDTO::getId)
.collect(Collectors.toList()), sysOrigin);
Map<Long, BadgePictureConfig> badgePictureMap = badgePictureConfigService
.mapBadge(sysOrigin, getBadgeContentList(propsActivityRewards));
@ -205,16 +208,21 @@ public class PropsActivityRewardGroupClientServiceImpl implements
return Maps.newHashMap();
}
return Optional.ofNullable(listGroupDTO(new ArrayList<>(groupIds)))
.map(config -> config.stream()
.collect(Collectors.groupingBy(PropsActivityRewardConfigInfoDTO::getGroupId)))
.orElseGet(Maps::newHashMap);
}
public List<PropsActivityRewardConfigInfoDTO> listGroupDTO(List<Long> groupIds) {
if (CollectionUtils.isEmpty(groupIds)) {
return Lists.newArrayList();
return Optional.ofNullable(listGroupDTO(new ArrayList<>(groupIds), null))
.map(config -> config.stream()
.collect(Collectors.groupingBy(PropsActivityRewardConfigInfoDTO::getGroupId)))
.orElseGet(Maps::newHashMap);
}
public List<PropsActivityRewardConfigInfoDTO> listGroupDTO(List<Long> groupIds) {
return listGroupDTO(groupIds, null);
}
private List<PropsActivityRewardConfigInfoDTO> listGroupDTO(List<Long> groupIds,
String sysOrigin) {
if (CollectionUtils.isEmpty(groupIds)) {
return Lists.newArrayList();
}
List<PropsActivityRewardConfig> propsActivityRewardConfigs = propsActivityRewardConfigService.listByGroupIds(
@ -224,8 +232,9 @@ public class PropsActivityRewardGroupClientServiceImpl implements
return Lists.newArrayList();
}
Map<Long, VipLevelConfig> vipConfigMap = vipLevelConfigService.mapByIds(
getVipLevelConfigIds(propsActivityRewardConfigs));
Map<Long, VipLevelConfig> vipConfigMap = loadVipConfigMap(sysOrigin,
getVipLevelConfigIds(propsActivityRewardConfigs),
getRoundedVipLevelConfigIds(propsActivityRewardConfigs));
Map<Long, PropsSourceRecord> vipCoverMap = propsSourceRecordService.mapByIds(
getVipCoverResourceIds(vipConfigMap.values()));
@ -358,6 +367,51 @@ public class PropsActivityRewardGroupClientServiceImpl implements
.collect(Collectors.toSet());
}
private Set<Long> getRoundedVipLevelConfigIds(List<PropsActivityRewardConfig> configs) {
return configs.stream()
.filter(config -> Objects.equals(config.getType(), PropsActivityRewardEnum.PROPS.name()))
.filter(config -> Objects.equals(config.getDetailType(),
VipActivityRewardCommon.VIP_DETAIL_TYPE))
.map(config -> DataTypeUtils.toLong(config.getContent()))
.filter(Objects::nonNull)
.collect(Collectors.toSet());
}
private Map<Long, VipLevelConfig> loadVipConfigMap(String sysOrigin,
Set<Long> vipLevelConfigIds, Set<Long> roundedVipLevelConfigIds) {
Map<Long, VipLevelConfig> vipConfigMap = StringUtils.isBlank(sysOrigin)
? vipLevelConfigService.mapByIds(vipLevelConfigIds)
: vipLevelConfigService.mapBySysOriginAndIds(sysOrigin, vipLevelConfigIds);
if (StringUtils.isBlank(sysOrigin) || CollectionUtils.isEmpty(roundedVipLevelConfigIds)) {
return vipConfigMap;
}
Set<Long> missingIds = roundedVipLevelConfigIds.stream()
.filter(id -> !vipConfigMap.containsKey(id))
.collect(Collectors.toSet());
if (CollectionUtils.isEmpty(missingIds)) {
return vipConfigMap;
}
List<VipLevelConfig> sysVipConfigs = vipLevelConfigService.listBySysOrigin(sysOrigin);
missingIds.forEach(id -> findClosestVipConfig(id, sysVipConfigs)
.ifPresent(vipConfig -> vipConfigMap.put(id, vipConfig)));
return vipConfigMap;
}
private Optional<VipLevelConfig> findClosestVipConfig(Long id,
List<VipLevelConfig> vipConfigs) {
if (Objects.isNull(id) || CollectionUtils.isEmpty(vipConfigs)) {
return Optional.empty();
}
return vipConfigs.stream()
.filter(config -> Objects.nonNull(config.getId()))
.filter(config -> vipIdDistance(id, config.getId()) <= VIP_ID_ROUNDING_TOLERANCE)
.min(Comparator.comparingLong(config -> vipIdDistance(id, config.getId())));
}
private long vipIdDistance(Long left, Long right) {
return Math.abs(left - right);
}
private Set<Long> getVipCoverResourceIds(Collection<VipLevelConfig> vipConfigs) {
if (CollectionUtils.isEmpty(vipConfigs)) {
return Set.of();

View File

@ -56,11 +56,12 @@
</testResources>
<plugins>
<plugin>
<artifactId>spring-boot-maven-plugin</artifactId>
<groupId>org.springframework.boot</groupId>
<executions>
<execution>
<goals>
<artifactId>spring-boot-maven-plugin</artifactId>
<groupId>org.springframework.boot</groupId>
<version>3.1.5</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>