Rotatory anlegen: Morning-Meeting-Moderation auslosen und nach Nextcloud schreiben

Express-App mit JSON-Speicher unter VCH_DATA_DIR, Monatskalender mit Fotos,
Personen mit Rollen und Teilzeit-Freitagen, Abwesenheiten, Feiertage je
Bundesland, faire Zufallsauslosung mit Fixieren und Neu-Auslosen.

Nextcloud: CalDAV-Discovery, Zielkalender wählbar, Termine je Werktag
schreiben und aktualisieren, Abwesenheiten aus Kalender importieren,
Personen samt Fotos aus dem Systemadressbuch übernehmen.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
ferdi2goandClaude Fable 5.1 committed 2026-09-16 06:39:37 +00:00
commit 95756778d8
26 files changed
+4697

No files matched your search

+66
View File
@@ -0,0 +1,66 @@
import { addDays } from './scheduler.js';
const pad = (n) => String(n).padStart(2, '0');
const iso = (y, m, d) => `${y}-${pad(m)}-${pad(d)}`;
/** Ostersonntag nach der Gauß'schen Osterformel (Meeus/Jones/Butcher). */
export function easterSunday(year) {
const a = year % 19;
const b = Math.floor(year / 100);
const c = year % 100;
const d = Math.floor(b / 4);
const e = b % 4;
const f = Math.floor((b + 8) / 25);
const g = Math.floor((b - f + 1) / 3);
const h = (19 * a + b - d - g + 15) % 30;
const i = Math.floor(c / 4);
const k = c % 4;
const l = (32 + 2 * e + 2 * i - h - k) % 7;
const m = Math.floor((a + 11 * h + 22 * l) / 451);
const month = Math.floor((h + l - 7 * m + 114) / 31);
const day = ((h + l - 7 * m + 114) % 31) + 1;
return iso(year, month, day);
}
export const BUNDESLAENDER = {
'': 'Nur bundesweite Feiertage',
BW: 'Baden-Württemberg', BY: 'Bayern', BE: 'Berlin', BB: 'Brandenburg', HB: 'Bremen',
HH: 'Hamburg', HE: 'Hessen', MV: 'Mecklenburg-Vorpommern', NI: 'Niedersachsen',
NW: 'Nordrhein-Westfalen', RP: 'Rheinland-Pfalz', SL: 'Saarland', SN: 'Sachsen',
ST: 'Sachsen-Anhalt', SH: 'Schleswig-Holstein', TH: 'Thüringen',
};
function bussUndBettag(year) {
// Mittwoch vor dem 23. November
let d = iso(year, 11, 22);
while (new Date(d + 'T00:00:00Z').getUTCDay() !== 3) d = addDays(d, -1);
return d;
}
/** Gesetzliche Feiertage eines Jahres, bundesweit plus die des gewählten Bundeslands. */
export function germanHolidays(year, state = '') {
const easter = easterSunday(year);
const all = [
{ date: iso(year, 1, 1), name: 'Neujahr' },
{ date: iso(year, 1, 6), name: 'Heilige Drei Könige', states: ['BW', 'BY', 'ST'] },
{ date: iso(year, 3, 8), name: 'Internationaler Frauentag', states: ['BE', 'MV'] },
{ date: addDays(easter, -2), name: 'Karfreitag' },
{ date: addDays(easter, 1), name: 'Ostermontag' },
{ date: iso(year, 5, 1), name: 'Tag der Arbeit' },
{ date: addDays(easter, 39), name: 'Christi Himmelfahrt' },
{ date: addDays(easter, 50), name: 'Pfingstmontag' },
{ date: addDays(easter, 60), name: 'Fronleichnam', states: ['BW', 'BY', 'HE', 'NW', 'RP', 'SL'] },
{ date: iso(year, 8, 15), name: 'Mariä Himmelfahrt', states: ['SL', 'BY'] },
{ date: iso(year, 9, 20), name: 'Weltkindertag', states: ['TH'] },
{ date: iso(year, 10, 3), name: 'Tag der Deutschen Einheit' },
{ date: iso(year, 10, 31), name: 'Reformationstag', states: ['BB', 'HB', 'HH', 'MV', 'NI', 'SN', 'ST', 'SH', 'TH'] },
{ date: iso(year, 11, 1), name: 'Allerheiligen', states: ['BW', 'BY', 'NW', 'RP', 'SL'] },
{ date: bussUndBettag(year), name: 'Buß- und Bettag', states: ['SN'] },
{ date: iso(year, 12, 25), name: '1. Weihnachtstag' },
{ date: iso(year, 12, 26), name: '2. Weihnachtstag' },
];
return all
.filter((h) => !h.states || h.states.includes(state))
.map(({ date, name }) => ({ date, name, auto: true }))
.sort((a, b) => a.date.localeCompare(b.date));
}