const CRON_EXPRESSION = '0 17 * * *'; /** * Importiert oder aktualisiert Währungskurse in PocketBase. * Das 'updated'-Feld wird durch die Collection als Autodate verwaltet. */ function runImport() { const ECB_URL = 'https://www.ecb.europa.eu/stats/eurofxref/eurofxref-daily.xml'; const COLLECTION_NAME = 'currencies'; const IMPORT_TIMEOUT_MS = 30000; /** * Extrahiert Währungskurse aus dem ECB-XML. * * @param {string} xml - Rohe XML-Antwort. * @returns {Array<{currency: string, rate: number}>} */ function parseRates(xml) { const CURRENCY_RATE_REGEX = /]*currency='([^']+)'[^>]*rate='([^']+)'[^>]*\/>/g; const rates = []; let match; while ((match = CURRENCY_RATE_REGEX.exec(xml)) !== null) { rates.push({ currency: match[1].toLowerCase(), rate: parseFloat(match[2]), }); } return rates; } const response = $http.send({ url: ECB_URL, method: 'GET', timeout: IMPORT_TIMEOUT_MS, }); if (response.statusCode !== 200) { throw new Error( 'Failed to fetch ECB rates: HTTP ' + response.statusCode, ); } const rates = parseRates(response.raw); if (rates.length === 0) { throw new Error('No rates found in ECB response'); } const collection = $app.findCollectionByNameOrId(COLLECTION_NAME); for (const item of rates) { let record; try { record = $app.findRecordById( COLLECTION_NAME, item.currency, ); } catch (e) { record = new Record(collection); record.id = item.currency; } record.set('rate', item.rate); $app.save(record); } } cronAdd('import-currencies', CRON_EXPRESSION, runImport);