NeahNew/app/api/missions/upload/route.ts
2025-05-05 13:04:01 +02:00

176 lines
5.8 KiB
TypeScript

import { NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from "@/app/api/auth/options";
import { PrismaClient } from '@prisma/client';
import { prisma } from '@/lib/prisma';
import {
uploadMissionLogo,
uploadMissionAttachment,
generateMissionLogoUploadUrl,
generateMissionAttachmentUploadUrl
} from '@/lib/mission-uploads';
// Helper function to check authentication
async function checkAuth(request: Request) {
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
console.error('Unauthorized access attempt:', {
url: request.url,
method: request.method,
headers: Object.fromEntries(request.headers)
});
return { authorized: false, userId: null };
}
return { authorized: true, userId: session.user.id };
}
// Generate presigned URL for direct upload to S3/Minio
export async function GET(request: Request) {
try {
const { authorized, userId } = await checkAuth(request);
if (!authorized || !userId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { searchParams } = new URL(request.url);
const missionId = searchParams.get('missionId');
const type = searchParams.get('type'); // 'logo' or 'attachment'
const filename = searchParams.get('filename');
if (!missionId || !type || !filename) {
return NextResponse.json({
error: 'Missing required parameters',
required: { missionId: true, type: true, filename: true },
received: { missionId: !!missionId, type: !!type, filename: !!filename }
}, { status: 400 });
}
// Verify that the mission exists and user has access to it
const mission = await prisma.mission.findUnique({
where: { id: missionId },
select: { id: true, creatorId: true }
});
if (!mission) {
return NextResponse.json({ error: 'Mission not found' }, { status: 404 });
}
// Currently only allow creator to upload files
// You can modify this to include other roles if needed
if (mission.creatorId !== userId) {
return NextResponse.json({ error: 'Not authorized to upload to this mission' }, { status: 403 });
}
let result;
if (type === 'logo') {
// For logo, we expect filename to contain the file extension (e.g., '.jpg')
const fileExtension = filename.substring(filename.lastIndexOf('.'));
result = await generateMissionLogoUploadUrl(userId, missionId, fileExtension);
} else if (type === 'attachment') {
result = await generateMissionAttachmentUploadUrl(userId, missionId, filename);
} else {
return NextResponse.json({ error: 'Invalid upload type' }, { status: 400 });
}
return NextResponse.json(result);
} catch (error) {
console.error('Error generating upload URL:', error);
return NextResponse.json({
error: 'Internal server error',
details: error instanceof Error ? error.message : String(error)
}, { status: 500 });
}
}
// Handle file upload (server-side)
export async function POST(request: Request) {
try {
const { authorized, userId } = await checkAuth(request);
if (!authorized || !userId) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
// Parse the form data
const formData = await request.formData();
const missionId = formData.get('missionId') as string;
const type = formData.get('type') as string; // 'logo' or 'attachment'
const file = formData.get('file') as File;
if (!missionId || !type || !file) {
return NextResponse.json({
error: 'Missing required fields',
required: { missionId: true, type: true, file: true },
received: { missionId: !!missionId, type: !!type, file: !!file }
}, { status: 400 });
}
// Verify that the mission exists and user has access to it
const mission = await prisma.mission.findUnique({
where: { id: missionId },
select: { id: true, creatorId: true }
});
if (!mission) {
return NextResponse.json({ error: 'Mission not found' }, { status: 404 });
}
// Currently only allow creator to upload files
if (mission.creatorId !== userId) {
return NextResponse.json({ error: 'Not authorized to upload to this mission' }, { status: 403 });
}
if (type === 'logo') {
// Upload logo file to Minio
const { filePath } = await uploadMissionLogo(userId, missionId, file);
// Update mission record with logo path
await prisma.mission.update({
where: { id: missionId },
data: { logo: filePath }
});
return NextResponse.json({ success: true, filePath });
}
else if (type === 'attachment') {
// Upload attachment file to Minio
const { filename, filePath, fileType, fileSize } = await uploadMissionAttachment(
userId,
missionId,
file
);
// Create attachment record in database
const attachment = await prisma.attachment.create({
data: {
filename,
filePath,
fileType,
fileSize,
missionId,
uploaderId: userId
}
});
return NextResponse.json({
success: true,
attachment: {
id: attachment.id,
filename: attachment.filename,
filePath: attachment.filePath,
fileType: attachment.fileType,
fileSize: attachment.fileSize,
createdAt: attachment.createdAt
}
});
}
else {
return NextResponse.json({ error: 'Invalid upload type' }, { status: 400 });
}
} catch (error) {
console.error('Error uploading file:', error);
return NextResponse.json({
error: 'Internal server error',
details: error instanceof Error ? error.message : String(error)
}, { status: 500 });
}
}