<?php
namespace Products\NotificationsBundle\Controller\Dashboard;
use App\Component\ViewLayer\AbstractView;
use App\Component\ViewLayer\Views\AbstractHtmlView;
use App\Component\ViewLayer\Views\AjaxHtmlView;
use App\Component\ViewLayer\Views\DocHtmlView;
use App\Component\ViewLayer\Views\JsonView;
use App\Controller\PaginationTrait;
use App\Entity\System\School;
use App\Form\Forms\DummyForm;
use App\Model\Messaging\SendgridEmailMessage;
use App\Service\Intl\CloudTranslator;
use App\Service\Messaging\MessagingContext;
use App\Service\Messaging\SendgridEmailMessenger;
use App\Util\Locales;
use Cms\CoreBundle\Util\DateTimeUtils;
use Cms\TenantBundle\Entity\Tenant;
use Products\NotificationsBundle\Controller\AbstractDashboardController;
use Products\NotificationsBundle\Doctrine\Repository\Notifications\Translations\TranslationRepository;
use Products\NotificationsBundle\Entity\AbstractContactAttempt;
use Products\NotificationsBundle\Entity\AbstractList;
use Products\NotificationsBundle\Entity\AbstractNotification;
use Products\NotificationsBundle\Entity\Notifications\Message;
use Products\NotificationsBundle\Entity\Notifications\Template;
use Products\NotificationsBundle\Entity\Notifications\Translations\Translation;
use Products\NotificationsBundle\Entity\Student;
use Products\NotificationsBundle\Form\Forms\Logs\ContactAttemptSearchForm;
use Products\NotificationsBundle\Form\Forms\Messages\MessageChannelsForm;
use Products\NotificationsBundle\Form\Forms\Messages\MessageDataForm;
use Products\NotificationsBundle\Form\Forms\Messages\MessageSearchForm;
use Products\NotificationsBundle\Form\Forms\Messages\MessageTestForm;
use Products\NotificationsBundle\Model\Searching\ContactAttemptSearch;
use Products\NotificationsBundle\Model\Searching\MessageSearch;
use Products\NotificationsBundle\Model\Testing\EmailTester;
use Products\NotificationsBundle\Model\Testing\PhoneTester;
use Products\NotificationsBundle\Service\EmailTemplateGeneratorFactory;
use Products\NotificationsBundle\Service\ListItemProvider;
use Products\NotificationsBundle\Service\MergeParamsProvider;
use Products\NotificationsBundle\Util\MessageContentGenerator;
use Products\NotificationsBundle\Service\MessageLogic;
use Products\NotificationsBundle\Service\Notifications\TranslationService;
use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\Routing\Annotation\Route;
/**
* Class MessagesController
* @package Products\NotificationsBundle\Controller\Dashboard
*
* @Route(
* "/messages",
* )
*/
final class MessagesController extends AbstractDashboardController
{
use PaginationTrait;
const ROUTES__MAIN = 'app.notifications.dashboard.messages.main';
const ROUTES__CREATE = 'app.notifications.dashboard.messages.create';
const ROUTES__UPDATE = 'app.notifications.dashboard.messages.update';
const ROUTES__CHECK_UPDATE_FORM = 'app.notifications.dashboard.messages.check_update_form';
const ROUTES__TRANSLATIONS = 'app.notifications.dashboard.messages.translations';
const ROUTES__CHECK_TRANSLATION_PROGRESS = 'app.notifications.dashboard.messages.check_translation_progress';
const ROUTES__MANAGE = 'app.notifications.dashboard.messages.manage';
const ROUTES__DETECT_TRANSLATION_CHANGE = 'app.notifications.dashboard.messages.detect_locale_change';
const ROUTES__DELETE = 'app.notifications.dashboard.messages.delete';
const ROUTES__UNSCHEDULE = 'app.notifications.dashboard.messages.unschedule';
const ROUTES__STUDENT_EMAIL_PREVIEW = 'app.notifications.dashboard.messages.student_email_preview';
const ROUTES__EMAIL_PREVIEW = 'app.notifications.dashboard.messages.email_preview';
const ROUTES__REPORT = 'app.notifications.dashboard.messages.report';
const ROUTES__LOGS = 'app.notifications.dashboard.messages.logs';
const ROUTES__DEBUGGING = 'app.notifications.dashboard.messages.debugging';
const ROUTES__FILTERED_LOGS = 'app.notifications.dashboard.messages.filtered_logs';
const ROUTES__TEST = 'app.notifications.dashboard.messages.test';
const ROUTES__DETAILS = 'app.notifications.dashboard.messages.details';
// DI
protected MessagingContext $mc;
protected EmailTemplateGeneratorFactory $emailTemplateGeneratorFactory;
protected CloudTranslator $cloudTranslator;
protected TranslationService $translationService;
protected ListItemProvider $listItemProvider;
protected MergeParamsProvider $mergeParamsProvider;
/**
* @param MessagingContext $mc
* @param EmailTemplateGeneratorFactory $emailTemplateGeneratorFactory
* @param CloudTranslator $cloudTranslator
* @param TranslationService $translationService
* @param ListItemProvider $listItemProvider
* @param MergeParamsProvider $mergeParamsProvider
*/
public function __construct(
MessagingContext $mc,
EmailTemplateGeneratorFactory $emailTemplateGeneratorFactory,
CloudTranslator $cloudTranslator,
TranslationService $translationService,
ListItemProvider $listItemProvider,
MergeParamsProvider $mergeParamsProvider
)
{
$this->mc = $mc;
$this->emailTemplateGeneratorFactory = $emailTemplateGeneratorFactory;
$this->cloudTranslator = $cloudTranslator;
$this->translationService = $translationService;
$this->listItemProvider = $listItemProvider;
$this->mergeParamsProvider = $mergeParamsProvider;
}
/**
* @param int $pagination
* @return AbstractHtmlView|RedirectResponse
*
* @Route(
* "/list/{pagination}",
* name = self::ROUTES__MAIN,
* requirements = {
* "pagination" = "[1-9]\d*",
* },
* defaults = {
* "pagination" = 0,
* },
* )
*/
public function mainAction(int $pagination = 0)
{
// AUDIT
$this->denyAccessUnlessMaybeGranted([
'app.notifications.messaging.general',
'app.notifications.messaging.urgent',
]);
$result = $this->doSearch(
Message::class,
'messages',
MessageSearch::class,
MessageSearchForm::class,
$pagination,
);
if ($result instanceof Response) {
return $result;
}
// avoids making duplicate queries
$result['messages'] = $result['messages']->getIterator();
$result['messagesIsGrantedArray'] = array_values(
array_filter(
array_map(
function (Message $message) {
try {
$this->audit($message);
return $message->getId();
} catch (\Throwable $exception) {
return null;
}
},
$result['messages']->getArrayCopy(),
)
)
);
return $this->html($result);
}
/**
* @param Request $request
* @param Message $message
* @return AbstractView|AjaxHtmlView|JsonView
*
* @Route(
* "/{message}/delete",
* name = MessagesController::ROUTES__DELETE,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function deleteAction(Request $request, Message $message): AbstractView
{
// AUDIT
$this->audit($message);
if ( ! $request->isXmlHttpRequest()) {
throw new NotFoundHttpException();
}
$form = $this->createForm(DummyForm::class);
if ($this->handleForm($form)) {
$id = $message->getId();
$this->getMessageLogic()->delete($message);
$this->getLoggingService()->createLog($message, $id);
return $this->jsonView([
'redirect' => true,
]);
}
return $this->ajax([
'message' => $message,
'form' => $form->createView(),
]);
}
/**
* @param Request $request
* @param Message $message
* @return AbstractView|AjaxHtmlView|JsonView
*
* @Route(
* "/{message}/unschedule",
* name = MessagesController::ROUTES__UNSCHEDULE,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function unscheduleAction(Request $request, Message $message): AbstractView
{
// AUDIT
$this->audit($message);
if ( ! $request->isXmlHttpRequest()) {
throw new NotFoundHttpException();
}
$form = $this->createForm(DummyForm::class);
if ($this->handleForm($form)) {
$this->getMessageLogic()->unschedule($message);
$this->getLoggingService()->createLog($message);
return $this->jsonView([
'redirect' => true,
]);
}
return $this->ajax([
'message' => $message,
'form' => $form->createView(),
]);
}
/**
* @param Request $request
* @return AbstractView|RedirectResponse
*
* @Route(
* "/create",
* name = MessagesController::ROUTES__CREATE,
* )
*/
public function createAction(Request $request)
{
// AUDIT
$this->denyAccessUnlessMaybeGranted([
'app.notifications.messaging.general',
'app.notifications.messaging.urgent',
]);
// check if we are cloning
if ($request->query->has('clone')) {
$starter = $this->getEntityManager()->getRepository(Message::class)->find($request->query->getInt('clone'));
} else if ($request->query->has('template')) {
$starter = $this->getEntityManager()->getRepository(Template::class)->find($request->query->getInt('template'));
} else {
throw new \Exception();
}
$this->denyAccessUnlessMaybeGranted(
sprintf('app.notifications.messaging.%s', $starter->isUrgent() ? 'urgent' : 'general')
);
// double check to make sure the template is sendable
if ($starter instanceof Template && ! $starter->isSendable()) {
throw new \Exception();
}
$prefillParams = null;
$formData = $request->request->get('message_data_form');
if (isset($formData['prefillParams'])) {
$prefillParams = json_decode($formData['prefillParams'], true);
if (json_last_error() !== JSON_ERROR_NONE) {
$prefillParams = null;
}
}
$messageLogic = $this->getMessageLogic();
/** @var Message $message */
$message = $messageLogic->init(new Message(), $starter, $prefillParams);
// generate the form
$form = $this->createForm(MessageDataForm::class, $message, ['prefillParams' => $messageLogic->getLastPrefillParams()]);
// handle form submission
if ($this->handleForm($form)) {
// create the new object
$this->getMessageLogic()->create($message);
$redirectRoute = self::ROUTES__MANAGE;
if ( ! empty($this->translationService->getTranslationLocales()) && ! $request->query->has('jump')) {
$redirectRoute = self::ROUTES__TRANSLATIONS;
$this->translationService->translate($message);
}
$this->getLoggingService()->createLog($message);
if (($this->generateUrl(self::ROUTES__MAIN) === $request->query->get('jump'))) {
return $this->redirectToRoute(self::ROUTES__UPDATE, [
'message' => $message->getId(),
'saved' => true,
]);
}
return $this->jumpOrRedirect(
$this->redirectToRoute(
$redirectRoute,
[
'message' => $message->getId(),
]
)
);
}
return $this->html([
'starter' => $starter,
'message' => $message,
'form' => $form->createView(),
'mergeParams' => $this->mergeParamsProvider->get($message),
]);
}
/**
* @param Request $request
* @param Message $message
* @return AbstractView|RedirectResponse
*
* @Route(
* "/{message}/update/check_form",
* name = MessagesController::ROUTES__CHECK_UPDATE_FORM,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function checkIfUpdateFormValidAction(Request $request, Message $message): JsonView
{
// AUDIT
$this->audit($message);
$form = $this->createForm(MessageDataForm::class, $message);
$form->handleRequest($request);
return $this->jsonView([
'isValid' => $form->isValid(),
]);
}
/**
* @param Request $request
* @param Message $message
* @return AbstractView|RedirectResponse
*
* @Route(
* "/{message}/update",
* name = MessagesController::ROUTES__UPDATE,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function updateAction(Request $request, Message $message)
{
// AUDIT
$this->audit($message);
$form = $this->createForm(MessageDataForm::class, $message);
if ($this->handleForm($form)) {
if ($this->getMessageLogic()->isTranslatableFieldsModified($message)) {
$message->markFlag(AbstractNotification::FLAGS__MODIFIED_SINCE_TRANSLATION);
}
$this->getMessageLogic()->update($message);
$redirectRoute = self::ROUTES__MANAGE;
$shouldRedirectToTranslatePage = (
! empty($this->translationService->getTranslationLocales()) &&
! $request->query->has('jump')
);
if ($shouldRedirectToTranslatePage) {
$redirectRoute = self::ROUTES__TRANSLATIONS;
$translatedLocales = array_map(function (Translation $translation) {
return $translation->getLocale();
}, $message->getTranslationsAsArray());
$untranslatedLocales = array_diff($this->translationService->getTranslationLocales(), $translatedLocales);
$shouldDismissManualTranslationEdits = $form->get('forceTranslation')->getData() === '1';
$shouldTranslate = (
!empty($untranslatedLocales) ||
$message->hasFlag(AbstractNotification::FLAGS__MODIFIED_SINCE_TRANSLATION) ||
$shouldDismissManualTranslationEdits
);
if ($shouldTranslate) {
$this->translationService->translate($message, $shouldDismissManualTranslationEdits);
}
}
$this->getLoggingService()->createLog($message);
return $this->jumpOrRedirect(
$this->redirectToRoute($redirectRoute, [
'message' => $message->getId(),
])
);
}
$hasManualTranslation = false;
foreach ($message->getTranslations() as $translation) {
if ($translation->hasFlag(Translation::FLAGS__MANUAL)) {
$hasManualTranslation = true;
}
}
return $this->html([
'hasManualTranslation' => $hasManualTranslation,
'message' => $message,
'form' => $form->createView(),
'mergeParams' => $this->mergeParamsProvider->get($message),
]);
}
/**
* @param Message $message
* @return AbstractView|RedirectResponse
*
* @Route(
* "/{message}/translations",
* name = MessagesController::ROUTES__TRANSLATIONS,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function translationsAction(Message $message)
{
// AUDIT
$this->audit($message);
return $this->html([
'message' => $message,
'statuses' => $this->checkTranslationsAction($message)->getData(),
'humanReadableLocaleNames' => Locales::RFC4646_HUMAN_READABLE,
]);
}
/**
* @param Message $message
* @return JsonView
*
* @Route(
* "/{message}/check_translation_progress",
* name = MessagesController::ROUTES__CHECK_TRANSLATION_PROGRESS,
* requirements = {
* "message" = "[1-9]\d*",
* }
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function checkTranslationsAction(Message $message): JsonView
{
// AUDIT
$this->audit($message);
/** @var TranslationRepository $translationRepository */
$translationRepository = $this->getEntityManager()->getRepository(Translation::class);
// create array to hold stats of all the translations
$statuses = array_fill_keys(
$this->translationService->getTranslationLocales(),
null,
);
// loop over each translation
$ready = true;
foreach (array_keys($statuses) as $locale) {
// attempt to find the translation
$translation = $translationRepository->findOneBy([
'notification' => $message,
'locale' => $locale,
]);
// if not found, we have not been started yet (return null status)
if ( ! $translation instanceof Translation) {
$statuses[$locale] = null;
$ready = false;
continue;
}
// it was found, set if it is ready or not
$statuses[$locale] = $translation->isReady();
// track the status of all
$ready = $ready && $statuses[$locale];
}
return $this->jsonView([
'ready' => $ready,
'statuses' => $statuses,
]);
}
/**
* @param Message $message
* @return AbstractView|RedirectResponse
*
* @Route(
* "/{message}/manage",
* name = MessagesController::ROUTES__MANAGE,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function manageAction(Message $message)
{
// AUDIT
$this->audit($message);
// init the date to end of day if not already set
if (empty($message->getWebsiteEndDateTime())) {
$message->setWebsiteEndDateTime(DateTimeUtils::tomorrow(
$this->getLocaleManager()->effectiveTimezone()
));
}
$languages = [];
foreach ($this->translationService->getTranslationLocales() as $locale) {
if (!isset(Locales::RFC4646_HUMAN_READABLE[$locale])) {
throw new \Exception('Locale is missing human readable name');
}
$humanReadableLocaleName = Locales::RFC4646_HUMAN_READABLE[$locale];
$languages[$locale] = [
'locale' => $locale,
'humanReadableLocaleName' => $humanReadableLocaleName,
'isActive' => false,
];
}
foreach ($message->getTranslations() as $translation) {
if (!isset(Locales::RFC4646_HUMAN_READABLE[$translation->getLocale()])) {
throw new \Exception('Locale is missing human readable name');
}
$humanReadableLocaleName = Locales::RFC4646_HUMAN_READABLE[$translation->getLocale()];
$languages[$translation->getLocale()] = [
'locale' => $translation->getLocale(),
'humanReadableLocaleName' => $humanReadableLocaleName,
'isActive' => $translation->hasFlag(Translation::FLAGS__MANUAL),
];
}
/** @var TranslationRepository $translationRepository */
$translationRepository = $this->getRepository(Translation::class);
$translations = [];
foreach ($this->translationService->getTranslationLocales() as $locale) {
$existingTranslation = $translationRepository->findOneBy([
'locale' => $locale,
'notification' => $message,
]);
if ($existingTranslation instanceof Translation) {
$translations[$locale] = $existingTranslation;
} else {
$translation = new Translation();
$translation->setLocale($locale);
$translation->setNotification($message);
$translation->setTenant($message->getTenant());
$message->addTranslation($translation);
}
}
// make form
$form = $this->createForm(MessageChannelsForm::class, $message);
// attempt form submit
if ($this->handleForm($form)) {
foreach ($message->getTranslationsAsArray() as $translation) {
if ($this->translationService->isModified($translation)) {
$translation->markFlag(Translation::FLAGS__MANUAL);
$this->getEntityManager()->persist($translation);
}
}
// save changes to message
$this->getMessageLogic()->update($message);
$this->getLoggingService()->createLog($message);
// determine if we are sending and handle it if so
if ($form->get('action')->getData() === 'send') {
$this->getMessageLogic()->broadcast(
$message->setScheduledAt(
($form->get('scheduled')->getData() === true)
? $form->get('scheduledAt')->getData()
: null
),
);
return $this->jumpOrRedirectToRoute(self::ROUTES__MAIN);
}
return $this->jumpOrRedirectToRoute(self::ROUTES__MANAGE, [
'message' => $message->getId(),
'saved' => true,
]);
}
return $this->html([
'message' => $message,
'form' => $form->createView(),
'configs' => $this->mc->getConfigs(),
'humanReadableLocales' => Locales::RFC4646_HUMAN_READABLE,
'languages' => $languages,
'translations' => $translations,
'counts' => [
'total' => $this->listItemProvider->countByLists($message->getListsAsArray()),
'lists' =>
array_combine(
array_map(
static function (AbstractList $list) {
return $list->getId();
},
$message->getListsAsArray(),
),
array_map(
function (AbstractList $list) {
return $this->listItemProvider->countByLists($list);
},
$message->getListsAsArray(),
)
),
],
]);
}
/**
* @param Message $message
* @param string $locale
* @return JsonView
*
* @Route(
* "/{message}/{locale}/is_translation_modified",
* name = MessagesController::ROUTES__DETECT_TRANSLATION_CHANGE,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function isTranslationModifiedAction(Message $message, string $locale)
{
// AUDIT
$this->audit($message);
$form = $this->createForm(MessageChannelsForm::class, $message);
$form->handleRequest($this->getRequest());
$translation = $message->getTranslation($locale);
if ( ! ($translation instanceof Translation)) {
return $this->jsonView([
'isModifiedOverall' => false,
'isScriptModified' => false,
'isRecordingModified' => false,
]);
}
if ($translation->hasFlag(Translation::FLAGS__MANUAL) || $this->translationService->isModified($translation)) {
return $this->jsonView([
'isModifiedOverall' => true,
'isScriptModified' => $this->translationService->isPropertyModified('script', $translation),
'isRecordingModified' => $this->translationService->isRecordingModified($translation),
]);
}
return $this->jsonView([
'isModifiedOverall' => false,
'isScriptModified' => false,
'isRecordingModified' => false,
]);
}
/**
* @param School $school
* @param Template $template
* @param Student $student
* @return Response
*
* @Route(
* "/email/preview/school/{school}/template/{template}/student/{student}",
* name = MessagesController::ROUTES__STUDENT_EMAIL_PREVIEW,
* requirements={
* "school" = "[1-9]\d*",
* "template" = "[1-9]\d*",
* "student" = "[1-9]\d*",
* }
* )
* @ParamConverter(
* "school",
* class = School::class,
* )
* @ParamConverter(
* "template",
* class = Template::class,
* )
* @ParamConverter(
* "student",
* class = Student::class,
* )
*/
public function studentEmailPreviewAction(School $school, Template $template, Student $student): Response
{
// AUDIT
$this->denyAccessUnlessGranted(
sprintf('app.notifications.messaging.%s', $template->isUrgent() ? 'urgent' : 'general')
);
// disable the profiler
$this->disableProfiling();
$merger = (new MessageContentGenerator())
->setStudent($student)
->setLocale($template->getLocale());
if ($template->getTenant() instanceof Tenant) {
$merger->setTimezone($template->getTenant()->getLocale()->getTimezone());
}
$message = new Message();
$message->setTenant($template->getTenant());
$message->setLocale($template->getLocale() ?? Locales::RFC4646_DEFAULT);
$message->setEmailFrom('');
$message->setEmailName('');
$message->setStatus(AbstractNotification::STATUSES__READY);
$message->setHtml(true);
$message->setDescription($template->getDescription());
$twigParameters = $this->emailTemplateGeneratorFactory->create()
->applyCore($message)
->applySchool($school)
->applyStudent($student);
$twigParameters->add(['translate' => '']);
$sendgridEmailMessage = (new SendgridEmailMessage())
->setTenant($template->getTenant())
->setSubject(html_entity_decode($merger->render($message->getEmailSubject()), ENT_QUOTES))
->setBodyHtml($merger->render($message->getEmailContent()))
->setTwigTemplate('@ProductsNotifications/emails/customer.html.twig')
->setTwigParameters($twigParameters->all());
return new Response($this->getSendgridEmailMessenger()->render($sendgridEmailMessage));
}
/**
* @param Message $message
* @param string|null $locale
* @return Response
*
* @Route(
* "/{message}/manage/email/preview/{school}/{locale}",
* name = MessagesController::ROUTES__EMAIL_PREVIEW,
* requirements = {
* "message" = "[1-9]\d*",
* },
* defaults = {
* "school" = null,
* "locale" = Locales::RFC4646_DEFAULT,
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
* @ParamConverter(
* "school",
* class = School::class,
* )
*/
public function emailPreviewAction(Message $message, School $school = null, ?string $locale = Locales::RFC4646_DEFAULT): Response
{
// AUDIT
$this->audit($message);
// disable the profiler
$this->disableProfiling();
// if empty school, load up from the message or load up the district
if ( ! $school) {
$school = $message->getBranding() ?: $this->getEntityManager()->getRepository(School::class)->findOneBy([
'type' => School::TYPES__DISTRICT,
]);
}
if ( ! $school instanceof School) {
throw new \Exception();
}
$notification = $message->getNotification($locale);
return new Response(
$this->getSendgridEmailMessenger()->render(
(new SendgridEmailMessage())
->setTenant($message->getTenant())
->setTemplateRenderDisabled($message->isHtml())
->setBodyHtml($notification->getEmailContent())
->setTwigTemplate('@ProductsNotifications/emails/customer.html.twig')
->setTwigParameters(
$this->emailTemplateGeneratorFactory->create()
->applyCore($message)
->applySchool($school)
->applyMessage($message)
->all()
)
)
);
}
/**
* @param Message $message
* @return DocHtmlView
*
* @Route(
* "/{message}/report",
* name = MessagesController::ROUTES__REPORT,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function reportAction(Message $message): DocHtmlView
{
// AUDIT
$this->audit($message);
return $this->html([
'configs' => $this->mc->getConfigs(),
'message' => $message,
]);
}
/**
* @param Message $message
* @param int $pagination
* @return DocHtmlView|RedirectResponse
*
* @Route(
* "/{message}/logs/{pagination}",
* name = MessagesController::ROUTES__LOGS,
* requirements = {
* "message" = "[1-9]\d*",
* "pagination" = "[1-9]\d*",
* },
* defaults = {
* "pagination" = 0,
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function logsAction(Message $message, int $pagination = 0)
{
// AUDIT
$this->audit($message);
$result = $this->doSearch(
AbstractContactAttempt::class,
'attempts',
(new ContactAttemptSearch())->setNotification($message),
ContactAttemptSearchForm::class,
$pagination,
);
return ($result instanceof Response) ? $result : $this->html(
array_merge(
$result,
[
'configs' => $this->mc->getConfigs(),
'message' => $message,
],
),
);
}
/**
* @param Message $message
* @return DocHtmlView
*
* @Route(
* "/{message}/debugging",
* name = MessagesController::ROUTES__DEBUGGING,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function debuggingAction(Message $message): DocHtmlView
{
// AUDIT
$this->audit($message);
return $this->html([
'configs' => $this->mc->getConfigs(),
'message' => $message,
]);
}
/**
* @param Message $message
* @return AbstractHtmlView
*
* @Route(
* "/{message}/filtered_logs/{pagination}",
* name = self::ROUTES__FILTERED_LOGS,
* requirements = {
* "message" = "[1-9]\d*",
* "pagination" = "[1-9]\d*",
* },
* defaults = {
* "pagination" = 0,
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function filteredLogsAction(Message $message, int $pagination = 0): AbstractHtmlView
{
// AUDIT
$this->audit($message);
$result = $this->doSearch(
AbstractContactAttempt::class,
'attempts',
(new ContactAttemptSearch())->setNotification($message),
ContactAttemptSearchForm::class,
$pagination,
);
return $this->ajax(
array_merge(
$result,
[
'configs' => $this->mc->getConfigs(),
'message' => $message,
],
),
);
}
/**
* @param Request $request
* @param Message $message
* @return AjaxHtmlView|JsonView
*
* @Route(
* "/{message}/_test",
* name = MessagesController::ROUTES__TEST,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function testAction(Request $request, Message $message)
{
// AUDIT
$this->audit($message);
// enforce ajax
if ( ! $request->isXmlHttpRequest()) {
throw new NotFoundHttpException();
}
// determine the logged in user
$user = $this->getGlobalContext()->getEffectiveAccount();
// create form to capture test contacts
$form = $this->createForm(MessageTestForm::class, [
'contacts' => [
array_values(array_filter([
new EmailTester($user->getEmail()),
($user->getSystemProfile()->getMobilePhone()) ? new PhoneTester($user->getSystemProfile()->getMobilePhone()) : null,
]))
],
]);
// make form to handle the possibly new changes to the message as based on the manage page
$messageForm = $this->createForm(MessageChannelsForm::class, $message);
// handle contacts form
if ($this->handleForm($form)) {
$messageData = [];
parse_str($form->getData()['data'], $messageData);
// handle this form submission as well
// have to pull data from the query string
if ($this->submitForm($messageForm, $messageData[$messageForm->getName()])) {
// message should be setup as we need it, can now run the test
try {
$test = $this->getMessageLogic()->test(
$message,
array_merge(...$form->getData()['contacts'])
);
} catch (\Exception $e) {
$form->addError(new FormError('Error sending tests, not all tests may have been sent.'));
}
}
// close the modal only if no errors
if ( ! $form->getErrors()->count()) {
return $this->jsonView([
'close' => true,
]);
}
}
return $this->ajax([
'message' => $message,
'form' => $form->createView(),
'messageFormName' => $messageForm->getName(),
]);
}
/**
* @param Message $message
* @return DocHtmlView
*
* @Route(
* "/{message}/details",
* name = MessagesController::ROUTES__DETAILS,
* requirements = {
* "message" = "[1-9]\d*",
* },
* )
* @ParamConverter(
* "message",
* class = Message::class,
* )
*/
public function detailsAction(Message $message): DocHtmlView
{
// AUDIT
$this->denyAccessUnlessGranted(
sprintf('app.notifications.messaging.%s', $message->isUrgent() ? 'urgent' : 'general')
);
return $this->html([
'message' => $message,
'humanReadableLocales' => Locales::RFC4646_HUMAN_READABLE
]);
}
/**
* @return MessageLogic|object
*/
private function getMessageLogic(): MessageLogic
{
return $this->get(__METHOD__);
}
/**
* @return SendgridEmailMessenger|object
*/
private function getSendgridEmailMessenger(): SendgridEmailMessenger
{
return $this->get(__METHOD__);
}
}