pref:优化审计体验

This commit is contained in:
叁玖领域 2026-06-09 14:50:35 +08:00
parent 993ecfc84c
commit 8fd9250af4
4 changed files with 82 additions and 7 deletions

View File

@ -3,5 +3,5 @@ org.gradle.downloadSources=false
org.gradle.parallel=true
org.gradle.degree_of_parallelism=16
project_group=top.r3944realms.ltdmanager
project_version=1.22.3
project_version=1.22.4
dg_lab_version=4.4.14.19

View File

@ -246,6 +246,42 @@ class WhitelistAuditModule(
}
}
}
// 额外检查:已拒绝但不在 approved 列表中的用户状态已变API 不再返回)
val approvedQqSet = whitelistEntries.map { it.qq }.toSet()
for ((qq, entry) in auditState.entries.toMap()) {
if (qq in approvedQqSet) continue
if (entry.rejectedTime == 0L) continue
val elapsed = now - entry.rejectedTime
if (elapsed >= graceMs) {
LoggerUtil.logger.info("[$name] $qq (${entry.playerName}) 宽限期已过不在approved列表执行删除")
whitelistClient.remove(entry.playerId)
auditState = auditState.copy(
entries = auditState.entries.toMutableMap().apply { remove(qq) }
)
saveState(auditState)
sendGroupNotification(
"白名单审计: ${entry.playerName}(QQ:$qq) 宽限期已过,白名单已删除"
)
sendEmail(
qq.toLong(), entry.playerName,
"LTD白名单已删除",
"你的白名单因宽限期已过已被永久删除。请重新申请白名单。"
)
} else if (elapsed >= graceMs - warningMs && entry.warningSentTime == 0L) {
val remainDays = ((graceMs - elapsed) / (24 * 60 * 60 * 1000)).toInt()
LoggerUtil.logger.info("[$name] $qq (${entry.playerName}) 宽限期即将过期 (剩余${remainDays}天)")
sendEmail(
qq.toLong(), entry.playerName,
"LTD白名单即将过期",
"你的白名单宽限期仅剩 ${remainDays} 天。请尽快在主群发送关键词重新激活,否则将被永久删除。"
)
val updated = entry.copy(warningSentTime = now)
auditState = auditState.copy(
entries = auditState.entries.toMutableMap().apply { put(qq, updated) }
)
saveState(auditState)
}
}
LoggerUtil.logger.info("[$name] 审计周期完成")
}
@ -328,20 +364,21 @@ class WhitelistAuditModule(
}
private suspend fun runAdhocAudit(): String {
val groupMembers = fetchWhitelistGroupMembers()
if (groupMembers == null) return "获取群成员失败,审计中断"
val groupMembers = fetchWhitelistGroupMembers() ?: return "获取群成员失败,审计中断"
val groupMemberQqSet = groupMembers.map { it.userId }.toSet()
val whitelistEntries = whitelistClient.listApproved()
if (whitelistEntries.isEmpty()) return "白名单通过数为0"
if (whitelistEntries.isEmpty()) return "白名单通过数为0,跳过审计"
val now = System.currentTimeMillis()
val graceMs = gracePeriodDays * 24 * 60 * 60 * 1000L
var inGroupOk = 0
var notInGroupNew = 0
val rejectedList = mutableListOf<String>() // 本次被拒绝的用户
var notInGroupGrace = mutableListOf<String>()
var notInGroupExpired = 0
val expiredList = mutableListOf<String>() // 本次被删除的用户
var inFilter = 0
for (entry in whitelistEntries) {
@ -365,6 +402,7 @@ class WhitelistAuditModule(
when {
existing == null -> {
notInGroupNew++
rejectedList.add("${entry.playerName}($qqLong)")
whitelistClient.reject(entry.id)
val newEntry = AuditEntry(
qq = entry.qq,
@ -379,6 +417,7 @@ class WhitelistAuditModule(
}
existing.rejectedTime > 0 && now - existing.rejectedTime >= graceMs -> {
notInGroupExpired++
expiredList.add("${entry.playerName}($qqLong)")
whitelistClient.remove(entry.id)
auditState = auditState.copy(
entries = auditState.entries.toMutableMap().apply { remove(key) }
@ -390,6 +429,24 @@ class WhitelistAuditModule(
}
}
}
// 额外检查:已拒绝但不在 approved 列表中的用户API 不再返回)
val approvedQqSet = whitelistEntries.map { it.qq }.toSet()
for ((qq, entry) in auditState.entries.toMap()) {
if (qq in approvedQqSet) continue
if (entry.rejectedTime == 0L) continue
val elapsed = now - entry.rejectedTime
if (elapsed >= graceMs) {
notInGroupExpired++
expiredList.add("${entry.playerName}($qq)")
whitelistClient.remove(entry.playerId)
auditState = auditState.copy(
entries = auditState.entries.toMutableMap().apply { remove(qq) }
)
} else {
val remainDays = ((graceMs - elapsed) / (24 * 60 * 60 * 1000)).toInt()
notInGroupGrace.add("${entry.playerName}($qq, 剩${remainDays}天)")
}
}
saveState(auditState)
return buildString {
@ -397,16 +454,24 @@ class WhitelistAuditModule(
appendLine("".repeat(16))
appendLine("白名单总数: ${whitelistEntries.size}")
appendLine("在群正常: $inGroupOk")
if (notInGroupNew > 0) {
appendLine("新发现不在群(已拒绝): $notInGroupNew")
rejectedList.forEach { appendLine("$it") }
}
if (notInGroupGrace.isNotEmpty()) {
appendLine("宽限期中: ${notInGroupGrace.joinToString()}")
appendLine("宽限期中: \n${notInGroupGrace.joinToString()}")
}
if (notInGroupExpired > 0) {
appendLine("已过期删除: $notInGroupExpired")
expiredList.forEach { appendLine("$it") }
}
if (inFilter > 0) {
appendLine("过滤列表跳过: $inFilter")
}
// val total = inGroupOk + notInGroupNew + notInGroupGrace.size + notInGroupExpired + inFilter
// if (total != whitelistEntries.size + auditState.entries.size) {
// appendLine("⚠ 计数不闭合: 统计${total} vs 入库${whitelistEntries.size}+状态${auditState.entries.size}")
// }
}
}

View File

@ -76,7 +76,15 @@ class WhitelistSystemClient private constructor()
}
// -- 便捷方法 --
suspend fun listApprovedAll(): List<WhitelistPlayerInfo> {
return when (val result = submitRequest(WhitelistListRequest())) {
is ResponseResult.Success -> {
val apiResponse = result.response as? WhitelistApiResponse
apiResponse?.data ?: emptyList()
}
is ResponseResult.Failure -> emptyList()
}
}
suspend fun listApproved(): List<WhitelistPlayerInfo> {
return when (val result = submitRequest(WhitelistListRequest())) {
is ResponseResult.Success -> {

View File

@ -17,6 +17,8 @@ class WhitelistListRequest : WhitelistSystemRequest() {
override fun method(): HttpMethod = HttpMethod.Get
override fun queryParameters(): Map<String, String> = mapOf("all" to "true")
override fun getResponse(
responseJson: String,
httpStatusCode: HttpStatusCode