feat: Additional Household Permissions (#4158)

Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com>
This commit is contained in:
Michael Genson
2024-09-17 10:48:14 -05:00
committed by GitHub
parent b1820f9b23
commit fd0257c1b8
37 changed files with 690 additions and 185 deletions

View File

@@ -73,7 +73,11 @@ class RecipeService(RecipeServiceBase):
# Check if this user has permission to edit this recipe
if self.household.id != recipe.household_id:
return False
other_household = self.repos.households.get_one(recipe.household_id)
if not (other_household and other_household.preferences):
return False
if other_household.preferences.lock_recipe_edits_from_other_households:
return False
if recipe.settings.locked:
return False
@@ -135,7 +139,7 @@ class RecipeService(RecipeServiceBase):
return Recipe(**additional_attrs)
def get_one(self, slug_or_id: str | UUID) -> Recipe | None:
def get_one(self, slug_or_id: str | UUID) -> Recipe:
if isinstance(slug_or_id, str):
try:
slug_or_id = UUID(slug_or_id)
@@ -301,10 +305,10 @@ class RecipeService(RecipeServiceBase):
data_service.write_image(f.read(), "webp")
return recipe
def duplicate_one(self, old_slug: str, dup_data: RecipeDuplicate) -> Recipe:
def duplicate_one(self, old_slug_or_id: str | UUID, dup_data: RecipeDuplicate) -> Recipe:
"""Duplicates a recipe and returns the new recipe."""
old_recipe = self._get_recipe(old_slug)
old_recipe = self.get_one(old_slug_or_id)
new_recipe_data = old_recipe.model_dump(exclude={"id", "name", "slug", "image", "comments"}, round_trip=True)
new_recipe = Recipe.model_validate(new_recipe_data)
@@ -356,7 +360,7 @@ class RecipeService(RecipeServiceBase):
return new_recipe
def _pre_update_check(self, slug: str, new_data: Recipe) -> Recipe:
def _pre_update_check(self, slug_or_id: str | UUID, new_data: Recipe) -> Recipe:
"""
gets the recipe from the database and performs a check to see if the user can update the recipe.
If the user can't update the recipe, an exception is raised.
@@ -367,14 +371,14 @@ class RecipeService(RecipeServiceBase):
- _if_ the user is locking the recipe, that they can lock the recipe (user is the owner)
Args:
slug (str): recipe slug
slug_or_id (str | UUID): recipe slug or id
new_data (Recipe): the new recipe data
Raises:
exceptions.PermissionDenied (403)
"""
recipe = self._get_recipe(slug)
recipe = self.get_one(slug_or_id)
if recipe is None or recipe.settings is None:
raise exceptions.NoEntryFound("Recipe not found.")
@@ -388,38 +392,35 @@ class RecipeService(RecipeServiceBase):
return recipe
def update_one(self, slug: str, update_data: Recipe) -> Recipe:
recipe = self._pre_update_check(slug, update_data)
def update_one(self, slug_or_id: str | UUID, update_data: Recipe) -> Recipe:
recipe = self._pre_update_check(slug_or_id, update_data)
new_data = self.repos.recipes.update(slug, update_data)
new_data = self.group_recipes.update(recipe.slug, update_data)
self.check_assets(new_data, recipe.slug)
return new_data
def patch_one(self, slug: str, patch_data: Recipe) -> Recipe:
recipe: Recipe | None = self._pre_update_check(slug, patch_data)
recipe = self._get_recipe(slug)
def patch_one(self, slug_or_id: str | UUID, patch_data: Recipe) -> Recipe:
recipe: Recipe | None = self._pre_update_check(slug_or_id, patch_data)
recipe = self.get_one(slug_or_id)
if recipe is None:
raise exceptions.NoEntryFound("Recipe not found.")
new_data = self.repos.recipes.patch(recipe.slug, patch_data.model_dump(exclude_unset=True))
new_data = self.group_recipes.patch(recipe.slug, patch_data.model_dump(exclude_unset=True))
self.check_assets(new_data, recipe.slug)
return new_data
def update_last_made(self, slug: str, timestamp: datetime) -> Recipe:
def update_last_made(self, slug_or_id: str | UUID, timestamp: datetime) -> Recipe:
# we bypass the pre update check since any user can update a recipe's last made date, even if it's locked,
# or if the user belongs to a different household
recipe = self._get_recipe(slug)
recipe = self.get_one(slug_or_id)
return self.group_recipes.patch(recipe.slug, {"last_made": timestamp})
def delete_one(self, slug) -> Recipe:
recipe = self._get_recipe(slug)
def delete_one(self, slug_or_id: str | UUID) -> Recipe:
recipe = self.get_one(slug_or_id)
if not self.can_update(recipe):
raise exceptions.PermissionDenied("You do not have permission to delete this recipe.")
data = self.repos.recipes.delete(recipe.id, "id")
data = self.group_recipes.delete(recipe.id, "id")
self.delete_assets(data)
return data

View File

@@ -39,6 +39,7 @@ class RegistrationService:
household=household,
can_invite=new_group,
can_manage=new_group,
can_manage_household=new_group,
can_organize=new_group,
)