mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-14 14:25:53 -05:00
Feature: Shopping List Label Section Improvements (#2090)
* added backend for shopping list label config * updated codegen * refactored shopping list ops to service removed unique contraint removed label settings from main route/schema added new route for label settings * codegen * made sure label settings output in position order * implemented submenu for label order drag and drop * removed redundant label and tweaked formatting * added view by label to user preferences * made items draggable within each label section * moved reorder labels to its own button * made dialog scrollable * fixed broken model * refactored labels to use a service moved shopping list label logic to service modified label seeder to use service * added tests * fix for first label missing the tag icon * fixed wrong mapped type * added statement to create existing relationships * fix restore test, maybe
This commit is contained in:
@@ -5,7 +5,11 @@ from sqlalchemy.ext.orderinglist import ordering_list
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from mealie.db.models.labels import MultiPurposeLabel
|
||||
from mealie.db.models.recipe.api_extras import ShoppingListExtras, ShoppingListItemExtras, api_extras
|
||||
from mealie.db.models.recipe.api_extras import (
|
||||
ShoppingListExtras,
|
||||
ShoppingListItemExtras,
|
||||
api_extras,
|
||||
)
|
||||
|
||||
from .._model_base import BaseMixins, SqlAlchemyBase
|
||||
from .._model_utils import GUID, auto_init
|
||||
@@ -99,6 +103,26 @@ class ShoppingListRecipeReference(BaseMixins, SqlAlchemyBase):
|
||||
pass
|
||||
|
||||
|
||||
class ShoppingListMultiPurposeLabel(SqlAlchemyBase, BaseMixins):
|
||||
__tablename__ = "shopping_lists_multi_purpose_labels"
|
||||
id: Mapped[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate)
|
||||
|
||||
shopping_list_id: Mapped[GUID] = mapped_column(GUID, ForeignKey("shopping_lists.id"), primary_key=True)
|
||||
shopping_list: Mapped["ShoppingList"] = orm.relationship("ShoppingList", back_populates="label_settings")
|
||||
label_id: Mapped[GUID] = mapped_column(GUID, ForeignKey("multi_purpose_labels.id"), primary_key=True)
|
||||
label: Mapped["MultiPurposeLabel"] = orm.relationship(
|
||||
"MultiPurposeLabel", back_populates="shopping_lists_label_settings"
|
||||
)
|
||||
position: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
|
||||
|
||||
class Config:
|
||||
exclude = {"label"}
|
||||
|
||||
@auto_init()
|
||||
def __init__(self, **_) -> None:
|
||||
pass
|
||||
|
||||
|
||||
class ShoppingList(SqlAlchemyBase, BaseMixins):
|
||||
__tablename__ = "shopping_lists"
|
||||
id: Mapped[GUID] = mapped_column(GUID, primary_key=True, default=GUID.generate)
|
||||
@@ -117,6 +141,12 @@ class ShoppingList(SqlAlchemyBase, BaseMixins):
|
||||
recipe_references: Mapped[ShoppingListRecipeReference] = orm.relationship(
|
||||
ShoppingListRecipeReference, cascade="all, delete, delete-orphan"
|
||||
)
|
||||
label_settings: Mapped[list["ShoppingListMultiPurposeLabel"]] = orm.relationship(
|
||||
ShoppingListMultiPurposeLabel,
|
||||
cascade="all, delete, delete-orphan",
|
||||
order_by="ShoppingListMultiPurposeLabel.position",
|
||||
collection_class=ordering_list("position"),
|
||||
)
|
||||
extras: Mapped[list[ShoppingListExtras]] = orm.relationship("ShoppingListExtras", cascade="all, delete-orphan")
|
||||
|
||||
class Config:
|
||||
|
||||
@@ -9,7 +9,8 @@ from ._model_utils import auto_init
|
||||
from ._model_utils.guid import GUID
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from group import Group, ShoppingListItem
|
||||
from group import Group
|
||||
from group.shopping_list import ShoppingListItem, ShoppingListMultiPurposeLabel
|
||||
from recipe import IngredientFoodModel
|
||||
|
||||
|
||||
@@ -24,6 +25,9 @@ class MultiPurposeLabel(SqlAlchemyBase, BaseMixins):
|
||||
|
||||
shopping_list_items: Mapped["ShoppingListItem"] = orm.relationship("ShoppingListItem", back_populates="label")
|
||||
foods: Mapped["IngredientFoodModel"] = orm.relationship("IngredientFoodModel", back_populates="label")
|
||||
shopping_lists_label_settings: Mapped[list["ShoppingListMultiPurposeLabel"]] = orm.relationship(
|
||||
"ShoppingListMultiPurposeLabel", back_populates="label", cascade="all, delete, delete-orphan"
|
||||
)
|
||||
|
||||
@auto_init()
|
||||
def __init__(self, **_) -> None:
|
||||
|
||||
@@ -15,6 +15,7 @@ from mealie.db.models.group.shopping_list import (
|
||||
ShoppingList,
|
||||
ShoppingListItem,
|
||||
ShoppingListItemRecipeReference,
|
||||
ShoppingListMultiPurposeLabel,
|
||||
ShoppingListRecipeReference,
|
||||
)
|
||||
from mealie.db.models.group.webhooks import GroupWebhooksModel
|
||||
@@ -40,6 +41,7 @@ from mealie.schema.group.group_preferences import ReadGroupPreferences
|
||||
from mealie.schema.group.group_shopping_list import (
|
||||
ShoppingListItemOut,
|
||||
ShoppingListItemRecipeRefOut,
|
||||
ShoppingListMultiPurposeLabelOut,
|
||||
ShoppingListOut,
|
||||
ShoppingListRecipeRefOut,
|
||||
)
|
||||
@@ -222,6 +224,12 @@ class AllRepositories:
|
||||
) -> RepositoryGeneric[ShoppingListRecipeRefOut, ShoppingListRecipeReference]:
|
||||
return RepositoryGeneric(self.session, PK_ID, ShoppingListRecipeReference, ShoppingListRecipeRefOut)
|
||||
|
||||
@cached_property
|
||||
def shopping_list_multi_purpose_labels(
|
||||
self,
|
||||
) -> RepositoryGeneric[ShoppingListMultiPurposeLabelOut, ShoppingListMultiPurposeLabel]:
|
||||
return RepositoryGeneric(self.session, PK_ID, ShoppingListMultiPurposeLabel, ShoppingListMultiPurposeLabelOut)
|
||||
|
||||
@cached_property
|
||||
def group_multi_purpose_labels(self) -> RepositoryGeneric[MultiPurposeLabelOut, MultiPurposeLabel]:
|
||||
return RepositoryGeneric(self.session, PK_ID, MultiPurposeLabel, MultiPurposeLabelOut)
|
||||
|
||||
@@ -1,15 +1,24 @@
|
||||
import json
|
||||
import pathlib
|
||||
from collections.abc import Generator
|
||||
from functools import cached_property
|
||||
|
||||
from mealie.schema.labels import MultiPurposeLabelSave
|
||||
from mealie.schema.recipe.recipe_ingredient import SaveIngredientFood, SaveIngredientUnit
|
||||
from mealie.schema.recipe.recipe_ingredient import (
|
||||
SaveIngredientFood,
|
||||
SaveIngredientUnit,
|
||||
)
|
||||
from mealie.services.group_services.labels_service import MultiPurposeLabelService
|
||||
|
||||
from ._abstract_seeder import AbstractSeeder
|
||||
from .resources import foods, labels, units
|
||||
|
||||
|
||||
class MultiPurposeLabelSeeder(AbstractSeeder):
|
||||
@cached_property
|
||||
def service(self):
|
||||
return MultiPurposeLabelService(self.repos, self.group_id)
|
||||
|
||||
def get_file(self, locale: str | None = None) -> pathlib.Path:
|
||||
locale_path = self.resources / "labels" / "locales" / f"{locale}.json"
|
||||
return locale_path if locale_path.exists() else labels.en_US
|
||||
@@ -27,7 +36,7 @@ class MultiPurposeLabelSeeder(AbstractSeeder):
|
||||
self.logger.info("Seeding MultiPurposeLabel")
|
||||
for label in self.load_data(locale):
|
||||
try:
|
||||
self.repos.group_multi_purpose_labels.create(label)
|
||||
self.service.create_one(label)
|
||||
except Exception as e:
|
||||
self.logger.error(e)
|
||||
|
||||
|
||||
@@ -10,25 +10,28 @@ from mealie.routes._base.routers import MealieCrudRoute
|
||||
from mealie.schema.labels import (
|
||||
MultiPurposeLabelCreate,
|
||||
MultiPurposeLabelOut,
|
||||
MultiPurposeLabelSave,
|
||||
MultiPurposeLabelSummary,
|
||||
MultiPurposeLabelUpdate,
|
||||
)
|
||||
from mealie.schema.labels.multi_purpose_label import MultiPurposeLabelPagination
|
||||
from mealie.schema.mapper import cast
|
||||
from mealie.schema.response.pagination import PaginationQuery
|
||||
from mealie.services.group_services.labels_service import MultiPurposeLabelService
|
||||
|
||||
router = APIRouter(prefix="/groups/labels", tags=["Group: Multi Purpose Labels"], route_class=MealieCrudRoute)
|
||||
|
||||
|
||||
@controller(router)
|
||||
class MultiPurposeLabelsController(BaseUserController):
|
||||
@cached_property
|
||||
def service(self):
|
||||
return MultiPurposeLabelService(self.repos, self.group.id)
|
||||
|
||||
@cached_property
|
||||
def repo(self):
|
||||
if not self.user:
|
||||
raise Exception("No user is logged in.")
|
||||
|
||||
return self.repos.group_multi_purpose_labels.by_group(self.user.group_id)
|
||||
return self.repos.group_multi_purpose_labels
|
||||
|
||||
# =======================================================================
|
||||
# CRUD Operations
|
||||
@@ -49,8 +52,7 @@ class MultiPurposeLabelsController(BaseUserController):
|
||||
|
||||
@router.post("", response_model=MultiPurposeLabelOut)
|
||||
def create_one(self, data: MultiPurposeLabelCreate):
|
||||
save_data = cast(data, MultiPurposeLabelSave, group_id=self.user.group_id)
|
||||
return self.mixins.create_one(save_data)
|
||||
return self.service.create_one(data)
|
||||
|
||||
@router.get("/{item_id}", response_model=MultiPurposeLabelOut)
|
||||
def get_one(self, item_id: UUID4):
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from collections.abc import Callable
|
||||
from functools import cached_property
|
||||
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from pydantic import UUID4
|
||||
|
||||
from mealie.routes._base.base_controllers import BaseCrudController
|
||||
@@ -16,6 +16,7 @@ from mealie.schema.group.group_shopping_list import (
|
||||
ShoppingListItemsCollectionOut,
|
||||
ShoppingListItemUpdate,
|
||||
ShoppingListItemUpdateBulk,
|
||||
ShoppingListMultiPurposeLabelUpdate,
|
||||
ShoppingListOut,
|
||||
ShoppingListPagination,
|
||||
ShoppingListRemoveRecipeParams,
|
||||
@@ -23,7 +24,6 @@ from mealie.schema.group.group_shopping_list import (
|
||||
ShoppingListSummary,
|
||||
ShoppingListUpdate,
|
||||
)
|
||||
from mealie.schema.mapper import cast
|
||||
from mealie.schema.response.pagination import PaginationQuery
|
||||
from mealie.schema.response.responses import SuccessResponse
|
||||
from mealie.services.event_bus_service.event_types import (
|
||||
@@ -89,7 +89,7 @@ def publish_list_item_events(publisher: Callable, items_collection: ShoppingList
|
||||
class ShoppingListItemController(BaseCrudController):
|
||||
@cached_property
|
||||
def service(self):
|
||||
return ShoppingListService(self.repos)
|
||||
return ShoppingListService(self.repos, self.user, self.group)
|
||||
|
||||
@cached_property
|
||||
def repo(self):
|
||||
@@ -154,7 +154,7 @@ router = APIRouter(prefix="/groups/shopping/lists", tags=["Group: Shopping Lists
|
||||
class ShoppingListController(BaseCrudController):
|
||||
@cached_property
|
||||
def service(self):
|
||||
return ShoppingListService(self.repos)
|
||||
return ShoppingListService(self.repos, self.user, self.group)
|
||||
|
||||
@cached_property
|
||||
def repo(self):
|
||||
@@ -179,9 +179,7 @@ class ShoppingListController(BaseCrudController):
|
||||
|
||||
@router.post("", response_model=ShoppingListOut, status_code=201)
|
||||
def create_one(self, data: ShoppingListCreate):
|
||||
save_data = cast(data, ShoppingListSave, group_id=self.user.group_id)
|
||||
shopping_list = self.mixins.create_one(save_data)
|
||||
|
||||
shopping_list = self.service.create_one_list(data)
|
||||
if shopping_list:
|
||||
self.publish_event(
|
||||
event_type=EventTypes.shopping_list_created,
|
||||
@@ -197,14 +195,12 @@ class ShoppingListController(BaseCrudController):
|
||||
|
||||
@router.put("/{item_id}", response_model=ShoppingListOut)
|
||||
def update_one(self, item_id: UUID4, data: ShoppingListUpdate):
|
||||
shopping_list = self.mixins.update_one(data, item_id) # type: ignore
|
||||
|
||||
if shopping_list:
|
||||
self.publish_event(
|
||||
event_type=EventTypes.shopping_list_updated,
|
||||
document_data=EventShoppingListData(operation=EventOperation.update, shopping_list_id=shopping_list.id),
|
||||
message=self.t("notifications.generic-updated", name=shopping_list.name),
|
||||
)
|
||||
shopping_list = self.mixins.update_one(data, item_id)
|
||||
self.publish_event(
|
||||
event_type=EventTypes.shopping_list_updated,
|
||||
document_data=EventShoppingListData(operation=EventOperation.update, shopping_list_id=shopping_list.id),
|
||||
message=self.t("notifications.generic-updated", name=shopping_list.name),
|
||||
)
|
||||
|
||||
return shopping_list
|
||||
|
||||
@@ -244,3 +240,23 @@ class ShoppingListController(BaseCrudController):
|
||||
|
||||
publish_list_item_events(self.publish_event, items)
|
||||
return shopping_list
|
||||
|
||||
@router.put("/{item_id}/label-settings", response_model=ShoppingListOut)
|
||||
def update_label_settings(self, item_id: UUID4, data: list[ShoppingListMultiPurposeLabelUpdate]):
|
||||
for setting in data:
|
||||
if setting.shopping_list_id != item_id:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail=f"object {setting.id} has an invalid shopping list id",
|
||||
)
|
||||
|
||||
self.repos.shopping_list_multi_purpose_labels.update_many(data)
|
||||
updated_list = self.get_one(item_id)
|
||||
|
||||
self.publish_event(
|
||||
event_type=EventTypes.shopping_list_updated,
|
||||
document_data=EventShoppingListData(operation=EventOperation.update, shopping_list_id=updated_list.id),
|
||||
message=self.t("notifications.generic-updated", name=updated_list.name),
|
||||
)
|
||||
|
||||
return updated_list
|
||||
|
||||
@@ -14,7 +14,11 @@ from .group_events import (
|
||||
from .group_exports import GroupDataExport
|
||||
from .group_migration import DataMigrationCreate, SupportedMigrations
|
||||
from .group_permissions import SetPermissions
|
||||
from .group_preferences import CreateGroupPreferences, ReadGroupPreferences, UpdateGroupPreferences
|
||||
from .group_preferences import (
|
||||
CreateGroupPreferences,
|
||||
ReadGroupPreferences,
|
||||
UpdateGroupPreferences,
|
||||
)
|
||||
from .group_seeder import SeederConfig
|
||||
from .group_shopping_list import (
|
||||
ShoppingListAddRecipeParams,
|
||||
@@ -28,6 +32,9 @@ from .group_shopping_list import (
|
||||
ShoppingListItemsCollectionOut,
|
||||
ShoppingListItemUpdate,
|
||||
ShoppingListItemUpdateBulk,
|
||||
ShoppingListMultiPurposeLabelCreate,
|
||||
ShoppingListMultiPurposeLabelOut,
|
||||
ShoppingListMultiPurposeLabelUpdate,
|
||||
ShoppingListOut,
|
||||
ShoppingListPagination,
|
||||
ShoppingListRecipeRefOut,
|
||||
@@ -37,8 +44,20 @@ from .group_shopping_list import (
|
||||
ShoppingListUpdate,
|
||||
)
|
||||
from .group_statistics import GroupStatistics, GroupStorage
|
||||
from .invite_token import CreateInviteToken, EmailInitationResponse, EmailInvitation, ReadInviteToken, SaveInviteToken
|
||||
from .webhook import CreateWebhook, ReadWebhook, SaveWebhook, WebhookPagination, WebhookType
|
||||
from .invite_token import (
|
||||
CreateInviteToken,
|
||||
EmailInitationResponse,
|
||||
EmailInvitation,
|
||||
ReadInviteToken,
|
||||
SaveInviteToken,
|
||||
)
|
||||
from .webhook import (
|
||||
CreateWebhook,
|
||||
ReadWebhook,
|
||||
SaveWebhook,
|
||||
WebhookPagination,
|
||||
WebhookType,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"CreateGroupPreferences",
|
||||
@@ -73,6 +92,9 @@ __all__ = [
|
||||
"ShoppingListItemUpdate",
|
||||
"ShoppingListItemUpdateBulk",
|
||||
"ShoppingListItemsCollectionOut",
|
||||
"ShoppingListMultiPurposeLabelCreate",
|
||||
"ShoppingListMultiPurposeLabelOut",
|
||||
"ShoppingListMultiPurposeLabelUpdate",
|
||||
"ShoppingListOut",
|
||||
"ShoppingListPagination",
|
||||
"ShoppingListRecipeRefOut",
|
||||
|
||||
@@ -9,6 +9,8 @@ from pydantic.utils import GetterDict
|
||||
from mealie.db.models.group.shopping_list import ShoppingList, ShoppingListItem
|
||||
from mealie.schema._mealie import MealieModel
|
||||
from mealie.schema._mealie.types import NoneFloat
|
||||
from mealie.schema.labels.multi_purpose_label import MultiPurposeLabelSummary
|
||||
from mealie.schema.recipe.recipe import RecipeSummary
|
||||
from mealie.schema.recipe.recipe_ingredient import (
|
||||
INGREDIENT_QTY_PRECISION,
|
||||
MAX_INGREDIENT_DENOMINATOR,
|
||||
@@ -186,6 +188,23 @@ class ShoppingListItemsCollectionOut(MealieModel):
|
||||
deleted_items: list[ShoppingListItemOut] = []
|
||||
|
||||
|
||||
class ShoppingListMultiPurposeLabelCreate(MealieModel):
|
||||
shopping_list_id: UUID4
|
||||
label_id: UUID4
|
||||
position: int = 0
|
||||
|
||||
|
||||
class ShoppingListMultiPurposeLabelUpdate(ShoppingListMultiPurposeLabelCreate):
|
||||
id: UUID4
|
||||
|
||||
|
||||
class ShoppingListMultiPurposeLabelOut(ShoppingListMultiPurposeLabelUpdate):
|
||||
label: MultiPurposeLabelSummary
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
|
||||
class ShoppingListItemPagination(PaginationBase):
|
||||
items: list[ShoppingListItemOut]
|
||||
|
||||
@@ -217,6 +236,8 @@ class ShoppingListSave(ShoppingListCreate):
|
||||
|
||||
class ShoppingListSummary(ShoppingListSave):
|
||||
id: UUID4
|
||||
recipe_references: list[ShoppingListRecipeRefOut]
|
||||
label_settings: list[ShoppingListMultiPurposeLabelOut]
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
@@ -233,16 +254,25 @@ class ShoppingListPagination(PaginationBase):
|
||||
items: list[ShoppingListSummary]
|
||||
|
||||
|
||||
class ShoppingListUpdate(ShoppingListSummary):
|
||||
class ShoppingListUpdate(ShoppingListSave):
|
||||
id: UUID4
|
||||
list_items: list[ShoppingListItemOut] = []
|
||||
|
||||
|
||||
class ShoppingListOut(ShoppingListUpdate):
|
||||
recipe_references: list[ShoppingListRecipeRefOut]
|
||||
label_settings: list[ShoppingListMultiPurposeLabelOut]
|
||||
|
||||
class Config:
|
||||
orm_mode = True
|
||||
|
||||
@classmethod
|
||||
def getter_dict(cls, name_orm: ShoppingList):
|
||||
return {
|
||||
**GetterDict(name_orm),
|
||||
"extras": {x.key_name: x.value for x in name_orm.extras},
|
||||
}
|
||||
|
||||
|
||||
class ShoppingListAddRecipeParams(MealieModel):
|
||||
recipe_increment_quantity: float = 1
|
||||
@@ -252,10 +282,3 @@ class ShoppingListAddRecipeParams(MealieModel):
|
||||
|
||||
class ShoppingListRemoveRecipeParams(MealieModel):
|
||||
recipe_decrement_quantity: float = 1
|
||||
|
||||
|
||||
from mealie.schema.labels.multi_purpose_label import MultiPurposeLabelSummary # noqa: E402
|
||||
from mealie.schema.recipe.recipe import RecipeSummary # noqa: E402
|
||||
|
||||
ShoppingListRecipeRefOut.update_forward_refs()
|
||||
ShoppingListItemOut.update_forward_refs()
|
||||
|
||||
45
mealie/services/group_services/labels_service.py
Normal file
45
mealie/services/group_services/labels_service.py
Normal file
@@ -0,0 +1,45 @@
|
||||
from pydantic import UUID4
|
||||
|
||||
from mealie.repos.repository_factory import AllRepositories
|
||||
from mealie.schema.group.group_shopping_list import ShoppingListMultiPurposeLabelCreate
|
||||
from mealie.schema.labels.multi_purpose_label import (
|
||||
MultiPurposeLabelCreate,
|
||||
MultiPurposeLabelOut,
|
||||
MultiPurposeLabelSave,
|
||||
)
|
||||
from mealie.schema.response.pagination import PaginationQuery
|
||||
|
||||
|
||||
class MultiPurposeLabelService:
|
||||
def __init__(self, repos: AllRepositories, group_id: UUID4):
|
||||
self.repos = repos
|
||||
self.group_id = group_id
|
||||
self.labels = repos.group_multi_purpose_labels
|
||||
|
||||
def _update_shopping_list_label_references(self, new_labels: list[MultiPurposeLabelOut]) -> None:
|
||||
shopping_lists_repo = self.repos.group_shopping_lists.by_group(self.group_id)
|
||||
shopping_list_multi_purpose_labels_repo = self.repos.shopping_list_multi_purpose_labels
|
||||
|
||||
shopping_lists = shopping_lists_repo.page_all(PaginationQuery(page=1, per_page=-1))
|
||||
new_shopping_list_labels: list[ShoppingListMultiPurposeLabelCreate] = []
|
||||
for label in new_labels:
|
||||
new_shopping_list_labels.extend(
|
||||
[
|
||||
ShoppingListMultiPurposeLabelCreate(
|
||||
shopping_list_id=shopping_list.id, label_id=label.id, position=len(shopping_list.label_settings)
|
||||
)
|
||||
for shopping_list in shopping_lists.items
|
||||
]
|
||||
)
|
||||
|
||||
shopping_list_multi_purpose_labels_repo.create_many(new_shopping_list_labels)
|
||||
|
||||
def create_one(self, data: MultiPurposeLabelCreate) -> MultiPurposeLabelOut:
|
||||
label = self.labels.create(data.cast(MultiPurposeLabelSave, group_id=self.group_id))
|
||||
self._update_shopping_list_label_references([label])
|
||||
return label
|
||||
|
||||
def create_many(self, data: list[MultiPurposeLabelCreate]) -> list[MultiPurposeLabelOut]:
|
||||
labels = self.labels.create_many([label.cast(MultiPurposeLabelSave, group_id=self.group_id) for label in data])
|
||||
self._update_shopping_list_label_references(labels)
|
||||
return labels
|
||||
@@ -6,6 +6,7 @@ from mealie.core.exceptions import UnexpectedNone
|
||||
from mealie.repos.repository_factory import AllRepositories
|
||||
from mealie.schema.group import ShoppingListItemCreate, ShoppingListOut
|
||||
from mealie.schema.group.group_shopping_list import (
|
||||
ShoppingListCreate,
|
||||
ShoppingListItemBase,
|
||||
ShoppingListItemOut,
|
||||
ShoppingListItemRecipeRefCreate,
|
||||
@@ -13,18 +14,23 @@ from mealie.schema.group.group_shopping_list import (
|
||||
ShoppingListItemsCollectionOut,
|
||||
ShoppingListItemUpdate,
|
||||
ShoppingListItemUpdateBulk,
|
||||
ShoppingListMultiPurposeLabelCreate,
|
||||
ShoppingListSave,
|
||||
)
|
||||
from mealie.schema.recipe.recipe_ingredient import (
|
||||
IngredientFood,
|
||||
IngredientUnit,
|
||||
RecipeIngredient,
|
||||
)
|
||||
from mealie.schema.response.pagination import PaginationQuery
|
||||
from mealie.schema.response.pagination import OrderDirection, PaginationQuery
|
||||
from mealie.schema.user.user import GroupInDB, PrivateUser
|
||||
|
||||
|
||||
class ShoppingListService:
|
||||
def __init__(self, repos: AllRepositories):
|
||||
def __init__(self, repos: AllRepositories, user: PrivateUser, group: GroupInDB):
|
||||
self.repos = repos
|
||||
self.user = user
|
||||
self.group = group
|
||||
self.shopping_lists = repos.group_shopping_lists
|
||||
self.list_items = repos.group_shopping_list_item
|
||||
self.list_item_refs = repos.group_shopping_list_item_references
|
||||
@@ -463,3 +469,18 @@ class ShoppingListService:
|
||||
break
|
||||
|
||||
return self.shopping_lists.get_one(shopping_list.id), items # type: ignore
|
||||
|
||||
def create_one_list(self, data: ShoppingListCreate):
|
||||
create_data = data.cast(ShoppingListSave, group_id=self.group.id)
|
||||
new_list = self.shopping_lists.create(create_data) # type: ignore
|
||||
|
||||
labels = self.repos.group_multi_purpose_labels.by_group(self.group.id).page_all(
|
||||
PaginationQuery(page=1, per_page=-1, order_by="name", order_direction=OrderDirection.asc)
|
||||
)
|
||||
label_settings = [
|
||||
ShoppingListMultiPurposeLabelCreate(shopping_list_id=new_list.id, label_id=label.id, position=i)
|
||||
for i, label in enumerate(labels.items)
|
||||
]
|
||||
|
||||
self.repos.shopping_list_multi_purpose_labels.create_many(label_settings)
|
||||
return self.shopping_lists.get_one(new_list.id)
|
||||
|
||||
Reference in New Issue
Block a user