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

Update sgyfetch function on firebase functions #115

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion client/src/components/classes/ClassesLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export default function ClassesLayout() {
let needToReset = false;
let classes: {[key:string]: any} = {};

const periods: SgyPeriod[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', 'S'];
const periods: SgyPeriod[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', 'S', 'P', 'H'];
for (const p of periods) {
const course = userData.classes[p];

Expand Down
10 changes: 5 additions & 5 deletions client/src/contexts/UserDataContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ type SgyCourseData = {
events: Event[];
}
export type SgyData = {
grades: SectionGrade[];
1?: SgyCourseData, 2?: SgyCourseData, 3?: SgyCourseData, 4?: SgyCourseData,
5?: SgyCourseData, 6?: SgyCourseData, 7?: SgyCourseData, S?: SgyCourseData,
0?: SgyCourseData, 8?: SgyCourseData
grades: SectionGrade[],
gradYear: number
} & {
[P in SgyPeriod]?: SgyCourseData
};
export type SgyPeriod = '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '0' | 'S';
export type SgyPeriod = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | 'S' | 'P' | 'H';

export const defaultUserData: UserData = {
clubs: [],
Expand Down
60 changes: 37 additions & 23 deletions functions/src/sgyfetch.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import * as functions from 'firebase-functions';
import admin from './util/adminInit';
import {get} from './util/sgyOAuth';
import {SgyData, SgyPeriod, SgyPeriodData} from '@watt/client/src/contexts/UserDataContext';

const SEMESTER = 1; // We are in semester 1
const CURRENT_YEAR = 2022; // will work for 2022-2023 school year

const YEAR_STR = `${CURRENT_YEAR}-${CURRENT_YEAR+1}`;

const firestore = admin.firestore();
const periods = ['0', '1', '2', '3', '4', '5', '6', '7', '8', 'SELF'];
const periods = ['0', '1', '2', '3', '4', '5', '6', '7', '8', 'S', 'P', 'H'];


// Get a user's stored firestore sgy info
Expand All @@ -17,21 +21,15 @@ async function getSgyInfo(uid: string) {
return {uid: creds.sgy.uid, key: creds.sgy.key, sec: creds.sgy.sec, classes: creds.classes};
}

// Parses info about the given schoology info string. Ex.
// `"Study Hall Kaneko (9813 43 FY)"` -> `{ pName: "Study Hall", pTeacher: "Kaneko", term: "FY" }`
// `"2 Liberatore (9813 43 FY)"` -> `{ pName: "2", pTeacher: "Liberatore", term: "FY" }`
function getClassInfo(info: string) {
const words = info.split(' ');
const pRegex = info.match(/\((.+)\)/);
let term = null;
if(pRegex) {
const parenblock = pRegex[1]; // 2696 1 FY
const items = parenblock.split(' '); // [2696, 1, FY]
term = items[items.length - 1]; // FY
}

return { pName: words[0], pTeacher: words[1], term };
const match = info.match(/(.+?) (\w+) \(\d+ \d+ (\w+)\)/);
if (!match) return { pName: '', pTeacher: '', term: null };
return { pName: match[1], pTeacher: match[2], term: match[3] };
}

type SgyPeriodData = {n: string, c: string, l: string, o: string, s: string};


// sgyfetch-init
// Populate the user's period customization with fetched class names from schoology,
Expand All @@ -51,16 +49,19 @@ export const init = functions.https.onCall(async (data, context) => {

const classes: {[key: string]: SgyPeriodData} = {};
for (const p in periods) {
classes[p[0]] = { n: '', c: '', l: '', o: '', s: '' };
classes[p] = { n: '', c: '', l: '', o: '', s: '' };
}

const teachers: {[key: string]: [string, string]} = {};
for (const element of sgyClasses) {
let {pName, pTeacher, term} = getClassInfo(element['section_title']);
if (term === `S${3-SEMESTER}`) continue; // 3 - SEMESTER will rule out S1 courses if SEMESTER is 2, and S2 courses if SEMESTER is 1

if (pName === 'SELF') pName = 'S'
if (pName === 'PRIME') pName = 'P'
if (pName === 'Study Hall') pName = 'H'

if (periods.includes(pName)) {
if (pName === 'SELF') pName = 'S'
if (pName === 'PRIME') pName = 'P'
classes[pName] = {
n: `${element.course_title} · ${pTeacher}`,
c: sgyInfo.classes[pName].c,
Expand Down Expand Up @@ -132,10 +133,22 @@ export const fetchMaterials = functions.https.onCall(async (data, context) => {

// Fetch courses, then kick out yucky ones
// TODO: type this better
let courses = (await get(`users/${sgyInfo.uid}/sections`, sgyInfo.key, sgyInfo.sec)).section
const unfiltered = await get(`users/${sgyInfo.uid}/sections`, sgyInfo.key, sgyInfo.sec);
const gunnStudentCourse = unfiltered.section.find((sec: {section_title: string}) => {
const title = sec.section_title.toLowerCase();
return (title.endsWith(YEAR_STR) && title !== YEAR_STR);
})
const grad_year = ['se', 'ju', 'so', 'fr'].indexOf(gunnStudentCourse.section_title.slice(0,2)) + CURRENT_YEAR + 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way to get graduation year via the schoology API? I recall when digging into obscure properties in people's userData objects on firestore that some people had a gradYear lumped into their schoology data. Is there a way we could fetch this instead of the gunn student course?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could, but it would require a separate fetch to /users/me, and iirc the gradYear is also off by one year for no reason at all. Might just be better to just parse courses instead.


let courses = unfiltered.section
.filter((sec: {section_title: string}) => {
const {pName, term} = getClassInfo(sec.section_title);
let {pName, term} = getClassInfo(sec.section_title);
if (term === `S${3 - SEMESTER}`) return false; // 3 - SEMESTER will rule out S1 courses if SEMESTER is 2, and S2 courses if SEMESTER is 1

if (pName === 'SELF') pName = 'S'
if (pName === 'PRIME') pName = 'P'
if (pName === 'Study Hall') pName = 'H'

return periods.includes(pName);
});

Expand All @@ -158,8 +171,11 @@ export const fetchMaterials = functions.https.onCall(async (data, context) => {
// Rip we have to flatten promises
const responses = await Promise.all(promises);

// TODO: type this better
const sections: {[key: string]: {info: any, documents: any, assignments: any, pages: any, events: any}} = {};
// Return an object of type `SgyData` containing relevant data.
const sections: SgyData = {
grades: (await grades).section,
gradYear: grad_year
}

// Unflattening smh my head my head my head
for (let i = 0; i < courses.length; i++) {
Expand All @@ -171,7 +187,7 @@ export const fetchMaterials = functions.https.onCall(async (data, context) => {
const pages = responses[4 * i + 2].page;
const events = responses[4 * i + 3].event;

sections[course.section_title.split(' ')[0][0]] = {
sections[course.section_title.split(' ')[0][0] as SgyPeriod] = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does

sections[course.section_title.split(' ')[0][0]]

work for study hall? I'm not sure what course.section_title looks like, but taking the first letter of the first word wouldn't work if the title were "Study Hall".

info: course,
documents,
assignments,
Expand All @@ -180,8 +196,6 @@ export const fetchMaterials = functions.https.onCall(async (data, context) => {
};
}

sections.grades = (await grades).section;

return sections;

} catch (e) {
Expand Down