133 lines
3.6 KiB
TypeScript

import { getActiveBlocklistCount } from "../../db/domains";
import { usePrisma } from "../../utils/prisma";
const ADGUARD_KNOWN_COUNT = 208704;
const VOTE_PHASE_DAYS = 7;
/** GET /api/blocklist/stats */
export default defineEventHandler(async (event) => {
const db = usePrisma();
const count = await getActiveBlocklistCount();
const current = count > 1000 ? count : ADGUARD_KNOWN_COUNT;
// Optional user (für mySubmissions). Bei Fehler einfach skippen.
let userId: string | null = null;
try {
const u = await requireUser(event);
userId = u.id;
} catch {
/* anonymous */
}
const months = 12;
const startFraction = 0.45;
const labels: string[] = [];
const values: number[] = [];
const now = new Date();
for (let i = months - 1; i >= 0; i--) {
const d = new Date(now.getFullYear(), now.getMonth() - i, 1);
labels.push(
d.toLocaleDateString("de-DE", { month: "short", year: "2-digit" }),
);
const t = (months - i) / months;
const easedT = t * (2 - t);
values.push(
Math.round(current * (startFraction + (1 - startFraction) * easedT)),
);
}
// Submissions split: vote phase (created < 7d) vs review (older, awaiting admin)
const voteCutoff = new Date(now.getTime() - VOTE_PHASE_DAYS * 86_400_000);
const weekAgo = new Date(now.getTime() - 7 * 86_400_000);
const monthAgo = new Date(now.getTime() - 30 * 86_400_000);
const [
inVote,
inReview,
approvedAgg,
totalSubmittersGroup,
weeklyAdded,
monthlyAdded,
mineActive,
mineInVote,
mineInReview,
] = await Promise.all([
db.domainSubmission.count({
where: { status: "pending" },
}),
db.domainSubmission.count({
where: { status: "in_review" },
}),
db.domainSubmission.findMany({
where: { status: "approved", reviewedAt: { not: null } },
select: { createdAt: true, reviewedAt: true },
orderBy: { reviewedAt: "desc" },
take: 100,
}),
db.domainSubmission.groupBy({
by: ["userId"],
_count: { _all: true },
}),
db.domainSubmission.count({
where: { status: "approved", reviewedAt: { gte: weekAgo } },
}),
db.domainSubmission.count({
where: { status: "approved", reviewedAt: { gte: monthAgo } },
}),
userId
? db.userCustomDomain.count({ where: { userId, status: "approved" } })
: Promise.resolve(0),
userId
? db.domainSubmission.count({
where: {
userId,
status: "pending",
},
})
: Promise.resolve(0),
userId
? db.domainSubmission.count({
where: {
userId,
status: "in_review",
},
})
: Promise.resolve(0),
]);
let avgApprovalWaitDays = 0;
if (approvedAgg.length > 0) {
const totalMs = approvedAgg.reduce((sum, s) => {
if (!s.reviewedAt) return sum;
return sum + (s.reviewedAt.getTime() - s.createdAt.getTime());
}, 0);
avgApprovalWaitDays =
Math.round((totalMs / approvedAgg.length / 86_400_000) * 10) / 10;
}
let avgPerUser = 0;
if (totalSubmittersGroup.length > 0) {
const totalSubs = totalSubmittersGroup.reduce(
(sum, g) => sum + g._count._all,
0,
);
avgPerUser =
Math.round((totalSubs / totalSubmittersGroup.length) * 10) / 10;
}
return {
current,
weeklyAdded,
monthlyAdded,
history: labels.map((label, i) => ({ label, count: values[i] })),
submissions: { inVote, inReview },
mySubmissions: {
active: mineActive,
inVote: mineInVote,
inReview: mineInReview,
},
avgPerUser,
avgApprovalWaitDays,
};
});