From 09765979e32dd9fd112794002d2cd56af1e25f8f Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Sun, 28 Mar 2021 12:42:21 -0800 Subject: [PATCH] feature/secure-routes (#226) * secure routes * add token to test routes * fix duplicate data Co-authored-by: hay-kot --- mealie/routes/backup_routes.py | 7 +++-- mealie/routes/debug_routes.py | 9 +++--- mealie/routes/mealplans/crud.py | 23 ++++++-------- mealie/routes/mealplans/helpers.py | 13 +++++--- mealie/routes/migration_routes.py | 7 +++-- mealie/routes/recipe/category_routes.py | 3 +- mealie/routes/recipe/recipe_crud_routes.py | 31 ++++++++++++++---- mealie/routes/recipe/tag_routes.py | 11 ++++--- mealie/routes/site_settings/custom_pages.py | 7 ++++- mealie/routes/site_settings/site_settings.py | 13 +++++--- mealie/routes/theme_routes.py | 18 +++++++---- tests/test_routes/test_import_routes.py | 4 +-- tests/test_routes/test_meal_routes.py | 15 +++++---- tests/test_routes/test_migration_routes.py | 29 ++++++++--------- tests/test_routes/test_recipe_routes.py | 33 ++++++++++---------- tests/test_routes/test_settings_routes.py | 25 ++++++--------- tests/test_routes/utils/routes_data.py | 8 ++--- 17 files changed, 142 insertions(+), 114 deletions(-) diff --git a/mealie/routes/backup_routes.py b/mealie/routes/backup_routes.py index 8c186a737..28786a1d0 100644 --- a/mealie/routes/backup_routes.py +++ b/mealie/routes/backup_routes.py @@ -4,6 +4,7 @@ import shutil from fastapi import APIRouter, Depends, File, HTTPException, UploadFile from mealie.core.config import BACKUP_DIR, TEMPLATE_DIR from mealie.db.db_setup import generate_session +from mealie.routes.deps import get_current_user from mealie.schema.backup import BackupJob, ImportJob, Imports, LocalBackup from mealie.schema.snackbar import SnackResponse from mealie.services.backups import imports @@ -11,7 +12,7 @@ from mealie.services.backups.exports import backup_all from sqlalchemy.orm.session import Session from starlette.responses import FileResponse -router = APIRouter(prefix="/api/backups", tags=["Backups"]) +router = APIRouter(prefix="/api/backups", tags=["Backups"], dependencies=[Depends(get_current_user)]) @router.get("/available", response_model=Imports) @@ -52,7 +53,7 @@ def export_database(data: BackupJob, session: Session = Depends(generate_session @router.post("/upload") -def upload_backup_zipfile(archive: UploadFile = File(...)): +def upload_backup_file(archive: UploadFile = File(...)): """ Upload a .zip File to later be imported into Mealie """ dest = BACKUP_DIR.joinpath(archive.filename) @@ -66,7 +67,7 @@ def upload_backup_zipfile(archive: UploadFile = File(...)): @router.get("/{file_name}/download") -async def upload_nextcloud_zipfile(file_name: str): +async def download_backup_file(file_name: str): """ Upload a .zip File to later be imported into Mealie """ file = BACKUP_DIR.joinpath(file_name) diff --git a/mealie/routes/debug_routes.py b/mealie/routes/debug_routes.py index b71a83056..72d1eeb3c 100644 --- a/mealie/routes/debug_routes.py +++ b/mealie/routes/debug_routes.py @@ -1,9 +1,10 @@ import json +from fastapi import APIRouter, Depends from mealie.core.config import APP_VERSION, DEBUG_DIR, LOGGER_FILE -from fastapi import APIRouter +from mealie.routes.deps import get_current_user -router = APIRouter(prefix="/api/debug", tags=["Debug"]) +router = APIRouter(prefix="/api/debug", tags=["Debug"], dependencies=[Depends(get_current_user)]) @router.get("/version") @@ -25,9 +26,7 @@ async def get_log(num: int): """ Doc Str """ with open(LOGGER_FILE, "rb") as f: log_text = tail(f, num) - HTML_RESPONSE = log_text - - return HTML_RESPONSE + return log_text def tail(f, lines=20): diff --git a/mealie/routes/mealplans/crud.py b/mealie/routes/mealplans/crud.py index 906d0029d..f5196c785 100644 --- a/mealie/routes/mealplans/crud.py +++ b/mealie/routes/mealplans/crud.py @@ -25,9 +25,7 @@ def get_all_meals( @router.post("/create") def create_meal_plan( - data: MealPlanIn, - session: Session = Depends(generate_session), - current_user=Depends(get_current_user), + data: MealPlanIn, session: Session = Depends(generate_session), current_user=Depends(get_current_user) ): """ Creates a meal plan database entry """ processed_plan = process_meals(session, data) @@ -37,7 +35,12 @@ def create_meal_plan( @router.put("/{plan_id}") -def update_meal_plan(plan_id: str, meal_plan: MealPlanIn, session: Session = Depends(generate_session)): +def update_meal_plan( + plan_id: str, + meal_plan: MealPlanIn, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Updates a meal plan based off ID """ processed_plan = process_meals(session, meal_plan) processed_plan = MealPlanInDB(uid=plan_id, **processed_plan.dict()) @@ -47,7 +50,7 @@ def update_meal_plan(plan_id: str, meal_plan: MealPlanIn, session: Session = Dep @router.delete("/{plan_id}") -def delete_meal_plan(plan_id, session: Session = Depends(generate_session)): +def delete_meal_plan(plan_id, session: Session = Depends(generate_session), current_user=Depends(get_current_user)): """ Removes a meal plan from the database """ db.meals.delete(session, plan_id) @@ -56,20 +59,14 @@ def delete_meal_plan(plan_id, session: Session = Depends(generate_session)): @router.get("/this-week", response_model=MealPlanInDB) -def get_this_week( - session: Session = Depends(generate_session), - current_user: UserInDB = Depends(get_current_user), -): +def get_this_week(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)): """ Returns the meal plan data for this week """ return db.groups.get_meals(session, current_user.group)[0] @router.get("/today", tags=["Meal Plan"]) -def get_today( - session: Session = Depends(generate_session), - current_user: UserInDB = Depends(get_current_user), -): +def get_today(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)): """ Returns the recipe slug for the meal scheduled for today. If no meal is scheduled nothing is returned diff --git a/mealie/routes/mealplans/helpers.py b/mealie/routes/mealplans/helpers.py index 0bf3a9702..f1e90d531 100644 --- a/mealie/routes/mealplans/helpers.py +++ b/mealie/routes/mealplans/helpers.py @@ -1,6 +1,7 @@ +from fastapi import APIRouter, Depends from mealie.db.database import db from mealie.db.db_setup import generate_session -from fastapi import APIRouter, Depends +from mealie.routes.deps import get_current_user from mealie.schema.meal import MealPlanInDB from mealie.schema.recipe import Recipe from sqlalchemy.orm.session import Session @@ -9,13 +10,15 @@ router = APIRouter(prefix="/api/meal-plans", tags=["Meal Plan"]) @router.get("/{id}/shopping-list") -def get_shopping_list(id: str, session: Session = Depends(generate_session)): +def get_shopping_list( + id: str, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): #! Refactor into Single Database Call mealplan = db.meals.get(session, id) mealplan: MealPlanInDB slugs = [x.slug for x in mealplan.meals] recipes: list[Recipe] = [db.recipes.get(session, x) for x in slugs] - ingredients = [{"name": x.name, "recipeIngredient": x.recipeIngredient} for x in recipes if x] - - return ingredients + return [{"name": x.name, "recipeIngredient": x.recipeIngredient} for x in recipes if x] diff --git a/mealie/routes/migration_routes.py b/mealie/routes/migration_routes.py index 9acc51f09..3422439c7 100644 --- a/mealie/routes/migration_routes.py +++ b/mealie/routes/migration_routes.py @@ -2,16 +2,17 @@ import operator import shutil from typing import List +from fastapi import APIRouter, Depends, File, HTTPException, UploadFile from mealie.core.config import MIGRATION_DIR from mealie.db.db_setup import generate_session -from fastapi import APIRouter, Depends, File, HTTPException, UploadFile +from mealie.routes.deps import get_current_user from mealie.schema.migration import MigrationFile, Migrations +from mealie.schema.snackbar import SnackResponse from mealie.services.migrations.chowdown import chowdown_migrate as chowdow_migrate from mealie.services.migrations.nextcloud import migrate as nextcloud_migrate from sqlalchemy.orm.session import Session -from mealie.schema.snackbar import SnackResponse -router = APIRouter(prefix="/api/migrations", tags=["Migration"]) +router = APIRouter(prefix="/api/migrations", tags=["Migration"], dependencies=[Depends(get_current_user)]) @router.get("", response_model=List[Migrations]) diff --git a/mealie/routes/recipe/category_routes.py b/mealie/routes/recipe/category_routes.py index 979d712c8..055a19124 100644 --- a/mealie/routes/recipe/category_routes.py +++ b/mealie/routes/recipe/category_routes.py @@ -1,3 +1,4 @@ +from mealie.routes.deps import get_current_user from mealie.db.database import db from mealie.db.db_setup import generate_session from fastapi import APIRouter, Depends @@ -26,7 +27,7 @@ def get_all_recipes_by_category(category: str, session: Session = Depends(genera @router.delete("/{category}") -async def delete_recipe_category(category: str, session: Session = Depends(generate_session)): +async def delete_recipe_category(category: str, session: Session = Depends(generate_session), current_user=Depends(get_current_user)): """Removes a recipe category from the database. Deleting a category does not impact a recipe. The category will be removed from any recipes that contain it""" diff --git a/mealie/routes/recipe/recipe_crud_routes.py b/mealie/routes/recipe/recipe_crud_routes.py index 3a5e217e9..baa254dc1 100644 --- a/mealie/routes/recipe/recipe_crud_routes.py +++ b/mealie/routes/recipe/recipe_crud_routes.py @@ -1,8 +1,9 @@ -from mealie.db.database import db -from mealie.db.db_setup import generate_session from fastapi import APIRouter, Depends, File, Form, HTTPException from fastapi.logger import logger from fastapi.responses import FileResponse +from mealie.db.database import db +from mealie.db.db_setup import generate_session +from mealie.routes.deps import get_current_user from mealie.schema.recipe import Recipe, RecipeURLIn from mealie.schema.snackbar import SnackResponse from mealie.services.image_services import read_image, write_image @@ -16,7 +17,11 @@ router = APIRouter( @router.post("/create", status_code=201, response_model=str) -def create_from_json(data: Recipe, session: Session = Depends(generate_session)) -> str: +def create_from_json( + 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()) @@ -24,7 +29,11 @@ def create_from_json(data: Recipe, session: Session = Depends(generate_session)) @router.post("/create-url", status_code=201, response_model=str) -def parse_recipe_url(url: RecipeURLIn, session: Session = Depends(generate_session)): +def parse_recipe_url( + url: RecipeURLIn, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Takes in a URL and attempts to scrape data and load it into the database """ recipe = create_from_url(url.url) @@ -41,7 +50,12 @@ def get_recipe(recipe_slug: str, session: Session = Depends(generate_session)): @router.put("/{recipe_slug}") -def update_recipe(recipe_slug: str, data: Recipe, session: Session = Depends(generate_session)): +def update_recipe( + recipe_slug: str, + data: Recipe, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Updates a recipe by existing slug and data. """ recipe: Recipe = db.recipes.update(session, recipe_slug, data.dict()) @@ -50,7 +64,11 @@ def update_recipe(recipe_slug: str, data: Recipe, session: Session = Depends(gen @router.delete("/{recipe_slug}") -def delete_recipe(recipe_slug: str, session: Session = Depends(generate_session)): +def delete_recipe( + recipe_slug: str, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Deletes a recipe by slug """ try: @@ -77,6 +95,7 @@ def update_recipe_image( image: bytes = File(...), extension: str = Form(...), session: Session = Depends(generate_session), + current_user=Depends(get_current_user), ): """ Removes an existing image and replaces it with the incoming file. """ response = write_image(recipe_slug, image, extension) diff --git a/mealie/routes/recipe/tag_routes.py b/mealie/routes/recipe/tag_routes.py index 0da90e668..50dfd379a 100644 --- a/mealie/routes/recipe/tag_routes.py +++ b/mealie/routes/recipe/tag_routes.py @@ -1,10 +1,9 @@ +from fastapi import APIRouter, Depends from mealie.db.database import db from mealie.db.db_setup import generate_session -from fastapi import APIRouter, Depends +from mealie.routes.deps import get_current_user +from mealie.schema.snackbar import SnackResponse from sqlalchemy.orm.session import Session -from mealie.schema.snackbar import SnackResponse - -from mealie.schema.snackbar import SnackResponse router = APIRouter(tags=["Recipes"]) @@ -27,7 +26,9 @@ def get_all_recipes_by_tag(tag: str, session: Session = Depends(generate_session @router.delete("/{tag}") -async def delete_recipe_tag(tag: str, session: Session = Depends(generate_session)): +async def delete_recipe_tag( + tag: str, session: Session = Depends(generate_session), current_user=Depends(get_current_user) +): """Removes a recipe tag from the database. Deleting a tag does not impact a recipe. The tag will be removed from any recipes that contain it""" diff --git a/mealie/routes/site_settings/custom_pages.py b/mealie/routes/site_settings/custom_pages.py index 33bd27598..5f912de08 100644 --- a/mealie/routes/site_settings/custom_pages.py +++ b/mealie/routes/site_settings/custom_pages.py @@ -57,7 +57,12 @@ async def get_single_page( @router.put("/{id}") -async def update_single_age(data: CustomPageOut, id: int, session: Session = Depends(generate_session)): +async def update_single_age( + data: CustomPageOut, + id: int, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Removes a custom page from the database """ return db.custom_pages.update(session, id, data.dict()) diff --git a/mealie/routes/site_settings/site_settings.py b/mealie/routes/site_settings/site_settings.py index 4f7bf9772..52f47f89b 100644 --- a/mealie/routes/site_settings/site_settings.py +++ b/mealie/routes/site_settings/site_settings.py @@ -1,13 +1,12 @@ +from fastapi import APIRouter, Depends from mealie.db.database import db from mealie.db.db_setup import generate_session -from fastapi import APIRouter, Depends +from mealie.routes.deps import get_current_user from mealie.schema.settings import SiteSettings from mealie.schema.snackbar import SnackResponse from mealie.schema.user import GroupInDB, UserInDB -from sqlalchemy.orm.session import Session from mealie.utils.post_webhooks import post_webhooks - -from mealie.routes.deps import get_current_user +from sqlalchemy.orm.session import Session router = APIRouter(prefix="/api/site-settings", tags=["Settings"]) @@ -20,7 +19,11 @@ def get_main_settings(session: Session = Depends(generate_session)): @router.put("") -def update_settings(data: SiteSettings, session: Session = Depends(generate_session)): +def update_settings( + data: SiteSettings, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Returns Site Settings """ db.settings.update(session, 1, data.dict()) diff --git a/mealie/routes/theme_routes.py b/mealie/routes/theme_routes.py index 91cfea268..78f1a09cb 100644 --- a/mealie/routes/theme_routes.py +++ b/mealie/routes/theme_routes.py @@ -1,9 +1,10 @@ -from mealie.db.db_setup import generate_session from fastapi import APIRouter, Depends +from mealie.db.database import db +from mealie.db.db_setup import generate_session +from mealie.routes.deps import get_current_user +from mealie.schema.snackbar import SnackResponse from mealie.schema.theme import SiteTheme from sqlalchemy.orm.session import Session -from mealie.schema.snackbar import SnackResponse -from mealie.db.database import db router = APIRouter(prefix="/api", tags=["Themes"]) @@ -16,7 +17,7 @@ def get_all_themes(session: Session = Depends(generate_session)): @router.post("/themes/create") -def create_theme(data: SiteTheme, session: Session = Depends(generate_session)): +def create_theme(data: SiteTheme, session: Session = Depends(generate_session), current_user=Depends(get_current_user)): """ Creates a site color theme database entry """ db.themes.create(session, data.dict()) @@ -30,7 +31,12 @@ def get_single_theme(theme_name: str, session: Session = Depends(generate_sessio @router.put("/themes/{theme_name}") -def update_theme(theme_name: str, data: SiteTheme, session: Session = Depends(generate_session)): +def update_theme( + theme_name: str, + data: SiteTheme, + session: Session = Depends(generate_session), + current_user=Depends(get_current_user), +): """ Update a theme database entry """ db.themes.update(session, theme_name, data.dict()) @@ -38,7 +44,7 @@ def update_theme(theme_name: str, data: SiteTheme, session: Session = Depends(ge @router.delete("/themes/{theme_name}") -def delete_theme(theme_name: str, session: Session = Depends(generate_session)): +def delete_theme(theme_name: str, session: Session = Depends(generate_session), current_user=Depends(get_current_user)): """ Deletes theme from the database """ db.themes.delete(session, theme_name) diff --git a/tests/test_routes/test_import_routes.py b/tests/test_routes/test_import_routes.py index 0dfc82d1d..19e812305 100644 --- a/tests/test_routes/test_import_routes.py +++ b/tests/test_routes/test_import_routes.py @@ -16,8 +16,8 @@ def backup_data(): } -def test_import(api_client, backup_data): - response = api_client.post("/api/backups/dev_sample_data_2021-Feb-13.zip/import", json=backup_data) +def test_import(api_client, backup_data, token): + response = api_client.post("/api/backups/dev_sample_data_2021-Feb-13.zip/import", json=backup_data, headers=token) assert response.status_code == 200 for key, value in json.loads(response.content).items(): diff --git a/tests/test_routes/test_meal_routes.py b/tests/test_routes/test_meal_routes.py index f1a478cac..f801ba45f 100644 --- a/tests/test_routes/test_meal_routes.py +++ b/tests/test_routes/test_meal_routes.py @@ -23,11 +23,10 @@ def get_meal_plan_template(first=None, second=None): } -@pytest.fixture -def slug_1(api_client): +@pytest.fixture(scope="session") +def slug_1(api_client, token): # Slug 1 - - slug_1 = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_test_data[0].url}) + slug_1 = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_test_data[0].url}, headers=token) slug_1 = json.loads(slug_1.content) yield slug_1 @@ -35,10 +34,10 @@ def slug_1(api_client): api_client.delete(RECIPES_PREFIX + "/" + slug_1) -@pytest.fixture -def slug_2(api_client): +@pytest.fixture(scope="session") +def slug_2(api_client, token): # Slug 2 - slug_2 = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_test_data[1].url}) + slug_2 = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_test_data[1].url}, headers=token) slug_2 = json.loads(slug_2.content) yield slug_2 @@ -99,6 +98,6 @@ def test_delete_mealplan(api_client, token): existing_mealplan = existing_mealplan[0] plan_uid = existing_mealplan.get("uid") - response = api_client.delete(f"{MEALPLAN_PREFIX}/{plan_uid}") + response = api_client.delete(f"{MEALPLAN_PREFIX}/{plan_uid}", headers=token) assert response.status_code == 200 diff --git a/tests/test_routes/test_migration_routes.py b/tests/test_routes/test_migration_routes.py index f0629bf1b..cbe71c774 100644 --- a/tests/test_routes/test_migration_routes.py +++ b/tests/test_routes/test_migration_routes.py @@ -21,11 +21,10 @@ def chowdown_zip(): zip_copy.unlink() -def test_upload_chowdown_zip(api_client, chowdown_zip): +def test_upload_chowdown_zip(api_client, chowdown_zip, token): response = api_client.post( - f"{MIGRATIONS_PREFIX}/chowdown/upload", - files={"archive": chowdown_zip.open("rb")}, + f"{MIGRATIONS_PREFIX}/chowdown/upload", files={"archive": chowdown_zip.open("rb")}, headers=token ) assert response.status_code == 200 @@ -33,10 +32,10 @@ def test_upload_chowdown_zip(api_client, chowdown_zip): assert MIGRATION_DIR.joinpath("chowdown", chowdown_zip.name).is_file() -def test_import_chowdown_directory(api_client, chowdown_zip): - api_client.delete(f"{RECIPES_PREFIX}/roasted-okra") # TODO: Manage Test Data better +def test_import_chowdown_directory(api_client, chowdown_zip, token): + api_client.delete(f"{RECIPES_PREFIX}/roasted-okra", headers=token) # TODO: Manage Test Data better selection = chowdown_zip.name - response = api_client.post(f"{MIGRATIONS_PREFIX}/chowdown/{selection}/import") + response = api_client.post(f"{MIGRATIONS_PREFIX}/chowdown/{selection}/import", headers=token) assert response.status_code == 200 @@ -48,9 +47,9 @@ def test_import_chowdown_directory(api_client, chowdown_zip): assert response.status_code == 200 -def test_delete_chowdown_migration_data(api_client, chowdown_zip): +def test_delete_chowdown_migration_data(api_client, chowdown_zip, token): selection = chowdown_zip.name - response = api_client.delete(f"{MIGRATIONS_PREFIX}/chowdown/{selection}/delete") + response = api_client.delete(f"{MIGRATIONS_PREFIX}/chowdown/{selection}/delete", headers=token) assert response.status_code == 200 assert not MIGRATION_DIR.joinpath(chowdown_zip.name).is_file() @@ -70,11 +69,9 @@ def nextcloud_zip(): zip_copy.unlink() -def test_upload_nextcloud_zip(api_client, nextcloud_zip): - +def test_upload_nextcloud_zip(api_client, nextcloud_zip, token): response = api_client.post( - f"{MIGRATIONS_PREFIX}/nextcloud/upload", - files={"archive": nextcloud_zip.open("rb")}, + f"{MIGRATIONS_PREFIX}/nextcloud/upload", files={"archive": nextcloud_zip.open("rb")}, headers=token ) assert response.status_code == 200 @@ -82,9 +79,9 @@ def test_upload_nextcloud_zip(api_client, nextcloud_zip): assert MIGRATION_DIR.joinpath("nextcloud", nextcloud_zip.name).is_file() -def test_import_nextcloud_directory(api_client, nextcloud_zip): +def test_import_nextcloud_directory(api_client, nextcloud_zip, token): selection = nextcloud_zip.name - response = api_client.post(f"{MIGRATIONS_PREFIX}/nextcloud/{selection}/import") + response = api_client.post(f"{MIGRATIONS_PREFIX}/nextcloud/{selection}/import", headers=token) assert response.status_code == 200 @@ -96,9 +93,9 @@ def test_import_nextcloud_directory(api_client, nextcloud_zip): assert response.status_code == 200 -def test_delete__nextcloud_migration_data(api_client, nextcloud_zip): +def test_delete__nextcloud_migration_data(api_client, nextcloud_zip, token): selection = nextcloud_zip.name - response = api_client.delete(f"{MIGRATIONS_PREFIX}/nextcloud/{selection}/delete") + response = api_client.delete(f"{MIGRATIONS_PREFIX}/nextcloud/{selection}/delete", headers=token) assert response.status_code == 200 assert not MIGRATION_DIR.joinpath(nextcloud_zip.name).is_file() diff --git a/tests/test_routes/test_recipe_routes.py b/tests/test_routes/test_recipe_routes.py index 1007b2d09..58b18f8e2 100644 --- a/tests/test_routes/test_recipe_routes.py +++ b/tests/test_routes/test_recipe_routes.py @@ -7,22 +7,23 @@ from tests.utils.routes import RECIPES_ALL, RECIPES_CREATE, RECIPES_CREATE_URL, @pytest.mark.parametrize("recipe_data", recipe_test_data) -def test_create_by_url(api_client, recipe_data: RecipeTestData): - response = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_data.url}) +def test_create_by_url(api_client, recipe_data: RecipeTestData, token): + api_client.delete(RECIPES_PREFIX + "/" + recipe_data.expected_slug, headers=token) + response = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_data.url}, headers=token) assert response.status_code == 201 assert json.loads(response.text) == recipe_data.expected_slug -def test_create_by_json(api_client): - api_client.delete(f"{RECIPES_PREFIX}/banana-bread") - response = api_client.post(RECIPES_CREATE, json=raw_recipe) +def test_create_by_json(api_client, token): + api_client.delete(f"{RECIPES_PREFIX}/banana-bread", headers=token) + response = api_client.post(RECIPES_CREATE, json=raw_recipe, headers=token) assert response.status_code == 201 assert json.loads(response.text) == "banana-bread" -def test_create_no_image(api_client): - response = api_client.post(RECIPES_CREATE, json=raw_recipe_no_image) +def test_create_no_image(api_client, token): + response = api_client.post(RECIPES_CREATE, json=raw_recipe_no_image, headers=token) assert response.status_code == 201 assert json.loads(response.text) == "banana-bread-no-image" @@ -46,8 +47,8 @@ def test_read_all_post(api_client): @pytest.mark.parametrize("recipe_data", recipe_test_data) -def test_read_update(api_client, recipe_data): - response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}") +def test_read_update(api_client, recipe_data, token): + response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", headers=token) assert response.status_code == 200 recipe = json.loads(response.content) @@ -61,7 +62,7 @@ def test_read_update(api_client, recipe_data): test_categories = ["one", "two", "three"] recipe["recipeCategory"] = test_categories - response = api_client.put(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", json=recipe) + response = api_client.put(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", json=recipe, headers=token) assert response.status_code == 200 assert json.loads(response.text) == recipe_data.expected_slug @@ -75,16 +76,16 @@ def test_read_update(api_client, recipe_data): @pytest.mark.parametrize("recipe_data", recipe_test_data) -def test_rename(api_client, recipe_data): - response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}") +def test_rename(api_client, recipe_data, token): + response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", headers=token) assert response.status_code == 200 - recipe = json.loads(response.content) + recipe = json.loads(response.text) new_name = recipe.get("name") + "-rename" new_slug = slugify(new_name) recipe["name"] = new_name - response = api_client.put(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", json=recipe) + response = api_client.put(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", json=recipe, headers=token) assert response.status_code == 200 assert json.loads(response.text) == new_slug @@ -93,6 +94,6 @@ def test_rename(api_client, recipe_data): @pytest.mark.parametrize("recipe_data", recipe_test_data) -def test_delete(api_client, recipe_data): - response = api_client.delete(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}") +def test_delete(api_client, recipe_data, token): + response = api_client.delete(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", headers=token) assert response.status_code == 200 diff --git a/tests/test_routes/test_settings_routes.py b/tests/test_routes/test_settings_routes.py index 718457861..5564226a6 100644 --- a/tests/test_routes/test_settings_routes.py +++ b/tests/test_routes/test_settings_routes.py @@ -1,14 +1,9 @@ import json -from mealie.schema.settings import SiteSettings -from mealie.schema.theme import SiteTheme import pytest -from tests.utils.routes import ( - SETTINGS_PREFIX, - SETTINGS_UPDATE, - THEMES_CREATE, - THEMES_PREFIX, -) +from mealie.schema.settings import SiteSettings +from mealie.schema.theme import SiteTheme +from tests.utils.routes import SETTINGS_PREFIX, SETTINGS_UPDATE, THEMES_CREATE, THEMES_PREFIX @pytest.fixture(scope="function") @@ -45,11 +40,11 @@ def test_default_settings(api_client, default_settings): assert json.loads(response.content) == default_settings -def test_update_settings(api_client, default_settings): +def test_update_settings(api_client, default_settings, token): default_settings["language"] = "fr" default_settings["showRecent"] = False - response = api_client.put(SETTINGS_UPDATE, json=default_settings) + response = api_client.put(SETTINGS_UPDATE, json=default_settings, headers=token) assert response.status_code == 200 @@ -63,12 +58,12 @@ def test_default_theme(api_client, default_theme): assert json.loads(response.content) == default_theme -def test_create_theme(api_client, new_theme): +def test_create_theme(api_client, new_theme, token): - response = api_client.post(THEMES_CREATE, json=new_theme) + response = api_client.post(THEMES_CREATE, json=new_theme, headers=token) assert response.status_code == 200 - response = api_client.get(f"{THEMES_PREFIX}/{new_theme.get('name')}") + response = api_client.get(f"{THEMES_PREFIX}/{new_theme.get('name')}", headers=token) assert response.status_code == 200 assert json.loads(response.content) == new_theme @@ -86,8 +81,8 @@ def test_read_theme(api_client, default_theme, new_theme): assert json.loads(response.content) == theme -def test_delete_theme(api_client, default_theme, new_theme): +def test_delete_theme(api_client, default_theme, new_theme, token): for theme in [default_theme, new_theme]: - response = api_client.delete(f"{THEMES_PREFIX}/{theme.get('name')}") + response = api_client.delete(f"{THEMES_PREFIX}/{theme.get('name')}", headers=token) assert response.status_code == 200 diff --git a/tests/test_routes/utils/routes_data.py b/tests/test_routes/utils/routes_data.py index ca580ffaa..700f970c3 100644 --- a/tests/test_routes/utils/routes_data.py +++ b/tests/test_routes/utils/routes_data.py @@ -6,12 +6,12 @@ class RecipeTestData: recipe_test_data = [ RecipeTestData( - url="https://www.bonappetit.com/recipe/rustic-shrimp-toasts", - expected_slug="rustic-shrimp-toasts", + url="https://www.bonappetit.com/recipe/spinach-thepla-and-vaghareli-dahi", + expected_slug="thepla-recipe-with-vaghareli-dahi", ), RecipeTestData( - url="https://www.allrecipes.com/recipe/282905/honey-garlic-shrimp/", - expected_slug="honey-garlic-shrimp", + url="https://www.bonappetit.com/recipe/classic-coleslaw", + expected_slug="traditional-coleslaw-recipe", ), ]