import { assert } from "./assert.ts";
import { getCourseId, getSesskey } from "./utils-ENV.js";
const DB_TEMPLATE_LIST_HEADER = `
| ChangeId |
Date |
Coach |
Json |
`;
const DB_TEMPLATE_LIST_ENTRY = `
| ##id## |
##timeadded## |
##user## |
[[Json]] |
`;
const DB_TEMPLATE_LIST_FOOTER = `
`;
let graduationDb = findGraduationDb();
const ID_QUERY_PARAM_REGEX = /[?&]id=(\d+)/;
async function findGraduationDb() {
let graduationDbId = localStorage.getItem("gruaduationDbId");
if (graduationDbId !== null) {
return new DB(Number(graduationDbId));
}
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");
for (const a of courseDoc.querySelectorAll("div.activityname a.aalink")) {
if (a.textContent.trim() === "Graduation Datenbank") {
const anchor = a as HTMLAnchorElement;
const match = anchor.href.match(ID_QUERY_PARAM_REGEX);
if (match === null) continue;
const dbId = match[1];
localStorage.setItem("graduationDbId", dbId);
return new DB(Number(dbId));
}
}
assert(false, "Graduation DB not found");
}
interface DatabaseParams {
[key: string]: string;
}
interface DatabaseEntry {
[key: string]: string;
}
class DB {
id: number;
d: Promise | null = null;
constructor(id: number, d?: number) {
this.id = id;
if (typeof d !== "undefined") {
this.d = new Promise((resolve) => {
resolve(d);
});
}
}
async fetchEntries(params?: DatabaseParams) {
return loadFromDatabaseActivity(this, params);
}
async saveEntry(json: string) {
return addEntryToDatabaseActivity(this, json);
}
async deleteEntries(entryIds: [number]) {
return deleteFromDatabaseActivity(await this.getD(), entryIds);
}
async getD() {
if (this.d === null) this.d = fetchDFromDatabaseActivity(this);
return this.d;
}
}
const dRegex = /d=(\d+)/;
function getDFromDbDoc(db: DB, dbDoc: Document) {
const urlWithD = dbDoc.querySelector('input[name="pageurl"]')!.value;
const match = dRegex.exec(urlWithD);
if (match === null) {
console.error(`d of database ${db.id} not found`);
return -1;
}
return Number(match[1]);
}
async function fetchDFromDatabaseActivity(db: DB): Promise {
let dbUrl = `${window.location.origin}/mod/data/view.php?id=${db.id}`;
const dbRes = await fetch(encodeURI(dbUrl));
const dbDoc = new DOMParser().parseFromString(await dbRes.text(), "text/html");
return getDFromDbDoc(db, dbDoc);
}
async function loadFromDatabaseActivity(db: DB, params?: DatabaseParams) {
let dbUrl = `${window.location.origin}/mod/data/view.php?id=${db.id}&mode=list&perpage=1000`;
// TODO(muhq): Why does this not include entries?
if (typeof params !== "undefined") {
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");
if (db.d === null) {
db.d = new Promise((resolve) => {
resolve(getDFromDbDoc(db, dbDoc));
});
}
let data: any[] = [];
dbDoc.querySelectorAll(".db-row").forEach((row) => {
let entry: DatabaseEntry = {};
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 getGraduationDb() {
return (await graduationDb)!;
}
async function addEntryToDatabaseActivity(db: DB, json: string) {
// TODO(muhq): do not fetch the form
const url = `/mod/data/edit.php?id=${db.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",
body: formData,
});
}
async function deleteFromDatabaseActivity(d: number, entryIds: [number]) {
const promises = [];
assert(d != -1, "DB has no valid d yet.");
for (const entryId of entryIds) {
const formData = new FormData();
formData.set("d", String(d));
formData.set("sesskey", getSesskey());
formData.set("confirm", "1");
formData.set("delete", String(entryId));
promises.push(
fetch("/mod/data/view.php", {
method: "POST",
body: formData,
}),
);
}
return Promise.all(promises);
}
export { DB, DatabaseEntry, DatabaseParams, getGraduationDb };