diff --git a/patches/015-email-mail-template.patch b/patches/015-email-mail-template.patch index 94663d39795f6035e19f7e083a54b6df6b2cb50f..039ee020c004d8de472a6960a660d4c862e16316 100644 --- a/patches/015-email-mail-template.patch +++ b/patches/015-email-mail-template.patch @@ -1,6 +1,44 @@ +From: Avinash +Date: Friday, 17 May 2024 19:45:00 +0530 +Subject: [PATCH] In the invitation modifying a recurring event highlight whether the modification is for one occurrence or all future occurrences + + +This patch helps in indentifying that For a recurring event, the invitee knows without a doubt whether the modification pushed by the updated invitation is a one time thing or a modification of all future events. + --- ./apps/dav/lib/CalDAV/Schedule/IMipPlugin.php 2024-03-18 11:18:20 +++ ./apps/dav/lib/CalDAV/Schedule/IMipPlugin-new.php 2024-03-11 11:18:22 -@@ -242,6 +242,13 @@ +@@ -174,7 +174,29 @@ + /** @var VEvent $oldVevent */ + $oldVevent = !empty($modified['old']) && is_array($modified['old']) ? array_pop($modified['old']) : null; + $isModified = isset($oldVevent); +- ++ $recurrenceId = $vEvent->{'RECURRENCE-ID'}; ++ if (isset($recurrenceId) && $modified['sentOld'] === 1 && !empty($oldVevent)) { ++ $dateTime = $recurrenceId->getValue(); ++ $recurrenceArray = explode('T', $dateTime); ++ ++ $oldVEventStart = $oldVevent->DTSTART; ++ $oldStartDateTime = $oldVEventStart->getValue(); ++ $startDateTimeArray = explode('T', $oldStartDateTime); ++ $finalStartTime = $recurrenceArray[0] . 'T' . $startDateTimeArray[1]; ++ ++ $timeZoneId = (string) $recurrenceId['TZID']; ++ $oldVevent->DTSTART->setDateTime( ++ new \DateTime($finalStartTime, new \DateTimeZone($timeZoneId)) ++ ); ++ ++ $oldVEventEnd = $oldVevent->DTEND; ++ $oldEndDateTime = $oldVEventEnd->getValue(); ++ $endDateTimeArray = explode('T', $oldEndDateTime); ++ $finalEndTime = $recurrenceArray[0] . 'T' . $endDateTimeArray[1]; ++ $oldVevent->DTEND->setDateTime( ++ new \DateTime($finalEndTime, new \DateTimeZone($timeZoneId)) ++ ); ++ } + // No changed events after all - this shouldn't happen if there is significant change yet here we are + // The scheduling status is debatable + if(empty($vEvent)) { +@@ -242,6 +266,13 @@ $data['invitee_name'] = ($senderName ?: $sender); $fromEMail = Util::getDefaultEmailAddress('invitations-noreply'); @@ -14,7 +52,7 @@ $fromName = $this->imipService->getFrom($senderName, $this->defaults->getName()); $message = $this->mailer->createMessage() -@@ -262,7 +269,22 @@ +@@ -262,7 +293,22 @@ $template = $this->mailer->createEMailTemplate('dav.calendarInvite.' . $method, $data); $template->addHeader(); @@ -32,13 +70,13 @@ + $template->addHeadingBanner('#EFFFDB','#293618',$l10n->t('This recurring event has been updated, please review the information below:')); + } + $sequence = $vEvent->SEQUENCE ? $vEvent->SEQUENCE->getValue() : NULL; -+ if ($sequence && $method !== self::METHOD_CANCEL && $method !== self::METHOD_REPLY && count($vEvent)==1 && ($sequence > 2)) { ++ if (($sequence && $method !== self::METHOD_CANCEL && $method !== self::METHOD_REPLY && ($sequence > 2)) || isset($vEvent->{'RECURRENCE-ID'})) { + $template->addHeadingBanner('#EFFFDB','#293618',$l10n->t('This event has been updated, please review the information below:')); + } $this->imipService->addBulletList($template, $vEvent, $data); // Only add response buttons to invitation requests: Fix Issue #11230 -@@ -295,7 +317,6 @@ +@@ -295,7 +341,6 @@ || in_array(strtolower($recipientDomain), $invitationLinkRecipients)) { $token = $this->imipService->createInvitationToken($iTipMessage, $vEvent, $lastOccurrence); $this->imipService->addResponseButtons($template, $token); @@ -46,10 +84,42 @@ } } - --- ./apps/dav/lib/CalDAV/Schedule/IMipService.php 2024-03-18 11:40:39 +++ ./apps/dav/lib/CalDAV/Schedule/IMipService-new.php 2024-03-18 13:47:17 -@@ -444,6 +444,51 @@ +@@ -169,10 +169,30 @@ + $oldUrl = self::readPropertyWithDefault($oldVEvent, 'URL', $defaultVal); + $data['meeting_url_html'] = !empty($oldUrl) && $oldUrl !== $data['meeting_url'] ? sprintf('%1$s', $oldUrl) : $data['meeting_url']; + +- $data['meeting_when_html'] = ++ if(isset($vEvent->RRULE)){ ++ $RRule= (string) $vEvent->RRULE->getValue(); ++ if (strpos($RRule, 'FREQ=DAILY') !== false) { ++ $timeTitle = $this->l10n->t('Repeats daily:'); ++ } ++ if (strpos($RRule, 'FREQ=WEEKLY') !== false) { ++ $timeTitle = $this->l10n->t('Repeats weekly:'); ++ } ++ if (strpos($RRule, 'FREQ=MONTHLY') !== false) { ++ $timeTitle = $this->l10n->t('Repeats monthly:'); ++ } ++ if (strpos($RRule, 'FREQ=YEARLY') !== false) { ++ $timeTitle = $this->l10n->t('Repeats yearly:'); ++ } ++ $data['meeting_when_html'] = + ($oldMeetingWhen !== $data['meeting_when'] && $oldMeetingWhen !== null) +- ? sprintf("%s
%s", $oldMeetingWhen, $data['meeting_when']) ++ ? sprintf("%s
%s %s", $oldMeetingWhen,$timeTitle, $data['meeting_when']) ++ : $data['meeting_when']; ++ } else { ++ $data['meeting_when_html'] = ++ ($oldMeetingWhen !== $data['meeting_when'] && $oldMeetingWhen !== null) ++ ? sprintf("%s
%s %s", $oldMeetingWhen, $this->l10n->t('Time:'),$data['meeting_when']) + : $data['meeting_when']; ++ } + } + return $data; + } +@@ -444,6 +464,51 @@ } /** @@ -101,8 +171,31 @@ * @param string $path * @return string */ -@@ -541,8 +586,14 @@ +@@ -537,12 +602,36 @@ + $data['meeting_title_html'] ?? $data['meeting_title'], $this->l10n->t('Title:'), + $this->getAbsoluteImagePath('caldav/title.png'), $data['meeting_title'], '', IMipPlugin::IMIP_INDENT); + if ($data['meeting_when'] !== '') { +- $template->addBodyListItem($data['meeting_when_html'] ?? $data['meeting_when'], $this->l10n->t('Time:'), ++ if(isset($vevent->RRULE)){ ++ $RRule=(string) $vevent->RRULE->getValue(); ++ if (strpos($RRule, 'FREQ=DAILY') !== false) { ++ $timeTitle = $this->l10n->t('Repeats daily:'); ++ } ++ if (strpos($RRule, 'FREQ=WEEKLY') !== false) { ++ $timeTitle = $this->l10n->t('Repeats weekly:'); ++ } ++ if (strpos($RRule, 'FREQ=MONTHLY') !== false) { ++ $timeTitle = $this->l10n->t('Repeats monthly:'); ++ } ++ if (strpos($RRule, 'FREQ=YEARLY') !== false) { ++ $timeTitle = $this->l10n->t('Repeats yearly:'); ++ } ++ $template->addBodyListItem($data['meeting_when_html'] ?? $data['meeting_when'], $timeTitle, $this->getAbsoluteImagePath('caldav/time.png'), $data['meeting_when'], '', IMipPlugin::IMIP_INDENT); ++ } else { ++ $template->addBodyListItem($data['meeting_when_html'] ?? $data['meeting_when'], $this->l10n->t('Time:'), ++ $this->getAbsoluteImagePath('caldav/time.png'), $data['meeting_when'], '', IMipPlugin::IMIP_INDENT); ++ } } if ($data['meeting_location'] !== '') { - $template->addBodyListItem($data['meeting_location_html'] ?? $data['meeting_location'], $this->l10n->t('Location:'), @@ -118,7 +211,7 @@ } if ($data['meeting_url'] !== '') { $template->addBodyListItem($data['meeting_url_html'] ?? $data['meeting_url'], $this->l10n->t('Link:'), -@@ -637,7 +688,7 @@ +@@ -637,7 +726,7 @@ * @param $token */ public function addResponseButtons(IEMailTemplate $template, $token) { @@ -127,7 +220,7 @@ $this->l10n->t('Accept'), $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.accept', [ 'token' => $token, -@@ -645,20 +696,10 @@ +@@ -645,20 +734,10 @@ $this->l10n->t('Decline'), $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.decline', [ 'token' => $token, @@ -151,3 +244,39 @@ } public function getReplyingAttendee(Message $iTipMessage): ?Property { + +--- ./apps/dav/lib/CalDAV/EventComparisonService.php 2024-05-06 12:46:29 ++++ ./apps/dav/lib/CalDAV/EventComparisonService-new.php 2024-05-06 12:47:11 +@@ -100,11 +100,10 @@ + unset($newEventComponents[$k]); + } + } +- ++ $sentOld = 0; + if(empty($old)) { +- return ['old' => null, 'new' => $newEventComponents]; ++ return ['old' => null, 'new' => $newEventComponents, 'sentOld' => $sentOld]; + } +- + $oldEventComponents = $old->getComponents(); + if(is_array($oldEventComponents) && !empty($oldEventComponents)) { + foreach ($oldEventComponents as $k => $event) { +@@ -113,11 +112,15 @@ + continue; + } + if($this->removeIfUnchanged($event, $newEventComponents)) { +- unset($oldEventComponents[$k]); ++ if($k!=1){ ++ unset($oldEventComponents[$k]); ++ } else { ++ $sentOld = 1; ++ } + } + } + } + +- return ['old' => array_values($oldEventComponents), 'new' => array_values($newEventComponents)]; ++ return ['old' => array_values($oldEventComponents), 'new' => array_values($newEventComponents), 'sentOld' => $sentOld]; + } + } +\ No newline at end of file