Scanner: Jooble entfernt
Quelle, Schlüsselfeld in Einstellungen -> Scanner und Doku raus. Agenten, die jooble noch gespeichert haben, bekommen es nicht mehr angezeigt; die Pipeline überspringt unbekannte Quellen ohnehin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
a85daf01da
commit
e0f6ef06cd
@@ -31,7 +31,8 @@ const agentOut = (row) => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
keywords: parseList(row.keywords),
|
||||
sources: parseList(row.sources),
|
||||
// Nur Quellen, die es noch gibt (Jooble ist am 29.09.2026 entfallen).
|
||||
sources: parseList(row.sources).filter((id) => SOURCE_IDS.includes(id)),
|
||||
excludes: parseList(row.excludes),
|
||||
is_active: Boolean(row.is_active),
|
||||
matches: Number(row.matches ?? 0),
|
||||
@@ -323,7 +324,7 @@ router.get('/settings', requireAdmin, async (req, res, next) => {
|
||||
router.patch('/settings', requireAdmin, async (req, res, next) => {
|
||||
try {
|
||||
const settings = await saveScannerSettings(req.body ?? {});
|
||||
const touchedKeys = ['adzunaId', 'adzunaKey', 'joobleKey'].filter((key) => req.body?.[key] !== undefined);
|
||||
const touchedKeys = ['adzunaId', 'adzunaKey'].filter((key) => req.body?.[key] !== undefined);
|
||||
await logHistory({
|
||||
entityType: 'system',
|
||||
entityLabel: 'Scanner',
|
||||
|
||||
@@ -22,7 +22,6 @@ export const DEFAULTS = {
|
||||
const SECRET_KEYS = {
|
||||
adzunaId: 'scanner_adzuna_id',
|
||||
adzunaKey: 'scanner_adzuna_key',
|
||||
joobleKey: 'scanner_jooble_key',
|
||||
};
|
||||
|
||||
const TIME = /^([01]\d|2[0-3]):[0-5]\d$/;
|
||||
|
||||
@@ -26,7 +26,6 @@ export const SOURCES = {
|
||||
stepstone: { label: 'StepStone', countries: 'DE', needsKey: null, fetch: fetchStepstone },
|
||||
karriere: { label: 'karriere.at', countries: 'AT', needsKey: null, fetch: fetchKarriere },
|
||||
adzuna: { label: 'Adzuna', countries: 'DE · AT · CH', needsKey: 'adzuna', fetch: fetchAdzuna },
|
||||
jooble: { label: 'Jooble', countries: 'DE · AT · CH', needsKey: 'jooble', fetch: fetchJooble },
|
||||
freelancermap: { label: 'freelancermap', countries: 'DE', needsKey: null, fetch: fetchFreelancermap },
|
||||
};
|
||||
|
||||
@@ -37,7 +36,6 @@ export function sourceReady(id, secrets) {
|
||||
const needs = SOURCES[id]?.needsKey;
|
||||
if (!needs) return true;
|
||||
if (needs === 'adzuna') return Boolean(secrets.adzunaId && secrets.adzunaKey);
|
||||
if (needs === 'jooble') return Boolean(secrets.joobleKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -291,38 +289,6 @@ async function fetchAdzuna(keyword, { maxAge, secrets }) {
|
||||
return jobs.filter((job) => job.title && job.url);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Jooble - kostenloser API-Schluessel (jooble.org/api/about), Sammler fuer DACH.
|
||||
* Je Land ein eigener Host.
|
||||
* ---------------------------------------------------------------------- */
|
||||
async function fetchJooble(keyword, { maxAge, secrets }) {
|
||||
const since = new Date(Date.now() - maxAge * 24 * 3_600_000).toISOString().slice(0, 10);
|
||||
const jobs = [];
|
||||
for (const country of ['de', 'at', 'ch']) {
|
||||
const data = await request(`https://${country}.jooble.org/api/${encodeURIComponent(secrets.joobleKey)}`, {
|
||||
json: true,
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ keywords: keyword, datecreatedfrom: since, page: '1' }),
|
||||
});
|
||||
for (const job of data?.jobs ?? []) {
|
||||
jobs.push({
|
||||
source: 'jooble',
|
||||
externalId: String(job.id ?? job.link),
|
||||
title: clean(job.title).replace(/<[^>]+>/g, ''),
|
||||
company: clean(job.company) || null,
|
||||
location: clean(job.location) || null,
|
||||
country: country.toUpperCase(),
|
||||
employmentType: clean(job.type) || null,
|
||||
url: job.link,
|
||||
description: clean(job.snippet).replace(/<[^>]+>/g, '').replace(/ /g, ' ') || null,
|
||||
publishedAt: toDate(job.updated),
|
||||
});
|
||||
}
|
||||
}
|
||||
return jobs.filter((job) => job.title && job.url);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* freelancermap - Projekte fuer Freiberufler und Interim, neueste zuerst.
|
||||
* Selektoren wie im Scanner des perinco CRM.
|
||||
|
||||
Reference in New Issue
Block a user