管理员权限
This commit is contained in:
parent
aaaee18491
commit
a6d7ec6349
@ -2,7 +2,9 @@ package com.company.agentfoundation.config;
|
|||||||
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@ConfigurationProperties(prefix = "foundation")
|
@ConfigurationProperties(prefix = "foundation")
|
||||||
@ -124,6 +126,7 @@ public class FoundationProperties {
|
|||||||
private Integer agentId;
|
private Integer agentId;
|
||||||
private String secret;
|
private String secret;
|
||||||
private String callbackPath;
|
private String callbackPath;
|
||||||
|
private List<String> adminUserIds = new ArrayList<>();
|
||||||
|
|
||||||
public String getName() { return name; }
|
public String getName() { return name; }
|
||||||
public void setName(String name) { this.name = name; }
|
public void setName(String name) { this.name = name; }
|
||||||
@ -133,6 +136,8 @@ public class FoundationProperties {
|
|||||||
public void setSecret(String secret) { this.secret = secret; }
|
public void setSecret(String secret) { this.secret = secret; }
|
||||||
public String getCallbackPath() { return callbackPath; }
|
public String getCallbackPath() { return callbackPath; }
|
||||||
public void setCallbackPath(String callbackPath) { this.callbackPath = callbackPath; }
|
public void setCallbackPath(String callbackPath) { this.callbackPath = callbackPath; }
|
||||||
|
public List<String> getAdminUserIds() { return adminUserIds; }
|
||||||
|
public void setAdminUserIds(List<String> adminUserIds) { this.adminUserIds = adminUserIds; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
package com.company.agentfoundation.crm.report;
|
package com.company.agentfoundation.crm.report;
|
||||||
|
|
||||||
|
import com.company.agentfoundation.config.FoundationProperties;
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.springframework.dao.EmptyResultDataAccessException;
|
import org.springframework.dao.EmptyResultDataAccessException;
|
||||||
@ -40,10 +41,16 @@ public class CustomerDailyReportService {
|
|||||||
|
|
||||||
private final NamedParameterJdbcTemplate jdbc;
|
private final NamedParameterJdbcTemplate jdbc;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
|
private final FoundationProperties foundationProperties;
|
||||||
|
|
||||||
public CustomerDailyReportService(NamedParameterJdbcTemplate jdbc, ObjectMapper objectMapper) {
|
public CustomerDailyReportService(
|
||||||
|
NamedParameterJdbcTemplate jdbc,
|
||||||
|
ObjectMapper objectMapper,
|
||||||
|
FoundationProperties foundationProperties
|
||||||
|
) {
|
||||||
this.jdbc = jdbc;
|
this.jdbc = jdbc;
|
||||||
this.objectMapper = objectMapper;
|
this.objectMapper = objectMapper;
|
||||||
|
this.foundationProperties = foundationProperties;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, Object> generate(CustomerDailyReportRequest request) {
|
public Map<String, Object> generate(CustomerDailyReportRequest request) {
|
||||||
@ -116,8 +123,12 @@ public class CustomerDailyReportService {
|
|||||||
|
|
||||||
private Caller resolveCaller(String wecomUserId) {
|
private Caller resolveCaller(String wecomUserId) {
|
||||||
String safeUserId = clean(wecomUserId);
|
String safeUserId = clean(wecomUserId);
|
||||||
|
if (isSportsVenueAdmin(safeUserId)) {
|
||||||
|
return new Caller(safeUserId, true, safeUserId, "企业微信管理员", "", "", "企业微信应用管理员",
|
||||||
|
"", "WECOM_APP_ADMIN", "ALL_ORGANIZATION");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return jdbc.queryForObject("""
|
Caller direct = jdbc.queryForObject("""
|
||||||
SELECT COALESCE(NULLIF(u.user_id, ''), c.boss_user_id, '') user_id,
|
SELECT COALESCE(NULLIF(u.user_id, ''), c.boss_user_id, '') user_id,
|
||||||
COALESCE(NULLIF(u.name, ''), c.name, '') name,
|
COALESCE(NULLIF(u.name, ''), c.name, '') name,
|
||||||
COALESCE(u.organization_id, '') organization_id,
|
COALESCE(u.organization_id, '') organization_id,
|
||||||
@ -130,17 +141,26 @@ public class CustomerDailyReportService {
|
|||||||
(rs, row) -> caller(safeUserId, rs.getString("user_id"), rs.getString("name"),
|
(rs, row) -> caller(safeUserId, rs.getString("user_id"), rs.getString("name"),
|
||||||
rs.getString("organization_id"), rs.getString("organization_name"),
|
rs.getString("organization_id"), rs.getString("organization_name"),
|
||||||
rs.getString("role_names"), rs.getString("manage_organizations"), "WECOM_USER_ID", ""));
|
rs.getString("role_names"), rs.getString("manage_organizations"), "WECOM_USER_ID", ""));
|
||||||
|
return direct != null && direct.resolved() ? direct : resolveLegacy(safeUserId);
|
||||||
} catch (EmptyResultDataAccessException ignored) {
|
} catch (EmptyResultDataAccessException ignored) {
|
||||||
return resolveLegacy(safeUserId);
|
return resolveLegacy(safeUserId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isSportsVenueAdmin(String wecomUserId) {
|
||||||
|
FoundationProperties.Wecom.App app = foundationProperties.getWecom().getApps().get("sports-venue");
|
||||||
|
return app != null && app.getAdminUserIds() != null && app.getAdminUserIds().stream()
|
||||||
|
.filter(id -> id != null && !id.isBlank())
|
||||||
|
.anyMatch(id -> id.trim().equalsIgnoreCase(wecomUserId));
|
||||||
|
}
|
||||||
|
|
||||||
private Caller resolveLegacy(String wecomUserId) {
|
private Caller resolveLegacy(String wecomUserId) {
|
||||||
Map<String, Object> legacy;
|
Map<String, Object> legacy;
|
||||||
try {
|
try {
|
||||||
legacy = jdbc.queryForMap("""
|
legacy = jdbc.queryForMap("""
|
||||||
SELECT employee_name, COALESCE(xuebang_account, '') xuebang_account,
|
SELECT employee_name, COALESCE(xuebang_account, '') xuebang_account,
|
||||||
COALESCE(data_scope_type, '') data_scope_type
|
COALESCE(data_scope_type, '') data_scope_type,
|
||||||
|
COALESCE(primary_role_name, '') primary_role_name
|
||||||
FROM employee_directory WHERE wecom_user_id = :wecomUserId LIMIT 1
|
FROM employee_directory WHERE wecom_user_id = :wecomUserId LIMIT 1
|
||||||
""", Map.of("wecomUserId", wecomUserId));
|
""", Map.of("wecomUserId", wecomUserId));
|
||||||
} catch (EmptyResultDataAccessException ignored) {
|
} catch (EmptyResultDataAccessException ignored) {
|
||||||
@ -163,9 +183,14 @@ public class CustomerDailyReportService {
|
|||||||
""".formatted(USER), Map.of()).stream()
|
""".formatted(USER), Map.of()).stream()
|
||||||
.filter(row -> normalized.equals(normalizeName(text(row, "name"))))
|
.filter(row -> normalized.equals(normalizeName(text(row, "name"))))
|
||||||
.toList();
|
.toList();
|
||||||
return matches.size() == 1
|
if (matches.size() == 1) {
|
||||||
? callerFromRow(wecomUserId, matches.get(0), "NORMALIZED_UNIQUE_NAME", text(legacy, "data_scope_type"))
|
return callerFromRow(wecomUserId, matches.get(0), "NORMALIZED_UNIQUE_NAME", text(legacy, "data_scope_type"));
|
||||||
: Caller.unresolved(wecomUserId);
|
}
|
||||||
|
if ("ALL_ORGANIZATION".equalsIgnoreCase(text(legacy, "data_scope_type"))) {
|
||||||
|
return new Caller(wecomUserId, true, wecomUserId, text(legacy, "employee_name"), "", "",
|
||||||
|
text(legacy, "primary_role_name"), "", "LEGACY_ADMIN_SCOPE", "ALL_ORGANIZATION");
|
||||||
|
}
|
||||||
|
return Caller.unresolved(wecomUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Caller callerFromRow(String wecomUserId, Map<String, Object> row, String method, String legacyScope) {
|
private Caller callerFromRow(String wecomUserId, Map<String, Object> row, String method, String legacyScope) {
|
||||||
|
|||||||
@ -27,7 +27,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
public class WecomCallbackController {
|
public class WecomCallbackController {
|
||||||
private static final Logger log = LoggerFactory.getLogger(WecomCallbackController.class);
|
private static final Logger log = LoggerFactory.getLogger(WecomCallbackController.class);
|
||||||
private static final long MESSAGE_DEDUP_TTL_SECONDS = 600;
|
private static final long MESSAGE_DEDUP_TTL_SECONDS = 600;
|
||||||
private static final String ERROR_REPLY = "语义识别或业务查询失败,请稍后重试";
|
private static final String GENERAL_ERROR_REPLY = "扣子问答调用失败,请稍后重试。";
|
||||||
|
private static final String SEMANTIC_ERROR_REPLY = "语义识别或业务查询失败,请稍后重试。";
|
||||||
private static final String GENERAL_APP = "general";
|
private static final String GENERAL_APP = "general";
|
||||||
private static final String SPORTS_VENUE_APP = "sports-venue";
|
private static final String SPORTS_VENUE_APP = "sports-venue";
|
||||||
private final SemanticDispatchService semanticDispatchService;
|
private final SemanticDispatchService semanticDispatchService;
|
||||||
@ -162,12 +163,13 @@ public class WecomCallbackController {
|
|||||||
? cozeWorkflowService.chatDefault(userText)
|
? cozeWorkflowService.chatDefault(userText)
|
||||||
: semanticDispatchService.dispatch(msg.getFromUserName(), userText);
|
: semanticDispatchService.dispatch(msg.getFromUserName(), userText);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("wecom callback semantic dispatch failed fromUser={} err={}", msg.getFromUserName(), e.getMessage(), e);
|
log.error("wecom callback processing failed mode={} fromUser={} err={}",
|
||||||
reply = ERROR_REPLY;
|
callbackMode, msg.getFromUserName(), e.getMessage(), e);
|
||||||
|
reply = errorReply(callbackMode);
|
||||||
}
|
}
|
||||||
if (reply == null || reply.isBlank()) {
|
if (reply == null || reply.isBlank()) {
|
||||||
log.warn("wecom callback semantic reply blank, fallback to error reply");
|
log.warn("wecom callback reply blank mode={}, fallback to error reply", callbackMode);
|
||||||
reply = ERROR_REPLY;
|
reply = errorReply(callbackMode);
|
||||||
}
|
}
|
||||||
log.info("wecom callback sending semantic reply toUser={} replyPreview={}", msg.getFromUserName(), preview(reply));
|
log.info("wecom callback sending semantic reply toUser={} replyPreview={}", msg.getFromUserName(), preview(reply));
|
||||||
wecomClient.sendText(appKey, msg.getFromUserName(), reply);
|
wecomClient.sendText(appKey, msg.getFromUserName(), reply);
|
||||||
@ -229,6 +231,10 @@ public class WecomCallbackController {
|
|||||||
return text.length() <= 80 ? text : text.substring(0, 80) + "...";
|
return text.length() <= 80 ? text : text.substring(0, 80) + "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String errorReply(CallbackMode callbackMode) {
|
||||||
|
return callbackMode == CallbackMode.GENERAL_CHAT ? GENERAL_ERROR_REPLY : SEMANTIC_ERROR_REPLY;
|
||||||
|
}
|
||||||
|
|
||||||
private enum CallbackMode {
|
private enum CallbackMode {
|
||||||
GENERAL_CHAT,
|
GENERAL_CHAT,
|
||||||
SEMANTIC_ROUTING
|
SEMANTIC_ROUTING
|
||||||
|
|||||||
@ -64,6 +64,11 @@ foundation:
|
|||||||
agent-id: 1000006
|
agent-id: 1000006
|
||||||
secret: V-fh1ROzjb06Hi9XB8VPb4HhE2ApI4j99NAjAXKYOb8
|
secret: V-fh1ROzjb06Hi9XB8VPb4HhE2ApI4j99NAjAXKYOb8
|
||||||
callback-path: /v1/integrations/wecom/sports-venue/callback
|
callback-path: /v1/integrations/wecom/sports-venue/callback
|
||||||
|
admin-user-ids:
|
||||||
|
- TangLong
|
||||||
|
- ChenWenJie
|
||||||
|
- XieChangLei
|
||||||
|
- ZhangYunYun
|
||||||
semantic:
|
semantic:
|
||||||
agent-id: crm-assistant
|
agent-id: crm-assistant
|
||||||
minimum-confidence: 0.60
|
minimum-confidence: 0.60
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user