From e8fcaf0687d9af37545e02ae6ae8a4e4dc85a293 Mon Sep 17 00:00:00 2001 From: Youssef Yasser Date: Tue, 5 Nov 2024 11:40:33 +0200 Subject: [PATCH 1/2] feat: implement book itinerary endpoint - create booking schema - add itinerary_bookings attribute to user schema --- backend/src/controllers/booking.controller.ts | 29 +++++++++++++++++++ backend/src/database/models/booking.model.ts | 28 ++++++++++++++++++ backend/src/database/models/user.model.ts | 3 ++ .../src/database/repositories/booking.repo.ts | 13 +++++++++ backend/src/routes/itinerary.route.ts | 3 ++ backend/src/types/User.types.ts | 3 ++ 6 files changed, 79 insertions(+) create mode 100644 backend/src/controllers/booking.controller.ts create mode 100644 backend/src/database/models/booking.model.ts create mode 100644 backend/src/database/repositories/booking.repo.ts diff --git a/backend/src/controllers/booking.controller.ts b/backend/src/controllers/booking.controller.ts new file mode 100644 index 0000000..4da95ac --- /dev/null +++ b/backend/src/controllers/booking.controller.ts @@ -0,0 +1,29 @@ +import { Request, Response } from 'express'; +import { ResponseStatusCodes } from '../types/ResponseStatusCodes.types'; +import { logger } from '../middlewares/logger.middleware'; +import Validator from '../utils/Validator.utils'; +import bookingRepo from '../database/repositories/booking.repo'; + +class BookingController { + async bookItinerary(req: Request, res: Response) { + try { + Validator.validateId(req.body.itinerary_id, 'incorrect itinerary id'); + + const booking = await bookingRepo.bookItinerary(req.user.userId, req.body.itinerary_id); + + const response = { + message: 'Booking successful', + data: { booking: booking }, + }; + + res.status(ResponseStatusCodes.CREATED).send(response); + } catch (error: any) { + logger.error(`Error occurred while booking itinerary: ${error.message}`); + res.status(ResponseStatusCodes.INTERNAL_SERVER_ERROR).send({ + message: `Error occurred while booking itinerary: ${error.message}`, + }); + } + } +} + +export default new BookingController(); diff --git a/backend/src/database/models/booking.model.ts b/backend/src/database/models/booking.model.ts new file mode 100644 index 0000000..770ac14 --- /dev/null +++ b/backend/src/database/models/booking.model.ts @@ -0,0 +1,28 @@ +import { model, Schema } from 'mongoose'; + +const bookingSchema = new Schema( + { + user: { + type: Schema.Types.ObjectId, + ref: 'user', + required: true, + }, + itinerary: { + type: Schema.Types.ObjectId, + ref: 'itinerary', + unique: true, + }, + status: { + type: String, + enum: ['pending', 'confirmed', 'attended', 'cancelled'], + default: 'pending', + }, + }, + { + timestamps: true, + } +); + +const Booking = model('booking', bookingSchema); + +export { bookingSchema, Booking }; diff --git a/backend/src/database/models/user.model.ts b/backend/src/database/models/user.model.ts index 1a9a013..f8f0648 100644 --- a/backend/src/database/models/user.model.ts +++ b/backend/src/database/models/user.model.ts @@ -82,6 +82,9 @@ const userSchema = new mongoose.Schema( average_rating: { type: Number, }, + itinerary_bookings: { + type: [{ type: Schema.Types.ObjectId, ref: 'booking' }], + }, modified_by: { type: Schema.Types.ObjectId, ref: 'user', diff --git a/backend/src/database/repositories/booking.repo.ts b/backend/src/database/repositories/booking.repo.ts new file mode 100644 index 0000000..3396c5a --- /dev/null +++ b/backend/src/database/repositories/booking.repo.ts @@ -0,0 +1,13 @@ +import { Booking } from '../models/booking.model'; +import { User } from '../models/user.model'; + +class BookingRepo { + async bookItinerary(userId: string, itineraryId: string) { + const booking = await Booking.create({ user: userId, itinerary: itineraryId }); + await User.findByIdAndUpdate(userId, { $push: { itinerary_bookings: booking._id } }); + + return booking; + } +} + +export default new BookingRepo(); diff --git a/backend/src/routes/itinerary.route.ts b/backend/src/routes/itinerary.route.ts index 6db40a6..5de56fb 100644 --- a/backend/src/routes/itinerary.route.ts +++ b/backend/src/routes/itinerary.route.ts @@ -10,9 +10,12 @@ import { toggleItineraryActive, flagItinerary, } from '../controllers/itinerary.controller'; +import BookingController from '../controllers/booking.controller'; const itineraryRouter = Router(); +itineraryRouter.post('/bookings', BookingController.bookItinerary); + itineraryRouter.get('/get', getItineraries); itineraryRouter.get('/mine', getItinerariesCreatedByUser); itineraryRouter.get('/:id', findItineraryById); diff --git a/backend/src/types/User.types.ts b/backend/src/types/User.types.ts index 70ca860..5b612f3 100644 --- a/backend/src/types/User.types.ts +++ b/backend/src/types/User.types.ts @@ -1,3 +1,5 @@ +import { Types } from 'mongoose'; + export enum accountType { Admin = 'Admin', Tourist = 'Tourist', @@ -35,4 +37,5 @@ export interface UserType { // Tourist loyalty_points: number; wallet?: number; + itinerary_bookings: [Types.ObjectId]; } From 8cbfbcb13a09617da7cd16f8107315ebdee652ba Mon Sep 17 00:00:00 2001 From: Youssef Yasser Date: Tue, 5 Nov 2024 12:41:40 +0200 Subject: [PATCH 2/2] feat: implement book activities endpoint --- backend/src/controllers/booking.controller.ts | 20 +++++++++++++++++++ backend/src/database/models/booking.model.ts | 5 ++++- backend/src/database/models/user.model.ts | 3 +++ .../src/database/repositories/booking.repo.ts | 7 +++++++ backend/src/routes/activity.route.ts | 3 +++ 5 files changed, 37 insertions(+), 1 deletion(-) diff --git a/backend/src/controllers/booking.controller.ts b/backend/src/controllers/booking.controller.ts index 4da95ac..ca66af1 100644 --- a/backend/src/controllers/booking.controller.ts +++ b/backend/src/controllers/booking.controller.ts @@ -24,6 +24,26 @@ class BookingController { }); } } + + async bookActivity(req: Request, res: Response) { + try { + Validator.validateId(req.body.activity_id, 'incorrect activity id'); + + const booking = await bookingRepo.bookActivity(req.user.userId, req.body.activity_id); + + const response = { + message: 'Booking successful', + data: { booking: booking }, + }; + + res.status(ResponseStatusCodes.CREATED).send(response); + } catch (error: any) { + logger.error(`Error occurred while booking activity: ${error.message}`); + res.status(ResponseStatusCodes.INTERNAL_SERVER_ERROR).send({ + message: `Error occurred while booking activity: ${error.message}`, + }); + } + } } export default new BookingController(); diff --git a/backend/src/database/models/booking.model.ts b/backend/src/database/models/booking.model.ts index 770ac14..aa30c4c 100644 --- a/backend/src/database/models/booking.model.ts +++ b/backend/src/database/models/booking.model.ts @@ -10,7 +10,10 @@ const bookingSchema = new Schema( itinerary: { type: Schema.Types.ObjectId, ref: 'itinerary', - unique: true, + }, + activity: { + type: Schema.Types.ObjectId, + ref: 'activity', }, status: { type: String, diff --git a/backend/src/database/models/user.model.ts b/backend/src/database/models/user.model.ts index f8f0648..6302848 100644 --- a/backend/src/database/models/user.model.ts +++ b/backend/src/database/models/user.model.ts @@ -85,6 +85,9 @@ const userSchema = new mongoose.Schema( itinerary_bookings: { type: [{ type: Schema.Types.ObjectId, ref: 'booking' }], }, + activity_bookings: { + type: [{ type: Schema.Types.ObjectId, ref: 'booking' }], + }, modified_by: { type: Schema.Types.ObjectId, ref: 'user', diff --git a/backend/src/database/repositories/booking.repo.ts b/backend/src/database/repositories/booking.repo.ts index 3396c5a..4f6b20e 100644 --- a/backend/src/database/repositories/booking.repo.ts +++ b/backend/src/database/repositories/booking.repo.ts @@ -8,6 +8,13 @@ class BookingRepo { return booking; } + + async bookActivity(userId: string, activityId: string) { + const booking = await Booking.create({ user: userId, activity: activityId }); + await User.findByIdAndUpdate(userId, { $push: { activity_bookings: booking._id } }); + + return booking; + } } export default new BookingRepo(); diff --git a/backend/src/routes/activity.route.ts b/backend/src/routes/activity.route.ts index f736bdc..47a993d 100644 --- a/backend/src/routes/activity.route.ts +++ b/backend/src/routes/activity.route.ts @@ -7,9 +7,12 @@ import { createActivity, getActivitiesByCreator, } from '../controllers/activity.controller'; +import BookingController from '../controllers/booking.controller'; const activityRouter = Router(); +activityRouter.post('/bookings', BookingController.bookActivity); + activityRouter.get('/', getAllActivities); activityRouter.get('/mine', getActivitiesByCreator); activityRouter.get('/:id', getActivityById);