feat: add tags/albums UI
This commit is contained in:
78
apps/web/app/api/assets/[id]/tags/route.ts
Normal file
78
apps/web/app/api/assets/[id]/tags/route.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import { getAdminToken, isAdminRequest } from "@tline/config";
|
||||
import { getDb } from "@tline/db";
|
||||
import { z } from "zod";
|
||||
|
||||
export const runtime = "nodejs";
|
||||
|
||||
const ADMIN_HEADER = "X-Porthole-Admin-Token";
|
||||
|
||||
const paramsSchema = z.object({
|
||||
id: z.string().uuid(),
|
||||
});
|
||||
|
||||
const bodySchema = z
|
||||
.object({
|
||||
tagId: z.string().uuid(),
|
||||
})
|
||||
.strict();
|
||||
|
||||
function getAdminOk(headers: Headers) {
|
||||
const headerToken = headers.get(ADMIN_HEADER);
|
||||
return isAdminRequest({ adminToken: getAdminToken() }, { headerToken });
|
||||
}
|
||||
|
||||
export async function POST(
|
||||
request: Request,
|
||||
context: { params: Promise<{ id: string }> },
|
||||
): Promise<Response> {
|
||||
if (!getAdminOk(request.headers)) {
|
||||
return Response.json({ error: "admin_required" }, { status: 401 });
|
||||
}
|
||||
|
||||
const rawParams = await context.params;
|
||||
const paramsParsed = paramsSchema.safeParse(rawParams);
|
||||
if (!paramsParsed.success) {
|
||||
return Response.json(
|
||||
{ error: "invalid_params", issues: paramsParsed.error.issues },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const bodyJson = await request.json().catch(() => ({}));
|
||||
const bodyParsed = bodySchema.safeParse(bodyJson);
|
||||
if (!bodyParsed.success) {
|
||||
return Response.json(
|
||||
{ error: "invalid_body", issues: bodyParsed.error.issues },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const db = getDb();
|
||||
const rows = await db<
|
||||
{
|
||||
asset_id: string;
|
||||
tag_id: string;
|
||||
}[]
|
||||
>`
|
||||
insert into asset_tags (asset_id, tag_id)
|
||||
values (${paramsParsed.data.id}, ${bodyParsed.data.tagId})
|
||||
on conflict (asset_id, tag_id)
|
||||
do nothing
|
||||
returning asset_id, tag_id
|
||||
`;
|
||||
|
||||
const created =
|
||||
rows[0] ??
|
||||
({ asset_id: paramsParsed.data.id, tag_id: bodyParsed.data.tagId } as const);
|
||||
|
||||
const payload = JSON.stringify({
|
||||
asset_id: created.asset_id,
|
||||
tag_id: created.tag_id,
|
||||
});
|
||||
await db`
|
||||
insert into audit_log (actor, action, entity_type, entity_id, payload)
|
||||
values ('admin', 'add_tag', 'asset', ${created.asset_id}, ${payload}::jsonb)
|
||||
`;
|
||||
|
||||
return Response.json(created, { status: 200 });
|
||||
}
|
||||
Reference in New Issue
Block a user