Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ ALGOLIA_FRONTEND_API_KEY=74e71e5r5c2Rb353f5a03376gb9878777

HOME_ALGOLIA_ENABLED=false

SLACK_URL=http://yolo
SLACK_URL=http://httpbin:8080/status/200

BLUESKY_API_IDENTIFIER=xxx
BLUESKY_API_APP_PASSWORD=yyy
Expand Down
3 changes: 3 additions & 0 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,6 @@ services:
image: nginx:1.29.7
volumes:
- ./docker/dockerfiles/statictestresources:/usr/share/nginx/html:ro

httpbin:
image: mccutchen/go-httpbin
20 changes: 19 additions & 1 deletion sources/AppBundle/Event/Talk/TalkFormHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use AppBundle\Notifier\SlackNotifier;
use CCMBenchmark\Ting\UnitOfWork;
use DateTime;
use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\Request;
Expand All @@ -27,6 +28,8 @@ public function __construct(
private readonly EventDispatcherInterface $eventDispatcher,
private readonly TalkToSpeakersRepository $talkToSpeakersRepository,
private readonly UnitOfWork $unitOfWork,
private readonly TalkSubmissionConfirmationMail $confirmationMail,
private readonly LoggerInterface $logger,
) {}

public function handle(Request $request, Event $event, FormInterface $form, Speaker $speaker): bool
Expand All @@ -39,9 +42,24 @@ public function handle(Request $request, Event $event, FormInterface $form, Spea
$talk = $form->getData();
$talk->setSubmittedOn(new DateTime());
$this->speakerRepository->save($speaker);
$locale = $request->getLocale();
if (!$this->unitOfWork->isManaged($talk)) {
$this->eventDispatcher->addListener(KernelEvents::TERMINATE, function () use ($talk, $event): void {
$this->slackNotifier->notifyTalk($talk, $event);
try {
$this->slackNotifier->notifyTalk($talk, $event);
} catch (\Throwable $e) {
$this->logger->warning('Slack talk notification failed: ' . $e->getMessage());
}
});
$this->eventDispatcher->addListener(KernelEvents::TERMINATE, function () use ($talk, $event, $speaker, $locale): void {
try {
$this->confirmationMail->send($talk, $event, $speaker, $locale);
} catch (\Throwable $e) {
$this->logger->error('CFP confirmation mail failed: ' . $e->getMessage(), [
'exception' => $e,
'talkId' => $talk->getId(),
]);
}
});
}
$this->talkRepository->save($talk);
Expand Down
80 changes: 80 additions & 0 deletions sources/AppBundle/Event/Talk/TalkSubmissionConfirmationMail.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php

declare(strict_types=1);

namespace AppBundle\Event\Talk;

use AppBundle\Email\Mailer\Mailer;
use AppBundle\Email\Mailer\MailUser;
use AppBundle\Email\Mailer\MailUserFactory;
use AppBundle\Email\Mailer\Message;
use AppBundle\Event\Model\Event;
use AppBundle\Event\Model\Speaker;
use AppBundle\Event\Model\Talk;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use Twig\Environment;

class TalkSubmissionConfirmationMail
{
public function __construct(
private readonly Mailer $mailer,
private readonly UrlGeneratorInterface $urlGenerator,
private readonly Environment $twig,
private readonly TranslatorInterface $translator,
) {}

public function send(Talk $talk, Event $event, Speaker $speaker, string $locale = 'fr'): void
{
$eventTitle = (string) $event->getTitle();

if ($locale === 'fr') {
$firstChar = mb_strtolower(mb_substr($eventTitle, 0, 1));
$eventParam = in_array($firstChar, ['a', 'e', 'i', 'o', 'u', 'h'], true)
? "de l'" . $eventTitle
: 'du ' . $eventTitle;
} else {
$eventParam = $eventTitle;
}

$votePageUrl = null;
if ($event->getVoteEnabled()) {
$votePageUrl = $this->urlGenerator->generate(
'vote_index',
['eventSlug' => $event->getPath()],
UrlGeneratorInterface::ABSOLUTE_URL,
);
}

$subject = $this->translator->trans(
'mail.cfp_submission.subject',
['%event%' => $eventTitle, '%title%' => $talk->getTitle()],
'messages',
$locale,
);

$bodyTitle = $this->translator->trans(
'mail.cfp_submission.title',
['%event%' => $eventParam],
'messages',
$locale,
);

$content = $this->twig->render('mail_templates/cfp_submission_confirmation_content.html.twig', [
'talk' => $talk,
'event' => $event,
'eventParam' => $eventParam,
'cfpEndDate' => $event->getDateEndCallForPapers(),
'votePageUrl' => $votePageUrl,
'locale' => $locale,
]);

$message = new Message(
$subject,
MailUserFactory::conferences(),
new MailUser($speaker->getEmail(), $speaker->getLabel()),
);

$this->mailer->sendTransactional($message, $content, MailUserFactory::conferences()->getEmail(), $bodyTitle);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{ 'mail.cfp_submission.text'|trans({
'%title%': talk.title|e,
'%event%': eventParam|e,
'%date%': cfpEndDate|date('d/m/Y')
}, 'messages', locale)|raw }}

{% if votePageUrl %}
{{ 'mail.cfp_submission.vote_section'|trans({'%url%': votePageUrl}, 'messages', locale)|raw }}
{% endif %}

<p>{{ 'mail.cfp_submission.abstract'|trans({}, 'messages', locale) }}</p>
<pre>{{ talk.abstract }}</pre>

<p>{{ 'mail.cfp_submission.signature'|trans({}, 'messages', locale) }}</p>
4 changes: 4 additions & 0 deletions tests/behat/features/EventPages/Cfp.feature
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ Feature: Event pages - CFP
Then I should see "Les nouvelles conférences à noter"
And I should see "Il n'y a plus aucune conférence à noter !"

@clearEmails
Scenario: On crée une nouvelle proposition en tant que userGithub1 mais on ne peut pas la noter
Given I am on "/event/forum/cfp"
Then I should see "Oauth login test"
Expand All @@ -62,6 +63,9 @@ Feature: Event pages - CFP
And I press "Sauvegarder"
Then I should not see "Cette valeur ne doit pas être vide."
And I should see "Proposition enregistrée !"
And I should only receive the following emails:
| to | subject |
| <monemail@provider.fr> | AFUP - forum - Confirmation de soumission au CFP - Généalogie des poissons rouges |
When I am on "/event/forum/cfp"
Then I should see "Généalogie des poissons rouges"
When I am on "/event/forum/vote"
Expand Down
18 changes: 18 additions & 0 deletions tests/behat/features/EventPages/CfpEn.feature
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,21 @@ Feature: Event pages - CFP - en anglais
And I attach the file "avatar1.png" to "speaker[photoFile]"
And I press "Save"
Then I should see "Profile saved."

@clearEmails
Scenario: On submitting a new talk a confirmation email is sent
Given I am on "/event/forum/cfp?_locale=en"
Then I should see "Oauth login test"
When I follow "Connect as userGithub1"
Then I should see "My speaker area"
When I follow "New submission"
When I fill in "talk[title]" with "The history of PHP"
And I fill in "talk[abstract]" with "An abstract about the history of PHP"
And I fill in "talk[hasAllowedToSharingWithLocalOffices]" with "1"
And I check "talk[codeOfConduct]"
And I check "talk[selectionAcknowledgement]"
And I press "Save"
Then I should see "Talk saved!"
And I should only receive the following emails:
| to | subject |
| <monemail@provider.fr> | AFUP - forum - CFP submission confirmation - The history of PHP |
13 changes: 13 additions & 0 deletions translations/messages.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -218,3 +218,16 @@ speaker_infos.microphone.label: "Microphone type"
speaker_infos.microphone.placeholder: "No preference"
speaker_infos.microphone.choice.headset: "Headset microphone"
speaker_infos.microphone.choice.handheld: "Handheld microphone"
'mail.cfp_submission.subject': 'AFUP - %event% - CFP submission confirmation - %title%'
'mail.cfp_submission.title': 'CFP submission confirmation - %event%'
'mail.cfp_submission.text': |
<p>Hello,</p>

<p>We confirm receipt of your talk submission « %title% » to the CFP %event%.</p>

<p>Once the call for papers closes on %date%, the conference team will make a selection following the <a href="https://event.afup.org/processus-de-selection-eventsafup/">process described on the dedicated page</a>.</p>

<p>Whatever the outcome, you will receive an email in the weeks following the end of the CFP.</p>
'mail.cfp_submission.vote_section': '<p>Feel free to check the public comments and votes on the <a href="%url%">dedicated page</a>. Please note these are advisory — the conference team has sole decision-making authority.</p>'
'mail.cfp_submission.abstract': 'Here is an abstract of your submission:'
'mail.cfp_submission.signature': 'Thank you for your contribution,'
13 changes: 13 additions & 0 deletions translations/messages.fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -242,3 +242,16 @@ speaker_infos.microphone.label: "Type de microphone"
speaker_infos.microphone.placeholder: "Pas de préférence"
speaker_infos.microphone.choice.headset: "Micro casque"
speaker_infos.microphone.choice.handheld: "Micro à main"
'mail.cfp_submission.subject': 'AFUP - %event% - Confirmation de soumission au CFP - %title%'
'mail.cfp_submission.title': 'Confirmation de soumission au CFP %event%'
'mail.cfp_submission.text': |
<p>Bonjour,</p>

<p>Nous vous confirmons la bonne réception de votre soumission « %title% » au CFP %event%.</p>

<p>Une fois l'appel à conférences terminé, le %date%, le pôle conférences effectuera une sélection en respectant bien le <a href="https://event.afup.org/processus-de-selection-eventsafup/">processus tel que décrit sur la page dédiée</a>.</p>

<p>Quel que soit le résultat, un courriel vous sera envoyé dans les semaines qui suivront la fin du CFP.</p>
'mail.cfp_submission.vote_section': '<p>N''hésitez pas à consulter les commentaires et votes du public sur la <a href="%url%">page dédiée</a>. Notez bien que ceux-ci sont indicatifs, le pôle conférences est seul décisionnaire sur la sélection.</p>'
'mail.cfp_submission.abstract': 'Voici un extrait de votre soumission :'
'mail.cfp_submission.signature': 'Merci pour votre contribution,'
Loading