|
@@ -7,6 +7,7 @@ import com.tzld.piaoquan.risk.control.model.po.UserBase;
|
|
|
import com.tzld.piaoquan.risk.control.model.po.WorkWechatRoomInfo;
|
|
|
import com.tzld.piaoquan.risk.control.model.po.WorkWechatRoomInfoExample;
|
|
|
import com.tzld.piaoquan.risk.control.model.qywx.*;
|
|
|
+import com.tzld.piaoquan.risk.control.service.BlacklistService;
|
|
|
import com.tzld.piaoquan.risk.control.util.HttpClientUtil;
|
|
|
import com.tzld.piaoquan.risk.control.util.HttpPoolClient;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
@@ -26,79 +27,40 @@ public class RiskUserOperateService {
|
|
|
private QywxConfig qywxConfig; // 注入配置类
|
|
|
@Autowired
|
|
|
private WorkWechatRoomInfoMapper workWechatRoomInfoMapper;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 黑名单管理服务,用于替换硬编码的黑名单检查逻辑
|
|
|
+ */
|
|
|
+ @Autowired
|
|
|
+ private BlacklistService blacklistService;
|
|
|
@Value("${qywx.corpid}")
|
|
|
private long corpid;
|
|
|
private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(10000, 10000, 2000, 5000, 5, 10000);
|
|
|
- private static final Logger LOGGER = LoggerFactory.getLogger(RiskUserHandleService.class);
|
|
|
-// private static final List<Long> BLACKLIST_VID = Collections.unmodifiableList(Arrays.asList(7881302926289574L,7881299753025521L));
|
|
|
- // 初始化不可变黑名单(合并现有值和JSON中的新值)
|
|
|
- private static final List<Long> BLACKLIST_VID = Collections.unmodifiableList(
|
|
|
- Arrays.asList(
|
|
|
- // 原始值
|
|
|
- 7881302926289574L,
|
|
|
- 7881299753025521L,
|
|
|
- // 从JSON数据中提取的所有blacklist_vid(已去重)
|
|
|
- 7881300466122683L, 7881300229048031L, 7881302316912185L,
|
|
|
- 7881301869028248L, 7881301211163085L, 7881302796091767L,
|
|
|
- 7881301324066702L, 7881300281998722L, 7881301967034720L,
|
|
|
- 7881301678337366L, 7881300378068659L, 7881302223127319L,
|
|
|
- 7881299679315751L, 7881302327344543L, 7881303556905502L,
|
|
|
- 7881300420063544L, 7881303114007258L, 7881299609215302L,
|
|
|
- 7881303411344664L, 7881300499073181L, 7881302121982115L,
|
|
|
- 7881301622998984L, 7881302715121782L, 7881301469189163L,
|
|
|
- 7881301825004114L, 7881303480126257L, 7881303502084260L,
|
|
|
- 7881300158073529L, 7881300519959317L, 7881301866079037L,
|
|
|
- 7881303096191474L, 7881303368954132L, 7881302764132335L,
|
|
|
- 7881302001968032L, 7881302064983891L, 7881303276328299L,
|
|
|
- 7881302018273598L, 7881303641326502L, 7881301501262524L,
|
|
|
- 7881301460217143L, 7881299789313131L, 7881300854349663L,
|
|
|
- 7881301505271795L, 7881300193294802L, 7881300949997575L,
|
|
|
- 7881302066324600L, 7881301257978308L, 7881303083154066L,
|
|
|
- 7881300846203333L, 7881301661295267L, 7881300149063751L,
|
|
|
- 7881303421311587L, 7881300317046467L, 7881301426914509L,
|
|
|
- 7881301034118168L, 7881303360258534L, 7881300540110306L,
|
|
|
- 7881303335206573L, 7881301178336419L, 7881299476125798L,
|
|
|
- 7881302710301946L, 7881301346342921L, 7881300543276102L,
|
|
|
- 7881302549156012L, 7881300984974896L, 7881300905339945L,
|
|
|
- 7881300014351503L, 7881299626065317L, 1688858033727935L,
|
|
|
- 7881303486038982L, 7881301946106537L, 7881303093341615L,
|
|
|
- 7881300064125930L, 7881301841001514L, 7881303046088935L,
|
|
|
- 7881302404997826L, 7881302075019397L, 7881300148942179L,
|
|
|
- 7881299647166280L, 7881299915041354L, 7881300444249607L,
|
|
|
- 7881300767993441L, 7881302633972298L, 7881300416188902L,
|
|
|
- 7881303513904106L, 7881300749032748L, 7881300268925255L,
|
|
|
- 7881303315067789L, 7881300808351909L, 7881300791125480L,
|
|
|
- 7881302408161558L, 7881302137137423L, 7881301119340365L,
|
|
|
- 7881302367951032L, 7881301267044221L, 7881301416981370L,
|
|
|
- 7881300843989486L, 7881302471324028L, 7881301871965471L,
|
|
|
- 7881301393187836L, 7881301698289157L, 7881303388311144L,
|
|
|
- 7881300820304366L, 7881299665950989L, 7881301992001273L,
|
|
|
- 7881302286953152L, 7881299836040719L, 7881300144150372L,
|
|
|
- 7881302832139110L, 7881302260054092L, 7881300488072079L,
|
|
|
- 7881299606154483L, 7881302132328341L, 7881301177020994L,
|
|
|
- 7881299603349260L, 7881301200004722L, 7881300437123751L,
|
|
|
- 7881301055969437L, 7881301654914877L, 7881300090992802L,
|
|
|
- 7881300090924829L, 7881300095962888L, 7881301643139014L,
|
|
|
- 7881303024343207L, 7881302048307942L, 7881303218068450L,
|
|
|
- 7881301852350459L, 7881301482317014L, 7881301843321743L,
|
|
|
- 7881302927306074L, 7881302900372515L, 7881302628314176L,
|
|
|
- 7881302733026214L, 7881303417300674L, 7881301797041258L,
|
|
|
- 7881302328298167L, 7881299771077377L, 7881301278033375L,
|
|
|
- 7881299963273148L, 7881299551165243L, 7881302964181882L,
|
|
|
- 7881300960043108L, 7881303282925921L, 7881301679355925L,
|
|
|
- 7881303320029350L, 7881299472340204L, 7881303594961434L,
|
|
|
- 7881300778933287L, 7881303467988227L, 7881299452963981L,
|
|
|
- 7881301668344400L, 7881303357010444L, 7881303133173876L,
|
|
|
- 7881303227934766L, 7881300066348945L, 7881301311983065L,
|
|
|
- 7881302496352111L, 7881299632359909L, 7881303344140343L,
|
|
|
- 7881301136317724L, 7881301988332126L, 7881300283335703L,
|
|
|
- 7881301475333555L, 7881301678333870L
|
|
|
- )
|
|
|
-);
|
|
|
+ private static final Logger logger = LoggerFactory.getLogger(RiskUserHandleService.class);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * 原硬编码黑名单常量已移除,改为使用数据库动态管理
|
|
|
+ *
|
|
|
+ * 迁移说明:
|
|
|
+ * 1. 原BLACKLIST_VID常量包含约120个用户VID
|
|
|
+ * 2. 这些VID已通过管理界面手动迁移到qywx_blacklist_user表中
|
|
|
+ * 3. 现在通过BlacklistService.isInBlacklist()方法进行黑名单检查
|
|
|
+ * 4. 支持动态添加、删除黑名单用户,无需重启服务
|
|
|
+ *
|
|
|
+ * 原硬编码数据备份(仅供参考,已迁移到数据库):
|
|
|
+ * private static final List<Long> BLACKLIST_VID = Collections.unmodifiableList(
|
|
|
+ * Arrays.asList(
|
|
|
+ * 7881302926289574L, 7881299753025521L, 7881300466122683L, ...
|
|
|
+ * // 共约120个VID,完整列表见数据迁移文档
|
|
|
+ * )
|
|
|
+ * );
|
|
|
+ */
|
|
|
|
|
|
/**
|
|
|
* 快速踢人功能 - 当检测到新成员加入群聊时,立即执行踢人操作
|
|
|
*
|
|
|
+ * 重构说明:使用数据库查询替换硬编码的黑名单检查
|
|
|
+ *
|
|
|
* @param message 群聊新增成员消息,包含新加入的成员信息
|
|
|
* @param uuid 企业微信用户的唯一标识符
|
|
|
* @return true-踢人成功,false-踢人失败或不满足踢人条件
|
|
@@ -113,20 +75,26 @@ public class RiskUserOperateService {
|
|
|
|
|
|
// 检查成员列表是否为空
|
|
|
if(message.getMemberList().isEmpty()) {
|
|
|
+ logger.warn("quickKick: member list is empty, skipping operation");
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
// 获取第一个新加入的成员VID(企业微信内部用户ID)
|
|
|
long vid = message.getMemberList().get(0);
|
|
|
|
|
|
- // 黑名单检查 - 如果用户不在黑名单中,则跳过踢人操作(保护重要用户)
|
|
|
- if(!BLACKLIST_VID.contains(vid)) {
|
|
|
- LOGGER.info("quickKick, vid: {} is in blacklist, skip kick", vid);
|
|
|
+ // 黑名单检查 - 使用数据库查询替换硬编码检查
|
|
|
+ try {
|
|
|
+ if( !blacklistService.isInBlacklist(vid)) {
|
|
|
+ logger.info("quickKick: vid {} is not in blacklist, skip kick operation", vid);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("quickKick: failed to check blacklist for vid {}, skipping kick for safety", vid, e);
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- // 如果是群聊,直接踢出
|
|
|
- LOGGER.info("quickKick, message: {}, uuid: {}", message, uuid);
|
|
|
+ // 群聊,直接踢出
|
|
|
+ logger.info("quickKick, message: {}, uuid: {}", message, uuid);
|
|
|
|
|
|
// 设置要踢出的用户VID列表
|
|
|
requestBody.put("blacklist_vid",Arrays.asList(message.getMemberList().get(0)));
|
|
@@ -144,15 +112,15 @@ public class RiskUserOperateService {
|
|
|
|
|
|
// 检查操作是否成功(errcode=0表示成功)
|
|
|
if (roomInfo.getErrcode() == 0) {
|
|
|
- LOGGER.info("quick Kick external user {} from room {} successfully", vid);
|
|
|
+ logger.info("quick Kick external user {} from room {} successfully", vid);
|
|
|
return true;
|
|
|
} else {
|
|
|
// 踢人失败,记录错误信息
|
|
|
- LOGGER.error("Failed to kick external user {} f: {}", vid, roomInfo.getErrmsg());
|
|
|
+ logger.error("Failed to kick external user {} f: {}", vid, roomInfo.getErrmsg());
|
|
|
}
|
|
|
} else {
|
|
|
// API调用失败,没有收到响应
|
|
|
- LOGGER.error("Failed to kick external user {} from : No response", vid);
|
|
|
+ logger.error("Failed to kick external user {} from : No response", vid);
|
|
|
}
|
|
|
|
|
|
// 默认返回失败
|
|
@@ -163,41 +131,44 @@ public class RiskUserOperateService {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- public boolean checkAndKickExternalUser(UserBase staff,RiskUserInfo riskUserInfo,long vid,long roomId) {
|
|
|
- LOGGER.info("checkAndKickExternalUser, staff: {}, riskUserInfo: {}, vid: {}, roomId: {}", staff, riskUserInfo, vid, roomId);
|
|
|
- boolean inRoom = isInRoom(staff, roomId, vid);
|
|
|
- if (!inRoom) {
|
|
|
- LOGGER.info("User {} is not in room {}", vid, roomId);
|
|
|
- return false;
|
|
|
- }
|
|
|
- LOGGER.info("User {} is in room {}", vid, roomId);
|
|
|
- kick(staff, roomId, vid);
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
+ /**
|
|
|
+ * 踢人功能 - 将指定用户从指定群聊中踢出
|
|
|
+ *
|
|
|
+ * 重构说明:使用数据库查询替换硬编码的黑名单检查
|
|
|
+ *
|
|
|
+ * @param staff 执行踢人操作的员工信息
|
|
|
+ * @param roomId 群聊ID
|
|
|
+ * @param vid 要踢出的用户VID
|
|
|
+ * @return true-踢人成功或跳过,false-踢人失败
|
|
|
+ */
|
|
|
public boolean kick(UserBase staff, long roomId, long vid) {
|
|
|
- if(BLACKLIST_VID.contains(vid)) {
|
|
|
- LOGGER.info("kick, vid: {} is in blacklist, skip normal kick", vid);
|
|
|
- return true;
|
|
|
+ // 黑名单检查 - 使用数据库查询替换硬编码检查
|
|
|
+ try {
|
|
|
+ if(blacklistService.isInBlacklist(vid)) {
|
|
|
+ logger.info("kick: vid {} is in blacklist, skip normal kick operation", vid);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ logger.debug("kick: vid {} is not in blacklist, proceeding with kick operation", vid);
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("kick: failed to check blacklist for vid {}", vid, e);
|
|
|
}
|
|
|
Map<String, Object> requestBody = new HashMap<>();
|
|
|
requestBody.put("uuid", staff.getUuid());
|
|
|
requestBody.put("oprType", 1);
|
|
|
requestBody.put("blacklist_vid",Arrays.asList(vid));
|
|
|
String params = JSON.toJSONString(requestBody);
|
|
|
- LOGGER.info("kick, staff: {}, params: {}", staff, params);
|
|
|
+ logger.info("kick, staff: {}, params: {}", staff, params);
|
|
|
Optional<String> response = httpPoolClientDefault.postJson(qywxConfig.getDomain() + qywxConfig.getPath("kick-external"), params);
|
|
|
if (response.isPresent()) {
|
|
|
QwCommonResModel<RoomListResponse> roomInfo = QwCommonResModel.parseResponse(response.get(), RoomListResponse.class);
|
|
|
if (roomInfo.getErrcode() == 0) {
|
|
|
- LOGGER.info("Kick external user {} from room {} successfully", vid, roomId);
|
|
|
+ logger.info("Kick external user {} from room {} successfully", vid, roomId);
|
|
|
return true;
|
|
|
} else {
|
|
|
- LOGGER.error("Failed to kick external user {} from room {}: {}", vid, roomId, roomInfo.getErrmsg());
|
|
|
+ logger.error("Failed to kick external user {} from room {}: {}", vid, roomId, roomInfo.getErrmsg());
|
|
|
}
|
|
|
} else {
|
|
|
- LOGGER.error("Failed to kick external user {} from room {}: No response", vid, roomId);
|
|
|
+ logger.error("Failed to kick external user {} from room {}: No response", vid, roomId);
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
@@ -206,12 +177,12 @@ public class RiskUserOperateService {
|
|
|
public boolean isInRoom(UserBase staff, long roomId,long vid) {
|
|
|
List<RoomMemberListInfo.Member> memberList = getRoomMemberList(staff, roomId);
|
|
|
if (memberList == null || memberList.isEmpty()) {
|
|
|
- LOGGER.info("isInRoom, memberList is empty");
|
|
|
+ logger.info("isInRoom, memberList is empty");
|
|
|
return false;
|
|
|
}
|
|
|
- LOGGER.info("isInRoom, memberList: {}", memberList);
|
|
|
+ logger.info("isInRoom, memberList: {}", memberList);
|
|
|
for (RoomMemberListInfo.Member member : memberList) {
|
|
|
- LOGGER.info("isInRoom, member: {}", member);
|
|
|
+ logger.info("isInRoom, member: {}", member);
|
|
|
if (member.getUin() == vid && member.getJoinScene() == 3) {
|
|
|
return true;
|
|
|
}
|
|
@@ -226,7 +197,7 @@ public class RiskUserOperateService {
|
|
|
String params = JSON.toJSONString(requestBody);
|
|
|
String url = qywxConfig.getDomain() + qywxConfig.getPath("get-roomMembers");
|
|
|
Optional<String> response = httpPoolClientDefault.postJson(url, params);
|
|
|
- LOGGER.info("getRoomMemberList, params: {}, response: {},url: {}", params, response, url);
|
|
|
+ logger.info("getRoomMemberList, params: {}, response: {},url: {}", params, response, url);
|
|
|
List<RoomMemberListInfo.Member> memberList = new ArrayList<>();
|
|
|
if (response.isPresent()) {
|
|
|
QwCommonResModel<RoomMemberListInfo> memberInfo = QwCommonResModel.parseResponse(response.get(), RoomMemberListInfo.class);
|