2025-11-13 10:16:09 +08:00

499 lines
18 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import com.red.circle.OtherServiceApplication;
import com.red.circle.common.business.enums.ConsoleAccountStatusEnum;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.other.app.dto.h5.UserIdentityVO;
import com.red.circle.other.app.service.user.user.AppUserDataViolationService;
import com.red.circle.other.infra.database.rds.entity.sys.Administrator;
import com.red.circle.other.infra.database.rds.service.sys.AdministratorAuthService;
import com.red.circle.other.infra.database.rds.service.sys.AdministratorService;
import com.red.circle.other.inner.endpoint.team.bd.BdTeamInfoClient;
import com.red.circle.other.inner.endpoint.team.bd.BdTeamLeaderClient;
import com.red.circle.other.inner.endpoint.team.target.TeamProfileClient;
import com.red.circle.other.inner.enums.sys.appmanager.RoomRolesEnum;
import com.red.circle.other.inner.enums.team.TeamMemberRole;
import com.red.circle.other.inner.model.cmd.user.ApprovalAccountCmd;
import com.red.circle.other.inner.model.dto.agency.agency.TeamMemberDTO;
import com.red.circle.wallet.inner.endpoint.freight.FreightGoldClient;
import dto.BanResultDTO;
import dto.DeviceFingerprintDTO;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import util.ExcelUtil;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@SpringBootTest(classes = OtherServiceApplication.class)
@RunWith(SpringRunner.class)
public class UserDataViolationTest {
@Autowired
private AppUserDataViolationService userDataViolationService;
@Autowired
private TeamProfileClient teamProfileClient;
@Autowired
private FreightGoldClient freightGoldClient;
@Autowired
private BdTeamInfoClient bdTeamInfoClient;
@Autowired
private AdministratorService administratorService;
@Autowired
private AdministratorAuthService administratorAuthService;
@Autowired
private BdTeamLeaderClient bdTeamLeaderClient;
/**
* 测试 Excel 导入功能
* 读取从数据库导出的设备指纹数据
*/
@Test
public void testImportDeviceFingerprint() {
// TODO: 修改为你实际的 Excel 文件路径
String inputFilePath = "C:\\Users\\Administrator\\Documents\\DataGripSql\\11.11同设备指纹用户统计英文版.xlsx";
try {
List<DeviceFingerprintDTO> dataList = ExcelUtil.importDeviceFingerprint(inputFilePath);
log.info("==================== 导入测试结果 ====================");
log.info("总共导入 {} 条设备指纹数据", dataList.size());
// 打印前 5 条数据作为示例
int displayCount = Math.min(5, dataList.size());
log.info("显示前 {} 条数据:", displayCount);
for (int i = 0; i < displayCount; i++) {
DeviceFingerprintDTO dto = dataList.get(i);
log.info("数据 {}: 设备指纹={}, 用户数={}, 用户IDs={}",
i + 1,
dto.getDeviceFingerprint(),
dto.getUserCount(),
dto.getUserIds());
}
log.info("==================================================");
} catch (Exception e) {
log.error("导入测试失败", e);
}
}
/**
* 测试 Excel 导出功能
* 生成示例封禁结果数据并导出
*/
@Test
public void testExportBanResults() {
// 创建示例数据
List<BanResultDTO> results = new ArrayList<>();
// 示例1被封禁的用户
BanResultDTO banned = new BanResultDTO();
banned.setUserId(1954059793963393025L);
banned.setDeviceFingerprint("iOS|iPhone 14|192.168.1.100");
banned.setUserIdentity("主播");
banned.setBanned("");
banned.setReason("同设备指纹下存在多个主播");
banned.setStatus("封禁成功");
banned.setRemark("设备指纹下共2个主播");
results.add(banned);
// 示例2不封禁的用户管理员
BanResultDTO notBanned1 = new BanResultDTO();
notBanned1.setUserId(1000000000000000001L);
notBanned1.setDeviceFingerprint("Android|Xiaomi 13|192.168.1.101");
notBanned1.setUserIdentity("超级管理员");
notBanned1.setBanned("");
notBanned1.setReason("管理员身份,不封禁");
notBanned1.setStatus("跳过");
notBanned1.setRemark("-");
results.add(notBanned1);
// 示例3不封禁的用户非主播
BanResultDTO notBanned2 = new BanResultDTO();
notBanned2.setUserId(2000000000000000001L);
notBanned2.setDeviceFingerprint("iOS|iPhone 15|192.168.1.102");
notBanned2.setUserIdentity("普通用户");
notBanned2.setBanned("");
notBanned2.setReason("非主播身份,不封禁");
notBanned2.setStatus("跳过");
notBanned2.setRemark("-");
results.add(notBanned2);
// TODO: 修改为你想要保存的文件路径
String outputFilePath = "D:\\ban_results_test.xlsx";
try {
ExcelUtil.exportBanResults(results, outputFilePath);
log.info("==================== 导出测试结果 ====================");
log.info("成功导出 {} 条封禁结果数据", results.size());
log.info("导出文件路径: {}", outputFilePath);
log.info("请打开 Excel 文件检查导出结果");
log.info("==================================================");
} catch (Exception e) {
log.error("导出测试失败", e);
}
}
@Test
public void testUnBanUsers() {
String inputFilePath = "C:\\Users\\Administrator\\Documents\\DataGripSql\\11.11同设备指纹用户统计英文版 - 副本.xlsx";
String outputFilePath = "D:\\ban_results_" + System.currentTimeMillis() + ".xlsx";
List<DeviceFingerprintDTO> deviceData = ExcelUtil.importDeviceFingerprint(inputFilePath);
for (DeviceFingerprintDTO device : deviceData) {
List<Long> userIds = parseUserIds(device.getUserIds());
for (Long userId : userIds) {
if (userId == 1963790037740466178L) {
System.out.println();
}
// 执行解封
ApprovalAccountCmd cmd = new ApprovalAccountCmd();
cmd.setAccountStatusEnum(ConsoleAccountStatusEnum.UNTIE_DEVICE_AND_ACCOUNT);
cmd.setDescription("1");
cmd.setBeApprovalUserId(userId);
cmd.setReqUserId(userId);
userDataViolationService.updateAccountStatus(cmd);
}
}
}
/**
* 批量用户封禁(完整流程)
* 1. 导入设备指纹数据
* 2. 判断用户身份
* 3. 执行封禁操作
* 4. 导出封禁结果
*/
@Test
public void batchBanUsers() {
// TODO: 修改为你实际的文件路径
String inputFilePath = "C:\\Users\\Administrator\\Documents\\DataGripSql\\11.11同设备指纹用户统计英文版.xlsx";
String outputFilePath = "D:\\ban_results_" + System.currentTimeMillis() + ".xlsx";
try {
log.info("==================== 开始批量封禁流程 ====================");
// 步骤1: 导入设备指纹数据
log.info("步骤1: 导入设备指纹数据...");
List<DeviceFingerprintDTO> deviceData = ExcelUtil.importDeviceFingerprint(inputFilePath);
log.info("成功导入 {} 条设备指纹数据", deviceData.size());
// 步骤2: 处理每个设备指纹的用户
log.info("步骤2: 开始处理用户封禁逻辑...");
List<BanResultDTO> allResults = new ArrayList<>();
int processedCount = 0;
for (DeviceFingerprintDTO device : deviceData) {
processedCount++;
log.info("处理进度: {}/{} - 设备指纹: {}", processedCount, deviceData.size(), device.getDeviceFingerprint());
// 解析用户ID列表
List<Long> userIds = parseUserIds(device.getUserIds());
log.info(" 该设备指纹下有 {} 个用户", userIds.size());
// 判断该设备指纹下的主播数量
List<Long> anchorUserIds = new ArrayList<>();
Map<Long, UserIdentityVO> identityMap = new HashMap<>();
for (Long userId : userIds) {
try {
UserIdentityVO identity = getUserIdentity(userId);
identityMap.put(userId, identity);
// 如果是主播,加入主播列表
if (Boolean.TRUE.equals(identity.getAnchor())) {
anchorUserIds.add(userId);
}
} catch (Exception e) {
log.error(" 获取用户 {} 身份失败", userId, e);
}
}
log.info(" 该设备指纹下有 {} 个主播", anchorUserIds.size());
// 处理每个用户
for (Long userId : userIds) {
BanResultDTO result = processUser(userId, device, identityMap.get(userId), anchorUserIds.size());
allResults.add(result);
}
}
// 步骤3: 导出结果
log.info("步骤3: 导出封禁结果...");
ExcelUtil.exportBanResults(allResults, outputFilePath);
// 步骤4: 统计结果
log.info("==================== 封禁流程完成 ====================");
long bannedCount = allResults.stream().filter(r -> "".equals(r.getBanned())).count();
long skippedCount = allResults.stream().filter(r -> "".equals(r.getBanned())).count();
long successCount = allResults.stream().filter(r -> "封禁成功".equals(r.getStatus())).count();
long failedCount = allResults.stream().filter(r -> "封禁失败".equals(r.getStatus())).count();
log.info("总处理用户数: {}", allResults.size());
log.info("封禁用户数: {}", bannedCount);
log.info("跳过用户数: {}", skippedCount);
log.info("封禁成功数: {}", successCount);
log.info("封禁失败数: {}", failedCount);
log.info("结果文件路径: {}", outputFilePath);
log.info("====================================================");
} catch (Exception e) {
log.error("批量封禁流程失败", e);
}
}
/**
* 处理单个用户
*/
private BanResultDTO processUser(Long userId, DeviceFingerprintDTO device,
UserIdentityVO identity, int anchorCount) {
BanResultDTO result = new BanResultDTO();
result.setUserId(userId);
result.setDeviceFingerprint(device.getDeviceFingerprint());
// 如果获取身份失败
if (identity == null) {
result.setUserIdentity("未知");
result.setBanned("");
result.setReason("获取用户身份失败");
result.setStatus("跳过");
result.setRemark("身份查询异常");
return result;
}
// 设置用户身份描述
result.setUserIdentity(buildIdentityDescription(identity));
// 判断是否需要封禁
boolean shouldBan = shouldBanUser(identity, anchorCount);
if (!shouldBan) {
result.setBanned("");
result.setReason(getSkipReason(identity, anchorCount));
result.setStatus("跳过");
result.setRemark(String.format("设备指纹下共%d个用户%d个主播", device.getUserCount(), anchorCount));
return result;
}
// 需要封禁,执行封禁操作
result.setBanned("");
result.setReason(String.format("设备指纹下存在%d个主播符合封禁条件", anchorCount));
result.setRemark(String.format("设备指纹下共%d个用户%d个主播", device.getUserCount(), anchorCount));
try {
// 执行封禁
ApprovalAccountCmd cmd = new ApprovalAccountCmd();
cmd.setAccountStatusEnum(ConsoleAccountStatusEnum.ARCHIVE);
cmd.setDescription("Multi-device fingerprint blocking");
cmd.setBeApprovalUserId(userId);
cmd.setReqUserId(userId);
cmd.setDays(365);
userDataViolationService.updateAccountStatus(cmd);
result.setStatus("封禁成功");
log.info(" 用户 {} 封禁成功", userId);
} catch (Exception e) {
result.setStatus("封禁失败");
result.setRemark(result.getRemark() + " | 错误: " + e.getMessage());
log.error(" 用户 {} 封禁失败", userId, e);
}
return result;
}
/**
* 判断是否应该封禁用户
* 封禁条件同设备指纹下存在2个及以上主播且该用户是主播
* 不封禁条件:
* 1. 超级管理员
* 2. 管理员
* 3. BD Leader
* 4. BD
* 5. 金币代理FreightAgent
* 6. 不是主播
*/
private boolean shouldBanUser(UserIdentityVO identity, int anchorCount) {
// 条件1: 设备指纹下必须有2个及以上主播
if (anchorCount < 2) {
return false;
}
// 条件2: 该用户必须是主播
if (!Boolean.TRUE.equals(identity.getAnchor())) {
return false;
}
// 条件3: 排除特殊身份用户
if (Boolean.TRUE.equals(identity.getSuperAdmin())) {
return false; // 超级管理员不封禁
}
if (Boolean.TRUE.equals(identity.getAdmin())) {
return false; // 管理员不封禁
}
if (Boolean.TRUE.equals(identity.getBdLeader())) {
return false; // BD Leader 不封禁
}
if (Boolean.TRUE.equals(identity.getBd())) {
return false; // BD 不封禁
}
if (Boolean.TRUE.equals(identity.getFreightAgent()) || Boolean.TRUE.equals(identity.getSuperFreightAgent())) {
return false; // 金币代理不封禁
}
// 通过所有检查,应该封禁
return true;
}
/**
* 获取跳过原因
*/
private String getSkipReason(UserIdentityVO identity, int anchorCount) {
if (anchorCount < 2) {
return "设备指纹下主播数量不足2个";
}
if (!Boolean.TRUE.equals(identity.getAnchor())) {
return "用户不是主播";
}
if (Boolean.TRUE.equals(identity.getSuperAdmin())) {
return "超级管理员身份,不封禁";
}
if (Boolean.TRUE.equals(identity.getAdmin())) {
return "管理员身份,不封禁";
}
if (Boolean.TRUE.equals(identity.getBdLeader())) {
return "BD Leader 身份,不封禁";
}
if (Boolean.TRUE.equals(identity.getBd())) {
return "BD 身份,不封禁";
}
if (Boolean.TRUE.equals(identity.getFreightAgent()) || Boolean.TRUE.equals(identity.getSuperFreightAgent())) {
return "金币代理身份,不封禁";
}
return "其他原因";
}
/**
* 构建用户身份描述
*/
private String buildIdentityDescription(UserIdentityVO identity) {
List<String> identities = new ArrayList<>();
if (Boolean.TRUE.equals(identity.getSuperAdmin())) {
identities.add("超级管理员");
}
if (Boolean.TRUE.equals(identity.getAdmin())) {
identities.add("管理员");
}
if (Boolean.TRUE.equals(identity.getManager())) {
identities.add("经理");
}
if (Boolean.TRUE.equals(identity.getBdLeader())) {
identities.add("BD Leader");
}
if (Boolean.TRUE.equals(identity.getBd())) {
identities.add("BD");
}
if (Boolean.TRUE.equals(identity.getAgent())) {
identities.add("代理");
}
if (Boolean.TRUE.equals(identity.getAnchor())) {
identities.add("主播");
}
if (Boolean.TRUE.equals(identity.getSuperFreightAgent())) {
identities.add("超级金币代理");
}
if (Boolean.TRUE.equals(identity.getFreightAgent())) {
identities.add("金币代理");
}
if (identities.isEmpty()) {
return "普通用户";
}
return String.join(", ", identities);
}
/**
* 解析用户ID字符串逗号分隔
*/
private List<Long> parseUserIds(String userIdsStr) {
if (userIdsStr == null || userIdsStr.trim().isEmpty()) {
return new ArrayList<>();
}
return Arrays.stream(userIdsStr.split(","))
.map(String::trim)
.filter(s -> !s.isEmpty())
.map(Long::parseLong)
.collect(Collectors.toList());
}
/**
* 单个用户封禁测试
*/
@Test
public void updateUserDataViolation() {
Long userId = 1954059793963393025L;
ApprovalAccountCmd cmd = new ApprovalAccountCmd();
cmd.setAccountStatusEnum(ConsoleAccountStatusEnum.ARCHIVE_DEVICE);
cmd.setDescription("Multi-device fingerprint blocking");
cmd.setBeApprovalUserId(userId);
cmd.setReqUserId(userId);
userDataViolationService.updateAccountStatus(cmd);
}
/**
* 获取用户身份信息
*/
public UserIdentityVO getUserIdentity(Long userId) {
TeamMemberDTO teamMember = ResponseAssert.requiredSuccess(
teamProfileClient.getByMemberId(userId));
Administrator administrator = administratorService.getByUserId(userId);
boolean isValidAdmin = administrator != null && Boolean.TRUE.equals(administrator.getStatus());
boolean isSuperAdmin = isValidAdmin && Optional.of(administrator)
.map(e -> RoomRolesEnum.MANAGER.eq(e.getRoles()) || RoomRolesEnum.SUPER_ADMIN.eq(e.getRoles()))
.orElse(Boolean.FALSE);
boolean isManager = isValidAdmin && Optional.of(administrator)
.map(e -> RoomRolesEnum.MANAGER.eq(e.getRoles()))
.orElse(Boolean.FALSE);
return new UserIdentityVO()
.setAgent(Objects.nonNull(teamMember) && TeamMemberRole.OWN.eq(teamMember.getRole()))
.setAnchor(Objects.nonNull(teamMember))
.setBd(ResponseAssert.requiredSuccess(bdTeamInfoClient.check(userId)))
.setFreightAgent(ResponseAssert.requiredSuccess(freightGoldClient.checkFreightAgent(userId)))
.setSuperFreightAgent(ResponseAssert.requiredSuccess(freightGoldClient.checkSuperFreightAgent(userId)))
.setSuperAdmin(isSuperAdmin)
.setAdmin(isValidAdmin)
.setBdLeader(ResponseAssert.requiredSuccess(bdTeamLeaderClient.check(userId)))
.setManager(isManager)
;
}
}