91 lines
3.1 KiB
JavaScript
91 lines
3.1 KiB
JavaScript
// 每月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);
|
|
});
|