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:
Hayden
2021-11-20 14:30:38 -09:00
committed by GitHub
parent d4bf81dee6
commit 912cc6d956
50 changed files with 456 additions and 246 deletions

View File

@@ -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:

View File

@@ -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)

View File

@@ -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)

View File

@@ -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(

View File

@@ -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)

View File

@@ -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:

View File

@@ -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)}

View 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(

View File

@@ -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"}

View File

@@ -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():

View 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:

View File

@@ -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()

View File

@@ -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:

View File

@@ -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)

View File

@@ -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:

View File

@@ -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)

View File

@@ -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()

View File

@@ -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:

View File

@@ -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,

View File

@@ -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)

View File

@@ -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")

View File

@@ -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())

View File

@@ -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)

View File

@@ -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)

View File

@@ -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]

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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}",