110 lines
3.4 KiB
JavaScript
110 lines
3.4 KiB
JavaScript
// 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,
|
|
};
|