Files
MinglarBackendNestJS/src/modules/host/handlers/mediaUploadToS3.ts

99 lines
2.8 KiB
TypeScript

import { APIGatewayProxyHandler } from 'aws-lambda';
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { v4 as uuid } from 'uuid';
import { prismaClient } from '../../../common/database/prisma.lambda.service';
import { HostService } from '../services/host.service';
import ApiError from '../../../common/utils/helper/ApiError';
import config from '../../../config/config';
import { verifyHostToken } from '../../../common/middlewares/jwt/authForHost';
const s3 = new S3Client({ region: config.aws.region });
const hostService = new HostService(prismaClient);
export const handler: APIGatewayProxyHandler = async (event) => {
try {
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
if (!token) throw new ApiError(401, 'Missing token.');
await verifyHostToken(token);
const body = JSON.parse(event.body || '{}');
const { files } = body;
if (!Array.isArray(files) || files.length === 0) {
throw new ApiError(400, 'files array is required');
}
const activityXid = event.pathParameters?.activityXid;
if (!activityXid) {
throw new ApiError(400, 'activityXid is required in path parameters');
}
const activityDetails = await hostService.getActivityDetailsById(Number(activityXid));
if (!activityDetails) {
throw new ApiError(404, 'Activity not found');
}
const results = [];
for (const file of files) {
const { fileName, mimeType } = file;
if (!fileName || !mimeType) {
throw new ApiError(400, 'Each file must have fileName and mimeType');
}
const safeFileName = fileName
.trim()
.replace(/\s+/g, '_')
.replace(/[^a-zA-Z0-9._-]/g, '')
.toLowerCase();
const key = `ActivityOnboarding/Activity_${activityXid}/Artifacts/${uuid()}_${safeFileName}`;
const command = new PutObjectCommand({
Bucket: config.aws.bucketName!,
Key: key,
ContentType: mimeType,
});
const uploadUrl = await getSignedUrl(s3, command, {
expiresIn: 300,
});
results.push({
uploadUrl,
key,
fileUrl: `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/${key}`,
});
}
return response(200, { files: results });
} catch (err: any) {
console.error('ERROR:', err);
// If it's your ApiError, return its status & message
if (err instanceof ApiError) {
return response(err.statusCode, err.message);
}
// Fallback for unknown errors
return response(500, 'Internal server error');
}
};
function response(statusCode: number, body: any) {
return {
statusCode,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify(body),
};
}