aboutsummaryrefslogtreecommitdiff
path: root/src/database.js
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2026-08-03 14:31:25 +0200
committerFlorian Fischer <florian.fischer@muhq.space>2026-08-03 14:31:25 +0200
commit6839831af54cd9302119bcc3bffafe10475958d4 (patch)
tree12a1c1fbd864e9579cb9c3a09d4bf4686a280b73 /src/database.js
parentfccb70cbd876785f6833dfe6efc10ec9e445556d (diff)
downloadbycs-sol-6839831af54cd9302119bcc3bffafe10475958d4.tar.gz
bycs-sol-6839831af54cd9302119bcc3bffafe10475958d4.zip
refactor project structure
* merge sites into single project root * fix name of mass-graduation site * enable typescript support
Diffstat (limited to 'src/database.js')
-rw-r--r--src/database.js160
1 files changed, 160 insertions, 0 deletions
diff --git a/src/database.js b/src/database.js
new file mode 100644
index 0000000..e929896
--- /dev/null
+++ b/src/database.js
@@ -0,0 +1,160 @@
+import { getCourseId } from "./utils-ENV.js";
+
+const DB_TEMPLATE_LIST_HEADER = `
+<table class="table table-striped">
+ <thead>
+ <tr>
+ <th>Json</th>
+ </tr>
+ </thead>
+ <tbody>
+`;
+const DB_TEMPLATE_LIST_ENTRY = `
+<tr class="db-row">
+ <td class="db-cell" data-key="date">##timeadded##</td>
+ <td class="db-cell" data-key="coach">##user##</td>
+ <td class="db-cell" data-key="json">[[Json]]</td>
+</tr>
+`;
+const DB_TEMPLATE_LIST_FOOTER = `
+ </tbody>
+</table>
+`;
+
+let studentDbs = populateStudentDbs();
+
+const ID_QUERY_PARAM_REGEX = /[?&]id=(\d+)/
+
+async function populateStudentDbs() {
+ const courseUrl = `https://lernplattform.bycs.de/course/view.php?id=${getCourseId()}`;
+ const courseRes = await fetch(courseUrl);
+ const courseDoc = new DOMParser().parseFromString(await courseRes.text(), 'text/html');
+
+ let dbs = new Map();
+ for (const link of courseDoc.querySelectorAll("div.activityname a.aalink")) {
+ if (link.textContent.trim() === "Submit Datenbank") {
+ const dbId = link.href.match(ID_QUERY_PARAM_REGEX)[1]
+ dbs.set("submit", new DB(dbId));
+ continue;
+ }
+
+ const match = link.textContent.match(/(\d+)(Shadow|Public|Submit)/);
+ if (!match) continue;
+ const studentId = match[1];
+ const dbType = match[2];
+ const dbId = link.href.match(ID_QUERY_PARAM_REGEX)[1]
+
+ if (!dbs.has(studentId)) {
+ dbs.set(studentId, {});
+ }
+
+ dbs.get(studentId)[dbType.toLowerCase()] = new DB(dbId);
+ }
+
+ return dbs;
+}
+
+async function getSubmitDb() {
+ const dbs = await studentDbs;
+ return dbs.get("submit");
+}
+
+class DB {
+ constructor(id) {
+ this.id = id;
+ }
+
+ async fetchEntries(params) {
+ return loadFromDatabaseActivity(this.id, params)
+ }
+
+ async saveEntry(json) {
+ return addEntryToDatabaseActivity(this.id, json);
+ }
+
+ static async getStudentDbs(student) {
+ const dbs = await studentDbs;
+ return dbs.get(student.id);
+ }
+}
+
+async function loadFromDatabaseActivity(id, params) {
+ let dbUrl = `${window.location.origin}/mod/data/view.php?id=${id}&mode=list&perpage=1000`;
+ // TODO(muhq): Why does this not include entries?
+ if (params) {
+ dbUrl += "&filter=1&advanced=1";
+ for (const param in params) {
+ dbUrl += `&${param}=${encodeURIComponent(params[param])}`
+ }
+ }
+
+ const dbRes = await fetch(encodeURI(dbUrl));
+ const dbDoc = new DOMParser().parseFromString(await dbRes.text(), 'text/html');
+ let data = [];
+ dbDoc.querySelectorAll('.db-row').forEach(row => {
+ let entry = {};
+ row.querySelectorAll('.db-cell').forEach(field => {
+ const key = field.dataset.key;
+ let value;
+ // Moodle includes the full date in the title attribute of the included span
+ if (key === "date") {
+ value = field.querySelector("span").title;
+ } else {
+ value = field.innerText.trim();
+ }
+ entry[key] = value;
+ });
+ data.push(entry);
+ });
+ return data;
+}
+
+async function loadFromStudentDatabase(student, type) {
+ const dbs = await DB.getStudentDbs(student);
+ const db = dbs[type];
+ return await db.fetchEntries()
+}
+
+async function addEntryToDatabaseActivity(id, json) {
+ const url = `/mod/data/edit.php?id=${id}`;
+ const editRes = await fetch(url);
+ const editDoc = new DOMParser().parseFromString(await editRes.text(), 'text/html');
+ const form = editDoc.querySelector('div[role="main"] > form');
+
+ const formData = new FormData(form);
+
+ for (const key of formData.keys()) {
+ if (key.startsWith("field_")) {
+ formData.set(key, json);
+ // We found our json key
+ break;
+ }
+ }
+ formData.set("saveandview", "Speichern");
+
+ return await fetch("/mod/data/edit.php", {
+ method: "POST",
+ // Set the FormData instance as the request body
+ body: formData,
+ });
+}
+
+async function addEntryToStudentDatabase(student, type, json) {
+ let db;
+ // global submit database
+ if (type === "submit") {
+ db = await getSubmitDb();
+ // individuell databases
+ } else {
+ const dbs = await DB.getStudentDbs(student);
+ db = dbs[type];
+ }
+ await db.saveEntry(json);
+}
+
+export {
+ DB,
+ getSubmitDb,
+ loadFromDatabaseActivity, loadFromStudentDatabase,
+ addEntryToDatabaseActivity, addEntryToStudentDatabase,
+};