feat: answer received form submissions by mail
This commit is contained in:
1 parent
19364df2db
commit
aa728ddc99
22 files changed
+974
-9
No files matched your search
@@ -29,10 +29,24 @@ class EmailTextRenderer
|
||||
*/
|
||||
private const ESCAPE_FLAGS = ENT_COMPAT | ENT_SUBSTITUTE;
|
||||
|
||||
/**
|
||||
* The token for the booking link, and why it is not handled like the other placeholders:
|
||||
* a placeholder value is substituted into the *rendered HTML* and escaped there, which is
|
||||
* what makes a teamer's own words harmless - but it also means such a value can never be a
|
||||
* link target, because CommonMark has already percent-encoded the braces by then
|
||||
* ("%7BbookingUrl%7D"). This one is substituted into the Markdown *before* parsing instead,
|
||||
* so the admin can write it as a proper link and CommonMark still gets to vet the URL
|
||||
* through allow_unsafe_links. That is only defensible because the value comes from the
|
||||
* deployment's own environment, exactly like the wording it is substituted into - never
|
||||
* from a teamer or an applicant. Do not extend this to anything a user can influence.
|
||||
*/
|
||||
private const BOOKING_URL_TOKEN = '{bookingUrl}';
|
||||
|
||||
public function __construct(
|
||||
private readonly EmailTextCatalog $catalog,
|
||||
private readonly EmailTextRepository $emailTextRepository,
|
||||
private readonly MailBodyRenderer $mailBodyRenderer,
|
||||
private readonly string $bookingUrl = '',
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -86,10 +100,29 @@ class EmailTextRenderer
|
||||
return new RenderedEmailTextDto(
|
||||
strtr($subject ?? '', $rawTokens),
|
||||
$this->renderHeadline($headline ?? '', $htmlTokens),
|
||||
$this->mailBodyRenderer->render($body ?? '', $rawTokens),
|
||||
$this->mailBodyRenderer->render($this->insertBookingUrl($body ?? ''), $rawTokens),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Refuses rather than sending a broken link: an unconfigured APPLICATION_FORM_BOOKING_URL
|
||||
* would otherwise render as <a href=""> and invite an applicant to book a call they cannot
|
||||
* reach. The caller decides what that means - the endpoint logs it and answers the
|
||||
* submission anyway, a reviewer sending by hand gets to see it.
|
||||
*/
|
||||
private function insertBookingUrl(string $body): string
|
||||
{
|
||||
if (false === str_contains($body, self::BOOKING_URL_TOKEN)) {
|
||||
return $body;
|
||||
}
|
||||
|
||||
if ('' === trim($this->bookingUrl)) {
|
||||
throw new \RuntimeException('The mail wording uses {bookingUrl}, but APPLICATION_FORM_BOOKING_URL is not configured.');
|
||||
}
|
||||
|
||||
return str_replace(self::BOOKING_URL_TOKEN, trim($this->bookingUrl), $body);
|
||||
}
|
||||
|
||||
/**
|
||||
* The headline is set as the mail's own <h1>, so it deliberately takes no Markdown:
|
||||
* emphasis inside an already bold heading says nothing, and a stray "-" or "#" at the
|
||||
|
||||
Reference in new issue
Block a user