diff --git a/controllers/liturgicalDayController.js b/controllers/liturgicalDayController.js new file mode 100644 index 0000000..6db04be --- /dev/null +++ b/controllers/liturgicalDayController.js @@ -0,0 +1,154 @@ +const { LiturgicalDay } = require('../models'); +const { Op } = require('sequelize'); +const axios = require('axios'); + +// Alle liturgischen Tage abrufen +const getAllLiturgicalDays = async (req, res) => { + try { + const days = await LiturgicalDay.findAll({ + order: [['date', 'ASC']] + }); + res.status(200).json(days); + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Fehler beim Abrufen der liturgischen Tage' }); + } +}; + +// Eindeutige Namen für Multiselect abrufen +const getLiturgicalDayNames = async (req, res) => { + try { + const days = await LiturgicalDay.findAll({ + attributes: ['dayName'], + group: ['dayName'], + order: [['dayName', 'ASC']] + }); + const names = days.map(day => day.dayName); + res.status(200).json(names); + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Fehler beim Abrufen der Tag-Namen' }); + } +}; + +// HTML von liturgischem Kalender parsen und in DB speichern +const loadLiturgicalYear = async (req, res) => { + const { year } = req.body; + + if (!year) { + return res.status(400).json({ message: 'Jahr ist erforderlich' }); + } + + const currentYear = new Date().getFullYear(); + if (year < currentYear || year > currentYear + 2) { + return res.status(400).json({ message: 'Jahr muss zwischen aktuellem Jahr und 2 Jahren in der Zukunft liegen' }); + } + + try { + const url = `https://www.eike-fleer.de/liturgischer-kalender/${year}.htm`; + const response = await axios.get(url, { + headers: { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' + } + }); + + const html = response.data; + + // Parse HTML - suche nach Tabellenzeilen mit Datum und Name + // Format: "DD.MM.YYYY DayName" + const regex = /(\d{2}\.\d{2}\.\d{4})\s*(?: |\s)+(.+?)(?:<\/|$)/gi; + const matches = [...html.matchAll(regex)]; + + const liturgicalDays = []; + + for (const match of matches) { + const dateStr = match[1]; // DD.MM.YYYY + let dayName = match[2]; + + // Bereinige den Tag-Namen von HTML-Tags und Entities + dayName = dayName + .replace(/<[^>]*>/g, '') // Entferne HTML-Tags + .replace(/ /g, ' ') // Ersetze + .replace(/ä/g, 'ä') + .replace(/ö/g, 'ö') + .replace(/ü/g, 'ü') + .replace(/Ä/g, 'Ä') + .replace(/Ö/g, 'Ö') + .replace(/Ü/g, 'Ü') + .replace(/ß/g, 'ß') + .trim(); + + // Konvertiere Datum von DD.MM.YYYY zu YYYY-MM-DD + const [day, month, yearPart] = dateStr.split('.'); + const isoDate = `${yearPart}-${month}-${day}`; + + if (dayName && dayName.length > 0) { + liturgicalDays.push({ + date: isoDate, + dayName: dayName + }); + } + } + + if (liturgicalDays.length === 0) { + return res.status(500).json({ message: 'Keine liturgischen Tage gefunden. Möglicherweise hat sich das HTML-Format geändert.' }); + } + + // Speichere oder aktualisiere die Einträge + for (const day of liturgicalDays) { + await LiturgicalDay.upsert({ + date: day.date, + dayName: day.dayName + }); + } + + res.status(200).json({ + message: `${liturgicalDays.length} liturgische Tage für ${year} erfolgreich geladen`, + count: liturgicalDays.length + }); + } catch (error) { + console.error('Fehler beim Laden der liturgischen Tage:', error); + if (error.response && error.response.status === 404) { + return res.status(404).json({ message: `Liturgischer Kalender für ${year} nicht gefunden` }); + } + res.status(500).json({ message: 'Fehler beim Laden der liturgischen Tage', error: error.message }); + } +}; + +// Einzelnen Tag erstellen +const createLiturgicalDay = async (req, res) => { + try { + const day = await LiturgicalDay.create(req.body); + res.status(201).json(day); + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Fehler beim Erstellen des liturgischen Tags' }); + } +}; + +// Tag löschen +const deleteLiturgicalDay = async (req, res) => { + try { + const { id } = req.params; + const deleted = await LiturgicalDay.destroy({ + where: { id } + }); + if (deleted) { + res.status(200).json({ message: 'Liturgischer Tag erfolgreich gelöscht' }); + } else { + res.status(404).json({ message: 'Liturgischer Tag nicht gefunden' }); + } + } catch (error) { + console.error(error); + res.status(500).json({ message: 'Fehler beim Löschen des liturgischen Tags' }); + } +}; + +module.exports = { + getAllLiturgicalDays, + getLiturgicalDayNames, + loadLiturgicalYear, + createLiturgicalDay, + deleteLiturgicalDay +}; + diff --git a/migrations/20251007150137-create-liturgical-days.js b/migrations/20251007150137-create-liturgical-days.js new file mode 100644 index 0000000..49fe1fd --- /dev/null +++ b/migrations/20251007150137-create-liturgical-days.js @@ -0,0 +1,28 @@ +'use strict'; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up (queryInterface, Sequelize) { + await queryInterface.createTable('liturgical_days', { + id: { + type: Sequelize.INTEGER, + primaryKey: true, + autoIncrement: true, + allowNull: false + }, + date: { + type: Sequelize.DATEONLY, + allowNull: false, + unique: true + }, + dayName: { + type: Sequelize.STRING, + allowNull: false + } + }); + }, + + async down (queryInterface, Sequelize) { + await queryInterface.dropTable('liturgical_days'); + } +}; diff --git a/models/LiturgicalDay.js b/models/LiturgicalDay.js new file mode 100644 index 0000000..d89ba45 --- /dev/null +++ b/models/LiturgicalDay.js @@ -0,0 +1,24 @@ +module.exports = (sequelize, DataTypes) => { + const LiturgicalDay = sequelize.define('LiturgicalDay', { + id: { + type: DataTypes.INTEGER, + primaryKey: true, + autoIncrement: true + }, + date: { + type: DataTypes.DATEONLY, + allowNull: false, + unique: true + }, + dayName: { + type: DataTypes.STRING, + allowNull: false + } + }, { + tableName: 'liturgical_days', + timestamps: false + }); + + return LiturgicalDay; +}; + diff --git a/routes/liturgicalDays.js b/routes/liturgicalDays.js new file mode 100644 index 0000000..6c1ccce --- /dev/null +++ b/routes/liturgicalDays.js @@ -0,0 +1,19 @@ +const express = require('express'); +const router = express.Router(); +const { + getAllLiturgicalDays, + getLiturgicalDayNames, + loadLiturgicalYear, + createLiturgicalDay, + deleteLiturgicalDay +} = require('../controllers/liturgicalDayController'); +const authMiddleware = require('../middleware/authMiddleware'); + +router.get('/', getAllLiturgicalDays); +router.get('/names', getLiturgicalDayNames); +router.post('/load-year', authMiddleware, loadLiturgicalYear); +router.post('/', authMiddleware, createLiturgicalDay); +router.delete('/:id', authMiddleware, deleteLiturgicalDay); + +module.exports = router; + diff --git a/server.js b/server.js index c69645c..d4eb563 100644 --- a/server.js +++ b/server.js @@ -17,7 +17,8 @@ const worshipRouter = require('./routes/worships'); const pageRouter = require('./routes/pages'); const userRouter = require('./routes/users'); const imageRouter = require('./routes/image'); -const filesRouter = require('./routes/files'); +const filesRouter = require('./routes/files'); +const liturgicalDaysRouter = require('./routes/liturgicalDays'); const app = express(); const PORT = parseInt(process.env.PORT, 10) || 3000; @@ -56,6 +57,7 @@ app.use('/api/page-content', pageRouter); app.use('/api/users', userRouter); app.use('/api/image', imageRouter); app.use('/api/files', filesRouter); +app.use('/api/liturgical-days', liturgicalDaysRouter); const options = { key: fs.readFileSync('server.key'), diff --git a/src/content/admin/WorshipManagement.vue b/src/content/admin/WorshipManagement.vue index 5c5c6ad..71fe103 100644 --- a/src/content/admin/WorshipManagement.vue +++ b/src/content/admin/WorshipManagement.vue @@ -7,10 +7,29 @@ placeholder="Veranstaltungsort wählen"> - + - +