Add getRandomActiveActivity API to fetch random active activities with token validation

This commit is contained in:
paritosh18
2026-02-23 12:05:52 +05:30
parent 81994d97ff
commit ca4def4695
3 changed files with 164 additions and 0 deletions

View File

@@ -301,4 +301,19 @@ viewMoreActivitiesByInterest:
events:
- httpApi:
path: /user/activities/view-more-activities
method: get
getRandomActiveActivity:
handler: src/modules/user/handlers/activities/getRandomActiveActivity.handler
memorySize: 384
package:
patterns:
- 'src/modules/user/handlers/activities/**'
- ${file(./serverless/patterns/base.yml):pattern1}
- ${file(./serverless/patterns/base.yml):pattern2}
- ${file(./serverless/patterns/base.yml):pattern3}
- ${file(./serverless/patterns/base.yml):pattern4}
events:
- httpApi:
path: /user/activities/get-random-active-activity
method: get

View File

@@ -0,0 +1,59 @@
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from 'aws-lambda';
import { safeHandler } from '../../../../common/utils/handlers/safeHandler';
import { prismaClient } from '../../../../common/database/prisma.lambda.service';
import ApiError from '../../../../common/utils/helper/ApiError';
import { UserService } from '../../services/user.service';
import { verifyUserToken } from '../../../../common/middlewares/jwt/authForUser';
const userService = new UserService(prismaClient);
export const handler = safeHandler(async (
event: APIGatewayProxyEvent,
context?: Context
): Promise<APIGatewayProxyResult> => {
// 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 verifyUserToken(token);
const userId = Number(userInfo.id);
if (!userId || Number.isNaN(userId)) {
throw new ApiError(400, 'Invalid user ID');
}
// Fetch 50 random active activities
const result = await userService.getRandomActiveActivity();
if (!result || result.length === 0) {
return {
statusCode: 404,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
success: false,
message: 'No active activities found',
data: [],
}),
};
}
return {
statusCode: 200,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
body: JSON.stringify({
success: true,
message: 'Random active activities retrieved successfully',
data: result,
count: result.length,
}),
};
});

View File

@@ -2616,4 +2616,94 @@ export class UserService {
return true;
}
async getRandomActiveActivity() {
return await this.prisma.$transaction(async (tx) => {
// Get count of active activities
const count = await tx.activities.count({
where: {
isActive: true,
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
deletedAt: null,
},
});
if (count === 0) {
return [];
}
// Determine how many activities to fetch (50 or less if count is smaller)
const takeCount = Math.min(50, count);
// Fetch random activities - using ORDER BY RANDOM() equivalent approach
// Get all IDs first, shuffle, then take 50
const allActivityIds = await tx.activities.findMany({
where: {
isActive: true,
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
deletedAt: null,
},
select: { id: true },
});
// Shuffle array and take first 50
const shuffled = allActivityIds.sort(() => Math.random() - 0.5);
const selectedIds = shuffled.slice(0, takeCount).map(a => a.id);
// Fetch activities with only activityTitle and ActivitiesMedia
const activities = await tx.activities.findMany({
where: {
id: { in: selectedIds },
isActive: true,
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
deletedAt: null,
},
select: {
id: true,
activityTitle: true,
ActivitiesMedia: {
where: {
isActive: true,
},
select: {
id: true,
mediaFileName: true,
mediaType: true,
},
orderBy: {
displayOrder: 'asc', // Get the first image by display order
},
take: 1, // Get only the first image
},
},
});
// Process activities to attach presigned URLs and format response
const result = await Promise.all(
activities.map(async (activity) => {
let activityImage = null;
let activityImagePresignedUrl = null;
// Get the first image and attach presigned URL
if (Array.isArray(activity.ActivitiesMedia) && activity.ActivitiesMedia.length > 0) {
const firstImage = activity.ActivitiesMedia[0];
activityImage = firstImage.mediaFileName;
activityImagePresignedUrl = await attachPresignedUrl(firstImage.mediaFileName);
}
return {
id: activity.id,
activityName: activity.activityTitle,
activityImage: activityImage,
activityImagePresignedUrl: activityImagePresignedUrl,
};
})
);
return result;
});
}
}