From 5a053cdcd6b88f9d19b50785626fbca74ddf8792 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Fri, 17 Jun 2022 13:25:47 -0800 Subject: [PATCH] feat: mealplan-webhooks (#1403) * fix type errors on event bus * webhooks fields required for new implementation * db migration * wip: webhook query + tests and stub function * ignore type checker error * type and method cleanup * datetime and time utc validator * update testing code for utc scheduled time * fix file cmp function call * update version_number * add support for translating "time" objects when restoring backup * bump recipe-scrapers * use specific import syntax * generate frontend types * utilize names exports * use utc times * add task to scheduler * implement new scheduler functionality * stub for type annotation * implement meal-plan data getter * add experimental banner --- ....34_f30cf048c228_add_new_webhook_fields.py | 31 +++++++ .../Domain/Group/GroupWebhookEditor.vue | 84 +++++++++++++++++++ frontend/composables/use-group-webhooks.ts | 41 ++++++++- frontend/pages/group/webhooks.vue | 62 +++++++------- frontend/types/api-types/group.ts | 10 ++- frontend/types/components.d.ts | 2 + mealie/app.py | 4 + mealie/db/models/group/webhooks.py | 13 ++- mealie/repos/repository_meals.py | 3 + mealie/schema/group/__init__.py | 2 +- mealie/schema/group/webhook.py | 40 ++++++++- .../services/backups_v2/alchemy_exporter.py | 9 +- .../event_bus_service/event_bus_service.py | 4 +- mealie/services/scheduler/tasks/__init__.py | 14 +++- .../services/scheduler/tasks/post_webhooks.py | 54 ++++++++++++ poetry.lock | 8 +- pyproject.toml | 2 +- tests/conftest.py | 16 ++-- .../user_group_tests/test_group_webhooks.py | 53 ++++++------ .../backup_v2_tests/test_alchemy_exporter.py | 2 +- .../backup_v2_tests/test_backup_v2.py | 2 +- .../scheduler/tasks/test_post_webhook.py | 65 ++++++++++++++ 22 files changed, 428 insertions(+), 93 deletions(-) create mode 100644 alembic/versions/2022-06-15-21.05.34_f30cf048c228_add_new_webhook_fields.py create mode 100644 frontend/components/Domain/Group/GroupWebhookEditor.vue create mode 100644 mealie/services/scheduler/tasks/post_webhooks.py create mode 100644 tests/unit_tests/services_tests/scheduler/tasks/test_post_webhook.py diff --git a/alembic/versions/2022-06-15-21.05.34_f30cf048c228_add_new_webhook_fields.py b/alembic/versions/2022-06-15-21.05.34_f30cf048c228_add_new_webhook_fields.py new file mode 100644 index 000000000000..5b1d029a1721 --- /dev/null +++ b/alembic/versions/2022-06-15-21.05.34_f30cf048c228_add_new_webhook_fields.py @@ -0,0 +1,31 @@ +"""add new webhook fields + + +Revision ID: f30cf048c228 +Revises: ab0bae02578f +Create Date: 2022-06-15 21:05:34.851857 + +""" +import sqlalchemy as sa + +from alembic import op + +# revision identifiers, used by Alembic. +revision = "f30cf048c228" +down_revision = "ab0bae02578f" +branch_labels = None +depends_on = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.add_column("webhook_urls", sa.Column("webhook_type", sa.String(), nullable=True)) + op.add_column("webhook_urls", sa.Column("scheduled_time", sa.Time(), nullable=True)) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_column("webhook_urls", "scheduled_time") + op.drop_column("webhook_urls", "webhook_type") + # ### end Alembic commands ### diff --git a/frontend/components/Domain/Group/GroupWebhookEditor.vue b/frontend/components/Domain/Group/GroupWebhookEditor.vue new file mode 100644 index 000000000000..b276fd032355 --- /dev/null +++ b/frontend/components/Domain/Group/GroupWebhookEditor.vue @@ -0,0 +1,84 @@ + + + diff --git a/frontend/composables/use-group-webhooks.ts b/frontend/composables/use-group-webhooks.ts index 7e7e2abcbd34..12fcc3493b49 100644 --- a/frontend/composables/use-group-webhooks.ts +++ b/frontend/composables/use-group-webhooks.ts @@ -37,7 +37,7 @@ export const useGroupWebhooks = function () { enabled: false, name: "New Webhook", url: "", - time: "00:00", + scheduledTime: "00:00", }; const { data } = await api.groupWebhooks.createOne(payload); @@ -52,8 +52,23 @@ export const useGroupWebhooks = function () { return; } + // Convert to UTC time + const [hours, minutes] = updateData.scheduledTime.split(":"); + + const newDt = new Date(); + newDt.setHours(Number(hours)); + newDt.setMinutes(Number(minutes)); + + updateData.scheduledTime = `${pad(newDt.getUTCHours(), 2)}:${pad(newDt.getUTCMinutes(), 2)}`; + console.log(updateData.scheduledTime); + + const payload = { + ...updateData, + scheduledTime: updateData.scheduledTime, + }; + loading.value = true; - const { data } = await api.groupWebhooks.updateOne(updateData.id, updateData); + const { data } = await api.groupWebhooks.updateOne(updateData.id, payload); if (data) { this.refreshAll(); } @@ -73,3 +88,25 @@ export const useGroupWebhooks = function () { return { webhooks, actions, validForm }; }; + +function pad(num: number, size: number) { + let numStr = num.toString(); + while (numStr.length < size) numStr = "0" + numStr; + return numStr; +} + +export function timeUTCToLocal(time: string): string { + const [hours, minutes] = time.split(":"); + const dt = new Date(); + dt.setUTCMinutes(Number(minutes)); + dt.setUTCHours(Number(hours)); + return `${pad(dt.getHours(), 2)}:${pad(dt.getMinutes(), 2)}`; +} + +export function timeLocalToUTC(time: string) { + const [hours, minutes] = time.split(":"); + const dt = new Date(); + dt.setHours(Number(hours)); + dt.setMinutes(Number(minutes)); + return `${pad(dt.getUTCHours(), 2)}:${pad(dt.getUTCMinutes(), 2)}`; +} diff --git a/frontend/pages/group/webhooks.vue b/frontend/pages/group/webhooks.vue index c631fbb97578..2bbf3b6b479f 100644 --- a/frontend/pages/group/webhooks.vue +++ b/frontend/pages/group/webhooks.vue @@ -5,10 +5,16 @@ - The webhooks defined below will be executed when a meal is defined for the day. At the scheduled time the webhooks - will be sent with the data from the recipe that is scheduled for the day + + The webhooks defined below will be executed when a meal is defined for the day. At the scheduled time the + webhooks will be sent with the data from the recipe that is scheduled for the day. Note that webhook execution + is not exact. The webhooks are executed on a 5 minutes interval so the webhooks will be executed within 5 +/- + minutes of the scheduled. + + + @@ -17,7 +23,7 @@ {{ $globals.icons.webhook }} - {{ webhook.name }} - {{ webhook.time }} + {{ webhook.name }} - {{ timeDisplay(timeUTCToLocal(webhook.scheduledTime)) }} - - - - - - - - - + @@ -65,15 +48,28 @@