♻️ Refactor backend and add comments
This commit is contained in:
@ -1,9 +1,9 @@
|
||||
import axios from "axios";
|
||||
const baseurl = "https://mobileapi.dsbcontrol.de";
|
||||
const baseUrl = "https://mobileapi.dsbcontrol.de";
|
||||
|
||||
export async function getAuthtoken(username, password) {
|
||||
const response = await axios.get(
|
||||
`${baseurl}/authid?user=${username}&password=${password}&bundleid&appversion&osversion&pushid`
|
||||
`${baseUrl}/authid?user=${username}&password=${password}&bundleid&appversion&osversion&pushid`
|
||||
);
|
||||
if (response.data == "") throw "Wrong username or password";
|
||||
return response.data;
|
||||
@ -11,13 +11,15 @@ export async function getAuthtoken(username, password) {
|
||||
|
||||
export async function getTimetables(authtoken) {
|
||||
const response = await axios.get(
|
||||
`${baseurl}/dsbtimetables?authid=${authtoken}`
|
||||
`${baseUrl}/dsbtimetables?authid=${authtoken}`
|
||||
);
|
||||
const timetables = response.data;
|
||||
|
||||
const urls = [];
|
||||
timetables.forEach((timetable) => {
|
||||
const rawTimestamp = timetable.Date;
|
||||
// Convert the timestamp to the correct
|
||||
// format so new Date() accepts it
|
||||
const date = rawTimestamp.split(" ")[0].split(".").reverse().join("-");
|
||||
const time = rawTimestamp.split(" ")[1];
|
||||
const timestamp = date + " " + time;
|
||||
|
@ -3,11 +3,9 @@ import axios from "axios";
|
||||
import { log, getLogPath } from "../logs.js";
|
||||
import { getAuthtoken, getTimetables } from "./dsbmobile.js";
|
||||
import { parseSubstitutionPlan } from "./untis.js";
|
||||
import fs from "fs";
|
||||
|
||||
const prisma = new Prisma.PrismaClient();
|
||||
|
||||
const dsbFiles = ["Schüler_Monitor - subst_001", "Schüler Morgen - subst_001"];
|
||||
const prisma = new Prisma.PrismaClient();
|
||||
|
||||
export class Parser {
|
||||
dsbUser;
|
||||
@ -16,22 +14,26 @@ export class Parser {
|
||||
this.dsbUser = dsbUser;
|
||||
this.dsbPassword = dsbPassword;
|
||||
|
||||
// Schedule plan updates
|
||||
setInterval(() => this.updatePlan(), interval);
|
||||
// Do the first update instantly
|
||||
this.updatePlan();
|
||||
}
|
||||
async updatePlan() {
|
||||
const startedAt = new Date();
|
||||
try {
|
||||
const data = await this.fetchDSB();
|
||||
if (!data) {
|
||||
throw "DSB request failed!";
|
||||
}
|
||||
if (!data) throw "DSB request failed!";
|
||||
|
||||
const plans = [];
|
||||
for (const entry of data) {
|
||||
// Download the substitution plan
|
||||
const data = await this.fetchFile(entry.url);
|
||||
// Parse the substitution plan
|
||||
const parsed = parseSubstitutionPlan(data);
|
||||
plans.push(parsed);
|
||||
}
|
||||
// Create a new parse event
|
||||
const parseEvent = await prisma.parseEvent.create({
|
||||
data: {
|
||||
logFile: getLogPath(),
|
||||
@ -40,10 +42,13 @@ export class Parser {
|
||||
succeeded: true,
|
||||
},
|
||||
});
|
||||
// Insert substitutions of all substitution plans
|
||||
for (const plan of plans) {
|
||||
await this.insertSubstitutions(plan, parseEvent);
|
||||
}
|
||||
} catch (error) {
|
||||
// If something went wrong, create a failed
|
||||
// parse event with the error message
|
||||
await prisma.parseEvent.create({
|
||||
data: {
|
||||
logFile: getLogPath(),
|
||||
@ -52,13 +57,16 @@ export class Parser {
|
||||
succeeded: false,
|
||||
},
|
||||
});
|
||||
// Log the error
|
||||
log("Parser / Main", "Parse event failed: " + error);
|
||||
}
|
||||
}
|
||||
async fetchDSB() {
|
||||
try {
|
||||
const token = await getAuthtoken(this.dsbUser, this.dsbPassword);
|
||||
// Fetch available files
|
||||
const response = await getTimetables(token);
|
||||
// Filter files that should be parsed
|
||||
const timetables = response.filter((e) => dsbFiles.includes(e.title));
|
||||
return timetables;
|
||||
} catch (error) {
|
||||
@ -78,7 +86,7 @@ export class Parser {
|
||||
return parseSubstitutionPlan(html);
|
||||
}
|
||||
async insertSubstitutions(parsedData, parseEvent) {
|
||||
const { updatedAt, date, changes } = parsedData;
|
||||
const { date, changes } = parsedData;
|
||||
const classList = await prisma.class.findMany();
|
||||
|
||||
const knownSubstitutions = await prisma.substitution.findMany({
|
||||
@ -88,16 +96,24 @@ export class Parser {
|
||||
},
|
||||
});
|
||||
|
||||
// Loop through every change of the substitution plan
|
||||
for (const change of changes) {
|
||||
// Find all classes the substitution belongs to
|
||||
const classes = this.getSubstitutionClasses(classList, change.class);
|
||||
// If the substitution does not belong to any classes known
|
||||
// by the server, use the provied class string instead
|
||||
if (classes.length == 0) classes.push(change.class || "unknown");
|
||||
|
||||
// Workaround no currect match possible for subsitutions of this
|
||||
// type beacuse they don't have a class and a subject attribute
|
||||
// Workaround: no correct match possible for subsitutions of this
|
||||
// type beacuse they do not have a class and a subject attribute
|
||||
if (change.type == "Sondereins." && !change.subject) {
|
||||
change.subject = change.notes;
|
||||
}
|
||||
|
||||
// Check if a substitution exists in the database that
|
||||
// it similar enough to the entry in the substitution
|
||||
// plan to be considered the same substitution
|
||||
// (Date, Type, Lesson, Classes and Subject need to be the same)
|
||||
const matchingSubstitutionId = knownSubstitutions.findIndex(
|
||||
(substitution) => {
|
||||
return substitution.date == new Date(date).setUTCHours(0, 0, 0, 0) &&
|
||||
@ -113,6 +129,7 @@ export class Parser {
|
||||
const matchingSubstitution = knownSubstitutions[matchingSubstitutionId];
|
||||
|
||||
if (!matchingSubstitution) {
|
||||
// If the substitution is new, create it in the database
|
||||
const newSubstitution = await prisma.substitution.create({
|
||||
data: {
|
||||
class: classes,
|
||||
@ -126,6 +143,7 @@ export class Parser {
|
||||
removed: false,
|
||||
},
|
||||
});
|
||||
// Also create a change entry for it
|
||||
const substitutionChange = await prisma.substitutionChange.create({
|
||||
data: {
|
||||
substitutionId: newSubstitution.id,
|
||||
@ -150,8 +168,10 @@ export class Parser {
|
||||
`Created new substitution: S:${newSubstitution.id} C:${substitutionChange.id}`
|
||||
);
|
||||
} else {
|
||||
// If the entry was updated, find the differences
|
||||
const differences = this.findDifferences(matchingSubstitution, change);
|
||||
if (Object.keys(differences).length > 0) {
|
||||
// If differences were found, update the entry in the database
|
||||
const prismaOptions = {
|
||||
where: {
|
||||
id: matchingSubstitution.id,
|
||||
@ -164,6 +184,7 @@ export class Parser {
|
||||
if (differences.notes) prismaOptions.data.notes = change.notes;
|
||||
|
||||
await prisma.substitution.update(prismaOptions);
|
||||
// And create a change event for it
|
||||
const substitutionChange = await prisma.substitutionChange.create({
|
||||
data: {
|
||||
substitutionId: matchingSubstitution.id,
|
||||
@ -182,9 +203,13 @@ export class Parser {
|
||||
`Substitution unchanged: S:${matchingSubstitution.id}`
|
||||
);
|
||||
}
|
||||
// Remove the substitution from the array to later know the
|
||||
// entries that are not present in the substitution plan
|
||||
knownSubstitutions.splice(matchingSubstitutionId, 1);
|
||||
}
|
||||
}
|
||||
// Mark all entries as removed that were
|
||||
// not found in the substitution plan
|
||||
for (const remainingSubstitution of knownSubstitutions) {
|
||||
await prisma.substitution.update({
|
||||
where: {
|
||||
|
Reference in New Issue
Block a user