Skip to content

fix(calendar): stop rebuilding a VTODO from the partial update dict on error - #1377

Open
thejdubb02 wants to merge 1 commit into
cbcoutinho:masterfrom
thejdubb02:fix/todo-merge-no-rebuild-fallback
Open

fix(calendar): stop rebuilding a VTODO from the partial update dict on error#1377
thejdubb02 wants to merge 1 commit into
cbcoutinho:masterfrom
thejdubb02:fix/todo-merge-no-rebuild-fallback

Conversation

@thejdubb02

@thejdubb02 thejdubb02 commented Aug 23, 2026

Copy link
Copy Markdown

Fixes #1252.

_merge_ical_todo_properties ended in a catch-all that returned
_create_ical_todo(todo_data, todo_uid). On the update path todo_data holds only the
fields the caller passed, so any exception replaced the stored todo with one rebuilt from
that partial dict — dropping summary, due date, dtstart, the completed timestamp,
categories, RRULE, alarms and every custom property the caller did not re-send — and
reported success.

This is the same defect removed from the event merge in #544. _merge_ical_properties
raises instead and its docstring records why; the todo path never got the same treatment.
It was already half-fixed — except ValueError: raise was added with a comment pointing
at that precedent — but every other exception still fell through to the rebuild.

todo_uid goes with it, for the reason event_uid did: the parameter existed only to
feed the fallback, and the UID carries through from the stored iCal as a preserved
property.

Reviewing

Most of the diff is the dedent from dropping the try:. ?w=1 shows the real change: 35 lines.

Test

test_a_non_value_error_does_not_silently_rebuild_the_todo passes a malformed reminder,
which raises AttributeError — precisely what the catch-all swallowed. It fails on
master and passes with this change. No mocking; the input is real.

On propagating instead of catching

One reviewer raised whether removing a catch-all risks unhandled exceptions reaching the
client. Worth stating what I checked: nc_calendar_update_todo catches only
DavPreconditionFailed and lets everything else propagate, and the event path has
behaved this way since #544. This change introduces no exception path that is not already
live for events. The alternative traded that for guaranteed silent data loss.

Provenance

Written with AI assistance, then verified rather than trusted:

  • The full unit suite runs clean — 56 passed, and the 13 collection errors are
    pre-existing on untouched master (missing optional test deps in my environment), not
    introduced here.
  • ruff check reports one fewer error than master; ruff format --check is clean.
  • The new test was confirmed to fail without the source change and pass with it.
  • The patch was reviewed by three independent models plus a human before submission, and
    the one dissent is answered above.
  • Running against my own Nextcloud instance, where this code path is in daily use.

Happy to split the whitespace-only dedent into its own commit if that reads better.

…n error

`_merge_ical_todo_properties` ended in a catch-all that returned
`_create_ical_todo(todo_data, todo_uid)`. On the update path `todo_data` carries
only the fields the caller passed, so any exception at all — including a transient
parse failure on an otherwise intact resource — silently replaced the stored todo
with one built from that partial dict, dropping summary, due date, dtstart, the
completed timestamp, categories, RRULE, alarms and every custom property the caller
did not happen to re-send, while reporting success.

This is the defect removed from the event merge in cbcoutinho#544. `_merge_ical_properties`
raises instead, and its docstring records why; the todo path never got the same
treatment. It had already been half-fixed — `except ValueError: raise` was added
with a comment pointing at that precedent — but everything else still fell through
to the rebuild.

`todo_uid` goes with it. Like `event_uid` before it, the parameter existed only to
feed the fallback; the UID carries through from the stored iCal as a preserved
property.

The bulk of the diff is the dedent from dropping the `try:`. `?w=1` shows the
change is 35 lines.

Fixes cbcoutinho#1252
@CLAassistant

CLAassistant commented Aug 23, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

_merge_ical_todo_properties still rebuilds a VTODO from the partial update dict on any error

2 participants