mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-08 15:00:37 -04:00
119 lines
3.6 KiB
TypeScript
119 lines
3.6 KiB
TypeScript
/* eslint-disable camelcase */
|
|
import SQL from 'sql-template-strings';
|
|
|
|
import type { Database } from '~/server/db.ts';
|
|
import type { UserRow } from '~/server/express/user.ts';
|
|
import type { SourceRow } from '~/server/sources.ts';
|
|
import type { IsGrantedFn } from '~/server/utils/useAuthentication.ts';
|
|
import { clearKey } from '~/src/helpers.ts';
|
|
import type { User } from '~/src/user.ts';
|
|
|
|
export interface NounRow {
|
|
id: string;
|
|
masc: string;
|
|
fem: string;
|
|
neutr: string;
|
|
nb: string;
|
|
mascPl: string;
|
|
femPl: string;
|
|
neutrPl: string;
|
|
nbPl: string;
|
|
approved: boolean;
|
|
base_id: string | null;
|
|
locale: string;
|
|
author_id: string | null;
|
|
deleted: boolean;
|
|
sources: string | null;
|
|
categories: string | null;
|
|
}
|
|
|
|
type NounRowWithAuthor = NounRow & { author: User['username'] };
|
|
|
|
export const addVersions = async (
|
|
db: Database,
|
|
isGranted: IsGrantedFn,
|
|
locale: string,
|
|
nouns: NounRowWithAuthor[],
|
|
) => {
|
|
const keys = new Set();
|
|
nouns.filter((s) => !!s && s.sources)
|
|
.forEach((s) => s.sources!.split(',').forEach((k) => keys.add(`'${clearKey(k.split('#')[0])}'`)));
|
|
|
|
const sources = await db.all<SourceRow & Pick<UserRow, 'username'>>(SQL`
|
|
SELECT s.*, u.username AS submitter FROM sources s
|
|
LEFT JOIN users u ON s.submitter_id = u.id
|
|
WHERE s.locale == ${locale}
|
|
AND s.deleted = 0
|
|
AND s.approved >= ${isGranted('sources') ? 0 : 1}
|
|
AND s.key IN (`.append([...keys].join(',')).append(SQL`)
|
|
`));
|
|
|
|
const sourcesMap: Record<string, SourceRow> = {};
|
|
sources.forEach((s) => sourcesMap[s.key!] = s);
|
|
|
|
return nouns.map((n) => ({
|
|
...n,
|
|
sourcesData: (n.sources ? n.sources.split(',') : [])
|
|
.map((s) => selectFragment(sourcesMap, s))
|
|
.filter((source) => source !== undefined),
|
|
}));
|
|
};
|
|
|
|
const selectFragment = (sourcesMap: Record<string, SourceRow>, keyAndFragment: string) => {
|
|
const [key, fragment] = keyAndFragment.split('#');
|
|
if (sourcesMap[key] === undefined) {
|
|
return undefined;
|
|
}
|
|
if (fragment === undefined) {
|
|
return sourcesMap[key];
|
|
}
|
|
|
|
const source = { ...sourcesMap[key] };
|
|
|
|
const fragments = source.fragments
|
|
? source.fragments.replace(/\\@/g, '###').split('@')
|
|
.map((x) => x.replace(/###/g, '@'))
|
|
: [];
|
|
|
|
source.fragments = fragments[parseInt(fragment) - 1];
|
|
|
|
return source;
|
|
};
|
|
|
|
export const getNounEntries = defineCachedFunction(async (
|
|
db: Database,
|
|
isGranted: IsGrantedFn,
|
|
locale: string,
|
|
) => {
|
|
return await addVersions(db, isGranted, locale, await db.all<NounRowWithAuthor>(SQL`
|
|
SELECT n.*, u.username AS author FROM nouns n
|
|
LEFT JOIN users u ON n.author_id = u.id
|
|
WHERE n.locale = ${locale}
|
|
AND n.deleted = 0
|
|
AND n.approved >= ${isGranted('nouns') ? 0 : 1}
|
|
ORDER BY n.approved, n.masc
|
|
`));
|
|
}, {
|
|
name: 'nouns',
|
|
getKey: (db, isGranted, locale) => locale,
|
|
shouldBypassCache: (db, isGranted) => isGranted('nouns'),
|
|
maxAge: 24 * 60 * 60,
|
|
});
|
|
|
|
export const approveNounEntry = async (db: Database, id: string, locale: string) => {
|
|
const { base_id } = (await db.get<Pick<NounRow, 'base_id'>>(SQL`SELECT base_id FROM nouns WHERE id=${id}`))!;
|
|
if (base_id) {
|
|
await db.get(SQL`
|
|
UPDATE nouns
|
|
SET deleted=1
|
|
WHERE id = ${base_id}
|
|
`);
|
|
}
|
|
await db.get(SQL`
|
|
UPDATE nouns
|
|
SET approved = 1, base_id = NULL
|
|
WHERE id = ${id}
|
|
`);
|
|
await invalidateCacheKind('nouns', locale);
|
|
};
|