201 lines
6.5 KiB
TypeScript
201 lines
6.5 KiB
TypeScript
// modules/minglar/handlers/updateProfile.ts
|
|
import config from '../../../config/config';
|
|
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
|
|
import AWS from 'aws-sdk';
|
|
import { prismaClient } from '../../../common/database/prisma.lambda.service';
|
|
import { verifyMinglarAdminToken } from '../../../common/middlewares/jwt/authForMinglarAdmin';
|
|
import { safeHandler } from '../../../common/utils/handlers/safeHandler';
|
|
import ApiError from '../../../common/utils/helper/ApiError';
|
|
import { parseJsonField, parseMultipartFormData } from '../../../common/utils/helper/parseMultipartFormData';
|
|
import { MinglarService } from '../services/minglar.service';
|
|
|
|
const minglarService = new MinglarService(prismaClient);
|
|
|
|
const s3 = new AWS.S3({
|
|
region: config.aws.region,
|
|
});
|
|
|
|
// Define uploadToS3 function with proper folder structure and file replacement
|
|
async function uploadToS3(buffer: Buffer, mimeType: string, originalName: string, folderType: 'profile' | 'documents', userId: number, documentType?: string) {
|
|
let s3Key: string;
|
|
|
|
// Sanitize file name: remove special characters and spaces
|
|
const sanitizeFileName = (name: string) => {
|
|
return name
|
|
.toLowerCase()
|
|
.replace(/[^a-z0-9.]/g, '_') // Replace special characters with underscore
|
|
.replace(/_+/g, '_') // Replace multiple underscores with single
|
|
.replace(/^_+|_+$/g, ''); // Remove leading/trailing underscores
|
|
};
|
|
|
|
// Get file extension from original file name
|
|
const fileExtension = originalName.split('.').pop() || 'jpg';
|
|
|
|
// Determine folder structure based on type
|
|
if (folderType === 'profile') {
|
|
// Profile Images: MinglarAdmin/ProfileImages/{UserID}/profile_image.{extension}
|
|
const fileName = `profile_image.${fileExtension}`;
|
|
const sanitizedFileName = sanitizeFileName(fileName);
|
|
s3Key = `MinglarAdmin/ProfileImages/${userId}/${sanitizedFileName}`;
|
|
} else if (folderType === 'documents' && documentType) {
|
|
// Documents: MinglarAdmin/Documents/{UserID}/{documentType}.{extension}
|
|
const fileName = `${documentType}.${fileExtension}`;
|
|
const sanitizedFileName = sanitizeFileName(fileName);
|
|
s3Key = `MinglarAdmin/Documents/${userId}/${sanitizedFileName}`;
|
|
} else {
|
|
throw new ApiError(400, 'Invalid folder type or missing documentType');
|
|
}
|
|
|
|
// Upload new file (S3 will automatically replace if same key exists)
|
|
await s3
|
|
.upload({
|
|
Bucket: config.aws.bucketName,
|
|
Key: s3Key,
|
|
Body: buffer,
|
|
ContentType: mimeType,
|
|
ACL: 'private',
|
|
})
|
|
.promise();
|
|
|
|
console.log(`File uploaded successfully: ${s3Key}`);
|
|
return `https://${config.aws.bucketName}.s3.${config.aws.region}.amazonaws.com/${s3Key}`;
|
|
}
|
|
|
|
export const handler = safeHandler(async (
|
|
event: APIGatewayProxyEvent,
|
|
context?: Context
|
|
): Promise<APIGatewayProxyResult> => {
|
|
try {
|
|
// Extract token from headers
|
|
const token = event.headers['x-auth-token'] || event.headers['X-Auth-Token'];
|
|
if (!token) {
|
|
throw new ApiError(400, 'This is a protected route. Please provide a valid token.');
|
|
}
|
|
|
|
// Verify token and get user info
|
|
const userInfo = await verifyMinglarAdminToken(token);
|
|
const userId = Number(userInfo.id);
|
|
|
|
if (!userId || isNaN(userId)) {
|
|
throw new ApiError(400, 'Invalid user ID');
|
|
}
|
|
|
|
// Parse multipart form data
|
|
const contentType = event.headers['Content-Type'] || event.headers['content-type'];
|
|
const isBase64Encoded = event.isBase64Encoded || false;
|
|
|
|
const { fields, files } = parseMultipartFormData(
|
|
event.body,
|
|
contentType,
|
|
isBase64Encoded
|
|
);
|
|
|
|
// Parse JSON fields
|
|
const userData = parseJsonField(fields, 'userData') || {};
|
|
const addressData = parseJsonField(fields, 'addressData') || {};
|
|
|
|
// Extract user fields
|
|
const { firstName, lastName, mobileNumber, dateOfBirth, profileImage } = userData;
|
|
|
|
// Extract address fields
|
|
const { address1, address2, stateXid, countryXid, cityXid, pinCode } = addressData;
|
|
|
|
// Handle file uploads with proper folder structure and replacement
|
|
const uploadedFiles: Array<{ fileName: string; filePath: string; documentType?: string, documentTypeName?: string }> = [];
|
|
let profileImagePath: string | undefined = profileImage;
|
|
|
|
// Upload profile image if provided as file
|
|
const profileImageFile = files.find(f => f.fieldName === 'profileImage');
|
|
if (profileImageFile) {
|
|
profileImagePath = await uploadToS3(
|
|
profileImageFile.data,
|
|
profileImageFile.contentType,
|
|
profileImageFile.fileName,
|
|
'profile',
|
|
userId
|
|
);
|
|
console.log('Profile image uploaded:', profileImagePath);
|
|
}
|
|
|
|
// Upload documents (aadharCard, panCard) with proper naming and replacement
|
|
const aadharFile = files.find(f => f.fieldName === 'aadharCard');
|
|
const panFile = files.find(f => f.fieldName === 'panCard');
|
|
|
|
if (aadharFile) {
|
|
const filePath = await uploadToS3(
|
|
aadharFile.data,
|
|
aadharFile.contentType,
|
|
aadharFile.fileName,
|
|
'documents',
|
|
userId,
|
|
'aadhar'
|
|
);
|
|
uploadedFiles.push({
|
|
fileName: aadharFile.fileName,
|
|
filePath,
|
|
documentType: 'aadhar',
|
|
documentTypeName: 'aadhar'
|
|
});
|
|
console.log('Aadhar document uploaded:', filePath);
|
|
}
|
|
|
|
if (panFile) {
|
|
const filePath = await uploadToS3(
|
|
panFile.data,
|
|
panFile.contentType,
|
|
panFile.fileName,
|
|
'documents',
|
|
userId,
|
|
'pan'
|
|
);
|
|
uploadedFiles.push({
|
|
fileName: panFile.fileName,
|
|
filePath,
|
|
documentType: 'pan',
|
|
documentTypeName: 'pan'
|
|
});
|
|
console.log('PAN document uploaded:', filePath);
|
|
}
|
|
|
|
// Update profile using service
|
|
const result = await minglarService.updateProfile(
|
|
userId,
|
|
{
|
|
firstName,
|
|
lastName,
|
|
mobileNumber,
|
|
dateOfBirth,
|
|
profileImage: profileImagePath,
|
|
},
|
|
{
|
|
address1,
|
|
address2,
|
|
stateXid,
|
|
countryXid,
|
|
cityXid,
|
|
pinCode,
|
|
},
|
|
uploadedFiles.filter(f => f.documentType).map(f => ({
|
|
fileName: f.fileName,
|
|
filePath: f.filePath,
|
|
documentTypeName: f.documentTypeName,
|
|
}))
|
|
);
|
|
|
|
return {
|
|
statusCode: 200,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Access-Control-Allow-Origin': '*',
|
|
},
|
|
body: JSON.stringify({
|
|
success: true,
|
|
message: 'Profile updated successfully',
|
|
data: result,
|
|
}),
|
|
};
|
|
} catch (error: any) {
|
|
console.error('❌ Error in updateProfile:', error);
|
|
throw error;
|
|
}
|
|
}); |