style: replace em dashes with hyphens throughout codebase
Replace all — with - in all source files (JS, CSS, HTML, JSON, Markdown) for consistency and readability. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -17,7 +17,7 @@ const router = express.Router();
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Session-Store (better-sqlite3, gleiche DB-Instanz wie App)
|
||||
// Eigene Implementierung — kein connect-sqlite3 (nutzt sqlite3-Bindings,
|
||||
// Eigene Implementierung - kein connect-sqlite3 (nutzt sqlite3-Bindings,
|
||||
// die separat kompiliert werden müssten und die Fehlerquelle waren).
|
||||
// --------------------------------------------------------
|
||||
class BetterSQLiteStore extends session.Store {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Modul: DB-Schema-Export für Tests
|
||||
* Zweck: SQL-Strings aus MIGRATIONS für node:sqlite-Tests exportieren.
|
||||
* Nur für Testzwecke — db.js nutzt die MIGRATIONS direkt intern.
|
||||
* Nur für Testzwecke - db.js nutzt die MIGRATIONS direkt intern.
|
||||
* Abhängigkeiten: keine
|
||||
*/
|
||||
|
||||
|
||||
+2
-2
@@ -60,7 +60,7 @@ function init() {
|
||||
|
||||
/**
|
||||
* Alle Migrationen in aufsteigender Reihenfolge.
|
||||
* Neue Migrations am Ende anhängen — niemals bestehende ändern.
|
||||
* Neue Migrations am Ende anhängen - niemals bestehende ändern.
|
||||
*/
|
||||
const MIGRATIONS = [
|
||||
{
|
||||
@@ -352,7 +352,7 @@ function currentVersion() {
|
||||
* @returns {import('better-sqlite3').Database}
|
||||
*/
|
||||
function get() {
|
||||
if (!db) throw new Error('[DB] Nicht initialisiert — init() zuerst aufrufen.');
|
||||
if (!db) throw new Error('[DB] Nicht initialisiert - init() zuerst aufrufen.');
|
||||
return db;
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -94,7 +94,7 @@ app.use('/api/', (req, res, next) => {
|
||||
});
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Statische Dateien (Frontend) — differenzierte Caching-Strategie
|
||||
// Statische Dateien (Frontend) - differenzierte Caching-Strategie
|
||||
//
|
||||
// HTML + JS + CSS: no-cache (Browser revalidiert via ETag/304, kein stale Content
|
||||
// nach Deployment). Bei unverändertem File → 304 Not Modified ohne Übertragung.
|
||||
@@ -113,7 +113,7 @@ app.use(express.static(path.join(__dirname, '..', 'public'), {
|
||||
} else if (['.png', '.jpg', '.jpeg', '.ico', '.svg', '.webp', '.woff2', '.woff'].includes(ext)) {
|
||||
res.setHeader('Cache-Control', 'public, max-age=2592000, immutable'); // 30 Tage
|
||||
} else {
|
||||
// HTML, JS, CSS, JSON, manifest, sw — immer revalidieren
|
||||
// HTML, JS, CSS, JSON, manifest, sw - immer revalidieren
|
||||
res.setHeader('Cache-Control', 'no-cache, must-revalidate');
|
||||
}
|
||||
// manifest.json: korrekter MIME-Type für PWA-Erkennung durch Chrome/Android
|
||||
|
||||
@@ -17,7 +17,7 @@ const { str, oneOf, date, num, rrule, collectErrors, MAX_TITLE, MONTH_RE } = req
|
||||
|
||||
/**
|
||||
* Erstellt fehlende Instanzen wiederkehrender Budget-Einträge für den angefragten Monat.
|
||||
* Läuft idempotent — bereits vorhandene oder explizit übersprungene Instanzen werden ignoriert.
|
||||
* Läuft idempotent - bereits vorhandene oder explizit übersprungene Instanzen werden ignoriert.
|
||||
* @param {import('better-sqlite3').Database} database
|
||||
* @param {string} month YYYY-MM
|
||||
*/
|
||||
|
||||
@@ -228,7 +228,7 @@ router.get('/google/callback', async (req, res) => {
|
||||
|
||||
await googleCalendar.handleCallback(code);
|
||||
|
||||
// Initialen Sync im Hintergrund starten (kein await — Redirect soll sofort erfolgen)
|
||||
// Initialen Sync im Hintergrund starten (kein await - Redirect soll sofort erfolgen)
|
||||
googleCalendar.sync().catch((e) => console.error('[Google] Initialer Sync fehlgeschlagen:', e.message));
|
||||
|
||||
res.redirect('/settings?sync_ok=google');
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Modul: Dashboard
|
||||
* Zweck: Aggregierter Endpoint — liefert Daten aller Dashboard-Widgets in einem Request
|
||||
* Zweck: Aggregierter Endpoint - liefert Daten aller Dashboard-Widgets in einem Request
|
||||
* Abhängigkeiten: express, server/db.js
|
||||
*/
|
||||
|
||||
@@ -13,7 +13,7 @@ const db = require('../db');
|
||||
/**
|
||||
* GET /api/v1/dashboard
|
||||
* Liefert aggregierte Daten für alle Dashboard-Widgets.
|
||||
* Jedes Widget-Objekt hat ein eigenes `error`-Feld falls die Abfrage fehlschlägt —
|
||||
* Jedes Widget-Objekt hat ein eigenes `error`-Feld falls die Abfrage fehlschlägt -
|
||||
* so bricht ein fehlerhaftes Widget nicht das gesamte Dashboard.
|
||||
*
|
||||
* Response: {
|
||||
|
||||
@@ -40,7 +40,7 @@ function weekEnd(dateStr) {
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Routen — Mahlzeiten-Vorschläge (vor dynamischen Routen!)
|
||||
// Routen - Mahlzeiten-Vorschläge (vor dynamischen Routen!)
|
||||
// --------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -70,7 +70,7 @@ router.get('/suggestions', (req, res) => {
|
||||
});
|
||||
|
||||
// --------------------------------------------------------
|
||||
// Routen — Wochenübersicht
|
||||
// Routen - Wochenübersicht
|
||||
// --------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -137,7 +137,7 @@ router.get('/', (req, res) => {
|
||||
});
|
||||
|
||||
// --------------------------------------------------------
|
||||
// CRUD — Mahlzeiten
|
||||
// CRUD - Mahlzeiten
|
||||
// --------------------------------------------------------
|
||||
|
||||
/**
|
||||
@@ -266,7 +266,7 @@ router.delete('/:id', (req, res) => {
|
||||
});
|
||||
|
||||
// --------------------------------------------------------
|
||||
// CRUD — Zutaten
|
||||
// CRUD - Zutaten
|
||||
// --------------------------------------------------------
|
||||
|
||||
/**
|
||||
|
||||
@@ -94,7 +94,7 @@ router.get('/', async (req, res) => {
|
||||
|
||||
// --------------------------------------------------------
|
||||
// GET /api/v1/weather/icon/:code
|
||||
// Proxy für OpenWeatherMap-Icons — vermeidet externe Bild-Requests
|
||||
// Proxy für OpenWeatherMap-Icons - vermeidet externe Bild-Requests
|
||||
// im PWA-Standalone-Modus (CORS/CSP-Probleme auf Android Chrome).
|
||||
// Erlaubte Codes: 2–4 alphanumerische Zeichen (z.B. "01d", "10n").
|
||||
// Response: PNG-Bild mit 24h-Cache
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/**
|
||||
* Modul: Apple Calendar Sync (CalDAV)
|
||||
* Zweck: Bidirektionaler Sync mit iCloud Calendar via CalDAV-Protokoll
|
||||
* Abhängigkeiten: tsdav (ESM — dynamisch importiert), server/db.js
|
||||
* Abhängigkeiten: tsdav (ESM - dynamisch importiert), server/db.js
|
||||
*
|
||||
* Konfiguration (.env):
|
||||
* APPLE_CALDAV_URL — z.B. https://caldav.icloud.com
|
||||
* APPLE_USERNAME — Apple-ID E-Mail
|
||||
* APPLE_APP_SPECIFIC_PASSWORD — App-spezifisches Passwort aus appleid.apple.com
|
||||
* APPLE_CALDAV_URL - z.B. https://caldav.icloud.com
|
||||
* APPLE_USERNAME - Apple-ID E-Mail
|
||||
* APPLE_APP_SPECIFIC_PASSWORD - App-spezifisches Passwort aus appleid.apple.com
|
||||
*
|
||||
* sync_config-Schlüssel:
|
||||
* apple_last_sync — ISO-8601-Timestamp des letzten Syncs
|
||||
* apple_last_sync - ISO-8601-Timestamp des letzten Syncs
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
@@ -134,7 +134,7 @@ function parseICS(ics) {
|
||||
const location = get('LOCATION') || null;
|
||||
const rrule = get('RRULE') ? `RRULE:${get('RRULE')}` : null;
|
||||
|
||||
// DTSTART — mit optionalem TZID oder VALUE=DATE
|
||||
// DTSTART - mit optionalem TZID oder VALUE=DATE
|
||||
const dtStartRaw = (() => {
|
||||
const m = /^DTSTART(?:;[^:]*)?:(.*)$/im.exec(block);
|
||||
return m ? m[1].trim() : null;
|
||||
@@ -148,7 +148,7 @@ function parseICS(ics) {
|
||||
const dtstart = dtStartRaw ? formatICSDate(dtStartRaw, allDay) : null;
|
||||
let dtend = dtEndRaw ? formatICSDate(dtEndRaw, allDay) : null;
|
||||
|
||||
// RFC 5545: DTEND for VALUE=DATE is exclusive — subtract one day
|
||||
// RFC 5545: DTEND for VALUE=DATE is exclusive - subtract one day
|
||||
if (allDay && dtend) {
|
||||
const d = new Date(dtend + 'T00:00:00');
|
||||
d.setDate(d.getDate() - 1);
|
||||
@@ -215,7 +215,7 @@ function applyDuration(dtstart, dur, allDay) {
|
||||
base.setHours(base.getHours() + hours, base.getMinutes() + mins, base.getSeconds() + secs);
|
||||
|
||||
if (allDay) {
|
||||
// Duration end is exclusive for DATE values — subtract one day for inclusive storage
|
||||
// Duration end is exclusive for DATE values - subtract one day for inclusive storage
|
||||
base.setDate(base.getDate() - 1);
|
||||
return `${base.getFullYear()}-${String(base.getMonth() + 1).padStart(2, '0')}-${String(base.getDate()).padStart(2, '0')}`;
|
||||
}
|
||||
@@ -247,7 +247,7 @@ function buildICS(event) {
|
||||
|
||||
if (event.all_day) {
|
||||
const startDate = event.start_datetime.slice(0, 10).replace(/-/g, '');
|
||||
// RFC 5545: DTEND for VALUE=DATE is exclusive — add one day
|
||||
// RFC 5545: DTEND for VALUE=DATE is exclusive - add one day
|
||||
const endSrc = (event.end_datetime || event.start_datetime).slice(0, 10);
|
||||
const endD = new Date(endSrc + 'T00:00:00');
|
||||
endD.setDate(endD.getDate() + 1);
|
||||
@@ -288,7 +288,7 @@ async function sync() {
|
||||
throw new Error('[Apple] Keine Credentials konfiguriert (weder in DB noch in .env).');
|
||||
}
|
||||
|
||||
// tsdav ist ESM-only — dynamischer Import aus CommonJS
|
||||
// tsdav ist ESM-only - dynamischer Import aus CommonJS
|
||||
const { createDAVClient } = await import('tsdav');
|
||||
|
||||
const client = await createDAVClient({
|
||||
@@ -307,7 +307,7 @@ async function sync() {
|
||||
// created_by: ersten existierenden User verwenden (nicht hardcoded ID 1)
|
||||
const owner = db.get().prepare('SELECT id FROM users ORDER BY id ASC LIMIT 1').get();
|
||||
if (!owner) {
|
||||
console.warn('[Apple] Kein User in der Datenbank — Sync übersprungen.');
|
||||
console.warn('[Apple] Kein User in der Datenbank - Sync übersprungen.');
|
||||
return;
|
||||
}
|
||||
const createdBy = owner.id;
|
||||
@@ -397,7 +397,7 @@ async function sync() {
|
||||
}
|
||||
|
||||
cfgSet('apple_last_sync', new Date().toISOString());
|
||||
console.log(`[Apple] Sync abgeschlossen — ${totalObjects} Objekte aus ${syncCalendars.length} Kalendern inbound, ${localEvents.length} lokal → iCloud.`);
|
||||
console.log(`[Apple] Sync abgeschlossen - ${totalObjects} Objekte aus ${syncCalendars.length} Kalendern inbound, ${localEvents.length} lokal → iCloud.`);
|
||||
}
|
||||
|
||||
module.exports = { sync, getStatus, saveCredentials, clearCredentials, testConnection };
|
||||
|
||||
@@ -4,11 +4,11 @@
|
||||
* Abhängigkeiten: googleapis, server/db.js
|
||||
*
|
||||
* sync_config-Schlüssel:
|
||||
* google_access_token — OAuth Access Token
|
||||
* google_refresh_token — OAuth Refresh Token (langlebig)
|
||||
* google_token_expiry — ISO-8601-Timestamp bis wann Access Token gültig ist
|
||||
* google_sync_token — Inkrementeller Sync-Token von Google (events.list)
|
||||
* google_last_sync — ISO-8601-Timestamp des letzten erfolgreichen Syncs
|
||||
* google_access_token - OAuth Access Token
|
||||
* google_refresh_token - OAuth Refresh Token (langlebig)
|
||||
* google_token_expiry - ISO-8601-Timestamp bis wann Access Token gültig ist
|
||||
* google_sync_token - Inkrementeller Sync-Token von Google (events.list)
|
||||
* google_last_sync - ISO-8601-Timestamp des letzten erfolgreichen Syncs
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
@@ -65,7 +65,7 @@ function loadAuthorizedClient() {
|
||||
const refreshToken = cfgGet('google_refresh_token');
|
||||
|
||||
if (!accessToken || !refreshToken) {
|
||||
throw new Error('[Google] Nicht konfiguriert — zuerst OAuth durchführen.');
|
||||
throw new Error('[Google] Nicht konfiguriert - zuerst OAuth durchführen.');
|
||||
}
|
||||
|
||||
const client = createClient();
|
||||
@@ -103,7 +103,7 @@ function getAuthUrl() {
|
||||
|
||||
/**
|
||||
* OAuth-Callback: tauscht Code gegen Tokens, speichert in sync_config.
|
||||
* @param {string} code — Code aus dem OAuth-Callback-Query-Parameter
|
||||
* @param {string} code - Code aus dem OAuth-Callback-Query-Parameter
|
||||
*/
|
||||
async function handleCallback(code) {
|
||||
const client = createClient();
|
||||
@@ -117,7 +117,7 @@ async function handleCallback(code) {
|
||||
cfgSet('google_refresh_token', tokens.refresh_token);
|
||||
if (tokens.expiry_date) cfgSet('google_token_expiry', String(tokens.expiry_date));
|
||||
|
||||
console.log('[Google] OAuth erfolgreich — Tokens gespeichert.');
|
||||
console.log('[Google] OAuth erfolgreich - Tokens gespeichert.');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,7 +179,7 @@ async function sync() {
|
||||
} catch (err) {
|
||||
if (err.code === 410) {
|
||||
// syncToken abgelaufen → vollständiger Resync
|
||||
console.warn('[Google] syncToken ungültig — vollständiger Resync.');
|
||||
console.warn('[Google] syncToken ungültig - vollständiger Resync.');
|
||||
cfgDel('google_sync_token');
|
||||
syncToken = null;
|
||||
continue;
|
||||
@@ -220,7 +220,7 @@ async function sync() {
|
||||
}
|
||||
|
||||
cfgSet('google_last_sync', new Date().toISOString());
|
||||
console.log(`[Google] Sync abgeschlossen — ${localEvents.length} lokal → Google, Inbound via syncToken.`);
|
||||
console.log(`[Google] Sync abgeschlossen - ${localEvents.length} lokal → Google, Inbound via syncToken.`);
|
||||
}
|
||||
|
||||
// --------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user