import { s3Client, putObject, generatePresignedUrl, S3_CONFIG, deleteObject } from '@/lib/s3'; import { PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3'; import { getSignedUrl } from '@aws-sdk/s3-request-presigner'; /** * Utilities for mission-related file uploads using Minio */ // Generate the mission logo path in Minio export function getMissionLogoPath(userId: string, missionId: string, fileExtension: string): string { // Simplify path to match pages bucket structure return `${missionId}/logo${fileExtension}`; } // Generate the mission attachment path in Minio export function getMissionAttachmentPath(userId: string, missionId: string, filename: string): string { // Simplify path to match pages bucket structure return `${missionId}/attachments/${filename}`; } // Upload mission logo to Minio export async function uploadMissionLogo( userId: string, missionId: string, file: File ): Promise<{ filePath: string }> { try { console.log('=== Starting logo upload process ==='); console.log('Upload params:', { userId, missionId, fileName: file.name, fileSize: file.size, fileType: file.type }); // Get file extension const fileExtension = file.name.substring(file.name.lastIndexOf('.')); console.log('File extension:', fileExtension); // Create file path const filePath = getMissionLogoPath(userId, missionId, fileExtension); console.log('Generated file path:', filePath); // Convert file to ArrayBuffer console.log('Converting file to buffer...'); const arrayBuffer = await file.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); console.log('Buffer created, size:', buffer.length); // Upload to Minio using the pages bucket instead of missions bucket console.log('Creating S3 command with bucket:', S3_CONFIG.bucket); console.log('S3 config:', { endpoint: S3_CONFIG.endpoint || 'MISSING!', region: S3_CONFIG.region || 'MISSING!', bucket: S3_CONFIG.bucket || 'MISSING!', hasAccessKey: !!S3_CONFIG.accessKey || 'MISSING!', hasSecretKey: !!S3_CONFIG.secretKey || 'MISSING!' }); // Log the full path being used console.log('FULL S3 PATH:', `${S3_CONFIG.endpoint}/${S3_CONFIG.bucket}/${filePath}`); const command = new PutObjectCommand({ Bucket: S3_CONFIG.bucket, Key: filePath, Body: buffer, ContentType: file.type, // Add ACL for public read access ACL: 'public-read', }); console.log('Sending upload command to S3/Minio...'); console.log('Command details:', { Bucket: command.input.Bucket, Key: command.input.Key, ContentType: command.input.ContentType, ACL: command.input.ACL, ContentLength: buffer.length }); try { const result = await s3Client.send(command); console.log('Upload successful, result:', result); } catch (uploadError) { console.error('S3 upload error details:', uploadError); console.error('Error name:', (uploadError as any).name); console.error('Error message:', (uploadError as any).message); if ((uploadError as any).$metadata) { console.error('Error metadata:', (uploadError as any).$metadata); } throw uploadError; } console.log('Upload complete, returning file path:', filePath); return { filePath }; } catch (error) { console.error('Error uploading mission logo:', error); throw new Error('Failed to upload mission logo'); } } // Upload mission attachment to Minio export async function uploadMissionAttachment( userId: string, missionId: string, file: File ): Promise<{ filename: string, filePath: string, fileType: string, fileSize: number }> { try { console.log('=== Starting attachment upload process ==='); console.log('Upload params:', { userId, missionId, fileName: file.name, fileSize: file.size, fileType: file.type }); // Create file path const filePath = getMissionAttachmentPath(userId, missionId, file.name); console.log('Generated file path:', filePath); // Convert file to ArrayBuffer console.log('Converting file to buffer...'); const arrayBuffer = await file.arrayBuffer(); const buffer = Buffer.from(arrayBuffer); console.log('Buffer created, size:', buffer.length); // Log the full path being used console.log('FULL S3 PATH:', `${S3_CONFIG.endpoint}/${S3_CONFIG.bucket}/${filePath}`); // Upload to Minio using pages bucket const command = new PutObjectCommand({ Bucket: S3_CONFIG.bucket, Key: filePath, Body: buffer, ContentType: file.type, // Add ACL for public read access ACL: 'public-read', }); console.log('Sending upload command to S3/Minio...'); console.log('Command details:', { Bucket: command.input.Bucket, Key: command.input.Key, ContentType: command.input.ContentType, ACL: command.input.ACL, ContentLength: buffer.length }); try { const result = await s3Client.send(command); console.log('Upload successful, result:', result); } catch (uploadError) { console.error('S3 upload error details:', uploadError); console.error('Error name:', (uploadError as any).name); console.error('Error message:', (uploadError as any).message); if ((uploadError as any).$metadata) { console.error('Error metadata:', (uploadError as any).$metadata); } throw uploadError; } return { filename: file.name, filePath, fileType: file.type, fileSize: file.size, }; } catch (error) { console.error('Error uploading mission attachment:', error); throw new Error('Failed to upload mission attachment'); } } // Generate presigned URL for missions bucket async function generateMissionPresignedUrl(key: string, expiresIn = 3600): Promise { try { const command = new PutObjectCommand({ Bucket: S3_CONFIG.bucket, Key: key }); return await getSignedUrl(s3Client, command, { expiresIn }); } catch (error) { console.error('Error generating presigned URL for missions bucket:', error); throw error; } } // Generate presigned URL for direct browser upload of mission logo export async function generateMissionLogoUploadUrl( userId: string, missionId: string, fileExtension: string, expiresIn = 3600 ): Promise<{ uploadUrl: string, filePath: string }> { try { const filePath = getMissionLogoPath(userId, missionId, fileExtension); const uploadUrl = await generateMissionPresignedUrl(filePath, expiresIn); return { uploadUrl, filePath }; } catch (error) { console.error('Error generating mission logo upload URL:', error); throw new Error('Failed to generate upload URL for mission logo'); } } // Generate presigned URL for direct browser upload of mission attachment export async function generateMissionAttachmentUploadUrl( userId: string, missionId: string, filename: string, expiresIn = 3600 ): Promise<{ uploadUrl: string, filePath: string }> { try { const filePath = getMissionAttachmentPath(userId, missionId, filename); const uploadUrl = await generateMissionPresignedUrl(filePath, expiresIn); return { uploadUrl, filePath }; } catch (error) { console.error('Error generating mission attachment upload URL:', error); throw new Error('Failed to generate upload URL for mission attachment'); } } // Delete object from missions bucket async function deleteMissionObject(key: string): Promise { try { const command = new DeleteObjectCommand({ Bucket: S3_CONFIG.bucket, Key: key }); await s3Client.send(command); return true; } catch (error) { console.error('Error deleting mission object:', error); throw error; } } // Delete mission attachment from Minio export async function deleteMissionAttachment(filePath: string): Promise { try { await deleteMissionObject(filePath); return true; } catch (error) { console.error('Error deleting mission attachment:', error); throw new Error('Failed to delete mission attachment'); } } // Delete mission logo from Minio export async function deleteMissionLogo(filePath: string): Promise { try { await deleteMissionObject(filePath); return true; } catch (error) { console.error('Error deleting mission logo:', error); throw new Error('Failed to delete mission logo'); } }