Skip to content

Commit 1f780ce

Browse files
st3inyAndyScherzinger
authored andcommitted
fix(caldav): don't send invitations to circles
Signed-off-by: Richard Steinmetz <richard@steinmetz.cloud>
1 parent 5466489 commit 1f780ce

File tree

3 files changed

+129
-3
lines changed

3 files changed

+129
-3
lines changed

apps/dav/lib/CalDAV/Schedule/IMipPlugin.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -170,9 +170,10 @@ public function schedule(Message $iTipMessage) {
170170
$iTipMessage->scheduleStatus = '5.0; EMail delivery failed';
171171
return;
172172
}
173-
// Don't send emails to things
174-
if ($this->imipService->isRoomOrResource($attendee)) {
175-
$this->logger->debug('No invitation sent as recipient is room or resource', [
173+
// Don't send emails to rooms, resources and circles
174+
if ($this->imipService->isRoomOrResource($attendee)
175+
|| $this->imipService->isCircle($attendee)) {
176+
$this->logger->debug('No invitation sent as recipient is room, resource or circle', [
176177
'attendee' => $recipient,
177178
]);
178179
$iTipMessage->scheduleStatus = '1.0;We got the message, but it\'s not significant enough to warrant an email';

apps/dav/lib/CalDAV/Schedule/IMipService.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,21 @@ public function isRoomOrResource(Property $attendee): bool {
11651165
return false;
11661166
}
11671167

1168+
public function isCircle(Property $attendee): bool {
1169+
$cuType = $attendee->offsetGet('CUTYPE');
1170+
if (!$cuType instanceof Parameter) {
1171+
return false;
1172+
}
1173+
1174+
$uri = $attendee->getValue();
1175+
if (!$uri) {
1176+
return false;
1177+
}
1178+
1179+
$cuTypeValue = $cuType->getValue();
1180+
return $cuTypeValue === 'GROUP' && str_starts_with($uri, 'mailto:circle+');
1181+
}
1182+
11681183
public function minimizeInterval(\DateInterval $dateInterval): array {
11691184
// evaluate if time interval is in the past
11701185
if ($dateInterval->invert == 1) {

apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ public function testParsingSingle(): void {
219219
->method('isRoomOrResource')
220220
->with($atnd)
221221
->willReturn(false);
222+
$this->service->expects(self::once())
223+
->method('isCircle')
224+
->with($atnd)
225+
->willReturn(false);
222226
$this->service->expects(self::once())
223227
->method('buildBodyData')
224228
->with($newVevent, $oldVEvent)
@@ -322,6 +326,88 @@ public function testAttendeeIsResource(): void {
322326
->method('isRoomOrResource')
323327
->with($room)
324328
->willReturn(true);
329+
$this->service->expects(self::never())
330+
->method('isCircle');
331+
$this->service->expects(self::never())
332+
->method('buildBodyData');
333+
$this->user->expects(self::any())
334+
->method('getUID')
335+
->willReturn('user1');
336+
$this->user->expects(self::any())
337+
->method('getDisplayName')
338+
->willReturn('Mr. Wizard');
339+
$this->userSession->expects(self::any())
340+
->method('getUser')
341+
->willReturn($this->user);
342+
$this->service->expects(self::never())
343+
->method('getFrom');
344+
$this->service->expects(self::never())
345+
->method('addSubjectAndHeading');
346+
$this->service->expects(self::never())
347+
->method('addBulletList');
348+
$this->service->expects(self::never())
349+
->method('getAttendeeRsvpOrReqForParticipant');
350+
$this->config->expects(self::never())
351+
->method('getValueString');
352+
$this->service->expects(self::never())
353+
->method('createInvitationToken');
354+
$this->service->expects(self::never())
355+
->method('addResponseButtons');
356+
$this->service->expects(self::never())
357+
->method('addMoreOptionsButton');
358+
$this->mailer->expects(self::never())
359+
->method('send');
360+
$this->plugin->schedule($message);
361+
$this->assertEquals('1.0', $message->getScheduleStatus());
362+
}
363+
364+
public function testAttendeeIsCircle(): void {
365+
$message = new Message();
366+
$message->method = 'REQUEST';
367+
$newVCalendar = new VCalendar();
368+
$newVevent = new VEvent($newVCalendar, 'one', array_merge([
369+
'UID' => 'uid-1234',
370+
'SEQUENCE' => 1,
371+
'SUMMARY' => 'Fellowship meeting without (!) Boromir',
372+
'DTSTART' => new \DateTime('2016-01-01 00:00:00')
373+
], []));
374+
$newVevent->add('ORGANIZER', 'mailto:gandalf@wiz.ard');
375+
$newVevent->add('ATTENDEE', 'mailto:' . 'circle+82utEV1Fle8wvxndZLK5TVAPtxj8IIe@middle.earth', ['RSVP' => 'TRUE', 'CN' => 'The Fellowship', 'CUTYPE' => 'GROUP']);
376+
$newVevent->add('ATTENDEE', 'mailto:' . 'boromir@tra.it.or', ['RSVP' => 'TRUE', 'MEMBER' => 'circle+82utEV1Fle8wvxndZLK5TVAPtxj8IIe@middle.earth']);
377+
$message->message = $newVCalendar;
378+
$message->sender = 'mailto:gandalf@wiz.ard';
379+
$message->senderName = 'Mr. Wizard';
380+
$message->recipient = 'mailto:' . 'circle+82utEV1Fle8wvxndZLK5TVAPtxj8IIe@middle.earth';
381+
$attendees = $newVevent->select('ATTENDEE');
382+
$circle = '';
383+
foreach ($attendees as $attendee) {
384+
if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
385+
$circle = $attendee;
386+
}
387+
}
388+
$this->assertNotEmpty($circle, 'Failed to find attendee belonging to the circle');
389+
$this->service->expects(self::once())
390+
->method('getLastOccurrence')
391+
->willReturn(1496912700);
392+
$this->mailer->expects(self::once())
393+
->method('validateMailAddress')
394+
->with('circle+82utEV1Fle8wvxndZLK5TVAPtxj8IIe@middle.earth')
395+
->willReturn(true);
396+
$this->eventComparisonService->expects(self::once())
397+
->method('findModified')
398+
->willReturn(['new' => [$newVevent], 'old' => null]);
399+
$this->service->expects(self::once())
400+
->method('getCurrentAttendee')
401+
->with($message)
402+
->willReturn($circle);
403+
$this->service->expects(self::once())
404+
->method('isRoomOrResource')
405+
->with($circle)
406+
->willReturn(false);
407+
$this->service->expects(self::once())
408+
->method('isCircle')
409+
->with($circle)
410+
->willReturn(true);
325411
$this->service->expects(self::never())
326412
->method('buildBodyData');
327413
$this->user->expects(self::any())
@@ -423,6 +509,10 @@ public function testParsingRecurrence(): void {
423509
->method('isRoomOrResource')
424510
->with($atnd)
425511
->willReturn(false);
512+
$this->service->expects(self::once())
513+
->method('isCircle')
514+
->with($atnd)
515+
->willReturn(false);
426516
$this->service->expects(self::once())
427517
->method('buildBodyData')
428518
->with($newVevent, null)
@@ -554,6 +644,10 @@ public function testFailedDelivery(): void {
554644
->method('isRoomOrResource')
555645
->with($atnd)
556646
->willReturn(false);
647+
$this->service->expects(self::once())
648+
->method('isCircle')
649+
->with($atnd)
650+
->willReturn(false);
557651
$this->service->expects(self::once())
558652
->method('buildBodyData')
559653
->with($newVevent, null)
@@ -660,6 +754,10 @@ public function testMailProviderSend(): void {
660754
->method('isRoomOrResource')
661755
->with($attendee)
662756
->willReturn(false);
757+
$this->service->expects(self::once())
758+
->method('isCircle')
759+
->with($attendee)
760+
->willReturn(false);
663761
$this->service->expects(self::once())
664762
->method('buildBodyData')
665763
->with($event, null)
@@ -767,6 +865,10 @@ public function testMailProviderDisabled(): void {
767865
->method('isRoomOrResource')
768866
->with($atnd)
769867
->willReturn(false);
868+
$this->service->expects(self::once())
869+
->method('isCircle')
870+
->with($atnd)
871+
->willReturn(false);
770872
$this->service->expects(self::once())
771873
->method('buildBodyData')
772874
->with($newVevent, $oldVEvent)
@@ -862,6 +964,10 @@ public function testNoOldEvent(): void {
862964
->method('isRoomOrResource')
863965
->with($atnd)
864966
->willReturn(false);
967+
$this->service->expects(self::once())
968+
->method('isCircle')
969+
->with($atnd)
970+
->willReturn(false);
865971
$this->service->expects(self::once())
866972
->method('buildBodyData')
867973
->with($newVevent, null)
@@ -955,6 +1061,10 @@ public function testNoButtons(): void {
9551061
->method('isRoomOrResource')
9561062
->with($atnd)
9571063
->willReturn(false);
1064+
$this->service->expects(self::once())
1065+
->method('isCircle')
1066+
->with($atnd)
1067+
->willReturn(false);
9581068
$this->service->expects(self::once())
9591069
->method('buildBodyData')
9601070
->with($newVevent, null)

0 commit comments

Comments
 (0)