PronounsPage/server/notify.ts
2025-07-04 17:29:52 +02:00

124 lines
3.7 KiB
TypeScript

import './setup.ts';
import SQL from 'sql-template-strings';
import dbConnection from './db.ts';
import type { UserRow } from './express/user.ts';
import mailer from './mailer.ts';
import { loadTranslator } from '~/server/data.ts';
import { newDate, isGrantedForUser, isPermissionArea } from '~/src/helpers.ts';
import type { PermissionArea } from '~/src/helpers.ts';
const shouldNotify = (frequency: number) => {
if (frequency === 0) {
return false;
}
if (frequency === 7) {
return newDate().getDay() === 6; // Saturdays
}
return true;
};
async function notify() {
const db = await dbConnection();
const awaitingModeration: {
type: PermissionArea | string & {};
locale: string;
c: number;
}[] = [
...await db.all(SQL`
SELECT 'nouns' as type, locale, count(*) as c
FROM nouns
WHERE approved = 0 AND deleted=0
GROUP BY locale
`),
...await db.all(SQL`
SELECT 'inclusive' as type, locale, count(*) as c
FROM inclusive
WHERE approved = 0 AND deleted=0
GROUP BY locale
`),
...await db.all(SQL`
SELECT 'terms' as type, locale, count(*) as c
FROM terms
WHERE approved = 0 AND deleted=0
GROUP BY locale
`),
...await db.all(SQL`
SELECT 'sources' as type, locale, count(*) as c
FROM sources
WHERE approved = 0 AND deleted=0
GROUP BY locale
`),
...await db.all(SQL`
SELECT 'names' as type, locale, count(*) as c
FROM names
WHERE approved = 0 AND deleted=0
GROUP BY locale
`),
...await db.all(SQL`
SELECT 'translations' as type, locale, count(*) as c
FROM translations
WHERE status = 0 OR status = 1
GROUP BY locale
`),
...await db.all(SQL`
SELECT 'reports' as type, null as locale, count(*) as c
FROM reports
WHERE isHandled = 0
`),
...await db.all(SQL`
SELECT 'ban-proposals' as type, null as locale, (
SELECT count(*)
FROM ban_proposals p
LEFT JOIN users u ON p.userId = u.id
WHERE u.bannedBy IS NULL
) as c
`),
].filter((r) => r.c > 0);
if (!awaitingModeration.length) {
console.log('No entries awaiting moderation');
return;
}
const admins = await db.all<Pick<UserRow, 'email' | 'roles' | 'adminNotifications'>[]>(SQL`
SELECT email, roles, adminNotifications
FROM users
WHERE roles != '' AND roles != '*-external'
`);
const awaitingModerationGrouped: Record<string, { [k: string]: number }> = {};
let count = 0;
for (const m of awaitingModeration) {
for (const admin of admins) {
if ((!isPermissionArea(m.type) || isGrantedForUser(admin, m.locale, m.type)) &&
shouldNotify(admin.adminNotifications)) {
awaitingModerationGrouped[admin.email] ||= {};
awaitingModerationGrouped[admin.email][`${m.locale || '*'}-${m.type}`] = m.c;
}
}
count += m.c;
}
console.log('Entries awaiting moderation: ', count);
for (const email in awaitingModerationGrouped) {
if (!Object.hasOwn(awaitingModerationGrouped, email)) {
continue;
}
const stats = awaitingModerationGrouped[email];
console.log('Sending email:', email, stats);
await mailer(email, 'notify', await loadTranslator('_'), { stats });
}
await db.close();
}
notify();