diff options
author | John Molakvoæ <skjnldsv@users.noreply.github.com> | 2020-09-04 19:53:02 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-09-04 19:53:02 +0200 |
commit | 593d64d935cad2a3b4c039ba511f1a5a15c6b756 (patch) | |
tree | 9cec38f80392b55eebae4ad1c38cbcd3469423e0 /apps/dav/lib | |
parent | 5483d02b5e3ef8d20054d3d0332d82a8a3dbd5b0 (diff) | |
parent | 442af8c5d57797bf255db036c8c04ab48f36c3a1 (diff) | |
download | nextcloud-server-593d64d935cad2a3b4c039ba511f1a5a15c6b756.tar.gz nextcloud-server-593d64d935cad2a3b4c039ba511f1a5a15c6b756.zip |
Merge pull request #17456 from brad2014/feature/brad2014/12391-improve-imip-mail-message-take-2
Diffstat (limited to 'apps/dav/lib')
-rw-r--r-- | apps/dav/lib/CalDAV/Schedule/IMipPlugin.php | 186 |
1 files changed, 132 insertions, 54 deletions
diff --git a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php index 6358a3a0293..56517ab28c1 100644 --- a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php +++ b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php @@ -3,7 +3,6 @@ * @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright Copyright (c) 2017, Georg Ehrke * - * @author brad2014 <brad2014@users.noreply.github.com> * @author Brad Rubenstein <brad@wbr.tech> * @author Christoph Wurst <christoph@winzerhof-wurst.at> * @author Georg Ehrke <oc.list@georgehrke.com> @@ -108,6 +107,7 @@ class IMipPlugin extends SabreIMipPlugin { public const METHOD_REQUEST = 'request'; public const METHOD_REPLY = 'reply'; public const METHOD_CANCEL = 'cancel'; + public const IMIP_INDENT = 15; // Enough for the length of all body bullet items, in all languages /** * @param IConfig $config @@ -204,26 +204,6 @@ class IMipPlugin extends SabreIMipPlugin { $meetingTitle = $vevent->SUMMARY; $meetingDescription = $vevent->DESCRIPTION; - $start = $vevent->DTSTART; - if (isset($vevent->DTEND)) { - $end = $vevent->DTEND; - } elseif (isset($vevent->DURATION)) { - $isFloating = $vevent->DTSTART->isFloating(); - $end = clone $vevent->DTSTART; - $endDateTime = $end->getDateTime(); - $endDateTime = $endDateTime->add(DateTimeParser::parse($vevent->DURATION->getValue())); - $end->setDateTime($endDateTime, $isFloating); - } elseif (!$vevent->DTSTART->hasTime()) { - $isFloating = $vevent->DTSTART->isFloating(); - $end = clone $vevent->DTSTART; - $endDateTime = $end->getDateTime(); - $endDateTime = $endDateTime->modify('+1 day'); - $end->setDateTime($endDateTime, $isFloating); - } else { - $end = clone $vevent->DTSTART; - } - - $meetingWhen = $this->generateWhenString($l10n, $start, $end); $meetingUrl = $vevent->URL; $meetingLocation = $vevent->LOCATION; @@ -261,10 +241,8 @@ class IMipPlugin extends SabreIMipPlugin { $summary = ((string) $summary !== '') ? (string) $summary : $l10n->t('Untitled event'); - $this->addSubjectAndHeading($template, $l10n, $method, $summary, - $meetingAttendeeName, $meetingInviteeName); - $this->addBulletList($template, $l10n, $meetingWhen, $meetingLocation, - $meetingDescription, $meetingUrl); + $this->addSubjectAndHeading($template, $l10n, $method, $summary); + $this->addBulletList($template, $l10n, $vevent); // Only add response buttons to invitation requests: Fix Issue #11230 @@ -370,7 +348,6 @@ class IMipPlugin extends SabreIMipPlugin { return $lastOccurrence; } - /** * @param Message $iTipMessage * @return null|Property @@ -420,10 +397,28 @@ class IMipPlugin extends SabreIMipPlugin { /** * @param IL10N $l10n - * @param Property $dtstart - * @param Property $dtend + * @param VEvent $vevent */ - private function generateWhenString(IL10N $l10n, Property $dtstart, Property $dtend) { + private function generateWhenString(IL10N $l10n, VEvent $vevent) { + $dtstart = $vevent->DTSTART; + if (isset($vevent->DTEND)) { + $dtend = $vevent->DTEND; + } elseif (isset($vevent->DURATION)) { + $isFloating = $vevent->DTSTART->isFloating(); + $dtend = clone $vevent->DTSTART; + $endDateTime = $dtend->getDateTime(); + $endDateTime = $endDateTime->add(DateTimeParser::parse($vevent->DURATION->getValue())); + $dtend->setDateTime($endDateTime, $isFloating); + } elseif (!$vevent->DTSTART->hasTime()) { + $isFloating = $vevent->DTSTART->isFloating(); + $dtend = clone $vevent->DTSTART; + $endDateTime = $dtend->getDateTime(); + $endDateTime = $endDateTime->modify('+1 day'); + $dtend->setDateTime($endDateTime, $isFloating); + } else { + $dtend = clone $vevent->DTSTART; + } + $isAllDay = $dtstart instanceof Property\ICalendar\Date; /** @var Property\ICalendar\Date | Property\ICalendar\DateTime $dtstart */ @@ -507,49 +502,132 @@ class IMipPlugin extends SabreIMipPlugin { * @param IL10N $l10n * @param string $method * @param string $summary - * @param string $attendeeName - * @param string $inviteeName */ private function addSubjectAndHeading(IEMailTemplate $template, IL10N $l10n, - $method, $summary, $attendeeName, $inviteeName) { + $method, $summary) { if ($method === self::METHOD_CANCEL) { - $template->setSubject('Cancelled: ' . $summary); - $template->addHeading($l10n->t('Invitation canceled'), $l10n->t('Hello %s,', [$attendeeName])); - $template->addBodyText($l10n->t('The meeting »%1$s« with %2$s was canceled.', [$summary, $inviteeName])); + $template->setSubject('Canceled: ' . $summary); + $template->addHeading($l10n->t('Invitation canceled')); } elseif ($method === self::METHOD_REPLY) { $template->setSubject('Re: ' . $summary); - $template->addHeading($l10n->t('Invitation updated'), $l10n->t('Hello %s,', [$attendeeName])); - $template->addBodyText($l10n->t('The meeting »%1$s« with %2$s was updated.', [$summary, $inviteeName])); + $template->addHeading($l10n->t('Invitation updated')); } else { $template->setSubject('Invitation: ' . $summary); - $template->addHeading($l10n->t('%1$s invited you to »%2$s«', [$inviteeName, $summary]), $l10n->t('Hello %s,', [$attendeeName])); + $template->addHeading($l10n->t('Invitation')); + } + } + + /** + * @param IEMailTemplate $template + * @param IL10N $l10n + * @param VEVENT $vevent + */ + private function addBulletList(IEMailTemplate $template, IL10N $l10n, $vevent) { + if ($vevent->SUMMARY) { + $template->addBodyListItem($vevent->SUMMARY, $l10n->t('Title:'), + $this->getAbsoluteImagePath('caldav/title.svg'),'','',self::IMIP_INDENT); + } + $meetingWhen = $this->generateWhenString($l10n, $vevent); + if ($meetingWhen) { + $template->addBodyListItem($meetingWhen, $l10n->t('Time:'), + $this->getAbsoluteImagePath('caldav/time.svg'),'','',self::IMIP_INDENT); + } + if ($vevent->LOCATION) { + $template->addBodyListItem($vevent->LOCATION, $l10n->t('Location:'), + $this->getAbsoluteImagePath('caldav/location.svg'),'','',self::IMIP_INDENT); + } + if ($vevent->URL) { + $url = $vevent->URL->getValue(); + $template->addBodyListItem(sprintf('<a href="%s">%s</a>', + htmlspecialchars($url), + htmlspecialchars($url)), + $l10n->t('Link:'), + $this->getAbsoluteImagePath('caldav/link.svg'), + $url,'',self::IMIP_INDENT); + } + + $this->addAttendees($template, $l10n, $vevent); + + /* Put description last, like an email body, since it can be arbitrarily long */ + if ($vevent->DESCRIPTION) { + $template->addBodyListItem($vevent->DESCRIPTION->getValue(), $l10n->t('Description:'), + $this->getAbsoluteImagePath('caldav/description.svg'),'','',self::IMIP_INDENT); } } /** + * addAttendees: add organizer and attendee names/emails to iMip mail. + * + * Enable with DAV setting: invitation_list_attendees (default: no) + * + * The default is 'no', which matches old behavior, and is privacy preserving. + * + * To enable including attendees in invitation emails: + * % php occ config:app:set dav invitation_list_attendees --value yes + * * @param IEMailTemplate $template * @param IL10N $l10n - * @param string $time - * @param string $location - * @param string $description - * @param string $url + * @param Message $iTipMessage + * @param int $lastOccurrence + * @author brad2014 on github.com */ - private function addBulletList(IEMailTemplate $template, IL10N $l10n, $time, $location, $description, $url) { - $template->addBodyListItem($time, $l10n->t('When:'), - $this->getAbsoluteImagePath('filetypes/text-calendar.svg')); - if ($location) { - $template->addBodyListItem($location, $l10n->t('Where:'), - $this->getAbsoluteImagePath('filetypes/location.svg')); + private function addAttendees(IEMailTemplate $template, IL10N $l10n, VEvent $vevent) { + if ($this->config->getAppValue('dav', 'invitation_list_attendees', 'no') === 'no') { + return; } - if ($description) { - $template->addBodyListItem((string)$description, $l10n->t('Description:'), - $this->getAbsoluteImagePath('filetypes/text.svg')); + + if (isset($vevent->ORGANIZER)) { + /** @var Property\ICalendar\CalAddress $organizer */ + $organizer = $vevent->ORGANIZER; + $organizerURI = $organizer->getNormalizedValue(); + list($scheme,$organizerEmail) = explode(':',$organizerURI,2); # strip off scheme mailto: + /** @var string|null $organizerName */ + $organizerName = isset($organizer['CN']) ? $organizer['CN'] : null; + $organizerHTML = sprintf('<a href="%s">%s</a>', + htmlspecialchars($organizerURI), + htmlspecialchars($organizerName ?: $organizerEmail)); + $organizerText = sprintf('%s <%s>', $organizerName, $organizerEmail); + if (isset($organizer['PARTSTAT'])) { + /** @var Parameter $partstat */ + $partstat = $organizer['PARTSTAT']; + if (strcasecmp($partstat->getValue(), 'ACCEPTED') === 0) { + $organizerHTML .= ' ✔︎'; + $organizerText .= ' ✔︎'; + } + } + $template->addBodyListItem($organizerHTML, $l10n->t('Organizer:'), + $this->getAbsoluteImagePath('caldav/organizer.svg'), + $organizerText,'',self::IMIP_INDENT); } - if ($url) { - $template->addBodyListItem((string)$url, $l10n->t('Link:'), - $this->getAbsoluteImagePath('filetypes/link.svg')); + + $attendees = $vevent->select('ATTENDEE'); + if (count($attendees) === 0) { + return; + } + + $attendeesHTML = []; + $attendeesText = []; + foreach ($attendees as $attendee) { + $attendeeURI = $attendee->getNormalizedValue(); + list($scheme,$attendeeEmail) = explode(':',$attendeeURI,2); # strip off scheme mailto: + $attendeeName = isset($attendee['CN']) ? $attendee['CN'] : null; + $attendeeHTML = sprintf('<a href="%s">%s</a>', + htmlspecialchars($attendeeURI), + htmlspecialchars($attendeeName ?: $attendeeEmail)); + $attendeeText = sprintf('%s <%s>', $attendeeName, $attendeeEmail); + if (isset($attendee['PARTSTAT']) + && strcasecmp($attendee['PARTSTAT'], 'ACCEPTED') === 0) { + $attendeeHTML .= ' ✔︎'; + $attendeeText .= ' ✔︎'; + } + array_push($attendeesHTML, $attendeeHTML); + array_push($attendeesText, $attendeeText); } + + $template->addBodyListItem(implode('<br/>',$attendeesHTML), $l10n->t('Attendees:'), + $this->getAbsoluteImagePath('caldav/attendees.svg'), + implode("\n",$attendeesText),'',self::IMIP_INDENT); } /** |