diff --git a/bruno/MVEP/address/Create Address.bru b/bruno/MVEP/address/Create Address.bru new file mode 100644 index 0000000..4e75d0c --- /dev/null +++ b/bruno/MVEP/address/Create Address.bru @@ -0,0 +1,29 @@ +meta { + name: Create Address + type: http + seq: 2 +} + +post { + url: {{url}}address + body: json + auth: none +} + +body:json { + { + "createdBy":"668ff65c49d6d8547222578b", + "name":"Home", + "doorNo":"4-176/1", + "email":"test@gmail.com", + "phone":"76599645868", + "street":"4th street", + "city":"Malikipuram", + "state":"Andhra Pradhes", + "zip":"533253", + "isDefault":true, + "additionalInstructions":"PLease be fast enough", + "coordinates":["-127.256","124.256"] + + } +} diff --git a/bruno/MVEP/address/Delete Address.bru b/bruno/MVEP/address/Delete Address.bru new file mode 100644 index 0000000..d23791b --- /dev/null +++ b/bruno/MVEP/address/Delete Address.bru @@ -0,0 +1,11 @@ +meta { + name: Delete Address + type: http + seq: 5 +} + +delete { + url: {{url}}address/6690e093df3fbfdb92fedf72 + body: none + auth: none +} diff --git a/bruno/MVEP/address/Get Users Address.bru b/bruno/MVEP/address/Get Users Address.bru new file mode 100644 index 0000000..e269b7e --- /dev/null +++ b/bruno/MVEP/address/Get Users Address.bru @@ -0,0 +1,11 @@ +meta { + name: Get Users Address + type: http + seq: 6 +} + +get { + url: {{url}}address/user/668ff65c49d6d8547222578b + body: none + auth: none +} diff --git a/bruno/MVEP/address/Get address by Id.bru b/bruno/MVEP/address/Get address by Id.bru new file mode 100644 index 0000000..0ea393d --- /dev/null +++ b/bruno/MVEP/address/Get address by Id.bru @@ -0,0 +1,11 @@ +meta { + name: Get address by Id + type: http + seq: 3 +} + +get { + url: {{url}}address/6690e26784b3e646dae86bb9 + body: none + auth: none +} diff --git a/bruno/MVEP/address/Get all address.bru b/bruno/MVEP/address/Get all address.bru new file mode 100644 index 0000000..871384c --- /dev/null +++ b/bruno/MVEP/address/Get all address.bru @@ -0,0 +1,11 @@ +meta { + name: Get all address + type: http + seq: 1 +} + +get { + url: {{url}}address + body: none + auth: none +} diff --git a/bruno/MVEP/address/Get user Default Address.bru b/bruno/MVEP/address/Get user Default Address.bru new file mode 100644 index 0000000..35b39c8 --- /dev/null +++ b/bruno/MVEP/address/Get user Default Address.bru @@ -0,0 +1,11 @@ +meta { + name: Get user Default Address + type: http + seq: 7 +} + +get { + url: {{url}}address/default/668ff65c49d6d8547222578b + body: none + auth: none +} diff --git a/bruno/MVEP/address/Update Address By Id.bru b/bruno/MVEP/address/Update Address By Id.bru new file mode 100644 index 0000000..2ec9a67 --- /dev/null +++ b/bruno/MVEP/address/Update Address By Id.bru @@ -0,0 +1,19 @@ +meta { + name: Update Address By Id + type: http + seq: 4 +} + +put { + url: {{url}}address/6690d45f8102ba5718734c86 + body: json + auth: none +} + +body:json { + { + "state":"Andhra Pradesh", + "zip":"533453", + "isDefault":true + } +} diff --git a/bruno/MVEP/sudo-users/login.bru b/bruno/MVEP/sudo-users/login.bru index add149c..986d12f 100644 --- a/bruno/MVEP/sudo-users/login.bru +++ b/bruno/MVEP/sudo-users/login.bru @@ -12,7 +12,7 @@ post { body:json { { - "email" : "eswarmamidi19@gmail.com", - "password" : "eswar@4321" + "email" : "root@gmail.com", + "password" : "password" } } diff --git a/bruno/MVEP/users/deleteUserById.bru b/bruno/MVEP/users/deleteUserById.bru new file mode 100644 index 0000000..535a7ce --- /dev/null +++ b/bruno/MVEP/users/deleteUserById.bru @@ -0,0 +1,11 @@ +meta { + name: deleteUserById + type: http + seq: 6 +} + +delete { + url: {{url}}user/66758b9891f947ae7f4f5f34 + body: none + auth: none +} diff --git a/bruno/MVEP/users/forgot-password.bru b/bruno/MVEP/users/forgot-password.bru new file mode 100644 index 0000000..e2d9a6c --- /dev/null +++ b/bruno/MVEP/users/forgot-password.bru @@ -0,0 +1,17 @@ +meta { + name: forgot-password + type: http + seq: 7 +} + +post { + url: {{url}}user/forgot-password + body: json + auth: none +} + +body:json { + { + "email":"testingclass@gmail.com" + } +} diff --git a/bruno/MVEP/users/get all users.bru b/bruno/MVEP/users/get all users.bru new file mode 100644 index 0000000..43dca2f --- /dev/null +++ b/bruno/MVEP/users/get all users.bru @@ -0,0 +1,11 @@ +meta { + name: get all users + type: http + seq: 2 +} + +get { + url: {{url}}user + body: none + auth: none +} diff --git a/bruno/MVEP/users/getUserById.bru b/bruno/MVEP/users/getUserById.bru new file mode 100644 index 0000000..6db385e --- /dev/null +++ b/bruno/MVEP/users/getUserById.bru @@ -0,0 +1,11 @@ +meta { + name: getUserById + type: http + seq: 4 +} + +get { + url: {{url}}user/668ff65c49d6d8547222578b + body: none + auth: none +} diff --git a/bruno/MVEP/users/login.bru b/bruno/MVEP/users/login.bru new file mode 100644 index 0000000..425a61c --- /dev/null +++ b/bruno/MVEP/users/login.bru @@ -0,0 +1,18 @@ +meta { + name: login + type: http + seq: 1 +} + +post { + url: {{url}}user/login + body: json + auth: none +} + +body:json { + { + "email":"testingclass@gmail.com", + "password":"123" + } +} diff --git a/bruno/MVEP/users/logout.bru b/bruno/MVEP/users/logout.bru new file mode 100644 index 0000000..98ab15e --- /dev/null +++ b/bruno/MVEP/users/logout.bru @@ -0,0 +1,11 @@ +meta { + name: logout + type: http + seq: 3 +} + +post { + url: {{url}}user/logout + body: none + auth: none +} diff --git a/bruno/MVEP/users/reset-password.bru b/bruno/MVEP/users/reset-password.bru new file mode 100644 index 0000000..ae68edf --- /dev/null +++ b/bruno/MVEP/users/reset-password.bru @@ -0,0 +1,19 @@ +meta { + name: reset-password + type: http + seq: 8 +} + +post { + url: {{url}}user/reset-password + body: json + auth: none +} + +body:json { + { + "token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NjhmZjY1YzQ5ZDZkODU0NzIyMjU3OGIiLCJpYXQiOjE3MjA3NjU5MTUsImV4cCI6MTcyMDc2NjUxNX0.2vG4IRRW6df3WhdMksu92CSqAWgiBE2UpG3cNQuM7Eg", + "password":"123", + "verify_password":"123" + } +} diff --git a/bruno/MVEP/users/updateUserById.bru b/bruno/MVEP/users/updateUserById.bru new file mode 100644 index 0000000..897ef17 --- /dev/null +++ b/bruno/MVEP/users/updateUserById.bru @@ -0,0 +1,22 @@ +meta { + name: updateUserById + type: http + seq: 5 +} + +put { + url: {{url}}user/66758b9891f947ae7f4f5f34 + body: json + auth: none +} + +body:json { + { + "cart":[ + { + "itemName":"IphoneX", + "price":"20000" + } + ] + } +} diff --git a/src/index.ts b/src/index.ts index 23fa6c2..a821cb4 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,12 +1,13 @@ import App from "./app"; +import UserAddressController from "./resources/Address/address-controller"; import RegionController from "./resources/Regions/region-controller"; import SudouserController from "./resources/Sudouser/sudouser-controller"; import UserController from "./resources/User/user-controller"; import { Controller } from "./utils/interfaces/controller-interface"; -import {config} from "dotenv"; +import { config } from "dotenv"; -config(); +config(); -const controllers :Controller[] =[new SudouserController() , new RegionController(),new UserController]; -const app = new App(controllers , Number(process.env.PORT)); +const controllers: Controller[] = [new SudouserController(), new RegionController(), new UserController, new UserAddressController]; +const app = new App(controllers, Number(process.env.PORT)); app.listen(); diff --git a/src/middleware/forgot-middleware.ts b/src/middleware/forgot-middleware.ts index ac09de3..134643a 100644 --- a/src/middleware/forgot-middleware.ts +++ b/src/middleware/forgot-middleware.ts @@ -1,14 +1,14 @@ -import jwt from "jsonwebtoken" -import { Request, Response, NextFunction } from "express-serve-static-core" +import { NextFunction, Request, Response } from "express-serve-static-core"; +import jwt from "jsonwebtoken"; export const verifyPasswordReset = async (req: Request, res: Response, next: NextFunction) => { try { - const { token } = req.params; + const { token } = req.body; if (!token) { return res.status(401).json({ message: "UnAuthorized" }); } - await jwt.verify(token, process.env.JWT_SECRET!, (err, decoded) => { + jwt.verify(token, process.env.JWT_SECRET!, (err:any, decoded:any) => { if (err) { if (err.name === 'TokenExpiredError') { return res.status(401).send({ error: "Token has expired" }); diff --git a/src/middleware/permissions-middleware.ts b/src/middleware/permissions-middleware.ts index 5a0261f..ce0868c 100644 --- a/src/middleware/permissions-middleware.ts +++ b/src/middleware/permissions-middleware.ts @@ -6,7 +6,7 @@ export const verifySuperAdmin = expressAsyncHandler( async (req: Request, res: Response, next: NextFunction) => { const loggedInSudoUser = await SudoUser.findById(req.loggedInSudoUserId); if (!loggedInSudoUser) { - res.json(400); + res.status(400); throw new Error("Sudo user is not logged in"); } if (loggedInSudoUser?.role !== 1) { diff --git a/src/resources/Address/address-controller.ts b/src/resources/Address/address-controller.ts new file mode 100644 index 0000000..1336ea5 --- /dev/null +++ b/src/resources/Address/address-controller.ts @@ -0,0 +1,232 @@ +import { Router } from "express"; +import expressAsyncHandler from "express-async-handler"; +import { Request, Response } from "express-serve-static-core"; +import { Controller } from "../../utils/interfaces/controller-interface"; +import { verifyAuthOrSudo } from "./address-middleware"; +import Address from "./address-model"; +import User from "../User/user-model"; + + +export default class UserAddressController implements Controller { + router: Router = Router(); + path: string = "address"; + + constructor() { + this.initializeRoutes(); + } + + private initializeRoutes(): void { + this.router.get('/', verifyAuthOrSudo, this.getAllAddress) + this.router.get('/:id', verifyAuthOrSudo, this.getAddressById) + this.router.get('/user/:id', verifyAuthOrSudo, this.getUserAddressesById) + this.router.get('/default/:id', verifyAuthOrSudo, this.getUserDefaultAddress) + this.router.post('/', verifyAuthOrSudo, this.createAddress) + this.router.put('/:id', verifyAuthOrSudo, this.updateAddress) + this.router.delete('/:id', verifyAuthOrSudo, this.deleteAddress) + } + + private getAllAddress = expressAsyncHandler( + async (req: Request, res: Response) => { + const allAddresses = await Address.find(); + res.status(200); + res.json({ + result: { + data: allAddresses + } + }) + } + + ) + + private getAddressById = expressAsyncHandler( + async (req: Request, res: Response) => { + const ID = req.params?.id; + if (!ID) { + res.status(400); + throw new Error("Address ID required"); + } + const fetchedAddress = await Address.findById(ID); + if (!fetchedAddress) { + res.status(404); + throw new Error("No Address Found"); + } + res.status(200).send( + { + results: { + data: fetchedAddress + } + } + ) + } + ) + + private getUserAddressesById = expressAsyncHandler( + async (req: Request, res: Response) => { + const ID = req.params?.id; + if (!ID) { + res.status(400); + throw new Error("User ID required"); + } + const isUserExists = await User.findById(ID); + if (!isUserExists) { + res.status(404); + throw new Error("No User Found"); + } + const userAddresses = await Address.find({ createdBy: ID }); + if (!userAddresses) { + res.status(404); + throw new Error('No User Address Found'); + } + res.status(200).send( + { + results: { + data: userAddresses + } + } + ) + } + ) + + private getUserDefaultAddress = expressAsyncHandler( + async (req: Request, res: Response) => { + const ID = req.params?.id; + if (!ID) { + res.status(400); + throw new Error("User ID required"); + } + const userAddresses = await Address.find({ createdBy: ID, isDefault: true }); + if (!userAddresses) { + res.status(404); + throw new Error('No User Address Found'); + } + res.status(200).send( + { + results: { + data: userAddresses + } + } + ) + } + ) + private createAddress = expressAsyncHandler( + async (req: Request, res: Response) => { + const { createdBy, isDefault, name, email, phone, doorNo, street, city, state, zip, additionalInstructions, coordinates } = req.body; + + if (!createdBy || !name || !doorNo || !street || !city || !state || !zip || !coordinates) { + res.status(400); + throw new Error("Missing required fields"); + } + + const newAddress = new Address({ + createdBy, + isDefault: isDefault ?? false, + name, + contact: { + email, + phone + }, + address: { + doorNo, + street, + city, + state, + zip, + location: { + coordinates + } + }, + additionalInstructions + }); + + const savedAddress = await newAddress.save(); + + if (!savedAddress) { + res.status(500); + throw new Error("New Address Creation Failed"); + } + + res.status(201).json({ + address_id: newAddress._id, + created: true + }); + return; + } + ) + + private updateAddress = expressAsyncHandler( + async (req: Request, res: Response) => { + const id = req.params?.id; + if (!id) { + res.status(400); + throw new Error("Address ID required"); + } + const address = await Address.findById(id); + if (!address) { + res.status(400); + throw new Error("No Address Found"); + } + + if (req.body.isDefault !== undefined) address.isDefault = req.body.isDefault; + if (req.body.name !== undefined) address.name = req.body.name; + if (req.body.email !== undefined) address.contact.email = req.body.email; + if (req.body.phone !== undefined) address.contact.phone = req.body.phone; + + if (req.body.doorNo !== undefined) address.address.doorNo = req.body.doorNo; + if (req.body.street !== undefined) address.address.street = req.body.street; + if (req.body.city !== undefined) address.address.city = req.body.city; + if (req.body.state !== undefined) address.address.state = req.body.state; + if (req.body.zip !== undefined) address.address.zip = req.body.zip; + if (req.body.coordinates !== undefined) address.address.location.coordinates = req.body.coordinates; + + if (req.body.additionalInstructions !== undefined) { + address.additionalInstructions = req.body.additionalInstructions; + } + if (req.body.additionalInstructions !== undefined) { + address.additionalInstructions = req.body.additionalInstructions; + } + + const updatedAddress = await address.save(); + if (!updatedAddress) { + res.status(500) + throw new Error('Update Failed'); + } + res.status(200).send({ + result: { + addressId: updatedAddress._id, + updated: true + } + }) + return; + + } + ) + + private deleteAddress = expressAsyncHandler( + async (req: Request, res: Response) => { + const id = req.params?.id; + if (!id) { + res.status(400); + throw new Error("Address ID required"); + } + const address = await Address.findById(id); + + if (!address) { + res.status(400); + throw new Error("No Address Found"); + } + + const deletedAddress = await address?.deleteOne(); + if (!deletedAddress) { + res.status(500); + throw new Error('Unable to delete Address'); + } + res.status(200).json({ + result: { + addressId: address._id, + deleted: true + } + }) + } + ) + +} diff --git a/src/resources/Address/address-interface.ts b/src/resources/Address/address-interface.ts new file mode 100644 index 0000000..28a4e63 --- /dev/null +++ b/src/resources/Address/address-interface.ts @@ -0,0 +1,30 @@ +import { JwtPayload } from "jsonwebtoken"; +import mongoose, { Document } from "mongoose"; + +interface Location { + type: string; + coordinates: [number, number]; +} + +interface Address { + doorNo: string; + street: string; + city: string; + state: string; + zip: string; + location: Location; +} + +interface Contact { + email: string; + phone: string; +} + +export interface UserAddress extends Document { + createdBy: mongoose.Schema.Types.ObjectId; + isDefault: boolean; + name: string; + contact: Contact; + address: Address; + additionalInstructions: string; +} diff --git a/src/resources/Address/address-middleware.ts b/src/resources/Address/address-middleware.ts new file mode 100644 index 0000000..8a1660f --- /dev/null +++ b/src/resources/Address/address-middleware.ts @@ -0,0 +1,36 @@ +import { Request, Response, NextFunction } from "express-serve-static-core"; +import expressAsyncHandler from "express-async-handler"; +import SudoUser from "../Sudouser/sudouser-model"; +import jwt, { JwtPayload } from "jsonwebtoken" + +export const verifyAuthOrSudo = expressAsyncHandler( + async (req: Request, res: Response, next: NextFunction) => { + try { + const token = req.cookies?.user_token; + const sudoToken = req.cookies?.sudo_user_auth_jwt; + if (token) { + const user = jwt.verify(token, process.env.JWT_SECRET!); + req.user = user as string; + return next(); + } + if (sudoToken) { + const decoded = jwt.verify( + sudoToken, + process.env.JWT_SECRET! + ) as JwtPayload; + req.loggedInSudoUserId = decoded.userId as string; + const loggedInSudoUser = await SudoUser.findById(req.loggedInSudoUserId); + if (loggedInSudoUser?.role !== 1) { + res.status(403).json({ message: "Not authorized" }); + return; + } + return next(); + } + res.status(401).json({ message: "UnAuthorized" }); + return; + + } catch (err) { + res.status(400).json({ message: "Invalid or expired token" }); + } + } +); diff --git a/src/resources/Address/address-model.ts b/src/resources/Address/address-model.ts new file mode 100644 index 0000000..13b884d --- /dev/null +++ b/src/resources/Address/address-model.ts @@ -0,0 +1,53 @@ +import mongoose, { CallbackError } from "mongoose" +import { UserAddress } from "./address-interface" +import User from "../User/user-model"; + +export const addressSchema = new mongoose.Schema({ + createdBy: { + type: mongoose.Schema.Types.ObjectId, + ref: "User", + required: true + }, + isDefault: { + type: Boolean, + default: false + }, + name: { + type: String, + required: true + }, + contact: { + email: String, + phone: String, + }, + address: { + doorNo: String, + street: String, + city: String, + state: String, + zip: String, + location: { + type: { + type: String, + default: 'Point' + }, + coordinates: [Number], + } + }, + additionalInstructions: { + type:String + } + +}, { collection: "addresses", timestamps: true }) + +addressSchema.post('save', async function (doc, next) { + try { + await User.findByIdAndUpdate(doc.createdBy, { $push: { addresses: doc._id } }); + next(); + } catch (error) { + next(error as CallbackError); + } +}); +const Address = mongoose.model('Address', addressSchema); + +export default Address; diff --git a/src/resources/User/user-controller.ts b/src/resources/User/user-controller.ts index c9037c6..b298eee 100644 --- a/src/resources/User/user-controller.ts +++ b/src/resources/User/user-controller.ts @@ -9,6 +9,8 @@ import { sendForgotPasswordMail } from "../../services/email-service"; import { verifyAuth } from "./user-middleware"; import { verifyPasswordReset } from "../../middleware/forgot-middleware"; import { verifySuperAdmin } from "../../middleware/permissions-middleware"; +import { sudouserProtectMiddleWare } from "../Sudouser/sudouser-middleware"; +import bcrypt from "bcrypt" export default class UserController implements Controller { router: Router = Router(); @@ -19,7 +21,7 @@ export default class UserController implements Controller { } private initializeRoutes(): void { - this.router.get('/', verifySuperAdmin,this.getAllUsers) + this.router.get('/', sudouserProtectMiddleWare, verifySuperAdmin,this.getAllUsers) this.router.get('/:id', this.getUserById) this.router.post('/', this.createUser) this.router.put('/:id', verifyAuth, this.updateUser) @@ -27,7 +29,7 @@ export default class UserController implements Controller { this.router.post('/login', this.loginUser) this.router.post('/logout', verifyAuth, this.logoutUser) this.router.post('/forgot-password', this.forgotPassword) - this.router.post('/reset-password/:token', verifyPasswordReset, this.changePassword) + this.router.post('/reset-password', verifyPasswordReset, this.changePassword) } private getAllUsers = expressAsyncHandler( @@ -175,7 +177,7 @@ export default class UserController implements Controller { private logoutUser = expressAsyncHandler( async (_, res: Response): Promise => { - res.clearCookie('token', { + res.clearCookie('user_token', { httpOnly: true, sameSite: 'strict' }).status(200).send({ result: { 'message': 'Logout Successfull' } }) @@ -219,8 +221,9 @@ export default class UserController implements Controller { throw new Error("Please re verify the password"); } const userId = decoded.userId; + const hashedPassword = await bcrypt.hash(password,10); const user = await User.findByIdAndUpdate(userId, { - password: password, + password: hashedPassword, }); res.json({ data: { diff --git a/src/resources/User/user-model.ts b/src/resources/User/user-model.ts index 29f525b..09b8321 100644 --- a/src/resources/User/user-model.ts +++ b/src/resources/User/user-model.ts @@ -29,7 +29,8 @@ const userSchema = new mongoose.Schema({ default: [] }, addresses: { - type: [{}], + type: [mongoose.Schema.Types.ObjectId], + ref:'Address', default: [] }, createdAt: {