Skip to content

Commit

Permalink
Merge pull request #200 from crux-bphc/update-search-service-after-ti…
Browse files Browse the repository at this point in the history
…metable-update

Update search service after timetable update and add search backend endpoint
  • Loading branch information
skoriop authored Jul 24, 2024
2 parents 3395bcc + 3390ba2 commit 491300a
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 2 deletions.
2 changes: 1 addition & 1 deletion backend/src/controllers/timetable/deleteTimetable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
43 changes: 43 additions & 0 deletions backend/src/controllers/timetable/searchTimetable.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
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({
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 searchResults = await response.json();

if (!response.ok) {
console.log("Error while searching timetable: ", searchResults.error);
return res.status(500).json({ message: "Internal Server Error" });
}

const timetables = searchResults.map(
(el: { timetable: Timetable; score: string }) => el.timetable,
);

return res.json(timetables);
} catch (err) {
console.log(err);
return res.status(500).json({ message: "Internal Server Error" });
}
};
107 changes: 106 additions & 1 deletion backend/src/controllers/timetable/updateChangedTimetable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,26 @@ 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,
checkForExamHoursClash,
} from "../../utils/checkForClashes.js";
import sqids from "../../utils/sqids.js";
import { addExamTimings, removeSection } from "../../utils/updateSection.js";
import { updateSectionWarnings } from "../../utils/updateWarnings.js";

const dataSchema = z.object({
body: z.object({
chronoSecret: namedNonEmptyStringType("chronoSecret"),
course: courseWithSectionsType,
}),
});
Expand All @@ -25,6 +30,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();
Expand Down Expand Up @@ -220,10 +228,107 @@ 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" });
}

// 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),
});
if (!res.ok) {
const resJson = await res.json();
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);
Expand Down
10 changes: 10 additions & 0 deletions backend/src/routers/timetableRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -41,6 +45,12 @@ timetableRouter.get(
getPublicTimetablesValidator,
getPublicTimetables,
);
timetableRouter.get(
"/search",
authenticate,
searchTimetableValidator,
searchTimetable,
);
timetableRouter.get("/:id", getTimetableByIdValidator, getTimetableById);
timetableRouter.post(
"/:id/delete",
Expand Down

0 comments on commit 491300a

Please sign in to comment.