diff --git a/.flake8 b/.flake8 index b90fca4d20a6..b764320ebfd3 100644 --- a/.flake8 +++ b/.flake8 @@ -1,6 +1,6 @@ [flake8] ignore = [ E501 # Line Length - See Black Config in pyproject.toml - E722 # Bare Exception | Temporary + E402 # Import Not at Top of File ] exclude = _all_models.py diff --git a/.gitignore b/.gitignore index e356f2f9db67..0f4444b6ed6f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,13 +3,11 @@ *__pycache__/ *.py[cod] *$py.class + # frontend/.env.development docs/site/ -mealie/temp/* -mealie/temp/api.html -.temp/ +*temp* .secret -!*/components/Recipe/Parts dev/data/backups/* dev/data/debug/* @@ -17,14 +15,6 @@ dev/data/img/* dev/data/migration/* dev/data/users/* -#Exception to keep folders -!mealie/dist/.gitkeep -!dev/data/backups/.gitkeep -!dev/data/backups/dev_sample_data* -!dev/data/debug/.gitkeep -!dev/data/migration/.gitkeep -!dev/data/img/.gitkeep - .DS_Store node_modules @@ -148,16 +138,11 @@ ENV/ # mypy .mypy_cache/ -# IDE settings -# .vscode/ - # Node Modules node_modules/ -mealie/data/debug/last_recipe.json +*.db *.sqlite -dev/data/db/test.db scratch.py dev/data/backups/dev_sample_data*.zip -dev/data/backups/dev_sample_data*.zip !dev/data/backups/test*.zip -dev/data/recipes/* +dev/data/recipes/* \ No newline at end of file diff --git a/frontend/src/components/Recipe/Parts/Helpers/SettingsMenu.vue b/frontend/src/components/Recipe/Parts/Helpers/SettingsMenu.vue new file mode 100644 index 000000000000..75445f160a90 --- /dev/null +++ b/frontend/src/components/Recipe/Parts/Helpers/SettingsMenu.vue @@ -0,0 +1,55 @@ + + + + + diff --git a/frontend/src/components/Recipe/RecipeEditor/index.vue b/frontend/src/components/Recipe/RecipeEditor/index.vue index cd675c5db65d..16225a952111 100644 --- a/frontend/src/components/Recipe/RecipeEditor/index.vue +++ b/frontend/src/components/Recipe/RecipeEditor/index.vue @@ -8,6 +8,11 @@ :slug="value.slug" @refresh="$emit('upload')" /> + @@ -122,6 +127,7 @@ import Instructions from "@/components/Recipe/Parts/Instructions"; import Ingredients from "@/components/Recipe/Parts/Ingredients"; import Assets from "@/components/Recipe/Parts/Assets.vue"; import Notes from "@/components/Recipe/Parts/Notes.vue"; +import SettingsMenu from "@/components/Recipe/Parts/Helpers/SettingsMenu.vue"; export default { components: { BulkAdd, @@ -133,6 +139,7 @@ export default { Ingredients, Assets, Notes, + SettingsMenu, }, props: { value: Object, diff --git a/mealie/app.py b/mealie/app.py index 75b2bb7a6d78..403998cd010c 100644 --- a/mealie/app.py +++ b/mealie/app.py @@ -3,13 +3,10 @@ from fastapi import FastAPI from mealie.core import root_logger from mealie.core.config import APP_VERSION, settings -from mealie.routes import (backup_routes, debug_routes, migration_routes, - theme_routes, utility_routes) +from mealie.routes import backup_routes, debug_routes, migration_routes, theme_routes, utility_routes from mealie.routes.groups import groups from mealie.routes.mealplans import mealplans -from mealie.routes.recipe import (all_recipe_routes, category_routes, - recipe_assets, recipe_crud_routes, - tag_routes) +from mealie.routes.recipe import router as recipe_router from mealie.routes.site_settings import all_settings from mealie.routes.users import users @@ -30,15 +27,10 @@ def start_scheduler(): def api_routers(): # Authentication - app.include_router(utility_routes.router) app.include_router(users.router) app.include_router(groups.router) # Recipes - app.include_router(all_recipe_routes.router) - app.include_router(category_routes.router) - app.include_router(tag_routes.router) - app.include_router(recipe_crud_routes.router) - app.include_router(recipe_assets.router) + app.include_router(recipe_router) # Meal Routes app.include_router(mealplans.router) # Settings Routes @@ -49,6 +41,7 @@ def api_routers(): # Migration Routes app.include_router(migration_routes.router) app.include_router(debug_routes.router) + app.include_router(utility_routes.router) api_routers() diff --git a/mealie/core/config.py b/mealie/core/config.py index be080dfb64a5..bdae8d3924d2 100644 --- a/mealie/core/config.py +++ b/mealie/core/config.py @@ -120,7 +120,7 @@ class AppSettings(BaseSettings): DEFAULT_EMAIL: str = "changeme@email.com" DEFAULT_PASSWORD: str = "MyPassword" - TOKEN_TIME: int = 2 # Time in Hours + TOKEN_TIME: int = 2 # Time in Hours # Not Used! SFTP_USERNAME: Optional[str] diff --git a/mealie/core/security.py b/mealie/core/security.py index 4f9848cab17d..12cbe2257b6a 100644 --- a/mealie/core/security.py +++ b/mealie/core/security.py @@ -14,7 +14,7 @@ ALGORITHM = "HS256" def create_access_token(data: dict(), expires_delta: timedelta = None) -> str: to_encode = data.copy() expires_delta = expires_delta or timedelta(hours=settings.TOKEN_TIME) - + expire = datetime.utcnow() + expires_delta to_encode.update({"exp": expire}) diff --git a/mealie/db/db_base.py b/mealie/db/db_base.py index ede800379122..3b0c571681cd 100644 --- a/mealie/db/db_base.py +++ b/mealie/db/db_base.py @@ -137,4 +137,3 @@ class BaseDocument: session.delete(result) session.commit() - diff --git a/mealie/routes/backup_routes.py b/mealie/routes/backup_routes.py index bfb304441da6..864a1380ac6f 100644 --- a/mealie/routes/backup_routes.py +++ b/mealie/routes/backup_routes.py @@ -1,17 +1,15 @@ import operator import shutil -from typing import Optional from fastapi import APIRouter, Depends, File, HTTPException, UploadFile, status from mealie.core.config import app_dirs from mealie.core.security import create_file_token from mealie.db.db_setup import generate_session -from mealie.routes.deps import get_current_user, validate_file_token +from mealie.routes.deps import get_current_user from mealie.schema.backup import BackupJob, ImportJob, Imports, LocalBackup from mealie.services.backups import imports 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"], dependencies=[Depends(get_current_user)]) @@ -46,8 +44,8 @@ def export_database(data: BackupJob, session: Session = Depends(generate_session export_groups=data.options.groups, ) return {"export_path": export_path} - except: - raise HTTPException( status.HTTP_500_INTERNAL_SERVER_ERROR ) + except Exception: + raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR) @router.post("/upload", status_code=status.HTTP_200_OK) @@ -59,8 +57,7 @@ def upload_backup_file(archive: UploadFile = File(...)): shutil.copyfileobj(archive.file, buffer) if not dest.is_file: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) - + raise HTTPException(status.HTTP_400_BAD_REQUEST) @router.get("/{file_name}/download") @@ -95,8 +92,8 @@ def delete_backup(file_name: str): file_path = app_dirs.BACKUP_DIR.joinpath(file_name) if not file_path.is_file(): - raise HTTPException( status.HTTP_400_BAD_REQUEST ) + raise HTTPException(status.HTTP_400_BAD_REQUEST) try: file_path.unlink() - except: - raise HTTPException( status.HTTP_500_INTERNAL_SERVER_ERROR ) + except Exception: + raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR) diff --git a/mealie/routes/debug_routes.py b/mealie/routes/debug_routes.py index 8dc919683809..500ee742e8f2 100644 --- a/mealie/routes/debug_routes.py +++ b/mealie/routes/debug_routes.py @@ -1,5 +1,3 @@ -import json - from fastapi import APIRouter, Depends from mealie.core.config import APP_VERSION, app_dirs, settings from mealie.core.root_logger import LOGGER_FILE diff --git a/mealie/routes/groups/crud.py b/mealie/routes/groups/crud.py index 933076b43785..81262697da6f 100644 --- a/mealie/routes/groups/crud.py +++ b/mealie/routes/groups/crud.py @@ -39,8 +39,8 @@ async def create_group( try: db.groups.create(session, group_data.dict()) - except: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) + except Exception: + raise HTTPException(status.HTTP_400_BAD_REQUEST) @router.put("/{id}") @@ -61,23 +61,14 @@ async def delete_user_group( """ Removes a user group from the database """ if id == 1: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail='DEFAULT_GROUP' - ) + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="DEFAULT_GROUP") group: GroupInDB = db.groups.get(session, id) if not group: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail='GROUP_NOT_FOUND' - ) + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="GROUP_NOT_FOUND") if not group.users == []: - raise HTTPException( - status_code=status.HTTP_400_BAD_REQUEST, - detail='GROUP_WITH_USERS' - ) + raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="GROUP_WITH_USERS") db.groups.delete(session, id) diff --git a/mealie/routes/mealplans/crud.py b/mealie/routes/mealplans/crud.py index 54d8bf116ae3..7b58853d7533 100644 --- a/mealie/routes/mealplans/crud.py +++ b/mealie/routes/mealplans/crud.py @@ -43,8 +43,8 @@ def update_meal_plan( processed_plan = MealPlanInDB(uid=plan_id, **processed_plan.dict()) try: db.meals.update(session, plan_id, processed_plan.dict()) - except: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) + except Exception: + raise HTTPException(status.HTTP_400_BAD_REQUEST) @router.delete("/{plan_id}") @@ -53,8 +53,8 @@ def delete_meal_plan(plan_id, session: Session = Depends(generate_session), curr try: db.meals.delete(session, plan_id) - except: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) + except Exception: + raise HTTPException(status.HTTP_400_BAD_REQUEST) @router.get("/this-week", response_model=MealPlanInDB) @@ -90,8 +90,8 @@ def get_todays_image(session: Session = Depends(generate_session), group_name: s if recipe: recipe_image = image.read_image(recipe.slug, image_type=image.IMG_OPTIONS.ORIGINAL_IMAGE) else: - raise HTTPException( status.HTTP_404_NOT_FOUND ) + raise HTTPException(status.HTTP_404_NOT_FOUND) if recipe_image: return FileResponse(recipe_image) else: - raise HTTPException( status.HTTP_404_NOT_FOUND ) + raise HTTPException(status.HTTP_404_NOT_FOUND) diff --git a/mealie/routes/migration_routes.py b/mealie/routes/migration_routes.py index fc870b32e7e2..8fcfd78000cd 100644 --- a/mealie/routes/migration_routes.py +++ b/mealie/routes/migration_routes.py @@ -9,6 +9,7 @@ from mealie.routes.deps import get_current_user from mealie.schema.migration import MigrationFile, Migrations from mealie.services.migrations import migration from sqlalchemy.orm.session import Session +from fastapi import HTTPException router = APIRouter(prefix="/api/migrations", tags=["Migration"], dependencies=[Depends(get_current_user)]) @@ -52,8 +53,7 @@ def delete_migration_data(import_type: migration.Migration, file_name: str): elif remove_path.is_dir(): shutil.rmtree(remove_path) else: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) - + raise HTTPException(status.HTTP_400_BAD_REQUEST) @router.post("/{import_type}/upload", status_code=status.HTTP_200_OK) @@ -67,4 +67,4 @@ def upload_nextcloud_zipfile(import_type: migration.Migration, archive: UploadFi shutil.copyfileobj(archive.file, buffer) if not dest.is_file: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) \ No newline at end of file + raise HTTPException(status.HTTP_400_BAD_REQUEST) diff --git a/mealie/routes/recipe/__init__.py b/mealie/routes/recipe/__init__.py index e69de29bb2d1..8af92586aae6 100644 --- a/mealie/routes/recipe/__init__.py +++ b/mealie/routes/recipe/__init__.py @@ -0,0 +1,10 @@ +from fastapi import APIRouter +from mealie.routes.recipe import all_recipe_routes, category_routes, recipe_assets, recipe_crud_routes, tag_routes + +router = APIRouter() + +router.include_router(all_recipe_routes.router) +router.include_router(recipe_crud_routes.router) +router.include_router(recipe_assets.router) +router.include_router(category_routes.router) +router.include_router(tag_routes.router) diff --git a/mealie/routes/recipe/all_recipe_routes.py b/mealie/routes/recipe/all_recipe_routes.py index 0a8556afc263..014815774ada 100644 --- a/mealie/routes/recipe/all_recipe_routes.py +++ b/mealie/routes/recipe/all_recipe_routes.py @@ -1,9 +1,7 @@ -from typing import List, Optional - -from fastapi import APIRouter, Depends, Query +from fastapi import APIRouter, Depends from mealie.db.database import db from mealie.db.db_setup import generate_session -from mealie.schema.recipe import AllRecipeRequest, RecipeSummary +from mealie.schema.recipe import RecipeSummary from slugify import slugify from sqlalchemy.orm.session import Session @@ -31,66 +29,6 @@ async def get_recipe_summary( return db.recipes.get_all(session, limit=limit, start=start, override_schema=RecipeSummary) -@router.get("/api/recipes", deprecated=True) -def get_all_recipes( - keys: Optional[List[str]] = Query(...), - num: Optional[int] = 100, - session: Session = Depends(generate_session), -): - """ - Returns key data for all recipes based off the query paramters provided. - For example, if slug, image, and name are provided you will recieve a list of - recipes containing the slug, image, and name property. By default, responses - are limited to 100. - - At this time you can only query top level values: - - - slug - - name - - description - - image - - recipeYield - - total_time - - prep_time - - perform_time - - rating - - org_url - - **Note:** You may experience problems with with query parameters. As an alternative - you may also use the post method and provide a body. - See the *Post* method for more details. - """ - - return db.recipes.get_all_limit_columns(session, keys, limit=num) - - -@router.post("/api/recipes", deprecated=True) -def get_all_recipes_post(body: AllRecipeRequest, session: Session = Depends(generate_session)): - """ - Returns key data for all recipes based off the body data provided. - For example, if slug, image, and name are provided you will recieve a list of - recipes containing the slug, image, and name property. - - At this time you can only query top level values: - - - slug - - name - - description - - image - - recipeYield - - total_time - - prep_time - - perform_time - - rating - - org_url - - Refer to the body example for data formats. - - """ - - return db.recipes.get_all_limit_columns(session, body.properties, body.limit) - - @router.post("/api/recipes/category") def filter_by_category(categories: list, session: Session = Depends(generate_session)): """ pass a list of categories and get a list of recipes associated with those categories """ diff --git a/mealie/routes/recipe/category_routes.py b/mealie/routes/recipe/category_routes.py index 2722bc8dd042..c358a69afb2d 100644 --- a/mealie/routes/recipe/category_routes.py +++ b/mealie/routes/recipe/category_routes.py @@ -37,8 +37,8 @@ async def create_recipe_category( try: return db.categories.create(session, category.dict()) - except: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) + except Exception: + raise HTTPException(status.HTTP_400_BAD_REQUEST) @router.put("/{category}", response_model=RecipeCategoryResponse) @@ -52,8 +52,8 @@ async def update_recipe_category( try: return db.categories.update(session, category, new_category.dict()) - except: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) + except Exception: + raise HTTPException(status.HTTP_400_BAD_REQUEST) @router.delete("/{category}") @@ -66,5 +66,5 @@ async def delete_recipe_category( try: db.categories.delete(session, category) - except: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) + except Exception: + raise HTTPException(status.HTTP_400_BAD_REQUEST) diff --git a/mealie/routes/recipe/recipe_assets.py b/mealie/routes/recipe/recipe_assets.py index 95d4e07b027a..ebab8d246c27 100644 --- a/mealie/routes/recipe/recipe_assets.py +++ b/mealie/routes/recipe/recipe_assets.py @@ -1,6 +1,7 @@ import shutil +from enum import Enum -from fastapi import APIRouter, Depends, File, Form, status, HTTPException +from fastapi import APIRouter, Depends, File, Form, HTTPException, status from fastapi.datastructures import UploadFile from mealie.core.config import app_dirs from mealie.db.database import db @@ -11,7 +12,24 @@ from slugify import slugify from sqlalchemy.orm.session import Session from starlette.responses import FileResponse -router = APIRouter(prefix="/api/recipes", tags=["Recipe Assets"]) +router = APIRouter(prefix="/api/recipes", tags=["Recipe Media"]) + + +class ImageType(str, Enum): + original = "original.webp" + small = "min-original.webp" + tiny = "tiny-original.webp" + + +@router.get("/image/{recipe_slug}/{file_name}") +async def get_recipe_img(recipe_slug: str, file_name: ImageType = ImageType.original): + """Takes in a recipe slug, returns the static image. This route is proxied in the docker image + and should not hit the API in production""" + recipe_image = app_dirs.IMG_DIR.joinpath(recipe_slug, file_name.value) + if recipe_image: + return FileResponse(recipe_image) + else: + raise HTTPException(status.HTTP_404_NOT_FOUND) @router.get("/{recipe_slug}/asset") @@ -41,9 +59,9 @@ def upload_recipe_asset( shutil.copyfileobj(file.file, buffer) if not dest.is_file(): - raise HTTPException( status.HTTP_500_INTERNAL_SERVER_ERROR ) + raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR) recipe: Recipe = db.recipes.get(session, recipe_slug) recipe.assets.append(asset_in) db.recipes.update(session, recipe_slug, recipe.dict()) - return asset_in \ No newline at end of file + return asset_in diff --git a/mealie/routes/recipe/recipe_crud_routes.py b/mealie/routes/recipe/recipe_crud_routes.py index cdeaf3f71c9f..2794370e8cf6 100644 --- a/mealie/routes/recipe/recipe_crud_routes.py +++ b/mealie/routes/recipe/recipe_crud_routes.py @@ -1,14 +1,10 @@ -from enum import Enum - from fastapi import APIRouter, Depends, File, Form, HTTPException, status -from fastapi.responses import FileResponse -from mealie.core.config import app_dirs 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.deps import get_current_user from mealie.schema.recipe import Recipe, RecipeURLIn -from mealie.services.image.image import IMG_OPTIONS, delete_image, read_image, rename_image, scrape_image, write_image +from mealie.services.image.image import delete_image, rename_image, scrape_image, write_image from mealie.services.scraper.scraper import create_from_url from sqlalchemy.orm.session import Session @@ -101,25 +97,8 @@ def delete_recipe( try: db.recipes.delete(session, recipe_slug) delete_image(recipe_slug) - except: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) - - - -class ImageType(str, Enum): - original = "original.webp" - small = "min-original.webp" - tiny = "tiny-original.webp" - - -@router.get("/image/{recipe_slug}/{file_name}") -async def get_recipe_img(recipe_slug: str, file_name: ImageType = ImageType.original): - """ Takes in a recipe slug, returns the static image """ - recipe_image = app_dirs.IMG_DIR.joinpath(recipe_slug, file_name.value) - if recipe_image: - return FileResponse(recipe_image) - else: - raise HTTPException( status.HTTP_404_NOT_FOUND ) + except Exception: + raise HTTPException(status.HTTP_400_BAD_REQUEST) @router.put("/{recipe_slug}/image") diff --git a/mealie/routes/recipe/tag_routes.py b/mealie/routes/recipe/tag_routes.py index 5d62715bbed7..57f6ba4b7efe 100644 --- a/mealie/routes/recipe/tag_routes.py +++ b/mealie/routes/recipe/tag_routes.py @@ -1,4 +1,4 @@ -from fastapi import APIRouter, Depends +from fastapi import APIRouter, Depends, HTTPException, status from mealie.db.database import db from mealie.db.db_setup import generate_session from mealie.routes.deps import get_current_user @@ -7,10 +7,7 @@ from sqlalchemy.orm.session import Session router = APIRouter(tags=["Recipes"]) -router = APIRouter( - prefix="/api/tags", - tags=["Recipe Tags"], -) +router = APIRouter(prefix="/api/tags", tags=["Recipe Tags"]) @router.get("") @@ -59,5 +56,5 @@ async def delete_recipe_tag( try: db.tags.delete(session, tag) - except: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) + except Exception: + raise HTTPException(status.HTTP_400_BAD_REQUEST) diff --git a/mealie/routes/theme_routes.py b/mealie/routes/theme_routes.py index f1f3dbd43566..9f25c8eaecff 100644 --- a/mealie/routes/theme_routes.py +++ b/mealie/routes/theme_routes.py @@ -21,7 +21,6 @@ def create_theme(data: SiteTheme, session: Session = Depends(generate_session), db.themes.create(session, data.dict()) - @router.get("/themes/{theme_name}") def get_single_theme(theme_name: str, session: Session = Depends(generate_session)): """ Returns a named theme """ @@ -44,5 +43,5 @@ def delete_theme(theme_name: str, session: Session = Depends(generate_session), """ Deletes theme from the database """ try: db.themes.delete(session, theme_name) - except: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) + except Exception: + raise HTTPException(status.HTTP_400_BAD_REQUEST) diff --git a/mealie/routes/users/auth.py b/mealie/routes/users/auth.py index 48a0679ec1c5..555abf3bea91 100644 --- a/mealie/routes/users/auth.py +++ b/mealie/routes/users/auth.py @@ -1,5 +1,3 @@ -from datetime import timedelta - from fastapi import APIRouter, Depends, status from fastapi.exceptions import HTTPException from fastapi.security import OAuth2PasswordRequestForm diff --git a/mealie/routes/users/crud.py b/mealie/routes/users/crud.py index d11d6a852188..bd8101de59e7 100644 --- a/mealie/routes/users/crud.py +++ b/mealie/routes/users/crud.py @@ -1,5 +1,4 @@ import shutil -from datetime import timedelta from fastapi import APIRouter, Depends, File, UploadFile, status, HTTPException from fastapi.responses import FileResponse @@ -34,8 +33,8 @@ async def get_all_users( ): if not current_user.admin: - raise HTTPException( status.HTTP_403_FORBIDDEN ) - + raise HTTPException(status.HTTP_403_FORBIDDEN) + return db.users.get_all(session) @@ -67,7 +66,6 @@ async def reset_user_password( db.users.update_password(session, id, new_password) - @router.put("/{id}") async def update_user( id: int, @@ -109,7 +107,7 @@ async def update_user_image( try: [x.unlink() for x in app_dirs.USER_DIR.join(id).glob("profile_image.*")] - except: + except Exception: pass dest = app_dirs.USER_DIR.joinpath(id, f"profile_image.{extension}") @@ -118,7 +116,7 @@ async def update_user_image( shutil.copyfileobj(profile_image.file, buffer) if not dest.is_file: - raise HTTPException( status.HTTP_500_INTERNAL_SERVER_ERROR ) + raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR) @router.put("/{id}/password") @@ -133,12 +131,11 @@ async def update_password( match_passwords = verify_password(password_change.current_password, current_user.password) match_id = current_user.id == id - if not ( match_passwords and match_id ): - raise HTTPException( status.HTTP_401_UNAUTHORIZED ) + if not (match_passwords and match_id): + raise HTTPException(status.HTTP_401_UNAUTHORIZED) new_password = get_password_hash(password_change.new_password) db.users.update_password(session, id, new_password) - @router.delete("/{id}") @@ -150,13 +147,10 @@ async def delete_user( """ Removes a user from the database. Must be the current user or a super user""" if id == 1: - raise HTTPException( - status_code=status.HTTP_403_FORBIDDEN, - detail='SUPER_USER' - ) + raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="SUPER_USER") if current_user.id == id or current_user.admin: try: db.users.delete(session, id) - except: - raise HTTPException( status.HTTP_400_BAD_REQUEST ) \ No newline at end of file + except Exception: + raise HTTPException(status.HTTP_400_BAD_REQUEST) diff --git a/mealie/routes/users/sign_up.py b/mealie/routes/users/sign_up.py index cd0bf8982c1e..c62d4f20414e 100644 --- a/mealie/routes/users/sign_up.py +++ b/mealie/routes/users/sign_up.py @@ -8,6 +8,7 @@ from mealie.routes.deps import get_current_user from mealie.schema.sign_up import SignUpIn, SignUpOut, SignUpToken from mealie.schema.user import UserIn, UserInDB from sqlalchemy.orm.session import Session +from fastapi import HTTPException, status router = APIRouter(prefix="/api/users/sign-ups", tags=["User Signup"]) @@ -33,7 +34,7 @@ async def create_user_sign_up_key( """ Generates a Random Token that a new user can sign up with """ if not current_user.admin: - raise HTTPException( status.HTTP_403_FORBIDDEN ) + raise HTTPException(status.HTTP_403_FORBIDDEN) sign_up = { "token": str(uuid.uuid1().hex), @@ -43,7 +44,6 @@ async def create_user_sign_up_key( return db.sign_ups.create(session, sign_up) - @router.post("/{token}") async def create_user_with_token( token: str, @@ -55,12 +55,12 @@ async def create_user_with_token( # Validate Token db_entry: SignUpOut = db.sign_ups.get(session, token, limit=1) if not db_entry: - raise HTTPException( status.HTTP_401_UNAUTHORIZED ) + raise HTTPException(status.HTTP_401_UNAUTHORIZED) # Create User new_user.admin = db_entry.admin new_user.password = get_password_hash(new_user.password) - data = db.users.create(session, new_user.dict()) + db.users.create(session, new_user.dict()) # DeleteToken db.sign_ups.delete(session, token) @@ -74,6 +74,6 @@ async def delete_token( ): """ Removed a token from the database """ if not current_user.admin: - raise HTTPException( status.HTTP_403_FORBIDDEN ) - + raise HTTPException(status.HTTP_403_FORBIDDEN) + db.sign_ups.delete(session, token) diff --git a/mealie/routes/utility_routes.py b/mealie/routes/utility_routes.py index e52f4bdd8057..6f30128ab75e 100644 --- a/mealie/routes/utility_routes.py +++ b/mealie/routes/utility_routes.py @@ -4,16 +4,17 @@ from typing import Optional from fastapi import APIRouter, Depends from mealie.routes.deps import validate_file_token from starlette.responses import FileResponse +from fastapi import HTTPException, status router = APIRouter(prefix="/api/utils", tags=["Utils"], include_in_schema=True) @router.get("/download") async def download_file(file_path: Optional[Path] = Depends(validate_file_token)): - """ Uses a file token obtained by an active user to retrieve a file from the operating - system. """ + """Uses a file token obtained by an active user to retrieve a file from the operating + system.""" print("File Name:", file_path) if not file_path.is_file(): - raise HTTPException( status.HTTP_400_BAD_REQUEST ) + raise HTTPException(status.HTTP_400_BAD_REQUEST) return FileResponse(file_path, media_type="application/octet-stream", filename=file_path.name) diff --git a/mealie/services/backups/exports.py b/mealie/services/backups/exports.py index cbbc0a853797..afd9a735eb84 100644 --- a/mealie/services/backups/exports.py +++ b/mealie/services/backups/exports.py @@ -37,7 +37,7 @@ class ExportDatabase: try: self.templates = [app_dirs.TEMPLATE_DIR.joinpath(x) for x in templates] - except: + except Exception: self.templates = False logger.info("No Jinja2 Templates Registered for Export") diff --git a/mealie/services/backups/imports.py b/mealie/services/backups/imports.py index 3d35a843a11d..b561752bd6d8 100644 --- a/mealie/services/backups/imports.py +++ b/mealie/services/backups/imports.py @@ -84,20 +84,20 @@ class ImportDatabase: try: del recipe_dict["_id"] del recipe_dict["date_added"] - except: + except Exception: pass # Migration from list to Object Type Data try: if "" in recipe_dict["tags"]: recipe_dict["tags"] = [tag for tag in recipe_dict["tags"] if tag != ""] - except: + except Exception: pass try: if "" in recipe_dict["categories"]: recipe_dict["categories"] = [cat for cat in recipe_dict["categories"] if cat != ""] - except: + except Exception: pass if type(recipe_dict["extras"]) == list: diff --git a/mealie/services/image/image.py b/mealie/services/image/image.py index 1353ac8a7686..ed5f90ab0cb0 100644 --- a/mealie/services/image/image.py +++ b/mealie/services/image/image.py @@ -54,7 +54,7 @@ def rename_image(original_slug, new_slug) -> Path: def write_image(recipe_slug: str, file_data: bytes, extension: str) -> Path: try: delete_image(recipe_slug) - except: + except Exception: pass image_dir = Path(app_dirs.IMG_DIR.joinpath(f"{recipe_slug}")) @@ -100,7 +100,7 @@ def scrape_image(image_url: str, slug: str) -> Path: try: r = requests.get(image_url, stream=True) - except: + except Exception: logger.exception("Fatal Image Request Exception") return None diff --git a/mealie/services/image/minify.py b/mealie/services/image/minify.py index 52344628427c..e33bbb38e106 100644 --- a/mealie/services/image/minify.py +++ b/mealie/services/image/minify.py @@ -35,14 +35,15 @@ def minify_image(image_file: Path) -> ImageSizes: min_dest (Path): FULL Destination File Path tiny_dest (Path): FULL Destination File Path """ + def cleanup(dir: Path) -> None: for file in dir.glob("*.*"): if file.suffix != ".webp": file.unlink() - org_dest = image_file.parent.joinpath(f"original.webp") - min_dest = image_file.parent.joinpath(f"min-original.webp") - tiny_dest = image_file.parent.joinpath(f"tiny-original.webp") + org_dest = image_file.parent.joinpath("original.webp") + min_dest = image_file.parent.joinpath("min-original.webp") + tiny_dest = image_file.parent.joinpath("tiny-original.webp") if min_dest.exists() and tiny_dest.exists() and org_dest.exists(): return diff --git a/mealie/services/meal_services.py b/mealie/services/meal_services.py index 7f5aaefa5c2c..9d657760810d 100644 --- a/mealie/services/meal_services.py +++ b/mealie/services/meal_services.py @@ -24,7 +24,7 @@ def process_meals(session: Session, meal_plan_base: MealPlanIn) -> MealPlanProce description=recipe.description, ) - except: + except Exception: meal_data = MealOut( date=meal_plan_base.startDate + timedelta(days=x), diff --git a/mealie/services/migrations/_migration_base.py b/mealie/services/migrations/_migration_base.py index 15434d5b22f5..6eb35895f7ef 100644 --- a/mealie/services/migrations/_migration_base.py +++ b/mealie/services/migrations/_migration_base.py @@ -8,7 +8,7 @@ from mealie.core import root_logger from mealie.db.database import db from mealie.schema.migration import MigrationImport from mealie.schema.recipe import Recipe -from mealie.services.image import image, minify +from mealie.services.image import image from mealie.services.scraper.cleaner import Cleaner from mealie.utils.unzip import unpack_zip from pydantic import BaseModel diff --git a/mealie/services/scraper/cleaner.py b/mealie/services/scraper/cleaner.py index 0129f68f8bd5..a24586bf4d74 100644 --- a/mealie/services/scraper/cleaner.py +++ b/mealie/services/scraper/cleaner.py @@ -115,7 +115,7 @@ class Cleaner: for step in instructions if step["type"].find("HowToStep") > -1 ] - except: + except Exception: pass else: diff --git a/mealie/services/scraper/open_graph.py b/mealie/services/scraper/open_graph.py index 7cd22e6c4852..ed41f7598c05 100644 --- a/mealie/services/scraper/open_graph.py +++ b/mealie/services/scraper/open_graph.py @@ -21,7 +21,7 @@ def basic_recipe_from_opengraph(html: str, url: str) -> dict: data = extruct.extract(html, base_url=base_url) try: properties = data["opengraph"][0]["properties"] - except: + except Exception: return return { diff --git a/mealie/services/scraper/scraper.py b/mealie/services/scraper/scraper.py index 6dfb39653f61..bee5cc178d3a 100644 --- a/mealie/services/scraper/scraper.py +++ b/mealie/services/scraper/scraper.py @@ -67,7 +67,7 @@ def download_image_for_recipe(recipe: dict) -> dict: try: img_path = scrape_image(recipe.get("image"), recipe.get("slug")) recipe["image"] = img_path.name - except: + except Exception: recipe["image"] = "no image" return recipe diff --git a/tests/conftest.py b/tests/conftest.py index 74b34c497f4b..f12b327f674f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,6 @@ from mealie.core.config import app_dirs, settings -#! I don't like it either! +# ! I don't like it either! SQLITE_FILE = app_dirs.SQLITE_DIR.joinpath("test.db") SQLITE_FILE.unlink(missing_ok=True) diff --git a/tests/data/migrations/chowdown/chowdown-gh-pages.zip b/tests/data/migrations/chowdown/chowdown-gh-pages.zip new file mode 100644 index 000000000000..bd90e08d4e8d Binary files /dev/null and b/tests/data/migrations/chowdown/chowdown-gh-pages.zip differ diff --git a/tests/data/migrations/nextcloud/new_nextcloud.zip b/tests/data/migrations/nextcloud/new_nextcloud.zip new file mode 100644 index 000000000000..a420370fffa2 Binary files /dev/null and b/tests/data/migrations/nextcloud/new_nextcloud.zip differ diff --git a/tests/integration_tests/test_group_routes.py b/tests/integration_tests/test_group_routes.py index d06f200270a9..d13fed128b00 100644 --- a/tests/integration_tests/test_group_routes.py +++ b/tests/integration_tests/test_group_routes.py @@ -37,7 +37,7 @@ def test_update_group(api_client: TestClient, api_routes: AppRoutes, token): # Test Update response = api_client.put(api_routes.groups_id(2), json=new_data, headers=token) assert response.status_code == 200 - + # Validate Changes response = api_client.get(api_routes.groups, headers=token) all_groups = json.loads(response.text) diff --git a/tests/integration_tests/test_recipe_routes.py b/tests/integration_tests/test_recipe_routes.py index b94d6d5f3e57..02803c05fd9c 100644 --- a/tests/integration_tests/test_recipe_routes.py +++ b/tests/integration_tests/test_recipe_routes.py @@ -34,11 +34,6 @@ def test_create_no_image(api_client: TestClient, api_routes: AppRoutes, token, r assert json.loads(response.text) == "banana-bread-no-image" -def test_read_all_post(api_client: TestClient, api_routes: AppRoutes): - response = api_client.post(api_routes.recipes, json={"properties": ["slug", "description", "rating"]}) - assert response.status_code == 200 - - @pytest.mark.parametrize("recipe_data", recipe_test_data) def test_read_update(api_client: TestClient, api_routes: AppRoutes, recipe_data, token): recipe_url = api_routes.recipes_recipe_slug(recipe_data.expected_slug)