"""WebSocket handlers for group CRUD operations.""" from __future__ import annotations from typing import Any from uuid import uuid4 import voluptuous as vol from homeassistant.components import websocket_api from homeassistant.core import HomeAssistant from ..const import ( DOMAIN, MAX_GROUP_TASK_REFS, MAX_ID_LENGTH, MAX_NAME_LENGTH, MAX_TEXT_LENGTH, ) from ..helpers.permissions import require_write from . import _get_global_entry @websocket_api.websocket_command({vol.Required("type"): f"{DOMAIN}/groups"}) @websocket_api.async_response async def ws_get_groups( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any], ) -> None: """Return all maintenance groups.""" from ..const import CONF_GROUPS global_entry = _get_global_entry(hass) if global_entry is None: connection.send_result(msg["id"], {"groups": {}}) return options = global_entry.options or global_entry.data groups = options.get(CONF_GROUPS, {}) connection.send_result(msg["id"], {"groups": groups}) @websocket_api.websocket_command( { vol.Required("type"): f"{DOMAIN}/group/create", vol.Required("name"): vol.All(str, vol.Length(min=1, max=MAX_NAME_LENGTH)), vol.Optional("description", default=""): vol.All(str, vol.Length(max=MAX_TEXT_LENGTH)), vol.Optional("task_refs", default=[]): vol.All( [ { vol.Required("entry_id"): vol.All(str, vol.Length(max=MAX_ID_LENGTH)), vol.Required("task_id"): vol.All(str, vol.Length(max=MAX_ID_LENGTH)), } ], vol.Length(max=MAX_GROUP_TASK_REFS), ), } ) @require_write @websocket_api.async_response async def ws_create_group( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any], ) -> None: """Create a new maintenance group.""" from ..const import CONF_GROUPS global_entry = _get_global_entry(hass) if global_entry is None: connection.send_error(msg["id"], "not_found", "Global config not found") return name = msg["name"].strip() if not name: connection.send_error(msg["id"], "invalid_input", "Name must not be empty") return group_id = uuid4().hex options = dict(global_entry.options or global_entry.data) groups = dict(options.get(CONF_GROUPS, {})) groups[group_id] = { "name": name, "description": msg.get("description", ""), "task_refs": msg.get("task_refs", []), } options[CONF_GROUPS] = groups hass.config_entries.async_update_entry(global_entry, options=options) connection.send_result(msg["id"], {"group_id": group_id}) @websocket_api.websocket_command( { vol.Required("type"): f"{DOMAIN}/group/update", vol.Required("group_id"): vol.All(str, vol.Length(max=MAX_ID_LENGTH)), vol.Optional("name"): vol.All(str, vol.Length(min=1, max=MAX_NAME_LENGTH)), vol.Optional("description"): vol.All(str, vol.Length(max=MAX_TEXT_LENGTH)), vol.Optional("task_refs"): vol.All( [ { vol.Required("entry_id"): vol.All(str, vol.Length(max=MAX_ID_LENGTH)), vol.Required("task_id"): vol.All(str, vol.Length(max=MAX_ID_LENGTH)), } ], vol.Length(max=MAX_GROUP_TASK_REFS), ), } ) @require_write @websocket_api.async_response async def ws_update_group( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any], ) -> None: """Update an existing maintenance group.""" from ..const import CONF_GROUPS global_entry = _get_global_entry(hass) if global_entry is None: connection.send_error(msg["id"], "not_found", "Global config not found") return options = dict(global_entry.options or global_entry.data) groups = dict(options.get(CONF_GROUPS, {})) group_id = msg["group_id"] if group_id not in groups: connection.send_error(msg["id"], "not_found", "Group not found") return group = dict(groups[group_id]) if "name" in msg: group["name"] = msg["name"] if "description" in msg: group["description"] = msg["description"] if "task_refs" in msg: group["task_refs"] = msg["task_refs"] groups[group_id] = group options[CONF_GROUPS] = groups hass.config_entries.async_update_entry(global_entry, options=options) connection.send_result(msg["id"], {"success": True}) @websocket_api.websocket_command( { vol.Required("type"): f"{DOMAIN}/group/delete", vol.Required("group_id"): vol.All(str, vol.Length(max=MAX_ID_LENGTH)), } ) @require_write @websocket_api.async_response async def ws_delete_group( hass: HomeAssistant, connection: websocket_api.ActiveConnection, msg: dict[str, Any], ) -> None: """Delete a maintenance group.""" from ..const import CONF_GROUPS global_entry = _get_global_entry(hass) if global_entry is None: connection.send_error(msg["id"], "not_found", "Global config not found") return options = dict(global_entry.options or global_entry.data) groups = dict(options.get(CONF_GROUPS, {})) group_id = msg["group_id"] if group_id not in groups: connection.send_error(msg["id"], "not_found", "Group not found") return del groups[group_id] options[CONF_GROUPS] = groups hass.config_entries.async_update_entry(global_entry, options=options) connection.send_result(msg["id"], {"success": True})