Browse Source

增加固定规则逻辑,阶段提交

刘立冬 1 month ago
parent
commit
1dbde13706

+ 42 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/model/qywx/UserListFromAdPlatformModel.java

@@ -0,0 +1,42 @@
+package com.tzld.piaoquan.risk.control.model.qywx;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class UserListFromAdPlatformModel {
+    @JSONField(name = "code")
+    private Integer code;
+
+    @JSONField(name = "msg")
+    private String msg;
+
+    @JSONField(name = "data")
+    private List<ChatMember> data;
+
+    @JSONField(name = "success")
+    private Boolean success;
+
+    @Data
+    public static class ChatMember {
+        @JSONField(name = "chatName")
+        private String chatName;
+
+        @JSONField(name = "chatId")
+        private String chatId;
+
+        @JSONField(name = "nickName")
+        private String nickName;
+
+        @JSONField(name = "externalId")
+        private String externalId;
+
+        @JSONField(name = "isAbnormal")
+        private Integer isAbnormal;
+
+        @JSONField(name = "joinTime")
+        private Long joinTime;
+    }
+}

+ 102 - 4
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/service/impl/RiskRuleConfigService.java

@@ -1,20 +1,35 @@
 package com.tzld.piaoquan.risk.control.service.impl;
 
+import com.alibaba.fastjson.JSON;
+import com.tzld.piaoquan.risk.control.config.QywxConfig;
 import com.tzld.piaoquan.risk.control.model.qywx.RoomListResponse;
+import com.tzld.piaoquan.risk.control.model.qywx.UserListFromAdPlatformModel;
+import com.tzld.piaoquan.risk.control.util.HttpClientUtil;
+import com.tzld.piaoquan.risk.control.util.HttpPoolClient;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
 
 @Slf4j
 @Service
 public class RiskRuleConfigService {
     @Autowired
     private WorkWechatServiceImpl workWechatServiceImpl;
+    private static final int USER_COUNT_THRESHOLD = 1; //生效人数阈值
+    private static final int USER_COUNT_THRESHOLD_FOR_ANOMALY_USER_RATIO = 30; //大于30人才触发是否关闭判断
+    private static final float ANOMALY_USER_RATIO = 0.2f; //异常用户比例20%
+
+    @Autowired
+    private QywxConfig config;
+    @Value("${qywx.corpid}")
+    private long corpid;
+    private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(10000, 10000, 2000, 5000, 5, 10000);
+
+    @Value("${getUserList.url:https://api.piaoquantv.com/ad/platform/wechat/group/groupUserDetailData}")
+    private String getUserList;
     Map<String, List<RoomListResponse.RoomInfo>> getKickOpenedRoom(Map<String, List<RoomListResponse.RoomInfo>> tobeOperate) {
         Map<String, List<RoomListResponse.RoomInfo>> filteredMap = new HashMap<>();
 
@@ -35,4 +50,87 @@ public class RiskRuleConfigService {
         return filteredMap;
     }
 
+
+
+    //防止误踢,只有满足存在五个正常群人数才会生效
+    public FixedRuleResult getFixedRulesForThisChat(String chatId) {
+        FixedRuleResult ruleResult = new FixedRuleResult();
+        List<UserListFromAdPlatformModel.ChatMember> memberList = getUserListFromAdPlatform(chatId);
+        if (memberList == null || memberList.isEmpty()) {
+            log.error("checkIfOpenedForFixedRules, memberList is empty for chatId: {}", chatId);
+            return ruleResult;
+        } else {
+            int size = memberList.size();//群总数,包括异常和正常
+            //memberList中isAbnormal是0代表正常用户
+            int normalSize = (int) memberList.stream()
+                    .filter(member -> member.getIsAbnormal() == 0)
+                    .count();
+            ruleResult.normalCount = normalSize;
+            ruleResult.abnormalCount = size - normalSize;
+            if(normalSize >= USER_COUNT_THRESHOLD) {//大于等于3才生效
+                log.info("checkIfOpenedForFixedRules, chatId: {}, size: {}, normalSize: {}", chatId, size, normalSize);
+                //如果群成员大于30人,才判断异常用户比例
+                ruleResult.isNormalCountEnough = true;
+                if (size >= USER_COUNT_THRESHOLD_FOR_ANOMALY_USER_RATIO) {
+                    //计算异常用户比例
+                    float anomalyUserRatio = (float) (size - normalSize) / size;
+                    log.info("checkIfOpenedForFixedRules, chatId: {}, anomalyUserRatio: {}", chatId, anomalyUserRatio);
+                    if (anomalyUserRatio >= ANOMALY_USER_RATIO) {
+                        log.info("checkIfOpenedForFixedRules, chatId: {}, anomalyUserRatio is high enough, opening rules", chatId);
+//                        return false;
+                        ruleResult.isAbnormalRatioHighEnough = true;
+                    } else {
+                        log.info("checkIfOpenedForFixedRules, chatId: {}, anomalyUserRatio is not high enough, not opening rules", chatId);
+                    }
+                }
+                return ruleResult;
+            } else {
+                log.info("checkIfOpenedForFixedRules, chatId: {}, size: {}, normalSize: {}, not enough normal users", chatId, size, normalSize);
+                return ruleResult;
+            }
+
+        }
+
+    }
+
+
+
+    private List<UserListFromAdPlatformModel.ChatMember> getUserListFromAdPlatform(String chatId) {
+        String url = String.format("%s?chatId=%s", getUserList, chatId);
+        List<UserListFromAdPlatformModel.ChatMember> result = Collections.emptyList();
+        log.info("getUserListFromAdPlatform, url: {}", url);
+        Optional<String> response = httpPoolClientDefault.get(url);
+        if (!response.isPresent()) {
+            log.error("getUserListFromAdPlatform, response is empty for chatId: {}", chatId);
+        } else {
+            log.info("getUserListFromAdPlatform, response: {}", response.get());
+            UserListFromAdPlatformModel model =  JSON.parseObject(response.get(), UserListFromAdPlatformModel.class);
+            if (model != null && model.getData() != null) {
+                result = model.getData();
+            } else {
+                log.error("getUserListFromAdPlatform, model is null or data is empty for chatId: {}", chatId);
+                return new ArrayList<>();
+            }
+        }
+        return result;
+    }
+
+    public static class FixedRuleResult {
+        boolean isNormalCountEnough = false;
+        int normalCount = 0;
+        boolean isAbnormalRatioHighEnough = false;
+        float abnormalUserRatio = 0.0f;
+        int abnormalCount = 0;
+
+        @Override
+        public String toString() {
+            return "FixedRuleResult{" +
+                    "isNormalCountEnough=" + isNormalCountEnough +
+                    ", normalCount=" + normalCount +
+                    ", isAbnormalRatioHighEnough=" + isAbnormalRatioHighEnough +
+                    ", abnormalUserRatio=" + abnormalUserRatio +
+                    ", abnormalCount=" + abnormalCount +
+                    '}';
+        }
+    }
 }

+ 12 - 6
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/service/impl/RiskUserHandleService.java

@@ -45,9 +45,7 @@ public class RiskUserHandleService {
         Map<String, List<RoomListResponse.RoomInfo>> toBeOperate = matchUserAndRoom(staffList, riskUserInfo);
         if (toBeOperate.isEmpty()) return 0;
         log.info("handleRiskUser, toBeOperate: {}", toBeOperate);
-        //TODO:检查过滤规则是否配置
         toBeOperate = riskRuleConfigService.getKickOpenedRoom(toBeOperate);
-
         //找到待踢的人,找到终止
         for (Map.Entry<String, List<RoomListResponse.RoomInfo>> entry : toBeOperate.entrySet()) {
             String staffVid = entry.getKey(); // Key: staff vid内部员工
@@ -59,12 +57,20 @@ public class RiskUserHandleService {
                 log.info("handleRiskUser, externalId2Vid error, staff: {}, riskUserInfo: {}", staff, riskUserInfo);
                 continue;
             }
+
             for (RoomListResponse.RoomInfo roomInfo : roomInfoList) {
-                boolean success = riskUserOperateService.checkAndKickExternalUser(staff, riskUserInfo, externalVid,Long.parseLong(roomInfo.getRoomId()));
-                if (success) {
-                    log.info("handleRiskUser to be kick user, vid: {},name: {}", externalVid,riskUserInfo.getExternalNickname());
-                    return 1;
+                RiskRuleConfigService.FixedRuleResult ruleResult = riskRuleConfigService.getFixedRulesForThisChat(riskUserInfo.getChatId());
+                log.info("handleRiskUser, ruleResult: {}, roomInfo: {}", ruleResult, roomInfo);
+                if(ruleResult.isNormalCountEnough && !ruleResult.isAbnormalRatioHighEnough) {//正常进入用户满足需求,且异常率符合阈值
+                    boolean success = riskUserOperateService.checkAndKickExternalUser(staff, riskUserInfo, externalVid,Long.parseLong(roomInfo.getRoomId()));
+                    if (success) {
+                        log.info("handleRiskUser to be kick user, vid: {},name: {}", externalVid,riskUserInfo.getExternalNickname());
+                        return 1;
+                    }
+                } else {
+                    log.info("handleRiskUser, ruleResult not enough, isNormalCountEnough: {}, isAnomalyUserRatioEnough: {}", ruleResult.isNormalCountEnough, ruleResult.isAbnormalRatioHighEnough);
                 }
+
             }
         }
         return 0;

+ 29 - 0
risk-control-core/src/main/java/com/tzld/piaoquan/risk/control/service/impl/RiskUserOperateService.java

@@ -24,6 +24,9 @@ import java.util.*;
 public class RiskUserOperateService {
     @Autowired
     private QywxConfig qywxConfig; // 注入配置类
+
+    @Value("${qywx.corpid}")
+    private long corpid;
     @Autowired
     private QywxUserDataService qwUserService;
     private static final HttpPoolClient httpPoolClientDefault = HttpClientUtil.create(10000, 10000, 2000, 5000, 5, 10000);
@@ -96,4 +99,30 @@ public class RiskUserOperateService {
         }
         return memberList;
     }
+
+    public void findRoomAndClosed(List<RoomListResponse.RoomInfo> filerRooms, String chatId, UserBase staff) {
+        if (filerRooms == null || filerRooms.isEmpty()) {
+            log.info("findRoomAndClosed, filerRooms is empty for chatId: {}", chatId);
+            return;
+        }
+        String url = qywxConfig.getDomain() + qywxConfig.getPath("chatIdToRoomId");
+        Map<String, Object> requestBody = new HashMap<>();
+        requestBody.put("uuid", staff.getUuid());
+        requestBody.put("corpid", corpid);
+        requestBody.put("chatid", chatId);
+        Optional<String> result = httpPoolClientDefault.postJson(url,JSON.toJSONString(requestBody));
+        if (!result.isPresent()) {
+            log.error("findRoomAndClosed, result is empty for chatId: {}", chatId);
+            return;
+        } else {
+            String roomId = "";
+            try {
+                roomId = JSON.parseObject(result.get()).getJSONObject("data").getString("room_id");
+            } catch (Exception e) {
+                log.error("findRoomAndClosed, error parsing response: {}", result.get(), e);
+                return;
+            }
+        }
+
+    }
 }

+ 2 - 4
risk-control-server/src/main/resources/application.yml

@@ -42,7 +42,5 @@ qywx:
     get-chatList: /wxwork/GetChatroomMembers
     get-roomMembers: /wxwork/GetRoomUserList
     kick-external: /wxwork/addOrSubRoomBlackList
-
-    # 其他路径可继续添加,例如:
-    # login: /login
-    # send-msg: /send-msg
+getUserList:
+  url: "https://api.piaoquantv.com/ad/platform/wechat/group/groupUserDetailData"  # 测试获取用户列表地址

+ 11 - 7
risk-control-server/src/test/java/com/tzld/piaoquan/risk/control/service/DemoServiceTest.java

@@ -3,6 +3,7 @@ package com.tzld.piaoquan.risk.control.service;
 import com.alibaba.fastjson.JSON;
 import com.tzld.piaoquan.risk.control.BaseTest;
 import com.tzld.piaoquan.risk.control.model.qywx.RiskUserInfo;
+import com.tzld.piaoquan.risk.control.service.impl.RiskRuleConfigService;
 import com.tzld.piaoquan.risk.control.service.impl.RiskUserHandleService;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -17,18 +18,21 @@ public class DemoServiceTest extends BaseTest {
     private MongoTemplate mongoTemplate;
     @Autowired
     private RiskUserHandleService riskUserHandleService;
+    @Autowired
+    private RiskRuleConfigService riskRuleConfigService;
 
     @Test
     void test(){
 //        String riskInfo = "{\"chat_id\":\"wrreQkBgAAqfC7PyfSzRwj2ailPbXImg\",\"group_name\":\"qqq\",\"corp_id\":\"ww84bf86fbc1f29e79\",\"admin_list\":[{\"userid\":\"woreQkBgAA0TWJDl2bJ-M5NIZtk3xohg\",\"nickname\":\"刘立冬3\"},{\"userid\":\"pony\",\"nickname\":\"我是张三\"}],\"external_id\":\"wmreQkBgAAXnVuQtd16o_TyiWMbj24vQ\",\"external_nickname\":\"ivy\",\"join_time\":1748189477,\"join_scene\":3,\"risk_level\":0}";
-        String riskInfo = "{\"admin_list\":[{\"nickname\":\"\",\"userid\":\"woreQkBgAA2FzlWY58zU8IWjfsgGO8_Q\"},{\"nickname\":\"\",\"userid\":\"woreQkBgAAGlRNZoCrJGIQsTEs7nXcdQ\"},{\"nickname\":\"\",\"userid\":\"woreQkBgAAJzhqfRbDSOnwnPwCepD9MA\"},{\"nickname\":\"刘老师\",\"userid\":\"woreQkBgAAXwOoWHoq0ZcdzQyFUThAUw\"}],\"chat_id\":\"wrreQkBgAArVD7HfifBbkQEdFkLp4E0g\",\"corp_id\":\"wpreQkBgAAWRroXvmkqvdAFp_E-FqqNA\",\"external_id\":\"wmreQkBgAA19k-PU5mfr-LWSqTiC9NRg\",\"external_nickname\":\"傘春龍\",\"group_name\":\"<中华养生长寿大典>课程C7\",\"join_scene\":0,\"join_time\":1748264037,\"risk_level\":0}";
-        RiskUserInfo riskUser = JSON.parseObject(riskInfo, RiskUserInfo.class);
-        System.out.println(riskUser);
-        riskUserHandleService.handleRiskUser(riskUser);
+//        String riskInfo = "{\"admin_list\":[{\"nickname\":\"\",\"userid\":\"woreQkBgAA2FzlWY58zU8IWjfsgGO8_Q\"},{\"nickname\":\"\",\"userid\":\"woreQkBgAAGlRNZoCrJGIQsTEs7nXcdQ\"},{\"nickname\":\"\",\"userid\":\"woreQkBgAAJzhqfRbDSOnwnPwCepD9MA\"},{\"nickname\":\"刘老师\",\"userid\":\"woreQkBgAAXwOoWHoq0ZcdzQyFUThAUw\"}],\"chat_id\":\"wrreQkBgAArVD7HfifBbkQEdFkLp4E0g\",\"corp_id\":\"wpreQkBgAAWRroXvmkqvdAFp_E-FqqNA\",\"external_id\":\"wmreQkBgAA19k-PU5mfr-LWSqTiC9NRg\",\"external_nickname\":\"傘春龍\",\"group_name\":\"<中华养生长寿大典>课程C7\",\"join_scene\":0,\"join_time\":1748264037,\"risk_level\":0}";
+//        RiskUserInfo riskUser = JSON.parseObject(riskInfo, RiskUserInfo.class);
+//        System.out.println(riskUser);
+//        riskUserHandleService.handleRiskUser(riskUser);
 //        demoService
-//       demoService.sayHello("world");
-        Map<String,Object> map = new HashMap<>();
-        map.put("video_id",1);
+////       demoService.sayHello("world");
+//        Map<String,Object> map = new HashMap<>();
+//        map.put("video_id",1);
 //        mongoTemplate.insert(map, "content_understanding_info");
+        riskRuleConfigService.getFixedRulesForThisChat("wrreQkBgAAK-2WCnCa7BWIWoGskw7faQ");
     }
 }