NeahStable/app/api/missions/[missionId]/files/folder/route.ts
2026-01-21 11:40:40 +01:00

145 lines
5.0 KiB
TypeScript

import { NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from "@/app/api/auth/options";
import { prisma } from '@/lib/prisma';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
// S3 Configuration for missions - uses environment variables
const MISSIONS_S3_CONFIG = {
endpoint: (process.env.MINIO_S3_UPLOAD_BUCKET_URL || process.env.S3_ENDPOINT || 'https://dome-api.slm-lab.net').replace(/\/$/, ''),
region: process.env.MINIO_AWS_REGION || process.env.S3_REGION || 'us-east-1',
accessKey: process.env.MINIO_ACCESS_KEY || process.env.S3_ACCESS_KEY || '',
secretKey: process.env.MINIO_SECRET_KEY || process.env.S3_SECRET_KEY || '',
bucket: 'missions' // Missions bucket is always 'missions'
};
// Validate required S3 configuration
if (!MISSIONS_S3_CONFIG.accessKey || !MISSIONS_S3_CONFIG.secretKey) {
const errorMsg = '⚠️ S3 credentials are missing! Please set MINIO_ACCESS_KEY and MINIO_SECRET_KEY environment variables.';
console.error(errorMsg);
if (process.env.NODE_ENV === 'production') {
throw new Error('S3 credentials are required in production environment');
}
}
// Use the exact same S3 client configuration as mission-uploads.ts
const missionsS3Client = new S3Client({
region: MISSIONS_S3_CONFIG.region,
endpoint: MISSIONS_S3_CONFIG.endpoint,
credentials: {
accessKeyId: MISSIONS_S3_CONFIG.accessKey,
secretAccessKey: MISSIONS_S3_CONFIG.secretKey
},
forcePathStyle: true // Required for MinIO
});
const MISSIONS_BUCKET = MISSIONS_S3_CONFIG.bucket;
// Helper function to check if user can manage files (creator or gardien)
// Also checks if mission is closed (closed missions cannot be modified)
async function checkCanManage(userId: string, missionId: string): Promise<{ canManage: boolean; isClosed: boolean }> {
const mission = await prisma.mission.findFirst({
where: { id: missionId },
select: {
creatorId: true,
isClosed: true,
missionUsers: {
where: { userId },
select: { role: true }
}
}
});
if (!mission) return { canManage: false, isClosed: false };
// If mission is closed, no one can manage files
if (mission.isClosed) {
return { canManage: false, isClosed: true };
}
// Creator can always manage
if (mission.creatorId === userId) return { canManage: true, isClosed: false };
// Gardiens can manage
const userRole = mission.missionUsers[0]?.role;
const canManage = userRole === 'gardien-temps' || userRole === 'gardien-parole' || userRole === 'gardien-memoire';
return { canManage, isClosed: false };
}
export async function POST(
request: Request,
{ params }: { params: Promise<{ missionId: string }> }
) {
try {
const session = await getServerSession(authOptions);
if (!session?.user?.id) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}
const { missionId } = await params;
const userId = session.user.id;
// Check if user can manage files and if mission is closed
const { canManage, isClosed } = await checkCanManage(userId, missionId);
if (isClosed) {
return NextResponse.json({ error: 'Mission is closed: folders cannot be created in closed missions' }, { status: 403 });
}
if (!canManage) {
return NextResponse.json({ error: 'Forbidden: You do not have permission to create folders' }, { status: 403 });
}
const body = await request.json();
const { path } = body;
if (!path) {
return NextResponse.json({ error: 'Path is required' }, { status: 400 });
}
// Construct the S3 key for the folder marker
// Files are stored in MinIO without the "missions/" prefix
// The path from frontend might be relative (e.g., "attachments/Content") or absolute
// We need to ensure it includes the missionId
let folderPath = path;
if (!folderPath.startsWith(missionId)) {
// If path doesn't start with missionId, prepend it
folderPath = `${missionId}/${folderPath}`;
}
// Remove "missions/" prefix if present (for consistency)
folderPath = folderPath.replace(/^missions\//, '');
const s3Key = folderPath.endsWith('/') ? `${folderPath}.placeholder` : `${folderPath}/.placeholder`;
console.log(`[POST /api/missions/${missionId}/files/folder] Creating folder:`, {
originalPath: path,
folderPath: folderPath,
s3Key: s3Key,
bucket: MISSIONS_BUCKET
});
// Create folder marker in S3
await missionsS3Client.send(new PutObjectCommand({
Bucket: MISSIONS_BUCKET,
Key: s3Key,
Body: Buffer.alloc(0),
ContentType: 'application/octet-stream'
}));
return NextResponse.json({
success: true,
folder: {
type: 'folder',
name: path.split('/').pop() || path,
path: `missions/${path}`,
key: `missions/${path}`
}
});
} catch (error: any) {
console.error('Error creating folder:', error);
return NextResponse.json(
{ error: 'Failed to create folder', details: error.message },
{ status: 500 }
);
}
}