diff options
| -rw-r--r-- | app/Http/RequestHandlers/BroadcastAction.php | 31 | ||||
| -rw-r--r-- | app/Http/RequestHandlers/BroadcastPage.php | 25 | ||||
| -rw-r--r-- | app/Http/RequestHandlers/ControlPanel.php | 11 | ||||
| -rw-r--r-- | app/Http/Routes/WebRoutes.php | 4 | ||||
| -rw-r--r-- | app/Services/MessageService.php | 30 | ||||
| -rw-r--r-- | resources/views/admin/broadcast.phtml | 22 | ||||
| -rw-r--r-- | resources/views/admin/control-panel.phtml | 19 | ||||
| -rw-r--r-- | tests/app/Http/RequestHandlers/ControlPanelControllerTest.php | 5 |
8 files changed, 67 insertions, 80 deletions
diff --git a/app/Http/RequestHandlers/BroadcastAction.php b/app/Http/RequestHandlers/BroadcastAction.php index 8a5c09ed6c..fcbda6983c 100644 --- a/app/Http/RequestHandlers/BroadcastAction.php +++ b/app/Http/RequestHandlers/BroadcastAction.php @@ -58,14 +58,13 @@ class BroadcastAction implements RequestHandlerInterface */ public function handle(ServerRequestInterface $request): ResponseInterface { - $user = Validator::attributes($request)->user(); - $params = (array) $request->getParsedBody(); - $body = $params['body']; - $subject = $params['subject']; - $to = $params['to']; + $recipients = $this->message_service->recipientTypes(); - $ip = Validator::attributes($request)->string('client-ip'); - $to_users = $this->message_service->recipientUsers($to); + $user = Validator::attributes($request)->user(); + $to = Validator::attributes($request)->isInArrayKeys($recipients)->string('to'); + $ip = Validator::attributes($request)->string('client-ip'); + $body = Validator::parsedBody($request)->isNotEmpty()->string('body'); + $subject = Validator::parsedBody($request)->isNotEmpty()->string('subject'); if ($body === '' || $subject === '') { return redirect(route(BroadcastPage::class, [ @@ -75,20 +74,20 @@ class BroadcastAction implements RequestHandlerInterface ])); } - $errors = false; - - foreach ($to_users as $to_user) { + foreach ($this->message_service->recipientUsers($to) as $to_user) { if ($this->message_service->deliverMessage($user, $to_user, $subject, $body, '', $ip)) { - FlashMessages::addMessage(I18N::translate('The message was successfully sent to %s.', e($to_user->realName())), 'success'); + FlashMessages::addMessage( + I18N::translate('The message was successfully sent to %s.', e($to_user->realName())), + 'success' + ); } else { - $errors = true; + FlashMessages::addMessage( + I18N::translate('The message was not sent to %s.', e($to_user->realName())), + 'danger' + ); } } - if ($errors) { - FlashMessages::addMessage(I18N::translate('The message was not sent.'), 'danger'); - } - return redirect(route(ControlPanel::class)); } } diff --git a/app/Http/RequestHandlers/BroadcastPage.php b/app/Http/RequestHandlers/BroadcastPage.php index 9de46dae2c..87f499f1d4 100644 --- a/app/Http/RequestHandlers/BroadcastPage.php +++ b/app/Http/RequestHandlers/BroadcastPage.php @@ -19,7 +19,6 @@ declare(strict_types=1); namespace Fisharebest\Webtrees\Http\RequestHandlers; -use Fisharebest\Webtrees\Contracts\UserInterface; use Fisharebest\Webtrees\Http\ViewResponseTrait; use Fisharebest\Webtrees\Services\MessageService; use Fisharebest\Webtrees\Validator; @@ -53,28 +52,20 @@ class BroadcastPage implements RequestHandlerInterface */ public function handle(ServerRequestInterface $request): ResponseInterface { - $user = Validator::attributes($request)->user(); - $params = $request->getQueryParams(); - $body = $params['body'] ?? ''; - $subject = $params['subject'] ?? ''; - $to = $params['to']; + $recipient_types = $this->message_service->recipientTypes(); - $to_names = $this->message_service->recipientUsers($to) - ->map(static function (UserInterface $user): string { - return $user->realName(); - }); + $user = Validator::attributes($request)->user(); + $to = Validator::attributes($request)->isInArrayKeys($recipient_types)->string('to'); - $title = $this->message_service->recipientDescription($to); + $title = $recipient_types[$to]; $this->layout = 'layouts/administration'; return $this->viewResponse('admin/broadcast', [ - 'body' => $body, - 'from' => $user, - 'subject' => $subject, - 'title' => $title, - 'to' => $to, - 'to_names' => $to_names, + 'from' => $user, + 'title' => $title, + 'to' => $to, + 'recipients' => $this->message_service->recipientUsers($to), ]); } } diff --git a/app/Http/RequestHandlers/ControlPanel.php b/app/Http/RequestHandlers/ControlPanel.php index 8c0db3ee7c..e1a7e234e5 100644 --- a/app/Http/RequestHandlers/ControlPanel.php +++ b/app/Http/RequestHandlers/ControlPanel.php @@ -53,6 +53,7 @@ use Fisharebest\Webtrees\Registry; use Fisharebest\Webtrees\Repository; use Fisharebest\Webtrees\Services\AdminService; use Fisharebest\Webtrees\Services\HousekeepingService; +use Fisharebest\Webtrees\Services\MessageService; use Fisharebest\Webtrees\Services\ModuleService; use Fisharebest\Webtrees\Services\ServerCheckService; use Fisharebest\Webtrees\Services\TreeService; @@ -79,10 +80,12 @@ class ControlPanel implements RequestHandlerInterface private AdminService $admin_service; - private ModuleService $module_service; - private HousekeepingService $housekeeping_service; + private MessageService $message_service; + + private ModuleService $module_service; + private ServerCheckService $server_check_service; private TreeService $tree_service; @@ -96,6 +99,7 @@ class ControlPanel implements RequestHandlerInterface * * @param AdminService $admin_service * @param HousekeepingService $housekeeping_service + * @param MessageService $message_service * @param ModuleService $module_service * @param ServerCheckService $server_check_service * @param TreeService $tree_service @@ -105,6 +109,7 @@ class ControlPanel implements RequestHandlerInterface public function __construct( AdminService $admin_service, HousekeepingService $housekeeping_service, + MessageService $message_service, ModuleService $module_service, ServerCheckService $server_check_service, TreeService $tree_service, @@ -113,6 +118,7 @@ class ControlPanel implements RequestHandlerInterface ) { $this->admin_service = $admin_service; $this->housekeeping_service = $housekeeping_service; + $this->message_service = $message_service; $this->module_service = $module_service; $this->server_check_service = $server_check_service; $this->tree_service = $tree_service; @@ -152,6 +158,7 @@ class ControlPanel implements RequestHandlerInterface 'moderators' => $this->user_service->moderators(), 'unapproved' => $this->user_service->unapproved(), 'unverified' => $this->user_service->unverified(), + 'recipients' => $this->message_service->recipientTypes(), 'all_trees' => $this->tree_service->all(), 'changes' => $this->totalChanges(), 'individuals' => $this->totalIndividuals(), diff --git a/app/Http/Routes/WebRoutes.php b/app/Http/Routes/WebRoutes.php index 3e3033ff55..f160252a78 100644 --- a/app/Http/Routes/WebRoutes.php +++ b/app/Http/Routes/WebRoutes.php @@ -348,8 +348,8 @@ class WebRoutes ]); $router->get(ControlPanel::class, ''); - $router->get(BroadcastPage::class, '/broadcast'); - $router->post(BroadcastAction::class, '/broadcast'); + $router->get(BroadcastPage::class, '/broadcast/{to}'); + $router->post(BroadcastAction::class, '/broadcast/{to}'); $router->get(CleanDataFolder::class, '/clean'); $router->post(DeletePath::class, '/delete-path'); $router->get(EmailPreferencesPage::class, '/email'); diff --git a/app/Services/MessageService.php b/app/Services/MessageService.php index f3788f1c7d..4e543e66b1 100644 --- a/app/Services/MessageService.php +++ b/app/Services/MessageService.php @@ -38,6 +38,10 @@ use function view; */ class MessageService { + private const BROADCAST_ALL = 'all'; + private const BROADCAST_NEVER = 'never'; + private const BROADCAST_GONE = 'gone'; + private EmailService $email_service; private UserService $user_service; @@ -178,13 +182,13 @@ class MessageService { switch ($to) { default: - case 'all': + case self::BROADCAST_ALL: return $this->user_service->all(); - case 'never_logged': + case self::BROADCAST_NEVER: return $this->user_service->all()->filter(static function (UserInterface $user): bool { return $user->getPreference(UserInterface::PREF_IS_ACCOUNT_APPROVED) === '1' && $user->getPreference(UserInterface::PREF_TIMESTAMP_REGISTERED) > $user->getPreference(UserInterface::PREF_TIMESTAMP_ACTIVE); }); - case 'last_6mo': + case self::BROADCAST_GONE: $six_months_ago = Registry::timestampFactory()->now()->subtractMonths(6)->timestamp(); return $this->user_service->all()->filter(static function (UserInterface $user) use ($six_months_ago): bool { @@ -196,21 +200,17 @@ class MessageService } /** - * @param string $to + * Recipients for broadcast messages * - * @return string + * @return array<string,string> */ - public function recipientDescription(string $to): string + public function recipientTypes(): array { - switch ($to) { - default: - case 'all': - return I18N::translate('Send a message to all users'); - case 'never_logged': - return I18N::translate('Send a message to users who have never signed in'); - case 'last_6mo': - return I18N::translate('Send a message to users who have not signed in for 6 months'); - } + return [ + self::BROADCAST_ALL => I18N::translate('Send a message to all users'), + self::BROADCAST_NEVER => I18N::translate('Send a message to users who have never signed in'), + self::BROADCAST_GONE => I18N::translate('Send a message to users who have not signed in for 6 months'), + ]; } /** diff --git a/resources/views/admin/broadcast.phtml b/resources/views/admin/broadcast.phtml index 44e25076af..e204e62feb 100644 --- a/resources/views/admin/broadcast.phtml +++ b/resources/views/admin/broadcast.phtml @@ -3,17 +3,14 @@ use Fisharebest\Webtrees\Contracts\UserInterface; use Fisharebest\Webtrees\Http\RequestHandlers\BroadcastAction; use Fisharebest\Webtrees\Http\RequestHandlers\ControlPanel; -use Fisharebest\Webtrees\Http\RequestHandlers\HomePage; use Fisharebest\Webtrees\I18N; use Illuminate\Support\Collection; /** - * @var string $body - * @var UserInterface $from - * @var string $subject - * @var string $title - * @var string $to - * @var Collection<int,string> $to_names + * @var UserInterface $from + * @var string $title + * @var string $to + * @var Collection<int,UserInterface> $recipients */ ?> @@ -22,7 +19,7 @@ use Illuminate\Support\Collection; <h1><?= $title ?></h1> -<form method="post" action="<?= e(route(BroadcastAction::class)) ?>"> +<form method="post" action="<?= e(route(BroadcastAction::class, ['to' => $to])) ?>"> <?= csrf_field() ?> <div class="row form-group mb-3"> @@ -39,8 +36,7 @@ use Illuminate\Support\Collection; <?= I18N::translateContext('Email recipient', 'To') ?> </label> <div class="col-sm-9"> - <input type="hidden" name="to" value="<?= e($to) ?>"> - <input class="form-control" id="to" type="text" value="<?= e($to_names->implode(', ')) ?>" disabled> + <input class="form-control" id="to" type="text" value="<?= $recipients->map(static fn (UserInterface $user): string => e($user->realName()))->implode(', ') ?>" disabled> </div> </div> @@ -49,7 +45,7 @@ use Illuminate\Support\Collection; <?= I18N::translate('Subject') ?> </label> <div class="col-sm-9"> - <input class="form-control" id="subject" type="text" name="subject" value="<?= e($subject) ?>" required="required"> + <input class="form-control" id="subject" type="text" name="subject" required="required"> </div> </div> @@ -58,7 +54,7 @@ use Illuminate\Support\Collection; <?= I18N::translate('Message') ?> </label> <div class="col-sm-9"> - <textarea class="form-control" id="body" name="body" rows="5" dir="auto" required="required"><?= e($body) ?></textarea> + <textarea class="form-control" id="body" name="body" rows="5" dir="auto" required="required"></textarea> </div> </div> @@ -68,7 +64,7 @@ use Illuminate\Support\Collection; <button type="submit" class="btn btn-primary"> <?= I18N::translate('Send') ?> </button> - <a class="btn btn-link" href="<?= e(route(HomePage::class)) ?>"> + <a class="btn btn-link" href="<?= e(route(ControlPanel::class)) ?>"> <?= I18N::translate('cancel') ?> </a> </div> diff --git a/resources/views/admin/control-panel.phtml b/resources/views/admin/control-panel.phtml index 0e40e4e45b..36cd60f1d2 100644 --- a/resources/views/admin/control-panel.phtml +++ b/resources/views/admin/control-panel.phtml @@ -128,6 +128,7 @@ use Illuminate\Support\Collection; * @var Collection<array-key,int> $notes * @var NoteListModule|null $note_list_module * @var Collection<int,ModuleInterface> $other_modules + * @var array<string,string> $recipients * @var Collection<int,ModuleReportInterface> $report_modules_disabled * @var Collection<int,ModuleReportInterface> $report_modules_enabled * @var Collection<array-key,int> $repositories @@ -534,24 +535,14 @@ use Illuminate\Support\Collection; </div> <div class="col-sm-6"> <ul class="fa-ul mx-0"> + <?php foreach ($recipients as $to => $recipient) : ?> <li> <span class="fa-li"><?= view('icons/email') ?></span> - <a href="<?= e(route(BroadcastPage::class, ['to' => 'all'])) ?>"> - <?= I18N::translate('Send a message to all users') ?> - </a> - </li> - <li> - <span class="fa-li"><?= view('icons/email') ?></span> - <a href="<?= e(route(BroadcastPage::class, ['to' => 'never_logged'])) ?>"> - <?= I18N::translate('Send a message to users who have never signed in') ?> - </a> - </li> - <li> - <span class="fa-li"><?= view('icons/email') ?></span> - <a href="<?= e(route(BroadcastPage::class, ['to' => 'last_6mo'])) ?>"> - <?= I18N::translate('Send a message to users who have not signed in for 6 months') ?> + <a href="<?= e(route(BroadcastPage::class, ['to' => $to])) ?>"> + <?= $recipient ?> </a> </li> + <?php endforeach ?> </ul> </div> </div> diff --git a/tests/app/Http/RequestHandlers/ControlPanelControllerTest.php b/tests/app/Http/RequestHandlers/ControlPanelControllerTest.php index b4ef19fd97..29bbc233a6 100644 --- a/tests/app/Http/RequestHandlers/ControlPanelControllerTest.php +++ b/tests/app/Http/RequestHandlers/ControlPanelControllerTest.php @@ -21,8 +21,10 @@ namespace Fisharebest\Webtrees\Http\RequestHandlers; use Fig\Http\Message\StatusCodeInterface; use Fisharebest\Webtrees\Services\AdminService; +use Fisharebest\Webtrees\Services\EmailService; use Fisharebest\Webtrees\Services\GedcomImportService; use Fisharebest\Webtrees\Services\HousekeepingService; +use Fisharebest\Webtrees\Services\MessageService; use Fisharebest\Webtrees\Services\ModuleService; use Fisharebest\Webtrees\Services\ServerCheckService; use Fisharebest\Webtrees\Services\TimeoutService; @@ -46,6 +48,7 @@ class ControlPanelControllerTest extends TestCase public function testControlPanel(): void { $admin_service = new AdminService(); + $message_service = new MessageService(new EmailService(), new UserService()); $module_service = new ModuleService(); $housekeeping_service = new HousekeepingService(); $server_check_service = new ServerCheckService(); @@ -54,7 +57,7 @@ class ControlPanelControllerTest extends TestCase $tree_service = new TreeService($gedcom_import_service); $upgrade_service = new UpgradeService($timeout_service); $user_service = new UserService(); - $handler = new ControlPanel($admin_service, $housekeeping_service, $module_service, $server_check_service, $tree_service, $upgrade_service, $user_service); + $handler = new ControlPanel($admin_service, $housekeeping_service, $message_service, $module_service, $server_check_service, $tree_service, $upgrade_service, $user_service); $request = self::createRequest(); $response = $handler->handle($request); |
