diff --git a/mealie/app.py b/mealie/app.py index 5f829d4dc..025c3d190 100644 --- a/mealie/app.py +++ b/mealie/app.py @@ -90,8 +90,8 @@ app.include_router(static_routes.router) # Generate API Documentation -if not PRODUCTION: - generate_api_docs(app) +# if not PRODUCTION: +# generate_api_docs(app) start_scheduler() diff --git a/mealie/db/db_base.py b/mealie/db/db_base.py index cbc2da4a9..63727743d 100644 --- a/mealie/db/db_base.py +++ b/mealie/db/db_base.py @@ -25,7 +25,7 @@ class BaseDocument: def get_all_limit_columns( self, session: Session, fields: List[str], limit: int = None - ) -> list[SqlAlchemyBase]: + ) -> List[SqlAlchemyBase]: """Queries the database for the selected model. Restricts return responses to the keys specified under "fields" diff --git a/mealie/routes/backup_routes.py b/mealie/routes/backup_routes.py index 7dcc4020d..076a334d7 100644 --- a/mealie/routes/backup_routes.py +++ b/mealie/routes/backup_routes.py @@ -11,7 +11,7 @@ from sqlalchemy.orm.session import Session from starlette.responses import FileResponse from utils.snackbar import SnackResponse -router = APIRouter(prefix="/api/backups", tags=["Import / Export"]) +router = APIRouter(prefix="/api/backups", tags=["Backups"]) @router.get("/available", response_model=Imports) diff --git a/mealie/routes/meal_routes.py b/mealie/routes/meal_routes.py index baea93a27..6145676fd 100644 --- a/mealie/routes/meal_routes.py +++ b/mealie/routes/meal_routes.py @@ -65,7 +65,7 @@ def delete_meal_plan(plan_id, db: Session = Depends(generate_session)): return SnackResponse.success("Mealplan Deleted") -@router.get("/today/", tags=["Meal Plan"]) +@router.get("/today", tags=["Meal Plan"]) def get_today(db: Session = Depends(generate_session)): """ Returns the recipe slug for the meal scheduled for today. diff --git a/mealie/services/scrape_services.py b/mealie/services/scrape_services.py index fc9ae6d95..106d27cf3 100644 --- a/mealie/services/scrape_services.py +++ b/mealie/services/scrape_services.py @@ -88,7 +88,7 @@ def normalize_time(time_entry) -> str: def normalize_data(recipe_data: dict) -> dict: recipe_data["totalTime"] = normalize_time(recipe_data.get("totalTime")) - recipe_data["description"] = cleanhtml(recipe_data.get("description")) + recipe_data["description"] = cleanhtml(recipe_data.get("description", "")) recipe_data["prepTime"] = normalize_time(recipe_data.get("prepTime")) recipe_data["performTime"] = normalize_time(recipe_data.get("performTime")) recipe_data["recipeYield"] = normalize_yield(recipe_data.get("recipeYield")) diff --git a/mealie/services/settings_services.py b/mealie/services/settings_services.py index 3e3c8398e..e7f1d7c34 100644 --- a/mealie/services/settings_services.py +++ b/mealie/services/settings_services.py @@ -141,6 +141,8 @@ def default_settings_init(): default_entry = SiteSettings(name="main", webhooks=webhooks) document = db.settings.save_new(session, default_entry.dict(), webhooks.dict()) + session.close() + if not sql_exists: default_settings_init() diff --git a/mealie/tests/conftest.py b/mealie/tests/conftest.py index 2ec4a9e3b..d30411537 100644 --- a/mealie/tests/conftest.py +++ b/mealie/tests/conftest.py @@ -23,6 +23,8 @@ def override_get_db(): db.close() + + @fixture(scope="session") def api_client(): diff --git a/mealie/tests/test_routes/test_meal_routes.py b/mealie/tests/test_routes/test_meal_routes.py index 7107834cb..f86e77c48 100644 --- a/mealie/tests/test_routes/test_meal_routes.py +++ b/mealie/tests/test_routes/test_meal_routes.py @@ -2,6 +2,13 @@ import json import pytest from tests.test_routes.utils.routes_data import recipe_test_data +from tests.utils.routes import ( + MEALPLAN_ALL, + MEALPLAN_CREATE, + MEALPLAN_PREFIX, + RECIPES_CREATE_URL, + RECIPES_PREFIX, +) def get_meal_plan_template(first=None, second=None): @@ -23,30 +30,30 @@ def get_meal_plan_template(first=None, second=None): } +## Meal Routes + + @pytest.fixture def slug_1(api_client): # Slug 1 - slug_1 = api_client.post( - "/api/recipe/create-url/", json={"url": recipe_test_data[0].url} - ) + + slug_1 = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_test_data[0].url}) slug_1 = json.loads(slug_1.content) yield slug_1 - api_client.delete(f"/api/recipe/{recipe_test_data[1].expected_slug}/delete/") + api_client.delete(RECIPES_PREFIX + "/" + slug_1) @pytest.fixture def slug_2(api_client): # Slug 2 - slug_2 = api_client.post( - "/api/recipe/create-url/", json={"url": recipe_test_data[1].url} - ) + slug_2 = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_test_data[1].url}) slug_2 = json.loads(slug_2.content) yield slug_2 - api_client.delete(f"/api/recipe/{recipe_test_data[0].expected_slug}/delete/") + api_client.delete(RECIPES_PREFIX + "/" + slug_2) def test_create_mealplan(api_client, slug_1, slug_2): @@ -54,12 +61,12 @@ def test_create_mealplan(api_client, slug_1, slug_2): meal_plan["meals"][0]["slug"] = slug_1 meal_plan["meals"][1]["slug"] = slug_2 - response = api_client.post("/api/meal-plan/create/", json=meal_plan) + response = api_client.post(MEALPLAN_CREATE, json=meal_plan) assert response.status_code == 200 def test_read_mealplan(api_client, slug_1, slug_2): - response = api_client.get("/api/meal-plan/all/") + response = api_client.get(MEALPLAN_ALL) assert response.status_code == 200 @@ -74,7 +81,7 @@ def test_read_mealplan(api_client, slug_1, slug_2): def test_update_mealplan(api_client, slug_1, slug_2): - response = api_client.get("/api/meal-plan/all/") + response = api_client.get(MEALPLAN_ALL) existing_mealplan = json.loads(response.text) existing_mealplan = existing_mealplan[0] @@ -84,13 +91,11 @@ def test_update_mealplan(api_client, slug_1, slug_2): existing_mealplan["meals"][0]["slug"] = slug_2 existing_mealplan["meals"][1]["slug"] = slug_1 - response = api_client.post( - f"/api/meal-plan/{plan_uid}/update/", json=existing_mealplan - ) + response = api_client.put(f"{MEALPLAN_PREFIX}/{plan_uid}", json=existing_mealplan) assert response.status_code == 200 - response = api_client.get("/api/meal-plan/all/") + response = api_client.get(MEALPLAN_ALL) existing_mealplan = json.loads(response.text) existing_mealplan = existing_mealplan[0] @@ -99,11 +104,13 @@ def test_update_mealplan(api_client, slug_1, slug_2): def test_delete_mealplan(api_client): - response = api_client.get("/api/meal-plan/all/") + response = api_client.get(MEALPLAN_ALL) + + assert response.status_code == 200 existing_mealplan = json.loads(response.text) existing_mealplan = existing_mealplan[0] plan_uid = existing_mealplan.get("uid") - response = api_client.delete(f"/api/meal-plan/{plan_uid}/delete/") + response = api_client.delete(f"{MEALPLAN_PREFIX}/{plan_uid}") assert response.status_code == 200 diff --git a/mealie/tests/test_routes/test_migration_routes.py b/mealie/tests/test_routes/test_migration_routes.py index 8706a02c1..2bb35ec93 100644 --- a/mealie/tests/test_routes/test_migration_routes.py +++ b/mealie/tests/test_routes/test_migration_routes.py @@ -4,6 +4,7 @@ import shutil import pytest from app_config import MIGRATION_DIR from tests.test_config import TEST_CHOWDOWN_DIR, TEST_NEXTCLOUD_DIR +from tests.utils.routes import MIGRATIONS_PREFIX, RECIPES_PREFIX ### Chowdown @@ -23,7 +24,8 @@ def chowdown_zip(): def test_upload_chowdown_zip(api_client, chowdown_zip): response = api_client.post( - "/api/migrations/chowdown/upload/", files={"archive": chowdown_zip.open("rb")} + f"{MIGRATIONS_PREFIX}/chowdown/upload", + files={"archive": chowdown_zip.open("rb")}, ) assert response.status_code == 200 @@ -33,7 +35,7 @@ def test_upload_chowdown_zip(api_client, chowdown_zip): def test_import_chowdown_directory(api_client, chowdown_zip): selection = chowdown_zip.name - response = api_client.post(f"/api/migrations/chowdown/{selection}/import/") + response = api_client.post(f"{MIGRATIONS_PREFIX}/chowdown/{selection}/import") assert response.status_code == 200 @@ -41,13 +43,13 @@ def test_import_chowdown_directory(api_client, chowdown_zip): assert report["failed"] == [] expected_slug = "roasted-okra" - response = api_client.get(f"/api/recipe/{expected_slug}/") + response = api_client.get(f"{RECIPES_PREFIX}/{expected_slug}") assert response.status_code == 200 def test_delete_chowdown_migration_data(api_client, chowdown_zip): selection = chowdown_zip.name - response = api_client.delete(f"/api/migrations/chowdown/{selection}/delete/") + response = api_client.delete(f"{MIGRATIONS_PREFIX}/chowdown/{selection}/delete") assert response.status_code == 200 assert not MIGRATION_DIR.joinpath(chowdown_zip.name).is_file() @@ -70,7 +72,8 @@ def nextcloud_zip(): def test_upload_nextcloud_zip(api_client, nextcloud_zip): response = api_client.post( - "/api/migrations/nextcloud/upload/", files={"archive": nextcloud_zip.open("rb")} + f"{MIGRATIONS_PREFIX}/nextcloud/upload", + files={"archive": nextcloud_zip.open("rb")}, ) assert response.status_code == 200 @@ -80,7 +83,7 @@ def test_upload_nextcloud_zip(api_client, nextcloud_zip): def test_import_nextcloud_directory(api_client, nextcloud_zip): selection = nextcloud_zip.name - response = api_client.post(f"/api/migrations/nextcloud/{selection}/import/") + response = api_client.post(f"{MIGRATIONS_PREFIX}/nextcloud/{selection}/import") assert response.status_code == 200 @@ -88,13 +91,13 @@ def test_import_nextcloud_directory(api_client, nextcloud_zip): assert report["failed"] == [] expected_slug = "air-fryer-shrimp" - response = api_client.get(f"/api/recipe/{expected_slug}/") + response = api_client.get(f"{RECIPES_PREFIX}/{expected_slug}") assert response.status_code == 200 def test_delete__nextcloud_migration_data(api_client, nextcloud_zip): selection = nextcloud_zip.name - response = api_client.delete(f"/api/migrations/nextcloud/{selection}/delete/") + response = api_client.delete(f"{MIGRATIONS_PREFIX}/nextcloud/{selection}/delete") assert response.status_code == 200 assert not MIGRATION_DIR.joinpath(nextcloud_zip.name).is_file() diff --git a/mealie/tests/test_routes/test_recipe_routes.py b/mealie/tests/test_routes/test_recipe_routes.py index 1543df416..286513abe 100644 --- a/mealie/tests/test_routes/test_recipe_routes.py +++ b/mealie/tests/test_routes/test_recipe_routes.py @@ -2,32 +2,31 @@ import json import pytest from slugify import slugify -from tests.test_routes.utils.routes_data import ( - RecipeTestData, - raw_recipe, - raw_recipe_no_image, - recipe_test_data, -) +from tests.test_routes.utils.routes_data import (RecipeTestData, raw_recipe, + raw_recipe_no_image, + recipe_test_data) +from tests.utils.routes import (RECIPES_ALL, RECIPES_CREATE, + RECIPES_CREATE_URL, RECIPES_PREFIX) @pytest.mark.parametrize("recipe_data", recipe_test_data) def test_create_by_url(api_client, recipe_data: RecipeTestData): - response = api_client.post("/api/recipe/create-url/", json={"url": recipe_data.url}) + response = api_client.post(RECIPES_CREATE_URL, json={"url": recipe_data.url}) assert response.status_code == 201 assert json.loads(response.text) == recipe_data.expected_slug def test_create_by_json(api_client): - response = api_client.post("/api/recipe/create/", json=raw_recipe) + response = api_client.post(RECIPES_CREATE, json=raw_recipe) - assert response.status_code == 200 + assert response.status_code == 201 assert json.loads(response.text) == "banana-bread" def test_create_no_image(api_client): - response = api_client.post("/api/recipe/create/", json=raw_recipe_no_image) + response = api_client.post(RECIPES_CREATE, json=raw_recipe_no_image) - assert response.status_code == 200 + assert response.status_code == 201 assert json.loads(response.text) == "banana-bread-no-image" @@ -35,24 +34,24 @@ def test_create_no_image(api_client): # data = {"image": test_image.open("rb").read(), "extension": "jpg"} # response = api_client.post( -# "/api/recipe/banana-bread-no-image/update/image/", files=data +# "{RECIPES_PREFIX}banana-bread-no-image/update/image/", files=data # ) # assert response.status_code == 200 -# response = api_client.get("/api/recipe/banana-bread-no-image/update/image/") +# response = api_client.get("{RECIPES_PREFIX}banana-bread-no-image/update/image/") def test_read_all_post(api_client): response = api_client.post( - "/api/all-recipes/", json={"properties": ["slug", "description", "rating"]} + RECIPES_ALL, json={"properties": ["slug", "description", "rating"]} ) assert response.status_code == 200 @pytest.mark.parametrize("recipe_data", recipe_test_data) def test_read_update(api_client, recipe_data): - response = api_client.get(f"/api/recipe/{recipe_data.expected_slug}/") + response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}") assert response.status_code == 200 recipe = json.loads(response.content) @@ -66,14 +65,14 @@ def test_read_update(api_client, recipe_data): test_categories = ["one", "two", "three"] recipe["categories"] = test_categories - response = api_client.post( - f"/api/recipe/{recipe_data.expected_slug}/update/", json=recipe + response = api_client.put( + f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", json=recipe ) assert response.status_code == 200 assert json.loads(response.text) == recipe_data.expected_slug - response = api_client.get(f"/api/recipe/{recipe_data.expected_slug}/") + response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}") recipe = json.loads(response.content) @@ -83,7 +82,7 @@ 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"/api/recipe/{recipe_data.expected_slug}/") + response = api_client.get(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}") assert response.status_code == 200 recipe = json.loads(response.content) @@ -91,8 +90,8 @@ def test_rename(api_client, recipe_data): new_slug = slugify(new_name) recipe["name"] = new_name - response = api_client.post( - f"/api/recipe/{recipe_data.expected_slug}/update/", json=recipe + response = api_client.put( + f"{RECIPES_PREFIX}/{recipe_data.expected_slug}", json=recipe ) assert response.status_code == 200 @@ -103,5 +102,5 @@ 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"/api/recipe/{recipe_data.expected_slug}/delete/") + response = api_client.delete(f"{RECIPES_PREFIX}/{recipe_data.expected_slug}") assert response.status_code == 200 diff --git a/mealie/tests/test_routes/test_settings_routes.py b/mealie/tests/test_routes/test_settings_routes.py index a8ef3b62a..f5a748179 100644 --- a/mealie/tests/test_routes/test_settings_routes.py +++ b/mealie/tests/test_routes/test_settings_routes.py @@ -1,6 +1,12 @@ import json import pytest +from tests.utils.routes import ( + SETTINGS_PREFIX, + SETTINGS_UPDATE, + THEMES_CREATE, + THEMES_PREFIX, +) @pytest.fixture(scope="function") @@ -26,7 +32,7 @@ def default_theme(api_client): "error": "#EF5350", }, } - api_client.post("/api/site-settings/themes/create/", json=default_theme) + api_client.post(THEMES_CREATE, json=default_theme) return default_theme @@ -48,7 +54,7 @@ def new_theme(): def test_default_settings(api_client, default_settings): - response = api_client.get("/api/site-settings/") + response = api_client.get(SETTINGS_PREFIX) assert response.status_code == 200 @@ -62,47 +68,45 @@ def test_update_settings(api_client, default_settings): "https://test3.url.com", ] - response = api_client.post("/api/site-settings/update/", json=default_settings) + response = api_client.put(SETTINGS_UPDATE, json=default_settings) assert response.status_code == 200 - response = api_client.get("/api/site-settings/") + response = api_client.get(SETTINGS_PREFIX) assert json.loads(response.content) == default_settings def test_default_theme(api_client, default_theme): - response = api_client.get("/api/site-settings/themes/default/") + response = api_client.get(f"{THEMES_PREFIX}/default") assert response.status_code == 200 assert json.loads(response.content) == default_theme def test_create_theme(api_client, new_theme): - response = api_client.post("/api/site-settings/themes/create/", json=new_theme) + response = api_client.post(THEMES_CREATE, json=new_theme) assert response.status_code == 200 - response = api_client.get(f"/api/site-settings/themes/{new_theme.get('name')}/") + response = api_client.get(f"{THEMES_PREFIX}/{new_theme.get('name')}") assert response.status_code == 200 assert json.loads(response.content) == new_theme def test_read_all_themes(api_client, default_theme, new_theme): - response = api_client.get("/api/site-settings/themes/") + response = api_client.get(THEMES_PREFIX) assert response.status_code == 200 assert json.loads(response.content) == [default_theme, new_theme] def test_read_theme(api_client, default_theme, new_theme): for theme in [default_theme, new_theme]: - response = api_client.get(f"/api/site-settings/themes/{theme.get('name')}/") + response = api_client.get(f"{THEMES_PREFIX}/{theme.get('name')}") assert response.status_code == 200 assert json.loads(response.content) == theme def test_delete_theme(api_client, default_theme, new_theme): for theme in [default_theme, new_theme]: - response = api_client.delete( - f"/api/site-settings/themes/{theme.get('name')}/delete/" - ) + response = api_client.delete(f"{THEMES_PREFIX}/{theme.get('name')}") assert response.status_code == 200 diff --git a/mealie/tests/test_routes/test_tags_categories.py b/mealie/tests/test_routes/test_tags_categories.py new file mode 100644 index 000000000..b28b04f64 --- /dev/null +++ b/mealie/tests/test_routes/test_tags_categories.py @@ -0,0 +1,3 @@ + + + diff --git a/mealie/tests/utils.py b/mealie/tests/utils.py index 6e02cf326..e69de29bb 100644 --- a/mealie/tests/utils.py +++ b/mealie/tests/utils.py @@ -1 +0,0 @@ -test_ \ No newline at end of file diff --git a/mealie/tests/utils/__init__.py b/mealie/tests/utils/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/mealie/tests/utils/routes.py b/mealie/tests/utils/routes.py new file mode 100644 index 000000000..6b58a7a25 --- /dev/null +++ b/mealie/tests/utils/routes.py @@ -0,0 +1,31 @@ +BASE = "/api" + +ALL_RECIPES = BASE + "/recipes" + +RECIPES_PREFIX = BASE + "/recipes" +RECIPES_ALL = RECIPES_PREFIX +RECIPES_CREATE = RECIPES_PREFIX + "/create" +RECIPES_CREATE_URL = RECIPES_PREFIX + "/create-url" + +CATEGORIES_PREFIX = BASE + "/categories" +TAGS_PREFIX = BASE + "/tags" + +MEALPLAN_PREFIX = BASE + "/meal-plans" +MEALPLAN_ALL = MEALPLAN_PREFIX + "/all" +MEALPLAN_CREATE = MEALPLAN_PREFIX + "/create" +MEALPLAN_THIS_WEEK = MEALPLAN_PREFIX + "/this-week" +MEALPLAN_TODAY = MEALPLAN_PREFIX + "/today" + +SETTINGS_PREFIX = BASE + "/site-settings" +SETTINGS_UPDATE = SETTINGS_PREFIX +TEST_WEBHOOKS = SETTINGS_PREFIX + "/webhooks/test" + +THEMES_PREFIX = BASE + "/themes" +THEMES_CREATE = THEMES_PREFIX + "/create" + +BACKUPS_PREFIX = BASE + "/backups" +BACKUPS_AVAILABLE = BACKUPS_PREFIX + "/available" +BACKUPS_EXPORT = BACKUPS_PREFIX + "/export/database" +BACKUPS_UPLOAD = BACKUPS_PREFIX + "/upload" + +MIGRATIONS_PREFIX = BASE + "/migrations"