feat(isac): add moderated contributor mode
This commit is contained in:
@@ -7,11 +7,12 @@ import type { Actions, PageServerLoad } from './$types';
|
||||
import { getPagination } from '$lib/server/pagination';
|
||||
import { auditRecord, recordIsacAudit } from '$lib/server/audit';
|
||||
import { applyIconMutation, gameDataIconMetadata, gameDataIconUrl, GameDataIconValidationError, readIconMutation } from '$lib/server/game-data-icons';
|
||||
import { getPendingEntities } from '$lib/server/data-moderation';
|
||||
|
||||
type SharedEffect = { statId: string; valueI: number; valueII: number };
|
||||
|
||||
export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
await requireDataView(await getSessionUser(cookies));
|
||||
const user = await requireDataView(await getSessionUser(cookies));
|
||||
const db = await getDatabase();
|
||||
const totalRow = await (await db.prepare('SELECT COUNT(*) AS total FROM talents')).get();
|
||||
const filter = ['slot1', 'slot2', 'exotic', 'backpack', 'body-armor'].includes(url.searchParams.get('filter') ?? '') ? String(url.searchParams.get('filter')) : '';
|
||||
@@ -35,7 +36,7 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
(await db.prepare('SELECT id,name,exotic_talent_id FROM weapons WHERE exotic_talent_id IS NOT NULL')).all(),
|
||||
(await db.prepare("SELECT entity_id,updated_at FROM game_data_icons WHERE entity_type='talent'")).all()
|
||||
]);
|
||||
const [triggerSummary, slotSummary, exoticSummary, gearSummary] = await Promise.all([
|
||||
const [triggerSummary, slotSummary, exoticSummary, gearSummary, pending] = await Promise.all([
|
||||
(await db.prepare('SELECT COUNT(*) AS total FROM talent_triggers')).get(),
|
||||
(await db.prepare(`SELECT
|
||||
SUM(CASE WHEN slot=1 THEN 1 ELSE 0 END) AS slot1,
|
||||
@@ -44,8 +45,14 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
(await db.prepare(`SELECT
|
||||
SUM(CASE WHEN category='Backpack' THEN 1 ELSE 0 END) AS backpack,
|
||||
SUM(CASE WHEN category IN ('Vest','Body Armor') THEN 1 ELSE 0 END) AS body_armor
|
||||
FROM talents`)).get()
|
||||
FROM talents`)).get(),
|
||||
getPendingEntities(user.id, [
|
||||
{ module: 'talents', action: 'saveTrigger', kind: 'trigger', fields: ['description'] },
|
||||
{ module: 'stats', action: 'save', kind: 'stat', fields: ['unit'] }
|
||||
])
|
||||
]);
|
||||
const pendingTriggers = pending.filter((item) => item.kind === 'trigger');
|
||||
const pendingStats = pending.filter((item) => item.kind === 'stat');
|
||||
return {
|
||||
talents: talents.map((talent) => ({
|
||||
...talent,
|
||||
@@ -70,8 +77,8 @@ export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
effects: effects.filter((effect) => effect.talent_tier_id === tier.id)
|
||||
}))
|
||||
})),
|
||||
triggers,
|
||||
stats,
|
||||
triggers: [...pendingTriggers, ...triggers],
|
||||
stats: [...pendingStats, ...stats],
|
||||
summary: {
|
||||
total: Number(totalRow?.total ?? 0),
|
||||
triggers: Number(triggerSummary?.total ?? 0),
|
||||
@@ -122,7 +129,7 @@ export const actions: Actions = {
|
||||
if (uptime && (!Number.isFinite(min) || !Number.isFinite(max) || Number(min) < 0 || Number(max) > 100 || Number(min) > Number(max))) return fail(400, { triggerError: 'Uptime must be a valid 0–100% range.' });
|
||||
const db = await getDatabase();
|
||||
if (await (await db.prepare('SELECT id FROM talent_triggers WHERE name=? COLLATE NOCASE AND id<>?')).get(name, id || 'new')) return fail(409, { triggerError: 'That trigger already exists.' });
|
||||
const now = new Date().toISOString(), triggerId = id || randomUUID();
|
||||
const now = new Date().toISOString(), triggerId = id || String(form.get('_proposedEntityId') ?? '') || randomUUID();
|
||||
const before = id ? await auditRecord('talent_triggers', id) : null;
|
||||
if (id) await (await db.prepare('UPDATE talent_triggers SET name=?,description=?,supports_uptime=?,min_uptime=?,max_uptime=?,updated_at=? WHERE id=?')).run(name, description, uptime ? 1 : 0, min, max, now, id);
|
||||
else await (await db.prepare('INSERT INTO talent_triggers(id,name,description,supports_uptime,min_uptime,max_uptime,created_at,updated_at) VALUES(?,?,?,?,?,?,?,?)')).run(triggerId, name, description, uptime ? 1 : 0, min, max, now, now);
|
||||
@@ -152,7 +159,7 @@ export const actions: Actions = {
|
||||
const statRows = await (await db.prepare(`SELECT id,unit FROM stat_attributes WHERE active=1 AND id IN (${sharedEffects.map(() => '?').join(',')})`)).all(...sharedEffects.map((effect) => effect.statId));
|
||||
if (statRows.length !== sharedEffects.length) return fail(400, { talentError: 'One or more selected attributes are unavailable.' });
|
||||
const units = new Map(statRows.map((stat) => [String(stat.id), stat.unit]));
|
||||
const talentId = id || randomUUID(), now = new Date().toISOString();
|
||||
const talentId = id || String(form.get('_proposedEntityId') ?? '') || randomUUID(), now = new Date().toISOString();
|
||||
const before = id ? { record: await auditRecord('talents', id), icon: await gameDataIconMetadata(db, 'talent', id), template: await (await db.prepare('SELECT template FROM talent_description_templates WHERE talent_id=?')).get(id), tiers: await (await db.prepare('SELECT tier,description FROM talent_tiers WHERE talent_id=? ORDER BY tier')).all(id) } : null;
|
||||
if (id) await (await db.prepare('UPDATE talents SET name=?,category=?,updated_at=? WHERE id=?')).run(name, storedCategory, now, id);
|
||||
else await (await db.prepare('INSERT INTO talents(id,name,category,created_at,updated_at) VALUES(?,?,?,?,?)')).run(talentId, name, storedCategory, now, now);
|
||||
|
||||
Reference in New Issue
Block a user