diff --git a/src/plugins/built-in/assessmentsAverage/engage.ts b/src/plugins/built-in/assessmentsAverage/engage.ts new file mode 100644 index 00000000..07b7c1e0 --- /dev/null +++ b/src/plugins/built-in/assessmentsAverage/engage.ts @@ -0,0 +1,55 @@ +const ENGAGE_STUDENT_STORAGE_KEY = () => + `bsplus.engageTimetable.student.${location.origin}`; + +/** Engage assessments URLs: /#?page=/assessments/{studentId}/{programme}:{metaclass}:{studentId} */ +export function getEngageAssessmentStudentId(): string | null { + const hashMatch = window.location.hash.match(/\/assessments\/(\d+)/); + if (hashMatch?.[1]) return hashMatch[1]; + + return localStorage.getItem(ENGAGE_STUDENT_STORAGE_KEY()); +} + +function randomEngagePdfFileName(): string { + const token = Math.random().toString(36).slice(2, 10); + return `${token}.pdf`; +} + +export async function requestEngageAssessmentPdf(params: { + assessmentID: string | number; + metaclassID: string | number; + studentID: string | number; +}): Promise { + const fileName = randomEngagePdfFileName(); + const cacheBuster = Math.random().toString(36).slice(2, 10); + + const response = await fetch( + `${location.origin}/seqta/parent/print/assessment?${cacheBuster}`, + { + method: "POST", + headers: { "Content-Type": "application/json; charset=utf-8" }, + credentials: "include", + body: JSON.stringify({ + id: params.assessmentID, + metaclass: params.metaclassID, + student: Number(params.studentID), + fileName, + }), + }, + ); + + if (!response.ok) { + throw new Error( + `Failed to generate PDF: ${response.status} ${response.statusText}`, + ); + } + + const data = (await response.json()) as { + payload?: { file?: string }; + }; + + return data.payload?.file ?? fileName; +} + +export function getEngageAssessmentReportUrl(fileName: string): string { + return `${location.origin}/seqta/parent/report/get?file=${encodeURIComponent(fileName)}`; +} diff --git a/src/plugins/built-in/assessmentsAverage/utils.ts b/src/plugins/built-in/assessmentsAverage/utils.ts index bf7514a6..f720cd19 100644 --- a/src/plugins/built-in/assessmentsAverage/utils.ts +++ b/src/plugins/built-in/assessmentsAverage/utils.ts @@ -1,5 +1,11 @@ import { getUserInfo } from "@/seqta/ui/AddBetterSEQTAElements.ts"; import ReactFiber from "@/seqta/utils/ReactFiber.ts"; +import { isSeqtaEngageExperience } from "@/seqta/utils/isSeqtaEngage"; +import { + getEngageAssessmentReportUrl, + getEngageAssessmentStudentId, + requestEngageAssessmentPdf, +} from "./engage.ts"; import { ensurePdfjsWorker, getPdfjsPageContextUrls, @@ -464,8 +470,6 @@ export async function extractPDFText(url: string): Promise { async function handleWeightings(mark: any, api: any) { const assessmentID = mark.id; const metaclassID = mark.metaclassID; - const userInfo = await getUserInfo(); - const userID = userInfo.id; const title = mark.title; if ( @@ -486,35 +490,55 @@ async function handleWeightings(mark: any, api: any) { }; try { - const filename = - "BetterSEQTA-" + - String(Math.floor(Math.random() * 1e15)).padStart(15, "0"); + let pdfUrl: string; - const printResponse = await fetch( - `${location.origin}/seqta/student/print/assessment`, - { - method: "POST", - headers: { "Content-Type": "application/json; charset=utf-8" }, - credentials: "include", - body: JSON.stringify({ - fileName: filename, - id: assessmentID, - metaclass: metaclassID, - student: userID, - }), - }, - ); + if (isSeqtaEngageExperience()) { + const studentID = getEngageAssessmentStudentId(); + if (!studentID) { + throw new Error("Could not resolve Engage student ID from URL or storage"); + } - if (!printResponse.ok) { - throw new Error( - `Failed to generate PDF: ${printResponse.status} ${printResponse.statusText}`, + const reportFile = await requestEngageAssessmentPdf({ + assessmentID, + metaclassID, + studentID, + }); + await new Promise((resolve) => setTimeout(resolve, 1000)); + pdfUrl = getEngageAssessmentReportUrl(reportFile); + } else { + const userInfo = await getUserInfo(); + const userID = userInfo.id; + + const filename = + "BetterSEQTA-" + + String(Math.floor(Math.random() * 1e15)).padStart(15, "0"); + + const printResponse = await fetch( + `${location.origin}/seqta/student/print/assessment`, + { + method: "POST", + headers: { "Content-Type": "application/json; charset=utf-8" }, + credentials: "include", + body: JSON.stringify({ + fileName: filename, + id: assessmentID, + metaclass: metaclassID, + student: userID, + }), + }, ); + + if (!printResponse.ok) { + throw new Error( + `Failed to generate PDF: ${printResponse.status} ${printResponse.statusText}`, + ); + } + + await new Promise((resolve) => setTimeout(resolve, 1000)); + + pdfUrl = `${location.origin}/seqta/student/report/get?file=${filename}`; } - await new Promise((resolve) => setTimeout(resolve, 1000)); - - const pdfUrl = `${location.origin}/seqta/student/report/get?file=${filename}`; - if (pdfUrl.startsWith("blob:")) { throw new Error(`Cannot fetch blob URL from extension: ${pdfUrl}`); }