diff --git a/nextjs/src/models/local/semesterTransferUtils.ts b/nextjs/src/models/local/semesterTransferUtils.ts new file mode 100644 index 0000000..74e1585 --- /dev/null +++ b/nextjs/src/models/local/semesterTransferUtils.ts @@ -0,0 +1,98 @@ +import { LocalAssignment } from "./assignment/localAssignment"; +import { LocalQuiz } from "./quiz/localQuiz"; +import { + dateToMarkdownString, + getDateFromString, + getDateFromStringOrThrow, + getDateOnlyMarkdownString, +} from "./timeUtils"; + +export const prepAssignmentForNewSemester = ( + assignment: LocalAssignment, + oldSemesterStartDate: string, + newSemesterStartDate: string +): LocalAssignment => { + const descriptionWithoutGithubClassroom = replaceClassroomUrl( + assignment.description + ); + return { + ...assignment, + description: descriptionWithoutGithubClassroom, + dueAt: + newDateOffset( + assignment.dueAt, + oldSemesterStartDate, + newSemesterStartDate + ) ?? assignment.dueAt, + lockAt: newDateOffset( + assignment.lockAt, + oldSemesterStartDate, + newSemesterStartDate + ), + }; +}; + + +export const prepQuizForNewSemester = ( + quiz: LocalQuiz, + oldSemesterStartDate: string, + newSemesterStartDate: string +): LocalQuiz => { + const descriptionWithoutGithubClassroom = replaceClassroomUrl( + quiz.description + ); + return { + ...quiz, + description: descriptionWithoutGithubClassroom, + dueAt: + newDateOffset( + quiz.dueAt, + oldSemesterStartDate, + newSemesterStartDate + ) ?? quiz.dueAt, + lockAt: newDateOffset( + quiz.lockAt, + oldSemesterStartDate, + newSemesterStartDate + ), + }; +}; + + + +const replaceClassroomUrl = (value: string) => { + const classroomPattern = + /https:\/\/classroom\.github\.com\/[a-zA-Z0-9\/._-]+/g; + const withoutGithubClassroom = value.replace( + classroomPattern, + "insert_github_classroom_url" + ); + return withoutGithubClassroom; +}; + +const newDateOffset = ( + dateString: string | undefined, + oldSemesterStartDate: string, + newSemesterStartDate: string +) => { + if (!dateString) return dateString; + const oldStart = getDateFromStringOrThrow( + oldSemesterStartDate, + "semester start date in new semester offset" + ); + const newStart = getDateFromStringOrThrow( + newSemesterStartDate, + "new semester start date in new semester offset" + ); + const date = getDateFromStringOrThrow( + dateString, + "date in new semester offset" + ); + const offset = date.getTime() - oldStart.getTime(); + + const newUnixTime = offset + newStart.getTime(); + + const newDate = new Date(newUnixTime); + + return dateToMarkdownString(newDate); +}; diff --git a/nextjs/src/models/local/tests/testSemesterImport.test.ts b/nextjs/src/models/local/tests/testSemesterImport.test.ts new file mode 100644 index 0000000..ff76a55 --- /dev/null +++ b/nextjs/src/models/local/tests/testSemesterImport.test.ts @@ -0,0 +1,173 @@ +import { describe, it, expect } from "vitest"; +import { LocalAssignment } from "../assignment/localAssignment"; +import { prepAssignmentForNewSemester, prepQuizForNewSemester } from "../semesterTransferUtils"; +import { LocalQuiz } from "../quiz/localQuiz"; + +describe("can take an assignment and template it for a new semester", () => { + it("can sanitize assignment github classroom repo url", () => { + const assignment: LocalAssignment = { + name: "test assignment", + description: ` +## test description + +[GitHub Classroom Assignment](https://classroom.github.com/a/y_eOxTfL) + +other stuff below`, + dueAt: "08/21/2023 23:59:00", + lockAt: "08/21/2023 23:59:00", + submissionTypes: [], + localAssignmentGroupName: "Final Project", + rubric: [], + allowedFileUploadExtensions: [], + }; + const oldSemesterStartDate = "08/26/2023 23:59:00"; + const newSemesterStartDate = "01/08/2024 23:59:00"; + + const sanitizedAssignment = prepAssignmentForNewSemester( + assignment, + oldSemesterStartDate, + newSemesterStartDate + ); + + expect(sanitizedAssignment.description).toEqual(` +## test description + +[GitHub Classroom Assignment](insert_github_classroom_url) + +other stuff below`); + }); + + it("can sanitize assignment github classroom repo url 2", () => { + const assignment: LocalAssignment = { + name: "test assignment", + description: ` + +other stuff below`, + dueAt: "08/21/2023 23:59:00", + lockAt: "08/21/2023 23:59:00", + submissionTypes: [], + localAssignmentGroupName: "Final Project", + rubric: [], + allowedFileUploadExtensions: [], + }; + const oldSemesterStartDate = "08/26/2023 23:59:00"; + const newSemesterStartDate = "01/08/2024 23:59:00"; + + const sanitizedAssignment = prepAssignmentForNewSemester( + assignment, + oldSemesterStartDate, + newSemesterStartDate + ); + + expect(sanitizedAssignment.description).toEqual(` + +other stuff below`); + }); + + it("can sanitize assignment github classroom repo url 3", () => { + const assignment: LocalAssignment = { + name: "test assignment", + description: `https://classroom.github.com/a/y_eOxTfL other things`, + dueAt: "08/21/2023 23:59:00", + lockAt: "08/21/2023 23:59:00", + submissionTypes: [], + localAssignmentGroupName: "Final Project", + rubric: [], + allowedFileUploadExtensions: [], + }; + const oldSemesterStartDate = "08/26/2023 23:59:00"; + const newSemesterStartDate = "01/08/2024 23:59:00"; + + const sanitizedAssignment = prepAssignmentForNewSemester( + assignment, + oldSemesterStartDate, + newSemesterStartDate + ); + + expect(sanitizedAssignment.description).toEqual( + `insert_github_classroom_url other things` + ); + }); +}); + +describe("can offset date based on new semester start", () => { + it("assignment with new semester start", () => { + const assignment: LocalAssignment = { + name: "test assignment", + description: `https://classroom.github.com/a/y_eOxTfL other things`, + dueAt: "08/29/2023 23:59:00", + lockAt: "08/29/2023 23:59:00", + submissionTypes: [], + localAssignmentGroupName: "Final Project", + rubric: [], + allowedFileUploadExtensions: [], + }; + + const oldSemesterStartDate = "08/26/2023 23:59:00"; + const newSemesterStartDate = "01/08/2024 23:59:00"; + + const sanitizedAssignment = prepAssignmentForNewSemester( + assignment, + oldSemesterStartDate, + newSemesterStartDate + ); + + expect(sanitizedAssignment.dueAt).toEqual("01/11/2024 23:59:00"); + expect(sanitizedAssignment.lockAt).toEqual("01/11/2024 23:59:00"); + }); + it("assignment with new semester start, no lock date", () => { + const assignment: LocalAssignment = { + name: "test assignment", + description: `https://classroom.github.com/a/y_eOxTfL other things`, + dueAt: "08/29/2023 23:59:00", + lockAt: undefined, + submissionTypes: [], + localAssignmentGroupName: "Final Project", + rubric: [], + allowedFileUploadExtensions: [], + }; + + const oldSemesterStartDate = "08/26/2023 23:59:00"; + const newSemesterStartDate = "01/08/2024 23:59:00"; + + const sanitizedAssignment = prepAssignmentForNewSemester( + assignment, + oldSemesterStartDate, + newSemesterStartDate + ); + + expect(sanitizedAssignment.dueAt).toEqual("01/11/2024 23:59:00"); + expect(sanitizedAssignment.lockAt).toEqual(undefined); + }); +}); + +describe("can prep quizzes", () => { + it("assignment with new semester start, no lock date", () => { + const quiz: LocalQuiz = { + name: "Test Quiz", + description: ` +# quiz description +`, + dueAt: "08/29/2023 23:59:00", + lockAt: "08/30/2023 23:59:00", + shuffleAnswers: true, + oneQuestionAtATime: false, + localAssignmentGroupName: "someId", + allowedAttempts: -1, + showCorrectAnswers: false, + questions: [], + }; + + const oldSemesterStartDate = "08/26/2023 23:59:00"; + const newSemesterStartDate = "01/08/2024 23:59:00"; + + const sanitizedQuiz = prepQuizForNewSemester( + quiz, + oldSemesterStartDate, + newSemesterStartDate + ); + + expect(sanitizedQuiz.dueAt).toEqual("01/11/2024 23:59:00"); + expect(sanitizedQuiz.lockAt).toEqual("01/12/2024 23:59:00"); + }); +});