mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-05 19:24:39 +00:00
feat: Assessments Average weightings parsing
ONLY PARSING SIDE IS COMPLETE. Does not factor into the average yet.
This commit is contained in:
@@ -93,6 +93,7 @@
|
|||||||
"mathjs": "^14.4.0",
|
"mathjs": "^14.4.0",
|
||||||
"million": "^3.1.11",
|
"million": "^3.1.11",
|
||||||
"motion": "^12.4.12",
|
"motion": "^12.4.12",
|
||||||
|
"pdfjs-dist": "^5.4.530",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
"react": "17",
|
"react": "17",
|
||||||
"react-best-gradient-color-picker": "3.0.11",
|
"react-best-gradient-color-picker": "3.0.11",
|
||||||
|
|||||||
@@ -7,6 +7,16 @@ import {
|
|||||||
import { type Plugin } from "@/plugins/core/types";
|
import { type Plugin } from "@/plugins/core/types";
|
||||||
import stringToHTML from "@/seqta/utils/stringToHTML";
|
import stringToHTML from "@/seqta/utils/stringToHTML";
|
||||||
import { waitForElm } from "@/seqta/utils/waitForElm";
|
import { waitForElm } from "@/seqta/utils/waitForElm";
|
||||||
|
import ReactFiber from "@/seqta/utils/ReactFiber.ts";
|
||||||
|
import { getUserInfo } from "@/seqta/ui/AddBetterSEQTAElements.ts";
|
||||||
|
import * as pdfjs from "pdfjs-dist";
|
||||||
|
pdfjs.GlobalWorkerOptions.workerSrc =
|
||||||
|
"https://cdn.jsdelivr.net/npm/pdfjs-dist/build/pdf.worker.min.mjs";
|
||||||
|
|
||||||
|
// Storage
|
||||||
|
interface weightingsStorage {
|
||||||
|
weightings: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
const settings = defineSettings({
|
const settings = defineSettings({
|
||||||
lettergrade: booleanSetting({
|
lettergrade: booleanSetting({
|
||||||
@@ -23,7 +33,7 @@ class AssessmentsAveragePluginClass extends BasePlugin<typeof settings> {
|
|||||||
|
|
||||||
const instance = new AssessmentsAveragePluginClass();
|
const instance = new AssessmentsAveragePluginClass();
|
||||||
|
|
||||||
const assessmentsAveragePlugin: Plugin<typeof settings> = {
|
const assessmentsAveragePlugin: Plugin<typeof settings, weightingsStorage> = {
|
||||||
id: "assessments-average",
|
id: "assessments-average",
|
||||||
name: "Assessment Averages",
|
name: "Assessment Averages",
|
||||||
description: "Adds an average grade to the Assessments page",
|
description: "Adds an average grade to the Assessments page",
|
||||||
@@ -32,8 +42,13 @@ const assessmentsAveragePlugin: Plugin<typeof settings> = {
|
|||||||
settings: instance.settings,
|
settings: instance.settings,
|
||||||
|
|
||||||
run: async (api) => {
|
run: async (api) => {
|
||||||
|
await api.storage.loaded;
|
||||||
|
|
||||||
|
if (!api.storage.weightings) {
|
||||||
|
api.storage.weightings = {};
|
||||||
|
}
|
||||||
|
|
||||||
api.seqta.onMount(".assessmentsWrapper", async () => {
|
api.seqta.onMount(".assessmentsWrapper", async () => {
|
||||||
// Wait for any assessment item to load first
|
|
||||||
await waitForElm(
|
await waitForElm(
|
||||||
"#main > .assessmentsWrapper .assessments [class*='AssessmentItem__AssessmentItem___']",
|
"#main > .assessmentsWrapper .assessments [class*='AssessmentItem__AssessmentItem___']",
|
||||||
true,
|
true,
|
||||||
@@ -41,6 +56,8 @@ const assessmentsAveragePlugin: Plugin<typeof settings> = {
|
|||||||
1000,
|
1000,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await parseAssessments(api);
|
||||||
|
|
||||||
// Helper function to find actual class names by their base pattern
|
// Helper function to find actual class names by their base pattern
|
||||||
const getClassByPattern = (
|
const getClassByPattern = (
|
||||||
element: Element | Document,
|
element: Element | Document,
|
||||||
@@ -201,4 +218,78 @@ const assessmentsAveragePlugin: Plugin<typeof settings> = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function extractPDFText(url: string): Promise<string> {
|
||||||
|
const loadingTask = pdfjs.getDocument(url);
|
||||||
|
const pdf = await loadingTask.promise;
|
||||||
|
|
||||||
|
let text = "";
|
||||||
|
|
||||||
|
for (let i = 1; i <= pdf.numPages; i++) {
|
||||||
|
const page = await pdf.getPage(i);
|
||||||
|
const content = await page.getTextContent();
|
||||||
|
text += content.items.map((item: any) => item.str).join(" ") + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleWeightings(mark: any, api: any) {
|
||||||
|
const assessmentID = mark.id;
|
||||||
|
const metaclassID = mark.metaclassID;
|
||||||
|
const userInfo = await getUserInfo();
|
||||||
|
const userID = userInfo.id;
|
||||||
|
if (api.storage.weightings[assessmentID] != undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
api.storage.weightings = {
|
||||||
|
...api.storage.weightings,
|
||||||
|
[assessmentID]: "processing",
|
||||||
|
};
|
||||||
|
|
||||||
|
const filename =
|
||||||
|
"BetterSEQTA-" + String(Math.floor(Math.random() * 1e15)).padStart(15, "0");
|
||||||
|
|
||||||
|
await fetch(`${location.origin}/seqta/student/print/assessment`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "Content-Type": "application/json; charset=utf-8" },
|
||||||
|
body: JSON.stringify({
|
||||||
|
fileName: filename,
|
||||||
|
id: assessmentID,
|
||||||
|
metaclass: metaclassID,
|
||||||
|
student: userID,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
const pdfUrl = `${location.origin}/seqta/student/report/get?file=${filename}`;
|
||||||
|
const text = await extractPDFText(pdfUrl);
|
||||||
|
|
||||||
|
// Use regex to find the line "Assessment weight: X"
|
||||||
|
const match = text.match(/Assessment weight:\s*(\d+\.?\d*)/i);
|
||||||
|
const weight = match ? match[1] : "N/A";
|
||||||
|
|
||||||
|
// Save it to storage
|
||||||
|
api.storage.weightings = {
|
||||||
|
...api.storage.weightings,
|
||||||
|
[assessmentID]: weight,
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log(`Assessment ID ${assessmentID} weight:`, weight);
|
||||||
|
|
||||||
|
console.log(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function parseAssessments(api: any) {
|
||||||
|
const state = await ReactFiber.find(
|
||||||
|
"[class*='AssessmentList__items___']",
|
||||||
|
).getState();
|
||||||
|
|
||||||
|
const marks = state["marks"];
|
||||||
|
if (!marks) return;
|
||||||
|
|
||||||
|
for (const mark of marks) {
|
||||||
|
await handleWeightings(mark, api);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export default assessmentsAveragePlugin;
|
export default assessmentsAveragePlugin;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ let cachedUserInfo: any = null;
|
|||||||
|
|
||||||
let LightDarkModeSnakeEggButton = 0;
|
let LightDarkModeSnakeEggButton = 0;
|
||||||
|
|
||||||
async function getUserInfo() {
|
export async function getUserInfo() {
|
||||||
if (cachedUserInfo) return cachedUserInfo;
|
if (cachedUserInfo) return cachedUserInfo;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user