From 75062520fdf604751cfabfeba2ec68edb3135d10 Mon Sep 17 00:00:00 2001 From: Abdelrahman Mohammed Date: Sat, 5 Oct 2024 21:59:08 +0300 Subject: [PATCH 1/2] feat: minor fixes and updates to models/references - fix schema references - email no longer required - add created_by to all - fix repos that search for tags to populate (not sure how that worked to begin with ngl) - refactoring --- backend/src/database/models/activity.model.ts | 77 ++++++---- .../src/database/models/attachment.model.ts | 31 ++-- .../src/database/models/itinerary.model.ts | 105 +++++++------ backend/src/database/models/museum.model.ts | 87 ++++++----- backend/src/database/models/product.model.ts | 79 +++++----- backend/src/database/models/review.model.ts | 49 ++++--- backend/src/database/models/tag.model.ts | 41 ++++-- backend/src/database/models/user.model.ts | 138 +++++++++--------- .../database/repositories/activity.repo.ts | 4 - .../database/repositories/attachment.repo.ts | 8 +- .../database/repositories/itinerary.repo.ts | 14 +- .../src/database/repositories/museum.repo.ts | 4 - .../src/database/repositories/product.repo.ts | 1 - backend/src/types/Attachment.types.ts | 1 - backend/src/types/Itinerary.types.ts | 2 +- backend/src/types/Museum.types.ts | 3 +- 16 files changed, 354 insertions(+), 290 deletions(-) diff --git a/backend/src/database/models/activity.model.ts b/backend/src/database/models/activity.model.ts index 1ea59f2..8f2a5a1 100644 --- a/backend/src/database/models/activity.model.ts +++ b/backend/src/database/models/activity.model.ts @@ -4,39 +4,52 @@ import { ActivityType } from '../../types/Activity.types'; import { ValidationException } from '../../exceptions/ValidationException'; import { getTagIds } from './tag.model'; -const activitySchema = new Schema({ - date: { - type: Date, - required: true, +const activitySchema = new Schema( + { + date: { + type: Date, + required: true, + }, + time: { + type: String, + required: true, + }, + location: { + type: locationSchema, + required: true, + }, + price: { + type: Number, + required: true, + min: 0, + }, + category: { + type: String, + required: true, + }, + tags: { + type: [{ type: Schema.Types.ObjectId, ref: 'tag' }], + }, + specialDiscounts: { + type: String, + }, + bookingOpen: { + type: Boolean, + required: true, + }, + created_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, + modified_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, }, - time: { - type: String, - required: true, - }, - location: { - type: locationSchema, - required: true, - }, - price: { - type: Number, - required: true, - min: 0, - }, - category: { - type: String, - required: true, - }, - tags: { - type: [{ type: Schema.Types.ObjectId, ref: 'tag' }], - }, - specialDiscounts: { - type: String, - }, - bookingOpen: { - type: Boolean, - required: true, - }, -}); + { + timestamps: true, + } +); async function getActivityIds(activitiesData: ActivityType[]): Promise { const activityIds: ActivityType[] = []; diff --git a/backend/src/database/models/attachment.model.ts b/backend/src/database/models/attachment.model.ts index 5793440..c57edcf 100644 --- a/backend/src/database/models/attachment.model.ts +++ b/backend/src/database/models/attachment.model.ts @@ -1,19 +1,24 @@ import { Schema, model } from 'mongoose'; -const attachmentSchema = new Schema({ - original_name: { - type: String, - required: true, +const attachmentSchema = new Schema( + { + original_name: { + type: String, + required: true, + }, + url: { + type: String, + required: true, + }, + created_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, }, - url: { - type: String, - required: true, - }, - timestamp: { - type: Date, - default: Date.now, - }, -}); + { + timestamps: true, + } +); const Attachment = model('attachment', attachmentSchema); diff --git a/backend/src/database/models/itinerary.model.ts b/backend/src/database/models/itinerary.model.ts index 2724e6f..00f48b1 100644 --- a/backend/src/database/models/itinerary.model.ts +++ b/backend/src/database/models/itinerary.model.ts @@ -1,53 +1,66 @@ import { Schema, model } from 'mongoose'; import { locationSchema } from './location.model'; -const itinerarySchema = new Schema({ - name: { - type: String, - required: true, +const itinerarySchema = new Schema( + { + name: { + type: String, + required: true, + }, + category: { + type: String, + required: true, + }, + tags: { + type: [{ type: Schema.Types.ObjectId, ref: 'tag' }], + }, + activities: { + type: [{ activity: { type: Schema.Types.ObjectId, ref: 'activity' }, duration: Number }], + }, + locations: { + type: [locationSchema], + }, + timeline: { + type: String, + }, + language: { + type: String, + required: true, + }, + price: { + type: Number, + required: true, + min: 0, + }, + available_datetimes: { + type: [Date], + required: true, + }, + accessibility: { + type: Boolean, + required: true, + }, + pick_up_location: { + type: locationSchema, + required: true, + }, + drop_off_location: { + type: locationSchema, + required: true, + }, + created_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, + modified_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, }, - category: { - type: String, - required: true, - }, - tags: { - type: [{ type: Schema.Types.ObjectId, ref: 'tag' }], - }, - activities: { - type: [{ type: Schema.Types.ObjectId, ref: 'activity' }], - }, - locations: { - type: [locationSchema], - }, - timeline: { - type: String, - }, - language: { - type: String, - required: true, - }, - price: { - type: Number, - required: true, - min: 0, - }, - available_datetimes: { - type: [Date], - required: true, - }, - accessibility: { - type: Boolean, - required: true, - }, - pick_up_location: { - type: locationSchema, - required: true, - }, - drop_off_location: { - type: locationSchema, - required: true, - }, -}); + { + timestamps: true, + } +); const Itinerary = model('itinerary', itinerarySchema); diff --git a/backend/src/database/models/museum.model.ts b/backend/src/database/models/museum.model.ts index ff43e8a..b516df7 100644 --- a/backend/src/database/models/museum.model.ts +++ b/backend/src/database/models/museum.model.ts @@ -1,49 +1,62 @@ import { Schema, model } from 'mongoose'; import { locationSchema } from './location.model'; -const museumSchema = new Schema({ - name: { - type: String, - required: true, - }, - tags: { - type: [{ type: Schema.Types.ObjectId, ref: 'tag' }], - }, - description: { - type: String, - required: true, - }, - category: { - type: String, - required: true, - }, - pictures: { - type: [String], - }, - location: { - type: locationSchema, - }, - opening_hours: { - type: String, - required: true, - }, - ticket_prices: { - foreigner: { - type: Number, +const museumSchema = new Schema( + { + name: { + type: String, required: true, - min: 0, }, - native: { - type: Number, + tags: { + type: [{ type: Schema.Types.ObjectId, ref: 'tag' }], + }, + description: { + type: String, required: true, - min: 0, }, - student: { - type: Number, + category: { + type: String, required: true, - min: 0, + }, + pictures: { + type: [{ type: Schema.Types.ObjectId, ref: 'attachment' }], + }, + location: { + type: locationSchema, + }, + opening_hours: { + type: String, + required: true, + }, + ticket_prices: { + foreigner: { + type: Number, + required: true, + min: 0, + }, + native: { + type: Number, + required: true, + min: 0, + }, + student: { + type: Number, + required: true, + min: 0, + }, + }, + created_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, + modified_by: { + type: Schema.Types.ObjectId, + ref: 'user', }, }, -}); + { + timestamps: true, + } +); export const Museum = model('museum', museumSchema); diff --git a/backend/src/database/models/product.model.ts b/backend/src/database/models/product.model.ts index ff69d3f..f39937f 100644 --- a/backend/src/database/models/product.model.ts +++ b/backend/src/database/models/product.model.ts @@ -1,42 +1,49 @@ import { Schema, model } from 'mongoose'; -import { attachmentSchema } from './attachment.model'; import { reviewSchema } from './review.model'; -const productSchema = new Schema({ - name: { - type: String, - required: true, - }, - description: { - type: String, - required: true, - }, - price: { - type: Number, - }, - available_quantity: { - type: Number, - }, - attachments: { - type: [attachmentSchema], - required: true, - }, - reviews: { - type: [reviewSchema], - }, - seller: { - type: Schema.Types.ObjectId, - ref: 'user', - required: true, - }, - tags: { - type: [{ type: Schema.Types.ObjectId, ref: 'tag' }], - }, - timestamp: { - type: Date, - default: Date.now, - }, -}); +const productSchema = new Schema( + { + name: { + type: String, + required: true, + }, + description: { + type: String, + required: true, + }, + price: { + type: Number, + }, + available_quantity: { + type: Number, + }, + attachments: { + type: [{ type: Schema.Types.ObjectId, ref: 'attachment' }], + }, + reviews: { + type: [reviewSchema], + }, + seller: { + type: Schema.Types.ObjectId, + ref: 'user', + required: true, + }, + tags: { + type: [{ type: Schema.Types.ObjectId, ref: 'tag' }], + }, + created_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, + modified_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, + }, + { + timestamps: true, + } +); export const Product = model('product', productSchema); diff --git a/backend/src/database/models/review.model.ts b/backend/src/database/models/review.model.ts index 88484ef..cf7c6a3 100644 --- a/backend/src/database/models/review.model.ts +++ b/backend/src/database/models/review.model.ts @@ -1,26 +1,35 @@ import { Schema, model } from 'mongoose'; -const reviewSchema = new Schema({ - user: { - type: Schema.Types.ObjectId, - ref: 'user', - required: true, +const reviewSchema = new Schema( + { + user: { + type: Schema.Types.ObjectId, + ref: 'user', + required: true, + }, + rating: { + type: Number, + required: true, + min: 1, + max: 5, + }, + comment: { + type: String, + required: true, + }, + created_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, + modified_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, }, - rating: { - type: Number, - required: true, - min: 1, - max: 5, - }, - comment: { - type: String, - required: true, - }, - timestamp: { - type: Date, - default: Date.now, - }, -}); + { + timestamps: true, + } +); const Review = model('review', reviewSchema); diff --git a/backend/src/database/models/tag.model.ts b/backend/src/database/models/tag.model.ts index 9202708..f0a783c 100644 --- a/backend/src/database/models/tag.model.ts +++ b/backend/src/database/models/tag.model.ts @@ -2,21 +2,34 @@ import { Schema, model } from 'mongoose'; import { TagType, type } from '../../types/Tag.types'; import { ValidationException } from '../../exceptions/ValidationException'; -const tagSchema = new Schema({ - name: { - type: String, - required: true, +const tagSchema = new Schema( + { + name: { + type: String, + required: true, + }, + type: { + type: String, + enum: Object.values(type), + required: true, + }, + historical_period: { + type: String, + required: true, + }, + created_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, + modified_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, }, - type: { - type: String, - enum: Object.values(type), - required: true, - }, - historical_period: { - type: String, - required: true, - }, -}); + { + timestamps: true, + } +); async function getTagIds(tagsData: TagType[]): Promise { const tagIds: TagType[] = []; diff --git a/backend/src/database/models/user.model.ts b/backend/src/database/models/user.model.ts index 5c7f6bc..6968459 100644 --- a/backend/src/database/models/user.model.ts +++ b/backend/src/database/models/user.model.ts @@ -1,72 +1,80 @@ import mongoose from 'mongoose'; +import { Schema, model } from 'mongoose'; import bcrypt from 'bcrypt'; -import { attachmentSchema } from './attachment.model'; import { accountType } from '../../types/User.types'; -const userSchema = new mongoose.Schema({ - account_type: { - type: String, - enum: Object.values(accountType), - required: true, - }, - accepted: { - type: Boolean, - required: true, - default: false, - }, - email: { - type: String, - required: true, - unique: true, - }, - username: { - type: String, - required: true, - }, - password: { - type: String, - required: true, - }, - mobile_number: { - type: String, - }, - nationality: { - type: String, - }, - dob: { - type: Date, - }, - job: { - type: String, - }, - years_of_experience: { - type: Number, - }, - previous_work: { - type: String, - }, - website: { - type: String, - }, - hotline: { - type: String, - }, - company_profile: { - type: String, - }, - name: { - type: String, - }, - description: { - type: String, - }, - wallet: { - type: Number, - }, - profile_pic: { - type: attachmentSchema, - }, -}); +const userSchema = new mongoose.Schema( + { + account_type: { + type: String, + enum: Object.values(accountType), + required: true, + }, + accepted: { + type: Boolean, + required: true, + default: false, + }, + email: { + type: String, + unique: true, + }, + username: { + type: String, + required: true, + }, + password: { + type: String, + required: true, + }, + mobile_number: { + type: String, + }, + nationality: { + type: String, + }, + dob: { + type: Date, + }, + job: { + type: String, + }, + years_of_experience: { + type: Number, + }, + previous_work: { + type: String, + }, + website: { + type: String, + }, + hotline: { + type: String, + }, + company_profile: { + type: String, + }, + name: { + type: String, + }, + description: { + type: String, + }, + wallet: { + type: Number, + }, + profile_pic: { + type: { type: Schema.Types.ObjectId, ref: 'attachment' }, + }, + modified_by: { + type: Schema.Types.ObjectId, + ref: 'user', + }, + }, + { + timestamps: true, + } +); userSchema.pre('save', function (next) { var user = this; diff --git a/backend/src/database/repositories/activity.repo.ts b/backend/src/database/repositories/activity.repo.ts index 922bcdb..9e4f2c3 100644 --- a/backend/src/database/repositories/activity.repo.ts +++ b/backend/src/database/repositories/activity.repo.ts @@ -11,15 +11,11 @@ class ActivityRepo { } async createActivity(activity: ActivityType) { - const tagIds = await getTagIds(activity.tags); - activity.tags = tagIds; return await Activity.create(activity); } async updateActivity(id: string, activity: ActivityType) { Validator.validateId(id, 'Invalid activity ID'); - const tagIds = await getTagIds(activity.tags); - activity.tags = tagIds; return await Activity.findByIdAndUpdate(id, activity); } diff --git a/backend/src/database/repositories/attachment.repo.ts b/backend/src/database/repositories/attachment.repo.ts index c57dffa..8b98c29 100644 --- a/backend/src/database/repositories/attachment.repo.ts +++ b/backend/src/database/repositories/attachment.repo.ts @@ -4,12 +4,12 @@ import { Attachment } from '../models/attachment.model'; import { AttachmentType } from '../../types/Attachment.types'; class AttachmentRepo { - async findAttachmentById(id: string): Promise { + async findAttachmentById(id: string) { Validator.validateId(id, 'Invalid attachment ID'); return await Attachment.findOne({ _id: new ObjectId(id) }); } - async createAttachment(attachment: any): Promise { + async createAttachment(attachment: any) { return await Attachment.create(attachment); } @@ -17,6 +17,10 @@ class AttachmentRepo { Validator.validateId(id, 'Invalid attachment ID'); return await Attachment.deleteOne({ _id: new ObjectId(id) }); } + + async deleteAttachments(ids: string[]) { + return await Attachment.deleteMany({ _id: { $in: ids.map((id) => new ObjectId(id)) } }); + } } export default new AttachmentRepo(); diff --git a/backend/src/database/repositories/itinerary.repo.ts b/backend/src/database/repositories/itinerary.repo.ts index 4cd0b8a..210cafb 100644 --- a/backend/src/database/repositories/itinerary.repo.ts +++ b/backend/src/database/repositories/itinerary.repo.ts @@ -1,35 +1,25 @@ import { ObjectId } from 'mongodb'; import { Itinerary } from '../models/itinerary.model'; -import { getTagIds } from '../models/tag.model'; import { ItineraryType } from '../../types/Itinerary.types'; import Validator from '../../utils/Validator.utils'; -import { getActivityIds } from '../models/activity.model'; class ItineraryRepo { async getItineraries(attributeName?: string, attributeValue?: RegExp | string) { const query = attributeName && attributeValue ? { [attributeName]: attributeValue } : {}; - return await Itinerary.find(query).populate(['tags', 'activities']); + return await Itinerary.find(query).populate(['tags', 'activities.activity']); } async findItineraryById(id: string) { Validator.validateId(id, 'Invalid itinerary ID'); - return await Itinerary.findById(id).populate(['tags', 'activities']); + return await Itinerary.findById(id).populate(['tags', 'activities.activity']); } async createItinerary(itinerary: ItineraryType) { - const tagIds = await getTagIds(itinerary.tags); - const activityIds = await getActivityIds(itinerary.activities); - itinerary.tags = tagIds; - itinerary.activities = activityIds; return await Itinerary.create(itinerary); } async updateItinerary(id: string, itinerary: ItineraryType) { Validator.validateId(id, 'Invalid itinerary ID'); - const tagIds = await getTagIds(itinerary.tags); - const activityIds = await getActivityIds(itinerary.activities); - itinerary.tags = tagIds; - itinerary.activities = activityIds; return await Itinerary.findByIdAndUpdate(id, itinerary); } diff --git a/backend/src/database/repositories/museum.repo.ts b/backend/src/database/repositories/museum.repo.ts index 37b17c4..af6286b 100644 --- a/backend/src/database/repositories/museum.repo.ts +++ b/backend/src/database/repositories/museum.repo.ts @@ -19,16 +19,12 @@ class MuseumRepo { } async createMuseum(museum: MuseumType) { - const tagIds = await getTagIds(museum.tags); - museum.tags = tagIds; const museumRes = await Museum.create(museum); return museumRes; } async updateMuseum(id: string, museum: MuseumType) { Validator.validateId(id, 'Invalid museum ID'); - const tagIds = await getTagIds(museum.tags); - museum.tags = tagIds; return await Museum.findByIdAndUpdate(id, museum); } diff --git a/backend/src/database/repositories/product.repo.ts b/backend/src/database/repositories/product.repo.ts index 3d2ec11..556ce9c 100644 --- a/backend/src/database/repositories/product.repo.ts +++ b/backend/src/database/repositories/product.repo.ts @@ -14,7 +14,6 @@ class ProductRepo { async updateProduct(id: string, details: string, price: number) { Validator.validateId(id, 'Invalid product ID'); - return await Product.updateOne({ _id: new ObjectId(id) }, { details, price }); } diff --git a/backend/src/types/Attachment.types.ts b/backend/src/types/Attachment.types.ts index 4c0ae89..bc14840 100644 --- a/backend/src/types/Attachment.types.ts +++ b/backend/src/types/Attachment.types.ts @@ -1,5 +1,4 @@ export interface AttachmentType { original_name: string; url: string; - timestamp: Date; } diff --git a/backend/src/types/Itinerary.types.ts b/backend/src/types/Itinerary.types.ts index cc1678e..ed67161 100644 --- a/backend/src/types/Itinerary.types.ts +++ b/backend/src/types/Itinerary.types.ts @@ -6,7 +6,7 @@ export interface ItineraryType { name: string; category: string; tags: TagType[]; - activities: ActivityType[]; + activities: String[]; locations: LocationType[]; timeline: string; language: string; diff --git a/backend/src/types/Museum.types.ts b/backend/src/types/Museum.types.ts index cd448d2..d2c7411 100644 --- a/backend/src/types/Museum.types.ts +++ b/backend/src/types/Museum.types.ts @@ -1,9 +1,8 @@ import { LocationType } from './Location.types'; -import { TagType } from './Tag.types'; export interface MuseumType { id: number; name: string; - tags: TagType[]; + tags: string[]; description: string; category: string; pictures: string[]; From 5e89ec3c43b3fc33255d8c5068f21c901f0a8266 Mon Sep 17 00:00:00 2001 From: Abdelrahman Mohammed Date: Sat, 5 Oct 2024 22:02:39 +0300 Subject: [PATCH 2/2] minor formatting fix --- backend/src/controllers/tag.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/controllers/tag.controller.ts b/backend/src/controllers/tag.controller.ts index f8f36ee..f865432 100644 --- a/backend/src/controllers/tag.controller.ts +++ b/backend/src/controllers/tag.controller.ts @@ -16,7 +16,7 @@ const getAllTags = async (req: Request, res: Response) => { logger.error(`Error fetching tags: ${error.message}`); res.status(ResponseStatusCodes.BAD_REQUEST).json({ message: error.message, data: [] }); } -} +}; const findTagById = async (req: Request, res: Response) => { try {