Init
This commit is contained in:
109
services/feiertage-service.js
Normal file
109
services/feiertage-service.js
Normal 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,
|
||||
};
|
||||
Reference in New Issue
Block a user