From 8fd9250af49aefdbec472bf5f02756315fbe7992 Mon Sep 17 00:00:00 2001 From: 3944Realms Date: Tue, 9 Jun 2026 14:50:35 +0800 Subject: [PATCH] =?UTF-8?q?pref:=E4=BC=98=E5=8C=96=E5=AE=A1=E8=AE=A1?= =?UTF-8?q?=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../ltdmanager/module/WhitelistAuditModule.kt | 75 +++++++++++++++++-- .../whitelist/WhitelistSystemClient.kt | 10 ++- .../whitelist/request/WhitelistListRequest.kt | 2 + 4 files changed, 82 insertions(+), 7 deletions(-) diff --git a/gradle.properties b/gradle.properties index cb70f11..eb55089 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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 diff --git a/src/main/kotlin/top/r3944realms/ltdmanager/module/WhitelistAuditModule.kt b/src/main/kotlin/top/r3944realms/ltdmanager/module/WhitelistAuditModule.kt index c8701a5..dda0b10 100644 --- a/src/main/kotlin/top/r3944realms/ltdmanager/module/WhitelistAuditModule.kt +++ b/src/main/kotlin/top/r3944realms/ltdmanager/module/WhitelistAuditModule.kt @@ -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() // 本次被拒绝的用户 var notInGroupGrace = mutableListOf() var notInGroupExpired = 0 + val expiredList = mutableListOf() // 本次被删除的用户 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 人") - appendLine("新发现不在群(已拒绝): $notInGroupNew 人") + 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}") +// } } } diff --git a/src/main/kotlin/top/r3944realms/ltdmanager/whitelist/WhitelistSystemClient.kt b/src/main/kotlin/top/r3944realms/ltdmanager/whitelist/WhitelistSystemClient.kt index 62b5641..3a1a5ee 100644 --- a/src/main/kotlin/top/r3944realms/ltdmanager/whitelist/WhitelistSystemClient.kt +++ b/src/main/kotlin/top/r3944realms/ltdmanager/whitelist/WhitelistSystemClient.kt @@ -76,7 +76,15 @@ class WhitelistSystemClient private constructor() } // -- 便捷方法 -- - + suspend fun listApprovedAll(): List { + 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 { return when (val result = submitRequest(WhitelistListRequest())) { is ResponseResult.Success -> { diff --git a/src/main/kotlin/top/r3944realms/ltdmanager/whitelist/request/WhitelistListRequest.kt b/src/main/kotlin/top/r3944realms/ltdmanager/whitelist/request/WhitelistListRequest.kt index 207f9c0..f9fc081 100644 --- a/src/main/kotlin/top/r3944realms/ltdmanager/whitelist/request/WhitelistListRequest.kt +++ b/src/main/kotlin/top/r3944realms/ltdmanager/whitelist/request/WhitelistListRequest.kt @@ -17,6 +17,8 @@ class WhitelistListRequest : WhitelistSystemRequest() { override fun method(): HttpMethod = HttpMethod.Get + override fun queryParameters(): Map = mapOf("all" to "true") + override fun getResponse( responseJson: String, httpStatusCode: HttpStatusCode