feat: 首次推送到Gitea - 完整项目代码 + 安全加固 + 知识库
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
// 每月1号运行:给活跃用户发放断签保护卡
|
||||
// Grant freeze cards to active users on the 1st of each month
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { PrismaMariaDb } from "@prisma/adapter-mariadb";
|
||||
import "dotenv/config";
|
||||
|
||||
const base = (process.env.DATABASE_URL || "mysql://localhost:3306/zhuiguang_ai?charset=utf8mb4").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 });
|
||||
|
||||
function getCurrentMonth() {
|
||||
const d = new Date();
|
||||
return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const currentMonth = getCurrentMonth();
|
||||
console.log(`[grant-freeze-cards] 开始发放 ${currentMonth} 月断签保护卡...`);
|
||||
|
||||
// 活跃判定:近 30 天有 签到 / 发帖 / 回复 任一即可(真人用户)。
|
||||
// 原实现只统计签到(forumCheckIn 常为空),导致断签卡永远发不出。
|
||||
const thirtyDaysAgo = new Date();
|
||||
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
|
||||
|
||||
const [checkinIds, topicIds, postIds] = await Promise.all([
|
||||
prisma.forumCheckIn.findMany({
|
||||
where: { checkInDate: { gte: thirtyDaysAgo } },
|
||||
distinct: ["userId"],
|
||||
select: { userId: true },
|
||||
}),
|
||||
prisma.forumTopic.findMany({
|
||||
where: { createdAt: { gte: thirtyDaysAgo }, user: { isBot: false } },
|
||||
distinct: ["userId"],
|
||||
select: { userId: true },
|
||||
}),
|
||||
prisma.forumPost.findMany({
|
||||
where: { createdAt: { gte: thirtyDaysAgo }, user: { isBot: false } },
|
||||
distinct: ["userId"],
|
||||
select: { userId: true },
|
||||
}),
|
||||
]);
|
||||
const activeUserIds = [...new Set([...checkinIds, ...topicIds, ...postIds].map((r) => r.userId))];
|
||||
|
||||
console.log(`[grant-freeze-cards] 找到 ${activeUserIds.length} 位近30天活跃用户`);
|
||||
|
||||
let granted = 0;
|
||||
let skipped = 0;
|
||||
let newUsers = 0;
|
||||
|
||||
for (const userId of activeUserIds) {
|
||||
const key = `streak_freeze_${userId}`;
|
||||
const existing = await prisma.systemConfig.findUnique({ where: { key } });
|
||||
|
||||
if (existing) {
|
||||
const data = existing.value;
|
||||
if (data.lastGrantedMonth === currentMonth) {
|
||||
skipped++;
|
||||
continue; // Already granted this month
|
||||
}
|
||||
// Grant 2 cards, cap at 2
|
||||
data.freezeCards = Math.min((data.freezeCards || 0) + 2, 2);
|
||||
data.lastGrantedMonth = currentMonth;
|
||||
await prisma.systemConfig.update({
|
||||
where: { key },
|
||||
data: { value: data },
|
||||
});
|
||||
granted++;
|
||||
} else {
|
||||
// New user: grant initial 2 cards
|
||||
await prisma.systemConfig.create({
|
||||
data: {
|
||||
key,
|
||||
value: { freezeCards: 2, lastGrantedMonth: currentMonth },
|
||||
},
|
||||
});
|
||||
newUsers++;
|
||||
}
|
||||
}
|
||||
|
||||
console.log(`[grant-freeze-cards] 完成: 发放 ${granted} 人, 新用户 ${newUsers} 人, 跳过 ${skipped} 人 (本月已发放) `);
|
||||
await prisma.$disconnect();
|
||||
}
|
||||
|
||||
main().catch(async (e) => {
|
||||
console.error("[grant-freeze-cards] 执行失败:", e.message);
|
||||
if (prisma) await prisma.$disconnect();
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user