Include the card description in the notification mail
Build package / php-lint (8.2) (push) Successful in 1m46s
Build package / php-lint (8.3) (push) Successful in 47s
Build package / php-lint (8.4) (push) Successful in 38s
Build package / xml-lint (push) Successful in 17s
Build package / unit-tests (push) Successful in 45s
Build package / package (push) Successful in 1m4s
Build package / php-lint (8.2) (push) Successful in 1m46s
Build package / php-lint (8.3) (push) Successful in 47s
Build package / php-lint (8.4) (push) Successful in 38s
Build package / xml-lint (push) Successful in 17s
Build package / unit-tests (push) Successful in 45s
Build package / package (push) Successful in 1m4s
The mail named the card and the workflow but not what the card is about, which meant opening Deck to know whether the move mattered. The description is escaped explicitly: addBodyText() only calls htmlspecialchars() when it has to derive the plain-text part itself, and we pass both parts to get line breaks in the HTML body -- so escaping user input is on us. Long descriptions are cut at 2000 characters. Deck stores the description as Markdown; it is sent unrendered rather than pulling in a parser for one mail.
This commit is contained in:
@@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user