From 558cb214c0c5ca442a1f11c5e71d1712b7a946ed Mon Sep 17 00:00:00 2001 From: paritosh18 Date: Mon, 2 Feb 2026 17:09:42 +0530 Subject: [PATCH] feat: add setUserLocationDetails functionality and corresponding API endpoint --- serverless/functions/user.yml | 15 +++ .../authentication/SetLocationofUser.ts | 92 +++++++++++++++++++ src/modules/user/services/user.service.ts | 83 ++++++++++++++++- 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 src/modules/user/handlers/authentication/SetLocationofUser.ts diff --git a/serverless/functions/user.yml b/serverless/functions/user.yml index ec5a4a7..fad4ae4 100644 --- a/serverless/functions/user.yml +++ b/serverless/functions/user.yml @@ -75,4 +75,19 @@ setUserInterest: events: - httpApi: path: /user/set-interests + method: post + +setUserLocationss: + handler: src/modules/user/handlers/authentication/SetLocationofUser.handler + memorySize: 384 + package: + patterns: + - 'src/modules/user/**' + - ${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/set-location-user method: post \ No newline at end of file diff --git a/src/modules/user/handlers/authentication/SetLocationofUser.ts b/src/modules/user/handlers/authentication/SetLocationofUser.ts new file mode 100644 index 0000000..f5619be --- /dev/null +++ b/src/modules/user/handlers/authentication/SetLocationofUser.ts @@ -0,0 +1,92 @@ +import { + APIGatewayProxyEvent, + APIGatewayProxyResult, + Context, +} from 'aws-lambda'; +import { prismaClient } from '../../../../common/database/prisma.lambda.service'; +import { verifyUserToken } from '../../../../common/middlewares/jwt/authForUser'; +import { safeHandler } from '../../../../common/utils/handlers/safeHandler'; +import ApiError from '../../../../common/utils/helper/ApiError'; +import { UserService } from '../../services/user.service'; + +const userService = new UserService(prismaClient); + +export const handler = safeHandler( + async ( + event: APIGatewayProxyEvent, + context?: Context, + ): Promise => { + // 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.', + ); + } + + // Authenticate user using verifyUserToken + const userInfo = await verifyUserToken(token); + const userId = userInfo.id; + + if (Number.isNaN(userId)) { + throw new ApiError(400, 'User id must be a number'); + } + + const user = await userService.getUserById(userId); + if (!user) { + throw new ApiError(404, 'User not found'); + } + + // Parse request body + let body: { + countryName?: string; + stateName?: string; + cityName?: string; + pinCode?: string; + latitude?: number; + longitude?: number; + locationName?: string; + locationAddress?: string; + }; + + try { + body = event.body ? JSON.parse(event.body) : {}; + } catch (error) { + throw new ApiError(400, 'Invalid JSON in request body'); + } + + const { countryName, stateName, cityName, pinCode, latitude, longitude, locationName, locationAddress } = body; + + // Validate required fields + if (!countryName || !stateName || !cityName) { + throw new ApiError(400, 'Country name, state name, and city name are required'); + } + + // Set the location details + await userService.setUserLocationDetails( + userId, + countryName, + stateName, + cityName, + pinCode, + latitude, + longitude, + locationName, + locationAddress, + ); + + return { + statusCode: 200, + headers: { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*', + }, + body: JSON.stringify({ + success: true, + message: 'Location details set successfully', + }), + }; + }, +); diff --git a/src/modules/user/services/user.service.ts b/src/modules/user/services/user.service.ts index 5ce217c..311c849 100644 --- a/src/modules/user/services/user.service.ts +++ b/src/modules/user/services/user.service.ts @@ -1,8 +1,9 @@ import { Injectable } from '@nestjs/common'; -import { PrismaClient, User } from '@prisma/client'; +import { PrismaClient, User, UserAddressDetails } from '@prisma/client'; import ApiError from '@/common/utils/helper/ApiError'; import * as bcrypt from 'bcryptjs'; import { UserPersonalInfoSchema } from '@/common/utils/validation/user/addPersonalInfo.validation'; +import { create } from 'domain'; @Injectable() export class UserService { constructor(private prisma: PrismaClient) { } @@ -139,4 +140,84 @@ export class UserService { }); } + async setUserLocationDetails( + userId: number, + countryName: string, + stateName: string, + cityName: string, + pinCode: string, + latitude?: number, + longitude?: number, + locationName?: string, + locationAddress?: string + ): Promise { + return this.prisma.$transaction(async (tx) => { + + // 1️⃣ Country: find or create + let country = await tx.countries.findUnique({ + where: { countryName }, + select: { id: true }, + }); + + if (!country) { + country = await tx.countries.create({ + data: { + countryName, + countryCode: countryName.slice(0, 3).toUpperCase(), + countryFlag: '', + }, + select: { id: true }, + }); + } + + // 2️⃣ State: find or create (GLOBAL UNIQUE) + let state = await tx.states.findUnique({ + where: { stateName }, + select: { id: true }, + }); + + if (!state) { + state = await tx.states.create({ + data: { + stateName, + countryXid: country.id, + }, + select: { id: true }, + }); + } + + // 3️⃣ City: find or create (GLOBAL UNIQUE) + let city = await tx.cities.findUnique({ + where: { cityName }, + select: { id: true }, + }); + + if (!city) { + city = await tx.cities.create({ + data: { + cityName, + stateXid: state.id, + }, + select: { id: true }, + }); + } + + // 4️⃣ Update user address + return tx.userAddressDetails.update({ + where: { id: userId }, + data: { + countryXid: country.id, + stateXid: state.id, + cityXid: city.id, + pinCode, + locationName: locationName ?? null, + locationAddress: locationAddress ?? null, + locationLat: latitude ?? null, + locationLong: longitude ?? null, + }, + }); + }); + } + + } \ No newline at end of file