Release 2.9.0

This commit is contained in:
2026-08-28 02:53:59 +01:00
parent 9097d45d6a
commit 3de0e89e94
67 changed files with 1767 additions and 98 deletions
@@ -288,6 +288,19 @@ module.exports = function registerApiSourceRoutes(app, deps) {
return res.status(404).send('API source not found');
}
if (String(req.body && req.body.data_source_action || '').trim() === 'toggle') {
const enabled = apiSource.enabled === 0 || apiSource.enabled === false ? 1 : 0;
await connection.query('UPDATE i_api_sources SET enabled = ?, modified_by = ? WHERE id = ?', [enabled, getAuditUserId(req), apiSource.id]);
if (enabled) {
dataSourceTasks.registerRecurringRefresh('api-source', apiSource.id, apiSource.name, apiSource.update_interval_value, apiSource.update_interval_unit, function () {
return dataSourceTasks.refreshApiSourceInBackground(apiSource.id, getAuditUserId(req));
});
} else {
dataSourceTasks.removeRecurringRefresh('api-source', apiSource.id);
}
return res.redirect('/data-sources/api-sources/' + apiSource.id + '/edit?message=' + encodeURIComponent(enabled ? 'API source enabled.' : 'API source disabled.'));
}
const payload = common.buildApiSourcePayload(req, apiSource);
if (await common.fetchDuplicateName(pool, 'i_api_sources', payload.name, apiSource.id)) {
return res.redirect('/data-sources/api-sources/' + apiSource.id + '/edit?message=' + encodeURIComponent('An API source with that name already exists.'));
@@ -295,35 +308,21 @@ module.exports = function registerApiSourceRoutes(app, deps) {
const actorId = getAuditUserId(req);
await connection.beginTransaction();
await connection.query(
'UPDATE i_api_sources SET name = ?, api_url = ?, request_method = ?, request_body_json = ?, auth_method = ?, auth_username = ?, auth_password = ?, auth_bearer_token = ?, auth_header_name = ?, auth_header_value = ?, token_url = ?, token_request_body_json = ?, token_response_path = ?, token_header_name = ?, token_header_prefix = ?, items_path = ?, update_interval_value = ?, update_interval_unit = ?, last_pulled_at = ?, last_pull_error = ?, last_response_status = ?, last_response_content_type = ?, last_response_json = ?, modified_by = ? WHERE id = ?',
[payload.name, payload.apiUrl, payload.requestMethod, payload.requestBodyJson || null, payload.authMethod, payload.authUsername || null, payload.authPassword || null, payload.authBearerToken || null, payload.authHeaderName || null, payload.authHeaderValue || null, payload.tokenUrl || null, payload.tokenRequestBodyJson || null, payload.tokenResponsePath || null, payload.tokenHeaderName || null, payload.tokenHeaderPrefix || null, payload.itemsPath || null, payload.updateIntervalValue, payload.updateIntervalUnit, null, null, null, null, null, actorId, apiSource.id]
'UPDATE i_api_sources SET name = ?, api_url = ?, request_method = ?, request_body_json = ?, auth_method = ?, auth_username = ?, auth_password = ?, auth_bearer_token = ?, auth_header_name = ?, auth_header_value = ?, token_url = ?, token_request_body_json = ?, token_response_path = ?, token_header_name = ?, token_header_prefix = ?, items_path = ?, update_interval_value = ?, update_interval_unit = ?, modified_by = ? WHERE id = ?',
[payload.name, payload.apiUrl, payload.requestMethod, payload.requestBodyJson || null, payload.authMethod, payload.authUsername || null, payload.authPassword || null, payload.authBearerToken || null, payload.authHeaderName || null, payload.authHeaderValue || null, payload.tokenUrl || null, payload.tokenRequestBodyJson || null, payload.tokenResponsePath || null, payload.tokenHeaderName || null, payload.tokenHeaderPrefix || null, payload.itemsPath || null, payload.updateIntervalValue, payload.updateIntervalUnit, actorId, apiSource.id]
);
await connection.commit();
dataSourceTasks.registerRecurringRefresh('api-source', apiSource.id, payload.name, payload.updateIntervalValue, payload.updateIntervalUnit, function () {
return dataSourceTasks.refreshApiSourceInBackground(apiSource.id, actorId);
});
const message = 'API source updated. Refresh is running in the background.';
const refreshTask = await backgroundTaskQueue.enqueueTask({
key: 'api-source-refresh:' + apiSource.id,
title: 'API source refresh',
category: 'data-source',
taskType: 'data-source-refresh',
payload: {
sourceType: 'api-source',
sourceId: apiSource.id,
sourceName: payload.name,
actorId: actorId
},
metadata: {
sourceType: 'api-source',
sourceId: apiSource.id,
sourceName: payload.name
}
});
redirectAfterSave(req, res, '/data-sources/api-sources/' + apiSource.id + '/edit?refresh_task_id=' + encodeURIComponent(refreshTask && refreshTask.id ? refreshTask.id : ''), {
if (apiSource.enabled === 0 || apiSource.enabled === false) {
dataSourceTasks.removeRecurringRefresh('api-source', apiSource.id);
} else {
dataSourceTasks.registerRecurringRefresh('api-source', apiSource.id, payload.name, payload.updateIntervalValue, payload.updateIntervalUnit, function () {
return dataSourceTasks.refreshApiSourceInBackground(apiSource.id, actorId);
});
}
redirectAfterSave(req, res, '/data-sources/api-sources/' + apiSource.id + '/edit', {
closeUrl: '/data-sources/api-sources',
newUrl: '/data-sources/api-sources/new',
message: message
message: 'API source updated.'
});
} catch (error) {
try {
@@ -337,6 +336,18 @@ module.exports = function registerApiSourceRoutes(app, deps) {
}
});
app.post('/data-sources/api-sources/:id/refresh', requirePermission('api-sources.allow'), async function (req, res, next) {
try {
const apiSource = await common.fetchApiSourceById(pool, Number(req.params.id));
if (!apiSource) return res.status(404).send('API source not found');
if (apiSource.enabled === 0 || apiSource.enabled === false) {
return res.redirect('/data-sources/api-sources/' + apiSource.id + '/edit?message=' + encodeURIComponent('API source is disabled.'));
}
await backgroundTaskQueue.enqueueTask({ key: 'api-source-refresh:' + apiSource.id, title: 'API source refresh', category: 'data-source', taskType: 'data-source-refresh', payload: { sourceType: 'api-source', sourceId: apiSource.id, sourceName: apiSource.name, actorId: getAuditUserId(req) }, metadata: { sourceType: 'api-source', sourceId: apiSource.id, sourceName: apiSource.name } });
res.redirect('/data-sources/api-sources/' + apiSource.id + '/edit?message=' + encodeURIComponent('API source refresh queued.'));
} catch (error) { next(error); }
});
app.post('/data-sources/api-sources/:id/delete', requirePermission('api-sources.delete'), async function (req, res, next) {
try {
const apiSource = await common.fetchApiSourceById(pool, Number(req.params.id));