Sending the presigned url for activity media and venue artifacts

This commit is contained in:
2025-12-24 11:50:13 +05:30
parent bf16a31ae6
commit 60ee1f5f21
2 changed files with 103 additions and 41 deletions

View File

@@ -186,23 +186,17 @@ export const handler = safeHandler(
const uploadedActivityMedia: Array<{ mediaType?: string; mediaFileName: string }> = [];
for (const file of files.filter(
(f) => f.fieldName === 'activityImages' || f.fieldName === 'activityVideos',
(f) => f.fieldName === 'images' || f.fieldName === 'videos'
)) {
const s3Key = `ActivityOnboarding/Activity_${activityPayload.activityXid}/Media/${Date.now()}_${file.fileName}`;
if (s3Key.length > 900) {
throw new ApiError(400, 'Generated S3 key too long');
}
await s3
.upload({
await s3.upload({
Bucket: config.aws.bucketName,
Key: s3Key,
Body: file.buffer,
ContentType: file.mimeType,
ACL: 'private',
})
.promise();
}).promise();
uploadedActivityMedia.push({
mediaType: file.mimeType,
@@ -210,6 +204,7 @@ export const handler = safeHandler(
});
}
/* 🔥 MERGE ACTIVITY MEDIA */
const existingMedia = Array.isArray(activityPayload.media)
? activityPayload.media
@@ -218,19 +213,21 @@ export const handler = safeHandler(
/* 9⃣ PROCESS VENUE MEDIA UPLOADS */
// Group venue files by index: venueImages[0], venueImages[1], etc.
const venueFilesMap: Map<number, Array<{ buffer: Buffer; mimeType: string; fileName: string }>> = new Map();
const venueFilesMap = new Map<number, typeof files>();
for (const file of files) {
// Match patterns like: venueImages[0], venueVideos[1], etc.
const match = file.fieldName.match(/^venue(Images|Videos)\[(\d+)\]$/);
if (match) {
const venueIndex = parseInt(match[2], 10);
const match = file.fieldName.match(/^venueFiles(\d+)$/);
if (!match) continue;
const venueIndex = Number(match[1]);
if (!venueFilesMap.has(venueIndex)) {
venueFilesMap.set(venueIndex, []);
}
venueFilesMap.get(venueIndex)!.push(file);
}
}
// Upload venue files and attach to corresponding venues
if (Array.isArray(activityPayload.venues)) {
@@ -238,24 +235,18 @@ export const handler = safeHandler(
const venue = activityPayload.venues[i];
const venueFiles = venueFilesMap.get(i) || [];
const uploadedVenueMedia: Array<{ mediaType?: string; mediaFileName: string }> = [];
const uploadedVenueMedia = [];
for (const file of venueFiles) {
const s3Key = `ActivityOnboarding/Activity_${activityPayload.activityXid}/Venue_${i}/Media/${Date.now()}_${file.fileName}`;
if (s3Key.length > 900) {
throw new ApiError(400, 'Generated S3 key too long for venue media');
}
await s3
.upload({
await s3.upload({
Bucket: config.aws.bucketName,
Key: s3Key,
Body: file.buffer,
ContentType: file.mimeType,
ACL: 'private',
})
.promise();
}).promise();
uploadedVenueMedia.push({
mediaType: file.mimeType,
@@ -263,12 +254,11 @@ export const handler = safeHandler(
});
}
// Merge with existing venue media
const existingVenueMedia = Array.isArray(venue.media) ? venue.media : [];
venue.media = [...existingVenueMedia, ...uploadedVenueMedia];
venue.media = [...(venue.media || []), ...uploadedVenueMedia];
}
}
/* 🔟 VALIDATION */
let parsedDto: CreateActivityInput;

View File

@@ -1704,7 +1704,7 @@ export class HostService {
}
async getAllDetailsOfActivityAndVenue(activityXid: number) {
return await this.prisma.activities.findMany({
const activity = await this.prisma.activities.findFirst({
where: { id: activityXid, isActive: true },
select: {
id: true,
@@ -1728,6 +1728,38 @@ export class HostService {
activityTypeName: true,
}
},
ActivitiesMedia: {
where: {
isActive: true
},
select: {
id: true,
mediaType: true,
mediaFileName: true,
}
},
ActivityVenues: {
where: {
isActive: true
},
select: {
id: true,
venueName: true,
venueCapacity: true,
availableSeats: true,
isMinPeopleReqMandatory: true,
minPeopleRequired: true,
minReqfullfilledBeforeMins: true,
venueDescription: true,
ActivityVenueArtifacts: {
select: {
id: true,
mediaType: true,
mediaFileName: true
}
}
}
},
ActivityPickUpDetails: {
where: {
isActive: true,
@@ -1936,6 +1968,46 @@ export class HostService {
}
})
if (!activity) {
throw new ApiError(404, 'Activity not found');
}
if (Array.isArray(activity.ActivitiesMedia)) {
for (const media of activity.ActivitiesMedia) {
if (!media?.mediaFileName) continue;
const filePath = media.mediaFileName;
// ✅ Robust S3 key extraction
const key = filePath.startsWith('http')
? new URL(filePath).pathname.replace(/^\/+/, '')
: filePath;
(media as any).presignedUrl = await getPresignedUrl(bucket, key);
}
}
if (Array.isArray(activity.ActivityVenues)) {
for (const venue of activity.ActivityVenues) {
if (!Array.isArray(venue.ActivityVenueArtifacts)) continue;
for (const artifact of venue.ActivityVenueArtifacts) {
if (!artifact?.mediaFileName) continue;
const filePath = artifact.mediaFileName;
// ✅ Robust S3 key extraction
const key = filePath.startsWith('http')
? new URL(filePath).pathname.replace(/^\/+/, '')
: filePath;
(artifact as any).preSignedURL = await getPresignedUrl(bucket, key);
}
}
}
return activity;
}
async createActivity(