diff --git a/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php b/apps/dav/lib/CalDAV/Schedule/IMipPlugin.php index 6a9b64ff9719db19b4406e559552594d202ecb5a..56517ab28c12774f8167d8f957768cd4b2686e08 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> @@ -242,8 +241,7 @@ class IMipPlugin extends SabreIMipPlugin { $summary = ((string) $summary !== '') ? (string) $summary : $l10n->t('Untitled event'); - $this->addSubjectAndHeading($template, $l10n, $method, $summary, - $meetingAttendeeName, $meetingInviteeName); + $this->addSubjectAndHeading($template, $l10n, $method, $summary); $this->addBulletList($template, $l10n, $vevent); @@ -402,20 +400,19 @@ class IMipPlugin extends SabreIMipPlugin { * @param VEvent $vevent */ 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 = $end->getDateTime(); + $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 = $end->getDateTime(); + $endDateTime = $dtend->getDateTime(); $endDateTime = $endDateTime->modify('+1 day'); $dtend->setDateTime($endDateTime, $isFloating); } else { @@ -526,7 +523,6 @@ class IMipPlugin extends SabreIMipPlugin { * @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); @@ -541,19 +537,20 @@ class IMipPlugin extends SabreIMipPlugin { $this->getAbsoluteImagePath('caldav/location.svg'),'','',self::IMIP_INDENT); } if ($vevent->URL) { + $url = $vevent->URL->getValue(); $template->addBodyListItem(sprintf('<a href="%s">%s</a>', - htmlspecialchars($vevent->URL), - htmlspecialchars($vevent->URL)), + htmlspecialchars($url), + htmlspecialchars($url)), $l10n->t('Link:'), $this->getAbsoluteImagePath('caldav/link.svg'), - $vevent->URL,'',self::IMIP_INDENT); + $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, $l10n->t('Description:'), + $template->addBodyListItem($vevent->DESCRIPTION->getValue(), $l10n->t('Description:'), $this->getAbsoluteImagePath('caldav/description.svg'),'','',self::IMIP_INDENT); } } @@ -581,18 +578,23 @@ class IMipPlugin extends SabreIMipPlugin { } 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']) - && strcasecmp($organizer['PARTSTAT'], 'ACCEPTED') === 0) { - $organizerHTML .= ' ✔︎'; - $organizerText .= ' ✔︎'; + 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'), diff --git a/apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php b/apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php index 8faa54f534a0cc82020024c612888f309b52d5c4..a31fdfdc5f7126d9d6c9a8b8539ee9a7763170dd 100644 --- a/apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php +++ b/apps/dav/tests/unit/CalDAV/Schedule/IMipPluginTest.php @@ -136,6 +136,7 @@ class IMipPluginTest extends TestCase { public function testDelivery() { $this->config + ->expects($this->at(1)) ->method('getAppValue') ->with('dav', 'invitation_link_recipients', 'yes') ->willReturn('yes'); @@ -148,6 +149,7 @@ class IMipPluginTest extends TestCase { public function testFailedDelivery() { $this->config + ->expects($this->at(1)) ->method('getAppValue') ->with('dav', 'invitation_link_recipients', 'yes') ->willReturn('yes'); @@ -163,6 +165,7 @@ class IMipPluginTest extends TestCase { public function testDeliveryWithNoCommonName() { $this->config + ->expects($this->at(1)) ->method('getAppValue') ->with('dav', 'invitation_link_recipients', 'yes') ->willReturn('yes'); @@ -188,9 +191,8 @@ class IMipPluginTest extends TestCase { */ public function testNoMessageSendForPastEvents(array $veventParams, bool $expectsMail) { $this->config - ->method('getAppValue') - ->with('dav', 'invitation_link_recipients', 'yes') - ->willReturn('yes'); + ->method('getAppValue') + ->willReturn('yes'); $message = $this->_testMessage($veventParams); @@ -228,6 +230,7 @@ class IMipPluginTest extends TestCase { $this->_expectSend($recipient, true, $has_buttons); $this->config + ->expects($this->at(1)) ->method('getAppValue') ->with('dav', 'invitation_link_recipients', 'yes') ->willReturn($config_setting); @@ -252,14 +255,13 @@ class IMipPluginTest extends TestCase { public function testMessageSendWhenEventWithoutName() { $this->config ->method('getAppValue') - ->with('dav', 'invitation_link_recipients', 'yes') ->willReturn('yes'); $message = $this->_testMessage(['SUMMARY' => '']); $this->_expectSend('frodo@hobb.it', true, true,'Invitation: Untitled event'); $this->emailTemplate->expects($this->once()) ->method('addHeading') - ->with('Mr. Wizard invited you to »Untitled event«'); + ->with('Invitation'); $this->plugin->schedule($message); $this->assertEquals('1.1', $message->getScheduleStatus()); } diff --git a/apps/settings/tests/Mailer/NewUserMailHelperTest.php b/apps/settings/tests/Mailer/NewUserMailHelperTest.php index fdb5da3bb548b328514ee5138a4fa43af7443d3b..7507c8a9dac7fe73c575fe511d4950fd4fbb4abe 100644 --- a/apps/settings/tests/Mailer/NewUserMailHelperTest.php +++ b/apps/settings/tests/Mailer/NewUserMailHelperTest.php @@ -599,6 +599,7 @@ Welcome to your TestCloud account, you can add, protect, and share your data. Your username is: john + Go to TestCloud: https://example.com/ Install Client: https://nextcloud.com/install/#install-clients @@ -817,6 +818,7 @@ Welcome aboard John Doe Welcome to your TestCloud account, you can add, protect, and share your data. + Go to TestCloud: https://example.com/ Install Client: https://nextcloud.com/install/#install-clients diff --git a/lib/private/Mail/EMailTemplate.php b/lib/private/Mail/EMailTemplate.php index 054378c2afa0105af3502ac1d21ed9b01b7cad65..e3768ae6cde8a197f94d440c29ba8fe8e23f90f4 100644 --- a/lib/private/Mail/EMailTemplate.php +++ b/lib/private/Mail/EMailTemplate.php @@ -447,21 +447,21 @@ EOF; * @param string $metaInfo Note: When $plainMetaInfo falls back to this, HTML is automatically escaped in the HTML email * @param string $icon Absolute path, must be 16*16 pixels * @param string|bool $plainText Text that is used in the plain text email - * if empty the $text is used, if false none will be used + * if empty or true the $text is used, if false none will be used * @param string|bool $plainMetaInfo Meta info that is used in the plain text email - * if empty the $metaInfo is used, if false none will be used + * if empty or true the $metaInfo is used, if false none will be used * @param integer plainIndent If > 0, Indent plainText by this amount. * @since 12.0.0 */ public function addBodyListItem(string $text, string $metaInfo = '', string $icon = '', $plainText = '', $plainMetaInfo = '', $plainIndent = 0) { $this->ensureBodyListOpened(); - if ($plainText === '') { + if ($plainText === '' || $plainText === true) { $plainText = $text; $text = htmlspecialchars($text); $text = str_replace("\n", "<br/>", $text); // convert newlines to HTML breaks } - if ($plainMetaInfo === '') { + if ($plainMetaInfo === '' || $plainMetaInfo === true) { $plainMetaInfo = $metaInfo; $metaInfo = htmlspecialchars($metaInfo); } @@ -494,8 +494,10 @@ EOF; * "plainIndent". Multilines after the first are indented plainIndent+1 * (to account for space after label). Fixes: #12391 */ + /** @var string $label */ + $label = ($plainMetaInfo !== false)? $plainMetaInfo : ''; $this->plainBody .= sprintf("%${plainIndent}s %s\n", - $plainMetaInfo, + $label, str_replace("\n", "\n" . str_repeat(' ', $plainIndent+1), $plainText)); } } diff --git a/lib/public/Mail/IEMailTemplate.php b/lib/public/Mail/IEMailTemplate.php index 70046d5c508f37f84e5a72b90555eba5018c62db..5f4e235a7eef5fed6a9ccdc07eddd8782c07af35 100644 --- a/lib/public/Mail/IEMailTemplate.php +++ b/lib/public/Mail/IEMailTemplate.php @@ -106,9 +106,10 @@ interface IEMailTemplate { * if empty the $text is used, if false none will be used * @param string|bool $plainMetaInfo Meta info that is used in the plain text email * if empty the $metaInfo is used, if false none will be used + * @param integer plainIndent If > 0, Indent plainText by this amount. * @since 12.0.0 */ - public function addBodyListItem(string $text, string $metaInfo = '', string $icon = '', $plainText = '', $plainMetaInfo = ''); + public function addBodyListItem(string $text, string $metaInfo = '', string $icon = '', $plainText = '', $plainMetaInfo = '', $plainIndent = 0); /** * Adds a button group of two buttons to the body of the email diff --git a/tests/data/emails/new-account-email-custom-text-alternative.txt b/tests/data/emails/new-account-email-custom-text-alternative.txt index f65744b20d9069501a274462e83709b7ccc90665..03cb99c1d76c22ace894e630c3d0d9efcd615504 100644 --- a/tests/data/emails/new-account-email-custom-text-alternative.txt +++ b/tests/data/emails/new-account-email-custom-text-alternative.txt @@ -4,6 +4,7 @@ Welcome to your Nextcloud account, you can add, protect, and share your data. - Your username is: abc + Set your password - text: https://example.org/resetPassword/123 Install Client - text: https://nextcloud.com/install/#install-clients diff --git a/tests/data/emails/new-account-email-custom.txt b/tests/data/emails/new-account-email-custom.txt index 57c5202a744ed03b516bc29f57c11f199c7d9a31..c075c49d6490056c6954912f41b697f95ee7af33 100644 --- a/tests/data/emails/new-account-email-custom.txt +++ b/tests/data/emails/new-account-email-custom.txt @@ -4,6 +4,7 @@ Welcome to your Nextcloud account, you can add, protect, and share your data. Your username is: abc + Set your password: https://example.org/resetPassword/123 Install Client: https://nextcloud.com/install/#install-clients diff --git a/tests/data/emails/new-account-email.txt b/tests/data/emails/new-account-email.txt index 895241341831c8349c0912903c7f94bce82ae96d..b246482af13f6f1b0a54e0a1132215cfbc6de027 100644 --- a/tests/data/emails/new-account-email.txt +++ b/tests/data/emails/new-account-email.txt @@ -4,6 +4,7 @@ Welcome to your Nextcloud account, you can add, protect, and share your data. Your username is: abc + Set your password: https://example.org/resetPassword/123 Install Client: https://nextcloud.com/install/#install-clients