146 lines
4.3 KiB
TypeScript
146 lines
4.3 KiB
TypeScript
import { createFileRoute } from "@tanstack/react-router";
|
|
import { superTokensRequestMiddleware } from "@/utils/supertokens";
|
|
import { pbAdmin } from "@/lib/pocketbase/client";
|
|
import { logger } from "@/lib/logger";
|
|
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 }) => {
|
|
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: "Invalid input",
|
|
details: validationResult.error.issues,
|
|
}),
|
|
{
|
|
status: 400,
|
|
headers: { "Content-Type": "application/json" },
|
|
}
|
|
);
|
|
}
|
|
|
|
if (!logoFile || logoFile.size === 0) {
|
|
return new Response(
|
|
JSON.stringify({
|
|
error: "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: "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: "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: "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: "Failed to upload logo",
|
|
message: error.message || "Unknown error occurred",
|
|
}),
|
|
{
|
|
status: 500,
|
|
headers: { "Content-Type": "application/json" },
|
|
}
|
|
);
|
|
}
|
|
},
|
|
},
|
|
},
|
|
});
|