feat(send): 实现 outbound rule 目标解析
This commit is contained in:
@@ -14,10 +14,14 @@ import com.sino.mci.channel.repository.ChannelAccountMapper;
|
||||
import com.sino.mci.channel.repository.ConversationMapper;
|
||||
import com.sino.mci.channel.entity.ConversationTagBinding;
|
||||
import com.sino.mci.crm.entity.ChannelIdentity;
|
||||
import com.sino.mci.crm.entity.Person;
|
||||
import com.sino.mci.crm.entity.PersonTagBinding;
|
||||
import com.sino.mci.crm.entity.Tag;
|
||||
import com.sino.mci.channel.repository.ConversationTagBindingMapper;
|
||||
import com.sino.mci.crm.repository.ChannelIdentityMapper;
|
||||
import com.sino.mci.crm.repository.PersonMapper;
|
||||
import com.sino.mci.crm.repository.PersonTagBindingMapper;
|
||||
import com.sino.mci.crm.repository.TagMapper;
|
||||
import com.sino.mci.exception.BusinessException;
|
||||
import com.sino.mci.send.dto.SendRecordResponse;
|
||||
import com.sino.mci.send.dto.SendRequest;
|
||||
@@ -33,12 +37,19 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@@ -59,6 +70,8 @@ public class SendService {
|
||||
private final ChannelAccountMapper accountMapper;
|
||||
private final ChannelAccountConversationMapper accountConversationMapper;
|
||||
private final ChannelIdentityMapper channelIdentityMapper;
|
||||
private final PersonMapper personMapper;
|
||||
private final TagMapper tagMapper;
|
||||
private final PersonTagBindingMapper personTagBindingMapper;
|
||||
private final ConversationTagBindingMapper conversationTagBindingMapper;
|
||||
private final ChannelAdapterRegistry adapterRegistry;
|
||||
@@ -158,7 +171,7 @@ public class SendService {
|
||||
String scope = (String) targetValue.getOrDefault("scope", "all");
|
||||
return resolveTagTarget(tenantCode, tagId.longValue(), channelType, scope);
|
||||
case "rule":
|
||||
throw new BusinessException("rule 目标解析尚未实现");
|
||||
return resolveRuleTarget(tenantCode, targetValue, channelType, channelStrategy);
|
||||
default:
|
||||
throw new BusinessException("不支持的目标类型: " + targetType);
|
||||
}
|
||||
@@ -235,6 +248,290 @@ public class SendService {
|
||||
return targets;
|
||||
}
|
||||
|
||||
private List<SendTarget> resolveRuleTarget(String tenantCode, Map<String, Object> targetValue,
|
||||
ChannelType channelType, Map<String, Object> channelStrategy) {
|
||||
RuleTargetValue ruleTarget = parseRuleTargetValue(targetValue);
|
||||
List<RuleMatchResult> results = new ArrayList<>();
|
||||
for (RuleCondition condition : ruleTarget.getRules()) {
|
||||
results.add(evaluateRuleCondition(tenantCode, condition));
|
||||
}
|
||||
Set<Long> personIds = combinePersonIds(ruleTarget.getLogic(), results);
|
||||
Set<Long> conversationIds = combineConversationIds(ruleTarget.getLogic(), results);
|
||||
|
||||
List<SendTarget> targets = new ArrayList<>();
|
||||
for (Long personId : personIds) {
|
||||
targets.addAll(resolvePersonTarget(tenantCode, personId, channelType));
|
||||
}
|
||||
for (Long conversationId : conversationIds) {
|
||||
targets.addAll(resolveConversationTarget(tenantCode, conversationId, channelType, channelStrategy));
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
private RuleTargetValue parseRuleTargetValue(Map<String, Object> targetValue) {
|
||||
if (targetValue == null) {
|
||||
throw new BusinessException("rule 目标缺少 rules");
|
||||
}
|
||||
Object rulesObj = targetValue.get("rules");
|
||||
if (!(rulesObj instanceof List) || ((List<?>) rulesObj).isEmpty()) {
|
||||
throw new BusinessException("rule 目标缺少 rules");
|
||||
}
|
||||
List<RuleCondition> rules = new ArrayList<>();
|
||||
for (Object item : (List<?>) rulesObj) {
|
||||
if (!(item instanceof Map)) {
|
||||
throw new BusinessException("rule 条件格式错误");
|
||||
}
|
||||
Map<?, ?> map = (Map<?, ?>) item;
|
||||
String field = toRuleString(map.get("field"));
|
||||
String operator = toRuleString(map.get("operator"));
|
||||
if (!StringUtils.hasText(field) || !StringUtils.hasText(operator)) {
|
||||
throw new BusinessException("rule 条件缺少 field 或 operator");
|
||||
}
|
||||
rules.add(new RuleCondition(field, operator, map.get("value")));
|
||||
}
|
||||
String logic = toRuleString(targetValue.getOrDefault("logic", "and"));
|
||||
if (!"and".equals(logic) && !"or".equals(logic)) {
|
||||
throw new BusinessException("rule 逻辑仅支持 and 或 or");
|
||||
}
|
||||
return new RuleTargetValue(rules, logic);
|
||||
}
|
||||
|
||||
private RuleMatchResult evaluateRuleCondition(String tenantCode, RuleCondition condition) {
|
||||
switch (condition.getField()) {
|
||||
case "tag":
|
||||
return evaluateTagCondition(tenantCode, condition);
|
||||
case "contract_id":
|
||||
return new RuleMatchResult(Collections.emptySet(),
|
||||
evaluateFieldCondition(tenantCode, condition, conversationMapper,
|
||||
Conversation::getTenantCode, Conversation::getId, Conversation::getContractId, this::toLong));
|
||||
case "institution_id":
|
||||
return new RuleMatchResult(
|
||||
evaluateFieldCondition(tenantCode, condition, personMapper,
|
||||
Person::getTenantCode, Person::getId, Person::getInstitutionId, this::toLong),
|
||||
evaluateFieldCondition(tenantCode, condition, conversationMapper,
|
||||
Conversation::getTenantCode, Conversation::getId, Conversation::getInstitutionId, this::toLong));
|
||||
case "supplier_id":
|
||||
return new RuleMatchResult(
|
||||
evaluateFieldCondition(tenantCode, condition, personMapper,
|
||||
Person::getTenantCode, Person::getId, Person::getSupplierId, this::toLong),
|
||||
evaluateFieldCondition(tenantCode, condition, conversationMapper,
|
||||
Conversation::getTenantCode, Conversation::getId, Conversation::getSupplierId, this::toLong));
|
||||
case "person_type":
|
||||
return new RuleMatchResult(
|
||||
evaluateFieldCondition(tenantCode, condition, personMapper,
|
||||
Person::getTenantCode, Person::getId, Person::getPersonType, this::toInteger),
|
||||
Collections.emptySet());
|
||||
case "channel_type":
|
||||
return new RuleMatchResult(Collections.emptySet(),
|
||||
evaluateFieldCondition(tenantCode, condition, conversationMapper,
|
||||
Conversation::getTenantCode, Conversation::getId, Conversation::getChannelType, this::toLowerCaseString));
|
||||
default:
|
||||
throw new BusinessException("rule 不支持的字段: " + condition.getField());
|
||||
}
|
||||
}
|
||||
|
||||
private <T, R> Set<Long> evaluateFieldCondition(String tenantCode, RuleCondition condition, BaseMapper<T> mapper,
|
||||
SFunction<T, String> tenantCodeGetter, SFunction<T, Long> idGetter,
|
||||
SFunction<T, R> fieldGetter, Function<Object, R> converter) {
|
||||
List<R> values = normalizeValues(condition.getValue()).stream()
|
||||
.map(converter)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<T>()
|
||||
.eq(tenantCodeGetter, tenantCode);
|
||||
if (values.isEmpty()) {
|
||||
if ("not_in".equals(condition.getOperator())) {
|
||||
return mapper.selectList(wrapper).stream().map(idGetter).collect(Collectors.toSet());
|
||||
}
|
||||
return Collections.emptySet();
|
||||
}
|
||||
applyOperator(wrapper, fieldGetter, condition.getOperator(), values);
|
||||
return mapper.selectList(wrapper).stream().map(idGetter).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private <T, R> void applyOperator(LambdaQueryWrapper<T> wrapper, SFunction<T, R> fieldGetter,
|
||||
String operator, List<R> values) {
|
||||
switch (operator) {
|
||||
case "eq":
|
||||
wrapper.eq(fieldGetter, values.get(0));
|
||||
break;
|
||||
case "ne":
|
||||
wrapper.ne(fieldGetter, values.get(0));
|
||||
break;
|
||||
case "in":
|
||||
wrapper.in(fieldGetter, values);
|
||||
break;
|
||||
case "not_in":
|
||||
wrapper.notIn(fieldGetter, values);
|
||||
break;
|
||||
default:
|
||||
throw new BusinessException("rule 不支持的算子: " + operator);
|
||||
}
|
||||
}
|
||||
|
||||
private RuleMatchResult evaluateTagCondition(String tenantCode, RuleCondition condition) {
|
||||
List<Object> values = normalizeValues(condition.getValue());
|
||||
Set<Long> tagIds = new HashSet<>();
|
||||
for (Object value : values) {
|
||||
if (value instanceof Number) {
|
||||
tagIds.add(((Number) value).longValue());
|
||||
} else if (value instanceof String) {
|
||||
List<Tag> tags = tagMapper.selectList(
|
||||
new LambdaQueryWrapper<Tag>()
|
||||
.eq(Tag::getTenantCode, tenantCode)
|
||||
.eq(Tag::getTagPath, value));
|
||||
for (Tag tag : tags) {
|
||||
tagIds.add(tag.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tagIds.isEmpty()) {
|
||||
if ("not_in".equals(condition.getOperator())) {
|
||||
return new RuleMatchResult(
|
||||
selectAllPersonIds(tenantCode),
|
||||
selectAllConversationIds(tenantCode));
|
||||
}
|
||||
return new RuleMatchResult(Collections.emptySet(), Collections.emptySet());
|
||||
}
|
||||
Set<Long> personIds = personTagBindingMapper.selectList(
|
||||
new LambdaQueryWrapper<PersonTagBinding>()
|
||||
.eq(PersonTagBinding::getTenantCode, tenantCode)
|
||||
.in(PersonTagBinding::getTagId, tagIds))
|
||||
.stream()
|
||||
.map(PersonTagBinding::getPersonId)
|
||||
.collect(Collectors.toSet());
|
||||
Set<Long> conversationIds = conversationTagBindingMapper.selectList(
|
||||
new LambdaQueryWrapper<ConversationTagBinding>()
|
||||
.eq(ConversationTagBinding::getTenantCode, tenantCode)
|
||||
.in(ConversationTagBinding::getTagId, tagIds))
|
||||
.stream()
|
||||
.map(ConversationTagBinding::getConversationId)
|
||||
.collect(Collectors.toSet());
|
||||
if ("ne".equals(condition.getOperator()) || "not_in".equals(condition.getOperator())) {
|
||||
Set<Long> allPersonIds = selectAllPersonIds(tenantCode);
|
||||
Set<Long> allConversationIds = selectAllConversationIds(tenantCode);
|
||||
allPersonIds.removeAll(personIds);
|
||||
allConversationIds.removeAll(conversationIds);
|
||||
return new RuleMatchResult(allPersonIds, allConversationIds);
|
||||
}
|
||||
return new RuleMatchResult(personIds, conversationIds);
|
||||
}
|
||||
|
||||
private Set<Long> selectAllPersonIds(String tenantCode) {
|
||||
return personMapper.selectList(
|
||||
new LambdaQueryWrapper<Person>().eq(Person::getTenantCode, tenantCode))
|
||||
.stream()
|
||||
.map(Person::getId)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<Long> selectAllConversationIds(String tenantCode) {
|
||||
return conversationMapper.selectList(
|
||||
new LambdaQueryWrapper<Conversation>().eq(Conversation::getTenantCode, tenantCode))
|
||||
.stream()
|
||||
.map(Conversation::getId)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private Set<Long> combinePersonIds(String logic, List<RuleMatchResult> results) {
|
||||
return "or".equals(logic) ? unionPersonIds(results) : intersectPersonIds(results);
|
||||
}
|
||||
|
||||
private Set<Long> unionPersonIds(List<RuleMatchResult> results) {
|
||||
Set<Long> ids = new HashSet<>();
|
||||
for (RuleMatchResult result : results) {
|
||||
ids.addAll(result.getPersonIds());
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
private Set<Long> intersectPersonIds(List<RuleMatchResult> results) {
|
||||
Set<Long> ids = null;
|
||||
for (RuleMatchResult result : results) {
|
||||
if (!result.getPersonIds().isEmpty()) {
|
||||
if (ids == null) {
|
||||
ids = new HashSet<>(result.getPersonIds());
|
||||
} else {
|
||||
ids.retainAll(result.getPersonIds());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids == null ? Collections.emptySet() : ids;
|
||||
}
|
||||
|
||||
private Set<Long> combineConversationIds(String logic, List<RuleMatchResult> results) {
|
||||
return "or".equals(logic) ? unionConversationIds(results) : intersectConversationIds(results);
|
||||
}
|
||||
|
||||
private Set<Long> unionConversationIds(List<RuleMatchResult> results) {
|
||||
Set<Long> ids = new HashSet<>();
|
||||
for (RuleMatchResult result : results) {
|
||||
ids.addAll(result.getConversationIds());
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
private Set<Long> intersectConversationIds(List<RuleMatchResult> results) {
|
||||
Set<Long> ids = null;
|
||||
for (RuleMatchResult result : results) {
|
||||
if (!result.getConversationIds().isEmpty()) {
|
||||
if (ids == null) {
|
||||
ids = new HashSet<>(result.getConversationIds());
|
||||
} else {
|
||||
ids.retainAll(result.getConversationIds());
|
||||
}
|
||||
}
|
||||
}
|
||||
return ids == null ? Collections.emptySet() : ids;
|
||||
}
|
||||
|
||||
private List<Object> normalizeValues(Object value) {
|
||||
if (value == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (value instanceof List) {
|
||||
return new ArrayList<>((List<?>) value);
|
||||
}
|
||||
return Collections.singletonList(value);
|
||||
}
|
||||
|
||||
private Long toLong(Object value) {
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).longValue();
|
||||
}
|
||||
if (value instanceof String) {
|
||||
try {
|
||||
return Long.parseLong((String) value);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Integer toInteger(Object value) {
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
if (value instanceof String) {
|
||||
try {
|
||||
return Integer.parseInt((String) value);
|
||||
} catch (NumberFormatException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String toLowerCaseString(Object value) {
|
||||
String str = toRuleString(value);
|
||||
return str != null ? str.toLowerCase() : null;
|
||||
}
|
||||
|
||||
private String toRuleString(Object value) {
|
||||
return value != null ? String.valueOf(value) : null;
|
||||
}
|
||||
|
||||
private Long selectSendAccount(Long conversationId, ChannelType channelType, Map<String, Object> channelStrategy) {
|
||||
String strategy = extractStrategy(channelStrategy);
|
||||
int bindingType = "backup".equals(strategy) ? BINDING_SEND_BACKUP : BINDING_SEND_PRIMARY;
|
||||
@@ -395,6 +692,69 @@ public class SendService {
|
||||
return response;
|
||||
}
|
||||
|
||||
private static class RuleCondition {
|
||||
|
||||
private final String field;
|
||||
private final String operator;
|
||||
private final Object value;
|
||||
|
||||
RuleCondition(String field, String operator, Object value) {
|
||||
this.field = field;
|
||||
this.operator = operator;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getField() {
|
||||
return field;
|
||||
}
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RuleTargetValue {
|
||||
|
||||
private final List<RuleCondition> rules;
|
||||
private final String logic;
|
||||
|
||||
RuleTargetValue(List<RuleCondition> rules, String logic) {
|
||||
this.rules = rules;
|
||||
this.logic = logic;
|
||||
}
|
||||
|
||||
public List<RuleCondition> getRules() {
|
||||
return rules;
|
||||
}
|
||||
|
||||
public String getLogic() {
|
||||
return logic;
|
||||
}
|
||||
}
|
||||
|
||||
private static class RuleMatchResult {
|
||||
|
||||
private final Set<Long> personIds;
|
||||
private final Set<Long> conversationIds;
|
||||
|
||||
RuleMatchResult(Set<Long> personIds, Set<Long> conversationIds) {
|
||||
this.personIds = personIds;
|
||||
this.conversationIds = conversationIds;
|
||||
}
|
||||
|
||||
public Set<Long> getPersonIds() {
|
||||
return personIds;
|
||||
}
|
||||
|
||||
public Set<Long> getConversationIds() {
|
||||
return conversationIds;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SendTarget {
|
||||
|
||||
private Long conversationId;
|
||||
|
||||
@@ -91,7 +91,7 @@ public class SendControllerTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectUnsupportedTargetType() throws Exception {
|
||||
void shouldRejectEmptyRuleTarget() throws Exception {
|
||||
String tenantCode = "send-" + UUID.randomUUID().toString().substring(0, 8);
|
||||
String authToken = createTenantAndLogin(mockMvc, tenantCode, "发送测试");
|
||||
|
||||
@@ -105,4 +105,167 @@ public class SendControllerTest {
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(-1));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveRuleTargetWithAndLogic() throws Exception {
|
||||
String tenantCode = "send-" + UUID.randomUUID().toString().substring(0, 8);
|
||||
String authToken = createTenantAndLogin(mockMvc, tenantCode, "发送测试");
|
||||
|
||||
Long accountId = createChannelAccount(authToken, tenantCode);
|
||||
Long tagId = createTag(authToken, tenantCode, "rule-and");
|
||||
Long personId = createPerson(authToken, tenantCode, 3);
|
||||
bindPersonTag(authToken, tenantCode, personId, tagId);
|
||||
createPersonIdentity(authToken, tenantCode, personId, "wecom", "user-001");
|
||||
Long conversationId = createConversation(authToken, tenantCode, "wecom", "room-and-001");
|
||||
bindConversationTag(authToken, tenantCode, conversationId, tagId);
|
||||
bindConversationAccount(authToken, tenantCode, conversationId, accountId);
|
||||
|
||||
String sendPayload = String.format(
|
||||
"{\"targetType\":\"rule\",\"targetValue\":{\"rules\":[{\"field\":\"tag\",\"operator\":\"in\",\"value\":[%d]},{\"field\":\"person_type\",\"operator\":\"eq\",\"value\":3},{\"field\":\"channel_type\",\"operator\":\"eq\",\"value\":\"wecom\"}],\"logic\":\"and\"},\"contentType\":\"text\",\"content\":{\"text\":\"hello\"},\"channelStrategy\":{\"channel_type\":\"wecom\",\"strategy\":\"primary\"}}",
|
||||
tagId);
|
||||
mockMvc.perform(post("/msg-platform/api/v1/send/test")
|
||||
.contextPath("/msg-platform")
|
||||
.header("Authorization", authToken)
|
||||
.header("X-Tenant-Code", tenantCode)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(sendPayload))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.totalCount").value(2))
|
||||
.andExpect(jsonPath("$.data.status").value("simulated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldResolveRuleTargetWithOrLogic() throws Exception {
|
||||
String tenantCode = "send-" + UUID.randomUUID().toString().substring(0, 8);
|
||||
String authToken = createTenantAndLogin(mockMvc, tenantCode, "发送测试");
|
||||
|
||||
Long accountId = createChannelAccount(authToken, tenantCode);
|
||||
Long personId = createPerson(authToken, tenantCode, 3);
|
||||
createPersonIdentity(authToken, tenantCode, personId, "wecom", "user-002");
|
||||
Long conversationId = createConversation(authToken, tenantCode, "wecom", "room-or-001");
|
||||
bindConversationAccount(authToken, tenantCode, conversationId, accountId);
|
||||
|
||||
String sendPayload = "{\"targetType\":\"rule\",\"targetValue\":{\"rules\":[{\"field\":\"person_type\",\"operator\":\"eq\",\"value\":3},{\"field\":\"channel_type\",\"operator\":\"eq\",\"value\":\"wecom\"}],\"logic\":\"or\"},\"contentType\":\"text\",\"content\":{\"text\":\"hello\"},\"channelStrategy\":{\"channel_type\":\"wecom\",\"strategy\":\"primary\"}}";
|
||||
mockMvc.perform(post("/msg-platform/api/v1/send/test")
|
||||
.contextPath("/msg-platform")
|
||||
.header("Authorization", authToken)
|
||||
.header("X-Tenant-Code", tenantCode)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(sendPayload))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andExpect(jsonPath("$.data.totalCount").value(2))
|
||||
.andExpect(jsonPath("$.data.status").value("simulated"));
|
||||
}
|
||||
|
||||
private Long createChannelAccount(String authToken, String tenantCode) throws Exception {
|
||||
String accountPayload = "{\"accountType\":1,\"channelType\":\"wecom\",\"accountId\":\"ZhangSan\",\"accountName\":\"张三\"}";
|
||||
String accountResponse = mockMvc.perform(post("/msg-platform/api/v1/channel-account")
|
||||
.contextPath("/msg-platform")
|
||||
.header("Authorization", authToken)
|
||||
.header("X-Tenant-Code", tenantCode)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(accountPayload))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
return ((Number) com.jayway.jsonpath.JsonPath.read(accountResponse, "$.data.id")).longValue();
|
||||
}
|
||||
|
||||
private Long createTag(String authToken, String tenantCode, String tagName) throws Exception {
|
||||
String tagPayload = String.format("{\"parentId\":0,\"tagName\":\"%s\"}", tagName);
|
||||
String tagResponse = mockMvc.perform(post("/msg-platform/api/v1/tag")
|
||||
.contextPath("/msg-platform")
|
||||
.header("Authorization", authToken)
|
||||
.header("X-Tenant-Code", tenantCode)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(tagPayload))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
return ((Number) com.jayway.jsonpath.JsonPath.read(tagResponse, "$.data.id")).longValue();
|
||||
}
|
||||
|
||||
private Long createPerson(String authToken, String tenantCode, int personType) throws Exception {
|
||||
String personPayload = String.format("{\"personCode\":\"P-%d\",\"personName\":\"张三\",\"phone\":\"13800138000\",\"personType\":%d}", personType, personType);
|
||||
String personResponse = mockMvc.perform(post("/msg-platform/api/v1/person")
|
||||
.contextPath("/msg-platform")
|
||||
.header("Authorization", authToken)
|
||||
.header("X-Tenant-Code", tenantCode)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(personPayload))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
return ((Number) com.jayway.jsonpath.JsonPath.read(personResponse, "$.data.id")).longValue();
|
||||
}
|
||||
|
||||
private void createPersonIdentity(String authToken, String tenantCode, Long personId,
|
||||
String channelType, String channelUserId) throws Exception {
|
||||
String identityPayload = String.format("{\"channelType\":\"%s\",\"channelUserId\":\"%s\"}", channelType, channelUserId);
|
||||
mockMvc.perform(post("/msg-platform/api/v1/person/" + personId + "/identities")
|
||||
.contextPath("/msg-platform")
|
||||
.header("Authorization", authToken)
|
||||
.header("X-Tenant-Code", tenantCode)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(identityPayload))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0));
|
||||
}
|
||||
|
||||
private void bindPersonTag(String authToken, String tenantCode, Long personId, Long tagId) throws Exception {
|
||||
String bindPayload = String.format("{\"tagIds\":[%d]}", tagId);
|
||||
mockMvc.perform(post("/msg-platform/api/v1/person/" + personId + "/bind-tags")
|
||||
.contextPath("/msg-platform")
|
||||
.header("Authorization", authToken)
|
||||
.header("X-Tenant-Code", tenantCode)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(bindPayload))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0));
|
||||
}
|
||||
|
||||
private Long createConversation(String authToken, String tenantCode, String channelType,
|
||||
String channelConversationId) throws Exception {
|
||||
String conversationPayload = String.format(
|
||||
"{\"conversationType\":2,\"channelType\":\"%s\",\"channelConversationId\":\"%s\",\"conversationName\":\"测试群\"}",
|
||||
channelType, channelConversationId);
|
||||
String conversationResponse = mockMvc.perform(post("/msg-platform/api/v1/conversation")
|
||||
.contextPath("/msg-platform")
|
||||
.header("Authorization", authToken)
|
||||
.header("X-Tenant-Code", tenantCode)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(conversationPayload))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0))
|
||||
.andReturn().getResponse().getContentAsString();
|
||||
return ((Number) com.jayway.jsonpath.JsonPath.read(conversationResponse, "$.data.id")).longValue();
|
||||
}
|
||||
|
||||
private void bindConversationTag(String authToken, String tenantCode, Long conversationId,
|
||||
Long tagId) throws Exception {
|
||||
String bindPayload = String.format("{\"tagIds\":[%d]}", tagId);
|
||||
mockMvc.perform(post("/msg-platform/api/v1/conversation/" + conversationId + "/bind-tags")
|
||||
.contextPath("/msg-platform")
|
||||
.header("Authorization", authToken)
|
||||
.header("X-Tenant-Code", tenantCode)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(bindPayload))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0));
|
||||
}
|
||||
|
||||
private void bindConversationAccount(String authToken, String tenantCode, Long conversationId,
|
||||
Long accountId) throws Exception {
|
||||
String bindPayload = String.format("{\"accountId\":%d,\"bindingType\":1,\"sortOrder\":1}", accountId);
|
||||
mockMvc.perform(post("/msg-platform/api/v1/conversation/" + conversationId + "/bind-account")
|
||||
.contextPath("/msg-platform")
|
||||
.header("Authorization", authToken)
|
||||
.header("X-Tenant-Code", tenantCode)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(bindPayload))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("$.code").value(0));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user