From 8c4be2fbe80e42472b8b17542a4282ec26d1fefe Mon Sep 17 00:00:00 2001 From: Meier Lukas Date: Fri, 20 Feb 2026 17:44:02 +0100 Subject: [PATCH] fix(analytics): restrict publishing to every week (#5028) --- .../tools/tasks/_components/tasks-table.tsx | 2 ++ apps/tasks/src/job-manager.ts | 13 ++++++++++++- packages/cron-job-api/src/index.ts | 10 +++++++++- packages/cron-jobs-core/src/creator.ts | 18 ++++++++++-------- packages/cron-jobs/src/jobs/analytics.ts | 1 + 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/apps/nextjs/src/app/[locale]/manage/tools/tasks/_components/tasks-table.tsx b/apps/nextjs/src/app/[locale]/manage/tools/tasks/_components/tasks-table.tsx index ceb27aa81..273f1e9ec 100644 --- a/apps/nextjs/src/app/[locale]/manage/tools/tasks/_components/tasks-table.tsx +++ b/apps/nextjs/src/app/[locale]/manage/tools/tasks/_components/tasks-table.tsx @@ -117,6 +117,8 @@ const createColumns = ( header: tTasks("field.interval.label"), size: 200, Cell({ row }) { + if (row.original.preventCustomInterval) return null; + const handleIntervalChange = (newCron: string | null) => { if (!newCron || newCron === row.original.cron) return; diff --git a/apps/tasks/src/job-manager.ts b/apps/tasks/src/job-manager.ts index 9e23c7d36..f4ec8bf97 100644 --- a/apps/tasks/src/job-manager.ts +++ b/apps/tasks/src/job-manager.ts @@ -31,6 +31,10 @@ export class JobManager implements IJobManager { if (!validateCron(cron)) { throw new Error(`Invalid cron expression: ${cron}`); } + if (job.preventCustomInterval && cron !== job.cronExpression) { + throw new Error(`Custom cron expressions are not allowed for job ${name}`); + } + await this.updateConfigurationAsync(name, { cronExpression: cron }); await this.jobGroup.getTask(name)?.destroy(); @@ -100,7 +104,13 @@ export class JobManager implements IJobManager { } public async getAllAsync(): Promise< - { name: JobGroupKeys; cron: string; preventManualExecution: boolean; isEnabled: boolean }[] + { + name: JobGroupKeys; + cron: string; + preventManualExecution: boolean; + preventCustomInterval: boolean; + isEnabled: boolean; + }[] > { const configurations = await this.db.query.cronJobConfigurations.findMany(); @@ -110,6 +120,7 @@ export class JobManager implements IJobManager { name, cron: config?.cronExpression ?? job.cronExpression, preventManualExecution: job.preventManualExecution, + preventCustomInterval: job.preventCustomInterval, isEnabled: config?.isEnabled ?? true, }; }); diff --git a/packages/cron-job-api/src/index.ts b/packages/cron-job-api/src/index.ts index cc3afb0a6..270a51242 100644 --- a/packages/cron-job-api/src/index.ts +++ b/packages/cron-job-api/src/index.ts @@ -17,7 +17,15 @@ export interface IJobManager { updateIntervalAsync(name: JobGroupKeys, cron: string): Promise; disableAsync(name: JobGroupKeys): Promise; enableAsync(name: JobGroupKeys): Promise; - getAllAsync(): Promise<{ name: JobGroupKeys; cron: string; preventManualExecution: boolean; isEnabled: boolean }[]>; + getAllAsync(): Promise< + { + name: JobGroupKeys; + cron: string; + preventManualExecution: boolean; + preventCustomInterval: boolean; + isEnabled: boolean; + }[] + >; } const t = initTRPC diff --git a/packages/cron-jobs-core/src/creator.ts b/packages/cron-jobs-core/src/creator.ts index c22598295..4f7a9310f 100644 --- a/packages/cron-jobs-core/src/creator.ts +++ b/packages/cron-jobs-core/src/creator.ts @@ -19,6 +19,7 @@ export interface CreateCronJobCreatorOptions { interface CreateCronJobOptions { runOnStart?: boolean; preventManualExecution?: boolean; + preventCustomInterval?: boolean; expectedMaximumDurationInMillis?: number; beforeStart?: () => MaybePromise; } @@ -78,14 +79,14 @@ const createCallback = eq(cronJobConfigurations.name, name), }); - const scheduledTask = createTask( - configuration?.cronExpression ?? defaultCronExpression, - () => void catchingCallbackAsync(), - { - name, - timezone: creatorOptions.timezone, - }, - ); + const cronExpression = options.preventCustomInterval + ? defaultCronExpression + : (configuration?.cronExpression ?? defaultCronExpression); + + const scheduledTask = createTask(cronExpression, () => void catchingCallbackAsync(), { + name, + timezone: creatorOptions.timezone, + }); creatorOptions.logger.logDebug("The scheduled task for cron job was created", { name, cronExpression: defaultCronExpression, @@ -114,6 +115,7 @@ const createCallback = { if (env.NO_EXTERNAL_CONNECTION) return; const analyticSetting = await getServerSettingByKeyAsync(db, "analytics");