102 lines
3.3 KiB
TypeScript
102 lines
3.3 KiB
TypeScript
|
|
import { NextRequest, NextResponse } from 'next/server';
|
||
|
|
import { requireAuth } from '@/lib/auth-utils';
|
||
|
|
import { postgresClient } from '@/lib/services/postgres-client';
|
||
|
|
|
||
|
|
// GET /api/me/queue-preferences
|
||
|
|
// -> { queues: [{ id, label, hidden }], hiddenIds: number[] }
|
||
|
|
// Returns every active queue with a `hidden` flag for the calling user,
|
||
|
|
// plus the bare list of hidden queue IDs (for clients that only need that).
|
||
|
|
//
|
||
|
|
// PUT /api/me/queue-preferences
|
||
|
|
// body { hiddenIds: number[] } -> { hiddenIds: number[] }
|
||
|
|
// Replaces the user's hidden-queue set atomically (full set semantics).
|
||
|
|
//
|
||
|
|
// Per-user only — writes target session.user.id, never an id from the body.
|
||
|
|
|
||
|
|
export async function GET(): Promise<NextResponse> {
|
||
|
|
const { session, error } = await requireAuth();
|
||
|
|
if (error) return error;
|
||
|
|
|
||
|
|
try {
|
||
|
|
const result = await postgresClient.query<{
|
||
|
|
value: number;
|
||
|
|
label: string;
|
||
|
|
hidden: boolean;
|
||
|
|
}>(
|
||
|
|
`SELECT q.value, q.label,
|
||
|
|
(p.queue_id IS NOT NULL) AS hidden
|
||
|
|
FROM queues q
|
||
|
|
LEFT JOIN user_queue_preferences p
|
||
|
|
ON p.queue_id = q.value AND p.user_id = $1
|
||
|
|
WHERE q.is_active = true
|
||
|
|
AND (q.is_deleted = false OR q.is_deleted IS NULL)
|
||
|
|
ORDER BY q.label`,
|
||
|
|
[session!.user.id],
|
||
|
|
);
|
||
|
|
const queues = result.rows.map((r) => ({
|
||
|
|
id: r.value,
|
||
|
|
label: r.label,
|
||
|
|
hidden: r.hidden,
|
||
|
|
}));
|
||
|
|
const hiddenIds = queues.filter((q) => q.hidden).map((q) => q.id);
|
||
|
|
return NextResponse.json({ queues, hiddenIds });
|
||
|
|
} catch (e) {
|
||
|
|
console.error('GET /api/me/queue-preferences failed:', e);
|
||
|
|
return NextResponse.json(
|
||
|
|
{ error: 'Failed to read queue preferences', message: e instanceof Error ? e.message : 'unknown' },
|
||
|
|
{ status: 500 },
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export async function PUT(request: NextRequest): Promise<NextResponse> {
|
||
|
|
const { session, error } = await requireAuth();
|
||
|
|
if (error) return error;
|
||
|
|
|
||
|
|
let body: unknown;
|
||
|
|
try {
|
||
|
|
body = await request.json();
|
||
|
|
} catch {
|
||
|
|
return NextResponse.json(
|
||
|
|
{ error: 'Invalid JSON', message: 'Request body must be JSON' },
|
||
|
|
{ status: 400 },
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const raw =
|
||
|
|
body && typeof body === 'object' && 'hiddenIds' in body
|
||
|
|
? (body as { hiddenIds: unknown }).hiddenIds
|
||
|
|
: undefined;
|
||
|
|
|
||
|
|
if (!Array.isArray(raw) || !raw.every((v) => Number.isInteger(v))) {
|
||
|
|
return NextResponse.json(
|
||
|
|
{ error: 'Invalid input', message: 'hiddenIds must be an array of integers' },
|
||
|
|
{ status: 400 },
|
||
|
|
);
|
||
|
|
}
|
||
|
|
const hiddenIds = [...new Set(raw as number[])];
|
||
|
|
|
||
|
|
const userId = session!.user.id;
|
||
|
|
|
||
|
|
try {
|
||
|
|
await postgresClient.transaction(async (client) => {
|
||
|
|
await client.query('DELETE FROM user_queue_preferences WHERE user_id = $1', [userId]);
|
||
|
|
if (hiddenIds.length > 0) {
|
||
|
|
const placeholders = hiddenIds.map((_, i) => `($1, $${i + 2})`).join(', ');
|
||
|
|
await client.query(
|
||
|
|
`INSERT INTO user_queue_preferences (user_id, queue_id) VALUES ${placeholders}
|
||
|
|
ON CONFLICT (user_id, queue_id) DO NOTHING`,
|
||
|
|
[userId, ...hiddenIds],
|
||
|
|
);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
return NextResponse.json({ hiddenIds });
|
||
|
|
} catch (e) {
|
||
|
|
console.error('PUT /api/me/queue-preferences failed:', e);
|
||
|
|
return NextResponse.json(
|
||
|
|
{ error: 'Failed to update queue preferences', message: e instanceof Error ? e.message : 'unknown' },
|
||
|
|
{ status: 500 },
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|