From 45c0995d9d0bfa910c936a56107dcfdfbfa889c9 Mon Sep 17 00:00:00 2001 From: Ali BARIN Date: Thu, 6 Oct 2022 23:11:14 +0200 Subject: [PATCH] refactor: rewrite scheduler as functional --- .../src/apps/scheduler/common/cron-times.ts | 10 + .../scheduler/common/get-date-time-object.ts | 14 + .../common/get-next-cron-date-time.ts | 10 + packages/backend/src/apps/scheduler/index.ts | 25 +- packages/backend/src/apps/scheduler/info.json | 608 ------------------ .../backend/src/apps/scheduler/triggers.ts | 19 - .../src/apps/scheduler/triggers/every-day.ts | 40 -- .../scheduler/triggers/every-day/index.ts | 170 +++++ .../src/apps/scheduler/triggers/every-hour.ts | 35 - .../scheduler/triggers/every-hour/index.ts | 64 ++ .../apps/scheduler/triggers/every-month.ts | 36 -- .../scheduler/triggers/every-month/index.ts | 283 ++++++++ .../src/apps/scheduler/triggers/every-week.ts | 36 -- .../scheduler/triggers/every-week/index.ts | 187 ++++++ packages/backend/src/apps/scheduler/utils.ts | 32 - .../graphql/mutations/update-flow-status.ts | 2 +- 16 files changed, 749 insertions(+), 822 deletions(-) create mode 100644 packages/backend/src/apps/scheduler/common/cron-times.ts create mode 100644 packages/backend/src/apps/scheduler/common/get-date-time-object.ts create mode 100644 packages/backend/src/apps/scheduler/common/get-next-cron-date-time.ts delete mode 100644 packages/backend/src/apps/scheduler/info.json delete mode 100644 packages/backend/src/apps/scheduler/triggers.ts delete mode 100644 packages/backend/src/apps/scheduler/triggers/every-day.ts create mode 100644 packages/backend/src/apps/scheduler/triggers/every-day/index.ts delete mode 100644 packages/backend/src/apps/scheduler/triggers/every-hour.ts create mode 100644 packages/backend/src/apps/scheduler/triggers/every-hour/index.ts delete mode 100644 packages/backend/src/apps/scheduler/triggers/every-month.ts create mode 100644 packages/backend/src/apps/scheduler/triggers/every-month/index.ts delete mode 100644 packages/backend/src/apps/scheduler/triggers/every-week.ts create mode 100644 packages/backend/src/apps/scheduler/triggers/every-week/index.ts delete mode 100644 packages/backend/src/apps/scheduler/utils.ts diff --git a/packages/backend/src/apps/scheduler/common/cron-times.ts b/packages/backend/src/apps/scheduler/common/cron-times.ts new file mode 100644 index 00000000..bcc33254 --- /dev/null +++ b/packages/backend/src/apps/scheduler/common/cron-times.ts @@ -0,0 +1,10 @@ +const cronTimes = { + everyHour: '0 * * * *', + everyHourExcludingWeekends: '0 * * * 1-5', + everyDayAt: (hour: number) => `0 ${hour} * * *`, + everyDayExcludingWeekendsAt: (hour: number) => `0 ${hour} * * 1-5`, + everyWeekOnAndAt: (weekday: number, hour: number) => `0 ${hour} * * ${weekday}`, + everyMonthOnAndAt: (day: number, hour: number) => `0 ${hour} ${day} * *`, +}; + +export default cronTimes; diff --git a/packages/backend/src/apps/scheduler/common/get-date-time-object.ts b/packages/backend/src/apps/scheduler/common/get-date-time-object.ts new file mode 100644 index 00000000..9a48cbf2 --- /dev/null +++ b/packages/backend/src/apps/scheduler/common/get-date-time-object.ts @@ -0,0 +1,14 @@ +import { DateTime } from 'luxon'; + +export default function getDateTimeObjectRepresentation(dateTime: DateTime) { + const defaults = dateTime.toObject(); + + return { + ...defaults, + ISO_date_time: dateTime.toISO(), + pretty_date: dateTime.toLocaleString(DateTime.DATE_MED), + pretty_time: dateTime.toLocaleString(DateTime.TIME_WITH_SECONDS), + pretty_day_of_week: dateTime.toFormat('cccc'), + day_of_week: dateTime.weekday, + }; +} diff --git a/packages/backend/src/apps/scheduler/common/get-next-cron-date-time.ts b/packages/backend/src/apps/scheduler/common/get-next-cron-date-time.ts new file mode 100644 index 00000000..b339006b --- /dev/null +++ b/packages/backend/src/apps/scheduler/common/get-next-cron-date-time.ts @@ -0,0 +1,10 @@ +import { DateTime } from 'luxon'; +import cronParser from 'cron-parser'; + +export default function getNextCronDateTime(cronString: string) { + const cronDate = cronParser.parseExpression(cronString); + const matchingNextCronDateTime = cronDate.next(); + const matchingNextDateTime = DateTime.fromJSDate(matchingNextCronDateTime.toDate()); + + return matchingNextDateTime; +}; diff --git a/packages/backend/src/apps/scheduler/index.ts b/packages/backend/src/apps/scheduler/index.ts index b7ee1a76..60f6c4c4 100644 --- a/packages/backend/src/apps/scheduler/index.ts +++ b/packages/backend/src/apps/scheduler/index.ts @@ -1,15 +1,10 @@ -import Triggers from './triggers'; -import { - IService, - IConnection, - IFlow, - IStep, -} from '@automatisch/types'; - -export default class Scheduler implements IService { - triggers: Triggers; - - constructor(connection: IConnection, flow: IFlow, step: IStep) { - this.triggers = new Triggers(step.parameters); - } -} +export default { + name: "Scheduler", + key: "scheduler", + iconUrl: "{BASE_URL}/apps/scheduler/assets/favicon.svg", + docUrl: "https://automatisch.io/docs/scheduler", + authDocUrl: "https://automatisch.io/docs/connections/scheduler", + primaryColor: "0059F7", + supportsConnections: false, + requiresAuthentication: false, +}; diff --git a/packages/backend/src/apps/scheduler/info.json b/packages/backend/src/apps/scheduler/info.json deleted file mode 100644 index d00807d5..00000000 --- a/packages/backend/src/apps/scheduler/info.json +++ /dev/null @@ -1,608 +0,0 @@ -{ - "name": "Scheduler", - "key": "scheduler", - "iconUrl": "{BASE_URL}/apps/scheduler/assets/favicon.svg", - "docUrl": "https://automatisch.io/docs/scheduler", - "authDocUrl": "https://automatisch.io/docs/connections/scheduler", - "primaryColor": "0059F7", - "supportsConnections": false, - "requiresAuthentication": false, - "triggers": [ - { - "name": "Every hour", - "key": "everyHour", - "description": "Triggers every hour.", - "substeps": [ - { - "key": "chooseTrigger", - "name": "Set up a trigger", - "arguments": [ - { - "label": "Trigger on weekends?", - "key": "triggersOnWeekend", - "type": "dropdown", - "description": "Should this flow trigger on Saturday and Sunday?", - "required": true, - "value": true, - "variables": false, - "options": [ - { - "label": "Yes", - "value": true - }, - { - "label": "No", - "value": false - } - ] - } - ] - }, - { - "key": "testStep", - "name": "Test trigger" - } - ] - }, - { - "name": "Every day", - "key": "everyDay", - "description": "Triggers every day.", - "substeps": [ - { - "key": "chooseTrigger", - "name": "Set up a trigger", - "arguments": [ - { - "label": "Trigger on weekends?", - "key": "triggersOnWeekend", - "type": "dropdown", - "description": "Should this flow trigger on Saturday and Sunday?", - "required": true, - "value": true, - "variables": false, - "options": [ - { - "label": "Yes", - "value": true - }, - { - "label": "No", - "value": false - } - ] - }, - { - "label": "Time of day", - "key": "hour", - "type": "dropdown", - "required": true, - "value": null, - "variables": false, - "options": [ - { - "label": "00:00", - "value": 0 - }, - { - "label": "01:00", - "value": 1 - }, - { - "label": "02:00", - "value": 2 - }, - { - "label": "03:00", - "value": 3 - }, - { - "label": "04:00", - "value": 4 - }, - { - "label": "05:00", - "value": 5 - }, - { - "label": "06:00", - "value": 6 - }, - { - "label": "07:00", - "value": 7 - }, - { - "label": "08:00", - "value": 8 - }, - { - "label": "09:00", - "value": 9 - }, - { - "label": "10:00", - "value": 10 - }, - { - "label": "11:00", - "value": 11 - }, - { - "label": "12:00", - "value": 12 - }, - { - "label": "13:00", - "value": 13 - }, - { - "label": "14:00", - "value": 14 - }, - { - "label": "15:00", - "value": 15 - }, - { - "label": "16:00", - "value": 16 - }, - { - "label": "17:00", - "value": 17 - }, - { - "label": "18:00", - "value": 18 - }, - { - "label": "19:00", - "value": 19 - }, - { - "label": "20:00", - "value": 20 - }, - { - "label": "21:00", - "value": 21 - }, - { - "label": "22:00", - "value": 22 - }, - { - "label": "23:00", - "value": 23 - } - ] - } - ] - }, - { - "key": "testStep", - "name": "Test trigger" - } - ] - }, - { - "name": "Every week", - "key": "everyWeek", - "description": "Triggers every week.", - "substeps": [ - { - "key": "chooseTrigger", - "name": "Set up a trigger", - "arguments": [ - { - "label": "Day of the week", - "key": "weekday", - "type": "dropdown", - "required": true, - "value": null, - "variables": false, - "options": [ - { - "label": "Monday", - "value": 1 - }, - { - "label": "Tuesday", - "value": 2 - }, - { - "label": "Wednesday", - "value": 3 - }, - { - "label": "Thursday", - "value": 4 - }, - { - "label": "Friday", - "value": 5 - }, - { - "label": "Saturday", - "value": 6 - }, - { - "label": "Sunday", - "value": 0 - } - ] - }, - { - "label": "Time of day", - "key": "hour", - "type": "dropdown", - "required": true, - "value": null, - "variables": false, - "options": [ - { - "label": "00:00", - "value": 0 - }, - { - "label": "01:00", - "value": 1 - }, - { - "label": "02:00", - "value": 2 - }, - { - "label": "03:00", - "value": 3 - }, - { - "label": "04:00", - "value": 4 - }, - { - "label": "05:00", - "value": 5 - }, - { - "label": "06:00", - "value": 6 - }, - { - "label": "07:00", - "value": 7 - }, - { - "label": "08:00", - "value": 8 - }, - { - "label": "09:00", - "value": 9 - }, - { - "label": "10:00", - "value": 10 - }, - { - "label": "11:00", - "value": 11 - }, - { - "label": "12:00", - "value": 12 - }, - { - "label": "13:00", - "value": 13 - }, - { - "label": "14:00", - "value": 14 - }, - { - "label": "15:00", - "value": 15 - }, - { - "label": "16:00", - "value": 16 - }, - { - "label": "17:00", - "value": 17 - }, - { - "label": "18:00", - "value": 18 - }, - { - "label": "19:00", - "value": 19 - }, - { - "label": "20:00", - "value": 20 - }, - { - "label": "21:00", - "value": 21 - }, - { - "label": "22:00", - "value": 22 - }, - { - "label": "23:00", - "value": 23 - } - ] - } - ] - }, - { - "key": "testStep", - "name": "Test trigger" - } - ] - }, - { - "name": "Every month", - "key": "everyMonth", - "description": "Triggers every month.", - "substeps": [ - { - "key": "chooseTrigger", - "name": "Set up a trigger", - "arguments": [ - { - "label": "Day of the month", - "key": "day", - "type": "dropdown", - "required": true, - "value": null, - "variables": false, - "options": [ - { - "label": 1, - "value": 1 - }, - { - "label": 2, - "value": 2 - }, - { - "label": 3, - "value": 3 - }, - { - "label": 4, - "value": 4 - }, - { - "label": 5, - "value": 5 - }, - { - "label": 6, - "value": 6 - }, - { - "label": 7, - "value": 7 - }, - { - "label": 8, - "value": 8 - }, - { - "label": 9, - "value": 9 - }, - { - "label": 10, - "value": 10 - }, - { - "label": 11, - "value": 11 - }, - { - "label": 12, - "value": 12 - }, - { - "label": 13, - "value": 13 - }, - { - "label": 14, - "value": 14 - }, - { - "label": 15, - "value": 15 - }, - { - "label": 16, - "value": 16 - }, - { - "label": 17, - "value": 17 - }, - { - "label": 18, - "value": 18 - }, - { - "label": 19, - "value": 19 - }, - { - "label": 20, - "value": 20 - }, - { - "label": 21, - "value": 21 - }, - { - "label": 22, - "value": 22 - }, - { - "label": 23, - "value": 23 - }, - { - "label": 24, - "value": 24 - }, - { - "label": 25, - "value": 25 - }, - { - "label": 26, - "value": 26 - }, - { - "label": 27, - "value": 27 - }, - { - "label": 28, - "value": 28 - }, - { - "label": 29, - "value": 29 - }, - { - "label": 30, - "value": 30 - }, - { - "label": 31, - "value": 31 - } - ] - }, - { - "label": "Time of day", - "key": "hour", - "type": "dropdown", - "required": true, - "value": null, - "variables": false, - "options": [ - { - "label": "00:00", - "value": 0 - }, - { - "label": "01:00", - "value": 1 - }, - { - "label": "02:00", - "value": 2 - }, - { - "label": "03:00", - "value": 3 - }, - { - "label": "04:00", - "value": 4 - }, - { - "label": "05:00", - "value": 5 - }, - { - "label": "06:00", - "value": 6 - }, - { - "label": "07:00", - "value": 7 - }, - { - "label": "08:00", - "value": 8 - }, - { - "label": "09:00", - "value": 9 - }, - { - "label": "10:00", - "value": 10 - }, - { - "label": "11:00", - "value": 11 - }, - { - "label": "12:00", - "value": 12 - }, - { - "label": "13:00", - "value": 13 - }, - { - "label": "14:00", - "value": 14 - }, - { - "label": "15:00", - "value": 15 - }, - { - "label": "16:00", - "value": 16 - }, - { - "label": "17:00", - "value": 17 - }, - { - "label": "18:00", - "value": 18 - }, - { - "label": "19:00", - "value": 19 - }, - { - "label": "20:00", - "value": 20 - }, - { - "label": "21:00", - "value": 21 - }, - { - "label": "22:00", - "value": 22 - }, - { - "label": "23:00", - "value": 23 - } - ] - } - ] - }, - { - "key": "testStep", - "name": "Test trigger" - } - ] - } - ] -} diff --git a/packages/backend/src/apps/scheduler/triggers.ts b/packages/backend/src/apps/scheduler/triggers.ts deleted file mode 100644 index ef959681..00000000 --- a/packages/backend/src/apps/scheduler/triggers.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { IStep } from '@automatisch/types'; -import EveryHour from './triggers/every-hour'; -import EveryDay from './triggers/every-day'; -import EveryWeek from './triggers/every-week'; -import EveryMonth from './triggers/every-month'; - -export default class Triggers { - everyHour: EveryHour; - everyDay: EveryDay; - everyWeek: EveryWeek; - everyMonth: EveryMonth; - - constructor(parameters: IStep["parameters"]) { - this.everyHour = new EveryHour(parameters); - this.everyDay = new EveryDay(parameters); - this.everyWeek = new EveryWeek(parameters); - this.everyMonth = new EveryMonth(parameters); - } -} diff --git a/packages/backend/src/apps/scheduler/triggers/every-day.ts b/packages/backend/src/apps/scheduler/triggers/every-day.ts deleted file mode 100644 index dceb2d7e..00000000 --- a/packages/backend/src/apps/scheduler/triggers/every-day.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { DateTime } from 'luxon'; -import type { IStep, IJSONValue, ITrigger } from '@automatisch/types'; -import { cronTimes, getNextCronDateTime, getDateTimeObjectRepresentation } from '../utils'; - -export default class EveryDay implements ITrigger { - triggersOnWeekend?: boolean; - hour?: number; - - constructor(parameters: IStep["parameters"]) { - if (parameters.triggersOnWeekend) { - this.triggersOnWeekend = parameters.triggersOnWeekend as boolean; - } - - if (parameters.hour) { - this.hour = parameters.hour as number; - } - } - - get interval() { - if (this.triggersOnWeekend) { - return cronTimes.everyDayAt(this.hour); - } - - return cronTimes.everyDayExcludingWeekendsAt(this.hour); - } - - async run(startDateTime: Date) { - const dateTime = DateTime.fromJSDate(startDateTime); - const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(dateTime) as IJSONValue; - - return [dateTimeObjectRepresentation] as IJSONValue; - } - - async testRun() { - const nextCronDateTime = getNextCronDateTime(this.interval); - const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(nextCronDateTime) as IJSONValue; - - return [dateTimeObjectRepresentation] as IJSONValue; - } -} diff --git a/packages/backend/src/apps/scheduler/triggers/every-day/index.ts b/packages/backend/src/apps/scheduler/triggers/every-day/index.ts new file mode 100644 index 00000000..faed677a --- /dev/null +++ b/packages/backend/src/apps/scheduler/triggers/every-day/index.ts @@ -0,0 +1,170 @@ +import { DateTime } from 'luxon'; +import { IGlobalVariable, IJSONValue } from '@automatisch/types'; +import cronTimes from '../../common/cron-times'; +import getNextCronDateTime from '../../common/get-next-cron-date-time'; +import getDateTimeObjectRepresentation from '../../common/get-date-time-object'; + +export default { + name: 'Every day', + key: 'everyDay', + description: 'Triggers every day.', + substeps: [ + { + key: 'chooseTrigger', + name: 'Set up a trigger', + arguments: [ + { + label: 'Trigger on weekends?', + key: 'triggersOnWeekend', + type: 'dropdown', + description: 'Should this flow trigger on Saturday and Sunday?', + required: true, + value: true, + variables: false, + options: [ + { + label: 'Yes', + value: true + }, + { + label: 'No', + value: false + } + ] + }, + { + label: 'Time of day', + key: 'hour', + type: 'dropdown', + required: true, + value: null, + variables: false, + options: [ + { + label: '00:00', + value: 0 + }, + { + label: '01:00', + value: 1 + }, + { + label: '02:00', + value: 2 + }, + { + label: '03:00', + value: 3 + }, + { + label: '04:00', + value: 4 + }, + { + label: '05:00', + value: 5 + }, + { + label: '06:00', + value: 6 + }, + { + label: '07:00', + value: 7 + }, + { + label: '08:00', + value: 8 + }, + { + label: '09:00', + value: 9 + }, + { + label: '10:00', + value: 10 + }, + { + label: '11:00', + value: 11 + }, + { + label: '12:00', + value: 12 + }, + { + label: '13:00', + value: 13 + }, + { + label: '14:00', + value: 14 + }, + { + label: '15:00', + value: 15 + }, + { + label: '16:00', + value: 16 + }, + { + label: '17:00', + value: 17 + }, + { + label: '18:00', + value: 18 + }, + { + label: '19:00', + value: 19 + }, + { + label: '20:00', + value: 20 + }, + { + label: '21:00', + value: 21 + }, + { + label: '22:00', + value: 22 + }, + { + label: '23:00', + value: 23 + } + ] + } + ] + }, + { + key: 'testStep', + name: 'Test trigger' + } + ], + + getInterval(parameters: IGlobalVariable["db"]["step"]["parameters"]) { + if (parameters.triggersOnWeekend as boolean) { + return cronTimes.everyDayAt(parameters.hour as number); + } + + return cronTimes.everyDayExcludingWeekendsAt(parameters.hour as number); + }, + + async run($: IGlobalVariable, startDateTime: Date) { + const dateTime = DateTime.fromJSDate(startDateTime); + const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(dateTime) as IJSONValue; + + return [dateTimeObjectRepresentation] as IJSONValue; + }, + + async testRun($: IGlobalVariable) { + const nextCronDateTime = getNextCronDateTime(this.getInterval($.db.step.parameters)); + const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(nextCronDateTime) as IJSONValue; + + return [dateTimeObjectRepresentation] as IJSONValue; + }, +}; diff --git a/packages/backend/src/apps/scheduler/triggers/every-hour.ts b/packages/backend/src/apps/scheduler/triggers/every-hour.ts deleted file mode 100644 index f76c9cf6..00000000 --- a/packages/backend/src/apps/scheduler/triggers/every-hour.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { DateTime } from 'luxon'; -import type { IStep, IJSONValue, ITrigger } from '@automatisch/types'; -import { cronTimes, getNextCronDateTime, getDateTimeObjectRepresentation } from '../utils'; - -export default class EveryHour implements ITrigger { - triggersOnWeekend?: boolean | string; - - constructor(parameters: IStep["parameters"]) { - if (parameters.triggersOnWeekend) { - this.triggersOnWeekend = parameters.triggersOnWeekend as string; - } - } - - get interval() { - if (this.triggersOnWeekend) { - return cronTimes.everyHour; - } - - return cronTimes.everyHourExcludingWeekends; - } - - async run(startDateTime: Date) { - const dateTime = DateTime.fromJSDate(startDateTime); - const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(dateTime) as IJSONValue; - - return [dateTimeObjectRepresentation] as IJSONValue; - } - - async testRun() { - const nextCronDateTime = getNextCronDateTime(this.interval); - const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(nextCronDateTime) as IJSONValue; - - return [dateTimeObjectRepresentation] as IJSONValue; - } -} diff --git a/packages/backend/src/apps/scheduler/triggers/every-hour/index.ts b/packages/backend/src/apps/scheduler/triggers/every-hour/index.ts new file mode 100644 index 00000000..e13e7d3d --- /dev/null +++ b/packages/backend/src/apps/scheduler/triggers/every-hour/index.ts @@ -0,0 +1,64 @@ +import { DateTime } from 'luxon'; +import { IGlobalVariable, IJSONValue } from '@automatisch/types'; +import cronTimes from '../../common/cron-times'; +import getNextCronDateTime from '../../common/get-next-cron-date-time'; +import getDateTimeObjectRepresentation from '../../common/get-date-time-object'; + +export default { + name: 'Every hour', + key: 'everyHour', + description: 'Triggers every hour.', + substeps: [ + { + key: 'chooseTrigger', + name: 'Set up a trigger', + arguments: [ + { + label: 'Trigger on weekends?', + key: 'triggersOnWeekend', + type: 'dropdown', + description: 'Should this flow trigger on Saturday and Sunday?', + required: true, + value: true, + variables: false, + options: [ + { + label: 'Yes', + value: true + }, + { + label: 'No', + value: false + } + ] + } + ] + }, + { + key: 'testStep', + name: 'Test trigger' + } + ], + + getInterval(parameters: IGlobalVariable["db"]["step"]["parameters"]) { + if (parameters.triggersOnWeekend) { + return cronTimes.everyHour + } + + return cronTimes.everyHourExcludingWeekends; + }, + + async run($: IGlobalVariable, startDateTime: Date) { + const dateTime = DateTime.fromJSDate(startDateTime); + const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(dateTime) as IJSONValue; + + return [dateTimeObjectRepresentation] as IJSONValue; + }, + + async testRun($: IGlobalVariable) { + const nextCronDateTime = getNextCronDateTime(this.getInterval($.db.step.parameters)); + const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(nextCronDateTime) as IJSONValue; + + return [dateTimeObjectRepresentation] as IJSONValue; + }, +}; diff --git a/packages/backend/src/apps/scheduler/triggers/every-month.ts b/packages/backend/src/apps/scheduler/triggers/every-month.ts deleted file mode 100644 index 822e3b31..00000000 --- a/packages/backend/src/apps/scheduler/triggers/every-month.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { DateTime } from 'luxon'; -import type { IStep, IJSONValue, ITrigger } from '@automatisch/types'; -import { cronTimes, getNextCronDateTime, getDateTimeObjectRepresentation } from '../utils'; - -export default class EveryMonth implements ITrigger { - day?: number; - hour?: number; - - constructor(parameters: IStep["parameters"]) { - if (parameters.day) { - this.day = parameters.day as number; - } - - if (parameters.hour) { - this.hour = parameters.hour as number; - } - } - - get interval() { - return cronTimes.everyMonthOnAndAt(this.day, this.hour); - } - - async run(startDateTime: Date) { - const dateTime = DateTime.fromJSDate(startDateTime); - const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(dateTime) as IJSONValue; - - return [dateTimeObjectRepresentation] as IJSONValue; - } - - async testRun() { - const nextCronDateTime = getNextCronDateTime(this.interval); - const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(nextCronDateTime) as IJSONValue; - - return [dateTimeObjectRepresentation] as IJSONValue; - } -} diff --git a/packages/backend/src/apps/scheduler/triggers/every-month/index.ts b/packages/backend/src/apps/scheduler/triggers/every-month/index.ts new file mode 100644 index 00000000..203a1393 --- /dev/null +++ b/packages/backend/src/apps/scheduler/triggers/every-month/index.ts @@ -0,0 +1,283 @@ +import { DateTime } from 'luxon'; +import { IGlobalVariable, IJSONValue } from '@automatisch/types'; +import cronTimes from '../../common/cron-times'; +import getNextCronDateTime from '../../common/get-next-cron-date-time'; +import getDateTimeObjectRepresentation from '../../common/get-date-time-object'; + +export default { + name: 'Every month', + key: 'everyMonth', + description: 'Triggers every month.', + substeps: [ + { + key: 'chooseTrigger', + name: 'Set up a trigger', + arguments: [ + { + label: 'Day of the month', + key: 'day', + type: 'dropdown', + required: true, + value: null, + variables: false, + options: [ + { + label: 1, + value: 1 + }, + { + label: 2, + value: 2 + }, + { + label: 3, + value: 3 + }, + { + label: 4, + value: 4 + }, + { + label: 5, + value: 5 + }, + { + label: 6, + value: 6 + }, + { + label: 7, + value: 7 + }, + { + label: 8, + value: 8 + }, + { + label: 9, + value: 9 + }, + { + label: 10, + value: 10 + }, + { + label: 11, + value: 11 + }, + { + label: 12, + value: 12 + }, + { + label: 13, + value: 13 + }, + { + label: 14, + value: 14 + }, + { + label: 15, + value: 15 + }, + { + label: 16, + value: 16 + }, + { + label: 17, + value: 17 + }, + { + label: 18, + value: 18 + }, + { + label: 19, + value: 19 + }, + { + label: 20, + value: 20 + }, + { + label: 21, + value: 21 + }, + { + label: 22, + value: 22 + }, + { + label: 23, + value: 23 + }, + { + label: 24, + value: 24 + }, + { + label: 25, + value: 25 + }, + { + label: 26, + value: 26 + }, + { + label: 27, + value: 27 + }, + { + label: 28, + value: 28 + }, + { + label: 29, + value: 29 + }, + { + label: 30, + value: 30 + }, + { + label: 31, + value: 31 + } + ] + }, + { + label: 'Time of day', + key: 'hour', + type: 'dropdown', + required: true, + value: null, + variables: false, + options: [ + { + label: '00:00', + value: 0 + }, + { + label: '01:00', + value: 1 + }, + { + label: '02:00', + value: 2 + }, + { + label: '03:00', + value: 3 + }, + { + label: '04:00', + value: 4 + }, + { + label: '05:00', + value: 5 + }, + { + label: '06:00', + value: 6 + }, + { + label: '07:00', + value: 7 + }, + { + label: '08:00', + value: 8 + }, + { + label: '09:00', + value: 9 + }, + { + label: '10:00', + value: 10 + }, + { + label: '11:00', + value: 11 + }, + { + label: '12:00', + value: 12 + }, + { + label: '13:00', + value: 13 + }, + { + label: '14:00', + value: 14 + }, + { + label: '15:00', + value: 15 + }, + { + label: '16:00', + value: 16 + }, + { + label: '17:00', + value: 17 + }, + { + label: '18:00', + value: 18 + }, + { + label: '19:00', + value: 19 + }, + { + label: '20:00', + value: 20 + }, + { + label: '21:00', + value: 21 + }, + { + label: '22:00', + value: 22 + }, + { + label: '23:00', + value: 23 + } + ] + } + ] + }, + { + key: 'testStep', + name: 'Test trigger' + } + ], + + getInterval(parameters: IGlobalVariable["db"]["step"]["parameters"]) { + const interval = cronTimes.everyMonthOnAndAt(parameters.day as number, parameters.hour as number); + + return interval; + }, + + async run($: IGlobalVariable, startDateTime: Date) { + const dateTime = DateTime.fromJSDate(startDateTime); + const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(dateTime) as IJSONValue; + + return [dateTimeObjectRepresentation] as IJSONValue; + }, + + async testRun($: IGlobalVariable) { + const nextCronDateTime = getNextCronDateTime(this.getInterval($.db.step.parameters)); + const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(nextCronDateTime) as IJSONValue; + + return [dateTimeObjectRepresentation] as IJSONValue; + }, +}; diff --git a/packages/backend/src/apps/scheduler/triggers/every-week.ts b/packages/backend/src/apps/scheduler/triggers/every-week.ts deleted file mode 100644 index 06012f7e..00000000 --- a/packages/backend/src/apps/scheduler/triggers/every-week.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { DateTime } from 'luxon'; -import type { IStep, IJSONValue, ITrigger } from '@automatisch/types'; -import { cronTimes, getNextCronDateTime, getDateTimeObjectRepresentation } from '../utils'; - -export default class EveryWeek implements ITrigger { - weekday?: number; - hour?: number; - - constructor(parameters: IStep["parameters"]) { - if (parameters.weekday) { - this.weekday = parameters.weekday as number; - } - - if (parameters.hour) { - this.hour = parameters.hour as number; - } - } - - get interval() { - return cronTimes.everyWeekOnAndAt(this.weekday, this.hour); - } - - async run(startDateTime: Date) { - const dateTime = DateTime.fromJSDate(startDateTime); - const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(dateTime) as IJSONValue; - - return [dateTimeObjectRepresentation] as IJSONValue; - } - - async testRun() { - const nextCronDateTime = getNextCronDateTime(this.interval); - const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(nextCronDateTime) as IJSONValue; - - return [dateTimeObjectRepresentation] as IJSONValue; - } -} diff --git a/packages/backend/src/apps/scheduler/triggers/every-week/index.ts b/packages/backend/src/apps/scheduler/triggers/every-week/index.ts new file mode 100644 index 00000000..72479cb3 --- /dev/null +++ b/packages/backend/src/apps/scheduler/triggers/every-week/index.ts @@ -0,0 +1,187 @@ +import { DateTime } from 'luxon'; +import { IGlobalVariable, IJSONValue } from '@automatisch/types'; +import cronTimes from '../../common/cron-times'; +import getNextCronDateTime from '../../common/get-next-cron-date-time'; +import getDateTimeObjectRepresentation from '../../common/get-date-time-object'; + +export default { + name: 'Every week', + key: 'everyWeek', + description: 'Triggers every week.', + substeps: [ + { + key: 'chooseTrigger', + name: 'Set up a trigger', + arguments: [ + { + label: 'Day of the week', + key: 'weekday', + type: 'dropdown', + required: true, + value: null, + variables: false, + options: [ + { + label: 'Monday', + value: 1 + }, + { + label: 'Tuesday', + value: 2 + }, + { + label: 'Wednesday', + value: 3 + }, + { + label: 'Thursday', + value: 4 + }, + { + label: 'Friday', + value: 5 + }, + { + label: 'Saturday', + value: 6 + }, + { + label: 'Sunday', + value: 0 + } + ] + }, + { + label: 'Time of day', + key: 'hour', + type: 'dropdown', + required: true, + value: null, + variables: false, + options: [ + { + label: '00:00', + value: 0 + }, + { + label: '01:00', + value: 1 + }, + { + label: '02:00', + value: 2 + }, + { + label: '03:00', + value: 3 + }, + { + label: '04:00', + value: 4 + }, + { + label: '05:00', + value: 5 + }, + { + label: '06:00', + value: 6 + }, + { + label: '07:00', + value: 7 + }, + { + label: '08:00', + value: 8 + }, + { + label: '09:00', + value: 9 + }, + { + label: '10:00', + value: 10 + }, + { + label: '11:00', + value: 11 + }, + { + label: '12:00', + value: 12 + }, + { + label: '13:00', + value: 13 + }, + { + label: '14:00', + value: 14 + }, + { + label: '15:00', + value: 15 + }, + { + label: '16:00', + value: 16 + }, + { + label: '17:00', + value: 17 + }, + { + label: '18:00', + value: 18 + }, + { + label: '19:00', + value: 19 + }, + { + label: '20:00', + value: 20 + }, + { + label: '21:00', + value: 21 + }, + { + label: '22:00', + value: 22 + }, + { + label: '23:00', + value: 23 + } + ] + } + ] + }, + { + key: 'testStep', + name: 'Test trigger' + } + ], + + getInterval(parameters: IGlobalVariable["db"]["step"]["parameters"]) { + const interval = cronTimes.everyWeekOnAndAt(parameters.weekday as number, parameters.hour as number); + + return interval; + }, + + async run($: IGlobalVariable, startDateTime: Date) { + const dateTime = DateTime.fromJSDate(startDateTime); + const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(dateTime) as IJSONValue; + + return [dateTimeObjectRepresentation] as IJSONValue; + }, + + async testRun($: IGlobalVariable) { + const nextCronDateTime = getNextCronDateTime(this.getInterval($.db.step.parameters)); + const dateTimeObjectRepresentation = getDateTimeObjectRepresentation(nextCronDateTime) as IJSONValue; + + return [dateTimeObjectRepresentation] as IJSONValue; + }, +}; diff --git a/packages/backend/src/apps/scheduler/utils.ts b/packages/backend/src/apps/scheduler/utils.ts deleted file mode 100644 index 192ba102..00000000 --- a/packages/backend/src/apps/scheduler/utils.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { DateTime } from 'luxon'; -import cronParser from 'cron-parser'; - -export const cronTimes = { - everyHour: '0 * * * *', - everyHourExcludingWeekends: '0 * * * 1-5', - everyDayAt: (hour: number) => `0 ${hour} * * *`, - everyDayExcludingWeekendsAt: (hour: number) => `0 ${hour} * * 1-5`, - everyWeekOnAndAt: (weekday: number, hour: number) => `0 ${hour} * * ${weekday}`, - everyMonthOnAndAt: (day: number, hour: number) => `0 ${hour} ${day} * *`, -}; - -export function getNextCronDateTime(cronString: string) { - const cronDate = cronParser.parseExpression(cronString); - const matchingNextCronDateTime = cronDate.next(); - const matchingNextDateTime = DateTime.fromJSDate(matchingNextCronDateTime.toDate()); - - return matchingNextDateTime; -}; - -export function getDateTimeObjectRepresentation(dateTime: DateTime) { - const defaults = dateTime.toObject(); - - return { - ...defaults, - ISO_date_time: dateTime.toISO(), - pretty_date: dateTime.toLocaleString(DateTime.DATE_MED), - pretty_time: dateTime.toLocaleString(DateTime.TIME_WITH_SECONDS), - pretty_day_of_week: dateTime.toFormat('cccc'), - day_of_week: dateTime.weekday, - }; -} diff --git a/packages/backend/src/graphql/mutations/update-flow-status.ts b/packages/backend/src/graphql/mutations/update-flow-status.ts index 11ec676e..467f9c27 100644 --- a/packages/backend/src/graphql/mutations/update-flow-status.ts +++ b/packages/backend/src/graphql/mutations/update-flow-status.ts @@ -33,7 +33,7 @@ const updateFlowStatus = async ( const triggerStep = await flow.getTriggerStep(); const trigger = await triggerStep.getTrigger(); - const interval = trigger.interval; + const interval = trigger.getInterval(triggerStep.parameters); const repeatOptions = { cron: interval || EVERY_15_MINUTES_CRON, };