mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-07-09 03:04:54 -04:00
refactor(backend): ♻️ Update tag naming and reorganized some routes. Still WIP
This commit is contained in:
parent
19fb6af050
commit
62836e5381
@ -8,8 +8,6 @@ from mealie.routes import backup_routes, debug_routes, migration_routes, router,
|
|||||||
from mealie.routes.about import about_router
|
from mealie.routes.about import about_router
|
||||||
from mealie.routes.mealplans import meal_plan_router
|
from mealie.routes.mealplans import meal_plan_router
|
||||||
from mealie.routes.media import media_router
|
from mealie.routes.media import media_router
|
||||||
from mealie.routes.recipe import recipe_router
|
|
||||||
from mealie.routes.shopping_list import shopping_list_router
|
|
||||||
from mealie.routes.site_settings import settings_router
|
from mealie.routes.site_settings import settings_router
|
||||||
from mealie.services.events import create_general_event
|
from mealie.services.events import create_general_event
|
||||||
from mealie.services.recipe.all_recipes import subscripte_to_recipe_events
|
from mealie.services.recipe.all_recipes import subscripte_to_recipe_events
|
||||||
@ -34,9 +32,7 @@ def start_scheduler():
|
|||||||
def api_routers():
|
def api_routers():
|
||||||
# Authentication
|
# Authentication
|
||||||
app.include_router(router)
|
app.include_router(router)
|
||||||
app.include_router(shopping_list_router)
|
|
||||||
# Recipes
|
# Recipes
|
||||||
app.include_router(recipe_router)
|
|
||||||
app.include_router(media_router)
|
app.include_router(media_router)
|
||||||
app.include_router(about_router)
|
app.include_router(about_router)
|
||||||
# Meal Routes
|
# Meal Routes
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from . import auth, groups, users
|
from . import auth, categories, groups, recipe, shopping_lists, tags, unit_and_foods, users
|
||||||
|
|
||||||
router = APIRouter(prefix="/api")
|
router = APIRouter(prefix="/api")
|
||||||
|
|
||||||
router.include_router(auth.router)
|
router.include_router(auth.router)
|
||||||
router.include_router(users.router)
|
router.include_router(users.router)
|
||||||
router.include_router(groups.router)
|
router.include_router(groups.router)
|
||||||
|
router.include_router(recipe.router)
|
||||||
|
router.include_router(unit_and_foods.router)
|
||||||
|
router.include_router(categories.router)
|
||||||
|
router.include_router(tags.router)
|
||||||
|
|
||||||
|
router.include_router(shopping_lists.router)
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from . import defaults, events
|
from . import defaults, events, notifications
|
||||||
|
|
||||||
about_router = APIRouter(prefix="/api/about")
|
about_router = APIRouter(prefix="/api/about")
|
||||||
|
|
||||||
about_router.include_router(events.router)
|
about_router.include_router(events.router, tags=["Events: CRUD"])
|
||||||
about_router.include_router(defaults.router)
|
about_router.include_router(notifications.router, tags=["Events: Notifications"])
|
||||||
|
about_router.include_router(defaults.router, tags=["Recipe: Defaults"])
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from mealie.schema.recipe import RecipeSettings
|
from mealie.schema.recipe import RecipeSettings
|
||||||
|
|
||||||
router = APIRouter(prefix="/recipes", tags=["About Recipes"])
|
router = APIRouter(prefix="/recipes")
|
||||||
|
|
||||||
|
|
||||||
@router.get("/defaults")
|
@router.get("/defaults")
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
from http.client import HTTPException
|
from fastapi import Depends
|
||||||
|
|
||||||
from fastapi import Depends, status
|
|
||||||
from mealie.core.root_logger import get_logger
|
from mealie.core.root_logger import get_logger
|
||||||
from mealie.db.database import db
|
from mealie.db.database import db
|
||||||
from mealie.db.db_setup import generate_session
|
from mealie.db.db_setup import generate_session
|
||||||
from mealie.routes.routers import AdminAPIRouter
|
from mealie.routes.routers import AdminAPIRouter
|
||||||
from mealie.schema.events import EventNotificationIn, EventNotificationOut, EventsOut, TestEvent
|
from mealie.schema.events import EventsOut
|
||||||
from mealie.services.events import test_notification
|
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
router = AdminAPIRouter(prefix="/events", tags=["App Events"])
|
router = AdminAPIRouter(prefix="/events")
|
||||||
|
|
||||||
logger = get_logger()
|
logger = get_logger()
|
||||||
|
|
||||||
@ -32,52 +29,3 @@ async def delete_events(session: Session = Depends(generate_session)):
|
|||||||
async def delete_event(id: int, session: Session = Depends(generate_session)):
|
async def delete_event(id: int, session: Session = Depends(generate_session)):
|
||||||
""" Delete event from the Database """
|
""" Delete event from the Database """
|
||||||
return db.events.delete(session, id)
|
return db.events.delete(session, id)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/notifications")
|
|
||||||
async def create_event_notification(
|
|
||||||
event_data: EventNotificationIn,
|
|
||||||
session: Session = Depends(generate_session),
|
|
||||||
):
|
|
||||||
""" Create event_notification in the Database """
|
|
||||||
|
|
||||||
return db.event_notifications.create(session, event_data)
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/notifications/test")
|
|
||||||
async def test_notification_route(
|
|
||||||
test_data: TestEvent,
|
|
||||||
session: Session = Depends(generate_session),
|
|
||||||
):
|
|
||||||
""" Create event_notification in the Database """
|
|
||||||
|
|
||||||
if test_data.id:
|
|
||||||
event_obj: EventNotificationIn = db.event_notifications.get(session, test_data.id)
|
|
||||||
test_data.test_url = event_obj.notification_url
|
|
||||||
|
|
||||||
try:
|
|
||||||
test_notification(test_data.test_url)
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(e)
|
|
||||||
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/notifications", response_model=list[EventNotificationOut])
|
|
||||||
async def get_all_event_notification(session: Session = Depends(generate_session)):
|
|
||||||
""" Get all event_notification from the Database """
|
|
||||||
# Get Item
|
|
||||||
return db.event_notifications.get_all(session, override_schema=EventNotificationOut)
|
|
||||||
|
|
||||||
|
|
||||||
@router.put("/notifications/{id}")
|
|
||||||
async def update_event_notification(id: int, session: Session = Depends(generate_session)):
|
|
||||||
""" Update event_notification in the Database """
|
|
||||||
# not yet implemented
|
|
||||||
raise HTTPException(status.HTTP_405_METHOD_NOT_ALLOWED)
|
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/notifications/{id}")
|
|
||||||
async def delete_event_notification(id: int, session: Session = Depends(generate_session)):
|
|
||||||
""" Delete event_notification from the Database """
|
|
||||||
# Delete Item
|
|
||||||
return db.event_notifications.delete(session, id)
|
|
||||||
|
63
mealie/routes/about/notifications.py
Normal file
63
mealie/routes/about/notifications.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
from http.client import HTTPException
|
||||||
|
|
||||||
|
from fastapi import Depends, status
|
||||||
|
from mealie.core.root_logger import get_logger
|
||||||
|
from mealie.db.database import db
|
||||||
|
from mealie.db.db_setup import generate_session
|
||||||
|
from mealie.routes.routers import AdminAPIRouter
|
||||||
|
from mealie.schema.events import EventNotificationIn, EventNotificationOut, TestEvent
|
||||||
|
from mealie.services.events import test_notification
|
||||||
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
|
router = AdminAPIRouter()
|
||||||
|
|
||||||
|
logger = get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/notifications")
|
||||||
|
async def create_event_notification(
|
||||||
|
event_data: EventNotificationIn,
|
||||||
|
session: Session = Depends(generate_session),
|
||||||
|
):
|
||||||
|
""" Create event_notification in the Database """
|
||||||
|
|
||||||
|
return db.event_notifications.create(session, event_data)
|
||||||
|
|
||||||
|
|
||||||
|
@router.post("/notifications/test")
|
||||||
|
async def test_notification_route(
|
||||||
|
test_data: TestEvent,
|
||||||
|
session: Session = Depends(generate_session),
|
||||||
|
):
|
||||||
|
""" Create event_notification in the Database """
|
||||||
|
|
||||||
|
if test_data.id:
|
||||||
|
event_obj: EventNotificationIn = db.event_notifications.get(session, test_data.id)
|
||||||
|
test_data.test_url = event_obj.notification_url
|
||||||
|
|
||||||
|
try:
|
||||||
|
test_notification(test_data.test_url)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(e)
|
||||||
|
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/notifications", response_model=list[EventNotificationOut])
|
||||||
|
async def get_all_event_notification(session: Session = Depends(generate_session)):
|
||||||
|
""" Get all event_notification from the Database """
|
||||||
|
# Get Item
|
||||||
|
return db.event_notifications.get_all(session, override_schema=EventNotificationOut)
|
||||||
|
|
||||||
|
|
||||||
|
@router.put("/notifications/{id}")
|
||||||
|
async def update_event_notification(id: int, session: Session = Depends(generate_session)):
|
||||||
|
""" Update event_notification in the Database """
|
||||||
|
# not yet implemented
|
||||||
|
raise HTTPException(status.HTTP_405_METHOD_NOT_ALLOWED)
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/notifications/{id}")
|
||||||
|
async def delete_event_notification(id: int, session: Session = Depends(generate_session)):
|
||||||
|
""" Delete event_notification from the Database """
|
||||||
|
# Delete Item
|
||||||
|
return db.event_notifications.delete(session, id)
|
11
mealie/routes/categories/__init__.py
Normal file
11
mealie/routes/categories/__init__.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from . import categories
|
||||||
|
|
||||||
|
prefix = "/categories"
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
router.include_router(categories.public_router, prefix=prefix, tags=["Categories: CRUD"])
|
||||||
|
router.include_router(categories.user_router, prefix=prefix, tags=["Categories: CRUD"])
|
||||||
|
router.include_router(categories.admin_router, prefix=prefix, tags=["Categories: CRUD"])
|
@ -6,9 +6,9 @@ from mealie.routes.routers import AdminAPIRouter, UserAPIRouter
|
|||||||
from mealie.schema.recipe import CategoryIn, RecipeCategoryResponse
|
from mealie.schema.recipe import CategoryIn, RecipeCategoryResponse
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
public_router = APIRouter(prefix="/api/categories", tags=["Recipe Categories"])
|
public_router = APIRouter()
|
||||||
user_router = UserAPIRouter(prefix="/api/categories", tags=["Recipe Categories"])
|
user_router = UserAPIRouter()
|
||||||
admin_router = AdminAPIRouter(prefix="/api/categories", tags=["Recipe Categories"])
|
admin_router = AdminAPIRouter()
|
||||||
|
|
||||||
|
|
||||||
@public_router.get("")
|
@public_router.get("")
|
@ -7,8 +7,8 @@ from mealie.schema.user import GroupBase, GroupInDB, UpdateGroup, UserInDB
|
|||||||
from mealie.services.events import create_group_event
|
from mealie.services.events import create_group_event
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
admin_router = AdminAPIRouter(prefix="/api/groups", tags=["Groups: CRUD"])
|
admin_router = AdminAPIRouter(prefix="/groups", tags=["Groups: CRUD"])
|
||||||
user_router = UserAPIRouter(prefix="/api/groups", tags=["Groups: CRUD"])
|
user_router = UserAPIRouter(prefix="/groups", tags=["Groups: CRUD"])
|
||||||
|
|
||||||
|
|
||||||
@user_router.get("/self", response_model=GroupInDB)
|
@user_router.get("/self", response_model=GroupInDB)
|
||||||
|
@ -2,6 +2,6 @@ from fastapi import APIRouter
|
|||||||
|
|
||||||
from . import recipe
|
from . import recipe
|
||||||
|
|
||||||
media_router = APIRouter(prefix="/api/media", tags=["Site Media"])
|
media_router = APIRouter(prefix="/api/media", tags=["Recipe: Images and Assets"])
|
||||||
|
|
||||||
media_router.include_router(recipe.router)
|
media_router.include_router(recipe.router)
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
from mealie.routes.recipe import all_recipe_routes, category_routes, comments, recipe_crud_routes, tag_routes
|
from mealie.routes.recipe import all_recipe_routes, comments, image_and_assets, recipe_crud_routes
|
||||||
|
|
||||||
recipe_router = APIRouter()
|
prefix = "/recipes"
|
||||||
|
|
||||||
recipe_router.include_router(all_recipe_routes.router)
|
router = APIRouter()
|
||||||
recipe_router.include_router(recipe_crud_routes.public_router)
|
|
||||||
recipe_router.include_router(recipe_crud_routes.user_router)
|
router.include_router(all_recipe_routes.router, prefix=prefix, tags=["Recipe: Query All"])
|
||||||
recipe_router.include_router(category_routes.public_router)
|
router.include_router(recipe_crud_routes.user_router, prefix=prefix, tags=["Recipe: CRUD"])
|
||||||
recipe_router.include_router(category_routes.user_router)
|
router.include_router(recipe_crud_routes.public_router, prefix=prefix, tags=["Recipe: CRUD"])
|
||||||
recipe_router.include_router(category_routes.admin_router)
|
router.include_router(image_and_assets.user_router, prefix=prefix, tags=["Recipe: Images and Assets"])
|
||||||
recipe_router.include_router(tag_routes.admin_router)
|
router.include_router(comments.router, prefix=prefix, tags=["Recipe: Comments"])
|
||||||
recipe_router.include_router(tag_routes.user_router)
|
|
||||||
recipe_router.include_router(tag_routes.public_router)
|
|
||||||
recipe_router.include_router(comments.router)
|
|
||||||
|
@ -4,10 +4,9 @@ from mealie.db.db_setup import generate_session
|
|||||||
from mealie.routes.deps import is_logged_in
|
from mealie.routes.deps import is_logged_in
|
||||||
from mealie.schema.recipe import RecipeSummary
|
from mealie.schema.recipe import RecipeSummary
|
||||||
from mealie.services.recipe.all_recipes import get_all_recipes_public, get_all_recipes_user
|
from mealie.services.recipe.all_recipes import get_all_recipes_public, get_all_recipes_user
|
||||||
from slugify import slugify
|
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
router = APIRouter(tags=["Query All Recipes"])
|
router = APIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.get("/api/recipes")
|
@router.get("/api/recipes")
|
||||||
@ -39,23 +38,3 @@ async def get_untagged_recipes(count: bool = False, session: Session = Depends(g
|
|||||||
@router.get("/api/recipes/summary/uncategorized", response_model=list[RecipeSummary])
|
@router.get("/api/recipes/summary/uncategorized", response_model=list[RecipeSummary])
|
||||||
async def get_uncategorized_recipes(count: bool = False, session: Session = Depends(generate_session)):
|
async def get_uncategorized_recipes(count: bool = False, session: Session = Depends(generate_session)):
|
||||||
return db.recipes.count_uncategorized(session, count=count, override_schema=RecipeSummary)
|
return db.recipes.count_uncategorized(session, count=count, override_schema=RecipeSummary)
|
||||||
|
|
||||||
|
|
||||||
@router.post("/api/recipes/category", deprecated=True)
|
|
||||||
def filter_by_category(categories: list, session: Session = Depends(generate_session)):
|
|
||||||
""" pass a list of categories and get a list of recipes associated with those categories """
|
|
||||||
# ! This should be refactored into a single database call, but I couldn't figure it out
|
|
||||||
in_category = [db.categories.get(session, slugify(cat), limit=1) for cat in categories]
|
|
||||||
in_category = [cat.recipes for cat in in_category if cat]
|
|
||||||
in_category = [item for sublist in in_category for item in sublist]
|
|
||||||
return in_category
|
|
||||||
|
|
||||||
|
|
||||||
@router.post("/api/recipes/tag", deprecated=True)
|
|
||||||
async def filter_by_tags(tags: list, session: Session = Depends(generate_session)):
|
|
||||||
""" pass a list of tags and get a list of recipes associated with those tags"""
|
|
||||||
# ! This should be refactored into a single database call, but I couldn't figure it out
|
|
||||||
in_tags = [db.tags.get(session, slugify(tag), limit=1) for tag in tags]
|
|
||||||
in_tags = [tag.recipes for tag in in_tags]
|
|
||||||
in_tags = [item for sublist in in_tags for item in sublist]
|
|
||||||
return in_tags
|
|
||||||
|
@ -9,10 +9,10 @@ from mealie.schema.recipe import CommentIn, CommentOut, CommentSaveToDB
|
|||||||
from mealie.schema.user import UserInDB
|
from mealie.schema.user import UserInDB
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
router = UserAPIRouter(prefix="/api", tags=["Recipe Comments"])
|
router = UserAPIRouter()
|
||||||
|
|
||||||
|
|
||||||
@router.post("/recipes/{slug}/comments")
|
@router.post("/{slug}/comments")
|
||||||
async def create_comment(
|
async def create_comment(
|
||||||
slug: str,
|
slug: str,
|
||||||
new_comment: CommentIn,
|
new_comment: CommentIn,
|
||||||
@ -25,7 +25,7 @@ async def create_comment(
|
|||||||
return db.comments.create(session, new_comment)
|
return db.comments.create(session, new_comment)
|
||||||
|
|
||||||
|
|
||||||
@router.put("/recipes/{slug}/comments/{id}")
|
@router.put("/{slug}/comments/{id}")
|
||||||
async def update_comment(
|
async def update_comment(
|
||||||
id: int,
|
id: int,
|
||||||
new_comment: CommentIn,
|
new_comment: CommentIn,
|
||||||
@ -41,7 +41,7 @@ async def update_comment(
|
|||||||
return db.comments.update(session, id, new_comment)
|
return db.comments.update(session, id, new_comment)
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/recipes/{slug}/comments/{id}")
|
@router.delete("/{slug}/comments/{id}")
|
||||||
async def delete_comment(
|
async def delete_comment(
|
||||||
id: int, session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)
|
id: int, session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)
|
||||||
):
|
):
|
||||||
|
63
mealie/routes/recipe/image_and_assets.py
Normal file
63
mealie/routes/recipe/image_and_assets.py
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
from shutil import copyfileobj
|
||||||
|
|
||||||
|
from fastapi import Depends, File, Form, HTTPException, status
|
||||||
|
from fastapi.datastructures import UploadFile
|
||||||
|
from mealie.db.database import db
|
||||||
|
from mealie.db.db_setup import generate_session
|
||||||
|
from mealie.routes.routers import UserAPIRouter
|
||||||
|
from mealie.schema.recipe import Recipe, RecipeAsset, RecipeURLIn
|
||||||
|
from mealie.services.image.image import scrape_image, write_image
|
||||||
|
from slugify import slugify
|
||||||
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
|
user_router = UserAPIRouter()
|
||||||
|
|
||||||
|
|
||||||
|
@user_router.post("/{recipe_slug}/image")
|
||||||
|
def scrape_image_url(
|
||||||
|
recipe_slug: str,
|
||||||
|
url: RecipeURLIn,
|
||||||
|
):
|
||||||
|
""" Removes an existing image and replaces it with the incoming file. """
|
||||||
|
|
||||||
|
scrape_image(url.url, recipe_slug)
|
||||||
|
|
||||||
|
|
||||||
|
@user_router.put("/{recipe_slug}/image")
|
||||||
|
def update_recipe_image(
|
||||||
|
recipe_slug: str,
|
||||||
|
image: bytes = File(...),
|
||||||
|
extension: str = Form(...),
|
||||||
|
session: Session = Depends(generate_session),
|
||||||
|
):
|
||||||
|
""" Removes an existing image and replaces it with the incoming file. """
|
||||||
|
write_image(recipe_slug, image, extension)
|
||||||
|
new_version = db.recipes.update_image(session, recipe_slug, extension)
|
||||||
|
|
||||||
|
return {"image": new_version}
|
||||||
|
|
||||||
|
|
||||||
|
@user_router.post("/{recipe_slug}/assets", response_model=RecipeAsset)
|
||||||
|
def upload_recipe_asset(
|
||||||
|
recipe_slug: str,
|
||||||
|
name: str = Form(...),
|
||||||
|
icon: str = Form(...),
|
||||||
|
extension: str = Form(...),
|
||||||
|
file: UploadFile = File(...),
|
||||||
|
session: Session = Depends(generate_session),
|
||||||
|
):
|
||||||
|
""" Upload a file to store as a recipe asset """
|
||||||
|
file_name = slugify(name) + "." + extension
|
||||||
|
asset_in = RecipeAsset(name=name, icon=icon, file_name=file_name)
|
||||||
|
dest = Recipe(slug=recipe_slug).asset_dir.joinpath(file_name)
|
||||||
|
|
||||||
|
with dest.open("wb") as buffer:
|
||||||
|
copyfileobj(file.file, buffer)
|
||||||
|
|
||||||
|
if not dest.is_file():
|
||||||
|
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)
|
||||||
|
|
||||||
|
recipe: Recipe = db.recipes.get(session, recipe_slug)
|
||||||
|
recipe.assets.append(asset_in)
|
||||||
|
db.recipes.update(session, recipe_slug, recipe.dict())
|
||||||
|
return asset_in
|
@ -1,9 +1,8 @@
|
|||||||
import json
|
import json
|
||||||
import shutil
|
import shutil
|
||||||
from shutil import copyfileobj
|
|
||||||
from zipfile import ZipFile
|
from zipfile import ZipFile
|
||||||
|
|
||||||
from fastapi import APIRouter, BackgroundTasks, Depends, File, Form, HTTPException, status
|
from fastapi import APIRouter, BackgroundTasks, Depends, File, HTTPException, status
|
||||||
from fastapi.datastructures import UploadFile
|
from fastapi.datastructures import UploadFile
|
||||||
from mealie.core.config import settings
|
from mealie.core.config import settings
|
||||||
from mealie.core.root_logger import get_logger
|
from mealie.core.root_logger import get_logger
|
||||||
@ -11,20 +10,19 @@ from mealie.db.database import db
|
|||||||
from mealie.db.db_setup import generate_session
|
from mealie.db.db_setup import generate_session
|
||||||
from mealie.routes.deps import get_current_user, is_logged_in, temporary_zip_path
|
from mealie.routes.deps import get_current_user, is_logged_in, temporary_zip_path
|
||||||
from mealie.routes.routers import UserAPIRouter
|
from mealie.routes.routers import UserAPIRouter
|
||||||
from mealie.schema.recipe import Recipe, RecipeAsset, RecipeImageTypes, RecipeURLIn
|
from mealie.schema.recipe import Recipe, RecipeImageTypes, RecipeURLIn
|
||||||
from mealie.schema.recipe.recipe import CreateRecipe
|
from mealie.schema.recipe.recipe import CreateRecipe
|
||||||
from mealie.schema.user import UserInDB
|
from mealie.schema.user import UserInDB
|
||||||
from mealie.services.events import create_recipe_event
|
from mealie.services.events import create_recipe_event
|
||||||
from mealie.services.image.image import scrape_image, write_image
|
from mealie.services.image.image import write_image
|
||||||
from mealie.services.recipe.media import check_assets, delete_assets
|
from mealie.services.recipe.media import check_assets, delete_assets
|
||||||
from mealie.services.scraper.scraper import create_from_url
|
from mealie.services.scraper.scraper import create_from_url
|
||||||
from scrape_schema_recipe import scrape_url
|
from scrape_schema_recipe import scrape_url
|
||||||
from slugify import slugify
|
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
from starlette.responses import FileResponse
|
from starlette.responses import FileResponse
|
||||||
|
|
||||||
user_router = UserAPIRouter(prefix="/api/recipes", tags=["Recipe CRUD"])
|
user_router = UserAPIRouter()
|
||||||
public_router = APIRouter(prefix="/api/recipes", tags=["Recipe CRUD"])
|
public_router = APIRouter()
|
||||||
logger = get_logger()
|
logger = get_logger()
|
||||||
|
|
||||||
|
|
||||||
@ -52,27 +50,6 @@ def create_from_name(
|
|||||||
return recipe.slug
|
return recipe.slug
|
||||||
|
|
||||||
|
|
||||||
@user_router.post("/create", status_code=201, response_model=str)
|
|
||||||
def create_from_json(
|
|
||||||
background_tasks: BackgroundTasks,
|
|
||||||
data: Recipe,
|
|
||||||
session: Session = Depends(generate_session),
|
|
||||||
current_user=Depends(get_current_user),
|
|
||||||
) -> str:
|
|
||||||
""" Takes in a JSON string and loads data into the database as a new entry"""
|
|
||||||
recipe: Recipe = db.recipes.create(session, data.dict())
|
|
||||||
|
|
||||||
background_tasks.add_task(
|
|
||||||
create_recipe_event,
|
|
||||||
"Recipe Created (URL)",
|
|
||||||
f"'{recipe.name}' by {current_user.full_name} \n {settings.BASE_URL}/recipe/{recipe.slug}",
|
|
||||||
session=session,
|
|
||||||
attachment=recipe.image_dir.joinpath("min-original.webp"),
|
|
||||||
)
|
|
||||||
|
|
||||||
return recipe.slug
|
|
||||||
|
|
||||||
|
|
||||||
@user_router.post("/test-scrape-url")
|
@user_router.post("/test-scrape-url")
|
||||||
def test_parse_recipe_url(url: RecipeURLIn):
|
def test_parse_recipe_url(url: RecipeURLIn):
|
||||||
return scrape_url(url.url)
|
return scrape_url(url.url)
|
||||||
@ -217,53 +194,3 @@ def delete_recipe(
|
|||||||
)
|
)
|
||||||
|
|
||||||
return recipe
|
return recipe
|
||||||
|
|
||||||
|
|
||||||
@user_router.put("/{recipe_slug}/image")
|
|
||||||
def update_recipe_image(
|
|
||||||
recipe_slug: str,
|
|
||||||
image: bytes = File(...),
|
|
||||||
extension: str = Form(...),
|
|
||||||
session: Session = Depends(generate_session),
|
|
||||||
):
|
|
||||||
""" Removes an existing image and replaces it with the incoming file. """
|
|
||||||
write_image(recipe_slug, image, extension)
|
|
||||||
new_version = db.recipes.update_image(session, recipe_slug, extension)
|
|
||||||
|
|
||||||
return {"image": new_version}
|
|
||||||
|
|
||||||
|
|
||||||
@user_router.post("/{recipe_slug}/image")
|
|
||||||
def scrape_image_url(
|
|
||||||
recipe_slug: str,
|
|
||||||
url: RecipeURLIn,
|
|
||||||
):
|
|
||||||
""" Removes an existing image and replaces it with the incoming file. """
|
|
||||||
|
|
||||||
scrape_image(url.url, recipe_slug)
|
|
||||||
|
|
||||||
|
|
||||||
@user_router.post("/{recipe_slug}/assets", response_model=RecipeAsset)
|
|
||||||
def upload_recipe_asset(
|
|
||||||
recipe_slug: str,
|
|
||||||
name: str = Form(...),
|
|
||||||
icon: str = Form(...),
|
|
||||||
extension: str = Form(...),
|
|
||||||
file: UploadFile = File(...),
|
|
||||||
session: Session = Depends(generate_session),
|
|
||||||
):
|
|
||||||
""" Upload a file to store as a recipe asset """
|
|
||||||
file_name = slugify(name) + "." + extension
|
|
||||||
asset_in = RecipeAsset(name=name, icon=icon, file_name=file_name)
|
|
||||||
dest = Recipe(slug=recipe_slug).asset_dir.joinpath(file_name)
|
|
||||||
|
|
||||||
with dest.open("wb") as buffer:
|
|
||||||
copyfileobj(file.file, buffer)
|
|
||||||
|
|
||||||
if not dest.is_file():
|
|
||||||
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)
|
|
||||||
|
|
||||||
recipe: Recipe = db.recipes.get(session, recipe_slug)
|
|
||||||
recipe.assets.append(asset_in)
|
|
||||||
db.recipes.update(session, recipe_slug, recipe.dict())
|
|
||||||
return asset_in
|
|
||||||
|
@ -7,10 +7,10 @@ from mealie.schema.meal_plan import ShoppingListIn, ShoppingListOut
|
|||||||
from mealie.schema.user import UserInDB
|
from mealie.schema.user import UserInDB
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
shopping_list_router = UserAPIRouter(prefix="/api/shopping-lists", tags=["Shopping Lists"])
|
router = UserAPIRouter(prefix="/shopping-lists", tags=["Shopping Lists: CRUD"])
|
||||||
|
|
||||||
|
|
||||||
@shopping_list_router.post("", response_model=ShoppingListOut)
|
@router.post("", response_model=ShoppingListOut)
|
||||||
async def create_shopping_list(
|
async def create_shopping_list(
|
||||||
list_in: ShoppingListIn,
|
list_in: ShoppingListIn,
|
||||||
current_user: UserInDB = Depends(get_current_user),
|
current_user: UserInDB = Depends(get_current_user),
|
||||||
@ -23,19 +23,19 @@ async def create_shopping_list(
|
|||||||
return db.shopping_lists.create(session, list_in)
|
return db.shopping_lists.create(session, list_in)
|
||||||
|
|
||||||
|
|
||||||
@shopping_list_router.get("/{id}", response_model=ShoppingListOut)
|
@router.get("/{id}", response_model=ShoppingListOut)
|
||||||
async def get_shopping_list(id: int, session: Session = Depends(generate_session)):
|
async def get_shopping_list(id: int, session: Session = Depends(generate_session)):
|
||||||
""" Get Shopping List from the Database """
|
""" Get Shopping List from the Database """
|
||||||
return db.shopping_lists.get(session, id)
|
return db.shopping_lists.get(session, id)
|
||||||
|
|
||||||
|
|
||||||
@shopping_list_router.put("/{id}", response_model=ShoppingListOut)
|
@router.put("/{id}", response_model=ShoppingListOut)
|
||||||
async def update_shopping_list(id: int, new_data: ShoppingListIn, session: Session = Depends(generate_session)):
|
async def update_shopping_list(id: int, new_data: ShoppingListIn, session: Session = Depends(generate_session)):
|
||||||
""" Update Shopping List in the Database """
|
""" Update Shopping List in the Database """
|
||||||
return db.shopping_lists.update(session, id, new_data)
|
return db.shopping_lists.update(session, id, new_data)
|
||||||
|
|
||||||
|
|
||||||
@shopping_list_router.delete("/{id}")
|
@router.delete("/{id}")
|
||||||
async def delete_shopping_list(id: int, session: Session = Depends(generate_session)):
|
async def delete_shopping_list(id: int, session: Session = Depends(generate_session)):
|
||||||
""" Delete Shopping List from the Database """
|
""" Delete Shopping List from the Database """
|
||||||
return db.shopping_lists.delete(session, id)
|
return db.shopping_lists.delete(session, id)
|
11
mealie/routes/tags/__init__.py
Normal file
11
mealie/routes/tags/__init__.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from fastapi import APIRouter
|
||||||
|
|
||||||
|
from . import tags
|
||||||
|
|
||||||
|
prefix = "/tags"
|
||||||
|
|
||||||
|
router = APIRouter()
|
||||||
|
|
||||||
|
router.include_router(tags.public_router, prefix=prefix, tags=["Tags: CRUD"])
|
||||||
|
router.include_router(tags.user_router, prefix=prefix, tags=["Tags: CRUD"])
|
||||||
|
router.include_router(tags.admin_router, prefix=prefix, tags=["Tags: CRUD"])
|
@ -6,9 +6,9 @@ from mealie.routes.routers import AdminAPIRouter, UserAPIRouter
|
|||||||
from mealie.schema.recipe import RecipeTagResponse, TagIn
|
from mealie.schema.recipe import RecipeTagResponse, TagIn
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
public_router = APIRouter(prefix="/api/tags", tags=["Recipe Tags"])
|
public_router = APIRouter()
|
||||||
user_router = UserAPIRouter(prefix="/api/tags", tags=["Recipe Tags"])
|
user_router = UserAPIRouter()
|
||||||
admin_router = AdminAPIRouter(prefix="/api/tags", tags=["Recipe Tags"])
|
admin_router = AdminAPIRouter()
|
||||||
|
|
||||||
|
|
||||||
@public_router.get("")
|
@public_router.get("")
|
@ -2,7 +2,7 @@ from fastapi import APIRouter
|
|||||||
|
|
||||||
from . import food_routes, unit_routes
|
from . import food_routes, unit_routes
|
||||||
|
|
||||||
units_and_foods_router = APIRouter(tags=["Food and Units"])
|
router = APIRouter()
|
||||||
|
|
||||||
units_and_foods_router.include_router(food_routes.router)
|
router.include_router(food_routes.router, prefix="/foods", tags=["Recipes: Foods"])
|
||||||
units_and_foods_router.include_router(unit_routes.router)
|
router.include_router(unit_routes.router, prefix="/units", tags=["Recipes: Units"])
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from mealie.routes.routers import UserAPIRouter
|
|
||||||
from mealie.core.root_logger import get_logger
|
from mealie.core.root_logger import get_logger
|
||||||
|
from mealie.routes.routers import UserAPIRouter
|
||||||
|
|
||||||
router = UserAPIRouter(prefix="/api/foods")
|
router = UserAPIRouter()
|
||||||
logger = get_logger()
|
logger = get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from mealie.routes.routers import UserAPIRouter
|
|
||||||
from mealie.core.root_logger import get_logger
|
from mealie.core.root_logger import get_logger
|
||||||
|
from mealie.routes.routers import UserAPIRouter
|
||||||
|
|
||||||
router = UserAPIRouter(prefix="/api/units")
|
router = UserAPIRouter()
|
||||||
logger = get_logger()
|
logger = get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,8 +6,7 @@ from mealie.db.database import db
|
|||||||
from mealie.db.db_setup import generate_session
|
from mealie.db.db_setup import generate_session
|
||||||
from mealie.routes.deps import get_admin_user
|
from mealie.routes.deps import get_admin_user
|
||||||
from mealie.routes.routers import AdminAPIRouter
|
from mealie.routes.routers import AdminAPIRouter
|
||||||
from mealie.schema.user import (SignUpIn, SignUpOut, SignUpToken, UserIn,
|
from mealie.schema.user import SignUpIn, SignUpOut, SignUpToken, UserIn, UserInDB
|
||||||
UserInDB)
|
|
||||||
from mealie.services.events import create_user_event
|
from mealie.services.events import create_user_event
|
||||||
from sqlalchemy.orm.session import Session
|
from sqlalchemy.orm.session import Session
|
||||||
|
|
||||||
|
@ -19,22 +19,6 @@ def test_create_by_url(api_client: TestClient, api_routes: AppRoutes, recipe_dat
|
|||||||
assert json.loads(response.text) == recipe_data.expected_slug
|
assert json.loads(response.text) == recipe_data.expected_slug
|
||||||
|
|
||||||
|
|
||||||
def test_create_by_json(api_client: TestClient, api_routes: AppRoutes, user_token, raw_recipe):
|
|
||||||
recipe_url = api_routes.recipes_recipe_slug("banana-bread")
|
|
||||||
api_client.delete(recipe_url, headers=user_token)
|
|
||||||
response = api_client.post(api_routes.recipes_create, json=raw_recipe, headers=user_token)
|
|
||||||
|
|
||||||
assert response.status_code == 201
|
|
||||||
assert json.loads(response.text) == "banana-bread"
|
|
||||||
|
|
||||||
|
|
||||||
def test_create_no_image(api_client: TestClient, api_routes: AppRoutes, user_token, raw_recipe_no_image):
|
|
||||||
response = api_client.post(api_routes.recipes_create, json=raw_recipe_no_image, headers=user_token)
|
|
||||||
|
|
||||||
assert response.status_code == 201
|
|
||||||
assert json.loads(response.text) == "banana-bread-no-image"
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("recipe_data", recipe_test_data)
|
@pytest.mark.parametrize("recipe_data", recipe_test_data)
|
||||||
def test_read_update(api_client: TestClient, api_routes: AppRoutes, recipe_data: RecipeSiteTestCase, user_token):
|
def test_read_update(api_client: TestClient, api_routes: AppRoutes, recipe_data: RecipeSiteTestCase, user_token):
|
||||||
recipe_url = api_routes.recipes_recipe_slug(recipe_data.expected_slug)
|
recipe_url = api_routes.recipes_recipe_slug(recipe_data.expected_slug)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user