Skip to content

Commit

Permalink
caldav: Add to docs + mind the +WAITING vtag, cancelled/completed dif…
Browse files Browse the repository at this point in the history
…ference
  • Loading branch information
bergercookie committed Aug 16, 2024
1 parent aaaa5d9 commit 3778451
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 30 deletions.
10 changes: 7 additions & 3 deletions docs/readme-tw-caldav.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,17 @@ converted to a vCard format and visa versa):

### Mappings

TW ↔ CalDAV will make the following mappings between items:
`tw_caldav_sync` will make the following mappings between items:

- `description``SUMMARY`
- `status``STATUS`
- `pending`, `waiting``NEEDS-ACTION`
- `completed``COMPLETED`
- `deleted``CANCELLED`
- `completed``COMPLETED` / `CANCELLED` (using a custom `UDA`
`caldav_completion_status`, in Taskwarrior to mark cancelled items)
- `deleted` ↔ (deletion of CalDAV item)

Regarding timestamps:

- TW `entry``CREATED`
- TW `end``COMPLETED`
- TW `modified``LAST-MODIFIED`
Expand Down
10 changes: 7 additions & 3 deletions syncall/caldav/caldav_side.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from caldav.lib.error import NotFoundError
from icalendar.prop import vCategory, vDatetime, vText

from syncall.tw_caldav_utils import SYNCALL_TW_UUID, SYNCALL_TW_WAITING

if TYPE_CHECKING:
import caldav
from item_synchronizer.types import ID
Expand All @@ -27,7 +29,8 @@ class CaldavSide(SyncSide):
"status",
"summary",
"due",
"x-syncall-tw-uuid",
SYNCALL_TW_UUID,
SYNCALL_TW_WAITING,
)

_date_keys: tuple[str] = ("end", "start", "last-modified")
Expand Down Expand Up @@ -140,12 +143,13 @@ def add_item(self, item):
summary=item.get("summary"),
priority=item.get("priority"),
description=item.get("description"),
status=item.get("status").upper(),
status=item["status"].upper(),
due=item.get("due"),
categories=item.get("categories"),
created=item.get("created"),
completed=item.get("completed"),
x_syncall_tw_uuid=item.get("x-syncall-tw-uuid"),
x_syncall_tw_uuid=item.get(SYNCALL_TW_UUID),
x_syncall_tw_waiting=item.get(SYNCALL_TW_WAITING),
)
return map_ics_to_item(icalendar_component(todo))

Expand Down
16 changes: 14 additions & 2 deletions syncall/scripts/tw_caldav_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
)

from syncall.app_utils import confirm_before_proceeding, inform_about_app_extras
from syncall.taskwarrior.taskwarrior_side import TW_CONFIG_DEFAULT_OVERRIDES

try:
from syncall.caldav.caldav_side import CaldavSide
Expand All @@ -32,14 +33,18 @@
register_teardown_handler,
)
from syncall.cli import opts_caldav, opts_miscellaneous, opts_tw_filtering
from syncall.tw_caldav_utils import convert_caldav_to_tw, convert_tw_to_caldav
from syncall.tw_caldav_utils import (
CALDAV_TASK_CANCELLED_UDA,
convert_caldav_to_tw,
convert_tw_to_caldav,
)


@click.command()
@opts_caldav()
@opts_tw_filtering()
@opts_miscellaneous("TW", "Caldav")
def main(
def main( # noqa: PLR0915
caldav_calendar: str,
caldav_url: str,
caldav_user: str | None,
Expand Down Expand Up @@ -155,10 +160,17 @@ def main(

# initialize sides ------------------------------------------------------------------------
# tw
tw_config_overrides = {}
tw_config_overrides["uda"] = TW_CONFIG_DEFAULT_OVERRIDES["uda"]
tw_config_overrides["uda"][CALDAV_TASK_CANCELLED_UDA] = {
"type": "string",
"label": "Task cancelled in Caldav true|false",
}
tw_side = TaskWarriorSide(
tw_filter=" ".join(tw_filter_li),
tags=tw_tags,
project=tw_project,
config_overrides=tw_config_overrides,
)

# caldav
Expand Down
6 changes: 3 additions & 3 deletions syncall/taskwarrior/taskwarrior_side.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"urgency",
]

tw_config_default_overrides = {
TW_CONFIG_DEFAULT_OVERRIDES = {
"context": "none",
"uda": {tw_duration_key: {"type": "duration", "label": "Syncall Duration"}},
}
Expand Down Expand Up @@ -64,14 +64,14 @@ def __init__(
to sync
:param config_file: Path to the taskwarrior RC file
:param config_overrides: Dictionary of taskrc key, values to override. See also
tw_config_default_overrides
TW_CONFIG_DEFAULT_OVERRIDES
"""
super().__init__(name="Tw", fullname="Taskwarrior", **kargs)
self._tags: set[str] = set(tags)
self._project: str = project or ""
self._tw_filter: str = tw_filter

config_overrides_ = tw_config_default_overrides.copy()
config_overrides_ = TW_CONFIG_DEFAULT_OVERRIDES.copy()
config_overrides_.update(config_overrides)

# determine config file
Expand Down
81 changes: 62 additions & 19 deletions syncall/tw_caldav_utils.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,18 @@
from __future__ import annotations

from datetime import timedelta
from typing import TYPE_CHECKING, Literal
from uuid import UUID

from item_synchronizer.types import Item
if TYPE_CHECKING:
from item_synchronizer.types import Item

from syncall.caldav.caldav_utils import parse_caldav_item_desc

aliases_tw_caldav_status = {
"completed": "completed",
"pending": "needs-action",
"waiting": "needs-action",
"deleted": "cancelled",
}
CALDAV_TASK_CANCELLED_UDA = "caldav_completion_status"
SYNCALL_TW_WAITING = "x-syncall-tw-waiting"
SYNCALL_TW_UUID = "x-syncall-tw-uuid"

aliases_caldav_tw_status = {
"completed": "completed",
"needs-action": "pending",
"in-process": "pending",
"cancelled": "deleted",
}

aliases_tw_caldav_priority = {
"l": 9,
Expand All @@ -28,6 +23,50 @@
aliases_caldav_tw_priority = {v: k for k, v in aliases_tw_caldav_priority.items()}


def _determine_caldav_status(tw_item: Item) -> tuple[str, Literal["true", "false"] | None]:
tw_status = tw_item["status"]
if tw_status == "pending":
caldav_status = "needs-action"
tw_waiting_ical_val = "false"
elif tw_status == "waiting":
caldav_status = "needs-action"
tw_waiting_ical_val = "true"

elif tw_status == "completed":
if tw_item.get(CALDAV_TASK_CANCELLED_UDA, "false") == "true":
caldav_status = "cancelled"
else:
caldav_status = "completed"
tw_waiting_ical_val = None
elif tw_status == "deleted":
caldav_status = "" # shouldn't matter
tw_waiting_ical_val = None
else:
raise ValueError(f"Unknown status: {tw_status}")

return caldav_status, tw_waiting_ical_val


def _determine_tw_status(caldav_item: Item) -> tuple[str, Literal["true", "false"] | None]:
caldav_status = caldav_item["status"]
if caldav_status in ("needs-action", "in-process"):
if caldav_item.get(SYNCALL_TW_WAITING, "false") == "true":
tw_status = "waiting"
else:
tw_status = "pending"
task_cancelled_uda_val = None
elif caldav_status == "completed":
tw_status = "completed"
task_cancelled_uda_val = "false"
elif caldav_status == "cancelled":
tw_status = "completed"
task_cancelled_uda_val = "true"
else:
raise ValueError(f"Unknown caldav status: {caldav_status}")

return tw_status, task_cancelled_uda_val


def convert_tw_to_caldav(tw_item: Item) -> Item:
assert all(
i in tw_item for i in ("description", "status", "uuid")
Expand All @@ -41,10 +80,12 @@ def convert_tw_to_caldav(tw_item: Item) -> Item:
caldav_item["description"] = "\n".join(tw_item["annotations"])

# uuid
caldav_item["x-syncall-tw-uuid"] = f'{tw_item["uuid"]}'
caldav_item[SYNCALL_TW_UUID] = tw_item["uuid"]

# Status
caldav_item["status"] = aliases_tw_caldav_status[tw_item["status"]]
caldav_item["status"], caldav_item[SYNCALL_TW_WAITING] = _determine_caldav_status(
tw_item=tw_item,
)

# Priority
if "priority" in tw_item:
Expand Down Expand Up @@ -96,11 +137,13 @@ def convert_caldav_to_tw(caldav_item: Item) -> Item:
tw_item["annotations"] = [
line.strip() for line in caldav_item["description"].split("\n") if line
]
if "x-syncall-tw-uuid" in caldav_item.keys():
tw_item["uuid"] = UUID(caldav_item["x-syncall-tw-uuid"])
if SYNCALL_TW_UUID in caldav_item.keys():
tw_item["uuid"] = UUID(caldav_item[SYNCALL_TW_UUID])

# Status
tw_item["status"] = aliases_caldav_tw_status[caldav_item["status"]]
# Status + task cancelled UDA
tw_item["status"], tw_item[CALDAV_TASK_CANCELLED_UDA] = _determine_tw_status(
caldav_item=caldav_item,
)

# Priority
if prio := aliases_caldav_tw_priority.get(caldav_item["priority"]):
Expand Down

0 comments on commit 3778451

Please sign in to comment.