278 files
This commit is contained in:
1 parent
d7a0a08372
commit
1b4f5f68c6
278 files changed
+36892
-7150
No files matched your search
@@ -2,7 +2,6 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date
|
||||
from typing import Any
|
||||
|
||||
import voluptuous as vol
|
||||
@@ -11,7 +10,6 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.util import dt as dt_util
|
||||
|
||||
from ..const import (
|
||||
CONF_OBJECT,
|
||||
CONF_VACATION_BUFFER_DAYS,
|
||||
CONF_VACATION_ENABLED,
|
||||
CONF_VACATION_END,
|
||||
@@ -20,10 +18,13 @@ from ..const import (
|
||||
DEFAULT_WARNING_DAYS,
|
||||
DOMAIN,
|
||||
MAX_ID_LENGTH,
|
||||
MAX_VACATION_EXEMPT_TASKS,
|
||||
)
|
||||
from ..helpers.aggregate import object_name
|
||||
from ..helpers.dates import parse_iso_date
|
||||
from ..helpers.schedule import read_legacy_fields
|
||||
from ..helpers.vacation import compute_preview, get_vacation_state
|
||||
from . import _get_merged_tasks, _get_object_entries, _load_global_options, _save_global_options
|
||||
from . import _get_merged_tasks, _get_object_entries, _load_global_options, _parse_iso_date, _save_global_options
|
||||
|
||||
|
||||
def _state_payload(hass: HomeAssistant) -> dict[str, Any]:
|
||||
@@ -51,7 +52,7 @@ async def ws_vacation_state(
|
||||
vol.Optional("buffer_days"): vol.All(int, vol.Range(min=0, max=14)),
|
||||
vol.Optional("exempt_task_ids"): vol.All(
|
||||
[vol.All(str, vol.Length(max=MAX_ID_LENGTH))],
|
||||
vol.Length(max=2000),
|
||||
vol.Length(max=MAX_VACATION_EXEMPT_TASKS),
|
||||
),
|
||||
}
|
||||
)
|
||||
@@ -71,38 +72,21 @@ async def ws_vacation_update(
|
||||
if "enabled" in msg:
|
||||
options[CONF_VACATION_ENABLED] = bool(msg["enabled"])
|
||||
|
||||
if "start" in msg:
|
||||
if msg["start"] is None:
|
||||
options[CONF_VACATION_START] = None
|
||||
else:
|
||||
try:
|
||||
date.fromisoformat(msg["start"])
|
||||
except (TypeError, ValueError):
|
||||
connection.send_error(msg["id"], "invalid_date", "start must be YYYY-MM-DD")
|
||||
return
|
||||
options[CONF_VACATION_START] = msg["start"]
|
||||
for field, key in (("start", CONF_VACATION_START), ("end", CONF_VACATION_END)):
|
||||
if field not in msg:
|
||||
continue
|
||||
if msg[field] is not None and _parse_iso_date(connection, msg["id"], msg[field], field=field) is None:
|
||||
return
|
||||
options[key] = msg[field]
|
||||
|
||||
if "end" in msg:
|
||||
if msg["end"] is None:
|
||||
options[CONF_VACATION_END] = None
|
||||
else:
|
||||
try:
|
||||
date.fromisoformat(msg["end"])
|
||||
except (TypeError, ValueError):
|
||||
connection.send_error(msg["id"], "invalid_date", "end must be YYYY-MM-DD")
|
||||
return
|
||||
options[CONF_VACATION_END] = msg["end"]
|
||||
|
||||
# End-vs-start sanity (only when both are present after the patch).
|
||||
sd = options.get(CONF_VACATION_START)
|
||||
ed = options.get(CONF_VACATION_END)
|
||||
if sd and ed:
|
||||
try:
|
||||
if date.fromisoformat(ed) < date.fromisoformat(sd):
|
||||
connection.send_error(msg["id"], "invalid_range", "end must be on or after start")
|
||||
return
|
||||
except (TypeError, ValueError):
|
||||
pass # Already rejected above
|
||||
# End-vs-start sanity (only when both are present after the patch; a
|
||||
# stored value that does not parse is skipped — the patch above already
|
||||
# refused a malformed incoming one).
|
||||
sd = parse_iso_date(options.get(CONF_VACATION_START))
|
||||
ed = parse_iso_date(options.get(CONF_VACATION_END))
|
||||
if sd is not None and ed is not None and ed < sd:
|
||||
connection.send_error(msg["id"], "invalid_range", "end must be on or after start")
|
||||
return
|
||||
|
||||
if "buffer_days" in msg:
|
||||
options[CONF_VACATION_BUFFER_DAYS] = int(msg["buffer_days"])
|
||||
@@ -119,7 +103,7 @@ async def ws_vacation_update(
|
||||
continue
|
||||
seen.add(v)
|
||||
cleaned.append(v)
|
||||
if len(cleaned) >= 2000:
|
||||
if len(cleaned) >= MAX_VACATION_EXEMPT_TASKS:
|
||||
break
|
||||
options[CONF_VACATION_EXEMPT_TASK_IDS] = cleaned
|
||||
|
||||
@@ -152,8 +136,7 @@ async def ws_vacation_preview(
|
||||
# Build the flat task list expected by compute_preview.
|
||||
tasks: list[dict[str, Any]] = []
|
||||
for entry in _get_object_entries(hass):
|
||||
obj_data = entry.data.get(CONF_OBJECT, {})
|
||||
obj_name = obj_data.get("name", "")
|
||||
obj_name = object_name(entry)
|
||||
# Merge dynamic store fields (last_performed, etc.) when available.
|
||||
merged = _get_merged_tasks(entry)
|
||||
|
||||
@@ -210,13 +193,9 @@ async def ws_vacation_end_now(
|
||||
# the user actually returned. Use HA's configured timezone — the user's
|
||||
# "today" should match what their dashboard shows, not the server's UTC.
|
||||
today = dt_util.now().date()
|
||||
sd = options.get(CONF_VACATION_START)
|
||||
if sd:
|
||||
try:
|
||||
if date.fromisoformat(sd) <= today:
|
||||
options[CONF_VACATION_END] = today.isoformat()
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
sd = parse_iso_date(options.get(CONF_VACATION_START))
|
||||
if sd is not None and sd <= today:
|
||||
options[CONF_VACATION_END] = today.isoformat()
|
||||
|
||||
_save_global_options(hass, global_entry, options)
|
||||
connection.send_result(msg["id"], _state_payload(hass))
|
||||
|
||||
Reference in new issue
Block a user