From 8b6c75877d5873b3a73531bfae6614d747ad0ad0 Mon Sep 17 00:00:00 2001 From: Brian Choromanski Date: Sat, 26 Oct 2024 11:17:25 -0400 Subject: [PATCH] docs: Swagger/OpenAPI Organization (#4446) --- docs/docs/overrides/api.html | 2 +- .../routes/households/controller_mealplan.py | 62 +++++++++---------- .../households/controller_shopping_lists.py | 44 ++++++------- .../organizers/controller_categories.py | 10 +-- mealie/routes/parser/ingredient_parser.py | 10 +-- mealie/routes/recipe/recipe_crud_routes.py | 28 ++++----- mealie/routes/unit_and_foods/foods.py | 18 +++--- mealie/routes/unit_and_foods/units.py | 18 +++--- 8 files changed, 96 insertions(+), 96 deletions(-) diff --git a/docs/docs/overrides/api.html b/docs/docs/overrides/api.html index 1b2598313..b6801b8b9 100644 --- a/docs/docs/overrides/api.html +++ b/docs/docs/overrides/api.html @@ -14,7 +14,7 @@
diff --git a/mealie/routes/households/controller_mealplan.py b/mealie/routes/households/controller_mealplan.py index 5f81e984f..c039cb973 100644 --- a/mealie/routes/households/controller_mealplan.py +++ b/mealie/routes/households/controller_mealplan.py @@ -66,37 +66,6 @@ class GroupMealplanController(BaseCrudController): ) return recipes_data.items - @router.get("/today") - def get_todays_meals(self): - return self.repo.get_today() - - @router.post("/random", response_model=ReadPlanEntry) - def create_random_meal(self, data: CreateRandomEntry): - """ - `create_random_meal` is a route that provides the randomized functionality for mealplaners. - It operates by following the rules set out in the household's mealplan settings. If no settings - are set, it will return any random meal. - - Refer to the mealplan settings routes for more information on how rules can be applied - to the random meal selector. - """ - random_recipes = self._get_random_recipes_from_mealplan(data.date, data.entry_type) - if not random_recipes: - raise HTTPException( - status_code=404, detail=ErrorResponse.respond(message=self.t("mealplan.no-recipes-match-your-rules")) - ) - - recipe = random_recipes[0] - return self.mixins.create_one( - SavePlanEntry( - date=data.date, - entry_type=data.entry_type, - recipe_id=recipe.id, - group_id=self.group_id, - user_id=self.user.id, - ) - ) - @router.get("", response_model=PlanEntryPagination) def get_all( self, @@ -144,6 +113,37 @@ class GroupMealplanController(BaseCrudController): return result + @router.get("/today") + def get_todays_meals(self): + return self.repo.get_today() + + @router.post("/random", response_model=ReadPlanEntry) + def create_random_meal(self, data: CreateRandomEntry): + """ + `create_random_meal` is a route that provides the randomized functionality for mealplaners. + It operates by following the rules set out in the household's mealplan settings. If no settings + are set, it will return any random meal. + + Refer to the mealplan settings routes for more information on how rules can be applied + to the random meal selector. + """ + random_recipes = self._get_random_recipes_from_mealplan(data.date, data.entry_type) + if not random_recipes: + raise HTTPException( + status_code=404, detail=ErrorResponse.respond(message=self.t("mealplan.no-recipes-match-your-rules")) + ) + + recipe = random_recipes[0] + return self.mixins.create_one( + SavePlanEntry( + date=data.date, + entry_type=data.entry_type, + recipe_id=recipe.id, + group_id=self.group_id, + user_id=self.user.id, + ) + ) + @router.get("/{item_id}", response_model=ReadPlanEntry) def get_one(self, item_id: int): return self.mixins.get_one(item_id) diff --git a/mealie/routes/households/controller_shopping_lists.py b/mealie/routes/households/controller_shopping_lists.py index 4c19d92dc..e60b3369d 100644 --- a/mealie/routes/households/controller_shopping_lists.py +++ b/mealie/routes/households/controller_shopping_lists.py @@ -230,28 +230,6 @@ class ShoppingListController(BaseCrudController): # ======================================================================= # Other Operations - @router.post("/{item_id}/recipe/{recipe_id}", response_model=ShoppingListOut) - def add_recipe_ingredients_to_list( - self, item_id: UUID4, recipe_id: UUID4, data: ShoppingListAddRecipeParams | None = None - ): - shopping_list, items = self.service.add_recipe_ingredients_to_list( - item_id, recipe_id, data.recipe_increment_quantity if data else 1, data.recipe_ingredients if data else None - ) - - publish_list_item_events(self.publish_event, items) - return shopping_list - - @router.post("/{item_id}/recipe/{recipe_id}/delete", response_model=ShoppingListOut) - def remove_recipe_ingredients_from_list( - self, item_id: UUID4, recipe_id: UUID4, data: ShoppingListRemoveRecipeParams | None = None - ): - shopping_list, items = self.service.remove_recipe_ingredients_from_list( - item_id, recipe_id, data.recipe_decrement_quantity if data else 1 - ) - - 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: @@ -273,3 +251,25 @@ class ShoppingListController(BaseCrudController): ) return updated_list + + @router.post("/{item_id}/recipe/{recipe_id}", response_model=ShoppingListOut) + def add_recipe_ingredients_to_list( + self, item_id: UUID4, recipe_id: UUID4, data: ShoppingListAddRecipeParams | None = None + ): + shopping_list, items = self.service.add_recipe_ingredients_to_list( + item_id, recipe_id, data.recipe_increment_quantity if data else 1, data.recipe_ingredients if data else None + ) + + publish_list_item_events(self.publish_event, items) + return shopping_list + + @router.post("/{item_id}/recipe/{recipe_id}/delete", response_model=ShoppingListOut) + def remove_recipe_ingredients_from_list( + self, item_id: UUID4, recipe_id: UUID4, data: ShoppingListRemoveRecipeParams | None = None + ): + shopping_list, items = self.service.remove_recipe_ingredients_from_list( + item_id, recipe_id, data.recipe_decrement_quantity if data else 1 + ) + + publish_list_item_events(self.publish_event, items) + return shopping_list diff --git a/mealie/routes/organizers/controller_categories.py b/mealie/routes/organizers/controller_categories.py index ca93ccc32..59aae5e1e 100644 --- a/mealie/routes/organizers/controller_categories.py +++ b/mealie/routes/organizers/controller_categories.py @@ -67,6 +67,11 @@ class RecipeCategoryController(BaseCrudController): return new_category + @router.get("/empty", response_model=list[CategoryBase]) + def get_all_empty(self): + """Returns a list of categories that do not contain any recipes""" + return self.repos.categories.get_empty() + @router.get("/{item_id}", response_model=CategorySummary) def get_one(self, item_id: UUID4): """Returns a list of recipes associated with the provided category.""" @@ -114,11 +119,6 @@ class RecipeCategoryController(BaseCrudController): # ========================================================================= # Read All Operations - @router.get("/empty", response_model=list[CategoryBase]) - def get_all_empty(self): - """Returns a list of categories that do not contain any recipes""" - return self.repos.categories.get_empty() - @router.get("/slug/{category_slug}") def get_one_by_slug(self, category_slug: str): """Returns a category object with the associated recieps relating to the category""" diff --git a/mealie/routes/parser/ingredient_parser.py b/mealie/routes/parser/ingredient_parser.py index dc2cc732c..a4a36d2aa 100644 --- a/mealie/routes/parser/ingredient_parser.py +++ b/mealie/routes/parser/ingredient_parser.py @@ -10,13 +10,13 @@ router = APIRouter(prefix="/parser") @controller(router) class IngredientParserController(BaseUserController): - @router.post("/ingredients", response_model=list[ParsedIngredient]) - async def parse_ingredients(self, ingredients: IngredientsRequest): - parser = get_parser(ingredients.parser, self.group_id, self.session) - return await parser.parse(ingredients.ingredients) - @router.post("/ingredient", response_model=ParsedIngredient) async def parse_ingredient(self, ingredient: IngredientRequest): parser = get_parser(ingredient.parser, self.group_id, self.session) response = await parser.parse([ingredient.ingredient]) return response[0] + + @router.post("/ingredients", response_model=list[ParsedIngredient]) + async def parse_ingredients(self, ingredients: IngredientsRequest): + parser = get_parser(ingredients.parser, self.group_id, self.session) + return await parser.parse(ingredients.ingredients) diff --git a/mealie/routes/recipe/recipe_crud_routes.py b/mealie/routes/recipe/recipe_crud_routes.py index e21aa9b31..a842c2da9 100644 --- a/mealie/routes/recipe/recipe_crud_routes.py +++ b/mealie/routes/recipe/recipe_crud_routes.py @@ -203,6 +203,20 @@ class RecipeController(BaseRecipeController): # ======================================================================= # URL Scraping Operations + @router.post("/test-scrape-url") + async def test_parse_recipe_url(self, data: ScrapeRecipeTest): + # Debugger should produce the same result as the scraper sees before cleaning + ScraperClass = RecipeScraperOpenAI if data.use_openai else RecipeScraperPackage + try: + if scraped_data := await ScraperClass(data.url, self.translator).scrape_url(): + return scraped_data.schema.data + except ForceTimeoutException as e: + raise HTTPException( + status_code=408, detail=ErrorResponse.respond(message="Recipe Scraping Timed Out") + ) from e + + return "recipe_scrapers was unable to scrape this URL" + @router.post("/create/html-or-json", status_code=201) async def create_recipe_from_html_or_json(self, req: ScrapeRecipeData): """Takes in raw HTML or a https://schema.org/Recipe object as a JSON string and parses it like a URL""" @@ -271,20 +285,6 @@ class RecipeController(BaseRecipeController): return {"reportId": report_id} - @router.post("/test-scrape-url") - async def test_parse_recipe_url(self, data: ScrapeRecipeTest): - # Debugger should produce the same result as the scraper sees before cleaning - ScraperClass = RecipeScraperOpenAI if data.use_openai else RecipeScraperPackage - try: - if scraped_data := await ScraperClass(data.url, self.translator).scrape_url(): - return scraped_data.schema.data - except ForceTimeoutException as e: - raise HTTPException( - status_code=408, detail=ErrorResponse.respond(message="Recipe Scraping Timed Out") - ) from e - - return "recipe_scrapers was unable to scrape this URL" - # ================================================================================================================== # Other Create Operations diff --git a/mealie/routes/unit_and_foods/foods.py b/mealie/routes/unit_and_foods/foods.py index bb2a02487..dc5aed653 100644 --- a/mealie/routes/unit_and_foods/foods.py +++ b/mealie/routes/unit_and_foods/foods.py @@ -35,15 +35,6 @@ class IngredientFoodsController(BaseUserController): self.registered_exceptions, ) - @router.put("/merge", response_model=SuccessResponse) - def merge_one(self, data: MergeFood): - try: - self.repo.merge(data.from_food, data.to_food) - return SuccessResponse.respond("Successfully merged foods") - except Exception as e: - self.logger.error(e) - raise HTTPException(500, "Failed to merge foods") from e - @router.get("", response_model=IngredientFoodPagination) def get_all(self, q: PaginationQuery = Depends(PaginationQuery), search: str | None = None): response = self.repo.page_all( @@ -60,6 +51,15 @@ class IngredientFoodsController(BaseUserController): save_data = mapper.cast(data, SaveIngredientFood, group_id=self.group_id) return self.mixins.create_one(save_data) + @router.put("/merge", response_model=SuccessResponse) + def merge_one(self, data: MergeFood): + try: + self.repo.merge(data.from_food, data.to_food) + return SuccessResponse.respond("Successfully merged foods") + except Exception as e: + self.logger.error(e) + raise HTTPException(500, "Failed to merge foods") from e + @router.get("/{item_id}", response_model=IngredientFood) def get_one(self, item_id: UUID4): return self.mixins.get_one(item_id) diff --git a/mealie/routes/unit_and_foods/units.py b/mealie/routes/unit_and_foods/units.py index 8f43e52a1..2f98b11e5 100644 --- a/mealie/routes/unit_and_foods/units.py +++ b/mealie/routes/unit_and_foods/units.py @@ -35,15 +35,6 @@ class IngredientUnitsController(BaseUserController): self.registered_exceptions, ) - @router.put("/merge", response_model=SuccessResponse) - def merge_one(self, data: MergeUnit): - try: - self.repo.merge(data.from_unit, data.to_unit) - return SuccessResponse.respond("Successfully merged units") - except Exception as e: - self.logger.error(e) - raise HTTPException(500, "Failed to merge units") from e - @router.get("", response_model=IngredientUnitPagination) def get_all(self, q: PaginationQuery = Depends(PaginationQuery), search: str | None = None): response = self.repo.page_all( @@ -60,6 +51,15 @@ class IngredientUnitsController(BaseUserController): save_data = mapper.cast(data, SaveIngredientUnit, group_id=self.group_id) return self.mixins.create_one(save_data) + @router.put("/merge", response_model=SuccessResponse) + def merge_one(self, data: MergeUnit): + try: + self.repo.merge(data.from_unit, data.to_unit) + return SuccessResponse.respond("Successfully merged units") + except Exception as e: + self.logger.error(e) + raise HTTPException(500, "Failed to merge units") from e + @router.get("/{item_id}", response_model=IngredientUnit) def get_one(self, item_id: UUID4): return self.mixins.get_one(item_id)