Compare commits
3 Commits
0325ce1815
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
1f30cda90a
|
|||
|
9d8db43cd4
|
|||
|
6b383b1af4
|
5
package-lock.json
generated
5
package-lock.json
generated
@@ -7,7 +7,7 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "jecnarozvrh",
|
"name": "jecnarozvrh",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "GPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"body-parser": "^2.2.0",
|
"body-parser": "^2.2.0",
|
||||||
"cheerio": "^1.1.2",
|
"cheerio": "^1.1.2",
|
||||||
@@ -947,8 +947,7 @@
|
|||||||
"version": "0.0.1452169",
|
"version": "0.0.1452169",
|
||||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1452169.tgz",
|
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1452169.tgz",
|
||||||
"integrity": "sha512-FOFDVMGrAUNp0dDKsAU1TorWJUx2JOU1k9xdgBKKJF3IBh/Uhl2yswG5r3TEAOrCiGY2QRp1e6LVDQrCsTKO4g==",
|
"integrity": "sha512-FOFDVMGrAUNp0dDKsAU1TorWJUx2JOU1k9xdgBKKJF3IBh/Uhl2yswG5r3TEAOrCiGY2QRp1e6LVDQrCsTKO4g==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/dom-serializer": {
|
"node_modules/dom-serializer": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
|||||||
@@ -12,8 +12,8 @@
|
|||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import parseV1 from "./parse/v1.js";
|
import parseV1V2 from "./parse/v1_v2.js";
|
||||||
|
|
||||||
export default async function parseThisShit(downloadedFilePath) {
|
export default async function parseThisShit(downloadedFilePath) {
|
||||||
await parseV1(downloadedFilePath)
|
await parseV1V2(downloadedFilePath)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import fs from "fs"
|
|||||||
import parseAbsence from "../utils/parseAbsence.js"
|
import parseAbsence from "../utils/parseAbsence.js"
|
||||||
import parseTeachers from "../utils/parseTeachers.js"
|
import parseTeachers from "../utils/parseTeachers.js"
|
||||||
|
|
||||||
export default async function parseV1(downloadedFilePath) {
|
export default async function parseV1V2(downloadedFilePath) {
|
||||||
const workbook = new ExcelJS.Workbook();
|
const workbook = new ExcelJS.Workbook();
|
||||||
await workbook.xlsx.readFile(downloadedFilePath);
|
await workbook.xlsx.readFile(downloadedFilePath);
|
||||||
const teacherMap = await parseTeachers();
|
const teacherMap = await parseTeachers();
|
||||||
@@ -216,7 +216,29 @@ export default async function parseV1(downloadedFilePath) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fs.writeFileSync("db/v1.json", JSON.stringify(data, null, 2));
|
fs.writeFileSync("db/v2.json", JSON.stringify(data, null, 2));
|
||||||
|
|
||||||
|
// Modify the data for v1
|
||||||
|
const copy = JSON.parse(JSON.stringify(data));
|
||||||
|
|
||||||
|
copy.schedule.forEach(day => {
|
||||||
|
if (!Array.isArray(day.ABSENCE)) return;
|
||||||
|
|
||||||
|
day.ABSENCE = day.ABSENCE.map(old => {
|
||||||
|
if (old.type === "zastoupen") {
|
||||||
|
return {
|
||||||
|
type: "invalid",
|
||||||
|
teacher: null,
|
||||||
|
teacherCode: null,
|
||||||
|
hours: null,
|
||||||
|
original: `za ${old.teacherCode.toUpperCase()} zastupuje ${old.zastupuje.teacherCode.toUpperCase()}`
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return old;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
fs.writeFileSync("db/v1.json", JSON.stringify(copy, null, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
//parseThisShit("downloads/table.xlsx")
|
//parseV1V2("db/current.xlsx")
|
||||||
@@ -98,6 +98,7 @@ export default function parseAbsence(input, teacherMap = {}) {
|
|||||||
const markConsumed = (start, end) => consumed.push([start, end]);
|
const markConsumed = (start, end) => consumed.push([start, end]);
|
||||||
const isConsumed = (i) => consumed.some(([a, b]) => i >= a && i < b);
|
const isConsumed = (i) => consumed.some(([a, b]) => i >= a && i < b);
|
||||||
|
|
||||||
|
// 1. Teachers with specific hours (e.g. "Ab 1-4")
|
||||||
const teacherListThenSpecRe =
|
const teacherListThenSpecRe =
|
||||||
/([A-Za-z]+(?:[,;]\s?[A-Za-z]+)*)(?:\s*)(\d+(?:\+|-\d+|,\d+)?)(?![A-Za-z])/g;
|
/([A-Za-z]+(?:[,;]\s?[A-Za-z]+)*)(?:\s*)(\d+(?:\+|-\d+|,\d+)?)(?![A-Za-z])/g;
|
||||||
|
|
||||||
@@ -115,6 +116,7 @@ export default function parseAbsence(input, teacherMap = {}) {
|
|||||||
markConsumed(matchStart, matchEnd);
|
markConsumed(matchStart, matchEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 2. Teachers with "-exk" suffix
|
||||||
const teacherExkRe = /([A-Za-z]+)-exk/gi;
|
const teacherExkRe = /([A-Za-z]+)-exk/gi;
|
||||||
while ((m = teacherExkRe.exec(s)) !== null) {
|
while ((m = teacherExkRe.exec(s)) !== null) {
|
||||||
const matchStart = m.index;
|
const matchStart = m.index;
|
||||||
@@ -132,7 +134,34 @@ export default function parseAbsence(input, teacherMap = {}) {
|
|||||||
markConsumed(matchStart, matchEnd);
|
markConsumed(matchStart, matchEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standalone teachers → whole day
|
// ---------------------------------------------------------
|
||||||
|
// 3. Substitution Pattern: "za Vn zastupuje Jk"
|
||||||
|
// ---------------------------------------------------------
|
||||||
|
const substitutionRe = /za\s+([A-Za-z]+)\s+zastupuje\s+([A-Za-z]+)/gi;
|
||||||
|
while ((m = substitutionRe.exec(s)) !== null) {
|
||||||
|
const matchStart = m.index;
|
||||||
|
const matchEnd = substitutionRe.lastIndex;
|
||||||
|
if (isConsumed(matchStart)) continue;
|
||||||
|
|
||||||
|
const missingCode = m[1];
|
||||||
|
const substituteCode = m[2];
|
||||||
|
|
||||||
|
const missingResolved = resolveTeacher(missingCode, teacherMap);
|
||||||
|
const subResolved = resolveTeacher(substituteCode, teacherMap);
|
||||||
|
|
||||||
|
results.push({
|
||||||
|
teacher: missingResolved.name,
|
||||||
|
teacherCode: missingResolved.code.toLowerCase(),
|
||||||
|
type: "zastoupen",
|
||||||
|
zastupuje: {
|
||||||
|
teacher: subResolved.name,
|
||||||
|
teacherCode: subResolved.code.toLowerCase()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
markConsumed(matchStart, matchEnd);
|
||||||
|
}
|
||||||
|
|
||||||
const teacherOnlyRe = /([A-Za-z]+(?:[,;]\s?[A-Za-z]+)*)/g;
|
const teacherOnlyRe = /([A-Za-z]+(?:[,;]\s?[A-Za-z]+)*)/g;
|
||||||
while ((m = teacherOnlyRe.exec(s)) !== null) {
|
while ((m = teacherOnlyRe.exec(s)) !== null) {
|
||||||
const matchStart = m.index;
|
const matchStart = m.index;
|
||||||
@@ -141,6 +170,9 @@ export default function parseAbsence(input, teacherMap = {}) {
|
|||||||
|
|
||||||
const tList = m[1].split(/[,;]\s*/).filter(Boolean);
|
const tList = m[1].split(/[,;]\s*/).filter(Boolean);
|
||||||
tList.forEach((t) => {
|
tList.forEach((t) => {
|
||||||
|
const lowerT = t.toLowerCase();
|
||||||
|
if (lowerT === 'za' || lowerT === 'zastupuje') return;
|
||||||
|
|
||||||
if (isTeacherToken(t)) results.push(makeResult(t, null, teacherMap));
|
if (isTeacherToken(t)) results.push(makeResult(t, null, teacherMap));
|
||||||
else
|
else
|
||||||
results.push({
|
results.push({
|
||||||
@@ -154,12 +186,12 @@ export default function parseAbsence(input, teacherMap = {}) {
|
|||||||
markConsumed(matchStart, matchEnd);
|
markConsumed(matchStart, matchEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bare specs without teacher → invalid
|
// 5. Bare specs without teacher → invalid
|
||||||
const specOnlyRe = /\b(\d+(?:\+|-\d+|,\d+)?)\b/g;
|
const specOnlyRe = /\b(\d+(?:\+|-\d+|,\d+)?)\b/g;
|
||||||
while ((m = specOnlyRe.exec(s)) !== null) {
|
while ((m = specOnlyRe.exec(s)) !== null) {
|
||||||
const matchStart = m.index;
|
const matchStart = m.index;
|
||||||
if (isConsumed(matchStart)) continue;
|
if (isConsumed(matchStart)) continue;
|
||||||
if (m[1].trim() == "exk") continue; // Exkurze, will be implemented later
|
if (m[1].trim() == "exk") continue;
|
||||||
|
|
||||||
results.push({
|
results.push({
|
||||||
type: "invalid",
|
type: "invalid",
|
||||||
|
|||||||
18
server.js
18
server.js
@@ -19,6 +19,7 @@ import fs from "fs/promises";
|
|||||||
import { getCurrentInterval } from "./scheduleRules.js";
|
import { getCurrentInterval } from "./scheduleRules.js";
|
||||||
import bodyParser from "body-parser";
|
import bodyParser from "body-parser";
|
||||||
|
|
||||||
|
const VERSIONS = ["v1", "v2"];
|
||||||
const PORT = process.env.PORT || 3000;
|
const PORT = process.env.PORT || 3000;
|
||||||
|
|
||||||
globalThis.File = class File {};
|
globalThis.File = class File {};
|
||||||
@@ -50,6 +51,23 @@ app.get('/versioned/v1', async (_, res) => {
|
|||||||
res.json(data);
|
res.json(data);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
VERSIONS.forEach((version) => {
|
||||||
|
app.get(`/versioned/${version}`, async (_, res) => {
|
||||||
|
try {
|
||||||
|
const filePath = path.join(process.cwd(), "db", `${version}.json`);
|
||||||
|
const dataStr = await fs.readFile(filePath, "utf8");
|
||||||
|
const data = JSON.parse(dataStr);
|
||||||
|
|
||||||
|
data.status.currentUpdateSchedule = getCurrentInterval();
|
||||||
|
|
||||||
|
res.json(data);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err);
|
||||||
|
res.status(500).json({ error: "Failed to load version data" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
app.get("/status", async (_, res) => {
|
app.get("/status", async (_, res) => {
|
||||||
const dataStr = await fs.readFile(path.resolve("./volume/customState.json"), {encoding: "utf8"});
|
const dataStr = await fs.readFile(path.resolve("./volume/customState.json"), {encoding: "utf8"});
|
||||||
const data = JSON.parse(dataStr);
|
const data = JSON.parse(dataStr);
|
||||||
|
|||||||
@@ -228,6 +228,18 @@ test("Me-exk", [
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
|
test("za Vn zastupuje Jk", [
|
||||||
|
{
|
||||||
|
teacher: "Ing. Zdeněk Vondra",
|
||||||
|
teacherCode: "vn",
|
||||||
|
type: "zastoupen",
|
||||||
|
zastupuje: {
|
||||||
|
teacher: "David Janoušek",
|
||||||
|
teacherCode: "jk"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
function test(input, expectedOutput) {
|
function test(input, expectedOutput) {
|
||||||
const res = parseAbsence(input, teachermap);
|
const res = parseAbsence(input, teachermap);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user