Skip to content
This repository has been archived by the owner on Oct 18, 2024. It is now read-only.

Commit

Permalink
feat: ✨ rework enrollment history endpoint (#126)
Browse files Browse the repository at this point in the history
  • Loading branch information
ecxyzzy authored Feb 5, 2024
1 parent 615f27d commit 5140300
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 170 deletions.
48 changes: 24 additions & 24 deletions .github/workflows/deploy-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,27 +80,27 @@ jobs:

- name: Deploy documentation CloudFormation stack
run: pnpm --filter="@tools/cdk" docs deploy
# deploy-services:
# name: Deploy services CloudFormation stack and production environment
#
# runs-on: ubuntu-latest
#
# environment:
# name: production-services
#
# steps:
# - name: Checkout repository
# uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4
#
# - name: Setup Node.js and pnpm
# uses: ./.github/actions/setup-node-and-pnpm
#
# - name: Install dependencies
# # Ensure NODE_ENV != production so pnpm will install devDependencies!!!
# run: NODE_ENV=development pnpm install --frozen-lockfile
#
# - name: Build services
# run: pnpm build --filter="@services/*"
#
# - name: Deploy stack
# run: pnpm --filter="@tools/cdk" services deploy
deploy-services:
name: Deploy services CloudFormation stack and production environment

runs-on: ubuntu-latest

environment:
name: production-services

steps:
- name: Checkout repository
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4

- name: Setup Node.js and pnpm
uses: ./.github/actions/setup-node-and-pnpm

- name: Install dependencies
# Ensure NODE_ENV != production so pnpm will install devDependencies!!!
run: NODE_ENV=development pnpm install --frozen-lockfile

- name: Build services
run: pnpm build --filter="@services/*"

- name: Deploy stack
run: pnpm --filter="@tools/cdk" services deploy
33 changes: 16 additions & 17 deletions apps/api/src/routes/v1/rest/enrollmentHistory/+endpoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { PrismaClient } from "@libs/db";
import { createHandler } from "@libs/lambda";
import type { EnrollmentHistory } from "@peterportal-api/types";

import { transformResults } from "./lib";
import { QuerySchema } from "./schema";

const prisma = new PrismaClient();
Expand All @@ -12,26 +13,24 @@ export const GET = createHandler(async (event, context, res) => {

const maybeParsed = QuerySchema.safeParse(query);
if (!maybeParsed.success) {
return res.createErrorResult(400, maybeParsed.error, requestId);
return res.createErrorResult(
400,
maybeParsed.error.issues.map((issue) => issue.message).join("; "),
requestId,
);
}
const {
data: { instructor, ...data },
} = maybeParsed;

return res.createOKResult<EnrollmentHistory[]>(
(
await prisma.websocEnrollmentHistory.findMany({
where: {
...data,
courseNumber: data.courseNumber?.toUpperCase(),
instructors: { array_contains: instructor },
},
})
).map((x) => {
const { timestamp: _, ...obj } = x;
return obj as unknown as EnrollmentHistory;
}),
headers,
requestId,
);
const sections = await prisma.websocEnrollmentHistory.findMany({
where: {
...data,
...(instructor && { instructors: { has: instructor } }),
},
include: { entries: true },
take: 6000,
});

return res.createOKResult<EnrollmentHistory[]>(transformResults(sections), headers, requestId);
});
21 changes: 21 additions & 0 deletions apps/api/src/routes/v1/rest/enrollmentHistory/lib.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { WebsocEnrollmentHistory, WebsocEnrollmentHistoryEntry } from "@libs/db";
import type { EnrollmentHistory, Meeting } from "@peterportal-api/types";

const stringifyDate = (date: Date) =>
`${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
export const transformResults = (
results: Array<WebsocEnrollmentHistory & { entries: WebsocEnrollmentHistoryEntry[] }>,
): EnrollmentHistory[] =>
results.map(({ entries, ...x }) => ({
...x,
sectionCode: x.sectionCode.toString().padStart(5, "0"),
meetings: x.meetings as Meeting[],
dates: entries.map((y) => y.date).map(stringifyDate),
maxCapacityHistory: entries.map((y) => y.maxCapacity),
totalEnrolledHistory: entries.map((y) => y.totalEnrolled),
waitlistHistory: entries.map((y) => y.waitlist),
waitlistCapHistory: entries.map((y) => y.waitlistCap),
requestedHistory: entries.map((y) => y.requested),
newOnlyReservedHistory: entries.map((y) => y.newOnlyReserved),
statusHistory: entries.map((y) => y.status),
}));
47 changes: 29 additions & 18 deletions apps/api/src/routes/v1/rest/enrollmentHistory/schema.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,34 @@
import { quarters, sectionTypes } from "@peterportal-api/types";
import { z } from "zod";

export const QuerySchema = z.object({
year: z
.string()
.regex(/^\d{4}$/, { message: "Invalid year provided" })
.optional(),
quarter: z.enum(quarters, { invalid_type_error: "Invalid quarter provided" }).optional(),
instructor: z.string().optional(),
department: z.string().optional(),
courseNumber: z.string().optional(),
sectionCode: z
.string()
.regex(/^\d{5}$/, { message: "Invalid sectionCode provided" })
.transform((x) => Number.parseInt(x, 10))
.optional(),
sectionType: z
.enum(sectionTypes, { invalid_type_error: "Invalid sectionType provided" })
.optional(),
});
export const QuerySchema = z
.object({
year: z
.string()
.regex(/^\d{4}$/, { message: "Invalid year provided" })
.optional(),
quarter: z.enum(quarters, { invalid_type_error: "Invalid quarter provided" }).optional(),
instructor: z.string().optional(),
department: z.string().optional(),
courseNumber: z.string().optional(),
sectionCode: z
.string()
.regex(/^\d{5}$/, { message: "Invalid sectionCode provided" })
.transform((x) => Number.parseInt(x, 10))
.optional(),
sectionType: z
.enum(sectionTypes, { invalid_type_error: "Invalid sectionType provided" })
.optional(),
})
.refine(
(x) =>
(x.department && x.courseNumber) ||
(x.sectionCode && x.year && x.quarter) ||
(x.instructor && x.courseNumber && x.year && x.quarter),
{
message:
"Must provide department and course number; section code and year/quarter; or instructor, course number, and year/quarter",
},
);

export type Query = z.infer<typeof QuerySchema>;
54 changes: 32 additions & 22 deletions libs/db/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -147,30 +147,40 @@ model GradesSection {
@@unique([year, quarter, sectionCode], name: "idx")
}

model WebsocEnrollmentHistoryEntry {
year String
quarter Quarter
sectionCode Int
WebsocEnrollmentHistory WebsocEnrollmentHistory @relation(fields: [year, quarter, sectionCode], references: [year, quarter, sectionCode])
date DateTime @db.Date
maxCapacity String
totalEnrolled String
waitlist String
waitlistCap String
requested String
newOnlyReserved String
status String
@@id([year, quarter, sectionCode, date])
@@unique([year, quarter, sectionCode, date], name: "idx")
}

model WebsocEnrollmentHistory {
year String
quarter Quarter
sectionCode Int
timestamp DateTime
department String
courseNumber String
sectionType WebsocSectionType
sectionNum String
units String
instructors Json
meetings Json
finalExam String
dates Json
maxCapacityHistory Json
totalEnrolledHistory Json
waitlistHistory Json
waitlistCapHistory Json
requestedHistory Json
newOnlyReservedHistory Json
statusHistory Json
year String
quarter Quarter
sectionCode Int
department String
courseNumber String
sectionType WebsocSectionType
sectionNum String
units String
instructors String[]
meetings Json
finalExam String
entries WebsocEnrollmentHistoryEntry[]
@@id([year, quarter, sectionCode, timestamp])
@@unique([year, quarter, sectionCode, timestamp], name: "idx")
@@id([year, quarter, sectionCode])
@@unique([year, quarter, sectionCode], name: "idx")
}

model WebsocSectionInstructor {
Expand Down
7 changes: 7 additions & 0 deletions libs/db/sql/access_control.sql
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ GRANT USAGE,
SELECT
ON ALL SEQUENCES IN SCHEMA public TO api_websoc_scraper;

GRANT
SELECT
,
INSERT,
UPDATE,
DELETE ON public."WebsocEnrollmentHistoryEntry" TO api_websoc_scraper;

GRANT
SELECT
,
Expand Down
8 changes: 7 additions & 1 deletion packages/types/types/enrollmentHistory.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { Quarter, SectionType } from "./constants";

export type Meeting = {
bldg: string[];
days: string;
time: string;
};

export type EnrollmentHistory = {
year: string;
quarter: Quarter;
Expand All @@ -10,7 +16,7 @@ export type EnrollmentHistory = {
sectionNum: string;
units: string;
instructors: string[];
meetings: string[];
meetings: Meeting[];
finalExam: string;
dates: string[];
maxCapacityHistory: string[];
Expand Down
Loading

0 comments on commit 5140300

Please sign in to comment.