missions finition

This commit is contained in:
alma 2026-01-21 11:40:40 +01:00
parent d7742ed6e8
commit 18143c73db
7 changed files with 136 additions and 37 deletions

View File

@ -4,19 +4,36 @@ import { authOptions } from "@/app/api/auth/options";
import { prisma } from '@/lib/prisma'; import { prisma } from '@/lib/prisma';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; 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 // Use the exact same S3 client configuration as mission-uploads.ts
// Use hardcoded credentials as primary (same as mission-uploads.ts)
const missionsS3Client = new S3Client({ const missionsS3Client = new S3Client({
region: 'us-east-1', region: MISSIONS_S3_CONFIG.region,
endpoint: 'https://dome-api.slm-lab.net', endpoint: MISSIONS_S3_CONFIG.endpoint,
credentials: { credentials: {
accessKeyId: '4aBT4CMb7JIMMyUtp4Pl', // Primary: hardcoded (same as mission-uploads.ts) accessKeyId: MISSIONS_S3_CONFIG.accessKey,
secretAccessKey: 'HGn39XhCIlqOjmDVzRK9MED2Fci2rYvDDgbLFElg' // Primary: hardcoded (same as mission-uploads.ts) secretAccessKey: MISSIONS_S3_CONFIG.secretKey
}, },
forcePathStyle: true // Required for MinIO forcePathStyle: true // Required for MinIO
}); });
const MISSIONS_BUCKET = 'missions'; const MISSIONS_BUCKET = MISSIONS_S3_CONFIG.bucket;
// Helper function to check if user can manage files (creator or gardien) // Helper function to check if user can manage files (creator or gardien)
// Also checks if mission is closed (closed missions cannot be modified) // Also checks if mission is closed (closed missions cannot be modified)

View File

@ -5,19 +5,37 @@ import { prisma } from '@/lib/prisma';
import { S3Client, ListObjectsV2Command, GetObjectCommand, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3'; import { S3Client, ListObjectsV2Command, GetObjectCommand, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3';
import { Readable } from 'stream'; import { Readable } from 'stream';
// 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 and image route // Use the exact same S3 client configuration as mission-uploads.ts and image route
// This ensures we use the same credentials and settings that work for other mission operations // This ensures we use the same credentials and settings that work for other mission operations
const missionsS3Client = new S3Client({ const missionsS3Client = new S3Client({
region: 'us-east-1', region: MISSIONS_S3_CONFIG.region,
endpoint: 'https://dome-api.slm-lab.net', endpoint: MISSIONS_S3_CONFIG.endpoint,
credentials: { credentials: {
accessKeyId: '4aBT4CMb7JIMMyUtp4Pl', accessKeyId: MISSIONS_S3_CONFIG.accessKey,
secretAccessKey: 'HGn39XhCIlqOjmDVzRK9MED2Fci2rYvDDgbLFElg' secretAccessKey: MISSIONS_S3_CONFIG.secretKey
}, },
forcePathStyle: true // Required for MinIO forcePathStyle: true // Required for MinIO
}); });
const MISSIONS_BUCKET = 'missions'; const MISSIONS_BUCKET = MISSIONS_S3_CONFIG.bucket;
// Helper function to check if user has access to mission // Helper function to check if user has access to mission
async function checkMissionAccess(userId: string, missionId: string): Promise<boolean> { async function checkMissionAccess(userId: string, missionId: string): Promise<boolean> {

View File

@ -5,13 +5,31 @@ import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { NoSuchKey } from '@aws-sdk/client-s3'; import { NoSuchKey } from '@aws-sdk/client-s3';
import { logger } from '@/lib/logger'; import { logger } from '@/lib/logger';
// 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');
}
}
// Initialize S3 client // Initialize S3 client
const s3Client = new S3Client({ const s3Client = new S3Client({
region: 'us-east-1', region: MISSIONS_S3_CONFIG.region,
endpoint: 'https://dome-api.slm-lab.net', endpoint: MISSIONS_S3_CONFIG.endpoint,
credentials: { credentials: {
accessKeyId: '4aBT4CMb7JIMMyUtp4Pl', accessKeyId: MISSIONS_S3_CONFIG.accessKey,
secretAccessKey: 'HGn39XhCIlqOjmDVzRK9MED2Fci2rYvDDgbLFElg' secretAccessKey: MISSIONS_S3_CONFIG.secretKey
}, },
forcePathStyle: true // Required for MinIO forcePathStyle: true // Required for MinIO
}); });
@ -43,7 +61,7 @@ export async function GET(
}); });
const command = new GetObjectCommand({ const command = new GetObjectCommand({
Bucket: 'missions', Bucket: MISSIONS_S3_CONFIG.bucket,
Key: minioPath, Key: minioPath,
}); });

View File

@ -9,6 +9,9 @@ import { CopyObjectCommand, DeleteObjectCommand, HeadObjectCommand } from '@aws-
import { uploadMissionLogo, uploadMissionAttachment, getMissionFileUrl } from '@/lib/mission-uploads'; import { uploadMissionLogo, uploadMissionAttachment, getMissionFileUrl } from '@/lib/mission-uploads';
import { logger } from '@/lib/logger'; import { logger } from '@/lib/logger';
// Missions bucket name - consistent across all mission file operations
const MISSIONS_BUCKET = 'missions';
// Types // Types
interface MissionCreateInput { interface MissionCreateInput {
name: string; name: string;
@ -194,7 +197,7 @@ export async function GET(request: Request) {
async function verifyFileExists(filePath: string): Promise<boolean> { async function verifyFileExists(filePath: string): Promise<boolean> {
try { try {
await s3Client.send(new HeadObjectCommand({ await s3Client.send(new HeadObjectCommand({
Bucket: 'missions', Bucket: MISSIONS_BUCKET,
Key: filePath.replace('missions/', '') Key: filePath.replace('missions/', '')
})); }));
return true; return true;
@ -530,7 +533,7 @@ export async function POST(request: Request) {
for (const file of uploadedFiles) { for (const file of uploadedFiles) {
try { try {
await s3Client.send(new DeleteObjectCommand({ await s3Client.send(new DeleteObjectCommand({
Bucket: 'missions', Bucket: MISSIONS_BUCKET,
Key: file.path.replace('missions/', '') Key: file.path.replace('missions/', '')
})); }));
logger.debug('Cleaned up file', { path: file.path }); logger.debug('Cleaned up file', { path: file.path });

View File

@ -148,10 +148,21 @@ services:
NODE_ENV: production NODE_ENV: production
NEXT_TELEMETRY_DISABLED: 1 NEXT_TELEMETRY_DISABLED: 1
# MinIO / S3 Configuration (required for mission file uploads)
MINIO_S3_UPLOAD_BUCKET_URL: ${MINIO_S3_UPLOAD_BUCKET_URL:-https://dome-api.slm-lab.net}
MINIO_AWS_REGION: ${MINIO_AWS_REGION:-us-east-1}
MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
# API URLs (required for mission creation)
NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-https://hub.slm-lab.net}
NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-https://hub.slm-lab.net}
# N8N Integration (required for mission creation workflow)
N8N_API_KEY: ${N8N_API_KEY}
N8N_WEBHOOK_URL: ${N8N_WEBHOOK_URL:-https://brain.slm-lab.net/webhook/mission-created}
# Autres variables d'environnement (ajoutez les vôtres) # Autres variables d'environnement (ajoutez les vôtres)
# MINIO_S3_UPLOAD_BUCKET_URL: ${MINIO_S3_UPLOAD_BUCKET_URL}
# MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY}
# MINIO_SECRET_KEY: ${MINIO_SECRET_KEY}
# volumes: # volumes:
# Optionnel: monter des fichiers de configuration ou des uploads # Optionnel: monter des fichiers de configuration ou des uploads
# - ./uploads:/app/uploads # - ./uploads:/app/uploads

View File

@ -42,13 +42,27 @@ NODE_ENV=production
NEXT_TELEMETRY_DISABLED=1 NEXT_TELEMETRY_DISABLED=1
# ============================================ # ============================================
# MinIO / S3 (si utilisé) # MinIO / S3 (REQUIS pour les missions)
# ============================================ # ============================================
# MINIO_S3_UPLOAD_BUCKET_URL=http://minio:9000 # Ces variables sont OBLIGATOIRES pour créer des missions avec logos et pièces jointes
# MINIO_AWS_REGION=us-east-1 MINIO_S3_UPLOAD_BUCKET_URL=https://dome-api.slm-lab.net
# MINIO_AWS_S3_UPLOAD_BUCKET_NAME=missions MINIO_AWS_REGION=us-east-1
# MINIO_ACCESS_KEY=minioadmin MINIO_AWS_S3_UPLOAD_BUCKET_NAME=missions
# MINIO_SECRET_KEY=CHANGEZ_CE_MOT_DE_PASSE MINIO_ACCESS_KEY=VOTRE_ACCESS_KEY
MINIO_SECRET_KEY=VOTRE_SECRET_KEY
# ============================================
# URLs de l'application (REQUIS pour les missions)
# ============================================
NEXT_PUBLIC_API_URL=https://hub.slm-lab.net
NEXT_PUBLIC_APP_URL=https://hub.slm-lab.net
# ============================================
# N8N Integration (REQUIS pour les missions)
# ============================================
# N8N est utilisé pour créer automatiquement les projets Leantime, repos Git, etc.
N8N_API_KEY=VOTRE_N8N_API_KEY
N8N_WEBHOOK_URL=https://brain.slm-lab.net/webhook/mission-created
# ============================================ # ============================================
# Autres services (ajoutez selon vos besoins) # Autres services (ajoutez selon vos besoins)

View File

@ -5,13 +5,31 @@
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { logger } from '@/lib/logger'; import { logger } from '@/lib/logger';
// 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');
}
}
// Initialize S3 client for Minio // Initialize S3 client for Minio
const s3Client = new S3Client({ const s3Client = new S3Client({
region: 'us-east-1', region: MISSIONS_S3_CONFIG.region,
endpoint: 'https://dome-api.slm-lab.net', endpoint: MISSIONS_S3_CONFIG.endpoint,
credentials: { credentials: {
accessKeyId: '4aBT4CMb7JIMMyUtp4Pl', accessKeyId: MISSIONS_S3_CONFIG.accessKey,
secretAccessKey: 'HGn39XhCIlqOjmDVzRK9MED2Fci2rYvDDgbLFElg' secretAccessKey: MISSIONS_S3_CONFIG.secretKey
}, },
forcePathStyle: true // Required for MinIO forcePathStyle: true // Required for MinIO
}); });
@ -53,7 +71,7 @@ export async function deleteMissionLogo(missionId: string, logoPath: string): Pr
}); });
const command = new DeleteObjectCommand({ const command = new DeleteObjectCommand({
Bucket: 'missions', Bucket: MISSIONS_S3_CONFIG.bucket,
Key: minioPath, Key: minioPath,
}); });
@ -83,7 +101,7 @@ export async function deleteMissionAttachment(filePath: string): Promise<void> {
}); });
const command = new DeleteObjectCommand({ const command = new DeleteObjectCommand({
Bucket: 'missions', Bucket: MISSIONS_S3_CONFIG.bucket,
Key: minioPath, Key: minioPath,
}); });
@ -118,13 +136,13 @@ export async function uploadMissionLogo(userId: string, missionId: string, file:
const buffer = Buffer.from(arrayBuffer); const buffer = Buffer.from(arrayBuffer);
logger.debug('Uploading to Minio', { logger.debug('Uploading to Minio', {
bucket: 'missions', bucket: MISSIONS_S3_CONFIG.bucket,
key: minioPath, key: minioPath,
contentType: file.type contentType: file.type
}); });
await s3Client.send(new PutObjectCommand({ await s3Client.send(new PutObjectCommand({
Bucket: 'missions', Bucket: MISSIONS_S3_CONFIG.bucket,
Key: minioPath, Key: minioPath,
Body: buffer, Body: buffer,
ContentType: file.type, ContentType: file.type,
@ -174,13 +192,13 @@ export async function uploadMissionAttachment(
const buffer = Buffer.from(arrayBuffer); const buffer = Buffer.from(arrayBuffer);
logger.debug('Uploading to Minio', { logger.debug('Uploading to Minio', {
bucket: 'missions', bucket: MISSIONS_S3_CONFIG.bucket,
key: minioPath, key: minioPath,
contentType: file.type contentType: file.type
}); });
await s3Client.send(new PutObjectCommand({ await s3Client.send(new PutObjectCommand({
Bucket: 'missions', Bucket: MISSIONS_S3_CONFIG.bucket,
Key: minioPath, Key: minioPath,
Body: buffer, Body: buffer,
ContentType: file.type, ContentType: file.type,