Skip to content

Conversation

@SebastianKrupinski
Copy link
Contributor

@SebastianKrupinski SebastianKrupinski commented Feb 17, 2025

Summary

Resolves: nextcloud/calendar#7057
Refactored iTip broker message generation to improve logic and RFC compatibility

Testing

How to test, open calendar app, and test the following

🔵 Single Event Operations

Basic Lifecycle

  • Create new event with attendees
  • Update event
  • Delete event
  • Cancel event (STATUS=CANCELLED)

Attendee Management

  • Add new attendee to existing event
  • Remove attendee from event
  • Remove all attendees (convert to non-scheduling)

🟣 Recurring Event Operations

Master Instance

  • Create recurring event (daily/weekly/monthly)
  • Update master event
  • Cancel master instance (entire series)
  • Delete master instance
  • Add EXDATE to master
  • Remove EXDATE from master
  • Convert recurring event to non-scheduling

Exception Instances

  • Create exception (modify single occurrence time)
  • Create exception (modify single occurrence summary)
  • Update existing exception
  • Cancel single occurrence (create cancelled exception)
  • Create new exception that is already cancelled

🟠 Partial Attendee Lists (EXDATE Logic)

Critical EXDATE Scenarios

  • Remove attendee from single occurrence (verify EXDATE in their REQUEST)
  • Add attendee to single occurrence only (verify they get only exception)
  • Different attendees on different exceptions:
    • Master: A + B + C
    • Exception 1: A + B only
    • Exception 2: A + C only
    • Verify A gets master + both exceptions
    • Verify B gets master + exception 1 + EXDATE for exception 2
    • Verify C gets master + exception 2 + EXDATE for exception 1

🔴 Edge Cases

Organizer & Empty States

  • Organizer is also an attendee (verify organizer doesn't receive message)
  • Create event with no attendees
  • Remove all attendees from event

✅ Verification Per Test

For each test above, verify:

Message Method

  • REQUEST for updates/additions
  • CANCEL for removals/cancellations

Recipients

  • All appropriate attendees receive messages
  • No duplicate messages sent
  • Organizer doesn't receive self-invites
  • SCHEDULE-AGENT=CLIENT attendees skipped

Message Content

  • All properties correctly reflected
  • EXDATE properly added for partial attendee lists

Instance Selection

  • Master included when appropriate
  • Exceptions included when appropriate
  • Cancelled instances not in REQUEST (only in CANCEL)

TODO

  • Add phpdoc to function
  • Add phpdoc parameter definitions for arrays

Checklist

Copy link
Member

@st3iny st3iny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The following case did not cause a reaction email being sent to the organizer:

  1. Organizer invites attendee (recurring, daily, 5 times).
  2. Attendee declines the second to last instance.

In general, no messages seem to get sent if an attendee accepts or declines a single instance.

Is this intended?

@SebastianKrupinski
Copy link
Contributor Author

Is this intended?

I don't think this has anything to do with this PR.

  1. Organizer invites attendee (recurring, daily, 5 times).

This should work just like any other scenario, I tested this on my end and the iTip message are being generated properly.

Example,

Screenshot 2025-02-24 140336

Screenshot 2025-02-24 140413

  1. Attendee declines the second to last instance.

This PR does not touch the Attendee portion of the iTipBroker, that is done in the parseEventForAttendee function and this only overloads the parseEventForOrganizer function which generates messages for organizer changes.

In general, no messages seem to get sent if an attendee accepts or declines a single instance.

I had the same problem, this is most likely a issue with your DEV instance, when our server tests run they empty out the appdata_* folder, this is the place where the contents of a sent message is saved and if the "appdata_/mail/mail_user" folder is missing the send process fails.

Screenshot 2025-02-24 140655

Screenshot 2025-02-24 140949

Screenshot 2025-02-24 141349

@st3iny
Copy link
Member

st3iny commented Feb 25, 2025

/backport to stable31

@st3iny
Copy link
Member

st3iny commented Feb 25, 2025

/backport to stable30

@susnux susnux added this to the Nextcloud 32 milestone Mar 2, 2025
st3iny
st3iny previously requested changes Mar 3, 2025
Copy link
Member

@st3iny st3iny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does not fix cancelling a single instance.

Consider two accounts: organizer and user.

  1. Organizer: Create recurring event, daily, 3 times and invite another user.
  2. User: Accept whole series.
  3. Organizer: Cancels an instance, e.g. the second one.

Expected: User will only see the second instance being cancelled.
Actual: The whole series is cancelled from user's POV.

I exported the events and was able to confirm that the organizer's event has a new instance with a cancelled state. The user's event however, does not contain a separate instance. Instead, the base event was cancelled.

@SebastianKrupinski
Copy link
Contributor Author

Does not fix cancelling a single instance.

Consider two accounts: organizer and user.

1. Organizer: Create recurring event, daily, 3 times and invite another user.

2. User: Accept whole series.

3. Organizer: Cancels an instance, e.g. the second one.

Expected: User will only see the second instance being cancelled. Actual: The whole series is cancelled from user's POV.

I exported the events and was able to confirm that the organizer's event has a new instance with a cancelled state. The user's event however, does not contain a separate instance. Instead, the base event was cancelled.

Okay, having a look. Disregard the last message, I tested the wrong thing

@SebastianKrupinski
Copy link
Contributor Author

Does not fix cancelling a single instance.

Consider two accounts: organizer and user.

1. Organizer: Create recurring event, daily, 3 times and invite another user.

2. User: Accept whole series.

3. Organizer: Cancels an instance, e.g. the second one.

Expected: User will only see the second instance being cancelled. Actual: The whole series is cancelled from user's POV.

I exported the events and was able to confirm that the organizer's event has a new instance with a cancelled state. The user's event however, does not contain a separate instance. Instead, the base event was cancelled.

LMAO. So I found the issue... You've found another bug that I didn't know existed...

So the iTipBroker is now generating proper messages for instances, but its not processing Cancellation instances properly...

The method at fault... Sabre\VObject\ITip\Broker::processMessageCancel()

    protected function processMessageCancel(Message $itipMessage, ?VCalendar $existingObject = null)
    {
        if (!$existingObject) {
            // The event didn't exist in the first place, so we're just
            // ignoring this message.
        } else {
            foreach ($existingObject->VEVENT as $vevent) {
                $vevent->STATUS = 'CANCELLED';
                $vevent->SEQUENCE = $itipMessage->sequence;
            }
        }

        return $existingObject;
    }

As you can see it does not check the iTipMessage for a RECURRANCE-ID, it just applies the cancellation to every instance...

@SebastianKrupinski SebastianKrupinski changed the title fix: iTipBroker message generation and testing fix(CalDAV): iTipBroker message generation and testing Mar 10, 2025
@ChristophWurst ChristophWurst requested a review from st3iny April 28, 2025 14:19
This was referenced Aug 22, 2025
This was referenced Sep 2, 2025
This was referenced Sep 25, 2025
@skjnldsv skjnldsv modified the milestones: Nextcloud 32, Nextcloud 33 Sep 28, 2025
@SebastianKrupinski SebastianKrupinski force-pushed the fix/noid/fix-itipbroker-messages branch from 9712d2a to 02205c3 Compare November 7, 2025 04:58
@ChristophWurst
Copy link
Member

Remove EXDATE from master

How do I do this from the Calendar UI?

@SebastianKrupinski
Copy link
Contributor Author

Remove EXDATE from master

How do I do this from the Calendar UI?

That one you actually can't do through the UI, we don't support that, it can be skipped, or you can do a manual PUT request to trigger it.

Copy link
Member

@ChristophWurst ChristophWurst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was not able to test this due to complexity

LGTM because there are tests

@SebastianKrupinski SebastianKrupinski force-pushed the fix/noid/fix-itipbroker-messages branch from 3486d70 to a96aece Compare December 11, 2025 17:36
This was referenced Jan 7, 2026
This was referenced Jan 14, 2026
@DerDreschner
Copy link

DerDreschner commented Jan 21, 2026

Okay, I tried to test the changes as good as possible. I discovered following issues. The "showstopper" (IMHO) are marked with ⛔ in front of the text, while "someone should have a look at it" is marked with ⚠️. All other issues have likely nothing to do with this change and affect the stable release already. They could also already be reported in the calendar repository - I didn't checked that to be honest.

  • ⛔ Attendees that are being removed from an event get no notification at all. That's true for all kinds of event and never worked for me. I didn't tested the EXDATE conditions until this is being resolved.

  • ⛔ Create a series of events with another attendee. Let them accept the invitation with Thunderbird. Send a changed start/end time to a single occurrence only. Thunderbird let the attendee not reply to the moved event nor take the changed time into account on the calendar. Instead, it will show the "This message contains an event that has already been processed." message. My best guess about what the issue here is: all VEVENT entries use the same UID and only the SEQUENCE number changes.

image
ics file content with two VEVENT entries, but same UID
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//IDN nextcloud.com//Calendar app 6.2.0-beta.0//EN
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VTIMEZONE
TZID:Europe/Berlin
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20260121T161443Z
DTSTAMP:20260121T161505Z
LAST-MODIFIED:20260121T161505Z
SEQUENCE:2
UID:c500493d-2447-48ec-be26-5489ba3af272
DTSTART;TZID=Europe/Berlin:20260201T100000
DTEND;TZID=Europe/Berlin:20260201T110000
STATUS:CONFIRMED
SUMMARY:Test einer weiteren Reihe
ATTENDEE;CN=david.dreschner@nextcloud.com;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-
 ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:david.dreschner@nextcloud.com
ORGANIZER;CN=David Dreschner:mailto:github-2017@dreschner.net
RRULE:FREQ=WEEKLY;COUNT=4;BYDAY=SU
END:VEVENT
BEGIN:VEVENT
CREATED:20260121T161718Z
DTSTAMP:20260121T161718Z
LAST-MODIFIED:20260121T161718Z
SEQUENCE:1
UID:c500493d-2447-48ec-be26-5489ba3af272
DTSTART;TZID=Europe/Berlin:20260201T150000
DTEND;TZID=Europe/Berlin:20260201T160000
STATUS:CONFIRMED
SUMMARY:Test einer weiteren Reihe
ATTENDEE;CN=david.dreschner@nextcloud.com;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-
 ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:david.dreschner@nextcloud.com
ORGANIZER;CN=David Dreschner:mailto:github-2017@dreschner.net
RECURRENCE-ID;TZID=Europe/Berlin:20260201T100000
END:VEVENT
END:VCALENDAR
  • This might occur due to the same reason as the error before or might be a TB bug! I will retest once the above issue is resolved! Create a series of events with another attendee. Afterwards, change the start time of the first occurrence. When the attendee now accepts on the second change with "accept all", only the series shows up as accepted. The first occurrence that changed do show up as "not replied yet".

  • ⚠️ This might be expected behavior? Although confusing as end-user? Create an event with an attendee. Set the status of the event to cancelled. The attendee will get a Cancelled email. If you delete the event from your personal calendar, the attendee get another cancelled email with the same content in the ICS file.

  • ⚠️ Nitpicking! When adding an attendee to an existing event, the subject says Updated invitation, which is technically correct, but confusing for the attendee that never got any invitation before. Should be Invitation instead (but only for them!).

Wishes from user perspective:

  • Mail app opens reply to event -> immediate update the response status shown in the calendar event. It's quite confusing to not see the update in real-time as it's only being done when the background job runs (especially when you're used to the behavior by Outlook + On-Prem Exchange, where this is the default). Before realizing (and keeping that in mind during testing) I tend to categorize that as bug honestly.

Highly likely to be already reported elsewhere (or should be tracked as separate issue otherwise):

  • When adding an attendee, I would expect the role being set to required as this is the default when nothing is selected.
  • Created events don't show the selected role for the attendees afterwards.
  • Create an event and add yourself to the attendee list by adding the e-mail address that's assigned to your nextcloud profile. In this case, the UI will now show the option to accept/decline/tentative the event. The number of attendees shows 2, although the list only shows one person (the organizer). When selecting decline during creation of the event, the event will be saved, which was unexpected to me. But - to mention that - only one notification is being sent when adding a single person multiple times (or none at all when adding yourself). When opening the event afterwards, there is no mention of the "second" attendee (yourself, just added by mail). To make matters worse, the title of the event is now shown two times, one after the other? And the organizer still shows up as "accepted", together with the option to accept/tentative respond to the invitation for the canceled event?
simplescreenrecorder-2026-01-21_17.42.49.mp4
image
  • When adding a single person multiple times, the created event lists them all instead of catching that by only adding them once. Thunderbird correctly merges them together when showing the list, but that shouldn't happen in my opinion. See issue above.
simplescreenrecorder-2026-01-21_17.53.07.mp4
ICS file created with same attendee multiple times
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//IDN nextcloud.com//Calendar app 6.2.0-beta.0//EN
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VTIMEZONE
TZID:Europe/Berlin
BEGIN:DAYLIGHT
TZNAME:CEST
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZNAME:CET
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
CREATED:20260121T165235Z
DTSTAMP:20260121T165322Z
LAST-MODIFIED:20260121T165322Z
SEQUENCE:2
UID:4b7ed97e-7326-4fe1-960e-772b158af342
DTSTART;TZID=Europe/Berlin:20260205T100000
DTEND;TZID=Europe/Berlin:20260205T110000
STATUS:CONFIRMED
SUMMARY:This is a test for adding a single person multiple times
ATTENDEE;CN=david.dreschner@nextcloud.com;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-
 ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:david.dreschner@nextcloud.com
ATTENDEE;CN=david.dreschner@nextcloud.com;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-
 ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:david.dreschner@nextcloud.com
ATTENDEE;CN=david.dreschner@nextcloud.com;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-
 ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:david.dreschner@nextcloud.com
ATTENDEE;CN=david.dreschner@nextcloud.com;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-
 ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:david.dreschner@nextcloud.com
ATTENDEE;CN=david.dreschner@nextcloud.com;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-
 ACTION;ROLE=REQ-PARTICIPANT;RSVP=TRUE:mailto:david.dreschner@nextcloud.com
ORGANIZER;CN=David Dreschner:mailto:github-2017@dreschner.net
END:VEVENT
END:VCALENDAR

@DerDreschner
Copy link

DerDreschner commented Jan 21, 2026

Follow up question for the next test round (@SebastianKrupinski): what's the best way to test the SCHEDULE-AGENT=CLIENT behavior? Is there any setting in the calendar to assume that clients handle the schedule? Or is that taken into account only after receiving an reply from someone with that flag set? I didn't test that case right now.

@SebastianKrupinski
Copy link
Contributor Author

Follow up question for the next test round (@SebastianKrupinski): what's the best way to test the SCHEDULE-AGENT=CLIENT behavior? Is there any setting in the calendar to assume that clients handle the schedule? Or is that taken into account only after receiving an reply from someone with that flag set? I didn't test that case right now.

You need a external client that supports this flag, or you can use a testing tool like Insomnia, create a PUT request that updates a existing event with "SCHEDULE-AGENT=CLIENT" set.

Signed-off-by: SebastianKrupinski <krupinskis05@gmail.com>
@SebastianKrupinski
Copy link
Contributor Author

Hi @DerDreschner

Thank you for the thoroughly testing but from the comments it looks like most of these items are unrelated to the PR, and what it fixes. Most seem to be UI bugs in Calendar and not related.

* ⛔ Attendees that are being removed from an event get no notification at all. That's true for all kinds of event and never worked for me. I didn't tested the `EXDATE` conditions until this is being resolved.

I will retest this, this was working originally, but I modified some code when I was testing all the scenarios.

* ⛔ Create a series of events with another attendee. Let them accept the invitation with Thunderbird. Send a changed start/end time to a single occurrence only. Thunderbird let the attendee not reply to the moved event nor take the changed time into account on the calendar. Instead, it will show the "This message contains an event that has already been processed." message. My best guess about what the issue here is: all `VEVENT` entries use the same `UID` and only the `SEQUENCE` number changes.

If you received a invitation then your test was successful. As for the 2 events with the same UID this is correct behavior as per RFC, this is also how the current code works, event modification are stored inside the same event, as a modification.

Current Code Result...

BEGIN:VCALENDAR
VERSION:2.0
CALSCALE:GREGORIAN
PRODID:-//IDN nextcloud.com//Calendar app 6.2.0-beta.0//EN

BEGIN:VEVENT
CREATED:20260121T180239Z
DTSTAMP:20260121T180400Z
LAST-MODIFIED:20260121T180400Z
SEQUENCE:2
UID:d14f8d5f-a6f1-4694-a2d7-a48e3dc067c9
DTSTART;TZID=America/New_York:20260126T100000
DTEND;TZID=America/New_York:20260126T110000
STATUS:CONFIRMED
SUMMARY:This is a recurring event
ATTENDEE;CN=User Two;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTI
 CIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.1:mailto:user2@nextdev.app
ORGANIZER;CN=User One:mailto:user1@nextdev.app
RRULE:FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;RELATED=START:-PT15M
SUMMARY:This is a recurring event
DESCRIPTION:This is an event reminder.
ATTENDEE:mailto:user2@nextdev.app
END:VALARM
END:VEVENT

BEGIN:VEVENT
CREATED:20260121T180425Z
DTSTAMP:20260121T180425Z
LAST-MODIFIED:20260121T180425Z
SEQUENCE:1
UID:d14f8d5f-a6f1-4694-a2d7-a48e3dc067c9
DTSTART;TZID=America/New_York:20260205T100000
DTEND;TZID=America/New_York:20260205T110000
STATUS:CONFIRMED
SUMMARY:This is a recurring event
ATTENDEE;CN=User Two;CUTYPE=INDIVIDUAL;PARTSTAT=NEEDS-ACTION;ROLE=REQ-PARTI
 CIPANT;RSVP=TRUE;SCHEDULE-STATUS=1.1:mailto:user2@nextdev.app
ORGANIZER;CN=User One:mailto:user1@nextdev.app
RECURRENCE-ID;TZID=America/New_York:20260204T100000
BEGIN:VALARM
ACTION:DISPLAY
TRIGGER;RELATED=START:-PT15M
SUMMARY:This is a recurring event
DESCRIPTION:This is an event reminder.
ATTENDEE:mailto:user2@nextdev.app
END:VALARM
END:VEVENT
END:VCALENDAR
* ⛔ **This might occur due to the same reason as the error before or might be a TB bug! I will retest once the above issue is resolved!** Create a series of events with another attendee. Afterwards, change the start time of the first occurrence. When the attendee now accepts on the second change with "accept all", only the series shows up as accepted. The first occurrence that changed do show up as "not replied yet".

It sounds like you clicked "This and all future events" on the second occurrence, this creates a new series modification that truncates the original event, I agree this is bad logic, but it is also the current logic. Fixing this is out of scope of this PR.

* ⚠️ **This might be expected behavior? Although confusing as end-user?** Create an event with an attendee. Set the status of the event to `cancelled`. The attendee will get a `Cancelled` email. If you delete the event from your personal calendar, the attendee get another `cancelled` email with the same content in the ICS file.

This is know behavior it is a flaw in the current trash bin implementation, emptying the trash causes another iTip message. This is out of scope of this PR.

* ⚠️ **Nitpicking!** When adding an attendee to an existing event, the subject says `Updated invitation`, which is technically correct, but confusing for the attendee that never got any invitation before. Should be `Invitation` instead (but only for them!).

I agree on this point, but the code that creates the actual email as "update" is in a different module and out of scope for this PR. This PR only handles the generation of the messages that the email module handles.

* Mail app opens reply to event -> immediate update the response status shown in the calendar event. It's quite confusing to not see the update in real-time as it's only being done when the background job runs (especially when you're used to the behavior by Outlook + On-Prem Exchange, where this is the default). Before realizing (and keeping that in mind during testing) I tend to categorize that as bug honestly.

This is out of scope of this PR. This has to do with the imip message only being processed in the back ground in the mail app.

* When adding an attendee, I would expect the role being set to `required` as this is the default when nothing is selected.

This is out of scope of this PR. This sounds like a UI issue in Calendar.

* Created events don't show the selected role for the attendees afterwards.

This is out of scope of this PR. This sounds like a UI issue in Calendar.

* Create an event and add yourself to the attendee list by adding the e-mail address that's assigned to your nextcloud profile. In this case, the UI will now show the option to accept/decline/tentative the event. The number of attendees shows `2`, although the list only shows one person (the organizer). When selecting `decline` during creation of the event, the event will be saved, which was unexpected to me. But - to mention that - only one notification is being sent when adding a single person multiple times (or none at all when adding yourself). When opening the event afterwards, there is no mention of the "second" attendee (yourself, just added by mail). To make matters worse, the title of the event is now shown two times, one after the other? And the organizer still shows up as "accepted", together with the option to accept/tentative respond to the invitation for the canceled event?

This is out of scope of this PR. This sounds like a UI issue in Calendar. Also I was not able to reproduce this, are you working with a up to date version of calendar?

* When adding a single person multiple times, the created event lists them all instead of catching that by only adding them once. Thunderbird correctly merges them together when showing the list, but that shouldn't happen in my opinion. See issue above.

This is out of scope of this PR. This is a UI glitch in Calendar app, I was able to confirm this.

@SebastianKrupinski SebastianKrupinski force-pushed the fix/noid/fix-itipbroker-messages branch from a96aece to fb71191 Compare January 21, 2026 18:59
@DerDreschner
Copy link

DerDreschner commented Jan 22, 2026

Most seem to be UI bugs in Calendar and not related.

Yes, I just wanted to document what kind of bugs I found in general during testing. I have no overview about what issues are open in calendar and how they are handled there - so, feel free to create new issues out of them or tell me which ones need a new issue, so I don't create duplicates. I'm happy to create them so we can fix that in the future.

I'm sorry if that way of testing / documenting creates any kind of frustration or confusion on your side, that wasn't my intention.

I will retest this, this was working originally, but I modified some code when I was testing all the scenarios.

Is this now fixed with the changes you pushed right after the comment?

If you received a invitation then your test was successful.

Alright, I did. So, test successful.

As for the 2 events with the same UID this is correct behavior as per RFC, this is also how the current code works, event modification are stored inside the same event, as a modification.

Ahh, I see. It was just my first best guess without further digging into the RFC. This point might be out-of-scope anyway, but that's something that works with Google Calendars. So, not broken in general with Thunderbird (although Google seem to have handled that the same way we do in the past). When changing an event of a series (or any other changes), Thunderbird shows the accept/tentative/decline selection instead of just showing the "already processed" message. But it looks like they handle it differently as the change ics only contains the VEVENT with SEQUENCE:1? Maybe TB only looks for the first found VEVENT inside the ics file to decide if is already being processed or not? I don't know, it's up to you. I just want to mention it for housekeeping. Let me know if I should create a new issue for that.

First invitation to event series via Google Calendar Screenshot from 2026-01-22 10-27-25
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VTIMEZONE
TZID:Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:GMT+2
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:GMT+1
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=Europe/Berlin:20260122T150000
DTEND;TZID=Europe/Berlin:20260122T160000
RRULE:FREQ=WEEKLY;BYDAY=TH
DTSTAMP:20260122T091036Z
ORGANIZER;CN=David Dreschner:mailto:example@gmail.com
UID:26f7oohvu5di0bhilh7hq9ju0n@google.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=
 TRUE;CN=github-2017@dreschner.net;X-NUM-GUESTS=0:mailto:github-2017@dreschner.net
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE
 ;CN=David Dreschner;X-NUM-GUESTS=0:mailto:example@gmail.com
X-GOOGLE-CONFERENCE:https://meet.google.com/ugx-snqm-xur
X-MICROSOFT-CDO-OWNERAPPTID:-506458114
CREATED:20260122T091033Z
DESCRIPTION:-::~:~::~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~
 :~:~:~:~:~:~:~:~::~:~::-\nJoin with Google Meet: https://meet.google.com/ug
 x-snqm-xur\n\nLearn more about Meet at: https://support.google.com/a/users/
 answer/9282720\n\nPlease do not edit this section.\n-::~:~::~:~:~:~:~:~:~:~
 :~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~::~:~::-
LAST-MODIFIED:20260122T091033Z
LOCATION:https://meet.google.com/ugx-snqm-xur
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Test
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR
Invitation to a changed event within the series via Google Calendar View after accepting the series invitation: Screenshot from 2026-01-22 10-29-39
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:REQUEST
BEGIN:VTIMEZONE
TZID:Europe/Berlin
X-LIC-LOCATION:Europe/Berlin
BEGIN:DAYLIGHT
TZOFFSETFROM:+0100
TZOFFSETTO:+0200
TZNAME:GMT+2
DTSTART:19700329T020000
RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=-1SU
END:DAYLIGHT
BEGIN:STANDARD
TZOFFSETFROM:+0200
TZOFFSETTO:+0100
TZNAME:GMT+1
DTSTART:19701025T030000
RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DTSTART;TZID=Europe/Berlin:20260129T153000
DTEND;TZID=Europe/Berlin:20260129T163000
DTSTAMP:20260122T091115Z
ORGANIZER;CN=David Dreschner:mailto:example@gmail.com
UID:26f7oohvu5di0bhilh7hq9ju0n@google.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=ACCEPTED;RSVP=TRUE
 ;CN=David Dreschner;X-NUM-GUESTS=0:mailto:example@gmail.com
ATTENDEE;CUTYPE=INDIVIDUAL;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-ACTION;RSVP=
 TRUE;CN=github-2017@dreschner.net;X-NUM-GUESTS=0:mailto:github-2017@dreschner.net
X-GOOGLE-CONFERENCE:https://meet.google.com/ugx-snqm-xur
X-MICROSOFT-CDO-OWNERAPPTID:1244671364
RECURRENCE-ID;TZID=Europe/Berlin:20260129T150000
CREATED:20260122T091033Z
DESCRIPTION:-::~:~::~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~
 :~:~:~:~:~:~:~:~::~:~::-\nJoin with Google Meet: https://meet.google.com/ug
 x-snqm-xur\n\nLearn more about Meet at: https://support.google.com/a/users/
 answer/9282720\n\nPlease do not edit this section.\n-::~:~::~:~:~:~:~:~:~:~
 :~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~:~::~:~::-
LAST-MODIFIED:20260122T091113Z
LOCATION:https://meet.google.com/ugx-snqm-xur
SEQUENCE:1
STATUS:CONFIRMED
SUMMARY:Test
TRANSP:OPAQUE
END:VEVENT
END:VCALENDAR

This is out of scope of this PR. This sounds like a UI issue in Calendar. Also I was not able to reproduce this, are you working with a up to date version of calendar?

I've used the main branch and built the UI locally before the test with node v20. Might be something wrong with my local build if you're unable to reproduce.

@SebastianKrupinski
Copy link
Contributor Author

so, feel free to create new issues out of them or tell me which ones need a new issue, so I don't create duplicates. I'm happy to create them so we can fix that in the future.

I'm sorry if that way of testing / documenting creates any kind of frustration or confusion on your side, that wasn't my intention.

I will retest this, this was working originally, but I modified some code when I was testing all the scenarios.

Is this now fixed with the changes you pushed right after the comment?

If you received a invitation then your test was successful.

Alright, I did. So, test successful.

As for the 2 events with the same UID this is correct behavior as per RFC, this is also how the current code works, event modification are stored inside the same event, as a modification.

Ahh, I see. It was just my first best guess without further digging into the RFC. This point might be out-of-scope anyway, but that's something that works with Google Calendars. So, not broken in general with Thunderbird (although Google seem to have handled that the same way we do in the past). When changing an event of a series (or any other changes), Thunderbird shows the accept/tentative/decline selection instead of just showing the "already processed" message. But it looks like they handle it differently as the change ics only contains the VEVENT with SEQUENCE:1? Maybe TB only looks for the first found VEVENT inside the ics file to decide if is already being processed or not? I don't know, it's up to you. I just want to mention it for housekeeping. Let me know if I should create a new issue for that.
First invitation to event series via Google Calendar

Invitation to a changed event within the series via Google Calendar

This is out of scope of this PR. This sounds like a UI issue in Calendar. Also I was not able to reproduce this, are you working with a up to date version of calendar?

I've used the main branch and built the UI locally before the test with node v20. Might be something wrong with my local build if you're unable to reproduce.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cancelling single instance in a recurring series

7 participants