mirror of
https://github.com/home-assistant/core.git
synced 2025-07-31 17:18:23 +00:00
Add get recipes search service to Mealie integration (#149348)
Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
parent
a21af78aa1
commit
91be25a292
@ -17,5 +17,7 @@ ATTR_INCLUDE_TAGS = "include_tags"
|
||||
ATTR_ENTRY_TYPE = "entry_type"
|
||||
ATTR_NOTE_TITLE = "note_title"
|
||||
ATTR_NOTE_TEXT = "note_text"
|
||||
ATTR_SEARCH_TERMS = "search_terms"
|
||||
ATTR_RESULT_LIMIT = "result_limit"
|
||||
|
||||
MIN_REQUIRED_MEALIE_VERSION = AwesomeVersion("v1.0.0")
|
||||
|
@ -30,6 +30,9 @@
|
||||
"get_recipe": {
|
||||
"service": "mdi:map"
|
||||
},
|
||||
"get_recipes": {
|
||||
"service": "mdi:book-open-page-variant"
|
||||
},
|
||||
"import_recipe": {
|
||||
"service": "mdi:map-search"
|
||||
},
|
||||
|
@ -32,6 +32,8 @@ from .const import (
|
||||
ATTR_NOTE_TEXT,
|
||||
ATTR_NOTE_TITLE,
|
||||
ATTR_RECIPE_ID,
|
||||
ATTR_RESULT_LIMIT,
|
||||
ATTR_SEARCH_TERMS,
|
||||
ATTR_START_DATE,
|
||||
ATTR_URL,
|
||||
DOMAIN,
|
||||
@ -55,6 +57,15 @@ SERVICE_GET_RECIPE_SCHEMA = vol.Schema(
|
||||
}
|
||||
)
|
||||
|
||||
SERVICE_GET_RECIPES = "get_recipes"
|
||||
SERVICE_GET_RECIPES_SCHEMA = vol.Schema(
|
||||
{
|
||||
vol.Required(ATTR_CONFIG_ENTRY_ID): str,
|
||||
vol.Optional(ATTR_SEARCH_TERMS): str,
|
||||
vol.Optional(ATTR_RESULT_LIMIT): int,
|
||||
}
|
||||
)
|
||||
|
||||
SERVICE_IMPORT_RECIPE = "import_recipe"
|
||||
SERVICE_IMPORT_RECIPE_SCHEMA = vol.Schema(
|
||||
{
|
||||
@ -159,6 +170,27 @@ async def _async_get_recipe(call: ServiceCall) -> ServiceResponse:
|
||||
return {"recipe": asdict(recipe)}
|
||||
|
||||
|
||||
async def _async_get_recipes(call: ServiceCall) -> ServiceResponse:
|
||||
"""Get recipes."""
|
||||
entry = _async_get_entry(call)
|
||||
search_terms = call.data.get(ATTR_SEARCH_TERMS)
|
||||
result_limit = call.data.get(ATTR_RESULT_LIMIT, 10)
|
||||
client = entry.runtime_data.client
|
||||
try:
|
||||
recipes = await client.get_recipes(search=search_terms, per_page=result_limit)
|
||||
except MealieConnectionError as err:
|
||||
raise HomeAssistantError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="connection_error",
|
||||
) from err
|
||||
except MealieNotFoundError as err:
|
||||
raise ServiceValidationError(
|
||||
translation_domain=DOMAIN,
|
||||
translation_key="no_recipes_found",
|
||||
) from err
|
||||
return {"recipes": asdict(recipes)}
|
||||
|
||||
|
||||
async def _async_import_recipe(call: ServiceCall) -> ServiceResponse:
|
||||
"""Import a recipe."""
|
||||
entry = _async_get_entry(call)
|
||||
@ -242,6 +274,13 @@ def async_setup_services(hass: HomeAssistant) -> None:
|
||||
schema=SERVICE_GET_RECIPE_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_GET_RECIPES,
|
||||
_async_get_recipes,
|
||||
schema=SERVICE_GET_RECIPES_SCHEMA,
|
||||
supports_response=SupportsResponse.ONLY,
|
||||
)
|
||||
hass.services.async_register(
|
||||
DOMAIN,
|
||||
SERVICE_IMPORT_RECIPE,
|
||||
|
@ -24,6 +24,27 @@ get_recipe:
|
||||
selector:
|
||||
text:
|
||||
|
||||
get_recipes:
|
||||
fields:
|
||||
config_entry_id:
|
||||
required: true
|
||||
selector:
|
||||
config_entry:
|
||||
integration: mealie
|
||||
search_terms:
|
||||
required: false
|
||||
selector:
|
||||
text:
|
||||
result_limit:
|
||||
required: false
|
||||
default: 10
|
||||
selector:
|
||||
number:
|
||||
min: 1
|
||||
max: 100
|
||||
mode: box
|
||||
unit_of_measurement: recipes
|
||||
|
||||
import_recipe:
|
||||
fields:
|
||||
config_entry_id:
|
||||
|
@ -109,6 +109,9 @@
|
||||
"recipe_not_found": {
|
||||
"message": "Recipe with ID or slug `{recipe_id}` not found."
|
||||
},
|
||||
"no_recipes_found": {
|
||||
"message": "No recipes found matching your search."
|
||||
},
|
||||
"could_not_import_recipe": {
|
||||
"message": "Mealie could not import the recipe from the URL."
|
||||
},
|
||||
@ -176,6 +179,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"get_recipes": {
|
||||
"name": "Get recipes",
|
||||
"description": "Searches for recipes with any matching properties in Mealie",
|
||||
"fields": {
|
||||
"config_entry_id": {
|
||||
"name": "[%key:component::mealie::services::get_mealplan::fields::config_entry_id::name%]",
|
||||
"description": "[%key:component::mealie::services::get_mealplan::fields::config_entry_id::description%]"
|
||||
},
|
||||
"search_terms": {
|
||||
"name": "Search terms",
|
||||
"description": "Terms to search for in recipe properties."
|
||||
},
|
||||
"result_limit": {
|
||||
"name": "Result limit",
|
||||
"description": "Maximum number of recipes to return (default: 10)."
|
||||
}
|
||||
}
|
||||
},
|
||||
"import_recipe": {
|
||||
"name": "Import recipe",
|
||||
"description": "Imports a recipe from an URL",
|
||||
|
@ -8,6 +8,7 @@ from aiomealie import (
|
||||
Mealplan,
|
||||
MealplanResponse,
|
||||
Recipe,
|
||||
RecipesResponse,
|
||||
ShoppingItemsResponse,
|
||||
ShoppingListsResponse,
|
||||
Statistics,
|
||||
@ -63,6 +64,8 @@ def mock_mealie_client() -> Generator[AsyncMock]:
|
||||
)
|
||||
recipe = Recipe.from_json(load_fixture("get_recipe.json", DOMAIN))
|
||||
client.get_recipe.return_value = recipe
|
||||
recipes = RecipesResponse.from_json(load_fixture("get_recipes.json", DOMAIN))
|
||||
client.get_recipes.return_value = recipes
|
||||
client.import_recipe.return_value = recipe
|
||||
client.get_shopping_lists.return_value = ShoppingListsResponse.from_json(
|
||||
load_fixture("get_shopping_lists.json", DOMAIN)
|
||||
|
1692
tests/components/mealie/fixtures/get_recipes.json
Normal file
1692
tests/components/mealie/fixtures/get_recipes.json
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -21,6 +21,8 @@ from homeassistant.components.mealie.const import (
|
||||
ATTR_NOTE_TEXT,
|
||||
ATTR_NOTE_TITLE,
|
||||
ATTR_RECIPE_ID,
|
||||
ATTR_RESULT_LIMIT,
|
||||
ATTR_SEARCH_TERMS,
|
||||
ATTR_START_DATE,
|
||||
ATTR_URL,
|
||||
DOMAIN,
|
||||
@ -28,6 +30,7 @@ from homeassistant.components.mealie.const import (
|
||||
from homeassistant.components.mealie.services import (
|
||||
SERVICE_GET_MEALPLAN,
|
||||
SERVICE_GET_RECIPE,
|
||||
SERVICE_GET_RECIPES,
|
||||
SERVICE_IMPORT_RECIPE,
|
||||
SERVICE_SET_MEALPLAN,
|
||||
SERVICE_SET_RANDOM_MEALPLAN,
|
||||
@ -150,6 +153,42 @@ async def test_service_recipe(
|
||||
assert response == snapshot
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"service_data",
|
||||
[
|
||||
# Default call
|
||||
{ATTR_CONFIG_ENTRY_ID: "mock_entry_id"},
|
||||
# With search terms and result limit
|
||||
{
|
||||
ATTR_CONFIG_ENTRY_ID: "mock_entry_id",
|
||||
ATTR_SEARCH_TERMS: "pasta",
|
||||
ATTR_RESULT_LIMIT: 5,
|
||||
},
|
||||
],
|
||||
)
|
||||
async def test_service_get_recipes(
|
||||
hass: HomeAssistant,
|
||||
mock_mealie_client: AsyncMock,
|
||||
mock_config_entry: MockConfigEntry,
|
||||
snapshot: SnapshotAssertion,
|
||||
service_data: dict,
|
||||
) -> None:
|
||||
"""Test the get_recipes service."""
|
||||
await setup_integration(hass, mock_config_entry)
|
||||
|
||||
# Patch entry_id into service_data for each run
|
||||
service_data = {**service_data, ATTR_CONFIG_ENTRY_ID: mock_config_entry.entry_id}
|
||||
|
||||
response = await hass.services.async_call(
|
||||
DOMAIN,
|
||||
SERVICE_GET_RECIPES,
|
||||
service_data,
|
||||
blocking=True,
|
||||
return_response=True,
|
||||
)
|
||||
assert response == snapshot
|
||||
|
||||
|
||||
async def test_service_import_recipe(
|
||||
hass: HomeAssistant,
|
||||
mock_mealie_client: AsyncMock,
|
||||
@ -332,6 +371,22 @@ async def test_service_set_mealplan(
|
||||
ServiceValidationError,
|
||||
"Recipe with ID or slug `recipe_id` not found",
|
||||
),
|
||||
(
|
||||
SERVICE_GET_RECIPES,
|
||||
{},
|
||||
"get_recipes",
|
||||
MealieConnectionError,
|
||||
HomeAssistantError,
|
||||
"Error connecting to Mealie instance",
|
||||
),
|
||||
(
|
||||
SERVICE_GET_RECIPES,
|
||||
{ATTR_SEARCH_TERMS: "pasta"},
|
||||
"get_recipes",
|
||||
MealieNotFoundError,
|
||||
ServiceValidationError,
|
||||
"No recipes found matching your search",
|
||||
),
|
||||
(
|
||||
SERVICE_IMPORT_RECIPE,
|
||||
{ATTR_URL: "http://example.com"},
|
||||
@ -402,6 +457,11 @@ async def test_services_connection_error(
|
||||
[
|
||||
(SERVICE_GET_MEALPLAN, {}),
|
||||
(SERVICE_GET_RECIPE, {ATTR_RECIPE_ID: "recipe_id"}),
|
||||
(SERVICE_GET_RECIPES, {}),
|
||||
(
|
||||
SERVICE_GET_RECIPES,
|
||||
{ATTR_SEARCH_TERMS: "pasta", ATTR_RESULT_LIMIT: 5},
|
||||
),
|
||||
(SERVICE_IMPORT_RECIPE, {ATTR_URL: "http://example.com"}),
|
||||
(
|
||||
SERVICE_SET_RANDOM_MEALPLAN,
|
||||
|
Loading…
x
Reference in New Issue
Block a user