Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scheduling with external organizer #1249

Open
pk1234 opened this issue Feb 17, 2020 · 13 comments
Open

Scheduling with external organizer #1249

pk1234 opened this issue Feb 17, 2020 · 13 comments

Comments

@pk1234
Copy link

pk1234 commented Feb 17, 2020

We are using SabreDAV 3.2.2 and recently activated scheduling, i.e. added

  $server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
  $server->addPlugin(new \Sabre\CalDAV\Schedule\IMipPlugin('Calendar-Server@our.domain'));

to our server.php.

Case 1: An internal organizer O creates a calendar entry with an internal attendee A. SabreDAV will then create two calendarobjects in the calendars of O and A and the partstat of A will be tentative in both of them. SabreDAV also sends an email to A. If A accepts the invitation (either from within the email-application or from the calendar-application) a confirmation email is be sent to O.

Case 2: An external orgainzer E creates a calendar entry and invites A. In this case no calendarobjects will be created until A accepts the invitation. At this point I would expect SabreDAV to sent a confirmation email to E. But SabreDAV does not send such an email, neither does the calendar app of A since auto-scheduling prevents this to happen in the client.

I tried to analyse the problem and here's what I found out so far:

  • Sabre\CalDAV\Schedule\Plugin::calendarObjectChange() is called after A accepts the invitation. In case 1 parameter $isNew is false, since the calendar of A already contains the event with partstat=tentative. In case 2 $isNew is true.
  • calendarObjectChange() calls processICalendarChange() with either $oldObject==NULL or $oldObject!=NULL
  • processICalendarChange() then calls Sabre\VObject\ITip\Broker::parseEvent() with either $oldCalendar==NULL or $oldCalendar!=NULL
  • parseEvent() has the following lines:
...
} elseif ($oldCalendar) {
    // We need to figure out if the user is an attendee, but we're only
    // doing so if there's an oldCalendar, because we only want to
    // process updates, not creation of new events.
    foreach ($eventInfo['attendees'] as $attendee) {
        if (in_array($attendee['href'], $userHref)) {
            return $this->parseEventForAttendee($baseCalendar, $eventInfo, $oldEventInfo, $attendee['href']);
        }
    }
}
...
  • so parseEvent() returns an empty array in case 2 since then $oldCalendar==null

So here are my questions:

  • Why is parseEvent() only processing updates of existing events?

It seems to me that this is causing the problem in case 2. I will try to fix this and let you know what happens.

Any other ideas how to fix this?

Peter

@pk1234
Copy link
Author

pk1234 commented Feb 19, 2020

It seems like the above problem is caused by three minor SabreDAV bugs, namely:

Here's what I did so far to make SabreDAV handle new vevents: When Sabre\CalDAV\Schedule\Plugin::calendarObjectChange() is called with $isNew==true, processICalendarChange() was called with $oldObj==null. I changed that such that processICalendarChange() is called with a fake old vevent that I create by cloning the new vevent and removing all attendees.

Here's the old code from vendor/sabre/dav/lib/CalDAV/Schedule/Plugin.php:

if (!$isNew) {
    $node = $this->server->tree->getNodeForPath($request->getPath());
    $oldObj = Reader::read($node->get());
} else {
    $oldObj = null;
}

and here's the new one:

if (!$isNew) {
    $node = $this->server->tree->getNodeForPath($request->getPath());
    $oldObj = Reader::read($node->get());
} else {
    $oldObj = null;
    if($vCal->VEVENT){
        $oldObj=clone $vCal;
        unset($oldObj->VEVENT->ATTENDEE);
    }
}

I have no idea wether this has unwanted side-effects. With our setup this worked (when #1250 and #1252 are fixed as well)

Peter

@m-a-v
Copy link

m-a-v commented Apr 21, 2020

@pk1234 Do you get valid ics files with your replies? See also my comments in #1168.

Thanks a lot for your other suggestions.

@m-a-v
Copy link

m-a-v commented May 17, 2020

The solution with the fake $oldObj seems quite hacky.

@evert I know it is sometimes difficult to remember commits that are years old. But could you shed some light on the subject? What I have seen is that creation of new events are not processed (tested with sabre/dav 4.1.0).

because we only want to process updates, not creation of new events.

See changes in (Broker.php):
sabre-io/vobject@18c86bc

The question is when an external organzier sends an event. Which would be the correct method to send a reply for the initial invitation? If I change the else if into an else path then a reply is sent to the organzier using the IMipPlugin. I dont't know if this would have any side effects.

https://github.com/sabre-io/vobject/blob/18c86bcbf8c962b5f1b10b25bd03148aa596f664/lib/Sabre/VObject/ITip/Broker.php#L191

@evert
Copy link
Member

evert commented May 17, 2020

Just looking at that line you sent:

My best guess is that, when an event is changed by an attendee of an event, the initial event creation is always triggered by the organizer.

When the event is first created, no attendee action has taken place. Only after the attendee performs an action (update RSVP, delete instance, etc) this would result in a message.

But I'm not sure. I don't really have the time to dig into this or the original issues. I'm no longer involved with this project

@m-a-v
Copy link

m-a-v commented May 18, 2020

OK. Thank you very much for your reply and your great work you've done.

I think this is a bug. If an external organzier creates an event (REQUEST) then no action is taken by the attendee since $oldObj is null. The initial action for an event (e.g. ACCEPT) should also create a reply in my point of view.

@evert
Copy link
Member

evert commented May 19, 2020

Under what condition / what clients will create events like this? Just curious, your reasoning seems sound

@m-a-v
Copy link

m-a-v commented May 19, 2020

I've only tested it with an external organizer (Google Calendar and Outlook 365) and the attendee is using eM Client in conjunction with sabre/dav. The external organzier creates an event and sends the invitation to the client (eM Client). In the client software I then accept the event.

image

@mc-buckets
Copy link

Is this going to be fixed officially? I tried changing the else if to an else but RSVP emails are still not being sent. My use case is simple: I routinely get invited to events by people using Google Calendar. I RSVP in my client (Thunderbird), but the person who sent me the event invite never gets my RSVP email.

Emails are properly sent to attendees when I create and edit events, they only don't work for RSVPs.

The solution with the fake $oldObj seems quite hacky.

@evert I know it is sometimes difficult to remember commits that are years old. But could you shed some light on the subject? What I have seen is that creation of new events are not processed (tested with sabre/dav 4.1.0).

because we only want to process updates, not creation of new events.

See changes in (Broker.php):
sabre-io/vobject@18c86bc

The question is when an external organzier sends an event. Which would be the correct method to send a reply for the initial invitation? If I change the else if into an else path then a reply is sent to the organzier using the IMipPlugin. I dont't know if this would have any side effects.

https://github.com/sabre-io/vobject/blob/18c86bcbf8c962b5f1b10b25bd03148aa596f664/lib/Sabre/VObject/ITip/Broker.php#L191

@mc-buckets
Copy link

Update: changing the elseif to an else and also doing the fixes outlined in #1250 and #1252 has everything working. I'm still curious why this wouldn't just work out of the box, the use case is common.

If I knew more PHP I would submit PRs w/ tests!

@evert
Copy link
Member

evert commented Dec 1, 2020

I'm no longer active on this project, so it's up to others to submit a PR and release it.

@icaroscherma
Copy link

I tried to find examples regarding Scheduling but I couldn't so far.

I got CalDAV working on my localhost environment (php8 + apache 2.4, dockerized), added to Mac OS Calendar.

If on Mac OS' Calendar app I add some invitees and right click Mail Event it goes as .ics file but there's no option natively on the email clients I tested to reply that (Accept, Decline, Tentative, Propose New Time).

I initially did a small iCal library to handle events (mostly meetings) from one software that I develop/maintain, and it was being handled as a subscribed calendar (not CalDAV, just plain iCalendar format), with REST API and a simple frontend to change invitee's statuses but it was getting big responses, taking longer to update, etc.

Then I decided to find a native solution and I came to sabre/dav and a few other libraries, but I couldn't find enough reading material in any library (or RFCs) to describe the process of Scheduling an event and how "replying" to that would work.

Closest to what I got was just displaying the event, but the user has no option to Confirm presence.

Screen Shot 2021-02-03 at 1 10 45 PM

Any suggestions on how to implement that?

@evert
Copy link
Member

evert commented Feb 3, 2021

@icaroscherma please don't hijack this bug report. This is off-topic.

You need IMIP: https://tools.ietf.org/html/rfc6047

@pk1234
Copy link
Author

pk1234 commented Feb 20, 2022

Hi everybody,

an external organizer does not get a reply if an attendee accepts his invitation. I temporarily fixed that in our 3.2.2 SabreDAV installation (see above) and the 2020-plan was to fix it in version 4 as well.

Now its 2022, we migrated to SabreDAV 4.3.1 and the problem is still there.

It seems obvious to me that an external organizer should receive a reply if an attendee accepts his invitation. In that case processICalendarChange() is called with $oldObject===null (unless my dirty hack is used)

Do we agree, that this is a BUG? Or should I do some RFC-reading first to find out whether this is a bug or not?

Peter

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

No branches or pull requests

5 participants