feature/secure-routes (#226)

* secure routes

* add token to test routes

* fix duplicate data

Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
Hayden 2021-03-28 12:42:21 -08:00 committed by GitHub
commit 09765979e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 142 additions and 114 deletions

View file

@ -4,6 +4,7 @@ import shutil
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
from mealie.core.config import BACKUP_DIR, TEMPLATE_DIR from mealie.core.config import BACKUP_DIR, TEMPLATE_DIR
from mealie.db.db_setup import generate_session 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.backup import BackupJob, ImportJob, Imports, LocalBackup
from mealie.schema.snackbar import SnackResponse from mealie.schema.snackbar import SnackResponse
from mealie.services.backups import imports 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 sqlalchemy.orm.session import Session
from starlette.responses import FileResponse 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) @router.get("/available", response_model=Imports)
@ -52,7 +53,7 @@ def export_database(data: BackupJob, session: Session = Depends(generate_session
@router.post("/upload") @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 """ """ Upload a .zip File to later be imported into Mealie """
dest = BACKUP_DIR.joinpath(archive.filename) dest = BACKUP_DIR.joinpath(archive.filename)
@ -66,7 +67,7 @@ def upload_backup_zipfile(archive: UploadFile = File(...)):
@router.get("/{file_name}/download") @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 """ """ Upload a .zip File to later be imported into Mealie """
file = BACKUP_DIR.joinpath(file_name) file = BACKUP_DIR.joinpath(file_name)

View file

@ -1,9 +1,10 @@
import json import json
from fastapi import APIRouter, Depends
from mealie.core.config import APP_VERSION, DEBUG_DIR, LOGGER_FILE 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") @router.get("/version")
@ -25,9 +26,7 @@ async def get_log(num: int):
""" Doc Str """ """ Doc Str """
with open(LOGGER_FILE, "rb") as f: with open(LOGGER_FILE, "rb") as f:
log_text = tail(f, num) log_text = tail(f, num)
HTML_RESPONSE = log_text return log_text
return HTML_RESPONSE
def tail(f, lines=20): def tail(f, lines=20):

View file

@ -25,9 +25,7 @@ def get_all_meals(
@router.post("/create") @router.post("/create")
def create_meal_plan( def create_meal_plan(
data: MealPlanIn, data: MealPlanIn, session: Session = Depends(generate_session), current_user=Depends(get_current_user)
session: Session = Depends(generate_session),
current_user=Depends(get_current_user),
): ):
""" Creates a meal plan database entry """ """ Creates a meal plan database entry """
processed_plan = process_meals(session, data) processed_plan = process_meals(session, data)
@ -37,7 +35,12 @@ def create_meal_plan(
@router.put("/{plan_id}") @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 """ """ Updates a meal plan based off ID """
processed_plan = process_meals(session, meal_plan) processed_plan = process_meals(session, meal_plan)
processed_plan = MealPlanInDB(uid=plan_id, **processed_plan.dict()) 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}") @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 """ """ Removes a meal plan from the database """
db.meals.delete(session, plan_id) 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) @router.get("/this-week", response_model=MealPlanInDB)
def get_this_week( def get_this_week(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)):
session: Session = Depends(generate_session),
current_user: UserInDB = Depends(get_current_user),
):
""" Returns the meal plan data for this week """ """ Returns the meal plan data for this week """
return db.groups.get_meals(session, current_user.group)[0] return db.groups.get_meals(session, current_user.group)[0]
@router.get("/today", tags=["Meal Plan"]) @router.get("/today", tags=["Meal Plan"])
def get_today( def get_today(session: Session = Depends(generate_session), current_user: UserInDB = Depends(get_current_user)):
session: Session = Depends(generate_session),
current_user: UserInDB = Depends(get_current_user),
):
""" """
Returns the recipe slug for the meal scheduled for today. Returns the recipe slug for the meal scheduled for today.
If no meal is scheduled nothing is returned If no meal is scheduled nothing is returned

View file

@ -1,6 +1,7 @@
from fastapi import APIRouter, Depends
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 fastapi import APIRouter, Depends from mealie.routes.deps import get_current_user
from mealie.schema.meal import MealPlanInDB from mealie.schema.meal import MealPlanInDB
from mealie.schema.recipe import Recipe from mealie.schema.recipe import Recipe
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
@ -9,13 +10,15 @@ router = APIRouter(prefix="/api/meal-plans", tags=["Meal Plan"])
@router.get("/{id}/shopping-list") @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 #! Refactor into Single Database Call
mealplan = db.meals.get(session, id) mealplan = db.meals.get(session, id)
mealplan: MealPlanInDB mealplan: MealPlanInDB
slugs = [x.slug for x in mealplan.meals] slugs = [x.slug for x in mealplan.meals]
recipes: list[Recipe] = [db.recipes.get(session, x) for x in slugs] 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 [{"name": x.name, "recipeIngredient": x.recipeIngredient} for x in recipes if x]
return ingredients

View file

@ -2,16 +2,17 @@ import operator
import shutil import shutil
from typing import List from typing import List
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
from mealie.core.config import MIGRATION_DIR from mealie.core.config import MIGRATION_DIR
from mealie.db.db_setup import generate_session 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.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.chowdown import chowdown_migrate as chowdow_migrate
from mealie.services.migrations.nextcloud import migrate as nextcloud_migrate from mealie.services.migrations.nextcloud import migrate as nextcloud_migrate
from sqlalchemy.orm.session import Session 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]) @router.get("", response_model=List[Migrations])

View file

@ -1,3 +1,4 @@
from mealie.routes.deps import get_current_user
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 fastapi import APIRouter, Depends from fastapi import APIRouter, Depends
@ -26,7 +27,7 @@ def get_all_recipes_by_category(category: str, session: Session = Depends(genera
@router.delete("/{category}") @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 """Removes a recipe category from the database. Deleting a
category does not impact a recipe. The category will be removed category does not impact a recipe. The category will be removed
from any recipes that contain it""" from any recipes that contain it"""

View file

@ -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 import APIRouter, Depends, File, Form, HTTPException
from fastapi.logger import logger from fastapi.logger import logger
from fastapi.responses import FileResponse 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.recipe import Recipe, RecipeURLIn
from mealie.schema.snackbar import SnackResponse from mealie.schema.snackbar import SnackResponse
from mealie.services.image_services import read_image, write_image 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) @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""" """ Takes in a JSON string and loads data into the database as a new entry"""
recipe: Recipe = db.recipes.create(session, data.dict()) 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) @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 """ """ Takes in a URL and attempts to scrape data and load it into the database """
recipe = create_from_url(url.url) 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}") @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. """ """ Updates a recipe by existing slug and data. """
recipe: Recipe = db.recipes.update(session, recipe_slug, data.dict()) 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}") @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 """ """ Deletes a recipe by slug """
try: try:
@ -77,6 +95,7 @@ def update_recipe_image(
image: bytes = File(...), image: bytes = File(...),
extension: str = Form(...), extension: str = Form(...),
session: Session = Depends(generate_session), session: Session = Depends(generate_session),
current_user=Depends(get_current_user),
): ):
""" Removes an existing image and replaces it with the incoming file. """ """ Removes an existing image and replaces it with the incoming file. """
response = write_image(recipe_slug, image, extension) response = write_image(recipe_slug, image, extension)

View file

@ -1,10 +1,9 @@
from fastapi import APIRouter, Depends
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 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 sqlalchemy.orm.session import Session
from mealie.schema.snackbar import SnackResponse
from mealie.schema.snackbar import SnackResponse
router = APIRouter(tags=["Recipes"]) router = APIRouter(tags=["Recipes"])
@ -27,7 +26,9 @@ def get_all_recipes_by_tag(tag: str, session: Session = Depends(generate_session
@router.delete("/{tag}") @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 """Removes a recipe tag from the database. Deleting a
tag does not impact a recipe. The tag will be removed tag does not impact a recipe. The tag will be removed
from any recipes that contain it""" from any recipes that contain it"""

View file

@ -57,7 +57,12 @@ async def get_single_page(
@router.put("/{id}") @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 """ """ Removes a custom page from the database """
return db.custom_pages.update(session, id, data.dict()) return db.custom_pages.update(session, id, data.dict())

View file

@ -1,13 +1,12 @@
from fastapi import APIRouter, Depends
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 fastapi import APIRouter, Depends from mealie.routes.deps import get_current_user
from mealie.schema.settings import SiteSettings from mealie.schema.settings import SiteSettings
from mealie.schema.snackbar import SnackResponse from mealie.schema.snackbar import SnackResponse
from mealie.schema.user import GroupInDB, UserInDB from mealie.schema.user import GroupInDB, UserInDB
from sqlalchemy.orm.session import Session
from mealie.utils.post_webhooks import post_webhooks from mealie.utils.post_webhooks import post_webhooks
from sqlalchemy.orm.session import Session
from mealie.routes.deps import get_current_user
router = APIRouter(prefix="/api/site-settings", tags=["Settings"]) router = APIRouter(prefix="/api/site-settings", tags=["Settings"])
@ -20,7 +19,11 @@ def get_main_settings(session: Session = Depends(generate_session)):
@router.put("") @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 """ """ Returns Site Settings """
db.settings.update(session, 1, data.dict()) db.settings.update(session, 1, data.dict())

View file

@ -1,9 +1,10 @@
from mealie.db.db_setup import generate_session
from fastapi import APIRouter, Depends 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 mealie.schema.theme import SiteTheme
from sqlalchemy.orm.session import Session from sqlalchemy.orm.session import Session
from mealie.schema.snackbar import SnackResponse
from mealie.db.database import db
router = APIRouter(prefix="/api", tags=["Themes"]) router = APIRouter(prefix="/api", tags=["Themes"])
@ -16,7 +17,7 @@ def get_all_themes(session: Session = Depends(generate_session)):
@router.post("/themes/create") @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 """ """ Creates a site color theme database entry """
db.themes.create(session, data.dict()) 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}") @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 """ """ Update a theme database entry """
db.themes.update(session, theme_name, data.dict()) 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}") @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 """ """ Deletes theme from the database """
db.themes.delete(session, theme_name) db.themes.delete(session, theme_name)

View file

@ -16,8 +16,8 @@ def backup_data():
} }
def test_import(api_client, 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) response = api_client.post("/api/backups/dev_sample_data_2021-Feb-13.zip/import", json=backup_data, headers=token)
assert response.status_code == 200 assert response.status_code == 200
for key, value in json.loads(response.content).items(): for key, value in json.loads(response.content).items():

View file

@ -23,11 +23,10 @@ def get_meal_plan_template(first=None, second=None):
} }
@pytest.fixture @pytest.fixture(scope="session")
def slug_1(api_client): def slug_1(api_client, token):
# Slug 1 # Slug 1
slug_1 = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_test_data[0].url}, headers=token)
slug_1 = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_test_data[0].url})
slug_1 = json.loads(slug_1.content) slug_1 = json.loads(slug_1.content)
yield slug_1 yield slug_1
@ -35,10 +34,10 @@ def slug_1(api_client):
api_client.delete(RECIPES_PREFIX + "/" + slug_1) api_client.delete(RECIPES_PREFIX + "/" + slug_1)
@pytest.fixture @pytest.fixture(scope="session")
def slug_2(api_client): def slug_2(api_client, token):
# Slug 2 # 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) slug_2 = json.loads(slug_2.content)
yield slug_2 yield slug_2
@ -99,6 +98,6 @@ def test_delete_mealplan(api_client, token):
existing_mealplan = existing_mealplan[0] existing_mealplan = existing_mealplan[0]
plan_uid = existing_mealplan.get("uid") 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 assert response.status_code == 200

View file

@ -21,11 +21,10 @@ def chowdown_zip():
zip_copy.unlink() 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( response = api_client.post(
f"{MIGRATIONS_PREFIX}/chowdown/upload", f"{MIGRATIONS_PREFIX}/chowdown/upload", files={"archive": chowdown_zip.open("rb")}, headers=token
files={"archive": chowdown_zip.open("rb")},
) )
assert response.status_code == 200 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() assert MIGRATION_DIR.joinpath("chowdown", chowdown_zip.name).is_file()
def test_import_chowdown_directory(api_client, chowdown_zip): def test_import_chowdown_directory(api_client, chowdown_zip, token):
api_client.delete(f"{RECIPES_PREFIX}/roasted-okra") # TODO: Manage Test Data better api_client.delete(f"{RECIPES_PREFIX}/roasted-okra", headers=token) # TODO: Manage Test Data better
selection = chowdown_zip.name 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 assert response.status_code == 200
@ -48,9 +47,9 @@ def test_import_chowdown_directory(api_client, chowdown_zip):
assert response.status_code == 200 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 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 response.status_code == 200
assert not MIGRATION_DIR.joinpath(chowdown_zip.name).is_file() assert not MIGRATION_DIR.joinpath(chowdown_zip.name).is_file()
@ -70,11 +69,9 @@ def nextcloud_zip():
zip_copy.unlink() 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( response = api_client.post(
f"{MIGRATIONS_PREFIX}/nextcloud/upload", f"{MIGRATIONS_PREFIX}/nextcloud/upload", files={"archive": nextcloud_zip.open("rb")}, headers=token
files={"archive": nextcloud_zip.open("rb")},
) )
assert response.status_code == 200 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() 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 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 assert response.status_code == 200
@ -96,9 +93,9 @@ def test_import_nextcloud_directory(api_client, nextcloud_zip):
assert response.status_code == 200 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 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 response.status_code == 200
assert not MIGRATION_DIR.joinpath(nextcloud_zip.name).is_file() assert not MIGRATION_DIR.joinpath(nextcloud_zip.name).is_file()

View file

@ -7,22 +7,23 @@ from tests.utils.routes import RECIPES_ALL, RECIPES_CREATE, RECIPES_CREATE_URL,
@pytest.mark.parametrize("recipe_data", recipe_test_data) @pytest.mark.parametrize("recipe_data", recipe_test_data)
def test_create_by_url(api_client, recipe_data: RecipeTestData): def test_create_by_url(api_client, recipe_data: RecipeTestData, token):
response = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_data.url}) 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 response.status_code == 201
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): def test_create_by_json(api_client, token):
api_client.delete(f"{RECIPES_PREFIX}/banana-bread") api_client.delete(f"{RECIPES_PREFIX}/banana-bread", headers=token)
response = api_client.post(RECIPES_CREATE, json=raw_recipe) response = api_client.post(RECIPES_CREATE, json=raw_recipe, headers=token)
assert response.status_code == 201 assert response.status_code == 201
assert json.loads(response.text) == "banana-bread" assert json.loads(response.text) == "banana-bread"
def test_create_no_image(api_client): def test_create_no_image(api_client, token):
response = api_client.post(RECIPES_CREATE, json=raw_recipe_no_image) response = api_client.post(RECIPES_CREATE, json=raw_recipe_no_image, headers=token)
assert response.status_code == 201 assert response.status_code == 201
assert json.loads(response.text) == "banana-bread-no-image" 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) @pytest.mark.parametrize("recipe_data", recipe_test_data)
def test_read_update(api_client, recipe_data): def test_read_update(api_client, recipe_data, token):
response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}") response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", headers=token)
assert response.status_code == 200 assert response.status_code == 200
recipe = json.loads(response.content) recipe = json.loads(response.content)
@ -61,7 +62,7 @@ def test_read_update(api_client, recipe_data):
test_categories = ["one", "two", "three"] test_categories = ["one", "two", "three"]
recipe["recipeCategory"] = test_categories 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 response.status_code == 200
assert json.loads(response.text) == recipe_data.expected_slug 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) @pytest.mark.parametrize("recipe_data", recipe_test_data)
def test_rename(api_client, recipe_data): def test_rename(api_client, recipe_data, token):
response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}") response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", headers=token)
assert response.status_code == 200 assert response.status_code == 200
recipe = json.loads(response.content) recipe = json.loads(response.text)
new_name = recipe.get("name") + "-rename" new_name = recipe.get("name") + "-rename"
new_slug = slugify(new_name) new_slug = slugify(new_name)
recipe["name"] = 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 response.status_code == 200
assert json.loads(response.text) == new_slug 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) @pytest.mark.parametrize("recipe_data", recipe_test_data)
def test_delete(api_client, recipe_data): def test_delete(api_client, recipe_data, token):
response = api_client.delete(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}") response = api_client.delete(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", headers=token)
assert response.status_code == 200 assert response.status_code == 200

View file

@ -1,14 +1,9 @@
import json import json
from mealie.schema.settings import SiteSettings
from mealie.schema.theme import SiteTheme
import pytest import pytest
from tests.utils.routes import ( from mealie.schema.settings import SiteSettings
SETTINGS_PREFIX, from mealie.schema.theme import SiteTheme
SETTINGS_UPDATE, from tests.utils.routes import SETTINGS_PREFIX, SETTINGS_UPDATE, THEMES_CREATE, THEMES_PREFIX
THEMES_CREATE,
THEMES_PREFIX,
)
@pytest.fixture(scope="function") @pytest.fixture(scope="function")
@ -45,11 +40,11 @@ def test_default_settings(api_client, default_settings):
assert json.loads(response.content) == 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["language"] = "fr"
default_settings["showRecent"] = False 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 assert response.status_code == 200
@ -63,12 +58,12 @@ def test_default_theme(api_client, default_theme):
assert json.loads(response.content) == 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 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 response.status_code == 200
assert json.loads(response.content) == new_theme 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 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]: 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 assert response.status_code == 200

View file

@ -6,12 +6,12 @@ class RecipeTestData:
recipe_test_data = [ recipe_test_data = [
RecipeTestData( RecipeTestData(
url="https://www.bonappetit.com/recipe/rustic-shrimp-toasts", url="https://www.bonappetit.com/recipe/spinach-thepla-and-vaghareli-dahi",
expected_slug="rustic-shrimp-toasts", expected_slug="thepla-recipe-with-vaghareli-dahi",
), ),
RecipeTestData( RecipeTestData(
url="https://www.allrecipes.com/recipe/282905/honey-garlic-shrimp/", url="https://www.bonappetit.com/recipe/classic-coleslaw",
expected_slug="honey-garlic-shrimp", expected_slug="traditional-coleslaw-recipe",
), ),
] ]