Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
bba51ef
rebase onto gql
maxmwang Oct 31, 2025
4ca2176
finalize rebase onto gql
maxmwang Oct 31, 2025
607ae23
notfis react component fixed, popup correct dropdowns, updated styling
PriyaDVenkatesan Oct 31, 2025
aadf6c1
fixed relative popover, right-edge anchor
PriyaDVenkatesan Oct 31, 2025
0011828
dynamic arrow, confirmation model, final feature cleanup
PriyaDVenkatesan Oct 31, 2025
d73245f
iconoir component, fixed checkbox/dropdown component
PriyaDVenkatesan Nov 3, 2025
b002a3d
resolved all frontend related pr comments
PriyaDVenkatesan Nov 3, 2025
fbed78e
Merge branch 'gql' into maxwang/gql-nofitications
ritam2006 Nov 11, 2025
d27d078
Adding fuse.js
ritam2006 Nov 11, 2025
af500df
Edited timestamp because of enrollment-checks change
ritam2006 Nov 11, 2025
1e0879b
idk what this is
ritam2006 Nov 11, 2025
f238359
cleaned up the entire frontend for notification
PineND Nov 13, 2025
35f88b1
warning and confirmation
PineND Nov 13, 2025
74c3b17
linting
PineND Nov 13, 2025
971108c
fix with design suggestion
PineND Nov 13, 2025
fba23ed
merge with recent version of gql - I dont want to deal with the lates…
PineND Nov 13, 2025
8926e4c
Removed notifications frontend
ritam2006 Nov 14, 2025
efcc675
Removed imports
ritam2006 Nov 14, 2025
85c3e67
Adding field for sendgrid api key to template
ritam2006 Nov 14, 2025
54a3da3
pr comments
Ryan6407 Nov 19, 2025
a7a52e0
Improving query for getting monitored classes
ritam2006 Nov 21, 2025
19a7e7b
Improving query for getting monitored classes
ritam2006 Nov 21, 2025
ea5bc21
moved enrollment-checks onto enrollment and put the email in a template
Ryan6407 Nov 21, 2025
5f237b2
Merge branch 'gql-notifications-backend' of https://github.com/asuc-o…
Ryan6407 Nov 21, 2025
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
2 changes: 2 additions & 0 deletions .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ AWS_SECRET_ACCESS_KEY=_
GOOGLE_CLIENT_ID=_
GOOGLE_CLIENT_SECRET=_
SESSION_SECRET=_

SENDGRID_API_KEY=_
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ generated-types/
# others
*.cert
*.key

prod-backup.gz
6 changes: 5 additions & 1 deletion apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
"@repo/common": "*",
"@repo/shared": "*",
"@repo/sis-api": "*",
"@types/node-cron": "^3.0.11",
"@types/nodemailer": "^7.0.2",
"compression": "^1.8.1",
"connect-redis": "^9.0.0",
"cors": "^2.8.5",
Expand All @@ -55,7 +57,9 @@
"keyv": "^5.5.3",
"lodash": "^4.17.21",
"mongodb": "^6.20.0",
"mongoose": "^8.19.1",
"mongoose": "^8.17.0",
"node-cron": "^4.2.1",
"nodemailer": "^7.0.7",
"papaparse": "^5.5.3",
"passport": "^0.7.0",
"passport-google-oauth20": "^2.0.0",
Expand Down
36 changes: 36 additions & 0 deletions apps/backend/src/modules/user/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,39 @@ export const getBookmarkedClasses = async (

return classes.map(formatClass);
};

export const getMonitoredClasses = async (
monitoredClasses:
| UserModule.MonitoredClassInput[]
| UserModule.MonitoredClass[]
) => {
const filters = monitoredClasses.map((mc) => {
const c = mc.class;
return {
year: c.year,
semester: c.semester,
sessionId: c.sessionId ?? "1",
subject: c.subject,
courseNumber: c.courseNumber,
number: c.number,
};
});

const docs = await ClassModel.find({ $or: filters }).lean();
const classKey = (c: any) =>
`${c.year}-${c.semester}-${c.sessionId ?? "1"}-${c.subject}-${c.courseNumber}-${c.number}`;
const docsByKey = new Map(docs.map((d) => [classKey(d), d]));

return monitoredClasses
.map((mc) => {
const key = classKey(mc.class);
const doc = docsByKey.get(key);
if (!doc) return null;

return {
class: formatClass(doc),
thresholds: mc.thresholds,
};
})
.filter(Boolean);
};
3 changes: 3 additions & 0 deletions apps/backend/src/modules/user/formatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { UserModule } from "./generated-types/module-types";
interface UserRelationships {
bookmarkedCourses: UserModule.BookmarkedCourseInput[];
bookmarkedClasses: UserModule.BookmarkedClassInput[];
monitoredClasses: UserModule.MonitoredClassInput[];
}

export type IntermediateUser = Omit<UserModule.User, keyof UserRelationships> &
Expand All @@ -21,5 +22,7 @@ export const formatUser = (user: UserType) => {
bookmarkedClasses: user.bookmarkedClasses,
majors: user.majors ? user.majors : [],
minors: user.minors ? user.minors : [],
monitoredClasses: user.monitoredClasses,
notificationsOn: user.notificationsOn,
} as IntermediateUser;
};
16 changes: 16 additions & 0 deletions apps/backend/src/modules/user/resolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
getBookmarkedClasses,
getBookmarkedCourses,
getMonitoredClasses,
getUser,
updateUser,
} from "./controller";
Expand Down Expand Up @@ -40,6 +41,21 @@ const resolvers: UserModule.Resolvers = {

return courses as unknown as UserModule.Course[];
},

monitoredClasses: async (parent: UserModule.User | IntermediateUser) => {
if (
parent.monitoredClasses[0] &&
(parent.monitoredClasses[0] as UserModule.MonitoredClass).class
) {
return parent.monitoredClasses as UserModule.MonitoredClass[];
}

const monitoredClasses = await getMonitoredClasses(
parent.monitoredClasses
);

return monitoredClasses as unknown as UserModule.MonitoredClass[];
},
},

Mutation: {
Expand Down
37 changes: 37 additions & 0 deletions apps/backend/src/modules/user/typedefs/user.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { gql } from "graphql-tag";

const typedef = gql`
type MonitoredClass {
class: Class!
thresholds: [Float]!
}

type User @cacheControl(scope: PRIVATE) {
_id: ID!
email: String!
Expand All @@ -11,6 +16,8 @@ const typedef = gql`
bookmarkedClasses: [Class!]!
majors: [String!]!
minors: [String!]!
monitoredClasses: [MonitoredClass!]!
notificationsOn: Boolean!
}

type Query {
Expand All @@ -31,11 +38,41 @@ const typedef = gql`
number: ClassNumber!
}

input MonitoredClassRefInput {
year: Int!
semester: Semester!
sessionId: SessionIdentifier
subject: String!
courseNumber: CourseNumber!
number: ClassNumber!
}

input MonitoredClassInput {
class: MonitoredClassRefInput!
thresholds: [Float!]!
}

input MonitoredClassRefInput {
year: Int!
semester: Semester!
sessionId: SessionIdentifier
subject: String!
courseNumber: CourseNumber!
number: ClassNumber!
}

input MonitoredClassInput {
class: MonitoredClassRefInput!
thresholds: [Float!]!
}

input UpdateUserInput {
bookmarkedClasses: [BookmarkedClassInput!]
bookmarkedCourses: [BookmarkedCourseInput!]
majors: [String!]
minors: [String!]
monitoredClasses: [MonitoredClassInput!]
notificationsOn: Boolean!
}

type Mutation {
Expand Down
1 change: 1 addition & 0 deletions apps/datapuller/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"@repo/sis-api": "*",
"dotenv": "^17.2.3",
"luxon": "^3.7.2",
"@sendgrid/mail": "^8.1.4",
"papaparse": "^5.5.3",
"tslog": "^4.10.2"
}
Expand Down
Loading