262 lines
8.4 KiB
TypeScript
262 lines
8.4 KiB
TypeScript
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 {
|
|
// Use a consistent path structure: missions/{missionId}/logo{extension}
|
|
return `missions/${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<string> {
|
|
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<boolean> {
|
|
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<boolean> {
|
|
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<boolean> {
|
|
try {
|
|
await deleteMissionObject(filePath);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Error deleting mission logo:', error);
|
|
throw new Error('Failed to delete mission logo');
|
|
}
|
|
}
|