From c0c28ee16793f91e0f8cc95f76cfd548d3adae2f Mon Sep 17 00:00:00 2001 From: kishan1735 Date: Sat, 20 Jul 2024 09:21:08 +0530 Subject: [PATCH 1/6] feat: update search service courses after timetable update --- .../controllers/timetable/deleteTimetable.ts | 2 +- .../timetable/updateChangedTimetable.ts | 49 ++++++++++++++++++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/backend/src/controllers/timetable/deleteTimetable.ts b/backend/src/controllers/timetable/deleteTimetable.ts index 6a0d1f5f..931506d3 100644 --- a/backend/src/controllers/timetable/deleteTimetable.ts +++ b/backend/src/controllers/timetable/deleteTimetable.ts @@ -83,7 +83,7 @@ export const deleteTimetable = async (req: Request, res: Response) => { headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ id: timetable.id }), + body: JSON.stringify({ id: req.params.id }), }); if (!res.ok) { const resJson = await res.json(); diff --git a/backend/src/controllers/timetable/updateChangedTimetable.ts b/backend/src/controllers/timetable/updateChangedTimetable.ts index fb5f3663..bd9ffa68 100644 --- a/backend/src/controllers/timetable/updateChangedTimetable.ts +++ b/backend/src/controllers/timetable/updateChangedTimetable.ts @@ -2,11 +2,14 @@ import type { Request, Response } from "express"; import { z } from "zod"; import { courseWithSectionsType, + namedNonEmptyStringType, sectionTypeList, } from "../../../../lib/src/index.js"; +import { env } from "../../config/server.js"; import { AppDataSource } from "../../db.js"; import { Course, Section, Timetable } from "../../entity/entities.js"; import { validate } from "../../middleware/zodValidateRequest.js"; +import { timetableRepository } from "../../repositories/timetableRepository.js"; import { checkForExamTimingsChange } from "../../utils/checkForChange.js"; import { checkForClassHoursClash, @@ -17,6 +20,7 @@ import { updateSectionWarnings } from "../../utils/updateWarnings.js"; const dataSchema = z.object({ body: z.object({ + chronoSecret: namedNonEmptyStringType("chronoSecret"), course: courseWithSectionsType, }), }); @@ -25,6 +29,9 @@ export const updateChangedTimetableValidator = validate(dataSchema); export const updateChangedTimetable = async (req: Request, res: Response) => { try { + if (env.CHRONO_SECRET !== req.body.chronoSecret) { + return res.status(401).json({ message: "Chrono Secret is incorrect" }); + } // Use a transaction because we will run many dependent mutations const queryRunner = AppDataSource.createQueryRunner(); await queryRunner.connect(); @@ -220,10 +227,50 @@ export const updateChangedTimetable = async (req: Request, res: Response) => { console.log("Error while querying for course: ", err.message); return res.status(500).json({ message: "Internal Server Error" }); } - // After everything passes fine, commit the transaction await queryRunner.commitTransaction(); queryRunner.release(); + + // update course in search service + try { + const searchServiceURL = `${env.SEARCH_SERVICE_URL}/course/remove`; + const res = await fetch(searchServiceURL, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ id: course.id }), + }); + if (!res.ok) { + const resJson = await res.json(); + console.log(resJson.error); + } + } catch (err: any) { + console.log( + "Error while removing course from search service: ", + err.message, + ); + return res.status(500).json({ message: "Internal Server Error" }); + } + + try { + const searchServiceURL = `${env.SEARCH_SERVICE_URL}/course/add`; + const res = await fetch(searchServiceURL, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(course), + }); + if (!res.ok) { + const resJson = await res.json(); + console.log(resJson.error); + } + } catch (err: any) { + console.log("Error while adding course to search service: ", err.message); + return res.status(500).json({ message: "Internal Server Error" }); + } + return res.json({ message: "Timetable successfully updated" }); } catch (err: any) { console.log(err); From 5a8dfd92eb9ecd84c616dafd4bd58c222c1ea90c Mon Sep 17 00:00:00 2001 From: kishan1735 Date: Sat, 20 Jul 2024 09:33:43 +0530 Subject: [PATCH 2/6] feat: update search service timetables after timetable update --- .../timetable/updateChangedTimetable.ts | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/backend/src/controllers/timetable/updateChangedTimetable.ts b/backend/src/controllers/timetable/updateChangedTimetable.ts index bd9ffa68..9265835f 100644 --- a/backend/src/controllers/timetable/updateChangedTimetable.ts +++ b/backend/src/controllers/timetable/updateChangedTimetable.ts @@ -15,6 +15,7 @@ import { checkForClassHoursClash, checkForExamHoursClash, } from "../../utils/checkForClashes.js"; +import sqids from "../../utils/sqids.js"; import { addExamTimings, removeSection } from "../../utils/updateSection.js"; import { updateSectionWarnings } from "../../utils/updateWarnings.js"; @@ -270,7 +271,65 @@ export const updateChangedTimetable = async (req: Request, res: Response) => { console.log("Error while adding course to search service: ", err.message); return res.status(500).json({ message: "Internal Server Error" }); } + // update timetables in search service + for (const timetable of timetables) { + try { + const searchServiceURL = `${env.SEARCH_SERVICE_URL}/timetable/remove`; + const encodedId = sqids.encode([timetable.id]); + const res = await fetch(searchServiceURL, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ id: encodedId }), + }); + + if (!res.ok) { + const resJson = await res.json(); + console.log(resJson.error); + } + } catch (err: any) { + console.log( + "Error while removing timetable from search service: ", + err.message, + ); + return res.status(500).json({ message: "Internal Server Error" }); + } + if (!timetable.draft && !timetable.private) { + const timetableWithSections = await timetableRepository + .createQueryBuilder("timetable") + .leftJoinAndSelect("timetable.sections", "section") + .where("timetable.id=:id", { id: timetable.id }) + .getOne(); + const encodedId = sqids.encode([timetable.id]); + const timetableWithSectionsString = { + ...timetableWithSections, + id: encodedId, + }; + try { + const searchServiceURL = `${env.SEARCH_SERVICE_URL}/timetable/add`; + const res = await fetch(searchServiceURL, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(timetableWithSectionsString), + }); + const resJson = await res.json(); + console.log(resJson); + if (!res.ok) { + console.log(resJson.error); + } + } catch (err: any) { + console.log( + "Error while adding timetable to search service: ", + err.message, + ); + return res.status(500).json({ message: "Internal Server Error" }); + } + } + } return res.json({ message: "Timetable successfully updated" }); } catch (err: any) { console.log(err); From 0fddd2120b877e015c72434ef77cf9121e2acec7 Mon Sep 17 00:00:00 2001 From: kishan1735 Date: Sat, 20 Jul 2024 09:35:25 +0530 Subject: [PATCH 3/6] refactor: remove console.logs --- backend/src/controllers/timetable/updateChangedTimetable.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/controllers/timetable/updateChangedTimetable.ts b/backend/src/controllers/timetable/updateChangedTimetable.ts index 9265835f..f2acc6a1 100644 --- a/backend/src/controllers/timetable/updateChangedTimetable.ts +++ b/backend/src/controllers/timetable/updateChangedTimetable.ts @@ -317,7 +317,6 @@ export const updateChangedTimetable = async (req: Request, res: Response) => { body: JSON.stringify(timetableWithSectionsString), }); const resJson = await res.json(); - console.log(resJson); if (!res.ok) { console.log(resJson.error); } From 7b101050f34a08c7353963342f0c9e1f68e3218f Mon Sep 17 00:00:00 2001 From: kishan1735 Date: Sat, 20 Jul 2024 23:50:55 +0530 Subject: [PATCH 4/6] feat: add timetable search endpoint --- .../controllers/timetable/searchTimetable.ts | 38 +++++++++++++++++++ backend/src/routers/timetableRouter.ts | 10 +++++ 2 files changed, 48 insertions(+) create mode 100644 backend/src/controllers/timetable/searchTimetable.ts diff --git a/backend/src/controllers/timetable/searchTimetable.ts b/backend/src/controllers/timetable/searchTimetable.ts new file mode 100644 index 00000000..a8fe5e92 --- /dev/null +++ b/backend/src/controllers/timetable/searchTimetable.ts @@ -0,0 +1,38 @@ +import { Request, Response } from "express"; +import { z } from "zod"; +import { namedNonEmptyStringType } from "../../../../lib/src/zodFieldTypes.js"; +import { env } from "../../config/server.js"; +import { validate } from "../../middleware/zodValidateRequest.js"; + +const searchTimetableSchema = z.object({ + query: z.object({ + query: namedNonEmptyStringType("query"), + }), +}); + +export const searchTimetableValidator = validate(searchTimetableSchema); + +export const searchTimetable = async (req: Request, res: Response) => { + try { + const { query } = req.query; + + const searchServiceURL = `${env.SEARCH_SERVICE_URL}/timetable/search?query=${query}`; + + const response = await fetch(searchServiceURL, { + method: "GET", + headers: { "Content-Type": "application/json" }, + }); + + const timetables = await response.json(); + + if (!timetables.ok) { + console.log("Error while searching timetable: ", timetables.error); + return res.status(500).json({ message: "Internal Server Error" }); + } + + return res.json(timetables); + } catch (err) { + console.log(err); + return res.status(500).json({ message: "Internal Server Error" }); + } +}; diff --git a/backend/src/routers/timetableRouter.ts b/backend/src/routers/timetableRouter.ts index f1df5252..e3df6361 100644 --- a/backend/src/routers/timetableRouter.ts +++ b/backend/src/routers/timetableRouter.ts @@ -30,6 +30,10 @@ import { removeSection, removeSectionValidator, } from "../controllers/timetable/removeSection.js"; +import { + searchTimetable, + searchTimetableValidator, +} from "../controllers/timetable/searchTimetable.js"; import { authenticate } from "../middleware/auth.js"; const timetableRouter = express.Router(); @@ -41,6 +45,12 @@ timetableRouter.get( getPublicTimetablesValidator, getPublicTimetables, ); +timetableRouter.get( + "/search", + authenticate, + searchTimetableValidator, + searchTimetable, +); timetableRouter.get("/:id", getTimetableByIdValidator, getTimetableById); timetableRouter.post( "/:id/delete", From e23e69088225ca59614e93189a33322c105d27b0 Mon Sep 17 00:00:00 2001 From: Kishan Abijay <42596478+kishan1735@users.noreply.github.com> Date: Tue, 23 Jul 2024 21:51:47 +0530 Subject: [PATCH 5/6] fix : minor fixes --- backend/src/controllers/timetable/searchTimetable.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/backend/src/controllers/timetable/searchTimetable.ts b/backend/src/controllers/timetable/searchTimetable.ts index a8fe5e92..7cb4c6b7 100644 --- a/backend/src/controllers/timetable/searchTimetable.ts +++ b/backend/src/controllers/timetable/searchTimetable.ts @@ -2,6 +2,7 @@ import { Request, Response } from "express"; import { z } from "zod"; import { namedNonEmptyStringType } from "../../../../lib/src/zodFieldTypes.js"; import { env } from "../../config/server.js"; +import { Timetable } from "../../entity/entities.js"; import { validate } from "../../middleware/zodValidateRequest.js"; const searchTimetableSchema = z.object({ @@ -23,13 +24,17 @@ export const searchTimetable = async (req: Request, res: Response) => { headers: { "Content-Type": "application/json" }, }); - const timetables = await response.json(); + let timetables = await response.json(); - if (!timetables.ok) { + if (!response.ok) { console.log("Error while searching timetable: ", timetables.error); return res.status(500).json({ message: "Internal Server Error" }); } + timetables = timetables.map( + (el: { timetable: Timetable; score: string }) => el.timetable, + ); + return res.json(timetables); } catch (err) { console.log(err); From 3390ba2217c76cf0791088e38e768283d16311b4 Mon Sep 17 00:00:00 2001 From: skoriop Date: Wed, 24 Jul 2024 14:25:13 +0530 Subject: [PATCH 6/6] fix: minor nitpicks --- backend/src/controllers/timetable/searchTimetable.ts | 6 +++--- backend/src/controllers/timetable/updateChangedTimetable.ts | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/src/controllers/timetable/searchTimetable.ts b/backend/src/controllers/timetable/searchTimetable.ts index 7cb4c6b7..6466830a 100644 --- a/backend/src/controllers/timetable/searchTimetable.ts +++ b/backend/src/controllers/timetable/searchTimetable.ts @@ -24,14 +24,14 @@ export const searchTimetable = async (req: Request, res: Response) => { headers: { "Content-Type": "application/json" }, }); - let timetables = await response.json(); + const searchResults = await response.json(); if (!response.ok) { - console.log("Error while searching timetable: ", timetables.error); + console.log("Error while searching timetable: ", searchResults.error); return res.status(500).json({ message: "Internal Server Error" }); } - timetables = timetables.map( + const timetables = searchResults.map( (el: { timetable: Timetable; score: string }) => el.timetable, ); diff --git a/backend/src/controllers/timetable/updateChangedTimetable.ts b/backend/src/controllers/timetable/updateChangedTimetable.ts index f2acc6a1..28679bab 100644 --- a/backend/src/controllers/timetable/updateChangedTimetable.ts +++ b/backend/src/controllers/timetable/updateChangedTimetable.ts @@ -271,8 +271,8 @@ export const updateChangedTimetable = async (req: Request, res: Response) => { console.log("Error while adding course to search service: ", err.message); return res.status(500).json({ message: "Internal Server Error" }); } - // update timetables in search service + // update timetables in search service for (const timetable of timetables) { try { const searchServiceURL = `${env.SEARCH_SERVICE_URL}/timetable/remove`; @@ -316,8 +316,8 @@ export const updateChangedTimetable = async (req: Request, res: Response) => { }, body: JSON.stringify(timetableWithSectionsString), }); - const resJson = await res.json(); if (!res.ok) { + const resJson = await res.json(); console.log(resJson.error); } } catch (err: any) {