mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-31 10:13:32 -04:00 
			
		
		
		
	api documentation
This commit is contained in:
		| @@ -1,4 +1,3 @@ | ||||
| # from datetime import datetime | ||||
| from typing import List, Optional | ||||
|  | ||||
| from pydantic import BaseModel | ||||
|   | ||||
							
								
								
									
										12
									
								
								mealie/models/migration_models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								mealie/models/migration_models.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| from pydantic.main import BaseModel | ||||
|  | ||||
|  | ||||
| class ChowdownURL(BaseModel): | ||||
|     url: str | ||||
|  | ||||
|     class Config: | ||||
|         schema_extra = { | ||||
|             "example": { | ||||
|                 "url": "https://chowdownrepo.com/repo", | ||||
|             } | ||||
|         } | ||||
							
								
								
									
										56
									
								
								mealie/models/recipe_models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								mealie/models/recipe_models.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| from typing import List, Optional | ||||
|  | ||||
| import pydantic | ||||
| from pydantic.main import BaseModel | ||||
|  | ||||
|  | ||||
| class RecipeResponse(BaseModel): | ||||
|     class Config: | ||||
|         schema_extra = { | ||||
|             "example": [ | ||||
|                 { | ||||
|                     "slug": "crockpot-buffalo-chicken", | ||||
|                     "image": "crockpot-buffalo-chicken.jpg", | ||||
|                     "name": "Crockpot Buffalo Chicken", | ||||
|                 }, | ||||
|                 { | ||||
|                     "slug": "downtown-marinade", | ||||
|                     "image": "downtown-marinade.jpg", | ||||
|                     "name": "Downtown Marinade", | ||||
|                 }, | ||||
|                 { | ||||
|                     "slug": "detroit-style-pepperoni-pizza", | ||||
|                     "image": "detroit-style-pepperoni-pizza.jpg", | ||||
|                     "name": "Detroit-Style Pepperoni Pizza", | ||||
|                 }, | ||||
|                 { | ||||
|                     "slug": "crispy-carrots", | ||||
|                     "image": "crispy-carrots.jpg", | ||||
|                     "name": "Crispy Carrots", | ||||
|                 }, | ||||
|             ] | ||||
|         } | ||||
|  | ||||
|  | ||||
| class AllRecipeRequest(BaseModel): | ||||
|     properties: List[str] | ||||
|     limit: Optional[int] | ||||
|  | ||||
|     class Config: | ||||
|         schema_extra = { | ||||
|             "example": { | ||||
|                 "properties": ["name", "slug", "image"], | ||||
|                 "limit": 100, | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
| class RecipeURLIn(BaseModel): | ||||
|     class Config: | ||||
|         schema_extra = {"example": {"url": "https://myfavoriterecipes.com/recipes"}} | ||||
|  | ||||
| class SlugResponse(BaseModel): | ||||
|     class Config: | ||||
|             schema_extra = { | ||||
|                 "example": "adult-mac-and-cheese" | ||||
|             } | ||||
| @@ -1,22 +1,23 @@ | ||||
| from pprint import pprint | ||||
| from typing import List | ||||
|  | ||||
| from fastapi import APIRouter, HTTPException | ||||
| from models.recipe_models import SlugResponse | ||||
| from services.meal_services import MealPlan | ||||
| from utils.snackbar import SnackResponse | ||||
|  | ||||
| router = APIRouter() | ||||
|  | ||||
|  | ||||
| @router.get("/api/meal-plan/all/", tags=["Meal Plan"]) | ||||
| @router.get("/api/meal-plan/all/", tags=["Meal Plan"], response_model=List[MealPlan]) | ||||
| async def get_all_meals(): | ||||
|     """ Returns a list of all available meal plans """ | ||||
|     """ Returns a list of all available Meal Plan """ | ||||
|  | ||||
|     return MealPlan.get_all() | ||||
|  | ||||
|  | ||||
| @router.post("/api/meal-plan/create/", tags=["Meal Plan"]) | ||||
| async def set_meal_plan(data: MealPlan): | ||||
|     """ Creates a mealplan database entry""" | ||||
|     """ Creates a meal plan database entry """ | ||||
|     data.process_meals() | ||||
|     data.save_to_db() | ||||
|  | ||||
| @@ -30,7 +31,7 @@ async def set_meal_plan(data: MealPlan): | ||||
|  | ||||
| @router.post("/api/meal-plan/{plan_id}/update/", tags=["Meal Plan"]) | ||||
| async def update_meal_plan(plan_id: str, meal_plan: MealPlan): | ||||
|     """ Updates a Meal Plan Based off ID """ | ||||
|     """ Updates a meal plan based off ID """ | ||||
|  | ||||
|     try: | ||||
|         meal_plan.process_meals() | ||||
| @@ -46,21 +47,24 @@ async def update_meal_plan(plan_id: str, meal_plan: MealPlan): | ||||
|  | ||||
| @router.delete("/api/meal-plan/{plan_id}/delete/", tags=["Meal Plan"]) | ||||
| async def delete_meal_plan(plan_id): | ||||
|     """ Doc Str """ | ||||
|     """ Removes a meal plan from the database """ | ||||
|  | ||||
|     MealPlan.delete(plan_id) | ||||
|  | ||||
|     return SnackResponse.success("Mealplan Deleted") | ||||
|  | ||||
|  | ||||
| @router.get("/api/meal-plan/today/", tags=["Meal Plan"]) | ||||
| @router.get("/api/meal-plan/today/", tags=["Meal Plan"], response_model=SlugResponse) | ||||
| async def get_today(): | ||||
|     """ Returns the meal plan data for today """ | ||||
|     """ | ||||
|     Returns the recipe slug for the meal scheduled for today. | ||||
|     If no meal is scheduled nothing is returned | ||||
|     """ | ||||
|  | ||||
|     return MealPlan.today() | ||||
|  | ||||
|  | ||||
| @router.get("/api/meal-plan/this-week/", tags=["Meal Plan"]) | ||||
| @router.get("/api/meal-plan/this-week/", tags=["Meal Plan"], response_model=MealPlan) | ||||
| async def get_this_week(): | ||||
|     """ Returns the meal plan data for this week """ | ||||
|  | ||||
|   | ||||
| @@ -1,5 +1,6 @@ | ||||
| from fastapi import APIRouter, HTTPException | ||||
| from models.backup_models import BackupJob | ||||
| from models.migration_models import ChowdownURL | ||||
| from services.migrations.chowdown import chowdown_migrate as chowdow_migrate | ||||
| from utils.snackbar import SnackResponse | ||||
|  | ||||
| @@ -7,10 +8,10 @@ router = APIRouter() | ||||
|  | ||||
|  | ||||
| @router.post("/api/migration/chowdown/repo/", tags=["Migration"]) | ||||
| async def import_chowdown_recipes(repo: dict): | ||||
| async def import_chowdown_recipes(repo: ChowdownURL): | ||||
|     """ Import Chowsdown Recipes from Repo URL """ | ||||
|     try: | ||||
|         report = chowdow_migrate(repo.get("url")) | ||||
|         report = chowdow_migrate(repo.url) | ||||
|         return SnackResponse.success( | ||||
|             "Recipes Imported from Git Repo, see report for failures.", | ||||
|             additional_data=report, | ||||
|   | ||||
| @@ -2,6 +2,12 @@ from typing import List, Optional | ||||
|  | ||||
| from fastapi import APIRouter, File, Form, HTTPException, Query | ||||
| from fastapi.responses import FileResponse | ||||
| from models.recipe_models import ( | ||||
|     AllRecipeRequest, | ||||
|     RecipeResponse, | ||||
|     RecipeURLIn, | ||||
|     SlugResponse, | ||||
| ) | ||||
| from services.image_services import read_image, write_image | ||||
| from services.recipe_services import Recipe, read_requested_values | ||||
| from services.scrape_services import create_from_url | ||||
| @@ -10,17 +16,42 @@ from utils.snackbar import SnackResponse | ||||
| router = APIRouter() | ||||
|  | ||||
|  | ||||
| @router.get("/api/all-recipes/", tags=["Recipes"]) | ||||
| @router.get("/api/all-recipes/", tags=["Recipes"], response_model=RecipeResponse) | ||||
| async def get_all_recipes( | ||||
|     keys: Optional[List[str]] = Query(...), num: Optional[int] = 100 | ||||
| ) -> Optional[List[str]]: | ||||
|     """ Returns key data for all recipes """ | ||||
| ): | ||||
|     """ | ||||
|     Returns key data for all recipes based off the query paramters provided. | ||||
|     For example, if slug, image, and name are provided you will recieve a list of | ||||
|     recipes containing the slug, image, and name property. By default, responses | ||||
|     are limited to 100. | ||||
|  | ||||
|     **Note:** You may experience problems with with query parameters. As an alternative | ||||
|     you may also use the post method and provide a body. | ||||
|     See the *Post* method for more details. | ||||
|     """ | ||||
|  | ||||
|     all_recipes = read_requested_values(keys, num) | ||||
|     return all_recipes | ||||
|  | ||||
|  | ||||
| @router.get("/api/recipe/{recipe_slug}/", tags=["Recipes"]) | ||||
| @router.post("/api/all-recipes/", tags=["Recipes"], response_model=RecipeResponse) | ||||
| async def get_all_recipes_post(body: AllRecipeRequest): | ||||
|     """ | ||||
|     Returns key data for all recipes based off the body data provided. | ||||
|     For example, if slug, image, and name are provided you will recieve a list of | ||||
|     recipes containing the slug, image, and name property. | ||||
|  | ||||
|     Refer to the body example for data formats. | ||||
|  | ||||
|     """ | ||||
|  | ||||
|     all_recipes = read_requested_values(body.properties, body.limit) | ||||
|  | ||||
|     return all_recipes | ||||
|  | ||||
|  | ||||
| @router.get("/api/recipe/{recipe_slug}/", tags=["Recipes"], response_model=Recipe) | ||||
| async def get_recipe(recipe_slug: str): | ||||
|     """ Takes in a recipe slug, returns all data for a recipe """ | ||||
|     recipe = Recipe.get_by_slug(recipe_slug) | ||||
| @@ -37,24 +68,21 @@ async def get_recipe_img(recipe_slug: str): | ||||
|  | ||||
|  | ||||
| # Recipe Creations | ||||
| @router.post("/api/recipe/create-url/", tags=["Recipes"], status_code=201) | ||||
| async def get_recipe_url(url: dict): | ||||
|     """ Takes in a URL and Attempts to scrape data and load it into the database """ | ||||
| @router.post( | ||||
|     "/api/recipe/create-url/", | ||||
|     tags=["Recipes"], | ||||
|     status_code=201, | ||||
|     response_model=SlugResponse, | ||||
| ) | ||||
| async def parse_recipe_url(url: RecipeURLIn): | ||||
|     """ Takes in a URL and attempts to scrape data and load it into the database """ | ||||
|  | ||||
|     url = url.get("url") | ||||
|     slug = create_from_url(url) | ||||
|  | ||||
|     # try: | ||||
|     #     slug = create_from_url(url) | ||||
|     # except: | ||||
|     #     raise HTTPException( | ||||
|     #         status_code=400, detail=SnackResponse.error("Unable to Parse URL") | ||||
|     #     ) | ||||
|     slug = create_from_url(url.url) | ||||
|  | ||||
|     return slug | ||||
|  | ||||
|  | ||||
| @router.post("/api/recipe/create/", tags=["Recipes"]) | ||||
| @router.post("/api/recipe/create/", tags=["Recipes"], response_model=SlugResponse) | ||||
| async def create_from_json(data: Recipe) -> str: | ||||
|     """ Takes in a JSON string and loads data into the database as a new entry""" | ||||
|     created_recipe = data.save_to_db() | ||||
| @@ -63,7 +91,7 @@ async def create_from_json(data: Recipe) -> str: | ||||
|  | ||||
|  | ||||
| @router.post("/api/recipe/{recipe_slug}/update/image/", tags=["Recipes"]) | ||||
| def update_image( | ||||
| def update_recipe_image( | ||||
|     recipe_slug: str, image: bytes = File(...), extension: str = Form(...) | ||||
| ): | ||||
|     """ Removes an existing image and replaces it with the incoming file. """ | ||||
| @@ -73,7 +101,7 @@ def update_image( | ||||
|  | ||||
|  | ||||
| @router.post("/api/recipe/{recipe_slug}/update/", tags=["Recipes"]) | ||||
| async def update(recipe_slug: str, data: Recipe): | ||||
| async def update_recipe(recipe_slug: str, data: Recipe): | ||||
|     """ Updates a recipe by existing slug and data. Data should containt """ | ||||
|  | ||||
|     data.update(recipe_slug) | ||||
| @@ -82,7 +110,7 @@ async def update(recipe_slug: str, data: Recipe): | ||||
|  | ||||
|  | ||||
| @router.delete("/api/recipe/{recipe_slug}/delete/", tags=["Recipes"]) | ||||
| async def delete(recipe_slug: str): | ||||
| async def delete_recipe(recipe_slug: str): | ||||
|     """ Deletes a recipe by slug """ | ||||
|  | ||||
|     try: | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| from typing import List | ||||
|  | ||||
| from db.mongo_setup import global_init | ||||
| from fastapi import APIRouter, HTTPException | ||||
| from services.scheduler_services import Scheduler, post_webhooks | ||||
| @@ -11,16 +13,16 @@ scheduler = Scheduler() | ||||
| scheduler.startup_scheduler() | ||||
|  | ||||
|  | ||||
| @router.get("/api/site-settings/", tags=["Settings"]) | ||||
| @router.get("/api/site-settings/", tags=["Settings"], response_model=SiteSettings) | ||||
| async def get_main_settings(): | ||||
|     """ Returns basic site Settings """ | ||||
|     """ Returns basic site settings """ | ||||
|  | ||||
|     return SiteSettings.get_site_settings() | ||||
|  | ||||
|  | ||||
| @router.post("/api/site-settings/webhooks/test/", tags=["Settings"]) | ||||
| async def test_webhooks(): | ||||
|     """ Test Webhooks """ | ||||
|     """ Run the function to test your webhooks """ | ||||
|  | ||||
|     return post_webhooks() | ||||
|  | ||||
| @@ -40,22 +42,26 @@ async def update_settings(data: SiteSettings): | ||||
|     return SnackResponse.success("Settings Updated") | ||||
|  | ||||
|  | ||||
| @router.get("/api/site-settings/themes/", tags=["Themes"]) | ||||
| @router.get( | ||||
|     "/api/site-settings/themes/", tags=["Themes"], response_model=List[SiteTheme] | ||||
| ) | ||||
| async def get_all_themes(): | ||||
|     """ Returns all site themes """ | ||||
|  | ||||
|     return SiteTheme.get_all() | ||||
|  | ||||
|  | ||||
| @router.get("/api/site-settings/themes/{theme_name}/", tags=["Themes"]) | ||||
| @router.get( | ||||
|     "/api/site-settings/themes/{theme_name}/", tags=["Themes"], response_model=SiteTheme | ||||
| ) | ||||
| async def get_single_theme(theme_name: str): | ||||
|     """ Returns basic site Settings """ | ||||
|     """ Returns a named theme """ | ||||
|     return SiteTheme.get_by_name(theme_name) | ||||
|  | ||||
|  | ||||
| @router.post("/api/site-settings/themes/create/", tags=["Themes"]) | ||||
| async def create_theme(data: SiteTheme): | ||||
|     """ Creates a Site Color Theme """ | ||||
|     """ Creates a site color theme database entry """ | ||||
|  | ||||
|     try: | ||||
|         data.save_to_db() | ||||
| @@ -69,7 +75,7 @@ async def create_theme(data: SiteTheme): | ||||
|  | ||||
| @router.post("/api/site-settings/themes/{theme_name}/update/", tags=["Themes"]) | ||||
| async def update_theme(theme_name: str, data: SiteTheme): | ||||
|     """ Returns basic site Settings """ | ||||
|     """ Update a theme database entry """ | ||||
|     try: | ||||
|         data.update_document() | ||||
|     except: | ||||
| @@ -82,7 +88,7 @@ async def update_theme(theme_name: str, data: SiteTheme): | ||||
|  | ||||
| @router.delete("/api/site-settings/themes/{theme_name}/delete/", tags=["Themes"]) | ||||
| async def delete_theme(theme_name: str): | ||||
|     """ Returns basic site Settings """ | ||||
|     """ Deletes theme from the database """ | ||||
|     try: | ||||
|         SiteTheme.delete_theme(theme_name) | ||||
|     except: | ||||
|   | ||||
| @@ -24,6 +24,18 @@ class SiteSettings(BaseModel): | ||||
|     name: str = "main" | ||||
|     webhooks: Webhooks | ||||
|  | ||||
|     class Config: | ||||
|         schema_extra = { | ||||
|             "example": { | ||||
|                 "name": "main", | ||||
|                 "webhooks": { | ||||
|                     "webhookTime": "00:00", | ||||
|                     "webhookURLs": ["https://mywebhookurl.com/webhook"], | ||||
|                     "enable": False, | ||||
|                 }, | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     @staticmethod | ||||
|     def _unpack_doc(document: SiteSettingsDocument): | ||||
|         document = json.loads(document.to_json()) | ||||
| @@ -65,6 +77,22 @@ class SiteTheme(BaseModel): | ||||
|     name: str | ||||
|     colors: Colors | ||||
|  | ||||
|     class Config: | ||||
|         schema_extra = { | ||||
|             "example": { | ||||
|                 "name": "default", | ||||
|                 "colors": { | ||||
|                     "primary": "#E58325", | ||||
|                     "accent": "#00457A", | ||||
|                     "secondary": "#973542", | ||||
|                     "success": "#5AB1BB", | ||||
|                     "info": "#4990BA", | ||||
|                     "warning": "#FF4081", | ||||
|                     "error": "#EF5350", | ||||
|                 }, | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_by_name(theme_name): | ||||
|         document = SiteThemeDocument.objects.get(name=theme_name) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user