aboutsummaryrefslogtreecommitdiffstats
path: root/apps/dav/lib
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@users.noreply.github.com>2020-09-04 19:53:02 +0200
committerGitHub <noreply@github.com>2020-09-04 19:53:02 +0200
commit593d64d935cad2a3b4c039ba511f1a5a15c6b756 (patch)
tree9cec38f80392b55eebae4ad1c38cbcd3469423e0 /apps/dav/lib
parent5483d02b5e3ef8d20054d3d0332d82a8a3dbd5b0 (diff)
parent442af8c5d57797bf255db036c8c04ab48f36c3a1 (diff)
downloadnextcloud-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.php186
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);
}
/**