From 7a2f91eb321ea0aeb300da71422d81ea862384c2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 10:53:32 +0100 Subject: [PATCH 01/17] chore(deps): update dependency pre-commit to v4.1.0 (#4922) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 8ca7c7b69..944a4ed2f 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1931,13 +1931,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "4.0.1" +version = "4.1.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.9" files = [ - {file = "pre_commit-4.0.1-py2.py3-none-any.whl", hash = "sha256:efde913840816312445dc98787724647c65473daefe420785f885e8ed9a06878"}, - {file = "pre_commit-4.0.1.tar.gz", hash = "sha256:80905ac375958c0444c65e9cebebd948b3cdb518f335a091a670a89d652139d2"}, + {file = "pre_commit-4.1.0-py2.py3-none-any.whl", hash = "sha256:d29e7cb346295bcc1cc75fc3e92e343495e3ea0196c9ec6ba53f49f10ab6ae7b"}, + {file = "pre_commit-4.1.0.tar.gz", hash = "sha256:ae3f018575a588e30dfddfab9a05448bfbd6b73d78709617b5a2b853549716d4"}, ] [package.dependencies] From 17bed603992f07e2ac1dc1935b521b29580b1a0f Mon Sep 17 00:00:00 2001 From: Felix Schneider Date: Tue, 21 Jan 2025 17:44:01 +0100 Subject: [PATCH 02/17] docs: Add community guide for integrating the Mealie-Bring-API (#4920) --- docs/docs/documentation/community-guide/bring-api.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/docs/documentation/community-guide/bring-api.md diff --git a/docs/docs/documentation/community-guide/bring-api.md b/docs/docs/documentation/community-guide/bring-api.md new file mode 100644 index 000000000..41214bb0c --- /dev/null +++ b/docs/docs/documentation/community-guide/bring-api.md @@ -0,0 +1,8 @@ +!!! info +This guide was submitted by a community member. Find something wrong? Submit a PR to get it fixed! + +Mealie supports adding the ingredients of a recipe to your [Bring](https://www.getbring.com/) shopping list, as you can +see [here](https://docs.mealie.io/documentation/getting-started/features/#recipe-actions). +However, for this to work, your Mealie instance needs to be exposed to the open Internet so that the Bring servers can access its information. If you don't want your server to be publicly accessible for security reasons, you can use the [Mealie-Bring-API](https://github.com/felixschndr/mealie-bring-api) written by a community member. This integration is entirely local and does not require any service to be exposed to the Internet. + +This is a small web server that runs locally next to your Mealie instance, and instead of Bring pulling the data from you, it pushes the data to Bring. [Check out the project](https://github.com/felixschndr/mealie-bring-api) for more information and installation instructions. From c74ba0eca1216bcd72905f6b76854cceeec87d7c Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Tue, 21 Jan 2025 14:29:01 -0600 Subject: [PATCH 03/17] chore(l10n): New Crowdin updates (#4926) --- frontend/lang/messages/es-ES.json | 40 +++++++++++++++---------------- mealie/lang/messages/es-ES.json | 14 +++++------ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/frontend/lang/messages/es-ES.json b/frontend/lang/messages/es-ES.json index 5edd7acaf..093f5d87e 100644 --- a/frontend/lang/messages/es-ES.json +++ b/frontend/lang/messages/es-ES.json @@ -277,7 +277,7 @@ "admin-group-management-text": "Los cambios en este grupo se reflejarán inmediatamente.", "group-id-value": "Id del Grupo: {0}", "total-households": "Total de Casas", - "you-must-select-a-group-before-selecting-a-household": "You must select a group before selecting a household" + "you-must-select-a-group-before-selecting-a-household": "Debe seleccionar un grupo antes de seleccionar un hogar" }, "household": { "household": "Casa", @@ -518,7 +518,7 @@ "save-recipe-before-use": "Guardar la receta antes de usar", "section-title": "Título de la sección", "servings": "Porciones", - "serves-amount": "Serves {amount}", + "serves-amount": "Personas {amount}", "share-recipe-message": "Quería compartir mi receta {0} contigo.", "show-nutrition-values": "Mostrar valores nutricionales", "sodium-content": "Sodio", @@ -547,8 +547,8 @@ "failed-to-add-recipe-to-mealplan": "Error al añadir receta al menú", "failed-to-add-to-list": "No se pudo agregar a la lista", "yield": "Raciones", - "yields-amount-with-text": "Yields {amount} {text}", - "yield-text": "Yield Text", + "yields-amount-with-text": "Raciones {amount} {text}", + "yield-text": "Texto de raciones", "quantity": "Cantidad", "choose-unit": "Elija unidad", "press-enter-to-create": "Presione Intro para crear", @@ -637,9 +637,9 @@ "recipe-debugger-use-openai-description": "Utilice OpenAI para analizar los resultados en lugar de depender de la biblioteca de analizadores. Cuando se crea una receta a través de la URL, esto se hace automáticamente si la biblioteca del analizador falla, pero puede probarla manualmente aquí.", "debug": "Depuración", "tree-view": "Vista en árbol", - "recipe-servings": "Recipe Servings", + "recipe-servings": "Cantidad de personas", "recipe-yield": "Porciones", - "recipe-yield-text": "Recipe Yield Text", + "recipe-yield-text": "Texto de raciones totales", "unit": "Unidades", "upload-image": "Subir imagen", "screen-awake": "Mantener la pantalla encendida", @@ -662,24 +662,24 @@ "no-food": "Sin Comida" }, "reset-servings-count": "Restablecer contador de porciones", - "not-linked-ingredients": "Additional Ingredients" + "not-linked-ingredients": "Ingredientes adicionales" }, "recipe-finder": { - "recipe-finder": "Recipe Finder", - "recipe-finder-description": "Search for recipes based on ingredients you have on hand. You can also filter by tools you have available, and set a maximum number of missing ingredients or tools.", + "recipe-finder": "Buscador de recetas", + "recipe-finder-description": "Busca recetas basadas en los ingredientes que tengas disponibles. También puede filtrar por utensilios disponibles, y establecer un número máximo de ingredientes o herramientas que faltan.", "selected-ingredients": "Ingredientes seleccionados", "no-ingredients-selected": "Ningún ingrediente seleccionado", - "missing": "Missing", + "missing": "Faltan", "no-recipes-found": "No se encontraron recetas", "no-recipes-found-description": "Intenta añadir más ingredientes a tu búsqueda o ajustar tus filtros", "include-ingredients-on-hand": "Incluye ingredientes a mano", - "include-tools-on-hand": "Include Tools On Hand", - "max-missing-ingredients": "Max Missing Ingredients", - "max-missing-tools": "Max Missing Tools", - "selected-tools": "Selected Tools", - "other-filters": "Other Filters", - "ready-to-make": "Ready to Make", - "almost-ready-to-make": "Almost Ready to Make" + "include-tools-on-hand": "Incluye utensilios disponibles", + "max-missing-ingredients": "Máximo de ingredientes que faltan", + "max-missing-tools": "Máximo de utensilios que faltan", + "selected-tools": "Utensilios seleccionados", + "other-filters": "Otros filtros", + "ready-to-make": "Listo para hacer", + "almost-ready-to-make": "Casi listo para hacer" }, "search": { "advanced-search": "Búsqueda avanzada", @@ -884,7 +884,7 @@ "are-you-sure-you-want-to-check-all-items": "¿Seguro que quieres seleccionar todos los elementos?", "are-you-sure-you-want-to-uncheck-all-items": "¿Seguro que quieres de-seleccionar todos los elementos?", "are-you-sure-you-want-to-delete-checked-items": "¿Está seguro que deseas eliminar los elementos seleccionados?", - "no-shopping-lists-found": "No Shopping Lists Found" + "no-shopping-lists-found": "No hay listas de la compra" }, "sidebar": { "all-recipes": "Recetas", @@ -1296,7 +1296,7 @@ "profile": { "welcome-user": "👋 ¡Bienvenido, {0}!", "description": "Administra tu perfil, recetas y ajustes de grupo.", - "invite-link": "Invite Link", + "invite-link": "Link de invitación", "get-invite-link": "Obtener enlace de invitación", "get-public-link": "Obtener enlace público", "account-summary": "Información de la cuenta", @@ -1346,7 +1346,7 @@ "cookbook": { "cookbooks": "Recetarios", "description": "Los recetarios son otra forma de organizar recetas creando secciones cruzadas de recetas y etiquetas. Crear un recetario añadirá una entrada a la barra lateral y todas las recetas con las etiquetas y categorías elegidas se mostrarán en el recetario.", - "hide-cookbooks-from-other-households": "Hide Cookbooks from Other Households", + "hide-cookbooks-from-other-households": "Ocultar libros de cocina de otros grupos/hogares", "hide-cookbooks-from-other-households-description": "Cuando esté habilitado, sólo los libros de cocina de su hogar aparecerán en la barra lateral", "public-cookbook": "Recetario público", "public-cookbook-description": "Los recetarios públicos se pueden compartir con usuarios externos y se mostrarán en su página de grupos.", diff --git a/mealie/lang/messages/es-ES.json b/mealie/lang/messages/es-ES.json index 33ad1e36c..06edabd99 100644 --- a/mealie/lang/messages/es-ES.json +++ b/mealie/lang/messages/es-ES.json @@ -4,18 +4,18 @@ }, "recipe": { "unique-name-error": "El nombre de la receta debe ser único", - "recipe-created": "Recipe Created", + "recipe-created": "Receta creada", "recipe-defaults": { "ingredient-note": "1 Taza de harina", "step-text": "Los pasos de receta, así como otros campos en la página de recetas, soportan sintaxis Markdown.\n\n**Agregar un enlace**\n\n[Mi Enlace](https://demo.mealie.io)\n" }, "servings-text": { - "makes": "Makes", - "serves": "Serves", - "serving": "Serving", - "servings": "Servings", - "yield": "Yield", - "yields": "Yields" + "makes": "Realizadas", + "serves": "Personas", + "serving": "Porción", + "servings": "Porciones", + "yield": "Ración", + "yields": "Raciones" } }, "mealplan": { From 8cd2da0abbc47be9483f9b516638e00300eafcd0 Mon Sep 17 00:00:00 2001 From: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:51:29 +0100 Subject: [PATCH 04/17] fix: prevent recipe sharing from different group (#4929) --- mealie/routes/shared/__init__.py | 6 ++++++ .../user_recipe_tests/test_recipe_share_tokens.py | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/mealie/routes/shared/__init__.py b/mealie/routes/shared/__init__.py index 14bbb4a19..cad900646 100644 --- a/mealie/routes/shared/__init__.py +++ b/mealie/routes/shared/__init__.py @@ -1,5 +1,6 @@ from functools import cached_property +from fastapi import HTTPException from pydantic import UUID4 from mealie.routes._base import BaseUserController, controller @@ -30,6 +31,11 @@ class RecipeSharedController(BaseUserController): @router.post("", response_model=RecipeShareToken, status_code=201) def create_one(self, data: RecipeShareTokenCreate) -> RecipeShareToken: + # check if recipe group id is the same as the user group id + recipe = self.repos.recipes.get_one(data.recipe_id, "id") + if recipe is None or recipe.group_id != self.group_id: + raise HTTPException(status_code=404, detail="Recipe not found in your group") + save_data = RecipeShareTokenSave(**data.model_dump(), group_id=self.group_id) return self.mixins.create_one(save_data) diff --git a/tests/integration_tests/user_recipe_tests/test_recipe_share_tokens.py b/tests/integration_tests/user_recipe_tests/test_recipe_share_tokens.py index 183d07363..7d4fc6c57 100644 --- a/tests/integration_tests/user_recipe_tests/test_recipe_share_tokens.py +++ b/tests/integration_tests/user_recipe_tests/test_recipe_share_tokens.py @@ -110,3 +110,12 @@ def test_recipe_share_tokens_delete_one(api_client: TestClient, unique_user: Tes token = database.recipe_share_tokens.get_one(token.id) assert token is None + + +def test_share_recipe_from_different_group(api_client: TestClient, unique_user: TestUser, g2_user: TestUser, slug: str): + database = unique_user.repos + recipe = database.recipes.get_one(slug) + assert recipe + + response = api_client.post(api_routes.shared_recipes, json={"recipeId": str(recipe.id)}, headers=g2_user.token) + assert response.status_code == 404 From bf616f9db5173d5f32cf53e9d034e2c307dda006 Mon Sep 17 00:00:00 2001 From: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com> Date: Wed, 22 Jan 2025 17:06:41 +0100 Subject: [PATCH 05/17] fix: prevent users from updating their own household privileges (#4928) Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com> --- .../controller_household_self_service.py | 3 + mealie/routes/users/_helpers.py | 49 +++++++++++-- mealie/routes/users/crud.py | 21 +----- mealie/routes/users/images.py | 2 +- mealie/routes/users/ratings.py | 2 +- .../test_household_permissions.py | 13 ++++ .../user_tests/test_user_crud.py | 71 ++++++++++++++++++- 7 files changed, 133 insertions(+), 28 deletions(-) diff --git a/mealie/routes/households/controller_household_self_service.py b/mealie/routes/households/controller_household_self_service.py index c3a7e0083..89b7c7112 100644 --- a/mealie/routes/households/controller_household_self_service.py +++ b/mealie/routes/households/controller_household_self_service.py @@ -76,6 +76,9 @@ class HouseholdSelfServiceController(BaseUserController): if target_user.household_id != self.household_id: raise HTTPException(status.HTTP_403_FORBIDDEN, detail="User is not a member of this household") + if target_user.id == self.user.id: + raise HTTPException(status.HTTP_403_FORBIDDEN, detail="User is not allowed to change their own permissions") + target_user.can_invite = permissions.can_invite target_user.can_manage = permissions.can_manage target_user.can_manage_household = permissions.can_manage_household diff --git a/mealie/routes/users/_helpers.py b/mealie/routes/users/_helpers.py index 83a5dbb25..6b69a1849 100644 --- a/mealie/routes/users/_helpers.py +++ b/mealie/routes/users/_helpers.py @@ -1,10 +1,49 @@ from fastapi import HTTPException, status from pydantic import UUID4 -from mealie.schema.user.user import PrivateUser +from mealie.schema.response.responses import ErrorResponse +from mealie.schema.user.user import PrivateUser, UserBase + +permission_attrs = ["can_invite", "can_manage", "can_manage_household", "can_organize", "admin"] -def assert_user_change_allowed(id: UUID4, current_user: PrivateUser): - if current_user.id != id and not current_user.admin: - # only admins can edit other users - raise HTTPException(status.HTTP_403_FORBIDDEN, detail="NOT_AN_ADMIN") +def _assert_non_admin_user_change_allowed(user_id: UUID4, current_user: PrivateUser, new_data: UserBase): + if current_user.id != user_id: + # User is trying to edit another user + raise HTTPException(status.HTTP_403_FORBIDDEN, ErrorResponse.respond("User cannot edit other users")) + + if any(getattr(current_user, p) != getattr(new_data, p) for p in permission_attrs): + # User is trying to change their own permissions + raise HTTPException( + status.HTTP_403_FORBIDDEN, + ErrorResponse.respond("User cannot change their own permissions"), + ) + + if current_user.group != new_data.group: + # prevent a regular user from changing their group + raise HTTPException( + status.HTTP_403_FORBIDDEN, ErrorResponse.respond("User doesn't have permission to change their group") + ) + + if current_user.household != new_data.household: + # prevent a regular user from changing their household + raise HTTPException( + status.HTTP_403_FORBIDDEN, + ErrorResponse.respond("User doesn't have permission to change their household"), + ) + + +def assert_user_change_allowed(user_id: UUID4, current_user: PrivateUser, new_data: UserBase): + if not current_user.admin: + _assert_non_admin_user_change_allowed(user_id, current_user, new_data) + return + + if current_user.id != user_id: + raise HTTPException(status.HTTP_403_FORBIDDEN, ErrorResponse.respond("Use the Admin API to update other users")) + + # Admin is trying to edit themselves + if any(getattr(current_user, p) != getattr(new_data, p) for p in permission_attrs): + # prevent an admin from excalating their own permissions + raise HTTPException( + status.HTTP_403_FORBIDDEN, ErrorResponse.respond("Admins can't change their own permissions") + ) diff --git a/mealie/routes/users/crud.py b/mealie/routes/users/crud.py index bdec3a20c..a246b6fa3 100644 --- a/mealie/routes/users/crud.py +++ b/mealie/routes/users/crud.py @@ -46,13 +46,6 @@ class AdminUserController(BaseAdminController): @admin_router.delete("/{item_id}") def delete_user(self, item_id: UUID4): - """Removes a user from the database. Must be the current user or a super user""" - - assert_user_change_allowed(item_id, self.user) - - if item_id == 1: # TODO: identify super_user - raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="SUPER_USER") - self.mixins.delete_one(item_id) @@ -106,19 +99,7 @@ class UserController(BaseUserController): @user_router.put("/{item_id}") def update_user(self, item_id: UUID4, new_data: UserBase): - assert_user_change_allowed(item_id, self.user) - - if not self.user.admin and (new_data.admin or self.user.group != new_data.group): - # prevent a regular user from doing admin tasks on themself - raise HTTPException( - status.HTTP_403_FORBIDDEN, ErrorResponse.respond("User doesn't have permission to change group") - ) - - if self.user.id == item_id and self.user.admin and not new_data.admin: - # prevent an admin from demoting themself - raise HTTPException( - status.HTTP_403_FORBIDDEN, ErrorResponse.respond("User doesn't have permission to change group") - ) + assert_user_change_allowed(item_id, self.user, new_data) try: self.repos.users.update(item_id, new_data.model_dump()) diff --git a/mealie/routes/users/images.py b/mealie/routes/users/images.py index e3d54e8d1..b472e4b1f 100644 --- a/mealie/routes/users/images.py +++ b/mealie/routes/users/images.py @@ -23,7 +23,7 @@ class UserImageController(BaseUserController): ): """Updates a User Image""" with get_temporary_path() as temp_path: - assert_user_change_allowed(id, self.user) + assert_user_change_allowed(id, self.user, self.user) temp_img = temp_path.joinpath(profile.filename) with temp_img.open("wb") as buffer: diff --git a/mealie/routes/users/ratings.py b/mealie/routes/users/ratings.py index c37849999..16adc99e5 100644 --- a/mealie/routes/users/ratings.py +++ b/mealie/routes/users/ratings.py @@ -54,7 +54,7 @@ class UserRatingsController(BaseUserController): @router.post("/{id}/ratings/{slug}") def set_rating(self, id: UUID4, slug: str, data: UserRatingUpdate): """Sets the user's rating for a recipe""" - assert_user_change_allowed(id, self.user) + assert_user_change_allowed(id, self.user, self.user) recipe = self.get_recipe_or_404(slug) user_rating = self.repos.user_ratings.get_by_user_and_recipe(id, recipe.id) diff --git a/tests/integration_tests/user_household_tests/test_household_permissions.py b/tests/integration_tests/user_household_tests/test_household_permissions.py index f467a6d76..b18b3aa25 100644 --- a/tests/integration_tests/user_household_tests/test_household_permissions.py +++ b/tests/integration_tests/user_household_tests/test_household_permissions.py @@ -86,3 +86,16 @@ def test_set_member_permissions_no_user( payload = get_permissions_payload(str(uuid4())) response = api_client.put(api_routes.households_permissions, json=payload, headers=unique_user.token) assert response.status_code == 404 + + +def test_set_own_permissions(api_client: TestClient, unique_user: TestUser): + database = unique_user.repos + + user = database.users.get_one(unique_user.user_id) + assert user + user.can_manage = True + database.users.update(user.id, user) + + form = {"user_id": str(unique_user.user_id), "canOrganize": not user.can_organize} + response = api_client.put(api_routes.households_permissions, json=form, headers=unique_user.token) + assert response.status_code == 403 diff --git a/tests/integration_tests/user_tests/test_user_crud.py b/tests/integration_tests/user_tests/test_user_crud.py index e2c1d3f2b..9d4a60e28 100644 --- a/tests/integration_tests/user_tests/test_user_crud.py +++ b/tests/integration_tests/user_tests/test_user_crud.py @@ -1,8 +1,9 @@ import pytest from fastapi.testclient import TestClient -from tests.utils import TestUser, api_routes +from tests.utils import api_routes from tests.utils.factories import random_email, random_int, random_string +from tests.utils.fixture_schemas import TestUser @pytest.mark.parametrize("use_admin_user", [True, False]) @@ -43,3 +44,71 @@ def test_get_all_users_admin(request: pytest.FixtureRequest, api_client: TestCli response_user_ids = {user["id"] for user in response.json()["items"]} for user_id in user_ids: assert user_id in response_user_ids + + +def test_user_update(api_client: TestClient, unique_user: TestUser, admin_user: TestUser): + response = api_client.get(api_routes.users_self, headers=unique_user.token) + user = response.json() + + # valid request without updates + response = api_client.put(api_routes.users_item_id(unique_user.user_id), json=user, headers=unique_user.token) + assert response.status_code == 200 + + # valid request with updates + tmp_user = user.copy() + tmp_user["email"] = random_email() + tmp_user["full_name"] = random_string() + response = api_client.put(api_routes.users_item_id(unique_user.user_id), json=tmp_user, headers=unique_user.token) + assert response.status_code == 200 + + # test user attempting to update another user + form = {"email": admin_user.email, "full_name": admin_user.full_name} + response = api_client.put(api_routes.users_item_id(admin_user.user_id), json=form, headers=unique_user.token) + assert response.status_code == 403 + + # test user attempting permission changes + permissions = ["canInvite", "canManage", "canManageHousehold", "canOrganize", "advanced", "admin"] + for permission in permissions: + tmp_user = user.copy() + tmp_user[permission] = not user[permission] + response = api_client.put(api_routes.users_item_id(unique_user.user_id), json=form, headers=unique_user.token) + assert response.status_code == 403 + + # test user attempting to change group + tmp_user = user.copy() + tmp_user["group"] = random_string() + response = api_client.put(api_routes.users_item_id(unique_user.user_id), json=tmp_user, headers=unique_user.token) + assert response.status_code == 403 + + # test user attempting to change household + tmp_user = user.copy() + tmp_user["household"] = random_string() + response = api_client.put(api_routes.users_item_id(unique_user.user_id), json=tmp_user, headers=unique_user.token) + assert response.status_code == 403 + + +def test_admin_updates(api_client: TestClient, admin_user: TestUser, unique_user: TestUser): + response = api_client.get(api_routes.users_item_id(unique_user.user_id), headers=admin_user.token) + user = response.json() + response = api_client.get(api_routes.users_item_id(admin_user.user_id), headers=admin_user.token) + admin = response.json() + + # admin updating themselves + tmp_user = admin.copy() + tmp_user["fullName"] = random_string() + response = api_client.put(api_routes.users_item_id(admin_user.user_id), json=tmp_user, headers=admin_user.token) + assert response.status_code == 200 + + # admin updating another user via the normal user route + tmp_user = user.copy() + tmp_user["fullName"] = random_string() + response = api_client.put(api_routes.users_item_id(unique_user.user_id), json=tmp_user, headers=admin_user.token) + assert response.status_code == 403 + + # admin updating their own permissions + permissions = ["canInvite", "canManage", "canManageHousehold", "canOrganize", "admin"] + for permission in permissions: + tmp_user = admin.copy() + tmp_user[permission] = not admin[permission] + response = api_client.put(api_routes.users_item_id(admin_user.user_id), json=tmp_user, headers=admin_user.token) + assert response.status_code == 403 From d2ced50fcceceb35e742765d99fd76378284f228 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 17:47:55 +0100 Subject: [PATCH 06/17] fix(deps): update dependency openai to v1.60.0 (#4932) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 944a4ed2f..ec6adf826 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1590,13 +1590,13 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] [[package]] name = "openai" -version = "1.59.9" +version = "1.60.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" files = [ - {file = "openai-1.59.9-py3-none-any.whl", hash = "sha256:61a0608a1313c08ddf92fe793b6dbd1630675a1fe3866b2f96447ce30050c448"}, - {file = "openai-1.59.9.tar.gz", hash = "sha256:ec1a20b0351b4c3e65c6292db71d8233515437c6065efd4fd50edeb55df5f5d2"}, + {file = "openai-1.60.0-py3-none-any.whl", hash = "sha256:df06c43be8018274980ac363da07d4b417bd835ead1c66e14396f6f15a0d5dda"}, + {file = "openai-1.60.0.tar.gz", hash = "sha256:7fa536cd4b644718645b874d2706e36dbbef38b327e42ca0623275da347ee1a9"}, ] [package.dependencies] From 0b89ab1a95b1688e987822d2b57bb84819078db6 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:51:47 -0600 Subject: [PATCH 07/17] chore(l10n): New Crowdin updates (#4934) --- frontend/lang/messages/cs-CZ.json | 20 +++++++++---------- .../seed/resources/foods/locales/cs-CZ.json | 6 +++--- .../seed/resources/units/locales/cs-CZ.json | 10 +++++----- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/frontend/lang/messages/cs-CZ.json b/frontend/lang/messages/cs-CZ.json index 40940d3b8..934378a7e 100644 --- a/frontend/lang/messages/cs-CZ.json +++ b/frontend/lang/messages/cs-CZ.json @@ -349,7 +349,7 @@ "note-only": "Pouze poznámka", "random-meal": "Náhodné jídlo", "random-dinner": "Náhodná večeře", - "random-side": "Random Side", + "random-side": "Náhodná příloha", "this-rule-will-apply": "Toto pravidlo se použije {dayCriteria} {mealTypeCriteria}.", "to-all-days": "na všechny dny", "on-days": "on {0}s", @@ -1059,14 +1059,14 @@ "food-label": "Označení jídla", "edit-food": "Upravit jídlo", "food-data": "Data jídla", - "example-food-singular": "ex: Onion", - "example-food-plural": "ex: Onions", + "example-food-singular": "např.: Brambora", + "example-food-plural": "např.: Brambory", "label-overwrite-warning": "Toto přiřadí vybraný štítek všem vybraným jídlům a může přepsat stávající štítky.", "on-hand-checkbox-label": "Nastavením tohoto příznaku bude tato potravina při přidávání receptu do nákupního seznamu ve výchozím nastavení odškrtnuta." }, "units": { "seed-dialog-text": "Naplnit databázi s běžnými jednotkami používanými ve vašem jazyce.", - "combine-unit-description": "Combining the selected units will merge the Source Unit and Target Unit into a single unit. The {source-unit-will-be-deleted} and all of the references to the Source Unit will be updated to point to the Target Unit.", + "combine-unit-description": "Zkombinování zvolených jednotek spojí zdrojovou a cílovou jednotku do jedné. {source-unit-will-be-deleted} a všechny odkazy na ni budou upraveny na cílovou jednotku.", "combine-unit": "Kombinovaná jednotka", "source-unit": "Zdrojová jednotka", "target-unit": "Cílová jednotka", @@ -1081,10 +1081,10 @@ "unit-data": "Data jednotky", "use-abbv": "Používat zkratky", "fraction": "Zlomek", - "example-unit-singular": "ex: Tablespoon", - "example-unit-plural": "ex: Tablespoons", - "example-unit-abbreviation-singular": "ex: Tbsp", - "example-unit-abbreviation-plural": "ex: Tbsps" + "example-unit-singular": "např.: Čajová lžička", + "example-unit-plural": "např.: Čajové lžičky", + "example-unit-abbreviation-singular": "např.: čl", + "example-unit-abbreviation-plural": "např.: čl" }, "labels": { "seed-dialog-text": "Naplnit databázi s běžnými popisky používanými ve vašem jazyce.", @@ -1296,7 +1296,7 @@ "profile": { "welcome-user": "👋 Vítejte, {0}!", "description": "Spravujte svůj profil, recepty a nastavení skupiny.", - "invite-link": "Invite Link", + "invite-link": "Odkaz pozvánky", "get-invite-link": "Získat odkaz na pozvánku", "get-public-link": "Získat veřejný odkaz", "account-summary": "Přehled účtu", @@ -1346,7 +1346,7 @@ "cookbook": { "cookbooks": "Kuchařky", "description": "Kuchařky jsou dalším způsobem, jak uspořádat recepty vytvořením průřezů receptů, organizátorů a dalších filtrů. Vytvořením kuchařky se přidá položka na postranní panel a v kuchařce se zobrazí všechny recepty s vybranými filtry.", - "hide-cookbooks-from-other-households": "Hide Cookbooks from Other Households", + "hide-cookbooks-from-other-households": "Skrýt kuchařky ostatních domácností", "hide-cookbooks-from-other-households-description": "Pokud je povoleno, objeví se na postranním panelu pouze kuchařské knihy z vaší domácnosti", "public-cookbook": "Veřejná kuchařka", "public-cookbook-description": "Veřejné kuchařky mohou být sdíleny s neregistrovanými uživateli a budou zobrazeny na stránce vaší skupiny.", diff --git a/mealie/repos/seed/resources/foods/locales/cs-CZ.json b/mealie/repos/seed/resources/foods/locales/cs-CZ.json index b8cbc31b3..cd563f227 100644 --- a/mealie/repos/seed/resources/foods/locales/cs-CZ.json +++ b/mealie/repos/seed/resources/foods/locales/cs-CZ.json @@ -48,7 +48,7 @@ }, "bell-peppers": { "name": "papriky", - "plural_name": "bell peppers" + "plural_name": "papriky" }, "blackberries": { "name": "ostružiny" @@ -260,8 +260,8 @@ "name": "kapradiny" }, "fiddlehead-fern": { - "name": "fiddlehead fern", - "plural_name": "fiddlehead ferns" + "name": "kapradina", + "plural_name": "kapradiny" }, "fish": { "name": "ryba" diff --git a/mealie/repos/seed/resources/units/locales/cs-CZ.json b/mealie/repos/seed/resources/units/locales/cs-CZ.json index 77c8df955..acfe45240 100644 --- a/mealie/repos/seed/resources/units/locales/cs-CZ.json +++ b/mealie/repos/seed/resources/units/locales/cs-CZ.json @@ -15,7 +15,7 @@ "name": "šálek", "plural_name": "šálků", "description": "", - "abbreviation": "c" + "abbreviation": "š" }, "fluid-ounce": { "name": "dutá unce", @@ -31,7 +31,7 @@ }, "quart": { "name": "čtvrtka", - "plural_name": "quarts", + "plural_name": "čtvrtky", "description": "", "abbreviation": "čtvrtka" }, @@ -92,7 +92,7 @@ }, "dash": { "name": "špetka", - "plural_name": "dashes", + "plural_name": "špetky", "description": "", "abbreviation": "" }, @@ -127,8 +127,8 @@ "abbreviation": "" }, "pack": { - "name": "pack", - "plural_name": "packs", + "name": "balení", + "plural_name": "balení", "description": "", "abbreviation": "" }, From 2716260473c48a413be5c742d62fc92a9617c2f7 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 Jan 2025 21:00:40 +0000 Subject: [PATCH 08/17] docs(auto): Update image tag, for release v2.5.0 (#4933) Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com> --- .../getting-started/installation/installation-checklist.md | 2 +- .../docs/documentation/getting-started/installation/postgres.md | 2 +- docs/docs/documentation/getting-started/installation/sqlite.md | 2 +- frontend/package.json | 2 +- pyproject.toml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/docs/documentation/getting-started/installation/installation-checklist.md b/docs/docs/documentation/getting-started/installation/installation-checklist.md index 1cf2500f7..9cc4f12cb 100644 --- a/docs/docs/documentation/getting-started/installation/installation-checklist.md +++ b/docs/docs/documentation/getting-started/installation/installation-checklist.md @@ -31,7 +31,7 @@ To deploy mealie on your local network, it is highly recommended to use Docker t We've gone through a few versions of Mealie v1 deployment targets. We have settled on a single container deployment, and we've begun publishing the nightly container on github containers. If you're looking to move from the old nightly (split containers _or_ the omni image) to the new nightly, there are a few things you need to do: 1. Take a backup just in case! -2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v2.4.2` +2. Replace the image for the API container with `ghcr.io/mealie-recipes/mealie:v2.5.0` 3. Take the external port from the frontend container and set that as the port mapped to port `9000` on the new container. The frontend is now served on port 9000 from the new container, so it will need to be mapped for you to have access. 4. Restart the container diff --git a/docs/docs/documentation/getting-started/installation/postgres.md b/docs/docs/documentation/getting-started/installation/postgres.md index dac2231c4..9c2062440 100644 --- a/docs/docs/documentation/getting-started/installation/postgres.md +++ b/docs/docs/documentation/getting-started/installation/postgres.md @@ -7,7 +7,7 @@ PostgreSQL might be considered if you need to support many concurrent users. In ```yaml services: mealie: - image: ghcr.io/mealie-recipes/mealie:v2.4.2 # (3) + image: ghcr.io/mealie-recipes/mealie:v2.5.0 # (3) container_name: mealie restart: always ports: diff --git a/docs/docs/documentation/getting-started/installation/sqlite.md b/docs/docs/documentation/getting-started/installation/sqlite.md index 49d2dd6f9..d1a92c09b 100644 --- a/docs/docs/documentation/getting-started/installation/sqlite.md +++ b/docs/docs/documentation/getting-started/installation/sqlite.md @@ -11,7 +11,7 @@ SQLite is a popular, open source, self-contained, zero-configuration database th ```yaml services: mealie: - image: ghcr.io/mealie-recipes/mealie:v2.4.2 # (3) + image: ghcr.io/mealie-recipes/mealie:v2.5.0 # (3) container_name: mealie restart: always ports: diff --git a/frontend/package.json b/frontend/package.json index ce8f058f7..1e7ba0582 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "mealie", -"version": "2.4.2", +"version": "2.5.0", "private": true, "scripts": { "dev": "nuxt", diff --git a/pyproject.toml b/pyproject.toml index 7c439ab96..c23328be3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ authors = ["Hayden "] description = "A Recipe Manager" license = "AGPL" name = "mealie" -version = "2.4.2" +version = "2.5.0" [tool.poetry.scripts] start = "mealie.app:main" From 2284ecb2260b587fb6a71e5f169764c33b59c328 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2025 11:22:02 -0600 Subject: [PATCH 09/17] fix(deps): update dependency fastapi to v0.115.7 (#4935) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index ec6adf826..7870cc4c8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -607,23 +607,23 @@ cli = ["requests"] [[package]] name = "fastapi" -version = "0.115.6" +version = "0.115.7" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"}, - {file = "fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654"}, + {file = "fastapi-0.115.7-py3-none-any.whl", hash = "sha256:eb6a8c8bf7f26009e8147111ff15b5177a0e19bb4a45bc3486ab14804539d21e"}, + {file = "fastapi-0.115.7.tar.gz", hash = "sha256:0f106da6c01d88a6786b3248fb4d7a940d071f6f488488898ad5d354b25ed015"}, ] [package.dependencies] pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" -starlette = ">=0.40.0,<0.42.0" +starlette = ">=0.40.0,<0.46.0" typing-extensions = ">=4.8.0" [package.extras] -all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] -standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=2.11.2)", "python-multipart (>=0.0.7)", "uvicorn[standard] (>=0.12.0)"] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "httpx (>=0.23.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "filelock" From 2fee1778ed4680f614e95c576a18552853456ac6 Mon Sep 17 00:00:00 2001 From: Hayden <64056131+hay-kot@users.noreply.github.com> Date: Thu, 23 Jan 2025 14:42:22 -0600 Subject: [PATCH 10/17] chore(l10n): New Crowdin updates (#4938) --- mealie/lang/messages/da-DK.json | 4 ++-- mealie/repos/seed/resources/foods/locales/da-DK.json | 2 +- mealie/repos/seed/resources/units/locales/da-DK.json | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mealie/lang/messages/da-DK.json b/mealie/lang/messages/da-DK.json index 2e1681a21..cfd3e51b9 100644 --- a/mealie/lang/messages/da-DK.json +++ b/mealie/lang/messages/da-DK.json @@ -42,7 +42,7 @@ "generic-updated": "{name} blev opdateret", "generic-created-with-url": "{name} er oprettet, {url}", "generic-updated-with-url": "{name} er blevet opdateret, {url}", - "generic-duplicated": "{name} er blevet dublikeret", + "generic-duplicated": "{name} er blevet duplikeret", "generic-deleted": "{name} er blevet slettet" }, "datetime": { @@ -60,7 +60,7 @@ "header_text": "Glemt adgangskode", "message_top": "Du har anmodet om at nulstille din adgangskode.", "message_bottom": "Klik på knappen ovenfor for at nulstille din adgangskode.", - "button_text": "Nulstil adgangskoden" + "button_text": "Nulstil adgangskode" }, "invitation": { "subject": "Invitation til at deltage i Mealie", diff --git a/mealie/repos/seed/resources/foods/locales/da-DK.json b/mealie/repos/seed/resources/foods/locales/da-DK.json index c5a00e426..20f74585b 100644 --- a/mealie/repos/seed/resources/foods/locales/da-DK.json +++ b/mealie/repos/seed/resources/foods/locales/da-DK.json @@ -9,7 +9,7 @@ "name": "ansjoser" }, "apples": { - "name": "æbler", + "name": "æble", "plural_name": "æbler" }, "artichoke": { diff --git a/mealie/repos/seed/resources/units/locales/da-DK.json b/mealie/repos/seed/resources/units/locales/da-DK.json index 518705433..f5d5fe827 100644 --- a/mealie/repos/seed/resources/units/locales/da-DK.json +++ b/mealie/repos/seed/resources/units/locales/da-DK.json @@ -73,8 +73,8 @@ "abbreviation": "g" }, "kilogram": { - "name": "kilogam", - "plural_name": "kilogam", + "name": "kilogram", + "plural_name": "kilogram", "description": "", "abbreviation": "kg" }, @@ -97,7 +97,7 @@ "abbreviation": "" }, "serving": { - "name": "servering", + "name": "portion", "plural_name": "portioner", "description": "", "abbreviation": "" From 8622e1950230f335152ca9aca0e75065686b1dc3 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 23 Jan 2025 15:14:55 -0600 Subject: [PATCH 11/17] chore(deps): update dependency ruff to v0.9.3 (#4939) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/poetry.lock b/poetry.lock index 7870cc4c8..914ce18ec 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2832,29 +2832,29 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "ruff" -version = "0.9.2" +version = "0.9.3" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" files = [ - {file = "ruff-0.9.2-py3-none-linux_armv6l.whl", hash = "sha256:80605a039ba1454d002b32139e4970becf84b5fee3a3c3bf1c2af6f61a784347"}, - {file = "ruff-0.9.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b9aab82bb20afd5f596527045c01e6ae25a718ff1784cb92947bff1f83068b00"}, - {file = "ruff-0.9.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:fbd337bac1cfa96be615f6efcd4bc4d077edbc127ef30e2b8ba2a27e18c054d4"}, - {file = "ruff-0.9.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82b35259b0cbf8daa22a498018e300b9bb0174c2bbb7bcba593935158a78054d"}, - {file = "ruff-0.9.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b6a9701d1e371bf41dca22015c3f89769da7576884d2add7317ec1ec8cb9c3c"}, - {file = "ruff-0.9.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cc53e68b3c5ae41e8faf83a3b89f4a5d7b2cb666dff4b366bb86ed2a85b481f"}, - {file = "ruff-0.9.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:8efd9da7a1ee314b910da155ca7e8953094a7c10d0c0a39bfde3fcfd2a015684"}, - {file = "ruff-0.9.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3292c5a22ea9a5f9a185e2d131dc7f98f8534a32fb6d2ee7b9944569239c648d"}, - {file = "ruff-0.9.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1a605fdcf6e8b2d39f9436d343d1f0ff70c365a1e681546de0104bef81ce88df"}, - {file = "ruff-0.9.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c547f7f256aa366834829a08375c297fa63386cbe5f1459efaf174086b564247"}, - {file = "ruff-0.9.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:d18bba3d3353ed916e882521bc3e0af403949dbada344c20c16ea78f47af965e"}, - {file = "ruff-0.9.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:b338edc4610142355ccf6b87bd356729b62bf1bc152a2fad5b0c7dc04af77bfe"}, - {file = "ruff-0.9.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:492a5e44ad9b22a0ea98cf72e40305cbdaf27fac0d927f8bc9e1df316dcc96eb"}, - {file = "ruff-0.9.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:af1e9e9fe7b1f767264d26b1075ac4ad831c7db976911fa362d09b2d0356426a"}, - {file = "ruff-0.9.2-py3-none-win32.whl", hash = "sha256:71cbe22e178c5da20e1514e1e01029c73dc09288a8028a5d3446e6bba87a5145"}, - {file = "ruff-0.9.2-py3-none-win_amd64.whl", hash = "sha256:c5e1d6abc798419cf46eed03f54f2e0c3adb1ad4b801119dedf23fcaf69b55b5"}, - {file = "ruff-0.9.2-py3-none-win_arm64.whl", hash = "sha256:a1b63fa24149918f8b37cef2ee6fff81f24f0d74b6f0bdc37bc3e1f2143e41c6"}, - {file = "ruff-0.9.2.tar.gz", hash = "sha256:b5eceb334d55fae5f316f783437392642ae18e16dcf4f1858d55d3c2a0f8f5d0"}, + {file = "ruff-0.9.3-py3-none-linux_armv6l.whl", hash = "sha256:7f39b879064c7d9670197d91124a75d118d00b0990586549949aae80cdc16624"}, + {file = "ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a187171e7c09efa4b4cc30ee5d0d55a8d6c5311b3e1b74ac5cb96cc89bafc43c"}, + {file = "ruff-0.9.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c59ab92f8e92d6725b7ded9d4a31be3ef42688a115c6d3da9457a5bda140e2b4"}, + {file = "ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc153c25e715be41bb228bc651c1e9b1a88d5c6e5ed0194fa0dfea02b026439"}, + {file = "ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646909a1e25e0dc28fbc529eab8eb7bb583079628e8cbe738192853dbbe43af5"}, + {file = "ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a5a46e09355695fbdbb30ed9889d6cf1c61b77b700a9fafc21b41f097bfbba4"}, + {file = "ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c4bb09d2bbb394e3730d0918c00276e79b2de70ec2a5231cd4ebb51a57df9ba1"}, + {file = "ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96a87ec31dc1044d8c2da2ebbed1c456d9b561e7d087734336518181b26b3aa5"}, + {file = "ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb7554aca6f842645022fe2d301c264e6925baa708b392867b7a62645304df4"}, + {file = "ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cabc332b7075a914ecea912cd1f3d4370489c8018f2c945a30bcc934e3bc06a6"}, + {file = "ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:33866c3cc2a575cbd546f2cd02bdd466fed65118e4365ee538a3deffd6fcb730"}, + {file = "ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:006e5de2621304c8810bcd2ee101587712fa93b4f955ed0985907a36c427e0c2"}, + {file = "ruff-0.9.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ba6eea4459dbd6b1be4e6bfc766079fb9b8dd2e5a35aff6baee4d9b1514ea519"}, + {file = "ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:90230a6b8055ad47d3325e9ee8f8a9ae7e273078a66401ac66df68943ced029b"}, + {file = "ruff-0.9.3-py3-none-win32.whl", hash = "sha256:eabe5eb2c19a42f4808c03b82bd313fc84d4e395133fb3fc1b1516170a31213c"}, + {file = "ruff-0.9.3-py3-none-win_amd64.whl", hash = "sha256:040ceb7f20791dfa0e78b4230ee9dce23da3b64dd5848e40e3bf3ab76468dcf4"}, + {file = "ruff-0.9.3-py3-none-win_arm64.whl", hash = "sha256:800d773f6d4d33b0a3c60e2c6ae8f4c202ea2de056365acfa519aa48acf28e0b"}, + {file = "ruff-0.9.3.tar.gz", hash = "sha256:8293f89985a090ebc3ed1064df31f3b4b56320cdfcec8b60d3295bddb955c22a"}, ] [[package]] From cbafc28fa16f62f5ffd6bcde9d20ac4f38502a78 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 24 Jan 2025 22:59:56 +0100 Subject: [PATCH 12/17] fix(deps): update dependency openai to v1.60.1 (#4941) Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- poetry.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index 914ce18ec..eaaaa6119 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1590,13 +1590,13 @@ signedtoken = ["cryptography (>=3.0.0)", "pyjwt (>=2.0.0,<3)"] [[package]] name = "openai" -version = "1.60.0" +version = "1.60.1" description = "The official Python library for the openai API" optional = false python-versions = ">=3.8" files = [ - {file = "openai-1.60.0-py3-none-any.whl", hash = "sha256:df06c43be8018274980ac363da07d4b417bd835ead1c66e14396f6f15a0d5dda"}, - {file = "openai-1.60.0.tar.gz", hash = "sha256:7fa536cd4b644718645b874d2706e36dbbef38b327e42ca0623275da347ee1a9"}, + {file = "openai-1.60.1-py3-none-any.whl", hash = "sha256:714181ec1c452353d456f143c22db892de7b373e3165063d02a2b798ed575ba1"}, + {file = "openai-1.60.1.tar.gz", hash = "sha256:beb1541dfc38b002bd629ab68b0d6fe35b870c5f4311d9bc4404d85af3214d5e"}, ] [package.dependencies] From 1e69577d125d9a33d4647834b5b4743f1a3ceeb2 Mon Sep 17 00:00:00 2001 From: James Elliott Date: Sat, 25 Jan 2025 12:48:34 +1100 Subject: [PATCH 13/17] docs: update oidcv2 authelia link (#4942) Co-authored-by: Michael Genson <71845777+michael-genson@users.noreply.github.com> --- .../documentation/getting-started/authentication/oidc-v2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/documentation/getting-started/authentication/oidc-v2.md b/docs/docs/documentation/getting-started/authentication/oidc-v2.md index 35f67369e..ee8c3ba9b 100644 --- a/docs/docs/documentation/getting-started/authentication/oidc-v2.md +++ b/docs/docs/documentation/getting-started/authentication/oidc-v2.md @@ -10,7 +10,7 @@ Mealie supports 3rd party authentication via [OpenID Connect (OIDC)](https://openid.net/connect/), an identity layer built on top of OAuth2. OIDC is supported by many Identity Providers (IdP), including: - [Authentik](https://goauthentik.io/integrations/sources/oauth/#openid-connect) -- [Authelia](https://www.authelia.com/configuration/identity-providers/open-id-connect/) +- [Authelia](https://www.authelia.com/integration/openid-connect/mealie/) - [Keycloak](https://www.keycloak.org/docs/latest/securing_apps/#_oidc) - [Okta](https://www.okta.com/openid-connect/) From 93c2df41c3ea44288d21618cd81c656e9a8e1ffd Mon Sep 17 00:00:00 2001 From: Cody Date: Sun, 26 Jan 2025 08:04:40 -0600 Subject: [PATCH 14/17] feat: Shopping list UI overhaul - three dot menu (#4415) Co-authored-by: Kuchenpirat <24235032+Kuchenpirat@users.noreply.github.com> --- frontend/pages/shopping-lists/_id.vue | 252 +++++++++--------------- frontend/pages/shopping-lists/index.vue | 100 +++++++++- 2 files changed, 183 insertions(+), 169 deletions(-) diff --git a/frontend/pages/shopping-lists/_id.vue b/frontend/pages/shopping-lists/_id.vue index 004dbcbb7..c575f0de3 100644 --- a/frontend/pages/shopping-lists/_id.vue +++ b/frontend/pages/shopping-lists/_id.vue @@ -17,11 +17,69 @@ - + - + + + + @@ -119,27 +177,6 @@ - - - - - - - - -
- - - {{ $t('shopping-list.reorder-labels') }} - {{ $t('general.add') }}
- -
- -
-
- +
+
+ +
+
+ +
+
@@ -277,29 +277,6 @@ - - -
- - - {{ $t('general.settings') }} - -
-
- - -
- -
-
@@ -314,7 +291,6 @@ import { useUserApi } from "~/composables/api"; import MultiPurposeLabelSection from "~/components/Domain/ShoppingList/MultiPurposeLabelSection.vue" import ShoppingListItem from "~/components/Domain/ShoppingList/ShoppingListItem.vue"; import { ShoppingListItemOut, ShoppingListMultiPurposeLabelOut, ShoppingListOut } from "~/lib/api/types/household"; -import { UserOut } from "~/lib/api/types/user"; import RecipeList from "~/components/Domain/Recipe/RecipeList.vue"; import ShoppingListItemEditor from "~/components/Domain/ShoppingList/ShoppingListItemEditor.vue"; import { useFoodStore, useLabelStore, useUnitStore } from "~/composables/store"; @@ -349,8 +325,8 @@ export default defineComponent({ const userApi = useUserApi(); const edit = ref(false); + const threeDot = ref(false); const reorderLabelsDialog = ref(false); - const settingsDialog = ref(false); const preserveItemOrder = ref(false); const route = useRoute(); @@ -678,13 +654,6 @@ export default defineComponent({ localLabels.value = shoppingList.value?.labelSettings } - async function toggleSettingsDialog() { - if (!settingsDialog.value) { - await fetchAllUsers(); - } - settingsDialog.value = !settingsDialog.value; - } - function updateLabelOrder(labelSettings: ShoppingListMultiPurposeLabelOut[]) { if (!shoppingList.value) { return; @@ -1064,39 +1033,6 @@ export default defineComponent({ refresh(); } - // =============================================================== - // Shopping List Settings - - const allUsers = ref([]); - const currentUserId = ref(); - async function fetchAllUsers() { - const { data } = await userApi.households.fetchMembers(); - if (!data) { - return; - } - - // update current user - allUsers.value = data.items.sort((a, b) => ((a.fullName || "") < (b.fullName || "") ? -1 : 1)); - currentUserId.value = shoppingList.value?.userId; - } - - async function updateSettings() { - if (!shoppingList.value || !currentUserId.value) { - return; - } - - loadingCounter.value += 1; - const { data } = await userApi.shopping.lists.updateOne( - shoppingList.value.id, - {...shoppingList.value, userId: currentUserId.value}, - ); - loadingCounter.value -= 1; - - if (data) { - refresh(); - } - } - return { ...toRefs(state), addRecipeReferenceToList, @@ -1112,6 +1048,7 @@ export default defineComponent({ openDeleteChecked, deleteListItem, edit, + threeDot, getLabelColor, groupSlug, itemsByLabel, @@ -1123,8 +1060,6 @@ export default defineComponent({ removeRecipeReferenceToList, reorderLabelsDialog, toggleReorderLabelsDialog, - settingsDialog, - toggleSettingsDialog, localLabels, updateLabelOrder, cancelLabelOrder, @@ -1144,9 +1079,6 @@ export default defineComponent({ updateIndexUncheckedByLabel, allUnits, allFoods, - allUsers, - currentUserId, - updateSettings, getTextColor, }; }, diff --git a/frontend/pages/shopping-lists/index.vue b/frontend/pages/shopping-lists/index.vue index 430ab9a70..ab5af4bd4 100644 --- a/frontend/pages/shopping-lists/index.vue +++ b/frontend/pages/shopping-lists/index.vue @@ -6,6 +6,27 @@ + + + + + + + + + {{ $t('shopping-list.are-you-sure-you-want-to-delete-this-item') }} @@ -38,26 +59,34 @@ {{ $globals.icons.cartCheck }} - {{ list.name }} - - - {{ $globals.icons.delete }} - - +
+ {{ list.name }} +
+
+ + + {{ $globals.icons.user }} + + + + + {{ $globals.icons.delete }} + + +
-
- -