Coverage for opt/mealie/lib/python3.12/site-packages/mealie/schema/recipe/recipe_timeline_events.py: 100%
57 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 03:04 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-07 03:04 +0000
1from datetime import UTC, datetime
2from enum import Enum
3from pathlib import Path
4from typing import Annotated
6from pydantic import UUID4, ConfigDict, Field
7from sqlalchemy.orm import joinedload
8from sqlalchemy.orm.interfaces import LoaderOption
10from mealie.core.config import get_app_dirs
11from mealie.db.models.recipe.recipe_timeline import RecipeTimelineEvent
12from mealie.db.models.users.users import User
13from mealie.schema._mealie import MealieModel
14from mealie.schema._mealie.mealie_model import UpdatedAtField
15from mealie.schema.recipe.recipe import Recipe
16from mealie.schema.response.pagination import PaginationBase
18app_dirs = get_app_dirs()
21class TimelineEventType(Enum):
22 system = "system"
23 info = "info"
24 comment = "comment"
27class TimelineEventImage(Enum):
28 has_image = "has image"
29 does_not_have_image = "does not have image"
32class RecipeTimelineEventIn(MealieModel):
33 recipe_id: UUID4
34 user_id: UUID4 | None = None
35 """can be inferred in some contexts, so it's not required"""
37 subject: str
38 event_type: TimelineEventType
40 message: str | None = Field(None, alias="eventMessage")
41 image: Annotated[TimelineEventImage | None, Field(validate_default=True)] = TimelineEventImage.does_not_have_image
43 timestamp: datetime = datetime.now(UTC)
44 model_config = ConfigDict(use_enum_values=True)
47class RecipeTimelineEventCreate(RecipeTimelineEventIn):
48 user_id: UUID4
51class RecipeTimelineEventUpdate(MealieModel):
52 subject: str
53 message: str | None = Field(None, alias="eventMessage")
54 image: TimelineEventImage | None = None
55 model_config = ConfigDict(use_enum_values=True)
58class RecipeTimelineEventOut(RecipeTimelineEventCreate):
59 id: UUID4
60 group_id: UUID4
61 household_id: UUID4
63 created_at: datetime
64 updated_at: datetime = UpdatedAtField(...)
65 model_config = ConfigDict(from_attributes=True)
67 @classmethod
68 def loader_options(cls) -> list[LoaderOption]:
69 return [
70 joinedload(RecipeTimelineEvent.recipe),
71 joinedload(RecipeTimelineEvent.user).load_only(User.household_id, User.group_id),
72 ]
74 @classmethod
75 def image_dir_from_id(cls, recipe_id: UUID4 | str, timeline_event_id: UUID4 | str) -> Path:
76 return Recipe.timeline_image_dir_from_id(recipe_id, timeline_event_id)
78 @property
79 def image_dir(self) -> Path:
80 return self.image_dir_from_id(self.recipe_id, self.id)
83class RecipeTimelineEventPagination(PaginationBase):
84 items: list[RecipeTimelineEventOut]