diff --git a/lib/DigestSender.php b/lib/DigestSender.php index 0dfe4d380..963afa996 100644 --- a/lib/DigestSender.php +++ b/lib/DigestSender.php @@ -220,27 +220,6 @@ public function sendDigestForUser(IUser $user, int $now, string $timezone, strin * @return string */ protected function getHTMLSubject(IEvent $event): string { - if ($event->getRichSubject() === '') { - return htmlspecialchars($event->getParsedSubject()); - } - - $placeholders = $replacements = []; - foreach ($event->getRichSubjectParameters() as $placeholder => $parameter) { - $placeholders[] = '{' . $placeholder . '}'; - - if ($parameter['type'] === 'file') { - $replacement = (string)$parameter['path']; - } else { - $replacement = (string)$parameter['name']; - } - - if (isset($parameter['link'])) { - $replacements[] = '' . htmlspecialchars($replacement) . ''; - } else { - $replacements[] = '' . htmlspecialchars($replacement) . ''; - } - } - - return str_replace($placeholders, $replacements, $event->getRichSubject()); + return HTMLSubjectFormatter::format($event); } } diff --git a/lib/HTMLSubjectFormatter.php b/lib/HTMLSubjectFormatter.php new file mode 100644 index 000000000..b9c480b7d --- /dev/null +++ b/lib/HTMLSubjectFormatter.php @@ -0,0 +1,37 @@ +getRichSubject() === '') { + return htmlspecialchars($event->getParsedSubject()); + } + + $placeholders = $replacements = []; + foreach ($event->getRichSubjectParameters() as $placeholder => $parameter) { + $placeholders[] = '{' . $placeholder . '}'; + + $replacement = $parameter['type'] === 'file' + ? (string)$parameter['path'] + : (string)$parameter['name']; + + if (isset($parameter['link'])) { + $replacements[] = '' . htmlspecialchars($replacement) . ''; + } else { + $replacements[] = '' . htmlspecialchars($replacement) . ''; + } + } + + return str_replace($placeholders, $replacements, $event->getRichSubject()); + } +} diff --git a/lib/MailQueueHandler.php b/lib/MailQueueHandler.php index 46be003e4..b089f0c48 100644 --- a/lib/MailQueueHandler.php +++ b/lib/MailQueueHandler.php @@ -379,28 +379,7 @@ function ($event) use ($timezone, $l) { } protected function getHTMLSubject(IEvent $event): string { - if ($event->getRichSubject() === '') { - return htmlspecialchars($event->getParsedSubject()); - } - - $placeholders = $replacements = []; - foreach ($event->getRichSubjectParameters() as $placeholder => $parameter) { - $placeholders[] = '{' . $placeholder . '}'; - - if ($parameter['type'] === 'file') { - $replacement = (string)$parameter['path']; - } else { - $replacement = (string)$parameter['name']; - } - - if (isset($parameter['link'])) { - $replacements[] = '' . htmlspecialchars($replacement) . ''; - } else { - $replacements[] = '' . htmlspecialchars($replacement) . ''; - } - } - - return str_replace($placeholders, $replacements, $event->getRichSubject()); + return HTMLSubjectFormatter::format($event); } /** diff --git a/tests/HTMLSubjectFormatterTest.php b/tests/HTMLSubjectFormatterTest.php new file mode 100644 index 000000000..321e0c0cc --- /dev/null +++ b/tests/HTMLSubjectFormatterTest.php @@ -0,0 +1,56 @@ +createMock(IEvent::class); + $event->method('getRichSubject')->willReturn($richSubject); + $event->method('getRichSubjectParameters')->willReturn($richParams); + $event->method('getParsedSubject')->willReturn($parsedSubject); + return $event; + } + + public function testNoRichSubjectFallsToParsed(): void { + $event = $this->getEvent('', [], 'Plain '); + $this->assertSame('Plain <subject>', HTMLSubjectFormatter::format($event)); + } + + public function testFileParameterUsesPath(): void { + $event = $this->getEvent( + 'File {file} was changed', + ['file' => ['type' => 'file', 'path' => '/my/file.txt', 'name' => 'file.txt']], + '', + ); + $this->assertSame('File /my/file.txt was changed', HTMLSubjectFormatter::format($event)); + } + + public function testNonFileParameterUsesName(): void { + $event = $this->getEvent( + '{user} shared', + ['user' => ['type' => 'user', 'name' => 'Alice & Bob']], + '', + ); + $this->assertSame('Alice & Bob shared', HTMLSubjectFormatter::format($event)); + } + + public function testParameterWithLinkRendersAnchor(): void { + $event = $this->getEvent( + 'See {file}', + ['file' => ['type' => 'file', 'path' => 'report.pdf', 'name' => 'report.pdf', 'link' => 'https://example.com/report.pdf']], + '', + ); + $this->assertSame('See report.pdf', HTMLSubjectFormatter::format($event)); + } +}