Coverage for opt/mealie/lib/python3.12/site-packages/mealie/services/recipe/recipe_bulk_service.py: 69%
86 statements
« prev ^ index » next coverage.py v7.10.6, created at 2025-11-25 17:29 +0000
« prev ^ index » next coverage.py v7.10.6, created at 2025-11-25 17:29 +0000
1from pathlib import Path 1b
3from mealie.core.exceptions import UnexpectedNone 1b
4from mealie.repos.repository_factory import AllRepositories 1b
5from mealie.schema.group.group_exports import GroupDataExport 1b
6from mealie.schema.recipe import CategoryBase 1b
7from mealie.schema.recipe.recipe_category import TagBase 1b
8from mealie.schema.recipe.recipe_settings import RecipeSettings 1b
9from mealie.schema.user.user import GroupInDB, PrivateUser 1b
10from mealie.services._base_service import BaseService 1b
11from mealie.services.exporter import Exporter, RecipeExporter 1b
14class RecipeBulkActionsService(BaseService): 1b
15 def __init__(self, repos: AllRepositories, user: PrivateUser, group: GroupInDB): 1b
16 self.repos = repos 1edca
17 self.user = user 1edca
18 self.group = group 1edca
19 super().__init__() 1edca
21 def export_recipes(self, temp_path: Path, slugs: list[str]) -> None: 1b
22 recipe_exporter = RecipeExporter(self.repos, self.group.id, slugs)
23 exporter = Exporter(self.group.id, temp_path, [recipe_exporter])
25 exporter.run(self.repos)
27 def get_exports(self) -> list[GroupDataExport]: 1b
28 return self.repos.group_exports.multi_query({"group_id": self.group.id})
30 def purge_exports(self) -> int: 1b
31 all_exports = self.get_exports()
33 exports_deleted = 0
34 for export in all_exports: 34 ↛ 35line 34 didn't jump to line 35 because the loop on line 34 never started
35 try:
36 Path(export.path).unlink(missing_ok=True)
37 self.repos.group_exports.delete(export.id)
38 exports_deleted += 1
39 except Exception as e:
40 self.logger.error(f"Failed to delete export {export.id}")
41 self.logger.error(e)
43 group = self.repos.groups.get_one(self.group.id)
45 if group is None: 45 ↛ 46line 45 didn't jump to line 46 because the condition on line 45 was never true
46 raise UnexpectedNone("Failed to purge exports for group, no group found")
48 for match in group.directory.glob("**/export/*zip"): 48 ↛ 49line 48 didn't jump to line 49 because the loop on line 48 never started
49 if match.is_file():
50 match.unlink()
51 exports_deleted += 1
53 return exports_deleted
55 def set_settings(self, recipes: list[str], settings: RecipeSettings) -> None: 1b
56 for slug in recipes: 1ca
57 recipe = self.repos.recipes.get_one(slug) 1ca
59 if recipe is None or recipe.settings is None: 1ca
60 raise UnexpectedNone(f"Failed to set settings for recipe {slug}, no recipe found") 1ca
62 settings.locked = recipe.settings.locked
63 recipe.settings = settings
65 try:
66 self.repos.recipes.update(slug, recipe)
67 except Exception as e:
68 self.logger.error(f"Failed to set settings for recipe {slug}")
69 self.logger.error(e)
71 def assign_tags(self, recipes: list[str], tags: list[TagBase]) -> None: 1b
72 for slug in recipes: 1ca
73 recipe = self.repos.recipes.get_one(slug) 1ca
75 if recipe is None: 1ca
76 raise UnexpectedNone(f"Failed to tag recipe {slug}, no recipe found") 1ca
78 if recipe.tags is None: 78 ↛ 79line 78 didn't jump to line 79 because the condition on line 78 was never true
79 recipe.tags = []
81 recipe.tags += tags # type: ignore
83 try:
84 self.repos.recipes.update(slug, recipe)
85 except Exception as e:
86 self.logger.error(f"Failed to tag recipe {slug}")
87 self.logger.error(e)
89 def assign_categories(self, recipes: list[str], categories: list[CategoryBase]) -> None: 1b
90 for slug in recipes: 1ea
91 recipe = self.repos.recipes.get_one(slug) 1ea
93 if recipe is None: 93 ↛ 96line 93 didn't jump to line 96 because the condition on line 93 was always true1ea
94 raise UnexpectedNone(f"Failed to categorize recipe {slug}, no recipe found") 1ea
96 if recipe.recipe_category is None:
97 recipe.recipe_category = []
99 recipe.recipe_category += categories # type: ignore
101 try:
102 self.repos.recipes.update(slug, recipe)
103 except Exception as e:
104 self.logger.error(f"Failed to categorize recipe {slug}")
105 self.logger.error(e)
107 def delete_recipes(self, recipes: list[str]) -> None: 1b
108 for slug in recipes: 1da
109 try: 1da
110 self.repos.recipes.delete(slug) 1da
111 except Exception as e: 1da
112 self.logger.error(f"Failed to delete recipe {slug}") 1da
113 self.logger.error(e) 1da