Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for syllabi #202

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"recommendations": ["dbaeumer.vscode-eslint", "nrwl.angular-console", "esbenp.prettier-vscode"]
"recommendations": [
"dbaeumer.vscode-eslint",
"nrwl.angular-console",
"esbenp.prettier-vscode",
"prisma.prisma"
]
}
4 changes: 4 additions & 0 deletions apps/backend/src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getFCEs } from "~/controllers/fces";
import { getInstructors } from "~/controllers/instructors";
import { getGeneds } from "~/controllers/geneds";
import { getSchedules } from "~/controllers/schedules";
import { getSyllabi, getAllSyllabi } from "~/controllers/syllabi";

const app = express();
const port = process.env.PORT || 3000;
Expand All @@ -33,6 +34,9 @@ app.route("/schedules").get(getSchedules);
app.route("/geneds").get(getGeneds);
app.route("/geneds").post(isUser, getGeneds);

app.route("/syllabi").get(getSyllabi)
app.route("/syllabi/all").get(getAllSyllabi);

// the next parameter is needed!
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const errorHandler: ErrorRequestHandler = (err, req, res, next) => {
Expand Down
75 changes: 75 additions & 0 deletions apps/backend/src/controllers/syllabi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { RequestHandler } from "express";
import { cleanID, PrismaReturn, SingleOrArray, singleToArray } from "~/util";
import db from "@cmucourses/db";

export interface GetSyllabi {
params: unknown;
resBody: PrismaReturn<typeof db.syllabi.findMany>;
reqBody: unknown;
query: {
number: SingleOrArray<string>;
};
}

export const getSyllabi: RequestHandler<
GetSyllabi["params"],
GetSyllabi["resBody"],
GetSyllabi["reqBody"],
GetSyllabi["query"]
> = async (req, res, next) => {
const numbers = singleToArray(req.query.number).map(cleanID);

try {
const syllabi = await db.syllabi.findMany({
where: {
number: { in: numbers },
}
});
res.json(syllabi);
} catch (e) {
next(e);
}
};

// TODO: use a better caching system

const allSyllabiEntry = {
allSyllabi: [] as GetAllSyllabi["resBody"],
lastCached: new Date(1970),
};

const getAllSyllabiDbQuery = {
select: {
name: true,
number: true,
},
};

export interface GetAllSyllabi {
params: unknown;
resBody: PrismaReturn<typeof db.syllabi.findMany<typeof getAllSyllabiDbQuery>>;
reqBody: unknown;
query: { number?: string | string[]; name?: string | string[] };
}

export const getAllSyllabi: RequestHandler<
GetAllSyllabi["params"],
GetAllSyllabi["resBody"],
GetAllSyllabi["reqBody"],
GetAllSyllabi["query"]
> = async (req, res, next) => {
if (new Date().valueOf() - allSyllabiEntry.lastCached.valueOf() > 1000 * 60 * 60 * 24) {
try {
const syllabi = await db.syllabi.findMany(getAllSyllabiDbQuery);

allSyllabiEntry.lastCached = new Date();
allSyllabiEntry.allSyllabi = syllabi;

res.json(syllabi);
} catch (e) {
next(e);
}
} else {
res.json(allSyllabiEntry.allSyllabi);
}
};
4 changes: 4 additions & 0 deletions apps/backend/src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ export const standardizeID = (id: string): string => {
return id;
};

export const cleanID = (id: string): string => {
return id.replace("-", "");
}

export type SingleOrArray<T> = T | T[];

export function singleToArray<T>(param: SingleOrArray<T>): T[] {
Expand Down
16 changes: 16 additions & 0 deletions apps/frontend/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const metadata = {
title: 'Next.js',
description: 'Generated by Next.js',
}

export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}
10 changes: 10 additions & 0 deletions apps/frontend/src/app/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ export interface Course {
fces?: FCE[];
}

export interface Syllabus {
season: string;
year: number;
department: string;
number: string;
section: string;
name: string;
url: string;
}

export interface Time {
days: number[];
begin: string;
Expand Down
11 changes: 10 additions & 1 deletion apps/frontend/src/components/CourseCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { CourseSchedulesDetail } from "./CourseSchedulesDetail";
import { useFetchCourseInfo } from "~/app/api/course";
import { useFetchFCEInfoByCourse } from "~/app/api/fce";
import { useAuth } from "@clerk/nextjs";
// import { useFetchSyllabus } from "~/app/api/syllabi";

interface Props {
courseID: string;
Expand All @@ -35,9 +36,11 @@ const CourseCard = ({
useFetchCourseInfo(courseID);
const { isPending: isFCEInfoPending, data: { fces } = {} } =
useFetchFCEInfoByCourse(courseID);
// const { isPending: isSyllabusPending, data: syllabi } =
// useFetchSyllabus(courseID);
const options = useAppSelector((state) => state.user.fceAggregation);

if (isCourseInfoPending || isFCEInfoPending || !info) {
if (isCourseInfoPending || isFCEInfoPending /*|| isSyllabusPending*/ || !info) {
return <></>;
}

Expand Down Expand Up @@ -112,6 +115,12 @@ const CourseCard = ({
{injectLinks(courseListToString(info.crosslisted))}
</div>
</div>
<div>
<div className="font-semibold">Syllabi</div>
<div className="text-md text-gray-500">
None
</div>
</div>
</div>
)}
</div>
Expand Down
7 changes: 7 additions & 0 deletions apps/frontend/src/components/SideNav.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
ChatBubbleBottomCenterTextIcon,
ClockIcon,
AcademicCapIcon,
MagnifyingGlassIcon,
StarIcon,
UserCircleIcon,
Expand Down Expand Up @@ -81,6 +82,12 @@ export const SideNav = ({ activePage }) => {
link="/instructors"
active={activePage === "instructors"}
/>
<SideNavItem
icon={AcademicCapIcon}
text="Syllabi"
link="/syllabi"
active={activePage === "syllabi"}
/>
<SideNavItem
icon={BookOpenIcon}
text="Geneds"
Expand Down
13 changes: 13 additions & 0 deletions packages/db/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -133,3 +133,16 @@ model geneds {
school String
tags String[]
}

model syllabi {
id String @id @default(auto()) @map("_id") @db.ObjectId
season String
year Int
department String
number String
section String
name String
url String

@@fulltext([name, number], map: "text")
}
Loading