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

1from datetime import UTC, datetime 

2from enum import Enum 

3from pathlib import Path 

4from typing import Annotated 

5 

6from pydantic import UUID4, ConfigDict, Field 

7from sqlalchemy.orm import joinedload 

8from sqlalchemy.orm.interfaces import LoaderOption 

9 

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 

17 

18app_dirs = get_app_dirs() 

19 

20 

21class TimelineEventType(Enum): 

22 system = "system" 

23 info = "info" 

24 comment = "comment" 

25 

26 

27class TimelineEventImage(Enum): 

28 has_image = "has image" 

29 does_not_have_image = "does not have image" 

30 

31 

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""" 

36 

37 subject: str 

38 event_type: TimelineEventType 

39 

40 message: str | None = Field(None, alias="eventMessage") 

41 image: Annotated[TimelineEventImage | None, Field(validate_default=True)] = TimelineEventImage.does_not_have_image 

42 

43 timestamp: datetime = datetime.now(UTC) 

44 model_config = ConfigDict(use_enum_values=True) 

45 

46 

47class RecipeTimelineEventCreate(RecipeTimelineEventIn): 

48 user_id: UUID4 

49 

50 

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) 

56 

57 

58class RecipeTimelineEventOut(RecipeTimelineEventCreate): 

59 id: UUID4 

60 group_id: UUID4 

61 household_id: UUID4 

62 

63 created_at: datetime 

64 updated_at: datetime = UpdatedAtField(...) 

65 model_config = ConfigDict(from_attributes=True) 

66 

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 ] 

73 

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) 

77 

78 @property 

79 def image_dir(self) -> Path: 

80 return self.image_dir_from_id(self.recipe_id, self.id) 

81 

82 

83class RecipeTimelineEventPagination(PaginationBase): 

84 items: list[RecipeTimelineEventOut]