/** * API-Client für den OSINT Lagemonitor. */ const API = { baseUrl: '/api', _getHeaders() { const token = localStorage.getItem('osint_token'); return { 'Content-Type': 'application/json', 'Authorization': token ? `Bearer ${token}` : '', }; }, async _request(method, path, body = null) { const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 30000); const options = { method, headers: this._getHeaders(), signal: controller.signal, }; if (body) { options.body = JSON.stringify(body); } let response; try { response = await fetch(`${this.baseUrl}${path}`, options); } catch (err) { clearTimeout(timeout); if (err.name === 'AbortError') { throw new Error('Zeitüberschreitung bei der Anfrage'); } throw err; } clearTimeout(timeout); if (response.status === 401) { localStorage.removeItem('osint_token'); localStorage.removeItem('osint_username'); window.location.href = '/'; return; } if (!response.ok) { const data = await response.json().catch(() => ({})); let detail = data.detail; if (Array.isArray(detail)) { detail = detail.map(e => e.msg || JSON.stringify(e)).join('; '); } else if (typeof detail === 'object' && detail !== null) { detail = JSON.stringify(detail); } throw new Error(detail || `Fehler ${response.status}`); } if (response.status === 204) return null; return response.json(); }, // Auth getMe() { return this._request('GET', '/auth/me'); }, // Incidents listIncidents(statusFilter = null) { const query = statusFilter ? `?status_filter=${statusFilter}` : ''; return this._request('GET', `/incidents${query}`); }, createIncident(data) { return this._request('POST', '/incidents', data); }, getRefreshingIncidents() { return this._request('GET', '/incidents/refreshing'); }, getIncident(id) { return this._request('GET', `/incidents/${id}`); }, updateIncident(id, data) { return this._request('PUT', `/incidents/${id}`, data); }, deleteIncident(id) { return this._request('DELETE', `/incidents/${id}`); }, getArticles(incidentId) { return this._request('GET', `/incidents/${incidentId}/articles`); }, getFactChecks(incidentId) { return this._request('GET', `/incidents/${incidentId}/factchecks`); }, getSnapshots(incidentId) { return this._request('GET', `/incidents/${incidentId}/snapshots`); }, getLocations(incidentId) { return this._request('GET', `/incidents/${incidentId}/locations`); }, triggerGeoparse(incidentId) { return this._request('POST', `/incidents/${incidentId}/geoparse`); }, getGeoparseStatus(incidentId) { return this._request('GET', `/incidents/${incidentId}/geoparse-status`); }, refreshIncident(id) { return this._request('POST', `/incidents/${id}/refresh`); }, getRefreshLog(incidentId, limit = 20) { return this._request('GET', `/incidents/${incidentId}/refresh-log?limit=${limit}`); }, // Sources (Quellenverwaltung) listSources(params = {}) { const query = new URLSearchParams(); if (params.source_type) query.set('source_type', params.source_type); if (params.category) query.set('category', params.category); if (params.source_status) query.set('source_status', params.source_status); const qs = query.toString(); return this._request('GET', `/sources${qs ? '?' + qs : ''}`); }, createSource(data) { return this._request('POST', '/sources', data); }, updateSource(id, data) { return this._request('PUT', `/sources/${id}`, data); }, deleteSource(id) { return this._request('DELETE', `/sources/${id}`); }, getSourceStats() { return this._request('GET', '/sources/stats'); }, discoverMulti(url) { return this._request('POST', '/sources/discover-multi', { url }); }, getMyExclusions() { return this._request('GET', '/sources/my-exclusions'); }, blockDomain(domain, notes) { return this._request('POST', '/sources/block-domain', { domain, notes }); }, unblockDomain(domain) { return this._request('POST', '/sources/unblock-domain', { domain }); }, deleteDomain(domain) { return this._request('DELETE', `/sources/domain/${encodeURIComponent(domain)}`); }, cancelRefresh(id) { return this._request('POST', `/incidents/${id}/cancel-refresh`); }, // Notifications listNotifications(limit = 50) { return this._request('GET', `/notifications?limit=${limit}`); }, markNotificationsRead(ids = null) { return this._request('PUT', '/notifications/mark-read', { notification_ids: ids }); }, // Subscriptions (E-Mail-Benachrichtigungen) getSubscription(incidentId) { return this._request('GET', '/incidents/' + incidentId + '/subscription'); }, updateSubscription(incidentId, data) { return this._request('PUT', '/incidents/' + incidentId + '/subscription', data); }, // Feedback sendFeedback(data) { return this._request('POST', '/feedback', data); }, async sendFeedbackForm(formData) { const token = localStorage.getItem('osint_token'); const controller = new AbortController(); const timeout = setTimeout(() => controller.abort(), 60000); const resp = await fetch(this.baseUrl + '/feedback', { method: 'POST', headers: { 'Authorization': token ? 'Bearer ' + token : '' }, body: formData, signal: controller.signal, }); clearTimeout(timeout); if (!resp.ok) { const err = await resp.json().catch(() => ({})); throw new Error(err.detail || 'Fehler ' + resp.status); } }, // Export exportIncident(id, format, scope) { const token = localStorage.getItem('osint_token'); return fetch(`${this.baseUrl}/incidents/${id}/export?format=${format}&scope=${scope}`, { headers: { 'Authorization': `Bearer ${token}` }, }); }, };