From d3436a5ca8dae8d4e434b09cdd7cd1636e5f0603 Mon Sep 17 00:00:00 2001 From: Craig Matear Date: Sun, 10 Aug 2025 02:43:23 +0100 Subject: [PATCH] feat: Add label notifier (#5879) Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com> --- frontend/lang/messages/en-US.json | 3 +- frontend/lib/api/types/admin.ts | 5 +- frontend/lib/api/types/analytics.ts | 1 - frontend/lib/api/types/cookbook.ts | 5 +- frontend/lib/api/types/group.ts | 1 - frontend/lib/api/types/household.ts | 14 ++- frontend/lib/api/types/labels.ts | 1 - frontend/lib/api/types/meal-plan.ts | 9 +- frontend/lib/api/types/recipe.ts | 15 ++- frontend/lib/api/types/reports.ts | 1 - frontend/lib/api/types/response.ts | 1 - frontend/lib/api/types/user.ts | 3 +- frontend/pages/household/notifiers.vue | 18 ++++ frontend/types/components.d.ts | 2 +- ...b583aac2d_add_label_notifier_crud_bools.py | 48 ++++++++++ mealie/db/models/household/events.py | 4 + mealie/routes/groups/controller_labels.py | 36 +++++++- mealie/schema/_mealie/__init__.py | 6 +- mealie/schema/admin/__init__.py | 36 ++++---- mealie/schema/group/__init__.py | 6 +- mealie/schema/household/__init__.py | 86 ++++++++--------- mealie/schema/household/group_events.py | 4 + mealie/schema/meal_plan/__init__.py | 6 +- mealie/schema/recipe/__init__.py | 92 +++++++++---------- mealie/schema/response/__init__.py | 4 +- mealie/schema/user/__init__.py | 12 +-- .../services/event_bus_service/event_types.py | 10 ++ .../test_group_notifications.py | 3 + tests/utils/api_routes/__init__.py | 2 - 29 files changed, 281 insertions(+), 153 deletions(-) create mode 100644 mealie/alembic/versions/2025-08-09-19.32.37_e6bb583aac2d_add_label_notifier_crud_bools.py diff --git a/frontend/lang/messages/en-US.json b/frontend/lang/messages/en-US.json index 15623ce09..53ef08f83 100644 --- a/frontend/lang/messages/en-US.json +++ b/frontend/lang/messages/en-US.json @@ -79,7 +79,8 @@ "tag-events": "Tag Events", "category-events": "Category Events", "when-a-new-user-joins-your-group": "When a new user joins your group", - "recipe-events": "Recipe Events" + "recipe-events": "Recipe Events", + "label-events": "Label Events" }, "general": { "add": "Add", diff --git a/frontend/lib/api/types/admin.ts b/frontend/lib/api/types/admin.ts index 95b431bc9..6f2022f6e 100644 --- a/frontend/lib/api/types/admin.ts +++ b/frontend/lib/api/types/admin.ts @@ -1,5 +1,4 @@ /* tslint:disable */ - /** /* This file was automatically generated from pydantic models by running pydantic2ts. /* Do not modify it by hand - just update the pydantic models and then re-run the script @@ -117,6 +116,7 @@ export interface CustomPageBase { export interface RecipeCategoryResponse { name: string; id: string; + groupId?: string | null; slug: string; recipes?: RecipeSummary[]; } @@ -149,18 +149,21 @@ export interface RecipeSummary { } export interface RecipeCategory { id?: string | null; + groupId?: string | null; name: string; slug: string; [k: string]: unknown; } export interface RecipeTag { id?: string | null; + groupId?: string | null; name: string; slug: string; [k: string]: unknown; } export interface RecipeTool { id: string; + groupId?: string | null; name: string; slug: string; householdsWithTool?: string[]; diff --git a/frontend/lib/api/types/analytics.ts b/frontend/lib/api/types/analytics.ts index 43cb23663..5bdc7fbcd 100644 --- a/frontend/lib/api/types/analytics.ts +++ b/frontend/lib/api/types/analytics.ts @@ -1,5 +1,4 @@ /* tslint:disable */ - /** /* This file was automatically generated from pydantic models by running pydantic2ts. /* Do not modify it by hand - just update the pydantic models and then re-run the script diff --git a/frontend/lib/api/types/cookbook.ts b/frontend/lib/api/types/cookbook.ts index 2daf20aaa..a35e5cd5f 100644 --- a/frontend/lib/api/types/cookbook.ts +++ b/frontend/lib/api/types/cookbook.ts @@ -1,5 +1,4 @@ /* tslint:disable */ - /** /* This file was automatically generated from pydantic models by running pydantic2ts. /* Do not modify it by hand - just update the pydantic models and then re-run the script @@ -39,7 +38,6 @@ export interface QueryFilterJSONPart { attributeName?: string | null; relationalOperator?: RelationalKeyword | RelationalOperator | null; value?: string | string[] | null; - [k: string]: unknown; } export interface RecipeCookBook { name: string; @@ -83,18 +81,21 @@ export interface RecipeSummary { } export interface RecipeCategory { id?: string | null; + groupId?: string | null; name: string; slug: string; [k: string]: unknown; } export interface RecipeTag { id?: string | null; + groupId?: string | null; name: string; slug: string; [k: string]: unknown; } export interface RecipeTool { id: string; + groupId?: string | null; name: string; slug: string; householdsWithTool?: string[]; diff --git a/frontend/lib/api/types/group.ts b/frontend/lib/api/types/group.ts index 1f72c09c5..8ebf2c96c 100644 --- a/frontend/lib/api/types/group.ts +++ b/frontend/lib/api/types/group.ts @@ -1,5 +1,4 @@ /* tslint:disable */ - /** /* This file was automatically generated from pydantic models by running pydantic2ts. /* Do not modify it by hand - just update the pydantic models and then re-run the script diff --git a/frontend/lib/api/types/household.ts b/frontend/lib/api/types/household.ts index b01fe7245..f3400dea4 100644 --- a/frontend/lib/api/types/household.ts +++ b/frontend/lib/api/types/household.ts @@ -1,5 +1,4 @@ /* tslint:disable */ - /** /* This file was automatically generated from pydantic models by running pydantic2ts. /* Do not modify it by hand - just update the pydantic models and then re-run the script @@ -70,6 +69,9 @@ export interface GroupEventNotifierOptions { categoryCreated?: boolean; categoryUpdated?: boolean; categoryDeleted?: boolean; + labelCreated?: boolean; + labelUpdated?: boolean; + labelDeleted?: boolean; } export interface GroupEventNotifierOptionsOut { testMessage?: boolean; @@ -94,6 +96,9 @@ export interface GroupEventNotifierOptionsOut { categoryCreated?: boolean; categoryUpdated?: boolean; categoryDeleted?: boolean; + labelCreated?: boolean; + labelUpdated?: boolean; + labelDeleted?: boolean; id: string; } export interface GroupEventNotifierOptionsSave { @@ -119,6 +124,9 @@ export interface GroupEventNotifierOptionsSave { categoryCreated?: boolean; categoryUpdated?: boolean; categoryDeleted?: boolean; + labelCreated?: boolean; + labelUpdated?: boolean; + labelDeleted?: boolean; notifierId: string; } export interface GroupEventNotifierOut { @@ -166,6 +174,7 @@ export interface GroupRecipeActionOut { export interface GroupRecipeActionPayload { action: GroupRecipeActionOut; content: unknown; + recipeScale: number; } export interface HouseholdCreate { groupId?: string | null; @@ -587,18 +596,21 @@ export interface RecipeSummary { } export interface RecipeCategory { id?: string | null; + groupId?: string | null; name: string; slug: string; [k: string]: unknown; } export interface RecipeTag { id?: string | null; + groupId?: string | null; name: string; slug: string; [k: string]: unknown; } export interface RecipeTool { id: string; + groupId?: string | null; name: string; slug: string; householdsWithTool?: string[]; diff --git a/frontend/lib/api/types/labels.ts b/frontend/lib/api/types/labels.ts index 9d44342cc..ee9335bb2 100644 --- a/frontend/lib/api/types/labels.ts +++ b/frontend/lib/api/types/labels.ts @@ -1,5 +1,4 @@ /* tslint:disable */ - /** /* This file was automatically generated from pydantic models by running pydantic2ts. /* Do not modify it by hand - just update the pydantic models and then re-run the script diff --git a/frontend/lib/api/types/meal-plan.ts b/frontend/lib/api/types/meal-plan.ts index aa28e6349..85f03de97 100644 --- a/frontend/lib/api/types/meal-plan.ts +++ b/frontend/lib/api/types/meal-plan.ts @@ -1,12 +1,9 @@ /* tslint:disable */ - /** /* This file was automatically generated from pydantic models by running pydantic2ts. /* Do not modify it by hand - just update the pydantic models and then re-run the script */ -import type { HouseholdSummary } from "./household"; - export type PlanEntryType = "breakfast" | "lunch" | "dinner" | "side"; export type PlanRulesDay = "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday" | "unset"; export type PlanRulesType = "breakfast" | "lunch" | "dinner" | "side" | "unset"; @@ -44,9 +41,6 @@ export interface PlanRulesOut { householdId: string; id: string; queryFilter?: QueryFilterJSON; - categories?: RecipeCategory[]; - tags?: RecipeTag[]; - households?: HouseholdSummary[]; } export interface QueryFilterJSON { parts?: QueryFilterJSONPart[]; @@ -108,18 +102,21 @@ export interface RecipeSummary { } export interface RecipeCategory { id?: string | null; + groupId?: string | null; name: string; slug: string; [k: string]: unknown; } export interface RecipeTag { id?: string | null; + groupId?: string | null; name: string; slug: string; [k: string]: unknown; } export interface RecipeTool { id: string; + groupId?: string | null; name: string; slug: string; householdsWithTool?: string[]; diff --git a/frontend/lib/api/types/recipe.ts b/frontend/lib/api/types/recipe.ts index 29e4f98bd..7b34ac8a3 100644 --- a/frontend/lib/api/types/recipe.ts +++ b/frontend/lib/api/types/recipe.ts @@ -19,6 +19,7 @@ export interface AssignCategories { export interface CategoryBase { name: string; id: string; + groupId?: string | null; slug: string; } export interface AssignSettings { @@ -40,6 +41,7 @@ export interface AssignTags { export interface TagBase { name: string; id: string; + groupId?: string | null; slug: string; } export interface CategoryIn { @@ -48,8 +50,8 @@ export interface CategoryIn { export interface CategoryOut { name: string; id: string; - slug: string; groupId: string; + slug: string; } export interface CategorySave { name: string; @@ -97,11 +99,13 @@ export interface CreateRecipeBulk { } export interface RecipeCategory { id?: string | null; + groupId?: string | null; name: string; slug: string; } export interface RecipeTag { id?: string | null; + groupId?: string | null; name: string; slug: string; } @@ -223,7 +227,7 @@ export interface Recipe { groupId?: string; name?: string | null; slug?: string; - image?: string; + image?: unknown; recipeServings?: number; recipeYieldQuantity?: number; recipeYield?: string | null; @@ -255,6 +259,7 @@ export interface Recipe { } export interface RecipeTool { id: string; + groupId?: string | null; name: string; slug: string; householdsWithTool?: string[]; @@ -293,6 +298,7 @@ export interface UserBase { export interface RecipeCategoryResponse { name: string; id: string; + groupId?: string | null; slug: string; recipes?: RecipeSummary[]; } @@ -399,6 +405,7 @@ export interface RecipeSuggestionResponseItem { export interface RecipeTagResponse { name: string; id: string; + groupId?: string | null; slug: string; recipes?: RecipeSummary[]; } @@ -447,12 +454,14 @@ export interface RecipeToolOut { name: string; householdsWithTool?: string[]; id: string; + groupId: string; slug: string; } export interface RecipeToolResponse { name: string; householdsWithTool?: string[]; id: string; + groupId: string; slug: string; recipes?: RecipeSummary[]; } @@ -507,7 +516,7 @@ export interface ScrapeRecipeTest { url: string; useOpenAI?: boolean; } -export interface SlugResponse { } +export interface SlugResponse {} export interface TagIn { name: string; } diff --git a/frontend/lib/api/types/reports.ts b/frontend/lib/api/types/reports.ts index e06788a0f..428c39f40 100644 --- a/frontend/lib/api/types/reports.ts +++ b/frontend/lib/api/types/reports.ts @@ -1,5 +1,4 @@ /* tslint:disable */ - /** /* This file was automatically generated from pydantic models by running pydantic2ts. /* Do not modify it by hand - just update the pydantic models and then re-run the script diff --git a/frontend/lib/api/types/response.ts b/frontend/lib/api/types/response.ts index d77f44084..9fa568846 100644 --- a/frontend/lib/api/types/response.ts +++ b/frontend/lib/api/types/response.ts @@ -1,5 +1,4 @@ /* tslint:disable */ - /** /* This file was automatically generated from pydantic models by running pydantic2ts. /* Do not modify it by hand - just update the pydantic models and then re-run the script diff --git a/frontend/lib/api/types/user.ts b/frontend/lib/api/types/user.ts index 58ef25f6a..a5818778b 100644 --- a/frontend/lib/api/types/user.ts +++ b/frontend/lib/api/types/user.ts @@ -1,5 +1,4 @@ /* tslint:disable */ - /** /* This file was automatically generated from pydantic models by running pydantic2ts. /* Do not modify it by hand - just update the pydantic models and then re-run the script @@ -63,6 +62,7 @@ export interface GroupInDB { export interface CategoryBase { name: string; id: string; + groupId?: string | null; slug: string; } export interface ReadWebhook { @@ -197,7 +197,6 @@ export interface UserBase { canManage?: boolean; canManageHousehold?: boolean; canOrganize?: boolean; - advancedOptions?: boolean; } export interface UserIn { id?: string | null; diff --git a/frontend/pages/household/notifiers.vue b/frontend/pages/household/notifiers.vue index de00aaa72..b836eb20f 100644 --- a/frontend/pages/household/notifiers.vue +++ b/frontend/pages/household/notifiers.vue @@ -368,6 +368,24 @@ export default defineNuxtComponent({ }, ], }, + { + id: 8, + text: i18n.t("events.label-events"), + options: [ + { + text: i18n.t("general.create") as string, + key: "labelCreated", + }, + { + text: i18n.t("general.update") as string, + key: "labelUpdated", + }, + { + text: i18n.t("general.delete") as string, + key: "labelDeleted", + }, + ], + }, ]; return { diff --git a/frontend/types/components.d.ts b/frontend/types/components.d.ts index d074283ee..9d0364a59 100644 --- a/frontend/types/components.d.ts +++ b/frontend/types/components.d.ts @@ -81,4 +81,4 @@ declare module "vue" { } } -export {}; +export { }; diff --git a/mealie/alembic/versions/2025-08-09-19.32.37_e6bb583aac2d_add_label_notifier_crud_bools.py b/mealie/alembic/versions/2025-08-09-19.32.37_e6bb583aac2d_add_label_notifier_crud_bools.py new file mode 100644 index 000000000..9b3c5d504 --- /dev/null +++ b/mealie/alembic/versions/2025-08-09-19.32.37_e6bb583aac2d_add_label_notifier_crud_bools.py @@ -0,0 +1,48 @@ +"""'Add label notifier CRUD bools' + +Revision ID: e6bb583aac2d +Revises: d7b3ce6fa31a +Create Date: 2025-08-09 19:32:37.285172 + +""" + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = "e6bb583aac2d" +down_revision: str | None = "d7b3ce6fa31a" +branch_labels: str | tuple[str, ...] | None = None +depends_on: str | tuple[str, ...] | None = None + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("group_events_notifier_options", schema=None) as batch_op: + batch_op.add_column( + sa.Column( + "label_created", sa.Boolean(), nullable=False, default=False, server_default=sa.sql.expression.false() + ) + ) + batch_op.add_column( + sa.Column( + "label_updated", sa.Boolean(), nullable=False, default=False, server_default=sa.sql.expression.false() + ) + ) + batch_op.add_column( + sa.Column( + "label_deleted", sa.Boolean(), nullable=False, default=False, server_default=sa.sql.expression.false() + ) + ) + + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + with op.batch_alter_table("group_events_notifier_options", schema=None) as batch_op: + batch_op.drop_column("label_deleted") + batch_op.drop_column("label_updated") + batch_op.drop_column("label_created") + + # ### end Alembic commands ### diff --git a/mealie/db/models/household/events.py b/mealie/db/models/household/events.py index 6be4f9931..9c850d40e 100644 --- a/mealie/db/models/household/events.py +++ b/mealie/db/models/household/events.py @@ -46,6 +46,10 @@ class GroupEventNotifierOptionsModel(SqlAlchemyBase, BaseMixins): category_updated: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) category_deleted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) + label_created: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) + label_updated: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) + label_deleted: Mapped[bool] = mapped_column(Boolean, default=False, nullable=False) + @auto_init() def __init__(self, **_) -> None: pass diff --git a/mealie/routes/groups/controller_labels.py b/mealie/routes/groups/controller_labels.py index fb008ef03..4a156eb94 100644 --- a/mealie/routes/groups/controller_labels.py +++ b/mealie/routes/groups/controller_labels.py @@ -3,7 +3,7 @@ from functools import cached_property from fastapi import APIRouter, Depends from pydantic import UUID4 -from mealie.routes._base.base_controllers import BaseUserController +from mealie.routes._base.base_controllers import BaseCrudController from mealie.routes._base.controller import controller from mealie.routes._base.mixins import HttpRepo from mealie.routes._base.routers import MealieCrudRoute @@ -15,13 +15,14 @@ from mealie.schema.labels import ( ) from mealie.schema.labels.multi_purpose_label import MultiPurposeLabelPagination from mealie.schema.response.pagination import PaginationQuery +from mealie.services.event_bus_service.event_types import EventLabelData, EventOperation, EventTypes from mealie.services.group_services.labels_service import MultiPurposeLabelService router = APIRouter(prefix="/groups/labels", tags=["Groups: Multi Purpose Labels"], route_class=MealieCrudRoute) @controller(router) -class MultiPurposeLabelsController(BaseUserController): +class MultiPurposeLabelsController(BaseCrudController): @cached_property def service(self): return MultiPurposeLabelService(self.repos) @@ -53,7 +54,15 @@ class MultiPurposeLabelsController(BaseUserController): @router.post("", response_model=MultiPurposeLabelOut) def create_one(self, data: MultiPurposeLabelCreate): - return self.service.create_one(data) + new_label = self.service.create_one(data) + self.publish_event( + event_type=EventTypes.label_created, + document_data=EventLabelData(operation=EventOperation.create, label_id=new_label.id), + group_id=new_label.group_id, + household_id=None, + message=self.t("notifications.generic-created", name=new_label.name), + ) + return new_label @router.get("/{item_id}", response_model=MultiPurposeLabelOut) def get_one(self, item_id: UUID4): @@ -61,8 +70,25 @@ class MultiPurposeLabelsController(BaseUserController): @router.put("/{item_id}", response_model=MultiPurposeLabelOut) def update_one(self, item_id: UUID4, data: MultiPurposeLabelUpdate): - return self.mixins.update_one(data, item_id) + label = self.mixins.update_one(data, item_id) + self.publish_event( + event_type=EventTypes.label_updated, + document_data=EventLabelData(operation=EventOperation.update, label_id=label.id), + group_id=label.group_id, + household_id=None, + message=self.t("notifications.generic-updated", name=label.name), + ) + return label @router.delete("/{item_id}", response_model=MultiPurposeLabelOut) def delete_one(self, item_id: UUID4): - return self.mixins.delete_one(item_id) # type: ignore + label = self.mixins.delete_one(item_id) + if label: + self.publish_event( + event_type=EventTypes.label_deleted, + document_data=EventLabelData(operation=EventOperation.delete, label_id=label.id), + group_id=label.group_id, + household_id=None, + message=self.t("notifications.generic-deleted", name=label.name), + ) + return label diff --git a/mealie/schema/_mealie/__init__.py b/mealie/schema/_mealie/__init__.py index 628e17908..7441e747a 100644 --- a/mealie/schema/_mealie/__init__.py +++ b/mealie/schema/_mealie/__init__.py @@ -3,11 +3,11 @@ from .datetime_parse import DateError, DateTimeError, DurationError, TimeError from .mealie_model import HasUUID, MealieModel, SearchType __all__ = [ + "HasUUID", + "MealieModel", + "SearchType", "DateError", "DateTimeError", "DurationError", "TimeError", - "HasUUID", - "MealieModel", - "SearchType", ] diff --git a/mealie/schema/admin/__init__.py b/mealie/schema/admin/__init__.py index 367e94739..92edafd25 100644 --- a/mealie/schema/admin/__init__.py +++ b/mealie/schema/admin/__init__.py @@ -18,28 +18,10 @@ from .restore import ( from .settings import CustomPageBase, CustomPageOut __all__ = [ - "MaintenanceLogs", - "MaintenanceStorageDetails", - "MaintenanceSummary", "ChowdownURL", "MigrationFile", "MigrationImport", "Migrations", - "CustomPageBase", - "CustomPageOut", - "CommentImport", - "CustomPageImport", - "GroupImport", - "ImportBase", - "NotificationImport", - "RecipeImport", - "SettingsImport", - "UserImport", - "AllBackups", - "BackupFile", - "BackupOptions", - "CreateBackup", - "ImportJob", "AdminAboutInfo", "AppInfo", "AppStartupInfo", @@ -49,5 +31,23 @@ __all__ = [ "EmailReady", "EmailSuccess", "EmailTest", + "CustomPageBase", + "CustomPageOut", + "AllBackups", + "BackupFile", + "BackupOptions", + "CreateBackup", + "ImportJob", + "MaintenanceLogs", + "MaintenanceStorageDetails", + "MaintenanceSummary", "DebugResponse", + "CommentImport", + "CustomPageImport", + "GroupImport", + "ImportBase", + "NotificationImport", + "RecipeImport", + "SettingsImport", + "UserImport", ] diff --git a/mealie/schema/group/__init__.py b/mealie/schema/group/__init__.py index a731b4432..3e0fb46fb 100644 --- a/mealie/schema/group/__init__.py +++ b/mealie/schema/group/__init__.py @@ -7,13 +7,13 @@ from .group_seeder import SeederConfig from .group_statistics import GroupStorage __all__ = [ + "GroupAdminUpdate", + "GroupStorage", "GroupDataExport", + "SeederConfig", "CreateGroupPreferences", "ReadGroupPreferences", "UpdateGroupPreferences", - "GroupStorage", "DataMigrationCreate", "SupportedMigrations", - "SeederConfig", - "GroupAdminUpdate", ] diff --git a/mealie/schema/household/__init__.py b/mealie/schema/household/__init__.py index 1fcc7bb25..f0e2f88d9 100644 --- a/mealie/schema/household/__init__.py +++ b/mealie/schema/household/__init__.py @@ -70,49 +70,6 @@ from .invite_token import CreateInviteToken, EmailInitationResponse, EmailInvita from .webhook import CreateWebhook, ReadWebhook, SaveWebhook, WebhookPagination, WebhookType __all__ = [ - "GroupEventNotifierCreate", - "GroupEventNotifierOptions", - "GroupEventNotifierOptionsOut", - "GroupEventNotifierOptionsSave", - "GroupEventNotifierOut", - "GroupEventNotifierPrivate", - "GroupEventNotifierSave", - "GroupEventNotifierUpdate", - "GroupEventPagination", - "CreateGroupRecipeAction", - "GroupRecipeActionOut", - "GroupRecipeActionPagination", - "GroupRecipeActionPayload", - "GroupRecipeActionType", - "SaveGroupRecipeAction", - "CreateWebhook", - "ReadWebhook", - "SaveWebhook", - "WebhookPagination", - "WebhookType", - "CreateHouseholdPreferences", - "ReadHouseholdPreferences", - "SaveHouseholdPreferences", - "UpdateHouseholdPreferences", - "HouseholdCreate", - "HouseholdInDB", - "HouseholdPagination", - "HouseholdRecipeBase", - "HouseholdRecipeCreate", - "HouseholdRecipeOut", - "HouseholdRecipeSummary", - "HouseholdRecipeUpdate", - "HouseholdSave", - "HouseholdSummary", - "HouseholdUserSummary", - "UpdateHousehold", - "UpdateHouseholdAdmin", - "HouseholdStatistics", - "CreateInviteToken", - "EmailInitationResponse", - "EmailInvitation", - "ReadInviteToken", - "SaveInviteToken", "ShoppingListAddRecipeParams", "ShoppingListAddRecipeParamsBulk", "ShoppingListCreate", @@ -136,5 +93,48 @@ __all__ = [ "ShoppingListSave", "ShoppingListSummary", "ShoppingListUpdate", + "GroupEventNotifierCreate", + "GroupEventNotifierOptions", + "GroupEventNotifierOptionsOut", + "GroupEventNotifierOptionsSave", + "GroupEventNotifierOut", + "GroupEventNotifierPrivate", + "GroupEventNotifierSave", + "GroupEventNotifierUpdate", + "GroupEventPagination", + "CreateGroupRecipeAction", + "GroupRecipeActionOut", + "GroupRecipeActionPagination", + "GroupRecipeActionPayload", + "GroupRecipeActionType", + "SaveGroupRecipeAction", + "CreateHouseholdPreferences", + "ReadHouseholdPreferences", + "SaveHouseholdPreferences", + "UpdateHouseholdPreferences", "SetPermissions", + "CreateInviteToken", + "EmailInitationResponse", + "EmailInvitation", + "ReadInviteToken", + "SaveInviteToken", + "HouseholdStatistics", + "CreateWebhook", + "ReadWebhook", + "SaveWebhook", + "WebhookPagination", + "WebhookType", + "HouseholdCreate", + "HouseholdInDB", + "HouseholdPagination", + "HouseholdRecipeBase", + "HouseholdRecipeCreate", + "HouseholdRecipeOut", + "HouseholdRecipeSummary", + "HouseholdRecipeUpdate", + "HouseholdSave", + "HouseholdSummary", + "HouseholdUserSummary", + "UpdateHousehold", + "UpdateHouseholdAdmin", ] diff --git a/mealie/schema/household/group_events.py b/mealie/schema/household/group_events.py index 3554e1b9f..7ab964f76 100644 --- a/mealie/schema/household/group_events.py +++ b/mealie/schema/household/group_events.py @@ -47,6 +47,10 @@ class GroupEventNotifierOptions(MealieModel): category_updated: bool = False category_deleted: bool = False + label_created: bool = False + label_updated: bool = False + label_deleted: bool = False + class GroupEventNotifierOptionsSave(GroupEventNotifierOptions): notifier_id: UUID4 diff --git a/mealie/schema/meal_plan/__init__.py b/mealie/schema/meal_plan/__init__.py index 639c61ee6..5f3b9b033 100644 --- a/mealie/schema/meal_plan/__init__.py +++ b/mealie/schema/meal_plan/__init__.py @@ -12,9 +12,6 @@ from .plan_rules import PlanRulesCreate, PlanRulesDay, PlanRulesOut, PlanRulesPa from .shopping_list import ListItem, ShoppingListIn, ShoppingListOut __all__ = [ - "ListItem", - "ShoppingListIn", - "ShoppingListOut", "CreatePlanEntry", "CreateRandomEntry", "PlanEntryPagination", @@ -22,6 +19,9 @@ __all__ = [ "ReadPlanEntry", "SavePlanEntry", "UpdatePlanEntry", + "ListItem", + "ShoppingListIn", + "ShoppingListOut", "PlanRulesCreate", "PlanRulesDay", "PlanRulesOut", diff --git a/mealie/schema/recipe/__init__.py b/mealie/schema/recipe/__init__.py index 2304c8a5e..d105db300 100644 --- a/mealie/schema/recipe/__init__.py +++ b/mealie/schema/recipe/__init__.py @@ -89,35 +89,6 @@ from .recipe_tool import RecipeToolCreate, RecipeToolOut, RecipeToolResponse, Re from .request_helpers import RecipeDuplicate, RecipeSlug, RecipeZipTokenResponse, SlugResponse, UpdateImageResponse __all__ = [ - "IngredientReferences", - "RecipeStep", - "RecipeNote", - "CategoryBase", - "CategoryIn", - "CategoryOut", - "CategorySave", - "RecipeCategoryResponse", - "RecipeTagResponse", - "TagBase", - "TagIn", - "TagOut", - "TagSave", - "RecipeAsset", - "RecipeTimelineEventCreate", - "RecipeTimelineEventIn", - "RecipeTimelineEventOut", - "RecipeTimelineEventPagination", - "RecipeTimelineEventUpdate", - "TimelineEventImage", - "TimelineEventType", - "RecipeSuggestionQuery", - "RecipeSuggestionResponse", - "RecipeSuggestionResponseItem", - "Nutrition", - "RecipeShareToken", - "RecipeShareTokenCreate", - "RecipeShareTokenSave", - "RecipeShareTokenSummary", "CreateIngredientFood", "CreateIngredientFoodAlias", "CreateIngredientUnit", @@ -140,13 +111,27 @@ __all__ = [ "SaveIngredientFood", "SaveIngredientUnit", "UnitFoodBase", + "RecipeTimelineEventCreate", + "RecipeTimelineEventIn", + "RecipeTimelineEventOut", + "RecipeTimelineEventPagination", + "RecipeTimelineEventUpdate", + "TimelineEventImage", + "TimelineEventType", + "Nutrition", + "AssignCategories", + "AssignSettings", + "AssignTags", + "DeleteRecipes", + "ExportBase", + "ExportRecipes", + "ExportTypes", "RecipeCommentCreate", "RecipeCommentOut", "RecipeCommentPagination", "RecipeCommentSave", "RecipeCommentUpdate", "UserBase", - "RecipeSettings", "CreateRecipe", "CreateRecipeBulk", "CreateRecipeByUrlBulk", @@ -160,25 +145,40 @@ __all__ = [ "RecipeTagPagination", "RecipeTool", "RecipeToolPagination", - "ScrapeRecipe", - "ScrapeRecipeBase", - "ScrapeRecipeData", - "ScrapeRecipeTest", - "AssignCategories", - "AssignSettings", - "AssignTags", - "DeleteRecipes", - "ExportBase", - "ExportRecipes", - "ExportTypes", - "RecipeToolCreate", - "RecipeToolOut", - "RecipeToolResponse", - "RecipeToolSave", - "RecipeImageTypes", + "IngredientReferences", + "RecipeStep", + "RecipeNote", + "RecipeSuggestionQuery", + "RecipeSuggestionResponse", + "RecipeSuggestionResponseItem", + "RecipeSettings", + "RecipeShareToken", + "RecipeShareTokenCreate", + "RecipeShareTokenSave", + "RecipeShareTokenSummary", + "RecipeAsset", "RecipeDuplicate", "RecipeSlug", "RecipeZipTokenResponse", "SlugResponse", "UpdateImageResponse", + "RecipeToolCreate", + "RecipeToolOut", + "RecipeToolResponse", + "RecipeToolSave", + "CategoryBase", + "CategoryIn", + "CategoryOut", + "CategorySave", + "RecipeCategoryResponse", + "RecipeTagResponse", + "TagBase", + "TagIn", + "TagOut", + "TagSave", + "ScrapeRecipe", + "ScrapeRecipeBase", + "ScrapeRecipeData", + "ScrapeRecipeTest", + "RecipeImageTypes", ] diff --git a/mealie/schema/response/__init__.py b/mealie/schema/response/__init__.py index c513794c5..fad4f840f 100644 --- a/mealie/schema/response/__init__.py +++ b/mealie/schema/response/__init__.py @@ -28,14 +28,14 @@ __all__ = [ "QueryFilterJSONPart", "RelationalKeyword", "RelationalOperator", - "ValidationResponse", + "SearchFilter", "OrderByNullPosition", "OrderDirection", "PaginationBase", "PaginationQuery", "RecipeSearchQuery", "RequestQuery", - "SearchFilter", + "ValidationResponse", "ErrorResponse", "FileTokenResponse", "SuccessResponse", diff --git a/mealie/schema/user/__init__.py b/mealie/schema/user/__init__.py index 76db2ec95..65e7e00a6 100644 --- a/mealie/schema/user/__init__.py +++ b/mealie/schema/user/__init__.py @@ -38,12 +38,6 @@ from .user_passwords import ( ) __all__ = [ - "ForgotPassword", - "PasswordResetToken", - "PrivatePasswordResetToken", - "ResetPassword", - "SavePasswordResetToken", - "ValidateResetToken", "CredentialsRequest", "CredentialsRequestForm", "Token", @@ -75,4 +69,10 @@ __all__ = [ "UserRatings", "UserSummary", "UserSummaryPagination", + "ForgotPassword", + "PasswordResetToken", + "PrivatePasswordResetToken", + "ResetPassword", + "SavePasswordResetToken", + "ValidateResetToken", ] diff --git a/mealie/services/event_bus_service/event_types.py b/mealie/services/event_bus_service/event_types.py index 6e3e54b05..b14bdd9af 100644 --- a/mealie/services/event_bus_service/event_types.py +++ b/mealie/services/event_bus_service/event_types.py @@ -53,6 +53,10 @@ class EventTypes(Enum): category_updated = auto() category_deleted = auto() + label_created = auto() + label_updated = auto() + label_deleted = auto() + class EventDocumentType(Enum): generic = "generic" @@ -68,6 +72,7 @@ class EventDocumentType(Enum): recipe_bulk_report = "recipe_bulk_report" recipe_timeline_event = "recipe_timeline_event" tag = "tag" + label = "label" class EventOperation(Enum): @@ -106,6 +111,11 @@ class EventCategoryData(EventDocumentDataBase): category_id: UUID4 +class EventLabelData(EventDocumentDataBase): + document_type: EventDocumentType = EventDocumentType.label + label_id: UUID4 + + class EventCookbookData(EventDocumentDataBase): document_type: EventDocumentType = EventDocumentType.cookbook cookbook_id: UUID4 diff --git a/tests/integration_tests/user_household_tests/test_group_notifications.py b/tests/integration_tests/user_household_tests/test_group_notifications.py index fa0cba5b7..3bd2c0c1a 100644 --- a/tests/integration_tests/user_household_tests/test_group_notifications.py +++ b/tests/integration_tests/user_household_tests/test_group_notifications.py @@ -38,6 +38,9 @@ def preferences_generator(): category_created=random_bool(), category_updated=random_bool(), category_deleted=random_bool(), + label_created=random_bool(), + label_updated=random_bool(), + label_deleted=random_bool(), ).model_dump(by_alias=True) diff --git a/tests/utils/api_routes/__init__.py b/tests/utils/api_routes/__init__.py index 02aee25c9..cd4c51f4a 100644 --- a/tests/utils/api_routes/__init__.py +++ b/tests/utils/api_routes/__init__.py @@ -173,8 +173,6 @@ units = "/api/units" """`/api/units`""" units_merge = "/api/units/merge" """`/api/units/merge`""" -users = "/api/users" -"""`/api/users`""" users_api_tokens = "/api/users/api-tokens" """`/api/users/api-tokens`""" users_forgot_password = "/api/users/forgot-password"