import { createFileRoute } from "@tanstack/react-router"; import { msg } from "@lingui/core/macro"; import { superTokensRequestMiddleware } from "@/utils/supertokens"; import { pbAdmin } from "@/lib/pocketbase/client"; import { logger } from "@/lib/logger"; import { localizedFor } from "@/lib/i18n/server-messages"; import { z } from "zod"; const uploadSchema = z.object({ tournamentId: z.string().min(1, "Tournament ID is required"), }); export const Route = createFileRoute("/api/tournaments/upload-logo")({ server: { middleware: [superTokensRequestMiddleware], handlers: { POST: async ({ request, context }) => { const i18n = localizedFor(context.metadata); try { const userId = context.userAuthId; const isAdmin = context.roles.includes("Admin"); if (!userId) return new Response("Unauthenticated", { status: 401 }); if (!isAdmin) return new Response("Unauthorized", { status: 403 }); const formData = await request.formData(); const tournamentId = formData.get("tournamentId") as string; const logoFile = formData.get("logo") as File; const validationResult = uploadSchema.safeParse({ tournamentId }); if (!validationResult.success) { return new Response( JSON.stringify({ error: i18n._(msg`Invalid input`), details: validationResult.error.issues, }), { status: 400, headers: { "Content-Type": "application/json" }, } ); } if (!logoFile || logoFile.size === 0) { return new Response( JSON.stringify({ error: i18n._(msg`Logo file is required`), }), { status: 400, headers: { "Content-Type": "application/json" }, } ); } const allowedTypes = [ "image/jpeg", "image/jpg", "image/png", "image/gif", ]; if (!allowedTypes.includes(logoFile.type)) { return new Response( JSON.stringify({ error: i18n._( msg`Invalid file type. Only JPEG, PNG and GIF are allowed.` ), }), { status: 400, headers: { "Content-Type": "application/json" }, } ); } const maxSize = 10 * 1024 * 1024; if (logoFile.size > maxSize) { return new Response( JSON.stringify({ error: i18n._(msg`File too large. Maximum size is 10MB.`), }), { status: 400, headers: { "Content-Type": "application/json" }, } ); } const tournament = await pbAdmin.getTournament(tournamentId); if (!tournament) { return new Response( JSON.stringify({ error: i18n._(msg`Tournament not found`), }), { status: 404, headers: { "Content-Type": "application/json" }, } ); } logger.info("Uploading tournament logo", { tournamentId, fileName: logoFile.name, fileSize: logoFile.size, userId, }); const pbFormData = new FormData(); pbFormData.append("logo", logoFile); const updatedTournament = await pbAdmin.updateTournament( tournamentId, pbFormData as any ); logger.info("Tournament logo uploaded successfully", { tournamentId, logo: updatedTournament.logo, }); return new Response( JSON.stringify({ success: true, tournament: updatedTournament, message: "Logo uploaded successfully", }), { status: 200, headers: { "Content-Type": "application/json" }, } ); } catch (error: any) { logger.error("Error uploading tournament logo:", error); return new Response( JSON.stringify({ error: i18n._(msg`Failed to upload logo`), message: error.message || i18n._(msg`Unknown error occurred`), }), { status: 500, headers: { "Content-Type": "application/json" }, } ); } }, }, }, });