mirror of
https://github.com/orangecoding/fredy.git
synced 2026-06-16 12:31:07 +00:00
fixing job state setting when job is disabled
This commit is contained in:
@@ -29,7 +29,7 @@ export default async function jobPlugin(fastify) {
|
|||||||
fastify.get('/', async (request) => {
|
fastify.get('/', async (request) => {
|
||||||
const isUserAdmin = isAdmin(request);
|
const isUserAdmin = isAdmin(request);
|
||||||
return jobStorage
|
return jobStorage
|
||||||
.getJobs()
|
.getJobs({ includeDisabled: true })
|
||||||
.filter(
|
.filter(
|
||||||
(job) =>
|
(job) =>
|
||||||
isUserAdmin ||
|
isUserAdmin ||
|
||||||
|
|||||||
@@ -169,9 +169,17 @@ export const removeJobsByUserId = (userId) => {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all jobs.
|
* Get all jobs.
|
||||||
|
*
|
||||||
|
* By default only enabled jobs are returned, since most callers (scheduler,
|
||||||
|
* geocoding cron, tracker, dashboard) operate on active jobs only. The UI,
|
||||||
|
* however, must also be able to load disabled jobs (e.g. to edit them or view
|
||||||
|
* their listings), so it passes `includeDisabled: true`.
|
||||||
|
*
|
||||||
|
* @param {Object} [params]
|
||||||
|
* @param {boolean} [params.includeDisabled=false] - When true, disabled jobs are included.
|
||||||
* @returns {Job[]} List of jobs ordered by name (NULLs last).
|
* @returns {Job[]} List of jobs ordered by name (NULLs last).
|
||||||
*/
|
*/
|
||||||
export const getJobs = () => {
|
export const getJobs = ({ includeDisabled = false } = {}) => {
|
||||||
const rows = SqliteConnection.query(
|
const rows = SqliteConnection.query(
|
||||||
`SELECT j.id,
|
`SELECT j.id,
|
||||||
j.user_id AS userId,
|
j.user_id AS userId,
|
||||||
@@ -186,7 +194,7 @@ export const getJobs = () => {
|
|||||||
j.last_run_at AS lastRunAt,
|
j.last_run_at AS lastRunAt,
|
||||||
(SELECT COUNT(1) FROM listings l WHERE l.job_id = j.id AND l.is_active = 1 AND l.manually_deleted = 0) AS numberOfFoundListings
|
(SELECT COUNT(1) FROM listings l WHERE l.job_id = j.id AND l.is_active = 1 AND l.manually_deleted = 0) AS numberOfFoundListings
|
||||||
FROM jobs j
|
FROM jobs j
|
||||||
WHERE j.enabled = 1
|
${includeDisabled ? '' : 'WHERE j.enabled = 1'}
|
||||||
ORDER BY j.name IS NULL, j.name`,
|
ORDER BY j.name IS NULL, j.name`,
|
||||||
);
|
);
|
||||||
return rows.map((row) => ({
|
return rows.map((row) => ({
|
||||||
|
|||||||
64
test/storage/jobStorage.test.js
Normal file
64
test/storage/jobStorage.test.js
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2026 by Christian Kellner.
|
||||||
|
* Licensed under Apache-2.0 with Commons Clause and Attribution/Naming Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { vi, describe, it, expect, beforeEach } from 'vitest';
|
||||||
|
|
||||||
|
// Mock SqliteConnection so we can assert which SQL the storage layer runs
|
||||||
|
// without spinning up a real SQLite DB.
|
||||||
|
|
||||||
|
const calls = {
|
||||||
|
execute: [],
|
||||||
|
query: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const sqliteMock = {
|
||||||
|
execute: (sql, params) => {
|
||||||
|
calls.execute.push({ sql, params });
|
||||||
|
return { changes: 1 };
|
||||||
|
},
|
||||||
|
query: (sql, params) => {
|
||||||
|
calls.query.push({ sql, params });
|
||||||
|
if (sqliteMock.__queryHandler) return sqliteMock.__queryHandler(sql, params);
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
__queryHandler: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
vi.mock('../../lib/services/storage/SqliteConnection.js', () => ({
|
||||||
|
default: sqliteMock,
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe('jobStorage.getJobs', () => {
|
||||||
|
let jobStorage;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
calls.execute.length = 0;
|
||||||
|
calls.query.length = 0;
|
||||||
|
sqliteMock.__queryHandler = null;
|
||||||
|
jobStorage = await import('../../lib/services/storage/jobStorage.js');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('filters out disabled jobs by default (WHERE j.enabled = 1)', () => {
|
||||||
|
jobStorage.getJobs();
|
||||||
|
expect(calls.query).toHaveLength(1);
|
||||||
|
expect(calls.query[0].sql).toMatch(/WHERE j\.enabled = 1/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('includes disabled jobs when includeDisabled is true', () => {
|
||||||
|
jobStorage.getJobs({ includeDisabled: true });
|
||||||
|
expect(calls.query).toHaveLength(1);
|
||||||
|
expect(calls.query[0].sql).not.toMatch(/WHERE j\.enabled = 1/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('coerces the enabled column to a boolean', () => {
|
||||||
|
sqliteMock.__queryHandler = () => [
|
||||||
|
{ id: 'enabled-job', enabled: 1 },
|
||||||
|
{ id: 'disabled-job', enabled: 0 },
|
||||||
|
];
|
||||||
|
const jobs = jobStorage.getJobs({ includeDisabled: true });
|
||||||
|
expect(jobs.find((j) => j.id === 'enabled-job').enabled).toBe(true);
|
||||||
|
expect(jobs.find((j) => j.id === 'disabled-job').enabled).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -185,6 +185,7 @@ const JobGrid = () => {
|
|||||||
await xhrPut(`/api/jobs/${jobId}/status`, { status });
|
await xhrPut(`/api/jobs/${jobId}/status`, { status });
|
||||||
Toast.success(t('jobs.toastStatusChanged'));
|
Toast.success(t('jobs.toastStatusChanged'));
|
||||||
loadData();
|
loadData();
|
||||||
|
actions.jobsData.getJobs(); // refresh the jobs slice read by the edit form so its switch isn't stale
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Toast.error(error.error);
|
Toast.error(error.error);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user