Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions apps/dav/lib/CalDAV/Schedule/IMipPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,10 @@ public function schedule(Message $iTipMessage) {
$iTipMessage->scheduleStatus = '5.0; EMail delivery failed';
return;
}
// Don't send emails to things
if ($this->imipService->isRoomOrResource($attendee)) {
$this->logger->debug('No invitation sent as recipient is room or resource', [
// Don't send emails to rooms, resources and circles
if ($this->imipService->isRoomOrResource($attendee)
|| $this->imipService->isCircle($attendee)) {
$this->logger->debug('No invitation sent as recipient is room, resource or circle', [
'attendee' => $recipient,
]);
$iTipMessage->scheduleStatus = '1.0;We got the message, but it\'s not significant enough to warrant an email';
Expand Down
15 changes: 15 additions & 0 deletions apps/dav/lib/CalDAV/Schedule/IMipService.php
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,21 @@ public function isRoomOrResource(Property $attendee): bool {
return false;
}

public function isCircle(Property $attendee): bool {
$cuType = $attendee->offsetGet('CUTYPE');
if (!$cuType instanceof Parameter) {
return false;
}

$uri = $attendee->getValue();
if (!$uri) {
return false;
}

$cuTypeValue = $cuType->getValue();
return $cuTypeValue === 'GROUP' && str_starts_with($uri, 'mailto:circle+');
}

public function minimizeInterval(\DateInterval $dateInterval): array {
// evaluate if time interval is in the past
if ($dateInterval->invert == 1) {
Expand Down
110 changes: 110 additions & 0 deletions apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,10 @@ public function testParsingSingle(): void {
->method('isRoomOrResource')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('isCircle')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('buildBodyData')
->with($newVevent, $oldVEvent)
Expand Down Expand Up @@ -321,6 +325,88 @@ public function testAttendeeIsResource(): void {
->method('isRoomOrResource')
->with($room)
->willReturn(true);
$this->service->expects(self::never())
->method('isCircle');
$this->service->expects(self::never())
->method('buildBodyData');
$this->user->expects(self::any())
->method('getUID')
->willReturn('user1');
$this->user->expects(self::any())
->method('getDisplayName')
->willReturn('Mr. Wizard');
$this->userSession->expects(self::any())
->method('getUser')
->willReturn($this->user);
$this->service->expects(self::never())
->method('getFrom');
$this->service->expects(self::never())
->method('addSubjectAndHeading');
$this->service->expects(self::never())
->method('addBulletList');
$this->service->expects(self::never())
->method('getAttendeeRsvpOrReqForParticipant');
$this->config->expects(self::never())
->method('getValueString');
$this->service->expects(self::never())
->method('createInvitationToken');
$this->service->expects(self::never())
->method('addResponseButtons');
$this->service->expects(self::never())
->method('addMoreOptionsButton');
$this->mailer->expects(self::never())
->method('send');
$this->plugin->schedule($message);
$this->assertEquals('1.0', $message->getScheduleStatus());
}

public function testAttendeeIsCircle(): void {
$message = new Message();
$message->method = 'REQUEST';
$newVCalendar = new VCalendar();
$newVevent = new VEvent($newVCalendar, 'one', array_merge([
'UID' => 'uid-1234',
'SEQUENCE' => 1,
'SUMMARY' => 'Fellowship meeting without (!) Boromir',
'DTSTART' => new \DateTime('2016-01-01 00:00:00')
], []));
$newVevent->add('ORGANIZER', 'mailto:gandalf@wiz.ard');
$newVevent->add('ATTENDEE', 'mailto:' . 'circle+82utEV1Fle8wvxndZLK5TVAPtxj8IIe@middle.earth', ['RSVP' => 'TRUE', 'CN' => 'The Fellowship', 'CUTYPE' => 'GROUP']);
$newVevent->add('ATTENDEE', 'mailto:' . 'boromir@tra.it.or', ['RSVP' => 'TRUE', 'MEMBER' => 'circle+82utEV1Fle8wvxndZLK5TVAPtxj8IIe@middle.earth']);
$message->message = $newVCalendar;
$message->sender = 'mailto:gandalf@wiz.ard';
$message->senderName = 'Mr. Wizard';
$message->recipient = 'mailto:' . 'circle+82utEV1Fle8wvxndZLK5TVAPtxj8IIe@middle.earth';
$attendees = $newVevent->select('ATTENDEE');
$circle = '';
foreach ($attendees as $attendee) {
if (strcasecmp($attendee->getValue(), $message->recipient) === 0) {
$circle = $attendee;
}
}
$this->assertNotEmpty($circle, 'Failed to find attendee belonging to the circle');
$this->service->expects(self::once())
->method('getLastOccurrence')
->willReturn(1496912700);
$this->mailer->expects(self::once())
->method('validateMailAddress')
->with('circle+82utEV1Fle8wvxndZLK5TVAPtxj8IIe@middle.earth')
->willReturn(true);
$this->eventComparisonService->expects(self::once())
->method('findModified')
->willReturn(['new' => [$newVevent], 'old' => null]);
$this->service->expects(self::once())
->method('getCurrentAttendee')
->with($message)
->willReturn($circle);
$this->service->expects(self::once())
->method('isRoomOrResource')
->with($circle)
->willReturn(false);
$this->service->expects(self::once())
->method('isCircle')
->with($circle)
->willReturn(true);
$this->service->expects(self::never())
->method('buildBodyData');
$this->user->expects(self::any())
Expand Down Expand Up @@ -422,6 +508,10 @@ public function testParsingRecurrence(): void {
->method('isRoomOrResource')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('isCircle')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('buildBodyData')
->with($newVevent, null)
Expand Down Expand Up @@ -553,6 +643,10 @@ public function testFailedDelivery(): void {
->method('isRoomOrResource')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('isCircle')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('buildBodyData')
->with($newVevent, null)
Expand Down Expand Up @@ -659,6 +753,10 @@ public function testMailProviderSend(): void {
->method('isRoomOrResource')
->with($attendee)
->willReturn(false);
$this->service->expects(self::once())
->method('isCircle')
->with($attendee)
->willReturn(false);
$this->service->expects(self::once())
->method('buildBodyData')
->with($event, null)
Expand Down Expand Up @@ -766,6 +864,10 @@ public function testMailProviderDisabled(): void {
->method('isRoomOrResource')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('isCircle')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('buildBodyData')
->with($newVevent, $oldVEvent)
Expand Down Expand Up @@ -861,6 +963,10 @@ public function testNoOldEvent(): void {
->method('isRoomOrResource')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('isCircle')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('buildBodyData')
->with($newVevent, null)
Expand Down Expand Up @@ -954,6 +1060,10 @@ public function testNoButtons(): void {
->method('isRoomOrResource')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('isCircle')
->with($atnd)
->willReturn(false);
$this->service->expects(self::once())
->method('buildBodyData')
->with($newVevent, null)
Expand Down
Loading