feat: add initial notification support

* Add updated recipe notification

* Add recipe deleted notification

* Add notifications translations

* Shopping lists full c/u/d notifications

* Add categories c/u/d notifications

* Deal with None values in translation provider

* Add tag c/u/d notifications

* Add cookbook c/u/d notifications

* use single key pairs for consistency with frontend

* change dependency injection strategy

* use generic update messages

* use service to manage url generation server-side

* use new strategies for messages

* fix translator

Co-authored-by: Miroito <alban.vachette@gmail.com>
This commit is contained in:
Hayden
2022-05-21 10:23:55 -08:00
committed by GitHub
parent 841b560abc
commit b2066dfe72
12 changed files with 244 additions and 24 deletions

View File

@@ -1,6 +1,6 @@
from functools import cached_property
from fastapi import APIRouter
from fastapi import APIRouter, Depends
from pydantic import UUID4, BaseModel
from mealie.routes._base import BaseUserController, controller
@@ -9,6 +9,9 @@ from mealie.schema import mapper
from mealie.schema.recipe import CategoryIn, RecipeCategoryResponse
from mealie.schema.recipe.recipe import RecipeCategory
from mealie.schema.recipe.recipe_category import CategoryBase, CategorySave
from mealie.services import urls
from mealie.services.event_bus_service.event_bus_service import EventBusService
from mealie.services.event_bus_service.message_types import EventTypes
router = APIRouter(prefix="/categories", tags=["Organizer: Categories"])
@@ -24,6 +27,9 @@ class CategorySummary(BaseModel):
@controller(router)
class RecipeCategoryController(BaseUserController):
event_bus: EventBusService = Depends(EventBusService)
# =========================================================================
# CRUD Operations
@cached_property
@@ -43,7 +49,18 @@ class RecipeCategoryController(BaseUserController):
def create_one(self, category: CategoryIn):
"""Creates a Category in the database"""
save_data = mapper.cast(category, CategorySave, group_id=self.group_id)
return self.mixins.create_one(save_data)
data = self.mixins.create_one(save_data)
if data:
self.event_bus.dispatch(
self.deps.acting_user.group_id,
EventTypes.category_created,
msg=self.t(
"notifications.generic-created-with-url",
name=data.name,
url=urls.category_url(data.slug, self.deps.settings.BASE_URL),
),
)
return data
@router.get("/{item_id}", response_model=CategorySummary)
def get_one(self, item_id: UUID4):
@@ -56,7 +73,19 @@ class RecipeCategoryController(BaseUserController):
def update_one(self, item_id: UUID4, update_data: CategoryIn):
"""Updates an existing Tag in the database"""
save_data = mapper.cast(update_data, CategorySave, group_id=self.group_id)
return self.mixins.update_one(save_data, item_id)
data = self.mixins.update_one(save_data, item_id)
if data:
self.event_bus.dispatch(
self.deps.acting_user.group_id,
EventTypes.category_updated,
msg=self.t(
"notifications.generic-updated-with-url",
name=data.name,
url=urls.category_url(data.slug, self.deps.settings.BASE_URL),
),
)
return data
@router.delete("/{item_id}")
def delete_one(self, item_id: UUID4):
@@ -65,7 +94,12 @@ class RecipeCategoryController(BaseUserController):
category does not impact a recipe. The category will be removed
from any recipes that contain it
"""
self.mixins.delete_one(item_id)
if data := self.mixins.delete_one(item_id):
self.event_bus.dispatch(
self.deps.acting_user.group_id,
EventTypes.category_deleted,
msg=self.t("notifications.generic-deleted", name=data.name),
)
# =========================================================================
# Read All Operations

View File

@@ -1,6 +1,6 @@
from functools import cached_property
from fastapi import APIRouter, HTTPException, status
from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import UUID4
from mealie.routes._base import BaseUserController, controller
@@ -9,12 +9,18 @@ from mealie.schema import mapper
from mealie.schema.recipe import RecipeTagResponse, TagIn
from mealie.schema.recipe.recipe import RecipeTag
from mealie.schema.recipe.recipe_category import TagSave
from mealie.services import urls
from mealie.services.event_bus_service.event_bus_service import EventBusService
from mealie.services.event_bus_service.message_types import EventTypes
router = APIRouter(prefix="/tags", tags=["Organizer: Tags"])
@controller(router)
class TagController(BaseUserController):
event_bus: EventBusService = Depends(EventBusService)
@cached_property
def repo(self):
return self.repos.tags.by_group(self.group_id)
@@ -42,13 +48,35 @@ class TagController(BaseUserController):
def create_one(self, tag: TagIn):
"""Creates a Tag in the database"""
save_data = mapper.cast(tag, TagSave, group_id=self.group_id)
return self.repo.create(save_data)
data = self.repo.create(save_data)
if data:
self.event_bus.dispatch(
self.deps.acting_user.group_id,
EventTypes.tag_created,
msg=self.t(
"notifications.generic-created-with-url",
name=data.name,
url=urls.tag_url(data.slug, self.deps.settings.BASE_URL),
),
)
return data
@router.put("/{item_id}", response_model=RecipeTagResponse)
def update_one(self, item_id: UUID4, new_tag: TagIn):
"""Updates an existing Tag in the database"""
save_data = mapper.cast(new_tag, TagSave, group_id=self.group_id)
return self.repo.update(item_id, save_data)
data = self.repo.update(item_id, save_data)
if data:
self.event_bus.dispatch(
self.deps.acting_user.group_id,
EventTypes.tag_updated,
msg=self.t(
"notifications.generic-updated-with-url",
name=data.name,
url=urls.tag_url(data.slug, self.deps.settings.BASE_URL),
),
)
return data
@router.delete("/{item_id}")
def delete_recipe_tag(self, item_id: UUID4):
@@ -57,10 +85,17 @@ class TagController(BaseUserController):
from any recipes that contain it"""
try:
self.repo.delete(item_id)
data = self.repo.delete(item_id)
except Exception as e:
raise HTTPException(status.HTTP_400_BAD_REQUEST) from e
if data:
self.event_bus.dispatch(
self.deps.acting_user.group_id,
EventTypes.tag_deleted,
msg=self.t("notifications.generic-deleted", name=data.name),
)
@router.get("/slug/{tag_slug}", response_model=RecipeTagResponse)
async def get_one_by_slug(self, tag_slug: str):
return self.repo.get_one(tag_slug, "slug", override_schema=RecipeTagResponse)