mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-12 05:15:18 -05:00
More localization (#358)
* Translate missing items on About page * Localize import summary dialog * Make site menu translation reactive * Localize import options * Include semi colon in string * Move API texts to frontend + better status codes * Provide feedback to user when no meal is planned * Fix API tests after latest rework * Add warning for API changes in changelog * Refactor API texts handling * Refactor API texts handling #2 * Better API feedback * Rearrange strings hierarchy * Add messages upon recipe updated * Fix 'recipe effected' typo * Remove snackbar usage in backend * Translate toolbox * Provide feedback for tags CRUD * Fix messed up merge * Translate sign-up form * Better feedback for sign-up CRUD * Refactor log-in API texts handling * No error message when user is not authenticated * Remove unimportant console log
This commit is contained in:
@@ -2,13 +2,12 @@ import operator
|
||||
import shutil
|
||||
from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
|
||||
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.schema.backup import BackupJob, ImportJob, Imports, LocalBackup
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.services.backups import imports
|
||||
from mealie.services.backups.exports import backup_all
|
||||
from sqlalchemy.orm.session import Session
|
||||
@@ -31,30 +30,27 @@ def available_imports():
|
||||
return Imports(imports=imports, templates=templates)
|
||||
|
||||
|
||||
@router.post("/export/database", status_code=201)
|
||||
@router.post("/export/database", status_code=status.HTTP_201_CREATED)
|
||||
def export_database(data: BackupJob, session: Session = Depends(generate_session)):
|
||||
"""Generates a backup of the recipe database in json format."""
|
||||
export_path = backup_all(
|
||||
session=session,
|
||||
tag=data.tag,
|
||||
templates=data.templates,
|
||||
export_recipes=data.options.recipes,
|
||||
export_settings=data.options.settings,
|
||||
export_pages=data.options.pages,
|
||||
export_themes=data.options.themes,
|
||||
export_users=data.options.users,
|
||||
export_groups=data.options.groups,
|
||||
)
|
||||
try:
|
||||
return SnackResponse.success("Backup Created at " + export_path)
|
||||
except:
|
||||
HTTPException(
|
||||
status_code=400,
|
||||
detail=SnackResponse.error("Error Creating Backup. See Log File"),
|
||||
export_path = backup_all(
|
||||
session=session,
|
||||
tag=data.tag,
|
||||
templates=data.templates,
|
||||
export_recipes=data.options.recipes,
|
||||
export_settings=data.options.settings,
|
||||
export_pages=data.options.pages,
|
||||
export_themes=data.options.themes,
|
||||
export_users=data.options.users,
|
||||
export_groups=data.options.groups,
|
||||
)
|
||||
return {"export_path": export_path}
|
||||
except:
|
||||
raise HTTPException( status.HTTP_500_INTERNAL_SERVER_ERROR )
|
||||
|
||||
|
||||
@router.post("/upload")
|
||||
@router.post("/upload", status_code=status.HTTP_200_OK)
|
||||
def upload_backup_file(archive: UploadFile = File(...)):
|
||||
""" Upload a .zip File to later be imported into Mealie """
|
||||
dest = app_dirs.BACKUP_DIR.joinpath(archive.filename)
|
||||
@@ -62,10 +58,9 @@ def upload_backup_file(archive: UploadFile = File(...)):
|
||||
with dest.open("wb") as buffer:
|
||||
shutil.copyfileobj(archive.file, buffer)
|
||||
|
||||
if dest.is_file:
|
||||
return SnackResponse.success("Backup uploaded")
|
||||
else:
|
||||
return SnackResponse.error("Failure uploading file")
|
||||
if not dest.is_file:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
|
||||
@router.get("/{file_name}/download")
|
||||
@@ -76,7 +71,7 @@ async def download_backup_file(file_name: str):
|
||||
return {"fileToken": create_file_token(file)}
|
||||
|
||||
|
||||
@router.post("/{file_name}/import", status_code=200)
|
||||
@router.post("/{file_name}/import", status_code=status.HTTP_200_OK)
|
||||
def import_database(file_name: str, import_data: ImportJob, session: Session = Depends(generate_session)):
|
||||
""" Import a database backup file generated from Mealie. """
|
||||
|
||||
@@ -94,16 +89,14 @@ def import_database(file_name: str, import_data: ImportJob, session: Session = D
|
||||
)
|
||||
|
||||
|
||||
@router.delete("/{file_name}/delete", status_code=200)
|
||||
@router.delete("/{file_name}/delete", status_code=status.HTTP_200_OK)
|
||||
def delete_backup(file_name: str):
|
||||
""" Removes a database backup from the file system """
|
||||
file_path = app_dirs.BACKUP_DIR.joinpath(file_name)
|
||||
|
||||
if not file_path.is_file():
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
try:
|
||||
app_dirs.BACKUP_DIR.joinpath(file_name).unlink()
|
||||
file_path.unlink()
|
||||
except:
|
||||
HTTPException(
|
||||
status_code=400,
|
||||
detail=SnackResponse.error("Unable to Delete Backup. See Log File"),
|
||||
)
|
||||
|
||||
return SnackResponse.error(f"{file_name} Deleted")
|
||||
raise HTTPException( status.HTTP_500_INTERNAL_SERVER_ERROR )
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, status, HTTPException
|
||||
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.user import GroupBase, GroupInDB, UpdateGroup, UserInDB
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
@@ -30,7 +29,7 @@ async def get_current_user_group(
|
||||
return db.groups.get(session, current_user.group, "name")
|
||||
|
||||
|
||||
@router.post("")
|
||||
@router.post("", status_code=status.HTTP_201_CREATED)
|
||||
async def create_group(
|
||||
group_data: GroupBase,
|
||||
current_user=Depends(get_current_user),
|
||||
@@ -40,9 +39,8 @@ async def create_group(
|
||||
|
||||
try:
|
||||
db.groups.create(session, group_data.dict())
|
||||
return SnackResponse.success("User Group Created", {"created": True})
|
||||
except:
|
||||
return SnackResponse.error("User Group Creation Failed")
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
@router.put("/{id}")
|
||||
@@ -55,8 +53,6 @@ async def update_group_data(
|
||||
""" Updates a User Group """
|
||||
db.groups.update(session, id, group_data.dict())
|
||||
|
||||
return SnackResponse.success("Group Settings Updated")
|
||||
|
||||
|
||||
@router.delete("/{id}")
|
||||
async def delete_user_group(
|
||||
@@ -65,16 +61,23 @@ async def delete_user_group(
|
||||
""" Removes a user group from the database """
|
||||
|
||||
if id == 1:
|
||||
return SnackResponse.error("Cannot delete default group")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='DEFAULT_GROUP'
|
||||
)
|
||||
|
||||
group: GroupInDB = db.groups.get(session, id)
|
||||
|
||||
if not group:
|
||||
return SnackResponse.error("Group not found")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='GROUP_NOT_FOUND'
|
||||
)
|
||||
|
||||
if not group.users == []:
|
||||
return SnackResponse.error("Cannot delete group with users")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail='GROUP_WITH_USERS'
|
||||
)
|
||||
|
||||
db.groups.delete(session, id)
|
||||
|
||||
return
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
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
|
||||
from mealie.schema.meal import MealPlanIn, MealPlanInDB
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import GroupInDB, UserInDB
|
||||
from mealie.services.image import image
|
||||
from mealie.services.meal_services import get_todays_meal, process_meals
|
||||
@@ -23,15 +22,13 @@ def get_all_meals(
|
||||
return db.groups.get_meals(session, current_user.group)
|
||||
|
||||
|
||||
@router.post("/create")
|
||||
@router.post("/create", status_code=status.HTTP_201_CREATED)
|
||||
def create_meal_plan(
|
||||
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)
|
||||
db.meals.create(session, processed_plan.dict())
|
||||
|
||||
return SnackResponse.success("Mealplan Created")
|
||||
return db.meals.create(session, processed_plan.dict())
|
||||
|
||||
|
||||
@router.put("/{plan_id}")
|
||||
@@ -44,25 +41,28 @@ def update_meal_plan(
|
||||
""" Updates a meal plan based off ID """
|
||||
processed_plan = process_meals(session, meal_plan)
|
||||
processed_plan = MealPlanInDB(uid=plan_id, **processed_plan.dict())
|
||||
db.meals.update(session, plan_id, processed_plan.dict())
|
||||
|
||||
return SnackResponse.info("Mealplan Updated")
|
||||
try:
|
||||
db.meals.update(session, plan_id, processed_plan.dict())
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
@router.delete("/{plan_id}")
|
||||
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)
|
||||
|
||||
return SnackResponse.error("Mealplan Deleted")
|
||||
try:
|
||||
db.meals.delete(session, plan_id)
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
@router.get("/this-week", response_model=MealPlanInDB)
|
||||
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]
|
||||
plans = db.groups.get_meals(session, current_user.group)
|
||||
if plans:
|
||||
return plans[0]
|
||||
|
||||
|
||||
@router.get("/today", tags=["Meal Plan"])
|
||||
@@ -74,8 +74,8 @@ def get_today(session: Session = Depends(generate_session), current_user: UserIn
|
||||
|
||||
group_in_db: GroupInDB = db.groups.get(session, current_user.group, "name")
|
||||
recipe = get_todays_meal(session, group_in_db)
|
||||
|
||||
return recipe.slug
|
||||
if recipe:
|
||||
return recipe.slug
|
||||
|
||||
|
||||
@router.get("/today/image", tags=["Meal Plan"])
|
||||
@@ -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(404, "no meal for today")
|
||||
raise HTTPException( status.HTTP_404_NOT_FOUND )
|
||||
if recipe_image:
|
||||
return FileResponse(recipe_image)
|
||||
else:
|
||||
raise HTTPException(404, "file not found")
|
||||
raise HTTPException( status.HTTP_404_NOT_FOUND )
|
||||
|
||||
@@ -2,12 +2,11 @@ import operator
|
||||
import shutil
|
||||
from typing import List
|
||||
|
||||
from fastapi import APIRouter, Depends, File, UploadFile
|
||||
from fastapi import APIRouter, Depends, File, UploadFile, status
|
||||
from mealie.core.config import app_dirs
|
||||
from mealie.db.db_setup import generate_session
|
||||
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 import migration
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
@@ -42,7 +41,7 @@ def import_migration(import_type: migration.Migration, file_name: str, session:
|
||||
return migration.migrate(import_type, file_path, session)
|
||||
|
||||
|
||||
@router.delete("/{import_type}/{file_name}/delete")
|
||||
@router.delete("/{import_type}/{file_name}/delete", status_code=status.HTTP_200_OK)
|
||||
def delete_migration_data(import_type: migration.Migration, file_name: str):
|
||||
""" Removes migration data from the file system """
|
||||
|
||||
@@ -53,12 +52,11 @@ def delete_migration_data(import_type: migration.Migration, file_name: str):
|
||||
elif remove_path.is_dir():
|
||||
shutil.rmtree(remove_path)
|
||||
else:
|
||||
SnackResponse.error("File/Folder not found.")
|
||||
|
||||
return SnackResponse.error(f"Migration Data Remove: {remove_path.absolute()}")
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
@router.post("/{import_type}/upload")
|
||||
|
||||
@router.post("/{import_type}/upload", status_code=status.HTTP_200_OK)
|
||||
def upload_nextcloud_zipfile(import_type: migration.Migration, archive: UploadFile = File(...)):
|
||||
""" Upload a .zip File to later be imported into Mealie """
|
||||
dir = app_dirs.MIGRATION_DIR.joinpath(import_type.value)
|
||||
@@ -68,7 +66,5 @@ def upload_nextcloud_zipfile(import_type: migration.Migration, archive: UploadFi
|
||||
with dest.open("wb") as buffer:
|
||||
shutil.copyfileobj(archive.file, buffer)
|
||||
|
||||
if dest.is_file:
|
||||
return SnackResponse.success("Migration data uploaded")
|
||||
else:
|
||||
return SnackResponse.error("Failure uploading file")
|
||||
if not dest.is_file:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
@@ -1,9 +1,8 @@
|
||||
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
|
||||
from mealie.schema.category import CategoryIn, RecipeCategoryResponse
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
router = APIRouter(
|
||||
@@ -36,7 +35,10 @@ async def create_recipe_category(
|
||||
):
|
||||
""" Creates a Category in the database """
|
||||
|
||||
return db.categories.create(session, category.dict())
|
||||
try:
|
||||
return db.categories.create(session, category.dict())
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
@router.put("/{category}", response_model=RecipeCategoryResponse)
|
||||
@@ -48,7 +50,10 @@ async def update_recipe_category(
|
||||
):
|
||||
""" Updates an existing Tag in the database """
|
||||
|
||||
return db.categories.update(session, category, new_category.dict())
|
||||
try:
|
||||
return db.categories.update(session, category, new_category.dict())
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
|
||||
@router.delete("/{category}")
|
||||
@@ -59,6 +64,7 @@ async def delete_recipe_category(
|
||||
category does not impact a recipe. The category will be removed
|
||||
from any recipes that contain it"""
|
||||
|
||||
db.categories.delete(session, category)
|
||||
|
||||
return SnackResponse.error(f"Category Deleted: {category}")
|
||||
try:
|
||||
db.categories.delete(session, category)
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import shutil
|
||||
|
||||
from fastapi import APIRouter, Depends, File, Form
|
||||
from fastapi import APIRouter, Depends, File, Form, status, HTTPException
|
||||
from fastapi.datastructures import UploadFile
|
||||
from mealie.core.config import app_dirs
|
||||
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, RecipeAsset
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from slugify import slugify
|
||||
from sqlalchemy.orm.session import Session
|
||||
from starlette.responses import FileResponse
|
||||
@@ -41,10 +40,10 @@ def upload_recipe_asset(
|
||||
with dest.open("wb") as buffer:
|
||||
shutil.copyfileobj(file.file, buffer)
|
||||
|
||||
if dest.is_file():
|
||||
recipe: Recipe = db.recipes.get(session, recipe_slug)
|
||||
recipe.assets.append(asset_in)
|
||||
db.recipes.update(session, recipe_slug, recipe.dict())
|
||||
return asset_in
|
||||
else:
|
||||
return SnackResponse.error("Failure uploading file")
|
||||
if not dest.is_file():
|
||||
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
|
||||
@@ -1,12 +1,11 @@
|
||||
from enum import Enum
|
||||
|
||||
from fastapi import APIRouter, Depends, File, Form, HTTPException
|
||||
from fastapi import APIRouter, Depends, File, Form, HTTPException, status
|
||||
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.image import IMG_OPTIONS, delete_image, read_image, rename_image, scrape_image, write_image
|
||||
from mealie.services.scraper.scraper import create_from_url
|
||||
from sqlalchemy.orm.session import Session
|
||||
@@ -100,9 +99,8 @@ def delete_recipe(
|
||||
db.recipes.delete(session, recipe_slug)
|
||||
delete_image(recipe_slug)
|
||||
except:
|
||||
raise HTTPException(status_code=404, detail=SnackResponse.error("Unable to Delete Recipe"))
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
return SnackResponse.error(f"Recipe {recipe_slug} Deleted")
|
||||
|
||||
|
||||
class ImageType(str, Enum):
|
||||
@@ -125,7 +123,7 @@ async def get_recipe_img(recipe_slug: str, image_type: ImageType = ImageType.ori
|
||||
if recipe_image:
|
||||
return FileResponse(recipe_image)
|
||||
else:
|
||||
raise HTTPException(404, "file not found")
|
||||
raise HTTPException( status.HTTP_404_NOT_FOUND )
|
||||
|
||||
|
||||
@router.put("/{recipe_slug}/image")
|
||||
@@ -152,5 +150,3 @@ def scrape_image_url(
|
||||
""" Removes an existing image and replaces it with the incoming file. """
|
||||
|
||||
scrape_image(url.url, recipe_slug)
|
||||
|
||||
return SnackResponse.success("Recipe Image Updated")
|
||||
|
||||
@@ -3,7 +3,6 @@ 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.category import RecipeTagResponse, TagIn
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
router = APIRouter(tags=["Recipes"])
|
||||
@@ -58,6 +57,7 @@ async def delete_recipe_tag(
|
||||
tag does not impact a recipe. The tag will be removed
|
||||
from any recipes that contain it"""
|
||||
|
||||
db.tags.delete(session, tag)
|
||||
|
||||
return SnackResponse.error(f"Tag Deleted: {tag}")
|
||||
try:
|
||||
db.tags.delete(session, tag)
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
@@ -5,7 +5,6 @@ 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.settings import CustomPageBase, CustomPageOut
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import UserInDB
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
@@ -29,8 +28,6 @@ async def create_new_page(
|
||||
|
||||
db.custom_pages.create(session, new_page.dict())
|
||||
|
||||
return SnackResponse.success("New Page Created")
|
||||
|
||||
|
||||
@router.put("")
|
||||
async def update_multiple_pages(
|
||||
@@ -41,7 +38,6 @@ async def update_multiple_pages(
|
||||
""" Update multiple custom pages """
|
||||
for page in pages:
|
||||
db.custom_pages.update(session, page.id, page.dict())
|
||||
return SnackResponse.success("Pages Updated")
|
||||
|
||||
|
||||
@router.get("/{id}")
|
||||
@@ -57,7 +53,7 @@ async def get_single_page(
|
||||
|
||||
|
||||
@router.put("/{id}")
|
||||
async def update_single_age(
|
||||
async def update_single_page(
|
||||
data: CustomPageOut,
|
||||
id: int,
|
||||
session: Session = Depends(generate_session),
|
||||
|
||||
@@ -3,7 +3,6 @@ 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.settings import SiteSettings
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import GroupInDB, UserInDB
|
||||
from mealie.utils.post_webhooks import post_webhooks
|
||||
from sqlalchemy.orm.session import Session
|
||||
@@ -27,8 +26,6 @@ def update_settings(
|
||||
""" Returns Site Settings """
|
||||
db.settings.update(session, 1, data.dict())
|
||||
|
||||
return SnackResponse.success("Settings Updated")
|
||||
|
||||
|
||||
@router.post("/webhooks/test")
|
||||
def test_webhooks(
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from fastapi import APIRouter, Depends, status, HTTPException
|
||||
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
|
||||
|
||||
@@ -16,12 +15,11 @@ def get_all_themes(session: Session = Depends(generate_session)):
|
||||
return db.themes.get_all(session)
|
||||
|
||||
|
||||
@router.post("/themes/create")
|
||||
@router.post("/themes/create", status_code=status.HTTP_201_CREATED)
|
||||
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())
|
||||
|
||||
return SnackResponse.success("Theme Saved")
|
||||
|
||||
|
||||
@router.get("/themes/{theme_name}")
|
||||
@@ -30,7 +28,7 @@ def get_single_theme(theme_name: str, session: Session = Depends(generate_sessio
|
||||
return db.themes.get(session, theme_name)
|
||||
|
||||
|
||||
@router.put("/themes/{theme_name}")
|
||||
@router.put("/themes/{theme_name}", status_code=status.HTTP_200_OK)
|
||||
def update_theme(
|
||||
theme_name: str,
|
||||
data: SiteTheme,
|
||||
@@ -40,12 +38,11 @@ def update_theme(
|
||||
""" Update a theme database entry """
|
||||
db.themes.update(session, theme_name, data.dict())
|
||||
|
||||
return SnackResponse.info(f"Theme Updated: {theme_name}")
|
||||
|
||||
|
||||
@router.delete("/themes/{theme_name}")
|
||||
@router.delete("/themes/{theme_name}", status_code=status.HTTP_200_OK)
|
||||
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)
|
||||
|
||||
return SnackResponse.error(f"Theme Deleted: {theme_name}")
|
||||
try:
|
||||
db.themes.delete(session, theme_name)
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
@@ -7,7 +7,6 @@ from mealie.core import security
|
||||
from mealie.core.security import authenticate_user
|
||||
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.user import UserInDB
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
@@ -28,15 +27,11 @@ def get_token(
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Incorrect username or password",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
|
||||
access_token = security.create_access_token(dict(sub=email))
|
||||
return SnackResponse.success(
|
||||
"User Successfully Logged In",
|
||||
{"access_token": access_token, "token_type": "bearer"},
|
||||
)
|
||||
return {"access_token": access_token, "token_type": "bearer"}
|
||||
|
||||
|
||||
@router.get("/refresh")
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import shutil
|
||||
from datetime import timedelta
|
||||
|
||||
from fastapi import APIRouter, Depends, File, UploadFile
|
||||
from fastapi import APIRouter, Depends, File, UploadFile, status, HTTPException
|
||||
from fastapi.responses import FileResponse
|
||||
from mealie.core import security
|
||||
from mealie.core.config import app_dirs, settings
|
||||
@@ -9,7 +9,6 @@ from mealie.core.security import get_password_hash, verify_password
|
||||
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.user import ChangePassword, UserBase, UserIn, UserInDB, UserOut
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
@@ -25,8 +24,7 @@ async def create_user(
|
||||
|
||||
new_user.password = get_password_hash(new_user.password)
|
||||
|
||||
data = db.users.create(session, new_user.dict())
|
||||
return SnackResponse.success(f"User Created: {new_user.full_name}", data)
|
||||
return db.users.create(session, new_user.dict())
|
||||
|
||||
|
||||
@router.get("", response_model=list[UserOut])
|
||||
@@ -35,10 +33,10 @@ async def get_all_users(
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
|
||||
if current_user.admin:
|
||||
return db.users.get_all(session)
|
||||
else:
|
||||
return {"details": "user not authorized"}
|
||||
if not current_user.admin:
|
||||
raise HTTPException( status.HTTP_403_FORBIDDEN )
|
||||
|
||||
return db.users.get_all(session)
|
||||
|
||||
|
||||
@router.get("/self", response_model=UserOut)
|
||||
@@ -68,7 +66,6 @@ async def reset_user_password(
|
||||
new_password = get_password_hash(settings.DEFAULT_PASSWORD)
|
||||
db.users.update_password(session, id, new_password)
|
||||
|
||||
return SnackResponse.success("Users Password Reset")
|
||||
|
||||
|
||||
@router.put("/{id}")
|
||||
@@ -85,8 +82,7 @@ async def update_user(
|
||||
if current_user.id == id:
|
||||
access_token = security.create_access_token(data=dict(sub=new_data.email))
|
||||
token = {"access_token": access_token, "token_type": "bearer"}
|
||||
|
||||
return SnackResponse.success("User Updated", token)
|
||||
return token
|
||||
|
||||
|
||||
@router.get("/{id}/image")
|
||||
@@ -121,10 +117,8 @@ async def update_user_image(
|
||||
with dest.open("wb") as buffer:
|
||||
shutil.copyfileobj(profile_image.file, buffer)
|
||||
|
||||
if dest.is_file:
|
||||
return SnackResponse.success("File uploaded")
|
||||
else:
|
||||
return SnackResponse.error("Failure uploading file")
|
||||
if not dest.is_file:
|
||||
raise HTTPException( status.HTTP_500_INTERNAL_SERVER_ERROR )
|
||||
|
||||
|
||||
@router.put("/{id}/password")
|
||||
@@ -139,12 +133,12 @@ async def update_password(
|
||||
match_passwords = verify_password(password_change.current_password, current_user.password)
|
||||
match_id = current_user.id == id
|
||||
|
||||
if match_passwords and match_id:
|
||||
new_password = get_password_hash(password_change.new_password)
|
||||
db.users.update_password(session, id, new_password)
|
||||
return SnackResponse.success("Password Updated")
|
||||
else:
|
||||
return SnackResponse.error("Existing password does not match")
|
||||
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}")
|
||||
@@ -156,8 +150,13 @@ async def delete_user(
|
||||
""" Removes a user from the database. Must be the current user or a super user"""
|
||||
|
||||
if id == 1:
|
||||
return SnackResponse.error("Error! Cannot Delete Super User")
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_403_FORBIDDEN,
|
||||
detail='SUPER_USER'
|
||||
)
|
||||
|
||||
if current_user.id == id or current_user.admin:
|
||||
db.users.delete(session, id)
|
||||
return SnackResponse.error("User Deleted")
|
||||
try:
|
||||
db.users.delete(session, id)
|
||||
except:
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
@@ -6,7 +6,6 @@ from mealie.db.db_setup import generate_session
|
||||
from fastapi import APIRouter, Depends
|
||||
from mealie.routes.deps import get_current_user
|
||||
from mealie.schema.sign_up import SignUpIn, SignUpOut, SignUpToken
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from mealie.schema.user import UserIn, UserInDB
|
||||
from sqlalchemy.orm.session import Session
|
||||
|
||||
@@ -33,18 +32,16 @@ async def create_user_sign_up_key(
|
||||
):
|
||||
""" Generates a Random Token that a new user can sign up with """
|
||||
|
||||
if current_user.admin:
|
||||
sign_up = {
|
||||
"token": str(uuid.uuid1().hex),
|
||||
"name": key_data.name,
|
||||
"admin": key_data.admin,
|
||||
}
|
||||
db_entry = db.sign_ups.create(session, sign_up)
|
||||
if not current_user.admin:
|
||||
raise HTTPException( status.HTTP_403_FORBIDDEN )
|
||||
|
||||
return db_entry
|
||||
sign_up = {
|
||||
"token": str(uuid.uuid1().hex),
|
||||
"name": key_data.name,
|
||||
"admin": key_data.admin,
|
||||
}
|
||||
return db.sign_ups.create(session, sign_up)
|
||||
|
||||
else:
|
||||
return {"details": "not authorized"}
|
||||
|
||||
|
||||
@router.post("/{token}")
|
||||
@@ -58,7 +55,7 @@ async def create_user_with_token(
|
||||
# Validate Token
|
||||
db_entry: SignUpOut = db.sign_ups.get(session, token, limit=1)
|
||||
if not db_entry:
|
||||
return SnackResponse.error("Invalid Token")
|
||||
raise HTTPException( status.HTTP_401_UNAUTHORIZED )
|
||||
|
||||
# Create User
|
||||
new_user.admin = db_entry.admin
|
||||
@@ -68,9 +65,6 @@ async def create_user_with_token(
|
||||
# DeleteToken
|
||||
db.sign_ups.delete(session, token)
|
||||
|
||||
# Respond
|
||||
return SnackResponse.success(f"User Created: {new_user.full_name}", data)
|
||||
|
||||
|
||||
@router.delete("/{token}")
|
||||
async def delete_token(
|
||||
@@ -79,8 +73,7 @@ async def delete_token(
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Removed a token from the database """
|
||||
if current_user.admin:
|
||||
db.sign_ups.delete(session, token)
|
||||
return SnackResponse.error("Sign Up Token Deleted")
|
||||
else:
|
||||
return {"details", "not authorized"}
|
||||
if not current_user.admin:
|
||||
raise HTTPException( status.HTTP_403_FORBIDDEN )
|
||||
|
||||
db.sign_ups.delete(session, token)
|
||||
|
||||
@@ -3,7 +3,6 @@ from typing import Optional
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
from mealie.routes.deps import validate_file_token
|
||||
from mealie.schema.snackbar import SnackResponse
|
||||
from starlette.responses import FileResponse
|
||||
|
||||
router = APIRouter(prefix="/api/utils", tags=["Utils"], include_in_schema=True)
|
||||
@@ -14,7 +13,7 @@ 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. """
|
||||
print("File Name:", file_path)
|
||||
if file_path.is_file():
|
||||
return FileResponse(file_path, media_type="application/octet-stream", filename=file_path.name)
|
||||
else:
|
||||
return SnackResponse.error("No File Found")
|
||||
if not file_path.is_file():
|
||||
raise HTTPException( status.HTTP_400_BAD_REQUEST )
|
||||
|
||||
return FileResponse(file_path, media_type="application/octet-stream", filename=file_path.name)
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
class SnackResponse:
|
||||
@staticmethod
|
||||
def _create_response(message: str, type: str, additional_data: dict = None) -> dict:
|
||||
|
||||
snackbar = {"snackbar": {"text": message, "type": type}}
|
||||
|
||||
if additional_data:
|
||||
snackbar.update(additional_data)
|
||||
|
||||
return snackbar
|
||||
|
||||
@staticmethod
|
||||
def success(message: str, additional_data: dict = None) -> dict:
|
||||
return SnackResponse._create_response(message, "success", additional_data)
|
||||
|
||||
@staticmethod
|
||||
def info(message: str, additional_data: dict = None) -> dict:
|
||||
return SnackResponse._create_response(message, "info", additional_data)
|
||||
|
||||
@staticmethod
|
||||
def warning(message: str, additional_data: dict = None) -> dict:
|
||||
return SnackResponse._create_response(message, "warning", additional_data)
|
||||
|
||||
@staticmethod
|
||||
def error(message: str, additional_data: dict = None) -> dict:
|
||||
return SnackResponse._create_response(message, "error", additional_data)
|
||||
Reference in New Issue
Block a user