Skip to content

Commit d61d62b

Browse files
authored
Merge pull request #48833 from nextcloud/fix/issue-48732-exdate-rdate-property-instances
fix: RDATE and EXDATE property instances
2 parents ca4be91 + de22119 commit d61d62b

File tree

4 files changed

+496
-48
lines changed

4 files changed

+496
-48
lines changed

apps/dav/lib/CalDAV/EventReader.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,12 @@ public function __construct(VCalendar|VEvent|array|string $input, ?string $uid =
200200
}
201201
// evaluate if RDATE exist and construct iterator
202202
if (isset($this->baseEvent->RDATE)) {
203+
$dates = [];
204+
foreach ($this->baseEvent->RDATE as $entry) {
205+
$dates[] = $entry->getValue();
206+
}
203207
$this->rdateIterator = new EventReaderRDate(
204-
$this->baseEvent->RDATE->getValue(),
208+
implode(',', $dates),
205209
$this->baseEventStartDate
206210
);
207211
}
@@ -214,8 +218,12 @@ public function __construct(VCalendar|VEvent|array|string $input, ?string $uid =
214218
}
215219
// evaluate if EXDATE exist and construct iterator
216220
if (isset($this->baseEvent->EXDATE)) {
221+
$dates = [];
222+
foreach ($this->baseEvent->EXDATE as $entry) {
223+
$dates[] = $entry->getValue();
224+
}
217225
$this->edateIterator = new EventReaderRDate(
218-
$this->baseEvent->EXDATE->getValue(),
226+
implode(',', $dates),
219227
$this->baseEventStartDate
220228
);
221229
}

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

Lines changed: 39 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ public function buildBodyData(VEvent $vEvent, ?VEvent $oldVEvent): array {
154154

155155
$data['meeting_when_html'] = $oldMeetingWhen !== $data['meeting_when'] ? sprintf("<span style='text-decoration: line-through'>%s</span><br />%s", $oldMeetingWhen, $data['meeting_when']) : $data['meeting_when'];
156156
}
157-
// generate occuring next string
157+
// generate occurring next string
158158
if ($eventReaderCurrent->recurs()) {
159159
$data['meeting_occurring'] = $this->generateOccurringString($eventReaderCurrent);
160160
}
@@ -163,7 +163,7 @@ public function buildBodyData(VEvent $vEvent, ?VEvent $oldVEvent): array {
163163
}
164164

165165
/**
166-
* genarates a when string based on if a event has an recurrence or not
166+
* generates a when string based on if a event has an recurrence or not
167167
*
168168
* @since 30.0.0
169169
*
@@ -179,7 +179,7 @@ public function generateWhenString(EventReader $er): string {
179179
}
180180

181181
/**
182-
* genarates a when string for a non recurring event
182+
* generates a when string for a non recurring event
183183
*
184184
* @since 30.0.0
185185
*
@@ -188,8 +188,8 @@ public function generateWhenString(EventReader $er): string {
188188
* @return string
189189
*/
190190
public function generateWhenStringSingular(EventReader $er): string {
191-
// calculate time differnce from now to start of event
192-
$occuring = $this->minimizeInterval($this->timeFactory->getDateTime()->diff($er->recurrenceDate()));
191+
// calculate time difference from now to start of event
192+
$occurring = $this->minimizeInterval($this->timeFactory->getDateTime()->diff($er->recurrenceDate()));
193193
// extract start date
194194
$startDate = $this->l10n->l('date', $er->startDateTime(), ['width' => 'full']);
195195
// time of the day
@@ -204,19 +204,19 @@ public function generateWhenStringSingular(EventReader $er): string {
204204
// Output produced in order:
205205
// In a day/week/month/year on July 1, 2024 for the entire day
206206
// In a day/week/month/year on July 1, 2024 between 8:00 AM - 9:00 AM (America/Toronto)
207-
// In 2 days/weeks/monthss/years on July 1, 2024 for the entire day
208-
// In 2 days/weeks/monthss/years on July 1, 2024 between 8:00 AM - 9:00 AM (America/Toronto)
209-
return match ([($occuring[0] > 1), !empty($endTime)]) {
210-
[false, false] => $this->l10n->t('In a %1$s on %2$s for the entire day', [$occuring[1], $startDate]),
211-
[false, true] => $this->l10n->t('In a %1$s on %2$s between %3$s - %4$s', [$occuring[1], $startDate, $startTime, $endTime]),
212-
[true, false] => $this->l10n->t('In %1$s %2$s on %3$s for the entire day', [$occuring[0], $occuring[1], $startDate]),
213-
[true, true] => $this->l10n->t('In %1$s %2$s on %3$s between %4$s - %5$s', [$occuring[0], $occuring[1], $startDate, $startTime, $endTime]),
207+
// In 2 days/weeks/months/years on July 1, 2024 for the entire day
208+
// In 2 days/weeks/months/years on July 1, 2024 between 8:00 AM - 9:00 AM (America/Toronto)
209+
return match ([($occurring[0] > 1), !empty($endTime)]) {
210+
[false, false] => $this->l10n->t('In a %1$s on %2$s for the entire day', [$occurring[1], $startDate]),
211+
[false, true] => $this->l10n->t('In a %1$s on %2$s between %3$s - %4$s', [$occurring[1], $startDate, $startTime, $endTime]),
212+
[true, false] => $this->l10n->t('In %1$s %2$s on %3$s for the entire day', [$occurring[0], $occurring[1], $startDate]),
213+
[true, true] => $this->l10n->t('In %1$s %2$s on %3$s between %4$s - %5$s', [$occurring[0], $occurring[1], $startDate, $startTime, $endTime]),
214214
default => $this->l10n->t('Could not generate when statement')
215215
};
216216
}
217217

218218
/**
219-
* genarates a when string based on recurrance precision/frequency
219+
* generates a when string based on recurrence precision/frequency
220220
*
221221
* @since 30.0.0
222222
*
@@ -235,7 +235,7 @@ public function generateWhenStringRecurring(EventReader $er): string {
235235
}
236236

237237
/**
238-
* genarates a when string for a daily precision/frequency
238+
* generates a when string for a daily precision/frequency
239239
*
240240
* @since 30.0.0
241241
*
@@ -287,7 +287,7 @@ public function generateWhenStringRecurringDaily(EventReader $er): string {
287287
}
288288

289289
/**
290-
* genarates a when string for a weekly precision/frequency
290+
* generates a when string for a weekly precision/frequency
291291
*
292292
* @since 30.0.0
293293
*
@@ -341,7 +341,7 @@ public function generateWhenStringRecurringWeekly(EventReader $er): string {
341341
}
342342

343343
/**
344-
* genarates a when string for a monthly precision/frequency
344+
* generates a when string for a monthly precision/frequency
345345
*
346346
* @since 30.0.0
347347
*
@@ -407,7 +407,7 @@ public function generateWhenStringRecurringMonthly(EventReader $er): string {
407407
}
408408

409409
/**
410-
* genarates a when string for a yearly precision/frequency
410+
* generates a when string for a yearly precision/frequency
411411
*
412412
* @since 30.0.0
413413
*
@@ -475,7 +475,7 @@ public function generateWhenStringRecurringYearly(EventReader $er): string {
475475
}
476476

477477
/**
478-
* genarates a when string for a fixed precision/frequency
478+
* generates a when string for a fixed precision/frequency
479479
*
480480
* @since 30.0.0
481481
*
@@ -509,7 +509,7 @@ public function generateWhenStringRecurringFixed(EventReader $er): string {
509509
}
510510

511511
/**
512-
* genarates a occurring next string for a recurring event
512+
* generates a occurring next string for a recurring event
513513
*
514514
* @since 30.0.0
515515
*
@@ -519,26 +519,26 @@ public function generateWhenStringRecurringFixed(EventReader $er): string {
519519
*/
520520
public function generateOccurringString(EventReader $er): string {
521521

522-
// reset to initial occurance
522+
// reset to initial occurrence
523523
$er->recurrenceRewind();
524524
// forward to current date
525525
$er->recurrenceAdvanceTo($this->timeFactory->getDateTime());
526-
// calculate time differnce from now to start of next event occurance and minimize it
527-
$occuranceIn = $this->minimizeInterval($this->timeFactory->getDateTime()->diff($er->recurrenceDate()));
528-
// store next occurance value
529-
$occurance = $this->l10n->l('date', $er->recurrenceDate(), ['width' => 'long']);
530-
// forward one occurance
526+
// calculate time difference from now to start of next event occurrence and minimize it
527+
$occurrenceIn = $this->minimizeInterval($this->timeFactory->getDateTime()->diff($er->recurrenceDate()));
528+
// store next occurrence value
529+
$occurrence = $this->l10n->l('date', $er->recurrenceDate(), ['width' => 'long']);
530+
// forward one occurrence
531531
$er->recurrenceAdvance();
532-
// evaluate if occurance is valid
532+
// evaluate if occurrence is valid
533533
if ($er->recurrenceDate() !== null) {
534-
// store following occurance value
535-
$occurance2 = $this->l10n->l('date', $er->recurrenceDate(), ['width' => 'long']);
536-
// forward one occurance
534+
// store following occurrence value
535+
$occurrence2 = $this->l10n->l('date', $er->recurrenceDate(), ['width' => 'long']);
536+
// forward one occurrence
537537
$er->recurrenceAdvance();
538-
// evaluate if occurance is valid
538+
// evaluate if occurrence is valid
539539
if ($er->recurrenceDate()) {
540-
// store following occurance value
541-
$occurance3 = $this->l10n->l('date', $er->recurrenceDate(), ['width' => 'long']);
540+
// store following occurrence value
541+
$occurrence3 = $this->l10n->l('date', $er->recurrenceDate(), ['width' => 'long']);
542542
}
543543
}
544544
// generate localized when string
@@ -551,13 +551,13 @@ public function generateOccurringString(EventReader $er): string {
551551
// In 2 days/weeks/months/years on July 1, 2024
552552
// In 2 days/weeks/months/years on July 1, 2024 then on July 3, 2024
553553
// In 2 days/weeks/months/years on July 1, 2024 then on July 3, 2024 and July 5, 2024
554-
return match ([($occuranceIn[0] > 1), !empty($occurance2), !empty($occurance3)]) {
555-
[false, false, false] => $this->l10n->t('In a %1$s on %2$s', [$occuranceIn[1], $occurance]),
556-
[false, true, false] => $this->l10n->t('In a %1$s on %2$s then on %3$s', [$occuranceIn[1], $occurance, $occurance2]),
557-
[false, true, true] => $this->l10n->t('In a %1$s on %2$s then on %3$s and %4$s', [$occuranceIn[1], $occurance, $occurance2, $occurance3]),
558-
[true, false, false] => $this->l10n->t('In %1$s %2$s on %3$s', [$occuranceIn[0], $occuranceIn[1], $occurance]),
559-
[true, true, false] => $this->l10n->t('In %1$s %2$s on %3$s then on %4$s', [$occuranceIn[0], $occuranceIn[1], $occurance, $occurance2]),
560-
[true, true, true] => $this->l10n->t('In %1$s %2$s on %3$s then on %4$s and %5$s', [$occuranceIn[0], $occuranceIn[1], $occurance, $occurance2, $occurance3]),
554+
return match ([($occurrenceIn[0] > 1), !empty($occurrence2), !empty($occurrence3)]) {
555+
[false, false, false] => $this->l10n->t('In a %1$s on %2$s', [$occurrenceIn[1], $occurrence]),
556+
[false, true, false] => $this->l10n->t('In a %1$s on %2$s then on %3$s', [$occurrenceIn[1], $occurrence, $occurrence2]),
557+
[false, true, true] => $this->l10n->t('In a %1$s on %2$s then on %3$s and %4$s', [$occurrenceIn[1], $occurrence, $occurrence2, $occurrence3]),
558+
[true, false, false] => $this->l10n->t('In %1$s %2$s on %3$s', [$occurrenceIn[0], $occurrenceIn[1], $occurrence]),
559+
[true, true, false] => $this->l10n->t('In %1$s %2$s on %3$s then on %4$s', [$occurrenceIn[0], $occurrenceIn[1], $occurrence, $occurrence2]),
560+
[true, true, true] => $this->l10n->t('In %1$s %2$s on %3$s then on %4$s and %5$s', [$occurrenceIn[0], $occurrenceIn[1], $occurrence, $occurrence2, $occurrence3]),
561561
default => $this->l10n->t('Could not generate next recurrence statement')
562562
};
563563

apps/dav/tests/unit/CalDAV/EventReaderTest.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,15 @@ public function testRecurringConcludes(): void {
533533
// test set by constructor
534534
$this->assertTrue($er->recurringConcludes());
535535

536+
/** test rdate (multiple property instances) recurrance */
537+
$vCalendar = clone $this->vCalendar1a;
538+
$vCalendar->VEVENT[0]->add('RDATE', '20240703');
539+
$vCalendar->VEVENT[0]->add('RDATE', '20240705');
540+
// construct event reader
541+
$er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
542+
// test set by constructor
543+
$this->assertTrue($er->recurringConcludes());
544+
536545
/** test rrule and rdate recurrance with rdate as last date */
537546
$vCalendar = clone $this->vCalendar1a;
538547
$vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
@@ -578,6 +587,15 @@ public function testRecurringConcludesAfter(): void {
578587
// test set by constructor
579588
$this->assertEquals(2, $er->recurringConcludesAfter());
580589

590+
/** test rdate (multiple property instances) recurrance */
591+
$vCalendar = clone $this->vCalendar1a;
592+
$vCalendar->VEVENT[0]->add('RDATE', '20240703');
593+
$vCalendar->VEVENT[0]->add('RDATE', '20240705');
594+
// construct event reader
595+
$er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
596+
// test set by constructor
597+
$this->assertEquals(2, $er->recurringConcludesAfter());
598+
581599
/** test rrule and rdate recurrance */
582600
$vCalendar = clone $this->vCalendar1a;
583601
$vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');
@@ -624,6 +642,15 @@ public function testRecurringConcludesOn(): void {
624642
// test set by constructor
625643
$this->assertEquals((new \DateTime('20240705T000000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
626644

645+
/** test rdate (multiple property instances) recurrance */
646+
$vCalendar = clone $this->vCalendar1a;
647+
$vCalendar->VEVENT[0]->add('RDATE', '20240703');
648+
$vCalendar->VEVENT[0]->add('RDATE', '20240705');
649+
// construct event reader
650+
$er = new EventReader($vCalendar, $vCalendar->VEVENT[0]->UID->getValue());
651+
// test set by constructor
652+
$this->assertEquals((new \DateTime('20240705T000000', (new DateTimeZone('America/Toronto')))), $er->recurringConcludesOn());
653+
627654
/** test rrule and rdate recurrance with rdate as last date */
628655
$vCalendar = clone $this->vCalendar1a;
629656
$vCalendar->VEVENT[0]->add('RRULE', 'FREQ=WEEKLY;COUNT=6;BYDAY=MO,WE,FR');

0 commit comments

Comments
 (0)