diff --git a/lib/Service/NotificationMailer.php b/lib/Service/NotificationMailer.php index 33f1ac2..8c35f38 100644 --- a/lib/Service/NotificationMailer.php +++ b/lib/Service/NotificationMailer.php @@ -9,12 +9,19 @@ use OCA\WorkflowDeckAutomation\Db\Workflow; use OCP\IL10N; use OCP\IURLGenerator; use OCP\IUser; +use OCP\Mail\IEMailTemplate; use OCP\Mail\IMailer; use OCP\Util; use Psr\Log\LoggerInterface; use Throwable; class NotificationMailer { + /** + * Descriptions are unbounded in Deck; keep the mail readable and well + * clear of any MTA size limits. + */ + private const MAX_DESCRIPTION_LENGTH = 2000; + public function __construct( private IMailer $mailer, private IURLGenerator $urlGenerator, @@ -48,6 +55,7 @@ class NotificationMailer { 'The card "%1$s" was moved because it is overdue (workflow "%2$s").', [$card->getTitle(), $workflow->getTitle()], )); + $this->addCardDescription($template, $card); $template->addBodyButton($this->l10n->t('Open card'), $cardLink); $template->addFooter(); @@ -69,4 +77,33 @@ class NotificationMailer { ]); } } + + /** + * Appends the card's description, if it has one. + * + * Deck stores the description as Markdown. It is sent as-is rather than + * rendered: pulling a Markdown parser in just for the mail would be a + * lot of machinery, and unrendered Markdown still reads fine. + */ + private function addCardDescription(IEMailTemplate $template, Card $card): void { + $description = trim((string)$card->getDescription()); + if ($description === '') { + return; + } + + if (mb_strlen($description) > self::MAX_DESCRIPTION_LENGTH) { + $description = mb_substr($description, 0, self::MAX_DESCRIPTION_LENGTH) . ' […]'; + } + + $template->addBodyText($this->l10n->t('Card content:')); + + // addBodyText() only runs htmlspecialchars() when it has to build the + // plain-text part itself. Passing both parts means escaping is on us + // -- and it has to be, because a card description is user input that + // would otherwise land unescaped in the HTML mail. + $template->addBodyText( + nl2br(htmlspecialchars($description, ENT_QUOTES, 'UTF-8'), false), + $description, + ); + } }