From 61631b15d5ddfc9943928679e9ec26eb52da9f2e Mon Sep 17 00:00:00 2001 From: CollinWoo Date: Thu, 9 Mar 2023 17:03:50 -0500 Subject: [PATCH 1/4] implement /archive endpoint --- backend/functions/src/student/functions.ts | 73 +++++++++++++++++++++- backend/functions/src/student/routes.ts | 11 ++++ backend/functions/src/types/index.ts | 2 + 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/backend/functions/src/student/functions.ts b/backend/functions/src/student/functions.ts index c201ded0..28948c2c 100644 --- a/backend/functions/src/student/functions.ts +++ b/backend/functions/src/student/functions.ts @@ -57,18 +57,40 @@ async function removeStudentFromCourse( courseId: string, groupNumber: any ) { + //remove unmatched student + if (groupNumber === -1) { + const ref = courseRef.doc(courseId) + + return ref + .update({ + unmatched: admin.firestore.FieldValue.arrayRemove(email), + }) + .catch((err) => { + console.log(err) + throw new Error(`error in removing ${email} from unmatched.`) + }) + } + + //remove matched student const ref = courseRef .doc(courseId) .collection('groups') .doc(groupNumber.toString()) + const data: any = (await ref.get()).data() if (data.members.length === 1 && data.members.includes(email)) { //second condition is a sanity check return ref.delete() // Fix this if we ever use this function, I don't think they want groups to ever be deleted fully } else { - return ref.update({ - members: admin.firestore.FieldValue.arrayRemove(email), - }) + return ref + .update({ + members: admin.firestore.FieldValue.arrayRemove(email), + updateTime: admin.firestore.FieldValue.serverTimestamp(), + }) + .catch((err) => { + console.log(err) + throw new Error(`error in removing ${email} from group ${groupNumber}.`) + }) } } @@ -168,6 +190,7 @@ export const addStudentSurveyResponse = async ( notesModifyTime: surveyTimestamp, // Can't use serverTimestamp in arrays... submissionTime: surveyTimestamp, templateTimestamps: {}, + archived: false, })) // First, update the [student] collection to include the data for the new student @@ -304,3 +327,47 @@ export const updateStudentNotes = async ( `Updated notes for [${courseId}] in student [${email}] to [${notes}]` ) } + +async function archiveStudentInStudent(email: any, courseId: string) { + const studentDocRef = studentRef.doc(email) + const studentDoc = await studentDocRef.get() + if (!studentDoc.exists) { + throw new Error(`Student document for ${email} does not exist`) + } + const studentData = studentDoc.data() as FirestoreStudent + const groups = studentData.groups + const groupMembership = groups.find((group) => group.courseId === courseId) + if (!groupMembership) { + throw new Error(`Student ${email} does not have membership in ${courseId}`) + } + + groupMembership.archived = true + await studentDocRef.update({ groups }) + logger.info(`Archived [${courseId}] in student [${email}]]`) + return groupMembership.groupNumber +} + +// //Returns the group number of the student with email [email] in course [courseID] +// async function getStudentGroup( +// email: any, +// courseId: string, +// ) { +// const studentDocRef = studentRef.doc(email) +// const studentDoc = await studentDocRef.get() +// if (!studentDoc.exists) { +// throw new Error(`Student document for ${email} does not exist`) +// } +// const studentData = studentDoc.data() as FirestoreStudent +// const groups = studentData.groups +// const groupMembership = groups.find((group) => group.courseId === courseId) +// if (!groupMembership) { +// throw new Error(`Student ${email} does not have membership in ${courseId}`) +// } + +// return groupMembership.groupNumber +// } + +export async function archiveStudent(email: any, courseId: string) { + const groupNum = await archiveStudentInStudent(email, courseId) + await removeStudentFromCourse(email, courseId, groupNum) +} diff --git a/backend/functions/src/student/routes.ts b/backend/functions/src/student/routes.ts index 90ba08b3..568e675e 100644 --- a/backend/functions/src/student/routes.ts +++ b/backend/functions/src/student/routes.ts @@ -9,6 +9,7 @@ import { getAllStudents, removeStudent, updateStudentNotes, + archiveStudent, } from './functions' router.get('/', (_, res) => { @@ -64,4 +65,14 @@ router.delete('/', checkAuth, (req, res) => { }) }) +router.post('/archive', (req, res) => { + const { email, courseId } = req.body + archiveStudent(email, courseId) + .then((data) => res.status(200).send({ success: true, data })) + .catch((err) => { + console.log(err) + res.status(400).send({ success: false, err: err.message }) + }) +}) + export default router diff --git a/backend/functions/src/types/index.ts b/backend/functions/src/types/index.ts index d00daefe..8529d69f 100644 --- a/backend/functions/src/types/index.ts +++ b/backend/functions/src/types/index.ts @@ -45,6 +45,7 @@ export type GroupMembership = { notesModifyTime: Date submissionTime: Date templateTimestamps: { [key: string]: Date } + archived: boolean } /** Information about an email template */ @@ -86,6 +87,7 @@ export type FirestoreGroupMembership = { notesModifyTime: Timestamp submissionTime: Timestamp templateTimestamps: EmailTimestamps + archived: boolean } /** How email template data is stored in the database */ From d5ccc73355b43c3235a1cf66e14002ab33185b4b Mon Sep 17 00:00:00 2001 From: CollinWoo Date: Thu, 9 Mar 2023 20:04:34 -0500 Subject: [PATCH 2/4] allow unarchiving students through survey --- backend/functions/src/student/functions.ts | 30 +++++----------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/backend/functions/src/student/functions.ts b/backend/functions/src/student/functions.ts index 28948c2c..7f03d38a 100644 --- a/backend/functions/src/student/functions.ts +++ b/backend/functions/src/student/functions.ts @@ -169,7 +169,11 @@ export const addStudentSurveyResponse = async ( // Find the existing courses this student is already in by checking group membership const existingData = (await studentRef.doc(email).get()).data() //gets all the existing data //studentCrses becomes courseIds of existingData.groups if available, otherwise [] - const existingCourses = existingData ? existingData.groups : [] //gets the existing courses + const existingCourses = existingData + ? existingData.groups.filter( + (course: { archived: string }) => !course.archived + ) + : [] //gets the existing courses const existingCourseIds: string[] = existingCourses.map( (course: { courseId: string }) => course.courseId ) @@ -328,7 +332,7 @@ export const updateStudentNotes = async ( ) } -async function archiveStudentInStudent(email: any, courseId: string) { +async function archiveStudentInStudent(email: string, courseId: string) { const studentDocRef = studentRef.doc(email) const studentDoc = await studentDocRef.get() if (!studentDoc.exists) { @@ -347,27 +351,7 @@ async function archiveStudentInStudent(email: any, courseId: string) { return groupMembership.groupNumber } -// //Returns the group number of the student with email [email] in course [courseID] -// async function getStudentGroup( -// email: any, -// courseId: string, -// ) { -// const studentDocRef = studentRef.doc(email) -// const studentDoc = await studentDocRef.get() -// if (!studentDoc.exists) { -// throw new Error(`Student document for ${email} does not exist`) -// } -// const studentData = studentDoc.data() as FirestoreStudent -// const groups = studentData.groups -// const groupMembership = groups.find((group) => group.courseId === courseId) -// if (!groupMembership) { -// throw new Error(`Student ${email} does not have membership in ${courseId}`) -// } - -// return groupMembership.groupNumber -// } - -export async function archiveStudent(email: any, courseId: string) { +export async function archiveStudent(email: string, courseId: string) { const groupNum = await archiveStudentInStudent(email, courseId) await removeStudentFromCourse(email, courseId, groupNum) } From 6057ef9c26c975521aeb92bf3603aa5062896220 Mon Sep 17 00:00:00 2001 From: CollinWoo Date: Tue, 25 Apr 2023 16:29:39 -0400 Subject: [PATCH 3/4] replace console.log with firebase logging --- backend/functions/src/student/functions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/functions/src/student/functions.ts b/backend/functions/src/student/functions.ts index 7f03d38a..454a103c 100644 --- a/backend/functions/src/student/functions.ts +++ b/backend/functions/src/student/functions.ts @@ -66,7 +66,7 @@ async function removeStudentFromCourse( unmatched: admin.firestore.FieldValue.arrayRemove(email), }) .catch((err) => { - console.log(err) + logger.error(` error in removing ${email} from unmatched: ${err} `) throw new Error(`error in removing ${email} from unmatched.`) }) } From 9c1521b6abde278901907cf5166f2e3c8f0b91c9 Mon Sep 17 00:00:00 2001 From: CollinWoo Date: Tue, 25 Apr 2023 20:36:34 -0400 Subject: [PATCH 4/4] fix bug with readding classes through survey --- backend/functions/src/student/functions.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/functions/src/student/functions.ts b/backend/functions/src/student/functions.ts index 454a103c..d5c4cf45 100644 --- a/backend/functions/src/student/functions.ts +++ b/backend/functions/src/student/functions.ts @@ -171,7 +171,11 @@ export const addStudentSurveyResponse = async ( //studentCrses becomes courseIds of existingData.groups if available, otherwise [] const existingCourses = existingData ? existingData.groups.filter( - (course: { archived: string }) => !course.archived + (course: { courseId: string; archived: string }) => + !course.archived || + !courseIdsWithNames + .map((course) => course.courseId) + .includes(course.courseId) ) : [] //gets the existing courses const existingCourseIds: string[] = existingCourses.map(