aegida-console / app / api / attachments / route.ts
route.ts
Raw
import { AuthError, authenticateRequest } from "@/lib/auth/server";
import { AttachmentValidationError, validateAttachmentUpload } from "@/lib/chat/attachments";
import {
  deleteGateFile,
  GateFileError,
  uploadGateFile,
} from "@/lib/chat/gate-files";
import { createPendingAttachment } from "@/lib/db/attachments";
import { getPool } from "@/lib/db/pool";

export const runtime = "nodejs";
const headers = { "Cache-Control": "no-store" };

export async function POST(request: Request): Promise<Response> {
  try {
    const user = await authenticateRequest(request);
    const authorization = request.headers.get("Authorization");
    if (!authorization) throw new AuthError();
    const file = (await request.formData()).get("file");
    if (!(file instanceof File)) throw new AttachmentValidationError();
    const validated = await validateAttachmentUpload(file);
    const gateFile = await uploadGateFile(file, authorization, request.signal);
    let attachment: Awaited<ReturnType<typeof createPendingAttachment>>;
    try {
      if (gateFile.bytes !== validated.size) throw new GateFileError();
      attachment = await createPendingAttachment(getPool(), user.id, {
        ...validated,
        gateFileId: gateFile.id,
      });
    } catch (error) {
      await deleteGateFile(
        gateFile.id,
        authorization,
        new AbortController().signal,
      ).catch(() => undefined);
      throw error;
    }
    return Response.json({ attachment: { id: attachment.id, name: attachment.name, contentType: attachment.contentType, size: attachment.size } }, { status: 201, headers });
  } catch (error) {
    const status =
      error instanceof AuthError ||
      (error instanceof GateFileError && error.reason === "unauthorized")
        ? 401
        : error instanceof AttachmentValidationError
          ? 400
          : 503;
    return Response.json({ error: status === 400 ? "Недопустимое вложение" : status === 401 ? "Unauthorized" : "Хранилище вложений временно недоступно" }, { status, headers });
  }
}