Merge branch 'paritosh-main1' of http://git.wdipl.com/Mayank.Mishra/MinglarBackendNestJS into paritosh-main1
This commit is contained in:
@@ -1036,6 +1036,8 @@ model ActivityOtherDetails {
|
||||
activityXid Int @map("activity_xid")
|
||||
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||
exclusiveNotes String? @map("exclusive_notes") @db.VarChar(500)
|
||||
SafetyInstruction String? @map("safety_instruction") @db.VarChar(400)
|
||||
Cancellations String? @map("cancellations") @db.VarChar(400)
|
||||
dosNotes String? @map("dos_notes") @db.VarChar(400)
|
||||
dontsNotes String? @map("donts_notes") @db.VarChar(400)
|
||||
tipsNotes String? @map("tips_notes") @db.VarChar(400)
|
||||
@@ -1074,6 +1076,7 @@ model ActivitiesMedia {
|
||||
activity Activities @relation(fields: [activityXid], references: [id], onDelete: Cascade)
|
||||
mediaType String @map("media_type") @db.VarChar(30)
|
||||
mediaFileName String @map("media_file_name") @db.VarChar(400)
|
||||
isCoverImage Boolean @default(false) @map("is_cover_image")
|
||||
displayOrder Int @map("display_order")
|
||||
isActive Boolean @default(true) @map("is_active")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
@@ -4,6 +4,7 @@ import { z } from 'zod';
|
||||
export const MediaDto = z.object({
|
||||
mediaType: z.string().optional(),
|
||||
mediaFileName: z.string(),
|
||||
isCoverImage: z.boolean().optional().default(false),
|
||||
});
|
||||
|
||||
/* ================= PRICE ================= */
|
||||
@@ -85,10 +86,12 @@ export const EligibilityDto = z.object({
|
||||
/* ================= OTHER DETAILS ================= */
|
||||
export const OtherDetailsDto = z.object({
|
||||
exclusiveNotes: z.string().optional(),
|
||||
safetyInstruction: z.string().optional(),
|
||||
dosNotes: z.string().optional(),
|
||||
dontsNotes: z.string().optional(),
|
||||
tipsNotes: z.string().optional(),
|
||||
termsAndCondition: z.string().optional(),
|
||||
cancellations: z.string().optional(),
|
||||
});
|
||||
|
||||
/* ================= CREATE ACTIVITY ================= */
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import config from '../../../../../config/config';
|
||||
import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
|
||||
import { prismaClient } from '../../../../../common/database/prisma.lambda.service';
|
||||
import { verifyHostToken } from '../../../../../common/middlewares/jwt/authForHost';
|
||||
@@ -59,8 +58,23 @@ export const handler = safeHandler(
|
||||
activity.media = media.map((m: any) => ({
|
||||
mediaType: m.mediaType ?? 'image',
|
||||
mediaFileName: m.mediaFileName,
|
||||
isCoverImage: m.isCoverImage ?? false,
|
||||
}));
|
||||
|
||||
/* 4.1️⃣ ATTACH SAFETY INSTRUCTIONS (string only) */
|
||||
if (activity.safetyInstruction !== undefined && activity.safetyInstruction !== null) {
|
||||
if (typeof activity.safetyInstruction !== 'string') {
|
||||
throw new ApiError(400, 'safetyInstruction must be a string');
|
||||
}
|
||||
}
|
||||
|
||||
/* 4.2️⃣ ATTACH CANCELLATIONS (string only) */
|
||||
if (activity.cancellations !== undefined && activity.cancellations !== null) {
|
||||
if (typeof activity.cancellations !== 'string') {
|
||||
throw new ApiError(400, 'cancellations must be a string');
|
||||
}
|
||||
}
|
||||
|
||||
/* 5️⃣ VALIDATION */
|
||||
let parsedDto: CreateActivityInput;
|
||||
|
||||
|
||||
@@ -383,7 +383,9 @@ export class HostService {
|
||||
}
|
||||
|
||||
async verifyHostOtp(email: string, otp: string): Promise<boolean> {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
const trimmedOtp = (otp || '').toString().trim();
|
||||
|
||||
const user = await this.prisma.user.findFirst({
|
||||
where: { emailAddress: email, isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
@@ -410,7 +412,7 @@ export class HostService {
|
||||
throw new ApiError(400, 'OTP has expired.');
|
||||
}
|
||||
|
||||
const isMatch = await bcrypt.compare(otp, userOtp.otpCode);
|
||||
const isMatch = await bcrypt.compare(trimmedOtp, userOtp.otpCode);
|
||||
|
||||
if (!isMatch) {
|
||||
throw new ApiError(400, 'Invalid OTP.');
|
||||
@@ -2950,6 +2952,7 @@ export class HostService {
|
||||
activityXid,
|
||||
mediaType: m.mediaType ?? 'unknown',
|
||||
mediaFileName: m.mediaFileName,
|
||||
isCoverImage: m.isCoverImage ?? false,
|
||||
displayOrder: index + 1,
|
||||
})),
|
||||
});
|
||||
@@ -3498,6 +3501,22 @@ export class HostService {
|
||||
data: {
|
||||
activityXid,
|
||||
exclusiveNotes: payload.otherDetails.exclusiveNotes ?? null,
|
||||
SafetyInstruction: (() => {
|
||||
const s = payload.otherDetails.safetyInstruction ?? null;
|
||||
if (s === undefined || s === null) return null;
|
||||
if (typeof s !== 'string') {
|
||||
throw new ApiError(400, 'safetyInstruction must be a string');
|
||||
}
|
||||
return s;
|
||||
})(),
|
||||
Cancellations: (() => {
|
||||
const c = payload.otherDetails.cancellations ?? null;
|
||||
if (c === undefined || c === null) return null;
|
||||
if (typeof c !== 'string') {
|
||||
throw new ApiError(400, 'cancellations must be a string');
|
||||
}
|
||||
return c;
|
||||
})(),
|
||||
dosNotes: payload.otherDetails.dosNotes ?? null,
|
||||
dontsNotes: payload.otherDetails.dontsNotes ?? null,
|
||||
tipsNotes: payload.otherDetails.tipsNotes ?? null,
|
||||
|
||||
@@ -23,10 +23,9 @@ import {
|
||||
import { PaginationOptions } from '@/common/utils/pagination/pagination.types';
|
||||
import config from '@/config/config';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { User } from '@prisma/client';
|
||||
import { PrismaClient, User } from '@prisma/client';
|
||||
import * as bcrypt from 'bcryptjs';
|
||||
import { PrismaService } from '../../../common/database/prisma.service';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import ApiError from '../../../common/utils/helper/ApiError';
|
||||
import { CreateMinglarDto, UpdateMinglarDto } from '../dto/minglar.dto';
|
||||
import { sendAMEmailForHostAssign } from './AMEmail.service';
|
||||
@@ -154,8 +153,10 @@ export class MinglarService {
|
||||
}
|
||||
|
||||
async verifyHostOtp(email: string, otp: string): Promise<boolean> {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: { emailAddress: email },
|
||||
const trimmedOtp = (otp || '').toString().trim();
|
||||
|
||||
const user = await this.prisma.user.findFirst({
|
||||
where: { emailAddress: email, isActive: true },
|
||||
select: {
|
||||
id: true,
|
||||
emailAddress: true,
|
||||
@@ -181,7 +182,7 @@ export class MinglarService {
|
||||
throw new ApiError(400, 'OTP has expired.');
|
||||
}
|
||||
|
||||
const isMatch = await bcrypt.compare(otp, userOtp.otpCode);
|
||||
const isMatch = await bcrypt.compare(trimmedOtp, userOtp.otpCode);
|
||||
|
||||
if (!isMatch) {
|
||||
throw new ApiError(400, 'Invalid OTP.');
|
||||
|
||||
@@ -413,6 +413,8 @@ export class UserService {
|
||||
}
|
||||
|
||||
async verifyHostOtp(mobileNumber: string, otp: string): Promise<boolean> {
|
||||
const trimmedOtp = (otp || '').toString().trim();
|
||||
|
||||
const user = await this.prisma.user.findFirst({
|
||||
where: { mobileNumber: mobileNumber, isActive: true },
|
||||
select: {
|
||||
@@ -440,7 +442,7 @@ export class UserService {
|
||||
throw new ApiError(400, 'OTP has expired.');
|
||||
}
|
||||
|
||||
const isMatch = await bcrypt.compare(otp, userOtp.otpCode);
|
||||
const isMatch = await bcrypt.compare(trimmedOtp, userOtp.otpCode);
|
||||
|
||||
if (!isMatch) {
|
||||
throw new ApiError(400, 'Invalid OTP.');
|
||||
@@ -1896,6 +1898,39 @@ export class UserService {
|
||||
|
||||
const skip = (page - 1) * limit;
|
||||
|
||||
// 0️⃣ Get user's interests and map to activity types
|
||||
const userInterests = await this.prisma.userInterests.findMany({
|
||||
where: { userXid: userId, isActive: true },
|
||||
select: { interestXid: true },
|
||||
});
|
||||
|
||||
if (!userInterests.length) {
|
||||
return {
|
||||
page,
|
||||
limit,
|
||||
totalCount: 0,
|
||||
hasMore: false,
|
||||
activities: [],
|
||||
};
|
||||
}
|
||||
|
||||
const activityTypeIds = (
|
||||
await this.prisma.activityTypes.findMany({
|
||||
where: { interestXid: { in: userInterests.map((u) => u.interestXid) }, isActive: true },
|
||||
select: { id: true },
|
||||
})
|
||||
).map((t) => t.id);
|
||||
|
||||
if (!activityTypeIds.length) {
|
||||
return {
|
||||
page,
|
||||
limit,
|
||||
totalCount: 0,
|
||||
hasMore: false,
|
||||
activities: [],
|
||||
};
|
||||
}
|
||||
|
||||
// Rough bounding box in degrees to reduce DB scan
|
||||
const earthRadiusKm = 6371;
|
||||
const latDelta = (radiusKm / earthRadiusKm) * (180 / Math.PI);
|
||||
@@ -1908,6 +1943,7 @@ export class UserService {
|
||||
isActive: true,
|
||||
activityInternalStatus: ACTIVITY_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
amInternalStatus: ACTIVITY_AM_INTERNAL_STATUS.ACTIVITY_LISTED,
|
||||
activityTypeXid: { in: activityTypeIds },
|
||||
checkInLat: {
|
||||
not: null,
|
||||
gte: userLat - latDelta,
|
||||
|
||||
Reference in New Issue
Block a user