mirror of
https://github.com/mealie-recipes/mealie.git
synced 2025-12-28 21:15:26 -05:00
feat(frontend): ✨ Add Meal Tags + UI Improvements (#807)
* feat: ✨ * fix colors * add additional support for settings meal tag * add defaults to recipe * use group reciep settings * fix login infinite loading * disable owner on initial load * add skeleton loader * add v-model support * formatting * fix overwriting existing values * feat(frontend): ✨ add markdown preview for steps * update black plus formatting * update help text * fix overwrite error * remove print Co-authored-by: hay-kot <hay-kot@pm.me>
This commit is contained in:
@@ -65,7 +65,7 @@ logging.basicConfig(
|
||||
|
||||
|
||||
def logger_init() -> logging.Logger:
|
||||
""" Returns the Root Loggin Object for Mealie """
|
||||
"""Returns the Root Loggin Object for Mealie"""
|
||||
return logging.getLogger("mealie")
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ root_logger.info("Testing Root Logger")
|
||||
|
||||
|
||||
def get_logger(module=None) -> logging.Logger:
|
||||
""" Returns a child logger for mealie """
|
||||
"""Returns a child logger for mealie"""
|
||||
global root_logger
|
||||
|
||||
if module is None:
|
||||
|
||||
@@ -14,7 +14,7 @@ logger = get_logger()
|
||||
|
||||
@router.get("", response_model=EventsOut)
|
||||
async def get_events(session: Session = Depends(generate_session)):
|
||||
""" Get event from the Database """
|
||||
"""Get event from the Database"""
|
||||
db = get_database(session)
|
||||
|
||||
return EventsOut(total=db.events.count_all(), events=db.events.get_all(order_by="time_stamp"))
|
||||
@@ -22,7 +22,7 @@ async def get_events(session: Session = Depends(generate_session)):
|
||||
|
||||
@router.delete("")
|
||||
async def delete_events(session: Session = Depends(generate_session)):
|
||||
""" Get event from the Database """
|
||||
"""Get event from the Database"""
|
||||
db = get_database(session)
|
||||
db.events.delete_all()
|
||||
return {"message": "All events deleted"}
|
||||
@@ -30,6 +30,6 @@ async def delete_events(session: Session = Depends(generate_session)):
|
||||
|
||||
@router.delete("/{id}")
|
||||
async def delete_event(id: int, session: Session = Depends(generate_session)):
|
||||
""" Delete event from the Database """
|
||||
"""Delete event from the Database"""
|
||||
db = get_database(session)
|
||||
return db.events.delete(id)
|
||||
|
||||
@@ -20,7 +20,7 @@ async def create_event_notification(
|
||||
event_data: EventNotificationIn,
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Create event_notification in the Database """
|
||||
"""Create event_notification in the Database"""
|
||||
db = get_database(session)
|
||||
|
||||
return db.event_notifications.create(event_data)
|
||||
@@ -31,7 +31,7 @@ async def test_notification_route(
|
||||
test_data: TestEvent,
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Create event_notification in the Database """
|
||||
"""Create event_notification in the Database"""
|
||||
db = get_database(session)
|
||||
|
||||
if test_data.id:
|
||||
@@ -47,21 +47,21 @@ async def test_notification_route(
|
||||
|
||||
@router.get("/notifications", response_model=list[EventNotificationOut])
|
||||
async def get_all_event_notification(session: Session = Depends(generate_session)):
|
||||
""" Get all event_notification from the Database """
|
||||
"""Get all event_notification from the Database"""
|
||||
db = get_database(session)
|
||||
return db.event_notifications.get_all(override_schema=EventNotificationOut)
|
||||
|
||||
|
||||
@router.put("/notifications/{id}")
|
||||
async def update_event_notification(id: int, session: Session = Depends(generate_session)):
|
||||
""" Update event_notification in the Database """
|
||||
"""Update event_notification in the Database"""
|
||||
# not yet implemented
|
||||
raise HTTPException(status.HTTP_405_METHOD_NOT_ALLOWED)
|
||||
|
||||
|
||||
@router.delete("/notifications/{id}")
|
||||
async def delete_event_notification(id: int, session: Session = Depends(generate_session)):
|
||||
""" Delete event_notification from the Database """
|
||||
"""Delete event_notification from the Database"""
|
||||
# Delete Item
|
||||
db = get_database(session)
|
||||
return db.event_notifications.delete(id)
|
||||
|
||||
@@ -12,7 +12,7 @@ router = APIRouter(prefix="/about")
|
||||
|
||||
@router.get("", response_model=AdminAboutInfo)
|
||||
async def get_app_info():
|
||||
""" Get general application information """
|
||||
"""Get general application information"""
|
||||
settings = get_app_settings()
|
||||
|
||||
return AdminAboutInfo(
|
||||
|
||||
@@ -25,7 +25,7 @@ class EmailTest(CamelModel):
|
||||
|
||||
@router.get("", response_model=EmailReady)
|
||||
async def check_email_config():
|
||||
""" Get general application information """
|
||||
"""Get general application information"""
|
||||
settings = get_app_settings()
|
||||
|
||||
return EmailReady(ready=settings.SMTP_ENABLE)
|
||||
|
||||
@@ -13,7 +13,7 @@ router = AdminAPIRouter(prefix="/groups")
|
||||
|
||||
@router.get("", response_model=list[GroupInDB])
|
||||
async def get_all_groups(session: Session = Depends(generate_session)):
|
||||
""" Returns a list of all groups in the database """
|
||||
"""Returns a list of all groups in the database"""
|
||||
db = get_database(session)
|
||||
|
||||
return db.groups.get_all()
|
||||
@@ -25,7 +25,7 @@ async def create_group(
|
||||
group_data: GroupBase,
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Creates a Group in the Database """
|
||||
"""Creates a Group in the Database"""
|
||||
db = get_database(session)
|
||||
|
||||
try:
|
||||
@@ -38,7 +38,7 @@ async def create_group(
|
||||
|
||||
@router.put("/{id}")
|
||||
async def update_group_data(id: int, group_data: UpdateGroup, session: Session = Depends(generate_session)):
|
||||
""" Updates a User Group """
|
||||
"""Updates a User Group"""
|
||||
db = get_database(session)
|
||||
db.groups.update(id, group_data.dict())
|
||||
|
||||
@@ -50,7 +50,7 @@ async def delete_user_group(
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Removes a user group from the database """
|
||||
"""Removes a user group from the database"""
|
||||
db = get_database(session)
|
||||
|
||||
if id == 1:
|
||||
|
||||
@@ -8,7 +8,7 @@ router = APIRouter(prefix="/logs")
|
||||
|
||||
@router.get("/{num}")
|
||||
async def get_log(num: int):
|
||||
""" Doc Str """
|
||||
"""Doc Str"""
|
||||
with open(LOGGER_FILE, "rb") as f:
|
||||
log_text = tail(f, num)
|
||||
return log_text
|
||||
@@ -16,7 +16,7 @@ async def get_log(num: int):
|
||||
|
||||
@router.get("")
|
||||
async def get_log_file():
|
||||
""" Returns a token to download a file """
|
||||
"""Returns a token to download a file"""
|
||||
return {"fileToken": create_file_token(LOGGER_FILE)}
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ router = APIRouter(prefix="/about")
|
||||
|
||||
@router.get("", response_model=AppInfo)
|
||||
async def get_app_info():
|
||||
""" Get general application information """
|
||||
"""Get general application information"""
|
||||
settings = get_app_settings()
|
||||
|
||||
return AppInfo(
|
||||
|
||||
@@ -43,6 +43,6 @@ def get_token(
|
||||
|
||||
@user_router.get("/refresh")
|
||||
async def refresh_token(current_user: PrivateUser = Depends(get_current_user)):
|
||||
""" Use a valid token to get another token"""
|
||||
"""Use a valid token to get another token"""
|
||||
access_token = security.create_access_token(data=dict(sub=current_user.email))
|
||||
return {"access_token": access_token, "token_type": "bearer"}
|
||||
|
||||
@@ -63,7 +63,7 @@ def export_database(
|
||||
|
||||
@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 """
|
||||
"""Upload a .zip File to later be imported into Mealie"""
|
||||
dest = app_dirs.BACKUP_DIR.joinpath(archive.filename)
|
||||
|
||||
with dest.open("wb") as buffer:
|
||||
@@ -75,7 +75,7 @@ def upload_backup_file(archive: UploadFile = File(...)):
|
||||
|
||||
@router.get("/{file_name}/download")
|
||||
async def download_backup_file(file_name: str):
|
||||
""" Returns a token to download a file """
|
||||
"""Returns a token to download a file"""
|
||||
file = app_dirs.BACKUP_DIR.joinpath(file_name)
|
||||
|
||||
return {"fileToken": create_file_token(file)}
|
||||
@@ -89,7 +89,7 @@ def import_database(
|
||||
session: Session = Depends(generate_session),
|
||||
user: PrivateUser = Depends(get_current_user),
|
||||
):
|
||||
""" Import a database backup file generated from Mealie. """
|
||||
"""Import a database backup file generated from Mealie."""
|
||||
|
||||
db_import = imports.import_database(
|
||||
user=user,
|
||||
@@ -109,7 +109,7 @@ def import_database(
|
||||
|
||||
@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 """
|
||||
"""Removes a database backup from the file system"""
|
||||
file_path = app_dirs.BACKUP_DIR.joinpath(file_name)
|
||||
|
||||
if not file_path.is_file():
|
||||
|
||||
@@ -14,14 +14,14 @@ admin_router = AdminAPIRouter()
|
||||
|
||||
@public_router.get("")
|
||||
async def get_all_recipe_categories(session: Session = Depends(generate_session)):
|
||||
""" Returns a list of available categories in the database """
|
||||
"""Returns a list of available categories in the database"""
|
||||
db = get_database(session)
|
||||
return db.categories.get_all_limit_columns(fields=["slug", "name"])
|
||||
|
||||
|
||||
@public_router.get("/empty")
|
||||
def get_empty_categories(session: Session = Depends(generate_session)):
|
||||
""" Returns a list of categories that do not contain any recipes"""
|
||||
"""Returns a list of categories that do not contain any recipes"""
|
||||
db = get_database(session)
|
||||
return db.categories.get_empty()
|
||||
|
||||
@@ -30,7 +30,7 @@ def get_empty_categories(session: Session = Depends(generate_session)):
|
||||
def get_all_recipes_by_category(
|
||||
category: str, session: Session = Depends(generate_session), is_user: bool = Depends(is_logged_in)
|
||||
):
|
||||
""" Returns a list of recipes associated with the provided category. """
|
||||
"""Returns a list of recipes associated with the provided category."""
|
||||
db = get_database(session)
|
||||
|
||||
category_obj = db.categories.get(category)
|
||||
@@ -44,7 +44,7 @@ def get_all_recipes_by_category(
|
||||
|
||||
@user_router.post("")
|
||||
async def create_recipe_category(category: CategoryIn, session: Session = Depends(generate_session)):
|
||||
""" Creates a Category in the database """
|
||||
"""Creates a Category in the database"""
|
||||
db = get_database(session)
|
||||
|
||||
try:
|
||||
@@ -55,7 +55,7 @@ async def create_recipe_category(category: CategoryIn, session: Session = Depend
|
||||
|
||||
@admin_router.put("/{category}", response_model=RecipeCategoryResponse)
|
||||
async def update_recipe_category(category: str, new_category: CategoryIn, session: Session = Depends(generate_session)):
|
||||
""" Updates an existing Tag in the database """
|
||||
"""Updates an existing Tag in the database"""
|
||||
db = get_database(session)
|
||||
|
||||
try:
|
||||
|
||||
@@ -10,13 +10,13 @@ user_router = UserAPIRouter(prefix="/groups", tags=["Groups: Self Service"])
|
||||
|
||||
@user_router.get("/self", response_model=GroupInDB)
|
||||
async def get_logged_in_user_group(g_service: GroupSelfService = Depends(GroupSelfService.write_existing)):
|
||||
""" Returns the Group Data for the Current User """
|
||||
"""Returns the Group Data for the Current User"""
|
||||
return g_service.item
|
||||
|
||||
|
||||
@user_router.get("/members", response_model=list[UserOut])
|
||||
async def get_group_members(g_service: GroupSelfService = Depends(GroupSelfService.write_existing)):
|
||||
""" Returns the Group of user lists """
|
||||
"""Returns the Group of user lists"""
|
||||
return g_service.get_members()
|
||||
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ async def get_recipe_img(slug: str, file_name: ImageType = ImageType.original):
|
||||
|
||||
@router.get("/{slug}/assets/{file_name}")
|
||||
async def get_recipe_asset(slug: str, file_name: str):
|
||||
""" Returns a recipe asset """
|
||||
"""Returns a recipe asset"""
|
||||
file = Recipe(slug=slug).asset_dir.joinpath(file_name)
|
||||
|
||||
try:
|
||||
|
||||
@@ -20,7 +20,7 @@ router = AdminAPIRouter(prefix="/api/migrations", tags=["Migration"])
|
||||
|
||||
@router.get("", response_model=List[Migrations])
|
||||
def get_all_migration_options():
|
||||
""" Returns a list of avaiable directories that can be imported into Mealie """
|
||||
"""Returns a list of avaiable directories that can be imported into Mealie"""
|
||||
response_data = []
|
||||
migration_dirs = [
|
||||
app_dirs.MIGRATION_DIR.joinpath("nextcloud"),
|
||||
@@ -46,14 +46,14 @@ def import_migration(
|
||||
session: Session = Depends(generate_session),
|
||||
user: PrivateUser = Depends(get_logged_in_user),
|
||||
):
|
||||
""" Imports all the recipes in a given directory """
|
||||
"""Imports all the recipes in a given directory"""
|
||||
file_path = app_dirs.MIGRATION_DIR.joinpath(import_type.value, file_name)
|
||||
return migration.migrate(user, import_type, file_path, session)
|
||||
|
||||
|
||||
@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 """
|
||||
"""Removes migration data from the file system"""
|
||||
|
||||
remove_path = app_dirs.MIGRATION_DIR.joinpath(import_type.value, file_name)
|
||||
|
||||
@@ -67,7 +67,7 @@ def delete_migration_data(import_type: migration.Migration, file_name: str):
|
||||
|
||||
@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 """
|
||||
"""Upload a .zip File to later be imported into Mealie"""
|
||||
dir = app_dirs.MIGRATION_DIR.joinpath(import_type.value)
|
||||
dir.mkdir(parents=True, exist_ok=True)
|
||||
dest = dir.joinpath(archive.filename)
|
||||
|
||||
@@ -20,7 +20,7 @@ async def create_comment(
|
||||
session: Session = Depends(generate_session),
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
):
|
||||
""" Create comment in the Database """
|
||||
"""Create comment in the Database"""
|
||||
db = get_database(session)
|
||||
|
||||
new_comment = SaveComment(user=current_user.id, text=new_comment.text, recipe_slug=slug)
|
||||
@@ -34,7 +34,7 @@ async def update_comment(
|
||||
session: Session = Depends(generate_session),
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
):
|
||||
""" Update comment in the Database """
|
||||
"""Update comment in the Database"""
|
||||
db = get_database(session)
|
||||
old_comment: CommentOut = db.comments.get(id)
|
||||
|
||||
@@ -48,7 +48,7 @@ async def update_comment(
|
||||
async def delete_comment(
|
||||
id: int, session: Session = Depends(generate_session), current_user: PrivateUser = Depends(get_current_user)
|
||||
):
|
||||
""" Delete comment from the Database """
|
||||
"""Delete comment from the Database"""
|
||||
db = get_database(session)
|
||||
comment: CommentOut = db.comments.get(id)
|
||||
if current_user.id == comment.user.id or current_user.admin:
|
||||
|
||||
@@ -16,7 +16,7 @@ user_router = UserAPIRouter()
|
||||
|
||||
@user_router.post("/{slug}/image")
|
||||
def scrape_image_url(slug: str, url: CreateRecipeByUrl):
|
||||
""" Removes an existing image and replaces it with the incoming file. """
|
||||
"""Removes an existing image and replaces it with the incoming file."""
|
||||
|
||||
scrape_image(url.url, slug)
|
||||
|
||||
@@ -28,7 +28,7 @@ def update_recipe_image(
|
||||
extension: str = Form(...),
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Removes an existing image and replaces it with the incoming file. """
|
||||
"""Removes an existing image and replaces it with the incoming file."""
|
||||
db = get_database(session)
|
||||
write_image(slug, image, extension)
|
||||
new_version = db.recipes.update_image(slug, extension)
|
||||
@@ -45,7 +45,7 @@ def upload_recipe_asset(
|
||||
file: UploadFile = File(...),
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Upload a file to store as a recipe asset """
|
||||
"""Upload a file to store as a recipe asset"""
|
||||
file_name = slugify(name) + "." + extension
|
||||
asset_in = RecipeAsset(name=name, icon=icon, file_name=file_name)
|
||||
dest = Recipe(slug=slug).asset_dir.joinpath(file_name)
|
||||
|
||||
@@ -27,13 +27,13 @@ async def get_all(start=0, limit=None, service: RecipeService = Depends(RecipeSe
|
||||
|
||||
@user_router.post("", status_code=201, response_model=str)
|
||||
def create_from_name(data: CreateRecipe, recipe_service: RecipeService = Depends(RecipeService.private)) -> 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"""
|
||||
return recipe_service.create_one(data).slug
|
||||
|
||||
|
||||
@user_router.post("/create-url", status_code=201, response_model=str)
|
||||
def parse_recipe_url(url: CreateRecipeByUrl, recipe_service: RecipeService = Depends(RecipeService.private)):
|
||||
""" 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)
|
||||
return recipe_service.create_one(recipe).slug
|
||||
|
||||
@@ -44,7 +44,7 @@ def parse_recipe_url_bulk(
|
||||
recipe_service: RecipeService = Depends(RecipeService.private),
|
||||
bg_service: BackgroundExecutor = Depends(BackgroundExecutor.private),
|
||||
):
|
||||
""" 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"""
|
||||
|
||||
def bulk_import_func(task_id: int, session: Session) -> None:
|
||||
database = get_database(session)
|
||||
@@ -94,30 +94,30 @@ async def create_recipe_from_zip(
|
||||
temp_path=Depends(temporary_zip_path),
|
||||
archive: UploadFile = File(...),
|
||||
):
|
||||
""" Create recipe from archive """
|
||||
"""Create recipe from archive"""
|
||||
recipe = recipe_service.create_from_zip(archive, temp_path)
|
||||
return recipe.slug
|
||||
|
||||
|
||||
@user_router.get("/{slug}", response_model=Recipe)
|
||||
def get_recipe(recipe_service: RecipeService = Depends(RecipeService.read_existing)):
|
||||
""" Takes in a recipe slug, returns all data for a recipe """
|
||||
"""Takes in a recipe slug, returns all data for a recipe"""
|
||||
return recipe_service.item
|
||||
|
||||
|
||||
@user_router.put("/{slug}")
|
||||
def update_recipe(data: Recipe, recipe_service: RecipeService = Depends(RecipeService.write_existing)):
|
||||
""" Updates a recipe by existing slug and data. """
|
||||
"""Updates a recipe by existing slug and data."""
|
||||
return recipe_service.update_one(data)
|
||||
|
||||
|
||||
@user_router.patch("/{slug}")
|
||||
def patch_recipe(data: Recipe, recipe_service: RecipeService = Depends(RecipeService.write_existing)):
|
||||
""" Updates a recipe by existing slug and data. """
|
||||
"""Updates a recipe by existing slug and data."""
|
||||
return recipe_service.patch_one(data)
|
||||
|
||||
|
||||
@user_router.delete("/{slug}")
|
||||
def delete_recipe(recipe_service: RecipeService = Depends(RecipeService.write_existing)):
|
||||
""" Deletes a recipe by slug """
|
||||
"""Deletes a recipe by slug"""
|
||||
return recipe_service.delete_one()
|
||||
|
||||
@@ -34,7 +34,7 @@ async def get_recipe_formats_and_templates(_: RecipeService = Depends(RecipeServ
|
||||
|
||||
@user_router.post("/{slug}/exports")
|
||||
async def get_recipe_zip_token(slug: str):
|
||||
""" Generates a recipe zip token to be used to download a recipe as a zip file """
|
||||
"""Generates a recipe zip token to be used to download a recipe as a zip file"""
|
||||
return {"token": create_recipe_slug_token(slug)}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ async def get_recipe_as_zip(
|
||||
session: Session = Depends(generate_session),
|
||||
temp_path=Depends(temporary_zip_path),
|
||||
):
|
||||
""" Get a Recipe and It's Original Image as a Zip File """
|
||||
"""Get a Recipe and It's Original Image as a Zip File"""
|
||||
slug = validate_recipe_token(token)
|
||||
|
||||
if slug != slug:
|
||||
|
||||
@@ -6,7 +6,7 @@ from mealie.core.dependencies import get_admin_user, get_current_user
|
||||
|
||||
|
||||
class AdminAPIRouter(APIRouter):
|
||||
""" Router for functions to be protected behind admin authentication """
|
||||
"""Router for functions to be protected behind admin authentication"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@@ -17,7 +17,7 @@ class AdminAPIRouter(APIRouter):
|
||||
|
||||
|
||||
class UserAPIRouter(APIRouter):
|
||||
""" Router for functions to be protected behind user authentication """
|
||||
"""Router for functions to be protected behind user authentication"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
@@ -17,7 +17,7 @@ async def create_shopping_list(
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Create Shopping List in the Database """
|
||||
"""Create Shopping List in the Database"""
|
||||
db = get_database(session)
|
||||
list_in.group = current_user.group
|
||||
|
||||
@@ -26,20 +26,20 @@ async def create_shopping_list(
|
||||
|
||||
@router.get("/{id}", response_model=ShoppingListOut)
|
||||
async def get_shopping_list(id: int, session: Session = Depends(generate_session)):
|
||||
""" Get Shopping List from the Database """
|
||||
"""Get Shopping List from the Database"""
|
||||
db = get_database(session)
|
||||
return db.shopping_lists.get(id)
|
||||
|
||||
|
||||
@router.put("/{id}", response_model=ShoppingListOut)
|
||||
async def update_shopping_list(id: int, new_data: ShoppingListIn, session: Session = Depends(generate_session)):
|
||||
""" Update Shopping List in the Database """
|
||||
"""Update Shopping List in the Database"""
|
||||
db = get_database(session)
|
||||
return db.shopping_lists.update(id, new_data)
|
||||
|
||||
|
||||
@router.delete("/{id}")
|
||||
async def delete_shopping_list(id: int, session: Session = Depends(generate_session)):
|
||||
""" Delete Shopping List from the Database """
|
||||
"""Delete Shopping List from the Database"""
|
||||
db = get_database(session)
|
||||
return db.shopping_lists.delete(id)
|
||||
|
||||
@@ -14,7 +14,7 @@ admin_router = AdminAPIRouter(prefix="/api/site-settings", tags=["Settings"])
|
||||
|
||||
@public_router.get("")
|
||||
def get_main_settings(session: Session = Depends(generate_session)):
|
||||
""" Returns basic site settings """
|
||||
"""Returns basic site settings"""
|
||||
db = get_database(session)
|
||||
|
||||
return db.settings.get(1)
|
||||
@@ -25,7 +25,7 @@ def test_webhooks(
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Run the function to test your webhooks """
|
||||
"""Run the function to test your webhooks"""
|
||||
db = get_database(session)
|
||||
group_entry: GroupInDB = db.groups.get(current_user.group, "name")
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@ admin_router = AdminAPIRouter()
|
||||
|
||||
@public_router.get("")
|
||||
async def get_all_recipe_tags(session: Session = Depends(generate_session)):
|
||||
""" Returns a list of available tags in the database """
|
||||
"""Returns a list of available tags in the database"""
|
||||
db = get_database(session)
|
||||
return db.tags.get_all_limit_columns(["slug", "name"])
|
||||
|
||||
|
||||
@public_router.get("/empty")
|
||||
def get_empty_tags(session: Session = Depends(generate_session)):
|
||||
""" Returns a list of tags that do not contain any recipes"""
|
||||
"""Returns a list of tags that do not contain any recipes"""
|
||||
db = get_database(session)
|
||||
return db.tags.get_empty()
|
||||
|
||||
@@ -30,7 +30,7 @@ def get_empty_tags(session: Session = Depends(generate_session)):
|
||||
def get_all_recipes_by_tag(
|
||||
tag: str, session: Session = Depends(generate_session), is_user: bool = Depends(is_logged_in)
|
||||
):
|
||||
""" Returns a list of recipes associated with the provided tag. """
|
||||
"""Returns a list of recipes associated with the provided tag."""
|
||||
db = get_database(session)
|
||||
tag_obj = db.tags.get(tag)
|
||||
tag_obj = RecipeTagResponse.from_orm(tag_obj)
|
||||
@@ -43,14 +43,14 @@ def get_all_recipes_by_tag(
|
||||
|
||||
@user_router.post("")
|
||||
async def create_recipe_tag(tag: TagIn, session: Session = Depends(generate_session)):
|
||||
""" Creates a Tag in the database """
|
||||
"""Creates a Tag in the database"""
|
||||
db = get_database(session)
|
||||
return db.tags.create(tag.dict())
|
||||
|
||||
|
||||
@admin_router.put("/{tag}", response_model=RecipeTagResponse)
|
||||
async def update_recipe_tag(tag: str, new_tag: TagIn, session: Session = Depends(generate_session)):
|
||||
""" Updates an existing Tag in the database """
|
||||
"""Updates an existing Tag in the database"""
|
||||
db = get_database(session)
|
||||
return db.tags.update(tag, new_tag.dict())
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ async def create_api_token(
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Create api_token in the Database """
|
||||
"""Create api_token in the Database"""
|
||||
|
||||
token_data = {"long_token": True, "id": current_user.id}
|
||||
|
||||
@@ -47,7 +47,7 @@ async def delete_api_token(
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Delete api_token from the Database """
|
||||
"""Delete api_token from the Database"""
|
||||
db = get_database(session)
|
||||
token: LongLiveTokenInDB = db.api_tokens.get(token_id)
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ def delete_user(
|
||||
session: Session = Depends(generate_session),
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
):
|
||||
""" Removes a user from the database. Must be the current user or a super user"""
|
||||
"""Removes a user from the database. Must be the current user or a super user"""
|
||||
|
||||
assert_user_change_allowed(id, current_user)
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ user_router = UserAPIRouter()
|
||||
|
||||
@user_router.get("/{id}/favorites", response_model=UserFavorites)
|
||||
async def get_favorites(id: str, session: Session = Depends(generate_session)):
|
||||
""" Get user's favorite recipes """
|
||||
"""Get user's favorite recipes"""
|
||||
db = get_database(session)
|
||||
return db.users.get(id, override_schema=UserFavorites)
|
||||
|
||||
@@ -24,7 +24,7 @@ def add_favorite(
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Adds a Recipe to the users favorites """
|
||||
"""Adds a Recipe to the users favorites"""
|
||||
|
||||
current_user.favorite_recipes.append(slug)
|
||||
db = get_database(session)
|
||||
@@ -37,7 +37,7 @@ def remove_favorite(
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
session: Session = Depends(generate_session),
|
||||
):
|
||||
""" Adds a Recipe to the users favorites """
|
||||
"""Adds a Recipe to the users favorites"""
|
||||
|
||||
assert_user_change_allowed(id, current_user)
|
||||
current_user.favorite_recipes = [x for x in current_user.favorite_recipes if x != slug]
|
||||
|
||||
@@ -18,7 +18,7 @@ user_router = UserAPIRouter(prefix="", tags=["Users: Images"])
|
||||
|
||||
@public_router.get("/{id}/image")
|
||||
async def get_user_image(id: str):
|
||||
""" Returns a users profile picture """
|
||||
"""Returns a users profile picture"""
|
||||
user_dir = app_dirs.USER_DIR.joinpath(id)
|
||||
for recipe_image in user_dir.glob("profile_image.*"):
|
||||
return FileResponse(recipe_image)
|
||||
@@ -32,7 +32,7 @@ def update_user_image(
|
||||
profile_image: UploadFile = File(...),
|
||||
current_user: PrivateUser = Depends(get_current_user),
|
||||
):
|
||||
""" Updates a User Image """
|
||||
"""Updates a User Image"""
|
||||
|
||||
assert_user_change_allowed(id, current_user)
|
||||
|
||||
|
||||
@@ -26,19 +26,19 @@ async def reset_user_password(id: int, session: Session = Depends(generate_sessi
|
||||
|
||||
@user_router.put("/{item_id}/password")
|
||||
def update_password(password_change: ChangePassword, user_service: UserService = Depends(UserService.write_existing)):
|
||||
""" Resets the User Password"""
|
||||
"""Resets the User Password"""
|
||||
return user_service.change_password(password_change)
|
||||
|
||||
|
||||
@public_router.post("/forgot-password")
|
||||
def forgot_password(email: ForgotPassword, session: Session = Depends(generate_session)):
|
||||
""" Sends an email with a reset link to the user"""
|
||||
"""Sends an email with a reset link to the user"""
|
||||
f_service = PasswordResetService(session)
|
||||
return f_service.send_reset_email(email.email)
|
||||
|
||||
|
||||
@public_router.post("/reset-password")
|
||||
def reset_password(reset_password: ResetPassword, session: Session = Depends(generate_session)):
|
||||
""" Resets the user password"""
|
||||
"""Resets the user password"""
|
||||
f_service = PasswordResetService(session)
|
||||
return f_service.reset_password(reset_password.token, reset_password.password)
|
||||
|
||||
@@ -297,7 +297,7 @@ def import_data(lines):
|
||||
|
||||
|
||||
def export_data(lines):
|
||||
""" Parse "raw" ingredient lines into CRF-ready output """
|
||||
"""Parse "raw" ingredient lines into CRF-ready output"""
|
||||
output = []
|
||||
for line in lines:
|
||||
line_clean = re.sub("<[^<]+?>", "", line)
|
||||
|
||||
@@ -1,6 +1,24 @@
|
||||
from mealie.schema.recipe import Recipe
|
||||
from mealie.schema.recipe.recipe_ingredient import RecipeIngredient
|
||||
from mealie.schema.recipe.recipe_step import RecipeStep
|
||||
from mealie.schema.user.user import PrivateUser
|
||||
|
||||
step_text = """Recipe steps as well as other fields in the recipe page support markdown syntax.
|
||||
|
||||
**Add a link**
|
||||
|
||||
[My Link](https://beta.mealie.io)
|
||||
|
||||
**Imbed an image**
|
||||
|
||||
Use the `height="100"` or `width="100"` attributes to set the size of the image.
|
||||
|
||||
<img height="100" src="https://images.unsplash.com/photo-1567620905732-2d1ec7ab7445?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=960&q=80"></img>
|
||||
|
||||
"""
|
||||
|
||||
ingredient_note = "1 Cup Flour"
|
||||
|
||||
|
||||
def recipe_creation_factory(user: PrivateUser, name: str, additional_attrs: dict = None) -> Recipe:
|
||||
"""
|
||||
@@ -13,4 +31,10 @@ def recipe_creation_factory(user: PrivateUser, name: str, additional_attrs: dict
|
||||
additional_attrs["user_id"] = user.id
|
||||
additional_attrs["group_id"] = user.group_id
|
||||
|
||||
if not additional_attrs.get("recipe_ingredient"):
|
||||
additional_attrs["recipe_ingredient"] = [RecipeIngredient(note=ingredient_note)]
|
||||
|
||||
if not additional_attrs.get("recipe_instructions"):
|
||||
additional_attrs["recipe_instructions"] = [RecipeStep(text=step_text)]
|
||||
|
||||
return Recipe(**additional_attrs)
|
||||
|
||||
@@ -13,6 +13,7 @@ from mealie.core.dependencies.grouped import PublicDeps, UserDeps
|
||||
from mealie.core.root_logger import get_logger
|
||||
from mealie.db.data_access_layer.recipe_access_model import RecipeDataAccessModel
|
||||
from mealie.schema.recipe.recipe import CreateRecipe, Recipe, RecipeSummary
|
||||
from mealie.schema.recipe.recipe_settings import RecipeSettings
|
||||
from mealie.services._base_http_service.crud_http_mixins import CrudHttpMixins
|
||||
from mealie.services._base_http_service.http_services import UserHttpService
|
||||
from mealie.services.events import create_recipe_event
|
||||
@@ -71,8 +72,25 @@ class RecipeService(CrudHttpMixins[CreateRecipe, Recipe, Recipe], UserHttpServic
|
||||
return [RecipeSummary.construct(**x) for x in new_items]
|
||||
|
||||
def create_one(self, create_data: Union[Recipe, CreateRecipe]) -> Recipe:
|
||||
create_data = recipe_creation_factory(self.user, name=create_data.name, additional_attrs=create_data.dict())
|
||||
group = self.db.groups.get(self.group_id, "id")
|
||||
|
||||
create_data = recipe_creation_factory(
|
||||
self.user,
|
||||
name=create_data.name,
|
||||
additional_attrs=create_data.dict(),
|
||||
)
|
||||
|
||||
create_data.settings = RecipeSettings(
|
||||
public=group.preferences.recipe_public,
|
||||
show_nutrition=group.preferences.recipe_show_nutrition,
|
||||
show_assets=group.preferences.recipe_show_assets,
|
||||
landscape_view=group.preferences.recipe_landscape_view,
|
||||
disable_comments=group.preferences.recipe_disable_comments,
|
||||
disable_amount=group.preferences.recipe_disable_amount,
|
||||
)
|
||||
|
||||
self._create_one(create_data, self.t("generic.server-error"), self.exception_key)
|
||||
|
||||
self._create_event(
|
||||
"Recipe Created",
|
||||
f"'{self.item.name}' by {self.user.username} \n {self.settings.BASE_URL}/recipe/{self.item.slug}",
|
||||
|
||||
Reference in New Issue
Block a user