-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add prerequisites data from Horaire-cours PDF (#48)
* Refactor CoursePrerequisite model and migrate unstructuredPrerequisite column to ProgramCourse * Make credits column nullable in Program model * Refactor logging missing programs and courses * Add pdf parsable flags to Program model & create a seeder for all parsable programs * create worker to get parsed horaire pdf data * quick cleanup & add endpoint * refactor variable name (CoursePrerequisite to Prerequisite) * wip adding prerequisites * add unstructured prerequisites * add logging rules for worker thread * cleanup * add metrics & enforce logging rules * move prereq logic to service * add unit tests for session utils * doc jobs process * refactor prerequisite * refactor prerequisite * run seeder on prerequisite job
- Loading branch information
Showing
40 changed files
with
1,442 additions
and
273 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
14 changes: 14 additions & 0 deletions
14
prisma/migrations/20241116063843_swap_unstructered_prerequ_column/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* | ||
Warnings: | ||
- You are about to drop the column `unstructuredPrerequisite` on the `CoursePrerequisite` table. All the data in the column will be lost. | ||
*/ | ||
-- AlterTable | ||
ALTER TABLE "CoursePrerequisite" DROP COLUMN "unstructuredPrerequisite"; | ||
|
||
-- AlterTable | ||
ALTER TABLE "ProgramCourse" ADD COLUMN "unstructuredPrerequisite" TEXT; | ||
|
||
-- CreateIndex | ||
CREATE INDEX "CoursePrerequisite_courseId_programId_idx" ON "CoursePrerequisite"("courseId", "programId"); |
2 changes: 2 additions & 0 deletions
2
prisma/migrations/20241116064515_change_credits_column_nullable/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
-- AlterTable | ||
ALTER TABLE "Program" ALTER COLUMN "credits" DROP NOT NULL; |
2 changes: 2 additions & 0 deletions
2
prisma/migrations/20241116232705_add_pdf_parsable_to_program_table/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
-- AlterTable | ||
ALTER TABLE "Program" ADD COLUMN "pdfParsable" BOOLEAN NOT NULL DEFAULT false; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* | ||
Warnings: | ||
- You are about to drop the column `pdfParsable` on the `Program` table. All the data in the column will be lost. | ||
*/ | ||
-- AlterTable | ||
ALTER TABLE "Program" DROP COLUMN "pdfParsable", | ||
ADD COLUMN "isHorairePdfParsable" BOOLEAN NOT NULL DEFAULT false, | ||
ADD COLUMN "isPlanificationPdfParsable" BOOLEAN NOT NULL DEFAULT false; |
8 changes: 8 additions & 0 deletions
8
prisma/migrations/20241119040325_add_unique_constraint_to_session/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
/* | ||
Warnings: | ||
- A unique constraint covering the columns `[year,trimester]` on the table `Session` will be added. If there are existing duplicate values, this will fail. | ||
*/ | ||
-- CreateIndex | ||
CREATE UNIQUE INDEX "Session_year_trimester_key" ON "Session"("year", "trimester"); |
34 changes: 34 additions & 0 deletions
34
prisma/migrations/20241120054503_refactor_prerequisite_name/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
Warnings: | ||
- You are about to drop the `CoursePrerequisite` table. If the table is not empty, all the data it contains will be lost. | ||
*/ | ||
-- DropForeignKey | ||
ALTER TABLE "CoursePrerequisite" DROP CONSTRAINT "CoursePrerequisite_courseId_programId_fkey"; | ||
|
||
-- DropForeignKey | ||
ALTER TABLE "CoursePrerequisite" DROP CONSTRAINT "CoursePrerequisite_prerequisiteId_programId_fkey"; | ||
|
||
-- DropTable | ||
DROP TABLE "CoursePrerequisite"; | ||
|
||
-- CreateTable | ||
CREATE TABLE "Prerequisite" ( | ||
"courseId" INTEGER NOT NULL, | ||
"prerequisiteId" INTEGER NOT NULL, | ||
"programId" INTEGER NOT NULL, | ||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"updatedAt" TIMESTAMP(3) NOT NULL, | ||
|
||
CONSTRAINT "Prerequisite_pkey" PRIMARY KEY ("courseId","programId","prerequisiteId") | ||
); | ||
|
||
-- CreateIndex | ||
CREATE INDEX "Prerequisite_courseId_programId_idx" ON "Prerequisite"("courseId", "programId"); | ||
|
||
-- AddForeignKey | ||
ALTER TABLE "Prerequisite" ADD CONSTRAINT "Prerequisite_courseId_programId_fkey" FOREIGN KEY ("courseId", "programId") REFERENCES "ProgramCourse"("courseId", "programId") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
||
-- AddForeignKey | ||
ALTER TABLE "Prerequisite" ADD CONSTRAINT "Prerequisite_prerequisiteId_programId_fkey" FOREIGN KEY ("prerequisiteId", "programId") REFERENCES "ProgramCourse"("courseId", "programId") ON DELETE RESTRICT ON UPDATE CASCADE; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"horairePdfPrograms": [ | ||
"5766", | ||
"7086", | ||
"7625", | ||
"7694", | ||
"7084", | ||
"7684", | ||
"6556", | ||
"6557", | ||
"6646", | ||
"4567", | ||
"4684", | ||
"4563", | ||
"0486", | ||
"4412", | ||
"4288", | ||
"4329" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { Logger } from '@nestjs/common'; | ||
|
||
import { PrismaService } from '../../src/prisma/prisma.service'; | ||
import { seedProgramPdfParserFlags } from '../../src/prisma/programs.seeder'; | ||
|
||
const prismaService = new PrismaService(); | ||
|
||
async function main() { | ||
await seedProgramPdfParserFlags(); | ||
} | ||
|
||
main() | ||
.catch((e) => { | ||
Logger.error(`Seeding error: ${e}`); | ||
process.exit(1); | ||
}) | ||
.finally(async () => { | ||
await prismaService.$disconnect(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { CourseCodeValidationPipe } from '../../pipes/models/course/course-code-validation-pipe'; | ||
|
||
export function parsePrerequisiteString( | ||
prerequisiteString: string, | ||
courseCodeValidationPipe: CourseCodeValidationPipe, | ||
): string[] | null { | ||
const trimmedPrerequisite = prerequisiteString.trim(); | ||
|
||
if (!trimmedPrerequisite) { | ||
return null; | ||
} | ||
|
||
// Attempt to validate the entire string as a single course code | ||
const singleValidation = | ||
courseCodeValidationPipe.transform(trimmedPrerequisite); | ||
if (singleValidation !== false) { | ||
return typeof singleValidation === 'string' ? [singleValidation] : null; | ||
} | ||
|
||
// If single validation fails, attempt to split and validate multiple course codes | ||
const courseCodes = trimmedPrerequisite.split(',').map((s) => s.trim()); | ||
|
||
const validCourseCodes: string[] = []; | ||
for (const code of courseCodes) { | ||
const validatedCode = courseCodeValidationPipe.transform(code); | ||
if (validatedCode === false) { | ||
// If any code is invalid, treat the entire prerequisite string as unstructured | ||
return null; | ||
} | ||
if (typeof validatedCode === 'string') { | ||
validCourseCodes.push(validatedCode); | ||
} | ||
} | ||
|
||
return validCourseCodes; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { Logger } from '@nestjs/common'; | ||
import { Trimester } from '@prisma/client'; | ||
|
||
const logger = new Logger('SessionUtil'); | ||
|
||
interface SessionDateRange { | ||
trimester: Trimester; | ||
index: number; | ||
start: { month: number; day: number }; | ||
end: { month: number; day: number }; | ||
} | ||
|
||
const SESSION_DATE_RANGES: SessionDateRange[] = [ | ||
{ | ||
trimester: Trimester.HIVER, | ||
index: 1, | ||
start: { month: 1, day: 6 }, // 6 janvier | ||
end: { month: 4, day: 28 }, // 28 avril | ||
}, | ||
{ | ||
trimester: Trimester.ETE, | ||
index: 2, | ||
start: { month: 5, day: 6 }, // 6 mai | ||
end: { month: 8, day: 17 }, // 17 août | ||
}, | ||
{ | ||
trimester: Trimester.AUTOMNE, | ||
index: 3, | ||
start: { month: 9, day: 3 }, // 3 septembre | ||
end: { month: 12, day: 19 }, // 19 décembre | ||
}, | ||
]; | ||
|
||
export function isDateInRange( | ||
date: { month: number; day: number }, | ||
start: { month: number; day: number }, | ||
end: { month: number; day: number }, | ||
): boolean { | ||
if (date.month < start.month || date.month > end.month) { | ||
return false; | ||
} | ||
|
||
if (date.month === start.month && date.day < start.day) { | ||
return false; | ||
} | ||
|
||
if (date.month === end.month && date.day > end.day) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
export function getCurrentSessionIndex(date: Date = new Date()): string | null { | ||
const year = date.getFullYear(); | ||
const month = date.getMonth() + 1; // JS months are 0-based | ||
const day = date.getDate(); | ||
|
||
for (const session of SESSION_DATE_RANGES) { | ||
if (isDateInRange({ month, day }, session.start, session.end)) { | ||
return `${year}${session.index}`; | ||
} | ||
} | ||
|
||
logger.error( | ||
`Unable to determine the current trimester for date: ${date.toISOString()}`, | ||
); | ||
return null; | ||
} | ||
|
||
export function getTrimesterByIndex(index: number): Trimester | null { | ||
switch (index) { | ||
case 1: | ||
return Trimester.HIVER; | ||
case 2: | ||
return Trimester.ETE; | ||
case 3: | ||
return Trimester.AUTOMNE; | ||
default: | ||
return null; | ||
} | ||
} | ||
|
||
export function getTrimesterIndexBySession(trimester: string): number { | ||
switch (trimester) { | ||
case 'HIVER': | ||
return 1; | ||
case 'ETE': | ||
return 2; | ||
case 'AUTOMNE': | ||
return 3; | ||
default: | ||
throw new Error(`Unknown trimester: ${trimester}`); | ||
} | ||
} | ||
|
||
export function getCurrentTrimester(date: Date = new Date()): Trimester | null { | ||
const yearIndex = getCurrentSessionIndex(date); | ||
if (!yearIndex) { | ||
return null; | ||
} | ||
|
||
const trimesterIndex = parseInt(yearIndex.slice(-1), 10); | ||
return getTrimesterByIndex(trimesterIndex); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.