refactor(backend): ♻️ cleanup HTTP service classes and remove database singleton (#687)

* refactor(backend): ♻️ cleanup duplicate code in http services

* refactor(backend): ♻️ refactor database away from singleton design

removed the database single and instead injected the session into a new Database class that is created during each request life-cycle. Now sessions no longer need to be passed into each method on the database

All tests pass, but there are likely some hidden breaking changes that were not discovered.

* fix venv

* disable venv cache

* fix install script

* bump poetry version

* postgres fixes

* revert install

* fix db initialization for postgres

* add postgres to docker

* refactor(backend): ♻️ cleanup unused and duplicate code in http services

* refactor(backend): remove sessions from arguments

* refactor(backend): ♻️ convert units and ingredients to use http service class

* test(backend):  add unit and food tests

* lint

* update tags

* re-enable cache

* fix missing fraction in db

* fix lint

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden
2021-09-19 15:31:34 -08:00
committed by GitHub
parent c0e3f04c23
commit 476aefeeb0
68 changed files with 1131 additions and 1084 deletions

View File

@@ -2,7 +2,7 @@ from fastapi import Depends
from sqlalchemy.orm.session import Session
from mealie.core.root_logger import get_logger
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import AdminAPIRouter
from mealie.schema.events import EventsOut
@@ -15,18 +15,20 @@ logger = get_logger()
@router.get("", response_model=EventsOut)
async def get_events(session: Session = Depends(generate_session)):
""" Get event from the Database """
# Get Item
return EventsOut(total=db.events.count_all(session), events=db.events.get_all(session, order_by="time_stamp"))
db = get_database(session)
return EventsOut(total=db.events.count_all(), events=db.events.get_all(order_by="time_stamp"))
@router.delete("")
async def delete_events(session: Session = Depends(generate_session)):
""" Get event from the Database """
# Get Item
db = get_database(session)
return db.events.delete_all(session)
@router.delete("/{id}")
async def delete_event(id: int, session: Session = Depends(generate_session)):
""" Delete event from the Database """
db = get_database(session)
return db.events.delete(session, id)

View File

@@ -4,7 +4,7 @@ from fastapi import Depends, status
from sqlalchemy.orm.session import Session
from mealie.core.root_logger import get_logger
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import AdminAPIRouter
from mealie.schema.events import EventNotificationIn, EventNotificationOut, TestEvent
@@ -21,8 +21,9 @@ async def create_event_notification(
session: Session = Depends(generate_session),
):
""" Create event_notification in the Database """
db = get_database(session)
return db.event_notifications.create(session, event_data)
return db.event_notifications.create(event_data)
@router.post("/notifications/test")
@@ -31,9 +32,10 @@ async def test_notification_route(
session: Session = Depends(generate_session),
):
""" Create event_notification in the Database """
db = get_database(session)
if test_data.id:
event_obj: EventNotificationIn = db.event_notifications.get(session, test_data.id)
event_obj: EventNotificationIn = db.event_notifications.get(test_data.id)
test_data.test_url = event_obj.notification_url
try:
@@ -46,8 +48,8 @@ async def test_notification_route(
@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)
db = get_database(session)
return db.event_notifications.get_all(override_schema=EventNotificationOut)
@router.put("/notifications/{id}")
@@ -61,4 +63,5 @@ async def update_event_notification(id: int, session: Session = Depends(generate
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)
db = get_database(session)
return db.event_notifications.delete(id)

View File

@@ -28,11 +28,11 @@ async def get_app_info():
@router.get("/statistics", response_model=AppStatistics)
async def get_app_statistics(session: Session = Depends(generate_session)):
db = get_database()
db = get_database(session)
return AppStatistics(
total_recipes=db.recipes.count_all(session),
uncategorized_recipes=db.recipes.count_uncategorized(session),
untagged_recipes=db.recipes.count_untagged(session),
total_users=db.users.count_all(session),
total_groups=db.groups.count_all(session),
total_recipes=db.recipes.count_all(),
uncategorized_recipes=db.recipes.count_uncategorized(),
untagged_recipes=db.recipes.count_untagged(),
total_users=db.users.count_all(),
total_groups=db.groups.count_all(),
)

View File

@@ -2,7 +2,7 @@ from fastapi import BackgroundTasks, Depends, HTTPException, status
from sqlalchemy.orm.session import Session
from mealie.core.dependencies import get_current_user
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import AdminAPIRouter
from mealie.schema.user import GroupBase, GroupInDB, PrivateUser, UpdateGroup
@@ -14,8 +14,9 @@ router = AdminAPIRouter(prefix="/groups")
@router.get("", response_model=list[GroupInDB])
async def get_all_groups(session: Session = Depends(generate_session)):
""" Returns a list of all groups in the database """
db = get_database(session)
return db.groups.get_all(session)
return db.groups.get_all()
@router.post("", status_code=status.HTTP_201_CREATED, response_model=GroupInDB)
@@ -25,9 +26,10 @@ async def create_group(
session: Session = Depends(generate_session),
):
""" Creates a Group in the Database """
db = get_database(session)
try:
new_group = db.groups.create(session, group_data.dict())
new_group = db.groups.create(group_data.dict())
background_tasks.add_task(create_group_event, "Group Created", f"'{group_data.name}' created", session)
return new_group
except Exception:
@@ -37,7 +39,8 @@ async def create_group(
@router.put("/{id}")
async def update_group_data(id: int, group_data: UpdateGroup, session: Session = Depends(generate_session)):
""" Updates a User Group """
db.groups.update(session, id, group_data.dict())
db = get_database(session)
db.groups.update(id, group_data.dict())
@router.delete("/{id}")
@@ -48,11 +51,12 @@ async def delete_user_group(
session: Session = Depends(generate_session),
):
""" Removes a user group from the database """
db = get_database(session)
if id == 1:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="DEFAULT_GROUP")
group: GroupInDB = db.groups.get(session, id)
group: GroupInDB = db.groups.get(id)
if not group:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="GROUP_NOT_FOUND")
@@ -64,4 +68,4 @@ async def delete_user_group(
create_group_event, "Group Deleted", f"'{group.name}' deleted by {current_user.full_name}", session
)
db.groups.delete(session, id)
db.groups.delete(id)

View File

@@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm.session import Session
from mealie.core.dependencies import is_logged_in
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import AdminAPIRouter, UserAPIRouter
from mealie.schema.recipe import CategoryIn, RecipeCategoryResponse
@@ -15,13 +15,15 @@ admin_router = AdminAPIRouter()
@public_router.get("")
async def get_all_recipe_categories(session: Session = Depends(generate_session)):
""" Returns a list of available categories in the database """
return db.categories.get_all_limit_columns(session, ["slug", "name"])
db = get_database(session)
return db.categories.get_all_limit_columns(fields=["slug", "name"])
@public_router.get("/empty")
def get_empty_categories(session: Session = Depends(generate_session)):
""" Returns a list of categories that do not contain any recipes"""
return db.categories.get_empty(session)
db = get_database(session)
return db.categories.get_empty()
@public_router.get("/{category}", response_model=RecipeCategoryResponse)
@@ -29,8 +31,9 @@ def get_all_recipes_by_category(
category: str, session: Session = Depends(generate_session), is_user: bool = Depends(is_logged_in)
):
""" Returns a list of recipes associated with the provided category. """
db = get_database(session)
category_obj = db.categories.get(session, category)
category_obj = db.categories.get(category)
category_obj = RecipeCategoryResponse.from_orm(category_obj)
if not is_user:
@@ -42,9 +45,10 @@ def get_all_recipes_by_category(
@user_router.post("")
async def create_recipe_category(category: CategoryIn, session: Session = Depends(generate_session)):
""" Creates a Category in the database """
db = get_database(session)
try:
return db.categories.create(session, category.dict())
return db.categories.create(category.dict())
except Exception:
raise HTTPException(status.HTTP_400_BAD_REQUEST)
@@ -52,9 +56,10 @@ async def create_recipe_category(category: CategoryIn, session: Session = Depend
@admin_router.put("/{category}", response_model=RecipeCategoryResponse)
async def update_recipe_category(category: str, new_category: CategoryIn, session: Session = Depends(generate_session)):
""" Updates an existing Tag in the database """
db = get_database(session)
try:
return db.categories.update(session, category, new_category.dict())
return db.categories.update(category, new_category.dict())
except Exception:
raise HTTPException(status.HTTP_400_BAD_REQUEST)
@@ -66,8 +71,9 @@ async def delete_recipe_category(category: str, session: Session = Depends(gener
category does not impact a recipe. The category will be removed
from any recipes that contain it
"""
db = get_database(session)
try:
db.categories.delete(session, category)
db.categories.delete(category)
except Exception:
raise HTTPException(status.HTTP_400_BAD_REQUEST)

View File

@@ -7,12 +7,10 @@ router = APIRouter()
@router.get("", response_model=list[ReadInviteToken])
def get_invite_tokens(g_service: GroupSelfService = Depends(GroupSelfService.write_existing)):
def get_invite_tokens(g_service: GroupSelfService = Depends(GroupSelfService.private)):
return g_service.get_invite_tokens()
@router.post("", response_model=ReadInviteToken, status_code=status.HTTP_201_CREATED)
def create_invite_token(
uses: CreateInviteToken, g_service: GroupSelfService = Depends(GroupSelfService.write_existing)
):
def create_invite_token(uses: CreateInviteToken, g_service: GroupSelfService = Depends(GroupSelfService.private)):
return g_service.create_invite_token(uses.uses)

View File

@@ -1,10 +0,0 @@
from fastapi import APIRouter
from . import crud, helpers, mealplans
meal_plan_router = APIRouter()
meal_plan_router.include_router(crud.router)
meal_plan_router.include_router(crud.public_router)
meal_plan_router.include_router(helpers.router)
meal_plan_router.include_router(mealplans.router)

View File

@@ -1,126 +0,0 @@
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status
from sqlalchemy.orm.session import Session
from starlette.responses import FileResponse
from mealie.core.dependencies import get_current_user
from mealie.db.database import db
from mealie.db.db_setup import generate_session
from mealie.routes.routers import UserAPIRouter
from mealie.schema.meal_plan import MealPlanIn, MealPlanOut
from mealie.schema.user import GroupInDB, PrivateUser
from mealie.services.events import create_group_event
from mealie.services.image import image
from mealie.services.meal_services import get_todays_meal, set_mealplan_dates
router = UserAPIRouter(prefix="/api/meal-plans", tags=["Meal Plan"])
public_router = APIRouter(prefix="/api/meal-plans", tags=["Meal Plan"])
@router.get("/all", response_model=list[MealPlanOut])
def get_all_meals(
current_user: PrivateUser = Depends(get_current_user),
session: Session = Depends(generate_session),
):
""" Returns a list of all available Meal Plan """
return db.groups.get_meals(session, current_user.group)
@router.get("/this-week", response_model=MealPlanOut)
def get_this_week(session: Session = Depends(generate_session), current_user: PrivateUser = Depends(get_current_user)):
""" Returns the meal plan data for this week """
plans = db.groups.get_meals(session, current_user.group)
if plans:
return plans[0]
@router.get("/today", tags=["Meal Plan"])
def get_today(session: Session = Depends(generate_session), current_user: PrivateUser = Depends(get_current_user)):
"""
Returns the recipe slug for the meal scheduled for today.
If no meal is scheduled nothing is returned
"""
group_in_db: GroupInDB = db.groups.get(session, current_user.group, "name")
recipe = get_todays_meal(session, group_in_db)
if recipe:
return recipe
@public_router.get("/today/image", tags=["Meal Plan"])
def get_todays_image(session: Session = Depends(generate_session), group_name: str = "Home"):
"""
Returns the image for todays meal-plan.
"""
group_in_db: GroupInDB = db.groups.get(session, group_name, "name")
recipe = get_todays_meal(session, group_in_db)
recipe_image = recipe.image_dir.joinpath(image.ImageOptions.ORIGINAL_IMAGE)
if not recipe and not recipe_image.exists():
raise HTTPException(status.HTTP_404_NOT_FOUND)
return FileResponse(recipe_image)
@router.get("/{id}", response_model=MealPlanOut)
def get_meal_plan(
id,
session: Session = Depends(generate_session),
):
""" Returns a single Meal Plan from the Database """
return db.meals.get(session, id)
@router.post("/create", status_code=status.HTTP_201_CREATED)
def create_meal_plan(
background_tasks: BackgroundTasks,
data: MealPlanIn,
session: Session = Depends(generate_session),
current_user: PrivateUser = Depends(get_current_user),
):
""" Creates a meal plan database entry """
set_mealplan_dates(data)
background_tasks.add_task(
create_group_event, "Meal Plan Created", f"Mealplan Created for '{current_user.group}'", session=session
)
return db.meals.create(session, data.dict())
@router.put("/{plan_id}")
def update_meal_plan(
background_tasks: BackgroundTasks,
plan_id: str,
meal_plan: MealPlanIn,
session: Session = Depends(generate_session),
current_user: PrivateUser = Depends(get_current_user),
):
""" Updates a meal plan based off ID """
set_mealplan_dates(meal_plan)
processed_plan = MealPlanOut(id=plan_id, **meal_plan.dict())
try:
db.meals.update(session, plan_id, processed_plan.dict())
background_tasks.add_task(
create_group_event, "Meal Plan Updated", f"Mealplan Updated for '{current_user.group}'", session=session
)
except Exception:
raise HTTPException(status.HTTP_400_BAD_REQUEST)
@router.delete("/{plan_id}")
def delete_meal_plan(
background_tasks: BackgroundTasks,
plan_id,
session: Session = Depends(generate_session),
current_user: PrivateUser = Depends(get_current_user),
):
""" Removes a meal plan from the database """
try:
db.meals.delete(session, plan_id)
background_tasks.add_task(
create_group_event, "Meal Plan Deleted", f"Mealplan Deleted for '{current_user.group}'", session=session
)
except Exception:
raise HTTPException(status.HTTP_400_BAD_REQUEST)

View File

@@ -1,50 +0,0 @@
from fastapi import Depends
from sqlalchemy.orm.session import Session
from mealie.core.dependencies import get_current_user
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 UserAPIRouter
from mealie.schema.meal_plan import ListItem, MealPlanOut, ShoppingListIn, ShoppingListOut
from mealie.schema.recipe import Recipe
from mealie.schema.user import PrivateUser
logger = get_logger()
router = UserAPIRouter(prefix="/api/meal-plans", tags=["Meal Plan"])
@router.get("/{id}/shopping-list")
def get_shopping_list(
id: str,
session: Session = Depends(generate_session),
current_user: PrivateUser = Depends(get_current_user),
):
mealplan: MealPlanOut = db.meals.get(session, id)
all_ingredients = []
for plan_day in mealplan.plan_days:
for meal in plan_day.meals:
if not meal.slug:
continue
try:
recipe: Recipe = db.recipes.get(session, meal.slug)
all_ingredients += recipe.recipe_ingredient
except Exception:
logger.error("Recipe Not Found")
new_list = ShoppingListIn(
name="MealPlan Shopping List", group=current_user.group, items=[ListItem(text=t.note) for t in all_ingredients]
)
created_list: ShoppingListOut = db.shopping_lists.create(session, new_list)
mealplan.shopping_list = created_list.id
db.meals.update(session, mealplan.id, mealplan)
return created_list

View File

@@ -1,8 +0,0 @@
from fastapi import APIRouter
from mealie.routes.mealplans import crud, helpers
router = APIRouter()
router.include_router(crud.router)
router.include_router(helpers.router)

View File

@@ -1,7 +1,7 @@
from fastapi import APIRouter, Depends
from sqlalchemy.orm.session import Session
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.schema.recipe import RecipeSummary
@@ -10,9 +10,11 @@ router = APIRouter()
@router.get("/summary/untagged", response_model=list[RecipeSummary])
async def get_untagged_recipes(count: bool = False, session: Session = Depends(generate_session)):
return db.recipes.count_untagged(session, count=count, override_schema=RecipeSummary)
db = get_database(session)
return db.recipes.count_untagged(count=count, override_schema=RecipeSummary)
@router.get("/summary/uncategorized", response_model=list[RecipeSummary])
async def get_uncategorized_recipes(count: bool = False, session: Session = Depends(generate_session)):
return db.recipes.count_uncategorized(session, count=count, override_schema=RecipeSummary)
db = get_database(session)
return db.recipes.count_uncategorized(count=count, override_schema=RecipeSummary)

View File

@@ -4,7 +4,7 @@ from fastapi import Depends, status
from sqlalchemy.orm.session import Session
from mealie.core.dependencies import get_current_user
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import UserAPIRouter
from mealie.schema.recipe import CommentOut, CreateComment, SaveComment
@@ -21,9 +21,10 @@ async def create_comment(
current_user: PrivateUser = Depends(get_current_user),
):
""" Create comment in the Database """
db = get_database(session)
new_comment = SaveComment(user=current_user.id, text=new_comment.text, recipe_slug=slug)
return db.comments.create(session, new_comment)
return db.comments.create(new_comment)
@router.put("/{slug}/comments/{id}")
@@ -34,12 +35,13 @@ async def update_comment(
current_user: PrivateUser = Depends(get_current_user),
):
""" Update comment in the Database """
old_comment: CommentOut = db.comments.get(session, id)
db = get_database(session)
old_comment: CommentOut = db.comments.get(id)
if current_user.id != old_comment.user.id:
raise HTTPException(status.HTTP_403_FORBIDDEN)
return db.comments.update(session, id, new_comment)
return db.comments.update(id, new_comment)
@router.delete("/{slug}/comments/{id}")
@@ -47,9 +49,10 @@ async def delete_comment(
id: int, session: Session = Depends(generate_session), current_user: PrivateUser = Depends(get_current_user)
):
""" Delete comment from the Database """
comment: CommentOut = db.comments.get(session, id)
db = get_database(session)
comment: CommentOut = db.comments.get(id)
if current_user.id == comment.user.id or current_user.admin:
db.comments.delete(session, id)
db.comments.delete(id)
return
raise HTTPException(status.HTTP_403_FORBIDDEN)

View File

@@ -5,7 +5,7 @@ from fastapi.datastructures import UploadFile
from slugify import slugify
from sqlalchemy.orm.session import Session
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import UserAPIRouter
from mealie.schema.recipe import CreateRecipeByURL, Recipe, RecipeAsset
@@ -32,8 +32,9 @@ def update_recipe_image(
session: Session = Depends(generate_session),
):
""" Removes an existing image and replaces it with the incoming file. """
db = get_database(session)
write_image(slug, image, extension)
new_version = db.recipes.update_image(session, slug, extension)
new_version = db.recipes.update_image(slug, extension)
return {"image": new_version}
@@ -58,7 +59,9 @@ def upload_recipe_asset(
if not dest.is_file():
raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR)
recipe: Recipe = db.recipes.get(session, slug)
db = get_database(session)
recipe: Recipe = db.recipes.get(slug)
recipe.assets.append(asset_in)
db.recipes.update(session, slug, recipe.dict())
db.recipes.update(slug, recipe.dict())
return asset_in

View File

@@ -10,7 +10,7 @@ from starlette.responses import FileResponse
from mealie.core.dependencies import temporary_zip_path
from mealie.core.root_logger import get_logger
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import UserAPIRouter
from mealie.schema.recipe import CreateRecipeByURL, Recipe, RecipeImageTypes
@@ -71,7 +71,9 @@ async def create_recipe_from_zip(
with myzip.open(file) as myfile:
recipe_image = myfile.read()
recipe: Recipe = db.recipes.create(session, Recipe(**recipe_dict))
db = get_database(session)
recipe: Recipe = db.recipes.create(Recipe(**recipe_dict))
write_image(recipe.slug, recipe_image, "webp")
@@ -89,7 +91,9 @@ async def get_recipe_as_zip(
slug: str, session: Session = Depends(generate_session), temp_path=Depends(temporary_zip_path)
):
""" Get a Recipe and It's Original Image as a Zip File """
recipe: Recipe = db.recipes.get(session, slug)
db = get_database(session)
recipe: Recipe = db.recipes.get(slug)
image_asset = recipe.image_dir.joinpath(RecipeImageTypes.original.value)
@@ -105,14 +109,12 @@ async def get_recipe_as_zip(
@user_router.put("/{slug}")
def update_recipe(data: Recipe, recipe_service: RecipeService = Depends(RecipeService.write_existing)):
""" Updates a recipe by existing slug and data. """
return recipe_service.update_one(data)
@user_router.patch("/{slug}")
def patch_recipe(data: Recipe, recipe_service: RecipeService = Depends(RecipeService.write_existing)):
""" Updates a recipe by existing slug and data. """
return recipe_service.patch_one(data)

View File

@@ -2,7 +2,7 @@ from fastapi import Depends
from sqlalchemy.orm.session import Session
from mealie.core.dependencies import get_current_user
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import UserAPIRouter
from mealie.schema.meal_plan import ShoppingListIn, ShoppingListOut
@@ -18,25 +18,28 @@ async def create_shopping_list(
session: Session = Depends(generate_session),
):
""" Create Shopping List in the Database """
db = get_database(session)
list_in.group = current_user.group
return db.shopping_lists.create(session, list_in)
return db.shopping_lists.create(list_in)
@router.get("/{id}", response_model=ShoppingListOut)
async def get_shopping_list(id: int, session: Session = Depends(generate_session)):
""" Get Shopping List from the Database """
return db.shopping_lists.get(session, id)
db = get_database(session)
return db.shopping_lists.get(id)
@router.put("/{id}", response_model=ShoppingListOut)
async def update_shopping_list(id: int, new_data: ShoppingListIn, session: Session = Depends(generate_session)):
""" Update Shopping List in the Database """
return db.shopping_lists.update(session, id, new_data)
db = get_database(session)
return db.shopping_lists.update(id, new_data)
@router.delete("/{id}")
async def delete_shopping_list(id: int, session: Session = Depends(generate_session)):
""" Delete Shopping List from the Database """
return db.shopping_lists.delete(session, id)
db = get_database(session)
return db.shopping_lists.delete(id)

View File

@@ -2,7 +2,7 @@ from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm.session import Session
from mealie.core.dependencies import get_current_user
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import AdminAPIRouter
from mealie.schema.admin import SiteSettings
@@ -16,8 +16,9 @@ admin_router = AdminAPIRouter(prefix="/api/site-settings", tags=["Settings"])
@public_router.get("")
def get_main_settings(session: Session = Depends(generate_session)):
""" Returns basic site settings """
db = get_database(session)
return db.settings.get(session, 1)
return db.settings.get(1)
@admin_router.put("")
@@ -26,7 +27,8 @@ def update_settings(
session: Session = Depends(generate_session),
):
""" Returns Site Settings """
db.settings.update(session, 1, data.dict())
db = get_database(session)
db.settings.update(1, data.dict())
@admin_router.post("/webhooks/test")
@@ -35,7 +37,8 @@ def test_webhooks(
session: Session = Depends(generate_session),
):
""" Run the function to test your webhooks """
group_entry: GroupInDB = db.groups.get(session, current_user.group, "name")
db = get_database(session)
group_entry: GroupInDB = db.groups.get(current_user.group, "name")
try:
post_webhooks(group_entry.id, session)

View File

@@ -1,8 +1,8 @@
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm.session import Session
from sqlalchemy.orm import Session
from mealie.core.dependencies import is_logged_in
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import AdminAPIRouter, UserAPIRouter
from mealie.schema.recipe import RecipeTagResponse, TagIn
@@ -15,13 +15,15 @@ admin_router = AdminAPIRouter()
@public_router.get("")
async def get_all_recipe_tags(session: Session = Depends(generate_session)):
""" Returns a list of available tags in the database """
return db.tags.get_all_limit_columns(session, ["slug", "name"])
db = get_database(session)
return db.tags.get_all_limit_columns(["slug", "name"])
@public_router.get("/empty")
def get_empty_tags(session: Session = Depends(generate_session)):
""" Returns a list of tags that do not contain any recipes"""
return db.tags.get_empty(session)
db = get_database(session)
return db.tags.get_empty()
@public_router.get("/{tag}", response_model=RecipeTagResponse)
@@ -29,7 +31,8 @@ def get_all_recipes_by_tag(
tag: str, session: Session = Depends(generate_session), is_user: bool = Depends(is_logged_in)
):
""" Returns a list of recipes associated with the provided tag. """
tag_obj = db.tags.get(session, tag)
db = get_database(session)
tag_obj = db.tags.get(tag)
tag_obj = RecipeTagResponse.from_orm(tag_obj)
if not is_user:
@@ -41,15 +44,15 @@ def get_all_recipes_by_tag(
@user_router.post("")
async def create_recipe_tag(tag: TagIn, session: Session = Depends(generate_session)):
""" Creates a Tag in the database """
return db.tags.create(session, tag.dict())
db = get_database(session)
return db.tags.create(tag.dict())
@admin_router.put("/{tag}", response_model=RecipeTagResponse)
async def update_recipe_tag(tag: str, new_tag: TagIn, session: Session = Depends(generate_session)):
""" Updates an existing Tag in the database """
return db.tags.update(session, tag, new_tag.dict())
db = get_database(session)
return db.tags.update(tag, new_tag.dict())
@admin_router.delete("/{tag}")
@@ -59,6 +62,7 @@ async def delete_recipe_tag(tag: str, session: Session = Depends(generate_sessio
from any recipes that contain it"""
try:
db.tags.delete(session, tag)
db = get_database(session)
db.tags.delete(tag)
except Exception:
raise HTTPException(status.HTTP_400_BAD_REQUEST)

View File

@@ -1,8 +1,10 @@
from fastapi import APIRouter
from . import food_routes, unit_routes
from mealie.services._base_http_service.router_factory import RouterFactory
from mealie.services.recipe.recipe_food_service import RecipeFoodService
from mealie.services.recipe.recipe_unit_service import RecipeUnitService
router = APIRouter()
router.include_router(food_routes.router, prefix="/foods", tags=["Recipes: Foods"])
router.include_router(unit_routes.router, prefix="/units", tags=["Recipes: Units"])
router.include_router(RouterFactory(RecipeFoodService, prefix="/foods", tags=["Recipes: Foods"]))
router.include_router(RouterFactory(RecipeUnitService, prefix="/units", tags=["Recipes: Units"]))

View File

@@ -1,44 +0,0 @@
from fastapi import Depends, status
from mealie.db.database import db
from mealie.db.db_setup import Session, generate_session
from mealie.routes.routers import UserAPIRouter
from mealie.schema.recipe import CreateIngredientFood, IngredientFood
router = UserAPIRouter()
@router.get("", response_model=list[IngredientFood])
async def get_all(
session: Session = Depends(generate_session),
):
""" Get unit from the Database """
# Get unit
return db.ingredient_foods.get_all(session)
@router.post("", response_model=IngredientFood, status_code=status.HTTP_201_CREATED)
async def create_food(unit: CreateIngredientFood, session: Session = Depends(generate_session)):
""" Create unit in the Database """
return db.ingredient_foods.create(session, unit)
@router.get("/{id}")
async def get_food(id: str, session: Session = Depends(generate_session)):
""" Get unit from the Database """
return db.ingredient_foods.get(session, id)
@router.put("/{id}")
async def update_food(id: str, unit: CreateIngredientFood, session: Session = Depends(generate_session)):
""" Update unit in the Database """
return db.ingredient_foods.update(session, id, unit)
@router.delete("/{id}")
async def delete_food(id: str, session: Session = Depends(generate_session)):
""" Delete unit from the Database """
return db.ingredient_foods.delete(session, id)

View File

@@ -1,44 +0,0 @@
from fastapi import Depends, status
from mealie.db.database import db
from mealie.db.db_setup import Session, generate_session
from mealie.routes.routers import UserAPIRouter
from mealie.schema.recipe import CreateIngredientUnit, IngredientUnit
router = UserAPIRouter()
@router.get("", response_model=list[IngredientUnit])
async def get_all(
session: Session = Depends(generate_session),
):
""" Get unit from the Database """
# Get unit
return db.ingredient_units.get_all(session)
@router.post("", response_model=IngredientUnit, status_code=status.HTTP_201_CREATED)
async def create_unit(unit: CreateIngredientUnit, session: Session = Depends(generate_session)):
""" Create unit in the Database """
return db.ingredient_units.create(session, unit)
@router.get("/{id}")
async def get_unit(id: str, session: Session = Depends(generate_session)):
""" Get unit from the Database """
return db.ingredient_units.get(session, id)
@router.put("/{id}")
async def update_unit(id: str, unit: CreateIngredientUnit, session: Session = Depends(generate_session)):
""" Update unit in the Database """
return db.ingredient_units.update(session, id, unit)
@router.delete("/{id}")
async def delete_unit(id: str, session: Session = Depends(generate_session)):
""" Delete unit from the Database """
return db.ingredient_units.delete(session, id)

View File

@@ -6,7 +6,7 @@ from sqlalchemy.orm.session import Session
from mealie.core.dependencies import get_current_user
from mealie.core.security import create_access_token
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import UserAPIRouter
from mealie.schema.user import CreateToken, LoingLiveTokenIn, LongLiveTokenInDB, PrivateUser
@@ -33,7 +33,9 @@ async def create_api_token(
parent_id=current_user.id,
)
new_token_in_db = db.api_tokens.create(session, token_model)
db = get_database(session)
new_token_in_db = db.api_tokens.create(token_model)
if new_token_in_db:
return {"token": token}
@@ -46,13 +48,14 @@ async def delete_api_token(
session: Session = Depends(generate_session),
):
""" Delete api_token from the Database """
token: LongLiveTokenInDB = db.api_tokens.get(session, token_id)
db = get_database(session)
token: LongLiveTokenInDB = db.api_tokens.get(token_id)
if not token:
raise HTTPException(status.HTTP_404_NOT_FOUND, f"Could not locate token with id '{token_id}' in database")
if token.user.email == current_user.email:
deleted_token = db.api_tokens.delete(session, token_id)
deleted_token = db.api_tokens.delete(token_id)
return {"token_delete": deleted_token.name}
else:
raise HTTPException(status.HTTP_403_FORBIDDEN)

View File

@@ -4,7 +4,7 @@ from sqlalchemy.orm.session import Session
from mealie.core import security
from mealie.core.dependencies import get_current_user
from mealie.core.security import hash_password
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import AdminAPIRouter, UserAPIRouter
from mealie.routes.users._helpers import assert_user_change_allowed
@@ -17,7 +17,8 @@ admin_router = AdminAPIRouter(prefix="")
@admin_router.get("", response_model=list[UserOut])
async def get_all_users(session: Session = Depends(generate_session)):
return db.users.get_all(session)
db = get_database(session)
return db.users.get_all()
@admin_router.post("", response_model=UserOut, status_code=201)
@@ -33,12 +34,14 @@ async def create_user(
create_user_event, "User Created", f"Created by {current_user.full_name}", session=session
)
return db.users.create(session, new_user.dict())
db = get_database(session)
return db.users.create(new_user.dict())
@admin_router.get("/{id}", response_model=UserOut)
async def get_user(id: int, session: Session = Depends(generate_session)):
return db.users.get(session, id)
db = get_database(session)
return db.users.get(id)
@admin_router.delete("/{id}")
@@ -56,7 +59,8 @@ def delete_user(
raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="SUPER_USER")
try:
db.users.delete(session, id)
db = get_database(session)
db.users.delete(id)
background_tasks.add_task(create_user_event, "User Deleted", f"User ID: {id}", session=session)
except Exception:
raise HTTPException(status.HTTP_400_BAD_REQUEST)
@@ -87,7 +91,9 @@ async def update_user(
# prevent an admin from demoting themself
raise HTTPException(status.HTTP_403_FORBIDDEN)
db.users.update(session, id, new_data.dict())
db = get_database(session)
db.users.update(id, new_data.dict())
if current_user.id == id:
access_token = security.create_access_token(data=dict(sub=new_data.email))
return {"access_token": access_token, "token_type": "bearer"}

View File

@@ -2,7 +2,7 @@ from fastapi import Depends
from sqlalchemy.orm.session import Session
from mealie.core.dependencies import get_current_user
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import UserAPIRouter
from mealie.routes.users._helpers import assert_user_change_allowed
@@ -14,8 +14,8 @@ user_router = UserAPIRouter()
@user_router.get("/{id}/favorites", response_model=UserFavorites)
async def get_favorites(id: str, session: Session = Depends(generate_session)):
""" Get user's favorite recipes """
return db.users.get(session, id, override_schema=UserFavorites)
db = get_database(session)
return db.users.get(id, override_schema=UserFavorites)
@user_router.post("/{id}/favorites/{slug}")
@@ -29,7 +29,8 @@ def add_favorite(
assert_user_change_allowed(id, current_user)
current_user.favorite_recipes.append(slug)
db.users.update(session, current_user.id, current_user)
db = get_database(session)
db.users.update(current_user.id, current_user)
@user_router.delete("/{id}/favorites/{slug}")
@@ -43,6 +44,7 @@ def remove_favorite(
assert_user_change_allowed(id, current_user)
current_user.favorite_recipes = [x for x in current_user.favorite_recipes if x != slug]
db.users.update(session, current_user.id, current_user)
db = get_database(session)
db.users.update(current_user.id, current_user)
return

View File

@@ -3,7 +3,7 @@ from sqlalchemy.orm.session import Session
from mealie.core.config import settings
from mealie.core.security import hash_password
from mealie.db.database import db
from mealie.db.database import get_database
from mealie.db.db_setup import generate_session
from mealie.routes.routers import UserAPIRouter
from mealie.schema.user import ChangePassword
@@ -15,7 +15,9 @@ user_router = UserAPIRouter(prefix="")
@user_router.put("/{id}/reset-password")
async def reset_user_password(id: int, session: Session = Depends(generate_session)):
new_password = hash_password(settings.DEFAULT_PASSWORD)
db.users.update_password(session, id, new_password)
db = get_database(session)
db.users.update_password(id, new_password)
@user_router.put("/{id}/password")