Add due date and description to CalDAV To-do (#104656)

Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
Co-authored-by: Robert Resch <robert@resch.dev>
This commit is contained in:
Allen Porter 2023-11-29 10:35:36 -08:00 committed by GitHub
parent 1522118453
commit af2f8699b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 142 additions and 24 deletions

View file

@ -2,10 +2,10 @@
from __future__ import annotations
import asyncio
from datetime import timedelta
from datetime import date, datetime, timedelta
from functools import partial
import logging
from typing import cast
from typing import Any, cast
import caldav
from caldav.lib.error import DAVError, NotFoundError
@ -21,6 +21,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util import dt as dt_util
from .api import async_get_calendars, get_attr_value
from .const import DOMAIN
@ -71,6 +72,12 @@ def _todo_item(resource: caldav.CalendarObjectResource) -> TodoItem | None:
or (summary := get_attr_value(todo, "summary")) is None
):
return None
due: date | datetime | None = None
if due_value := get_attr_value(todo, "due"):
if isinstance(due_value, datetime):
due = dt_util.as_local(due_value)
elif isinstance(due_value, date):
due = due_value
return TodoItem(
uid=uid,
summary=summary,
@ -78,9 +85,28 @@ def _todo_item(resource: caldav.CalendarObjectResource) -> TodoItem | None:
get_attr_value(todo, "status") or "",
TodoItemStatus.NEEDS_ACTION,
),
due=due,
description=get_attr_value(todo, "description"),
)
def _to_ics_fields(item: TodoItem) -> dict[str, Any]:
"""Convert a TodoItem to the set of add or update arguments."""
item_data: dict[str, Any] = {}
if summary := item.summary:
item_data["summary"] = summary
if status := item.status:
item_data["status"] = TODO_STATUS_MAP_INV.get(status, "NEEDS-ACTION")
if due := item.due:
if isinstance(due, datetime):
item_data["due"] = dt_util.as_utc(due).strftime("%Y%m%dT%H%M%SZ")
else:
item_data["due"] = due.strftime("%Y%m%d")
if description := item.description:
item_data["description"] = description
return item_data
class WebDavTodoListEntity(TodoListEntity):
"""CalDAV To-do list entity."""
@ -89,6 +115,9 @@ class WebDavTodoListEntity(TodoListEntity):
TodoListEntityFeature.CREATE_TODO_ITEM
| TodoListEntityFeature.UPDATE_TODO_ITEM
| TodoListEntityFeature.DELETE_TODO_ITEM
| TodoListEntityFeature.SET_DUE_DATE_ON_ITEM
| TodoListEntityFeature.SET_DUE_DATETIME_ON_ITEM
| TodoListEntityFeature.SET_DESCRIPTION_ON_ITEM
)
def __init__(self, calendar: caldav.Calendar, config_entry_id: str) -> None:
@ -116,13 +145,7 @@ class WebDavTodoListEntity(TodoListEntity):
"""Add an item to the To-do list."""
try:
await self.hass.async_add_executor_job(
partial(
self._calendar.save_todo,
summary=item.summary,
status=TODO_STATUS_MAP_INV.get(
item.status or TodoItemStatus.NEEDS_ACTION, "NEEDS-ACTION"
),
),
partial(self._calendar.save_todo, **_to_ics_fields(item)),
)
except (requests.ConnectionError, DAVError) as err:
raise HomeAssistantError(f"CalDAV save error: {err}") from err
@ -139,10 +162,7 @@ class WebDavTodoListEntity(TodoListEntity):
except (requests.ConnectionError, DAVError) as err:
raise HomeAssistantError(f"CalDAV lookup error: {err}") from err
vtodo = todo.icalendar_component # type: ignore[attr-defined]
if item.summary:
vtodo["summary"] = item.summary
if item.status:
vtodo["status"] = TODO_STATUS_MAP_INV.get(item.status, "NEEDS-ACTION")
vtodo.update(**_to_ics_fields(item))
try:
await self.hass.async_add_executor_job(
partial(