/* * Copyright (C) 2025 Jakub Žitník * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ import express from "express"; import path from "path"; const app = express(); import fs from "fs/promises"; import { getCurrentInterval } from "./scheduleRules.js"; import bodyParser from "body-parser"; const PORT = process.env.PORT || 3000; globalThis.File = class File {}; app.use(bodyParser.json()); app.get('/', async (req, res) => { const userAgent = req.headers['user-agent'] || ''; const isBrowser = /Mozilla|Chrome|Firefox|Safari|Edg/.test(userAgent); if (isBrowser) { res.sendFile(path.join(process.cwd(), "web", "public", "index.html")); } else { const dataStr = await fs.readFile(path.join(process.cwd(), "db", "v1.json"), "utf8"); const data = JSON.parse(dataStr); data["status"]["currentUpdateSchedule"] = getCurrentInterval(); res.json(data); } }); app.get('/versioned/v1', async (_, res) => { const dataStr = await fs.readFile(path.join(process.cwd(), "db", "v1.json"), "utf8"); const data = JSON.parse(dataStr); data["status"]["currentUpdateSchedule"] = getCurrentInterval(); res.json(data); }); app.get("/status", async (_, res) => { const dataStr = await fs.readFile(path.resolve("./volume/customState.json"), {encoding: "utf8"}); const data = JSON.parse(dataStr); if (data.working) { res.json({ working: true }) } else { res.json({ working: data.working, message: data.message }) } }) app.post("/report", async (req, res) => { const { class: className, location, content } = req.body; if (!className || !location || !content) { return res.status(400).json({ error: "Missing required fields." }); } if (!["TIMETABLE", "ABSENCES", "OTHER"].includes(location)) { return res.status(400).json({ error: "Invalid location value." }); } const url = `https://n8n.local.jzitnik.dev/webhook/${process.env.WEBHOOK_UUID}`; let resp; try { resp = await fetch(url, { method: "POST", headers: { "Content-Type": "text/plain", }, body: `${content}\n\nClass: ${className}\nLocation: ${location}`, }); } catch (err) { console.error('Fetch failed:', err.message); console.error(err); throw err; } if (!resp.ok) { throw new Error(`Request failed`); } res.status(200).json({ message: "Report received successfully." }); }); app.use(express.static(path.join(process.cwd(), 'web/public'), { index: 'index.html', extensions: ['html'], })); app.listen(PORT, () => { console.log(`Server is running at http://localhost:${PORT}`); });