-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #767 from sandboxnu/minor-endpoints
minor endpoints folder, types, and missing data
- Loading branch information
Showing
8 changed files
with
296 additions
and
0 deletions.
There are no files selected for viewing
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,125 @@ | ||
import { Minor } from "@graduate/common"; | ||
// year minor name minor data | ||
const MINORS: Record<string, Record<string, Minor>> = {}; | ||
const MINOR_YEARS = new Set<string>(); | ||
|
||
const rootDir = "./src/minor/minors"; | ||
|
||
interface YearData { | ||
year: string; | ||
} | ||
|
||
interface YearCollegeData { | ||
year: string; | ||
college: string; | ||
} | ||
|
||
interface YearCollegeMinorData { | ||
year: string; | ||
college: string; | ||
minor: string; | ||
} | ||
|
||
async function fileExists( | ||
fs: typeof import("fs/promises"), | ||
path: string | ||
): Promise<boolean> { | ||
return await fs.access(path, fs.constants.F_OK).then( | ||
() => true, | ||
() => false | ||
); | ||
} | ||
|
||
// TODO: this code is quick and dirty but works. this should be replaced with some dry-er code later. | ||
/** | ||
* Iterates over the ./minors directory, collecting minors and adding them to | ||
* the exported MINORS and MINOR_YEARS object/set respectively. It prioritizes | ||
* parsed.commit.json files over parsed.initial.json files because _.commit._ | ||
* files have been human-reviewed and _.initial._ files are raw scraper output. | ||
*/ | ||
async function collateMinors() { | ||
// TODO: determine why these needed to be runtime imports (normal import statements didn't work here). | ||
const fs = await import("fs/promises"); | ||
const path = await import("path"); | ||
const years = ( | ||
await fs.readdir(path.resolve(rootDir), { | ||
withFileTypes: true, | ||
}) | ||
) | ||
.filter((dirent) => dirent.isDirectory()) | ||
.map( | ||
(dirent): YearData => ({ | ||
year: dirent.name, | ||
}) | ||
); | ||
|
||
const colleges = ( | ||
await Promise.all( | ||
years.map(async ({ year }) => { | ||
const colleges = await fs.readdir(path.join(rootDir, year), { | ||
withFileTypes: true, | ||
}); | ||
return colleges | ||
.filter((dirent) => dirent.isDirectory()) | ||
.map( | ||
(college): YearCollegeData => ({ | ||
year: year, | ||
college: college.name, | ||
}) | ||
); | ||
}) | ||
) | ||
).flat(); | ||
|
||
const minors = ( | ||
await Promise.all( | ||
colleges.map(async ({ year, college }) => { | ||
const minors = await fs.readdir(path.join(rootDir, year, college), { | ||
withFileTypes: true, | ||
}); | ||
return minors | ||
.filter((dirent) => dirent.isDirectory()) | ||
.map( | ||
(minor): YearCollegeMinorData => ({ | ||
year: year, | ||
college: college, | ||
minor: minor.name, | ||
}) | ||
); | ||
}) | ||
) | ||
).flat(); | ||
|
||
years.forEach(({ year }) => { | ||
MINOR_YEARS.add(year); | ||
MINORS[year] = {}; | ||
}); | ||
|
||
const done = await Promise.all( | ||
minors.map(async ({ year, college, minor }) => { | ||
const basePath = path.join(rootDir, year, college, minor); | ||
const commitFile = path.join(basePath, "parsed.commit.json"); | ||
const initialFile = path.join(basePath, "parsed.initial.json"); | ||
|
||
if (await fileExists(fs, commitFile)) { | ||
const fileData = JSON.parse( | ||
(await fs.readFile(commitFile)).toString() | ||
) as Minor; | ||
MINORS[year][fileData.name] = fileData; | ||
} else if (await fileExists(fs, initialFile)) { | ||
const fileData = JSON.parse( | ||
(await fs.readFile(initialFile)).toString() | ||
) as Minor; | ||
if (MINORS[year]) MINORS[year][fileData.name] = fileData; | ||
} | ||
}) | ||
); | ||
|
||
console.log( | ||
`Successfully loaded ${done.length} minors across ${MINOR_YEARS.size} years!` | ||
); | ||
} | ||
|
||
collateMinors(); | ||
|
||
export { MINORS, MINOR_YEARS }; |
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,32 @@ | ||
import { GetSupportedMinorsResponse, Minor } from "@graduate/common"; | ||
import { MinorService } from "./minor.service"; | ||
import { | ||
Controller, | ||
Get, | ||
NotFoundException, | ||
Param, | ||
ParseIntPipe, | ||
} from "@nestjs/common"; | ||
|
||
@Controller("minors") | ||
export class MinorController { | ||
constructor(private readonly minorService: MinorService) {} | ||
@Get("/:catalogYear/:minorName") | ||
getMinor( | ||
@Param("catalogYear", ParseIntPipe) catalogYear: number, | ||
@Param("minorName") minorName: string | ||
): Minor { | ||
const minor = this.minorService.findByMinorAndYear(minorName, catalogYear); | ||
if (!minor) { | ||
throw new NotFoundException(); | ||
} | ||
|
||
return minor; | ||
} | ||
|
||
@Get("supportedMinors") | ||
getSupportedMinors(): GetSupportedMinorsResponse { | ||
const supportedMinors = this.minorService.getSupportedMinors(); | ||
return { supportedMinors }; | ||
} | ||
} |
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 @@ | ||
import { Module } from "@nestjs/common"; | ||
import { MinorService } from "./minor.service"; | ||
import { MinorController } from "./minor.controller"; | ||
|
||
@Module({ | ||
controllers: [MinorController], | ||
providers: [MinorService], | ||
exports: [MinorService], | ||
}) | ||
export class MinorModule {} |
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,35 @@ | ||
import { Injectable, Logger } from "@nestjs/common"; | ||
import { formatServiceCtx } from "src/utils"; | ||
import { MINOR_YEARS, MINORS } from "./minor-collator"; | ||
import { Minor, SupportedMinors } from "@graduate/common"; | ||
|
||
@Injectable() | ||
export class MinorService { | ||
private readonly logger: Logger = new Logger(); | ||
findByMinorAndYear(minorName: string, catalogYear: number): Minor | null { | ||
if (!MINOR_YEARS.has(String(catalogYear))) { | ||
this.logger.debug( | ||
{ message: "Minor year not found", catalogYear }, | ||
MinorService.formatMinorServiceCtx("findByMinorAndYear") | ||
); | ||
return null; | ||
} | ||
|
||
if (!MINORS[catalogYear][minorName]) { | ||
this.logger.debug( | ||
{ message: "Minor within year not found", minorName, catalogYear }, | ||
MinorService.formatMinorServiceCtx("findByMinorAndYear") | ||
); | ||
return null; | ||
} | ||
return MINORS[catalogYear][minorName]; | ||
} | ||
|
||
getSupportedMinors(): SupportedMinors { | ||
return MINORS; | ||
} | ||
|
||
private static formatMinorServiceCtx(methodName: string): string { | ||
return formatServiceCtx(MinorService.name, methodName); | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
packages/api/src/minor/minors/2022/science/mathematics/parsed.initial.json
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,58 @@ | ||
{ | ||
"name": "Mathematics", | ||
"totalCreditsRequired": 24, | ||
"yearVersion": 2022, | ||
"requirementSections": [ | ||
{ | ||
"type": "SECTION", | ||
"title": "Required Courses", | ||
"requirements": [ | ||
{ | ||
"type": "COURSE", | ||
"classId": 1341, | ||
"subject": "MATH" | ||
}, | ||
{ | ||
"type": "COURSE", | ||
"classId": 1341, | ||
"subject": "MATH" | ||
} | ||
] | ||
}, | ||
{ | ||
"type": "SECTION", | ||
"title": "Intermediate-Level Courses", | ||
"requirements": [ | ||
{ | ||
"type": "COURSE", | ||
"classId": 2321, | ||
"subject": "MATH" | ||
}, | ||
{ | ||
"type": "COURSE", | ||
"classId": 2341, | ||
"subject": "MATH" | ||
}, | ||
{ | ||
"type": "COURSE", | ||
"classId": 2331, | ||
"subject": "MATH" | ||
} | ||
], | ||
"minRequirementCount": 2 | ||
}, | ||
{ | ||
"type": "RANGE", | ||
"subject": "MATH", | ||
"idRangeStart": 3001, | ||
"idRangeEnd": 4699, | ||
"exceptions": [ | ||
{ | ||
"subject": "MATH", | ||
"classId": 4000, | ||
"type": "COURSE" | ||
} | ||
] | ||
} | ||
] | ||
} |
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