feat(channel/send): support all 4 binding types and validate send targets
- BindConversationAccountRequest: restrict bindingType to 1-4 - ConversationService.bindAccount: upsert binding by account+conversation+type with sortOrder and status=1 - SendService.selectSendAccount: prefer send-primary(1), fallback send-backup(2), status=1, tenant/channel match, sortOrder asc - SendService.resolveConversationTarget/resolvePersonTarget: verify account tenant, channel type and status; ensure person identity channel type matches for single chat
This commit is contained in:
@@ -2,6 +2,7 @@ package com.sino.mci.channel.dto;
|
||||
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import org.hibernate.validator.constraints.Range;
|
||||
|
||||
@Data
|
||||
public class BindConversationAccountRequest {
|
||||
@@ -10,6 +11,7 @@ public class BindConversationAccountRequest {
|
||||
private Long accountId;
|
||||
|
||||
@NotNull
|
||||
@Range(min = 1, max = 4)
|
||||
private Integer bindingType;
|
||||
|
||||
private Integer sortOrder;
|
||||
|
||||
@@ -104,14 +104,11 @@ public class ConversationService {
|
||||
public void bindAccount(String tenantCode, Long conversationId, BindConversationAccountRequest request) {
|
||||
getConversation(tenantCode, conversationId);
|
||||
|
||||
ChannelAccountConversation existing = bindingMapper.selectOne(
|
||||
bindingMapper.delete(
|
||||
new LambdaQueryWrapper<ChannelAccountConversation>()
|
||||
.eq(ChannelAccountConversation::getAccountId, request.getAccountId())
|
||||
.eq(ChannelAccountConversation::getConversationId, conversationId)
|
||||
.eq(ChannelAccountConversation::getBindingType, request.getBindingType()));
|
||||
if (existing != null) {
|
||||
throw new BusinessException("该账号已绑定此会话的相同类型");
|
||||
}
|
||||
|
||||
ChannelAccountConversation binding = new ChannelAccountConversation();
|
||||
binding.setAccountId(request.getAccountId());
|
||||
|
||||
@@ -9,7 +9,9 @@ import com.sino.mci.channel.common.dto.SendMessageResult;
|
||||
import com.sino.mci.channel.common.model.ChannelType;
|
||||
import com.sino.mci.channel.common.spi.ChannelAdapter;
|
||||
import com.sino.mci.channel.entity.ChannelAccount;
|
||||
import com.sino.mci.channel.entity.ChannelAccountConversation;
|
||||
import com.sino.mci.channel.entity.Conversation;
|
||||
import com.sino.mci.channel.repository.ChannelAccountConversationMapper;
|
||||
import com.sino.mci.channel.repository.ChannelAccountMapper;
|
||||
import com.sino.mci.channel.repository.ConversationMapper;
|
||||
import com.sino.mci.channel.service.AccountSelector;
|
||||
@@ -80,6 +82,7 @@ public class SendService {
|
||||
private final SendRecordMapper sendRecordMapper;
|
||||
private final ConversationMapper conversationMapper;
|
||||
private final ChannelAccountMapper accountMapper;
|
||||
private final ChannelAccountConversationMapper channelAccountConversationMapper;
|
||||
private final ChannelIdentityMapper channelIdentityMapper;
|
||||
private final PersonMapper personMapper;
|
||||
private final TagMapper tagMapper;
|
||||
@@ -332,6 +335,12 @@ public class SendService {
|
||||
if (accountId == null) {
|
||||
throw new BusinessException("会话未配置发送账号: " + conversationId);
|
||||
}
|
||||
ChannelAccount account = accountMapper.selectById(accountId);
|
||||
if (account == null || !tenantCode.equals(account.getTenantCode())
|
||||
|| !channelType.name().equalsIgnoreCase(account.getChannelType())
|
||||
|| account.getStatus() == null || account.getStatus() != STATUS_ENABLED) {
|
||||
throw new BusinessException("会话没有可用的发送账号: " + conversationId);
|
||||
}
|
||||
SendTarget target = new SendTarget();
|
||||
target.setConversationId(conversationId);
|
||||
target.setPersonId(null);
|
||||
@@ -356,6 +365,14 @@ public class SendService {
|
||||
if (accountId == null) {
|
||||
throw new BusinessException("租户未配置可用发送账号: channel=" + channelType.name().toLowerCase());
|
||||
}
|
||||
ChannelAccount account = accountMapper.selectById(accountId);
|
||||
if (account == null || !tenantCode.equals(account.getTenantCode())
|
||||
|| account.getStatus() == null || account.getStatus() != STATUS_ENABLED) {
|
||||
throw new BusinessException("租户没有可用的发送账号: channel=" + channelType.name().toLowerCase());
|
||||
}
|
||||
if (!channelType.name().equalsIgnoreCase(account.getChannelType())) {
|
||||
throw new BusinessException("单聊发送账号渠道类型与目标身份不一致");
|
||||
}
|
||||
SendTarget target = new SendTarget();
|
||||
target.setConversationId(null);
|
||||
target.setPersonId(personId);
|
||||
@@ -675,7 +692,24 @@ public class SendService {
|
||||
}
|
||||
|
||||
private Long selectSendAccount(String tenantCode, Long conversationId, ChannelType channelType, Map<String, Object> channelStrategy) {
|
||||
return accountSelector.selectSendAccount(tenantCode, conversationId, channelType, extractStrategy(channelStrategy));
|
||||
List<Integer> bindingTypes = List.of(1, 2);
|
||||
for (Integer bindingType : bindingTypes) {
|
||||
List<ChannelAccountConversation> bindings = channelAccountConversationMapper.selectList(
|
||||
new LambdaQueryWrapper<ChannelAccountConversation>()
|
||||
.eq(ChannelAccountConversation::getConversationId, conversationId)
|
||||
.eq(ChannelAccountConversation::getBindingType, bindingType)
|
||||
.eq(ChannelAccountConversation::getStatus, STATUS_ENABLED)
|
||||
.orderByAsc(ChannelAccountConversation::getSortOrder));
|
||||
for (ChannelAccountConversation binding : bindings) {
|
||||
ChannelAccount account = accountMapper.selectById(binding.getAccountId());
|
||||
if (account != null && tenantCode.equals(account.getTenantCode())
|
||||
&& channelType.name().equalsIgnoreCase(account.getChannelType())
|
||||
&& account.getStatus() != null && account.getStatus() == STATUS_ENABLED) {
|
||||
return account.getId();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Long selectDefaultAccount(String tenantCode, ChannelType channelType) {
|
||||
|
||||
Reference in New Issue
Block a user