This commit is contained in:
2026-01-30 10:44:07 +01:00
commit a1ddaf5a35
37 changed files with 16573 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
// Feiertage-Service: Lädt Feiertage aus DB oder von feiertage-api.de (BW), speichert in public_holidays
const https = require('https');
const { db } = require('../database');
const API_BASE = 'https://feiertage-api.de/api/';
const LAND = 'BW';
/**
* Holt Feiertage für ein Jahr von der API und speichert sie in der DB.
* @param {number} year
* @returns {Promise<Set<string>>} Set von Datums-Strings YYYY-MM-DD
*/
function fetchHolidaysFromAPI(year) {
return new Promise((resolve, reject) => {
const url = `${API_BASE}?jahr=${year}&nur_land=${LAND}`;
https.get(url, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
try {
const json = JSON.parse(data);
const dates = new Set();
const toInsert = [];
for (const [name, obj] of Object.entries(json)) {
if (obj && obj.datum) {
dates.add(obj.datum);
toInsert.push({ date: obj.datum, name: name || null });
}
}
if (toInsert.length === 0) {
resolve(dates);
return;
}
let pending = toInsert.length;
toInsert.forEach(({ date, name }) => {
db.run('INSERT OR REPLACE INTO public_holidays (date, name) VALUES (?, ?)', [date, name], (err) => {
if (err) console.warn('Feiertage: Fehler beim Speichern:', err.message);
pending--;
if (pending === 0) resolve(dates);
});
});
} catch (e) {
reject(e);
}
});
}).on('error', reject);
});
}
/**
* Liest Feiertage für ein Jahr aus der DB.
* @param {number} year
* @returns {Promise<Set<string>>}
*/
function getHolidaysFromDB(year) {
return new Promise((resolve, reject) => {
const pattern = `${year}-%`;
db.all('SELECT date FROM public_holidays WHERE date LIKE ?', [pattern], (err, rows) => {
if (err) return reject(err);
const set = new Set((rows || []).map((r) => r.date));
resolve(set);
});
});
}
/**
* Liefert alle Feiertage für ein Jahr. Zuerst DB; wenn Jahr fehlt, API aufrufen und in DB schreiben.
* @param {number} year
* @returns {Promise<Set<string>>} Set von YYYY-MM-DD
*/
function getHolidaysForYear(year) {
return getHolidaysFromDB(year).then((set) => {
if (set.size > 0) return set;
return fetchHolidaysFromAPI(year).catch((err) => {
console.warn('Feiertage API fehlgeschlagen für Jahr', year, err.message);
return new Set();
});
});
}
/**
* Liefert alle Feiertage im Datumsbereich [weekStart, weekEnd] (inklusive).
* Lädt ggf. fehlende Jahre aus der API und speichert sie in der DB.
* @param {string} weekStart YYYY-MM-DD
* @param {string} weekEnd YYYY-MM-DD
* @returns {Promise<Set<string>>} Set von YYYY-MM-DD
*/
function getHolidaysForDateRange(weekStart, weekEnd) {
const startYear = parseInt(weekStart.slice(0, 4), 10);
const endYear = parseInt(weekEnd.slice(0, 4), 10);
const years = [];
for (let y = startYear; y <= endYear; y++) years.push(y);
return Promise.all(years.map((y) => getHolidaysForYear(y))).then((sets) => {
const combined = new Set();
sets.forEach((s) => s.forEach((d) => combined.add(d)));
const inRange = new Set();
combined.forEach((d) => {
if (d >= weekStart && d <= weekEnd) inRange.add(d);
});
return inRange;
});
}
module.exports = {
getHolidaysForYear,
getHolidaysForDateRange,
};