全项目扫描修复: Docker数据卷修复+安全requireAdmin+12页SEO+API白名单+脚本超时+常量提取+假数据删除

This commit is contained in:
ZhuiGuangAI Dev
2026-06-12 17:27:47 +08:00
parent 464924aea0
commit 4c325c8699
454 changed files with 33647 additions and 980 deletions
+163
View File
@@ -0,0 +1,163 @@
// 对齐 forumTopic.likeCount / forumPost.likeCount 与真实 Like 表的计数
// 用法:
// node scripts/reconcile-like-counts.mjs # 仅巡检
// node scripts/reconcile-like-counts.mjs --fix # 巡检 + 自动修正
// node scripts/reconcile-like-counts.mjs --scope=topic|post|both
// node scripts/reconcile-like-counts.mjs --bot-only # 只检查 bot 的话题/回复
import { PrismaClient } from "@prisma/client";
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
import "dotenv/config";
const base = process.env.DATABASE_URL.replace("mysql://", "mariadb://");
const sep = base.includes("?") ? "&" : "?";
const connectionString = `${base}${sep}connection_limit=5&pool_timeout=15`;
const adapter = new PrismaMariaDb(connectionString);
const prisma = new PrismaClient({ adapter });
const args = process.argv.slice(2);
const fixMode = args.includes("--fix");
const botOnly = args.includes("--bot-only");
const scopeArg = args.find((a) => a.startsWith("--scope="));
const scope = scopeArg ? scopeArg.split("=")[1] : "both";
const limitArg = args.find((a) => a.startsWith("--limit="));
const limit = limitArg ? parseInt(limitArg.split("=")[1], 10) : 5000;
function ts() {
return `[${new Date().toISOString()}]`;
}
async function reconcileTopics() {
console.log(`\n${ts()} 巡检 forumTopic.likeCount ...`);
const where = {};
if (botOnly) where.user = { isBot: true };
const all = await prisma.forumTopic.findMany({
where,
select: { id: true, likeCount: true, userId: true },
take: limit,
});
console.log(` 范围: ${all.length} 个 topic${botOnly ? " (bot 限定)" : ""}`);
// 批量统计真实点赞数(按 topicId groupBy)
const topicIds = all.map((t) => t.id);
if (topicIds.length === 0) return { drift: 0, fixed: 0 };
const realCounts = await prisma.forumTopicLike.groupBy({
by: ["topicId"],
where: { topicId: { in: topicIds } },
_count: { _all: true },
});
const realMap = new Map(realCounts.map((r) => [r.topicId, r._count._all]));
let drift = 0;
let fixed = 0;
const samples = [];
for (const t of all) {
const real = realMap.get(t.id) || 0;
if (real !== t.likeCount) {
drift++;
if (samples.length < 8) {
samples.push({ id: t.id, stored: t.likeCount, real });
}
if (fixMode) {
await prisma.forumTopic.update({
where: { id: t.id },
data: { likeCount: real },
});
fixed++;
}
}
}
console.log(` 偏差: ${drift}${fixMode ? `,已修正 ${fixed}` : ""}`);
if (samples.length > 0) {
console.log(` 示例(最多 8 条):`);
for (const s of samples) {
console.log(` topic ${s.id}: stored=${s.stored} 实际=${s.real}`);
}
}
return { drift, fixed };
}
async function reconcilePosts() {
console.log(`\n${ts()} 巡检 forumPost.likeCount ...`);
const where = {};
if (botOnly) where.user = { isBot: true };
const all = await prisma.forumPost.findMany({
where,
select: { id: true, likeCount: true, userId: true },
take: limit,
});
console.log(` 范围: ${all.length} 个 post${botOnly ? " (bot 限定)" : ""}`);
const postIds = all.map((p) => p.id);
if (postIds.length === 0) return { drift: 0, fixed: 0 };
const realCounts = await prisma.forumPostLike.groupBy({
by: ["postId"],
where: { postId: { in: postIds } },
_count: { _all: true },
});
const realMap = new Map(realCounts.map((r) => [r.postId, r._count._all]));
let drift = 0;
let fixed = 0;
const samples = [];
for (const p of all) {
const real = realMap.get(p.id) || 0;
if (real !== p.likeCount) {
drift++;
if (samples.length < 8) {
samples.push({ id: p.id, stored: p.likeCount, real });
}
if (fixMode) {
await prisma.forumPost.update({
where: { id: p.id },
data: { likeCount: real },
});
fixed++;
}
}
}
console.log(` 偏差: ${drift}${fixMode ? `,已修正 ${fixed}` : ""}`);
if (samples.length > 0) {
console.log(` 示例(最多 8 条):`);
for (const s of samples) {
console.log(` post ${s.id}: stored=${s.stored} 实际=${s.real}`);
}
}
return { drift, fixed };
}
async function main() {
console.log(`========== 点赞数对齐巡检 ==========`);
console.log(`模式: ${fixMode ? "FIX(自动修正)" : "CHECK(仅巡检)"}`);
console.log(`范围: ${scope}${botOnly ? " (仅 bot)" : ""}`);
console.log(`扫描上限: ${limit}`);
const summary = { topic: { drift: 0, fixed: 0 }, post: { drift: 0, fixed: 0 } };
if (scope === "topic" || scope === "both") {
summary.topic = await reconcileTopics();
}
if (scope === "post" || scope === "both") {
summary.post = await reconcilePosts();
}
console.log(`\n========== 总结 ==========`);
console.log(`话题偏差: ${summary.topic.drift}${fixMode ? `(已修正 ${summary.topic.fixed})` : ""}`);
console.log(`回复偏差: ${summary.post.drift}${fixMode ? `(已修正 ${summary.post.fixed})` : ""}`);
const totalDrift = summary.topic.drift + summary.post.drift;
if (totalDrift === 0) {
console.log(`\n✅ 全部对齐,无需修正`);
} else if (fixMode) {
console.log(`\n🔧 已完成修正`);
} else {
console.log(`\n⚠️ 发现偏差,加 --fix 自动修正`);
}
await prisma.$disconnect();
}
main().catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});