Files
dickloads/src/routes/admin/api/groups/[id]/+server.ts
Falkan aeeae1e7ce refactor: simplify admin code — extract shared helpers, fix quality issues
- Extract KEBAB_RE, SESSION_COOKIE, SESSION_MAX_AGE_MS, COOKIE_MAX_AGE,
  authRequest(), and sessionResponse() to auth.ts — eliminating 4 copies
  of the auth() wrapper and 3 copies of KEBAB_RE across admin API routes
- Remove timing side-channel: drop a.length !== b.length early-return
  before timingSafeEqual in verifySession (SHA-256 HMAC always 64 chars)
- Fix YOLO localStorage write-before-read race using initialization guard
- Fix admin layout /api/ bypass to return {} instead of {authenticated:true}
- Extract extractError() helper in admin page — removes 4 inline patterns
- Parallel Promise.all in admin loadData() — halves round-trip latency
- Parallel Promise.all in moveCheckedUnits() + surface per-request errors
- Hoist Big(inputValue) above .map() in converter — one alloc per recompute
- O(n) single-pass orderedResults using Map instead of O(n*groups) filters
- Fix expandedGroups.add() mutation — use Set assignment for consistency

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 14:04:33 -04:00

103 lines
3.5 KiB
TypeScript

import { json } from '@sveltejs/kit';
import { loadData, saveData } from '$lib/server/data';
import { authRequest } from '$lib/server/auth';
import type { RequestHandler } from './$types';
import type { Group } from '$lib/types';
export const PUT: RequestHandler = async ({ request, params }) => {
if (!authRequest(request)) return json({ error: 'Unauthorized' }, { status: 401 });
const { id } = params;
const body = await request.json().catch(() => null);
if (!body) return json({ error: 'Invalid JSON' }, { status: 400 });
const data = loadData();
const gIdx = data.groups.findIndex((g) => g.id === id);
if (gIdx === -1) return json({ error: 'Group not found' }, { status: 404 });
const patch = body as Partial<Group>;
const currentGroup = data.groups[gIdx];
// Special case: changing baseUnitId requires recalculating all unit toBase values
if (patch.baseUnitId !== undefined && patch.baseUnitId !== currentGroup.baseUnitId) {
const newBaseId = patch.baseUnitId;
const newBaseUnit = data.units.find((u) => u.id === newBaseId && u.group === id);
if (!newBaseUnit) {
return json({ error: `baseUnitId '${newBaseId}' not found in this group` }, { status: 400 });
}
const X = newBaseUnit.toBase; // Current toBase of the new base unit
// Recalculate all units in this group: unit.toBase = unit.toBase / X
// Then set new base unit toBase = 1.0
for (const unit of data.units) {
if (unit.group === id) {
unit.toBase = unit.id === newBaseId ? 1.0 : unit.toBase / X;
}
}
}
const updated: Group = { ...currentGroup, ...patch };
data.groups[gIdx] = updated;
saveData(data);
return json(updated);
};
export const DELETE: RequestHandler = async ({ request, params }) => {
if (!authRequest(request)) return json({ error: 'Unauthorized' }, { status: 401 });
const { id } = params;
const body = await request.json().catch(() => ({}));
const { action, targetGroupId, toBaseAction } = body as {
action?: 'reassign' | 'orphan';
targetGroupId?: string;
toBaseAction?: 'recalculate' | 'reset' | 'keep';
};
if (!action || (action !== 'reassign' && action !== 'orphan')) {
return json({ error: "action must be 'reassign' or 'orphan'" }, { status: 400 });
}
const data = loadData();
const gIdx = data.groups.findIndex((g) => g.id === id);
if (gIdx === -1) return json({ error: 'Group not found' }, { status: 404 });
const fromGroup = data.groups[gIdx];
const unitsInGroup = data.units.filter((u) => u.group === id);
if (action === 'reassign') {
if (!targetGroupId) {
return json({ error: 'targetGroupId required for reassign' }, { status: 400 });
}
if (targetGroupId === id) {
return json({ error: 'Cannot reassign to the same group' }, { status: 400 });
}
const toGroup = data.groups.find((g) => g.id === targetGroupId);
if (!toGroup) {
return json({ error: `Target group '${targetGroupId}' not found` }, { status: 404 });
}
for (const unit of data.units) {
if (unit.group === id) {
if (toBaseAction === 'recalculate') {
unit.toBase = (unit.toBase * fromGroup.toUniversal) / toGroup.toUniversal;
} else if (toBaseAction === 'reset') {
unit.toBase = 1.0;
}
// 'keep' or default: no change to toBase
unit.group = targetGroupId;
}
}
} else {
// orphan
for (const unit of data.units) {
if (unit.group === id) unit.group = null;
}
}
data.groups.splice(gIdx, 1);
saveData(data);
return json({ ok: true, unitsAffected: unitsInGroup.length });
};