Add more shopping list services (#45591)

Co-authored-by: Franck Nijhof <git@frenck.dev>
pull/46976/head
MHV33 2021-02-23 16:25:50 -06:00 committed by GitHub
parent d96249e39c
commit 23b2953773
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 99 additions and 2 deletions

View File

@ -15,17 +15,21 @@ from homeassistant.util.json import load_json, save_json
from .const import DOMAIN
ATTR_NAME = "name"
ATTR_COMPLETE = "complete"
_LOGGER = logging.getLogger(__name__)
CONFIG_SCHEMA = vol.Schema({DOMAIN: {}}, extra=vol.ALLOW_EXTRA)
EVENT = "shopping_list_updated"
ITEM_UPDATE_SCHEMA = vol.Schema({"complete": bool, ATTR_NAME: str})
ITEM_UPDATE_SCHEMA = vol.Schema({ATTR_COMPLETE: bool, ATTR_NAME: str})
PERSISTENCE = ".shopping_list.json"
SERVICE_ADD_ITEM = "add_item"
SERVICE_COMPLETE_ITEM = "complete_item"
SERVICE_INCOMPLETE_ITEM = "incomplete_item"
SERVICE_COMPLETE_ALL = "complete_all"
SERVICE_INCOMPLETE_ALL = "incomplete_all"
SERVICE_ITEM_SCHEMA = vol.Schema({vol.Required(ATTR_NAME): vol.Any(None, cv.string)})
SERVICE_LIST_SCHEMA = vol.Schema({})
WS_TYPE_SHOPPING_LIST_ITEMS = "shopping_list/items"
WS_TYPE_SHOPPING_LIST_ADD_ITEM = "shopping_list/items/add"
@ -92,6 +96,27 @@ async def async_setup_entry(hass, config_entry):
else:
await data.async_update(item["id"], {"name": name, "complete": True})
async def incomplete_item_service(call):
"""Mark the item provided via `name` as incomplete."""
data = hass.data[DOMAIN]
name = call.data.get(ATTR_NAME)
if name is None:
return
try:
item = [item for item in data.items if item["name"] == name][0]
except IndexError:
_LOGGER.error("Restoring of item failed: %s cannot be found", name)
else:
await data.async_update(item["id"], {"name": name, "complete": False})
async def complete_all_service(call):
"""Mark all items in the list as complete."""
await data.async_update_list({"complete": True})
async def incomplete_all_service(call):
"""Mark all items in the list as incomplete."""
await data.async_update_list({"complete": False})
data = hass.data[DOMAIN] = ShoppingData(hass)
await data.async_load()
@ -101,6 +126,24 @@ async def async_setup_entry(hass, config_entry):
hass.services.async_register(
DOMAIN, SERVICE_COMPLETE_ITEM, complete_item_service, schema=SERVICE_ITEM_SCHEMA
)
hass.services.async_register(
DOMAIN,
SERVICE_INCOMPLETE_ITEM,
incomplete_item_service,
schema=SERVICE_ITEM_SCHEMA,
)
hass.services.async_register(
DOMAIN,
SERVICE_COMPLETE_ALL,
complete_all_service,
schema=SERVICE_LIST_SCHEMA,
)
hass.services.async_register(
DOMAIN,
SERVICE_INCOMPLETE_ALL,
incomplete_all_service,
schema=SERVICE_LIST_SCHEMA,
)
hass.http.register_view(ShoppingListView)
hass.http.register_view(CreateShoppingListItemView)
@ -165,6 +208,13 @@ class ShoppingData:
self.items = [itm for itm in self.items if not itm["complete"]]
await self.hass.async_add_executor_job(self.save)
async def async_update_list(self, info):
"""Update all items in the list."""
for item in self.items:
item.update(info)
await self.hass.async_add_executor_job(self.save)
return self.items
@callback
def async_reorder(self, item_ids):
"""Reorder items."""

View File

@ -21,3 +21,16 @@ complete_item:
example: Beer
selector:
text:
incomplete_item:
description: Marks an item as incomplete in the shopping list.
fields:
name:
description: The name of the item to mark as incomplete.
example: Beer
complete_all:
description: Marks all items as completed in the shopping list. It does not remove the items.
incomplete_all:
description: Marks all items as incomplete in the shopping list.

View File

@ -1,5 +1,6 @@
"""Test shopping list component."""
from homeassistant.components.shopping_list.const import DOMAIN
from homeassistant.components.websocket_api.const import (
ERR_INVALID_FORMAT,
ERR_NOT_FOUND,
@ -19,6 +20,39 @@ async def test_add_item(hass, sl_setup):
assert response.speech["plain"]["speech"] == "I've added beer to your shopping list"
async def test_update_list(hass, sl_setup):
"""Test updating all list items."""
await intent.async_handle(
hass, "test", "HassShoppingListAddItem", {"item": {"value": "beer"}}
)
await intent.async_handle(
hass, "test", "HassShoppingListAddItem", {"item": {"value": "cheese"}}
)
# Update a single attribute, other attributes shouldn't change
await hass.data[DOMAIN].async_update_list({"complete": True})
beer = hass.data[DOMAIN].items[0]
assert beer["name"] == "beer"
assert beer["complete"] is True
cheese = hass.data[DOMAIN].items[1]
assert cheese["name"] == "cheese"
assert cheese["complete"] is True
# Update multiple attributes
await hass.data[DOMAIN].async_update_list({"name": "dupe", "complete": False})
beer = hass.data[DOMAIN].items[0]
assert beer["name"] == "dupe"
assert beer["complete"] is False
cheese = hass.data[DOMAIN].items[1]
assert cheese["name"] == "dupe"
assert cheese["complete"] is False
async def test_recent_items_intent(hass, sl_setup):
"""Test recent items."""