Browser-Plugin: Multi-User/X-API-Key + Footer-Download
Plugin (Manifest V3) refactored für gehostete Multi-User-Instanz: - Tracker-URL hardcoded https://nextjobs.cc (keine URL-Eingabe mehr) - Authentifizierung ausschließlich über persönlichen REST-API-Key (Header X-API-Key), pro Benutzer in chrome.storage.sync - Server: /api/indeed-import nutzt neuen requireApiKey-Middleware, ordnet Import dem Benutzerkonto mit passendem cfg:API_TOKEN zu Download: /plugin/nextjobs-stellen-import.zip packt extension/ on the fly (dep-freier STORE-Zip in lib/zipdir.js, deterministischer Timestamp), route hinter requireAuth. Footer-Link im App-Footer. Dockerfile kopiert extension/ ins Image. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+26
-15
@@ -1,36 +1,40 @@
|
||||
const DEFAULT_TRACKER_URL = 'http://localhost:3000';
|
||||
// Tracker-Adresse ist fest (gehostete Instanz). Jeder Benutzer gibt seinen
|
||||
// eigenen REST-API-Key ein (X-API-Key), über den der Server den Import dem
|
||||
// richtigen Benutzerkonto zuordnet — siehe /api/indeed-import serverseitig.
|
||||
const TRACKER_URL = 'https://nextjobs.cc';
|
||||
|
||||
const $ = (id) => document.getElementById(id);
|
||||
const statusEl = $('status');
|
||||
|
||||
function normalize(url) {
|
||||
return (url || '').trim().replace(/\/+$/, '');
|
||||
}
|
||||
function setStatus(html, cls) {
|
||||
statusEl.innerHTML = html;
|
||||
statusEl.className = cls || '';
|
||||
}
|
||||
|
||||
// ---- Settings (tracker URL) ------------------------------------------------
|
||||
// ---- Settings (API-Key) ----------------------------------------------------
|
||||
|
||||
chrome.storage.sync.get({ trackerUrl: DEFAULT_TRACKER_URL }, (items) => {
|
||||
$('trackerUrl').value = items.trackerUrl || DEFAULT_TRACKER_URL;
|
||||
chrome.storage.sync.get({ apiKey: '' }, (items) => {
|
||||
$('apiKey').value = items.apiKey || '';
|
||||
});
|
||||
|
||||
$('saveBtn').addEventListener('click', () => {
|
||||
const url = normalize($('trackerUrl').value) || DEFAULT_TRACKER_URL;
|
||||
chrome.storage.sync.set({ trackerUrl: url }, () => {
|
||||
$('trackerUrl').value = url;
|
||||
setStatus('Einstellungen gespeichert.', 'ok');
|
||||
const key = $('apiKey').value.trim();
|
||||
chrome.storage.sync.set({ apiKey: key }, () => {
|
||||
setStatus(key ? 'API-Key gespeichert.' : 'API-Key entfernt.', key ? 'ok' : '');
|
||||
});
|
||||
});
|
||||
|
||||
$('testBtn').addEventListener('click', async () => {
|
||||
const url = normalize($('trackerUrl').value) || DEFAULT_TRACKER_URL;
|
||||
const key = $('apiKey').value.trim();
|
||||
if (!key) { setStatus('Bitte erst API-Key eingeben.', 'err'); return; }
|
||||
setStatus('Teste Verbindung …', '');
|
||||
try {
|
||||
const res = await fetch(url + '/api/settings', { method: 'GET' });
|
||||
setStatus(res.ok ? 'Verbindung erfolgreich ✓' : 'Erreichbar, aber unerwartete Antwort (' + res.status + ').', res.ok ? 'ok' : 'err');
|
||||
const res = await fetch(TRACKER_URL + '/api/v1/health', {
|
||||
headers: { 'X-API-Key': key },
|
||||
});
|
||||
if (res.ok) setStatus('Verbindung erfolgreich ✓ — Key gültig.', 'ok');
|
||||
else if (res.status === 401) setStatus('Key abgelehnt (401). Bitte API-Key prüfen.', 'err');
|
||||
else setStatus('Erreichbar, aber unerwartete Antwort (' + res.status + ').', 'err');
|
||||
} catch (err) {
|
||||
setStatus('Nicht erreichbar: ' + err.message, 'err');
|
||||
}
|
||||
@@ -158,6 +162,13 @@ function sendJob(payload) {
|
||||
setStatus('Fehler: ' + chrome.runtime.lastError.message, 'err');
|
||||
return;
|
||||
}
|
||||
if (resp && resp.needKey) {
|
||||
$('sendBtn').disabled = false;
|
||||
setStatus('Bitte erst in den Einstellungen deinen API-Key hinterlegen.', 'err');
|
||||
const s = document.getElementById('settings'); if (s) s.open = true;
|
||||
$('apiKey').focus();
|
||||
return;
|
||||
}
|
||||
if (resp && resp.duplicate) {
|
||||
$('sendBtn').disabled = false;
|
||||
if (confirm(duplicateWarning(resp.matches))) {
|
||||
@@ -198,4 +209,4 @@ $('sendBtn').addEventListener('click', () => {
|
||||
$('rescanBtn').addEventListener('click', scanActivePage);
|
||||
|
||||
// Auto-extract as soon as the popup opens.
|
||||
scanActivePage();
|
||||
scanActivePage();
|
||||
Reference in New Issue
Block a user