From 713f8222e4994b05add851c0bf2fecebe64ffadf Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Thu, 2 Feb 2023 22:53:51 +0100 Subject: [PATCH] Unified user notifications --- includes/controller/angeltypes_controller.php | 2 +- .../controller/shift_entries_controller.php | 4 +- .../controller/user_angeltypes_controller.php | 24 ++---- includes/helper/email_helper.php | 2 +- includes/helper/message_helper.php | 76 ++++++++----------- includes/pages/admin_shifts.php | 1 + includes/pages/guest_login.php | 6 +- includes/pages/schedule/ImportSchedule.php | 15 ++-- includes/view/ShiftEntry_view.php | 4 +- includes/view/UserAngelTypes_view.php | 8 +- includes/view/User_view.php | 2 +- resources/lang/de_DE/default.po | 4 +- resources/lang/pt_BR/default.po | 4 +- resources/views/layouts/parts/messages.twig | 10 +-- resources/views/pages/login.twig | 4 + src/Controllers/Admin/FaqController.php | 2 +- src/Controllers/Admin/NewsController.php | 2 +- src/Controllers/Admin/QuestionsController.php | 4 +- src/Controllers/Admin/UserShirtController.php | 2 +- .../Admin/UserWorkLogController.php | 2 +- src/Controllers/AuthController.php | 7 +- src/Controllers/FaqController.php | 2 +- src/Controllers/HasUserNotifications.php | 29 +++++-- src/Controllers/NewsController.php | 2 - src/Controllers/NotificationType.php | 13 ++++ src/Controllers/PasswordResetController.php | 7 +- src/Controllers/QuestionsController.php | 4 +- src/Controllers/SettingsController.php | 18 ++--- src/Middleware/ErrorHandler.php | 6 +- src/Renderer/Twig/Extensions/Legacy.php | 1 - src/Renderer/Twig/Extensions/Notification.php | 46 +++++++++++ src/Renderer/TwigServiceProvider.php | 2 + .../Controllers/Admin/FaqControllerTest.php | 18 +---- .../Controllers/Admin/NewsControllerTest.php | 17 +---- tests/Unit/Controllers/AuthControllerTest.php | 19 ++--- tests/Unit/Controllers/ControllerTest.php | 23 +++++- .../Controllers/HasUserNotificationsTest.php | 18 +++-- .../PasswordResetControllerTest.php | 27 +++---- .../Controllers/SettingsControllerTest.php | 18 ++--- .../HasUserNotificationsImplementation.php | 3 +- tests/Unit/Middleware/ErrorHandlerTest.php | 8 +- .../Renderer/Twig/Extensions/LegacyTest.php | 1 - .../Twig/Extensions/NotificationTest.php | 59 ++++++++++++++ 43 files changed, 313 insertions(+), 213 deletions(-) create mode 100644 src/Controllers/NotificationType.php create mode 100644 src/Renderer/Twig/Extensions/Notification.php create mode 100644 tests/Unit/Renderer/Twig/Extensions/NotificationTest.php diff --git a/includes/controller/angeltypes_controller.php b/includes/controller/angeltypes_controller.php index 75691602..c2a54774 100644 --- a/includes/controller/angeltypes_controller.php +++ b/includes/controller/angeltypes_controller.php @@ -88,7 +88,7 @@ function angeltype_delete_controller() if (request()->hasPostData('delete')) { $angeltype->delete(); engelsystem_log('Deleted angeltype: ' . AngelType_name_render($angeltype, true)); - success(sprintf(__('Angeltype %s deleted.'), AngelType_name_render($angeltype))); + success(sprintf(__('Angeltype %s deleted.'), $angeltype->name)); throw_redirect(page_link_to('angeltypes')); } diff --git a/includes/controller/shift_entries_controller.php b/includes/controller/shift_entries_controller.php index fa3f6d95..b28ff009 100644 --- a/includes/controller/shift_entries_controller.php +++ b/includes/controller/shift_entries_controller.php @@ -108,7 +108,7 @@ function shift_entry_create_controller_admin(Shift $shift, ?AngelType $angeltype $shiftEntry->save(); ShiftEntry_onCreate($shiftEntry); - success(sprintf(__('%s has been subscribed to the shift.'), User_Nick_render($signup_user))); + success(sprintf(__('%s has been subscribed to the shift.'), $signup_user->name)); throw_redirect(shift_link($shift)); } @@ -157,7 +157,7 @@ function shift_entry_create_controller_supporter(Shift $shift, AngelType $angelt $shiftEntry->save(); ShiftEntry_onCreate($shiftEntry); - success(sprintf(__('%s has been subscribed to the shift.'), User_Nick_render($signup_user))); + success(sprintf(__('%s has been subscribed to the shift.'), $signup_user->name)); throw_redirect(shift_link($shift)); } diff --git a/includes/controller/user_angeltypes_controller.php b/includes/controller/user_angeltypes_controller.php index 4710a50a..917769f6 100644 --- a/includes/controller/user_angeltypes_controller.php +++ b/includes/controller/user_angeltypes_controller.php @@ -82,7 +82,7 @@ function user_angeltypes_delete_all_controller(): array ->delete(); engelsystem_log(sprintf('Denied all users for angeltype %s', AngelType_name_render($angeltype, true))); - success(sprintf(__('Denied all users for angeltype %s.'), AngelType_name_render($angeltype))); + success(sprintf(__('Denied all users for angeltype %s.'), $angeltype->name)); throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id])); } @@ -121,7 +121,7 @@ function user_angeltypes_confirm_all_controller(): array ->update(['confirm_user_id' => $user->id]); engelsystem_log(sprintf('Confirmed all users for angeltype %s', AngelType_name_render($angeltype, true))); - success(sprintf(__('Confirmed all users for angeltype %s.'), AngelType_name_render($angeltype))); + success(sprintf(__('Confirmed all users for angeltype %s.'), $angeltype->name)); foreach ($users as $user) { user_angeltype_confirm_email($user, $angeltype); @@ -169,11 +169,7 @@ function user_angeltype_confirm_controller(): array User_Nick_render($user_source, true), AngelType_name_render($angeltype, true) )); - success(sprintf( - __('%s confirmed for angeltype %s.'), - User_Nick_render($user_source), - AngelType_name_render($angeltype) - )); + success(sprintf(__('%s confirmed for angeltype %s.'), $user_source->name, $angeltype->name)); user_angeltype_confirm_email($user_source, $angeltype); @@ -268,7 +264,7 @@ function user_angeltype_delete_controller(): array $user_angeltype->delete(); engelsystem_log(sprintf('User %s removed from %s.', User_Nick_render($user_source, true), $angeltype->name)); - success(sprintf(__('User %s removed from %s.'), User_Nick_render($user_source), $angeltype->name)); + success(sprintf(__('User %s removed from %s.'), $user_source->name, $angeltype->name)); throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id])); } @@ -323,11 +319,7 @@ function user_angeltype_update_controller(): array AngelType_name_render($angeltype, true), User_Nick_render($user_source, true) )); - success(sprintf( - $msg, - AngelType_name_render($angeltype), - User_Nick_render($user_source) - )); + success(sprintf($msg, $angeltype->name, $user_source->name)); throw_redirect(page_link_to('angeltypes', ['action' => 'view', 'angeltype_id' => $angeltype->id])); } @@ -375,11 +367,7 @@ function user_angeltype_add_controller(): array User_Nick_render($user_source, true), AngelType_name_render($angeltype, true) )); - success(sprintf( - __('User %s added to %s.'), - User_Nick_render($user_source), - AngelType_name_render($angeltype) - )); + success(sprintf(__('User %s added to %s.'), $user_source->name, $angeltype->name)); if ($request->hasPostData('auto_confirm_user')) { $userAngelType->confirmUser()->associate($user_source); diff --git a/includes/helper/email_helper.php b/includes/helper/email_helper.php index eff64675..f3b8826c 100644 --- a/includes/helper/email_helper.php +++ b/includes/helper/email_helper.php @@ -48,7 +48,7 @@ function engelsystem_email_to_user($recipientUser, $title, $message, $notIfItsMe $translator->setLocale($locale); if (!$status) { - error(sprintf(__('User %s could not be notified by email due to an error.'), User_Nick_render($recipientUser))); + error(sprintf(__('User %s could not be notified by email due to an error.'), $recipientUser->name)); engelsystem_log(sprintf('User %s could not be notified by email due to an error.', $recipientUser->name)); } diff --git a/includes/helper/message_helper.php b/includes/helper/message_helper.php index 52c63eb3..13526a63 100644 --- a/includes/helper/message_helper.php +++ b/includes/helper/message_helper.php @@ -1,40 +1,15 @@ get('msg', ''); - $session->set('msg', ''); - - if ($includeMessagesFromNewProcedure) { - foreach (session()->get('errors', []) as $msg) { - $message .= error(__($msg), true); - } - foreach (session()->get('warnings', []) as $msg) { - $message .= warning(__($msg), true); - } - foreach (session()->get('information', []) as $msg) { - $message .= info(__($msg), true); - } - foreach (session()->get('messages', []) as $msg) { - $message .= success(__($msg), true); - } - - foreach (['errors', 'warnings', 'information', 'messages'] as $type) { - session()->remove($type); - } - } - - return $message; + return view('layouts/parts/messages.twig'); } /** @@ -46,7 +21,7 @@ function msg(bool $includeMessagesFromNewProcedure = false) */ function info($msg, $immediately = false) { - return alert('info', $msg, $immediately); + return alert(NotificationType::INFORMATION, $msg, $immediately); } /** @@ -58,7 +33,7 @@ function info($msg, $immediately = false) */ function warning($msg, $immediately = false) { - return alert('warning', $msg, $immediately); + return alert(NotificationType::WARNING, $msg, $immediately); } /** @@ -70,7 +45,7 @@ function warning($msg, $immediately = false) */ function error($msg, $immediately = false) { - return alert('danger', $msg, $immediately); + return alert(NotificationType::ERROR, $msg, $immediately); } /** @@ -82,31 +57,44 @@ function error($msg, $immediately = false) */ function success($msg, $immediately = false) { - return alert('success', $msg, $immediately); + return alert(NotificationType::MESSAGE, $msg, $immediately); } /** - * Renders an alert message with the given alert-* class. + * Renders an alert message with the given alert-* class or sets it in session * - * @param string $class - * @param string $msg - * @param bool $immediately + * @see \Engelsystem\Controllers\HasUserNotifications + * + * @param NotificationType $type + * @param string $msg + * @param bool $immediately * @return string */ -function alert($class, $msg, $immediately = false) +function alert(NotificationType $type, $msg, $immediately = false) { if (empty($msg)) { return ''; } if ($immediately) { - return ''; + $type = str_replace( + [ + NotificationType::ERROR->value, + NotificationType::WARNING->value, + NotificationType::INFORMATION->value, + NotificationType::MESSAGE->value, + ], + ['danger', 'warning', 'info', 'success'], + $type->value + ); + return ''; } + $type = 'messages.' . $type->value; $session = session(); - $message = $session->get('msg', ''); - $message .= alert($class, $msg, true); - $session->set('msg', $message); + $messages = $session->get($type, []); + $messages[] = $msg; + $session->set($type, $messages); return ''; } diff --git a/includes/pages/admin_shifts.php b/includes/pages/admin_shifts.php index 806eabf6..2e3cd84e 100644 --- a/includes/pages/admin_shifts.php +++ b/includes/pages/admin_shifts.php @@ -50,6 +50,7 @@ function admin_shifts() } // Load angeltypes + /** @var AngelType[] $types */ $types = AngelType::all(); $needed_angel_types = []; foreach ($types as $type) { diff --git a/includes/pages/guest_login.php b/includes/pages/guest_login.php index 43a96784..9a2b4e77 100644 --- a/includes/pages/guest_login.php +++ b/includes/pages/guest_login.php @@ -121,7 +121,7 @@ function guest_register() } if (User::whereName($nick)->count() > 0) { $valid = false; - $msg .= error(sprintf(__('Your nick "%s" already exists.'), $nick), true); + $msg .= error(sprintf(__('Your nick "%s" already exists.'), htmlspecialchars($nick)), true); } } else { $valid = false; @@ -330,8 +330,8 @@ function guest_register() } // If a welcome message is present, display it on the next page - if ($message = $config->get('welcome_msg')) { - info((new Parsedown())->text($message)); + if ($config->get('welcome_msg')) { + $session->set('show_welcome', true); } // Login the user diff --git a/includes/pages/schedule/ImportSchedule.php b/includes/pages/schedule/ImportSchedule.php index 5c52f807..e1a940ce 100644 --- a/includes/pages/schedule/ImportSchedule.php +++ b/includes/pages/schedule/ImportSchedule.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Engelsystem\Controllers\Admin\Schedule; +use Engelsystem\Controllers\NotificationType; use Engelsystem\Helpers\Carbon; use DateTimeInterface; use Engelsystem\Controllers\BaseController; @@ -83,7 +84,7 @@ class ImportSchedule extends BaseController [ 'is_index' => true, 'schedules' => ScheduleUrl::all(), - ] + $this->getNotifications() + ] ); } @@ -98,7 +99,7 @@ class ImportSchedule extends BaseController [ 'schedule' => $schedule, 'shift_types' => ShiftType::all()->pluck('name', 'id'), - ] + $this->getNotifications() + ] ); } @@ -169,7 +170,7 @@ class ImportSchedule extends BaseController $schedule ) = $this->getScheduleData($request); } catch (ErrorException $e) { - $this->addNotification($e->getMessage(), 'errors'); + $this->addNotification($e->getMessage(), NotificationType::ERROR); return back(); } @@ -186,7 +187,7 @@ class ImportSchedule extends BaseController 'update' => $changeEvents, 'delete' => $deleteEvents, ], - ] + $this->getNotifications() + ] ); } @@ -210,7 +211,7 @@ class ImportSchedule extends BaseController $scheduleUrl ) = $this->getScheduleData($request); } catch (ErrorException $e) { - $this->addNotification($e->getMessage(), 'errors'); + $this->addNotification($e->getMessage(), NotificationType::ERROR); return back(); } @@ -250,8 +251,8 @@ class ImportSchedule extends BaseController $scheduleUrl->touch(); $this->log('Ended schedule "{name}" import', ['name' => $scheduleUrl->name]); - return redirect($this->url, 303) - ->with('messages', ['schedule.import.success']); + $this->addNotification('schedule.import.success'); + return redirect($this->url, 303); } protected function createRoom(Room $room): void diff --git a/includes/view/ShiftEntry_view.php b/includes/view/ShiftEntry_view.php index d952ce20..c4d98178 100644 --- a/includes/view/ShiftEntry_view.php +++ b/includes/view/ShiftEntry_view.php @@ -126,7 +126,7 @@ function ShiftEntry_create_view_supporter(Shift $shift, Room $room, AngelType $a Shift_view_header($shift, $room), info(sprintf( __('Do you want to sign up the following user for this shift as %s?'), - AngelType_name_render($angeltype) + $angeltype->name ), true), form([ form_select('user_id', __('User'), $users_select, $signup_user->id), @@ -153,7 +153,7 @@ function ShiftEntry_create_view_user(Shift $shift, Room $room, AngelType $angelt . ' %c', [ Shift_view_header($shift, $room), - info(sprintf(__('Do you want to sign up for this shift as %s?'), AngelType_name_render($angeltype)), true), + info(sprintf(__('Do you want to sign up for this shift as %s?'), $angeltype->name), true), form([ form_textarea('comment', __('Comment (for your eyes only):'), $comment), form_submit('submit', icon('check-lg') . __('Save')), diff --git a/includes/view/UserAngelTypes_view.php b/includes/view/UserAngelTypes_view.php index 330c3454..e6950c7e 100644 --- a/includes/view/UserAngelTypes_view.php +++ b/includes/view/UserAngelTypes_view.php @@ -20,7 +20,7 @@ function UserAngelType_update_view(UserAngelType $user_angeltype, User $user, An ? __('Do you really want to add supporter rights for %s to %s?') : __('Do you really want to remove supporter rights for %s from %s?'), $angeltype->name, - User_Nick_render($user) + $user->name ), true), form([ buttons([ @@ -92,7 +92,7 @@ function UserAngelType_confirm_view(UserAngelType $user_angeltype, User $user, A msg(), info(sprintf( __('Do you really want to confirm %s for %s?'), - User_Nick_render($user), + $user->name, $angeltype->name ), true), form([ @@ -116,7 +116,7 @@ function UserAngelType_delete_view(UserAngelType $user_angeltype, User $user, An msg(), info(sprintf( __('Do you really want to delete %s from %s?'), - User_Nick_render($user), + $user->name, $angeltype->name ), true), form([ @@ -170,7 +170,7 @@ function UserAngelType_join_view($user, AngelType $angeltype) msg(), info(sprintf( __('Do you really want to add %s to %s?'), - User_Nick_render($user), + $user->name, $angeltype->name ), true), form([ diff --git a/includes/view/User_view.php b/includes/view/User_view.php index 18e530bc..c327bdd7 100644 --- a/includes/view/User_view.php +++ b/includes/view/User_view.php @@ -534,7 +534,7 @@ function User_view( . htmlspecialchars($user_source->name) . (config('enable_user_name') ? ' ' . $user_name . '' : ''), [ - msg(true), + msg(), div('row', [ div('col-md-12', [ buttons([ diff --git a/resources/lang/de_DE/default.po b/resources/lang/de_DE/default.po index acdae4a0..c71b4946 100644 --- a/resources/lang/de_DE/default.po +++ b/resources/lang/de_DE/default.po @@ -1545,8 +1545,8 @@ msgstr "" #: includes/pages/guest_login.php:82 #, php-format -msgid "Your nick "%s" already exists." -msgstr "Der Nick "%s" existiert schon." +msgid "Your nick \"%s\" already exists." +msgstr "Der Nick \"%s\" existiert bereits." #: includes/pages/guest_login.php:86 msgid "Please enter a nickname." diff --git a/resources/lang/pt_BR/default.po b/resources/lang/pt_BR/default.po index 8ba5dcd7..9f48b4ce 100644 --- a/resources/lang/pt_BR/default.po +++ b/resources/lang/pt_BR/default.po @@ -1296,8 +1296,8 @@ msgstr "Logout" #: includes/pages/guest_login.php:56 #, php-format -msgid "Your nick "%s" already exists." -msgstr "Seu apelido "%s" já existe." +msgid "Your nick \"%s\" already exists." +msgstr "Seu apelido \"%s\" já existe." #: includes/pages/guest_login.php:60 #, php-format diff --git a/resources/views/layouts/parts/messages.twig b/resources/views/layouts/parts/messages.twig index b6f03aa4..4f346fd5 100644 --- a/resources/views/layouts/parts/messages.twig +++ b/resources/views/layouts/parts/messages.twig @@ -1,19 +1,17 @@ {% import 'macros/base.twig' as m %} -{{ msg() }} - -{% for message in errors|default([]) %} +{% for message in notifications('error') %} {{ m.alert(__(message), 'danger') }} {% endfor %} -{% for message in warnings|default([]) %} +{% for message in notifications('warning') %} {{ m.alert(__(message), 'warning') }} {% endfor %} -{% for message in information|default([]) %} +{% for message in notifications('information') %} {{ m.alert(__(message), 'info') }} {% endfor %} -{% for message in messages|default([]) %} +{% for message in notifications('message') %} {{ m.alert(__(message), 'success') }} {% endfor %} diff --git a/resources/views/pages/login.twig b/resources/views/pages/login.twig index 8da88ed5..59ffd1dc 100644 --- a/resources/views/pages/login.twig +++ b/resources/views/pages/login.twig @@ -34,6 +34,10 @@
{% include 'layouts/parts/messages.twig' %} + {% if session_get('show_welcome', false) %} + {{ m.alert(config('welcome_msg') | md, null, true) }} + {% endif %} +
{{ csrf() }}
diff --git a/src/Controllers/Admin/FaqController.php b/src/Controllers/Admin/FaqController.php index 8a598603..a01c740e 100644 --- a/src/Controllers/Admin/FaqController.php +++ b/src/Controllers/Admin/FaqController.php @@ -83,7 +83,7 @@ class FaqController extends BaseController { return $this->response->withView( 'pages/faq/edit.twig', - ['faq' => $faq] + $this->getNotifications() + ['faq' => $faq] ); } } diff --git a/src/Controllers/Admin/NewsController.php b/src/Controllers/Admin/NewsController.php index 6d94760d..19adac9f 100644 --- a/src/Controllers/Admin/NewsController.php +++ b/src/Controllers/Admin/NewsController.php @@ -49,7 +49,7 @@ class NewsController extends BaseController 'news' => $news, 'is_meeting' => $news ? $news->is_meeting : $isMeetingDefault, 'is_pinned' => $news ? $news->is_pinned : false, - ] + $this->getNotifications(), + ], ); } diff --git a/src/Controllers/Admin/QuestionsController.php b/src/Controllers/Admin/QuestionsController.php index e3dea87b..c033bdb4 100644 --- a/src/Controllers/Admin/QuestionsController.php +++ b/src/Controllers/Admin/QuestionsController.php @@ -42,7 +42,7 @@ class QuestionsController extends BaseController return $this->response->withView( 'pages/questions/overview.twig', - ['questions' => $questions, 'is_admin' => true] + $this->getNotifications() + ['questions' => $questions, 'is_admin' => true] ); } @@ -120,7 +120,7 @@ class QuestionsController extends BaseController { return $this->response->withView( 'pages/questions/edit.twig', - ['question' => $question, 'is_admin' => true] + $this->getNotifications() + ['question' => $question, 'is_admin' => true] ); } } diff --git a/src/Controllers/Admin/UserShirtController.php b/src/Controllers/Admin/UserShirtController.php index fef1ee15..2aaa0fa3 100644 --- a/src/Controllers/Admin/UserShirtController.php +++ b/src/Controllers/Admin/UserShirtController.php @@ -42,7 +42,7 @@ class UserShirtController extends BaseController return $this->response->withView( 'admin/user/edit-shirt.twig', - ['userdata' => $user] + $this->getNotifications() + ['userdata' => $user] ); } diff --git a/src/Controllers/Admin/UserWorkLogController.php b/src/Controllers/Admin/UserWorkLogController.php index d13357bf..829d012a 100644 --- a/src/Controllers/Admin/UserWorkLogController.php +++ b/src/Controllers/Admin/UserWorkLogController.php @@ -142,7 +142,7 @@ class UserWorkLogController extends BaseController 'work_hours' => $work_hours, 'comment' => $comment, 'is_edit' => $is_edit, - ] + $this->getNotifications() + ] ); } diff --git a/src/Controllers/AuthController.php b/src/Controllers/AuthController.php index b9f28e53..5c8fa421 100644 --- a/src/Controllers/AuthController.php +++ b/src/Controllers/AuthController.php @@ -39,10 +39,7 @@ class AuthController extends BaseController protected function showLogin(): Response { - return $this->response->withView( - 'pages/login', - $this->getNotifications() - ); + return $this->response->withView('pages/login'); } /** @@ -58,7 +55,7 @@ class AuthController extends BaseController $user = $this->auth->authenticate($data['login'], $data['password']); if (!$user instanceof User) { - $this->addNotification('auth.not-found', 'errors'); + $this->addNotification('auth.not-found', NotificationType::ERROR); return $this->showLogin(); } diff --git a/src/Controllers/FaqController.php b/src/Controllers/FaqController.php index 7343534d..1278a891 100644 --- a/src/Controllers/FaqController.php +++ b/src/Controllers/FaqController.php @@ -32,7 +32,7 @@ class FaqController extends BaseController return $this->response->withView( 'pages/faq/overview.twig', - ['text' => $text, 'items' => $faq] + $this->getNotifications() + ['text' => $text, 'items' => $faq] ); } } diff --git a/src/Controllers/HasUserNotifications.php b/src/Controllers/HasUserNotifications.php index deb4eb5c..5789158f 100644 --- a/src/Controllers/HasUserNotifications.php +++ b/src/Controllers/HasUserNotifications.php @@ -4,25 +4,40 @@ declare(strict_types=1); namespace Engelsystem\Controllers; -use Illuminate\Support\Arr; use Illuminate\Support\Collection; trait HasUserNotifications { - protected function addNotification(string|array $value, string $type = 'messages'): void + protected function addNotification(string|array $value, NotificationType $type = NotificationType::MESSAGE): void { + $type = 'messages.' . $type->value; session()->set( $type, - array_merge(session()->get($type, []), [$value]) + array_merge_recursive(session()->get($type, []), (array) $value) ); } - protected function getNotifications(): array + /** + * @param NotificationType[]|null $types + * @return array> + */ + protected function getNotifications(array $types = null): array { $return = []; - foreach (['errors', 'warnings', 'information', 'messages'] as $type) { - $return[$type] = Collection::make(Arr::flatten(session()->get($type, []))); - session()->remove($type); + $types = $types ?: [ + NotificationType::ERROR, + NotificationType::WARNING, + NotificationType::INFORMATION, + NotificationType::MESSAGE, + ]; + + foreach ($types as $type) { + $type = $type->value; + $path = 'messages.' . $type; + $return[$type] = Collection::make( + session()->get($path, []) + )->flatten(); + session()->remove($path); } return $return; diff --git a/src/Controllers/NewsController.php b/src/Controllers/NewsController.php index 0e34f9f5..5dfb1828 100644 --- a/src/Controllers/NewsController.php +++ b/src/Controllers/NewsController.php @@ -157,8 +157,6 @@ class NewsController extends BaseController */ protected function renderView(string $page, array $data): Response { - $data += $this->getNotifications(); - return $this->response->withView($page, $data); } } diff --git a/src/Controllers/NotificationType.php b/src/Controllers/NotificationType.php new file mode 100644 index 00000000..b2e76ef8 --- /dev/null +++ b/src/Controllers/NotificationType.php @@ -0,0 +1,13 @@ +addNotification('validation.password.confirmed', 'errors'); + $this->addNotification('validation.password.confirmed', NotificationType::ERROR); return $this->showView('pages/password/reset-form'); } @@ -101,10 +101,7 @@ class PasswordResetController extends BaseController protected function showView(string $view = 'pages/password/reset', array $data = []): Response { - return $this->response->withView( - $view, - array_merge_recursive($this->getNotifications(), $data) - ); + return $this->response->withView($view, $data); } protected function requireToken(Request $request): PasswordReset diff --git a/src/Controllers/QuestionsController.php b/src/Controllers/QuestionsController.php index 900ccd08..85b28489 100644 --- a/src/Controllers/QuestionsController.php +++ b/src/Controllers/QuestionsController.php @@ -40,7 +40,7 @@ class QuestionsController extends BaseController return $this->response->withView( 'pages/questions/overview.twig', - ['questions' => $questions] + $this->getNotifications() + ['questions' => $questions] ); } @@ -48,7 +48,7 @@ class QuestionsController extends BaseController { return $this->response->withView( 'pages/questions/edit.twig', - ['question' => null] + $this->getNotifications() + ['question' => null] ); } diff --git a/src/Controllers/SettingsController.php b/src/Controllers/SettingsController.php index 87136bc9..1fc2a4de 100644 --- a/src/Controllers/SettingsController.php +++ b/src/Controllers/SettingsController.php @@ -40,7 +40,7 @@ class SettingsController extends BaseController [ 'settings_menu' => $this->settingsMenu(), 'user' => $user, - ] + $this->getNotifications() + ] ); } @@ -60,10 +60,10 @@ class SettingsController extends BaseController if (config('enable_planned_arrival')) { if (!$this->isArrivalDateValid($data['planned_arrival_date'], $data['planned_departure_date'])) { - $this->addNotification('settings.profile.planned_arrival_date.invalid', 'errors'); + $this->addNotification('settings.profile.planned_arrival_date.invalid', NotificationType::ERROR); return $this->redirect->to('/settings/profile'); } elseif (!$this->isDepartureDateValid($data['planned_arrival_date'], $data['planned_departure_date'])) { - $this->addNotification('settings.profile.planned_departure_date.invalid', 'errors'); + $this->addNotification('settings.profile.planned_departure_date.invalid', NotificationType::ERROR); return $this->redirect->to('/settings/profile'); } else { $user->personalData->planned_arrival_date = $data['planned_arrival_date']; @@ -115,7 +115,7 @@ class SettingsController extends BaseController [ 'settings_menu' => $this->settingsMenu(), 'min_length' => config('min_password_length'), - ] + $this->getNotifications() + ] ); } @@ -131,9 +131,9 @@ class SettingsController extends BaseController ]); if (!empty($user->password) && !$this->auth->verifyPassword($user, $data['password'])) { - $this->addNotification('auth.password.error', 'errors'); + $this->addNotification('auth.password.error', NotificationType::ERROR); } elseif ($data['new_password'] != $data['new_password2']) { - $this->addNotification('validation.password.confirmed', 'errors'); + $this->addNotification('validation.password.confirmed', NotificationType::ERROR); } else { $this->auth->setPassword($user, $data['new_password']); @@ -158,7 +158,7 @@ class SettingsController extends BaseController 'settings_menu' => $this->settingsMenu(), 'themes' => $themes, 'current_theme' => $currentTheme, - ] + $this->getNotifications() + ] ); } @@ -192,7 +192,7 @@ class SettingsController extends BaseController 'settings_menu' => $this->settingsMenu(), 'languages' => $languages, 'current_language' => $currentLanguage, - ] + $this->getNotifications() + ] ); } @@ -228,7 +228,7 @@ class SettingsController extends BaseController [ 'settings_menu' => $this->settingsMenu(), 'providers' => $providers, - ] + $this->getNotifications(), + ], ); } diff --git a/src/Middleware/ErrorHandler.php b/src/Middleware/ErrorHandler.php index 2e07ddb3..98678e22 100644 --- a/src/Middleware/ErrorHandler.php +++ b/src/Middleware/ErrorHandler.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Engelsystem\Middleware; +use Engelsystem\Controllers\NotificationType; use Engelsystem\Http\Exceptions\HttpException; use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Request; @@ -55,7 +56,10 @@ class ErrorHandler implements MiddlewareInterface $response = $this->createResponse($e->getMessage(), $e->getStatusCode(), $e->getHeaders()); } catch (ValidationException $e) { $response = $this->redirectBack(); - $response->with('errors', ['validation' => $e->getValidator()->getErrors()]); + $response->with( + 'messages.' . NotificationType::ERROR->value, + ['validation' => $e->getValidator()->getErrors()] + ); if ($request instanceof Request) { $response->withInput(Arr::except($request->request->all(), $this->formIgnore)); diff --git a/src/Renderer/Twig/Extensions/Legacy.php b/src/Renderer/Twig/Extensions/Legacy.php index e6669bc1..ea23fdd0 100644 --- a/src/Renderer/Twig/Extensions/Legacy.php +++ b/src/Renderer/Twig/Extensions/Legacy.php @@ -26,7 +26,6 @@ class Legacy extends TwigExtension new TwigFunction('menuUserHints', 'header_render_hints', $isSafeHtml), new TwigFunction('menuLanguages', 'make_language_select', $isSafeHtml), new TwigFunction('page', [$this, 'getPage']), - new TwigFunction('msg', 'msg', $isSafeHtml), ]; } diff --git a/src/Renderer/Twig/Extensions/Notification.php b/src/Renderer/Twig/Extensions/Notification.php new file mode 100644 index 00000000..fefe8220 --- /dev/null +++ b/src/Renderer/Twig/Extensions/Notification.php @@ -0,0 +1,46 @@ +getNotifications($types); + if ($types) { + $messages = $messages[$type] ?? []; + } + + return collect($messages); + } +} diff --git a/src/Renderer/TwigServiceProvider.php b/src/Renderer/TwigServiceProvider.php index cdd0d025..a25bb3f3 100644 --- a/src/Renderer/TwigServiceProvider.php +++ b/src/Renderer/TwigServiceProvider.php @@ -14,6 +14,7 @@ use Engelsystem\Renderer\Twig\Extensions\Develop; use Engelsystem\Renderer\Twig\Extensions\Globals; use Engelsystem\Renderer\Twig\Extensions\Legacy; use Engelsystem\Renderer\Twig\Extensions\Markdown; +use Engelsystem\Renderer\Twig\Extensions\Notification; use Engelsystem\Renderer\Twig\Extensions\Session; use Engelsystem\Renderer\Twig\Extensions\Translation; use Engelsystem\Renderer\Twig\Extensions\Url; @@ -34,6 +35,7 @@ class TwigServiceProvider extends ServiceProvider 'csrf' => Csrf::class, 'develop' => Develop::class, 'globals' => Globals::class, + 'notification' => Notification::class, 'twigmodel' => TwigModel::class, 'session' => Session::class, 'legacy' => Legacy::class, diff --git a/tests/Unit/Controllers/Admin/FaqControllerTest.php b/tests/Unit/Controllers/Admin/FaqControllerTest.php index a0d8f8ca..7ac661db 100644 --- a/tests/Unit/Controllers/Admin/FaqControllerTest.php +++ b/tests/Unit/Controllers/Admin/FaqControllerTest.php @@ -5,12 +5,11 @@ declare(strict_types=1); namespace Engelsystem\Test\Unit\Controllers\Admin; use Engelsystem\Controllers\Admin\FaqController; +use Engelsystem\Controllers\NotificationType; use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Validation\Validator; use Engelsystem\Models\Faq; use Engelsystem\Test\Unit\Controllers\ControllerTest; -use Illuminate\Support\Collection; -use Symfony\Component\HttpFoundation\Session\Session; class FaqControllerTest extends ControllerTest { @@ -33,10 +32,7 @@ class FaqControllerTest extends ControllerTest ->willReturnCallback(function ($view, $data) { $this->assertEquals('pages/faq/edit.twig', $view); - /** @var Collection $warnings */ - $warnings = $data['messages']; $this->assertNotEmpty($data['faq']); - $this->assertTrue($warnings->isEmpty()); return $this->response; }); @@ -45,6 +41,7 @@ class FaqControllerTest extends ControllerTest $controller = $this->app->make(FaqController::class); $controller->edit($this->request); + $this->assertHasNoNotifications(NotificationType::WARNING); } /** @@ -82,14 +79,10 @@ class FaqControllerTest extends ControllerTest $this->assertTrue($this->log->hasInfoThatContains('Updated')); - /** @var Session $session */ - $session = $this->app->get('session'); - $messages = $session->get('messages'); - $this->assertEquals('faq.edit.success', $messages[0]); - $faq = (new Faq())->find(2); $this->assertEquals('Foo?', $faq->question); $this->assertEquals('Bar!', $faq->text); + $this->assertHasNotification('faq.edit.success'); } /** @@ -153,10 +146,7 @@ class FaqControllerTest extends ControllerTest $this->assertTrue($this->log->hasInfoThatContains('Deleted')); - /** @var Session $session */ - $session = $this->app->get('session'); - $messages = $session->get('messages'); - $this->assertEquals('faq.delete.success', $messages[0]); + $this->assertHasNotification('faq.delete.success'); } /** diff --git a/tests/Unit/Controllers/Admin/NewsControllerTest.php b/tests/Unit/Controllers/Admin/NewsControllerTest.php index d991d006..6b236b24 100644 --- a/tests/Unit/Controllers/Admin/NewsControllerTest.php +++ b/tests/Unit/Controllers/Admin/NewsControllerTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Engelsystem\Test\Unit\Controllers\Admin; use Engelsystem\Controllers\Admin\NewsController; +use Engelsystem\Controllers\NotificationType; use Engelsystem\Events\EventDispatcher; use Engelsystem\Helpers\Authenticator; use Engelsystem\Http\Exceptions\ValidationException; @@ -12,9 +13,7 @@ use Engelsystem\Http\Validation\Validator; use Engelsystem\Models\News; use Engelsystem\Models\User\User; use Engelsystem\Test\Unit\Controllers\ControllerTest; -use Illuminate\Support\Collection; use PHPUnit\Framework\MockObject\MockObject; -use Symfony\Component\HttpFoundation\Session\Session; class NewsControllerTest extends ControllerTest { @@ -42,10 +41,7 @@ class NewsControllerTest extends ControllerTest ->willReturnCallback(function ($view, $data) { $this->assertEquals('pages/news/edit.twig', $view); - /** @var Collection $warnings */ - $warnings = $data['warnings']; $this->assertNotEmpty($data['news']); - $this->assertTrue($warnings->isEmpty()); return $this->response; }); @@ -54,6 +50,7 @@ class NewsControllerTest extends ControllerTest $controller = $this->app->make(NewsController::class); $controller->edit($this->request); + $this->assertHasNoNotifications(NotificationType::WARNING); } /** @@ -147,10 +144,7 @@ class NewsControllerTest extends ControllerTest $this->assertTrue($this->log->hasInfoThatContains('Updated')); - /** @var Session $session */ - $session = $this->app->get('session'); - $messages = $session->get('messages'); - $this->assertEquals('news.edit.success', $messages[0]); + $this->assertHasNotification('news.edit.success'); $news = (new News())->find($id); $this->assertEquals($text, $news->text); @@ -224,10 +218,7 @@ class NewsControllerTest extends ControllerTest $this->assertTrue($this->log->hasInfoThatContains('Deleted')); - /** @var Session $session */ - $session = $this->app->get('session'); - $messages = $session->get('messages'); - $this->assertEquals('news.delete.success', $messages[0]); + $this->assertHasNotification('news.delete.success'); } /** diff --git a/tests/Unit/Controllers/AuthControllerTest.php b/tests/Unit/Controllers/AuthControllerTest.php index 18177974..f518ac70 100644 --- a/tests/Unit/Controllers/AuthControllerTest.php +++ b/tests/Unit/Controllers/AuthControllerTest.php @@ -7,6 +7,7 @@ namespace Engelsystem\Test\Unit\Controllers; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use Engelsystem\Config\Config; use Engelsystem\Controllers\AuthController; +use Engelsystem\Controllers\NotificationType; use Engelsystem\Helpers\Authenticator; use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Redirector; @@ -16,13 +17,12 @@ use Engelsystem\Http\Validation\Validator; use Engelsystem\Models\User\Settings; use Engelsystem\Models\User\User; use Engelsystem\Test\Unit\HasDatabase; -use Engelsystem\Test\Unit\TestCase; use PHPUnit\Framework\MockObject\MockObject; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; -class AuthControllerTest extends TestCase +class AuthControllerTest extends ControllerTest { use ArraySubsetAsserts; use HasDatabase; @@ -42,11 +42,6 @@ class AuthControllerTest extends TestCase /** @var Authenticator|MockObject $auth */ list(, $session, $redirect, $config, $auth) = $this->getMocks(); - $session->expects($this->atLeastOnce()) - ->method('get') - ->willReturnCallback(function ($type) { - return $type == 'errors' ? ['foo' => 'bar'] : []; - }); $response->expects($this->once()) ->method('withView') ->with('pages/login') @@ -70,11 +65,10 @@ class AuthControllerTest extends TestCase /** @var Config $config */ /** @var Authenticator|MockObject $auth */ list(, , $redirect, $config, $auth) = $this->getMocks(); - $session = new Session(new MockArraySessionStorage()); + $this->session = new Session(new MockArraySessionStorage()); + $this->app->instance('session', $this->session); /** @var Validator|MockObject $validator */ $validator = new Validator(); - $session->set('errors', [['bar' => 'some.bar.error']]); - $this->app->instance('session', $session); $user = $this->createUser(); $auth->expects($this->exactly(2)) @@ -86,13 +80,12 @@ class AuthControllerTest extends TestCase ->method('withView') ->willReturnCallback(function ($view, $data = []) use ($response) { $this->assertEquals('pages/login', $view); - $this->assertArraySubset(['errors' => collect(['some.bar.error', 'auth.not-found'])], $data); return $response; }); /** @var AuthController|MockObject $controller */ $controller = $this->getMockBuilder(AuthController::class) - ->setConstructorArgs([$response, $session, $redirect, $config, $auth]) + ->setConstructorArgs([$response, $this->session, $redirect, $config, $auth]) ->onlyMethods(['loginUser']) ->getMock(); $controller->setValidator($validator); @@ -120,7 +113,7 @@ class AuthControllerTest extends TestCase // No user found $request = new Request([], ['login' => 'foo', 'password' => 'bar']); $controller->postLogin($request); - $this->assertEquals([], $session->all()); + $this->assertHasNotification('auth.not-found', NotificationType::ERROR); // Authenticated user $controller->postLogin($request); diff --git a/tests/Unit/Controllers/ControllerTest.php b/tests/Unit/Controllers/ControllerTest.php index 4515d4c8..fa428f86 100644 --- a/tests/Unit/Controllers/ControllerTest.php +++ b/tests/Unit/Controllers/ControllerTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Engelsystem\Test\Unit\Controllers; use Engelsystem\Config\Config; +use Engelsystem\Controllers\NotificationType; use Engelsystem\Http\Request; use Engelsystem\Http\Response; use Engelsystem\Http\UrlGenerator; @@ -33,12 +34,26 @@ abstract class ControllerTest extends TestCase protected Session $session; /** - * @param string|null $type + * @param string|string[] $value */ - protected function assertHasNotification(string $value, string $type = 'messages'): void + protected function setNotification(string|array $value, NotificationType $type = NotificationType::MESSAGE): void { - $messages = $this->session->get($type, []); - $this->assertTrue(in_array($value, $messages)); + $this->session->set( + 'messages.' . $type->value, + array_merge($this->session->get('messages.' . $type->value, []), (array) $value) + ); + } + + protected function assertHasNotification(string $value, NotificationType $type = NotificationType::MESSAGE): void + { + $messages = $this->session->get('messages.' . $type->value, []); + $this->assertTrue(in_array($value, $messages), 'Has ' . $type->value . ' notification: ' . $value); + } + + protected function assertHasNoNotifications(NotificationType $type = null): void + { + $messages = $this->session->get('messages' . ($type ? '.' . $type->value : ''), []); + $this->assertEmpty($messages, 'Has no' . ($type ? ' ' . $type->value : '') . ' notification.'); } /** diff --git a/tests/Unit/Controllers/HasUserNotificationsTest.php b/tests/Unit/Controllers/HasUserNotificationsTest.php index b60af305..cb817018 100644 --- a/tests/Unit/Controllers/HasUserNotificationsTest.php +++ b/tests/Unit/Controllers/HasUserNotificationsTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Engelsystem\Test\Unit\Controllers; +use Engelsystem\Controllers\NotificationType; use Engelsystem\Test\Unit\Controllers\Stub\HasUserNotificationsImplementation; use Engelsystem\Test\Unit\TestCase; use Illuminate\Support\Collection; @@ -22,16 +23,17 @@ class HasUserNotificationsTest extends TestCase $this->app->instance('session', $session); $notify = new HasUserNotificationsImplementation(); - $notify->add('Foo', 'errors'); - $notify->add('Bar', 'warnings'); - $notify->add(['Baz', 'Lorem'], 'information'); - $notify->add(['Hm', ['Uff', 'sum']], 'messages'); + $notify->add('Foo', NotificationType::ERROR); + $notify->add('Bar', NotificationType::WARNING); + $notify->add(['Baz', 'Lorem'], NotificationType::INFORMATION); + $notify->add(['Hm', ['test'], 'some' => ['Uff', 'sum']], NotificationType::MESSAGE); + $notify->add(['some' => ['it']], NotificationType::MESSAGE); $this->assertEquals([ - 'errors' => new Collection(['Foo']), - 'warnings' => new Collection(['Bar']), - 'information' => new Collection(['Baz', 'Lorem']), - 'messages' => new Collection(['Hm', 'Uff', 'sum']), + NotificationType::ERROR->value => new Collection(['Foo']), + NotificationType::WARNING->value => new Collection(['Bar']), + NotificationType::INFORMATION->value => new Collection(['Baz', 'Lorem']), + NotificationType::MESSAGE->value => new Collection(['Hm', 'test', 'Uff', 'sum', 'it']), ], $notify->get()); } } diff --git a/tests/Unit/Controllers/PasswordResetControllerTest.php b/tests/Unit/Controllers/PasswordResetControllerTest.php index d0d5fb09..c653f3c0 100644 --- a/tests/Unit/Controllers/PasswordResetControllerTest.php +++ b/tests/Unit/Controllers/PasswordResetControllerTest.php @@ -6,6 +6,7 @@ namespace Engelsystem\Test\Unit\Controllers; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; use Engelsystem\Config\Config; +use Engelsystem\Controllers\NotificationType; use Engelsystem\Controllers\PasswordResetController; use Engelsystem\Helpers\Authenticator; use Engelsystem\Http\Exceptions\HttpNotFound; @@ -18,13 +19,12 @@ use Engelsystem\Models\User\PasswordReset; use Engelsystem\Models\User\User; use Engelsystem\Renderer\Renderer; use Engelsystem\Test\Unit\HasDatabase; -use Engelsystem\Test\Unit\TestCase; use PHPUnit\Framework\MockObject\MockObject; use Psr\Log\Test\TestLogger; use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; -class PasswordResetControllerTest extends TestCase +class PasswordResetControllerTest extends ControllerTest { use ArraySubsetAsserts; use HasDatabase; @@ -55,7 +55,7 @@ class PasswordResetControllerTest extends TestCase $controller = $this->getController( 'pages/password/reset-success', - ['type' => 'email', 'errors' => collect()] + ['type' => 'email'] ); /** @var TestLogger $log */ $log = $this->args['log']; @@ -67,6 +67,7 @@ class PasswordResetControllerTest extends TestCase $this->assertNotEmpty((new PasswordReset())->find($user->id)->first()); $this->assertTrue($log->hasInfoThatContains($user->name)); + $this->assertHasNoNotifications(); } /** @@ -92,10 +93,11 @@ class PasswordResetControllerTest extends TestCase $controller = $this->getController( 'pages/password/reset-success', - ['type' => 'email', 'errors' => collect()] + ['type' => 'email'] ); $controller->postReset($request); + $this->assertHasNoNotifications(); } /** @@ -148,7 +150,7 @@ class PasswordResetControllerTest extends TestCase $controller = $this->getController( 'pages/password/reset-success', - ['type' => 'reset', 'errors' => collect()] + ['type' => 'reset'] ); $auth = new Authenticator($request, $this->args['session'], $user); @@ -159,6 +161,7 @@ class PasswordResetControllerTest extends TestCase $this->assertEmpty((new PasswordReset())->find($user->id)); $this->assertNotNull(auth()->authenticate($user->name, $password)); + $this->assertHasNoNotifications(); } /** @@ -179,16 +182,10 @@ class PasswordResetControllerTest extends TestCase ['token' => $token->token] ); - $controller = $this->getController( - 'pages/password/reset-form', - ['errors' => collect(['some.other.error', 'validation.password.confirmed'])] - ); - /** @var Session $session */ - $session = $this->args['session']; - $session->set('errors', ['foo' => ['bar' => 'some.other.error']]); + $controller = $this->getController('pages/password/reset-form'); $controller->postResetPassword($request); - $this->assertEmpty($session->get('errors')); + $this->assertHasNotification('validation.password.confirmed', NotificationType::ERROR); } protected function getControllerArgs(): array @@ -203,6 +200,10 @@ class PasswordResetControllerTest extends TestCase $this->app->instance('session', $session); + $this->session = $session; + $this->response = $response; + $this->log = $log; + return $this->args = [ 'response' => $response, 'session' => $session, diff --git a/tests/Unit/Controllers/SettingsControllerTest.php b/tests/Unit/Controllers/SettingsControllerTest.php index 4f161f11..c16b2b12 100644 --- a/tests/Unit/Controllers/SettingsControllerTest.php +++ b/tests/Unit/Controllers/SettingsControllerTest.php @@ -6,6 +6,7 @@ namespace Engelsystem\Test\Unit\Controllers; use Carbon\Carbon; use Engelsystem\Config\Config; +use Engelsystem\Controllers\NotificationType; use Engelsystem\Controllers\SettingsController; use Engelsystem\Http\Exceptions\HttpNotFound; use Engelsystem\Http\Response; @@ -133,7 +134,7 @@ class SettingsControllerTest extends ControllerTest $this->setUpProfileTest(); config(['buildup_start' => new Carbon('2022-01-02')]); // arrival before buildup $this->controller->saveProfile($this->request); - $this->assertHasNotification('settings.profile.planned_arrival_date.invalid', 'errors'); + $this->assertHasNotification('settings.profile.planned_arrival_date.invalid', NotificationType::ERROR); } /** @@ -144,7 +145,7 @@ class SettingsControllerTest extends ControllerTest $this->setUpProfileTest(); config(['teardown_end' => new Carbon('2022-01-01')]); // departure after teardown $this->controller->saveProfile($this->request); - $this->assertHasNotification('settings.profile.planned_departure_date.invalid', 'errors'); + $this->assertHasNotification('settings.profile.planned_departure_date.invalid', NotificationType::ERROR); } /** @@ -272,7 +273,7 @@ class SettingsControllerTest extends ControllerTest /** @var Session $session */ $session = $this->app->get('session'); - $messages = $session->get('messages'); + $messages = $session->get('messages.' . NotificationType::MESSAGE->value); $this->assertEquals('settings.password.success', $messages[0]); } @@ -328,10 +329,7 @@ class SettingsControllerTest extends ControllerTest $this->controller->savePassword($this->request); - /** @var Session $session */ - $session = $this->app->get('session'); - $errors = $session->get('errors'); - $this->assertEquals('auth.password.error', $errors[0]); + $this->assertHasNotification('auth.password.error', NotificationType::ERROR); } /** @@ -359,10 +357,7 @@ class SettingsControllerTest extends ControllerTest $this->controller->savePassword($this->request); - /** @var Session $session */ - $session = $this->app->get('session'); - $errors = $session->get('errors'); - $this->assertEquals('validation.password.confirmed', $errors[0]); + $this->assertHasNotification('validation.password.confirmed', NotificationType::ERROR); } public function savePasswordValidationProvider(): array @@ -558,7 +553,6 @@ class SettingsControllerTest extends ControllerTest ->method('withView') ->willReturnCallback(function ($view, $data) use ($providers) { $this->assertEquals('pages/settings/oauth', $view); - $this->assertArrayHasKey('information', $data); $this->assertArrayHasKey('providers', $data); $this->assertEquals($providers, $data['providers']); diff --git a/tests/Unit/Controllers/Stub/HasUserNotificationsImplementation.php b/tests/Unit/Controllers/Stub/HasUserNotificationsImplementation.php index 0ace6355..19409b45 100644 --- a/tests/Unit/Controllers/Stub/HasUserNotificationsImplementation.php +++ b/tests/Unit/Controllers/Stub/HasUserNotificationsImplementation.php @@ -5,12 +5,13 @@ declare(strict_types=1); namespace Engelsystem\Test\Unit\Controllers\Stub; use Engelsystem\Controllers\HasUserNotifications; +use Engelsystem\Controllers\NotificationType; class HasUserNotificationsImplementation { use HasUserNotifications; - public function add(string|array $value, string $type = 'messages'): void + public function add(string|array $value, NotificationType $type = NotificationType::MESSAGE): void { $this->addNotification($value, $type); } diff --git a/tests/Unit/Middleware/ErrorHandlerTest.php b/tests/Unit/Middleware/ErrorHandlerTest.php index 6926126b..52e21dea 100644 --- a/tests/Unit/Middleware/ErrorHandlerTest.php +++ b/tests/Unit/Middleware/ErrorHandlerTest.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Engelsystem\Test\Unit\Middleware; use Engelsystem\Config\Config; +use Engelsystem\Controllers\NotificationType; use Engelsystem\Http\Exceptions\HttpException; use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Psr7ServiceProvider; @@ -185,7 +186,10 @@ class ErrorHandlerTest extends TestCase ->willReturn(['foo' => ['validation.foo.numeric']]); $session = new Session(new MockArraySessionStorage()); - $session->set('errors', ['validation' => ['foo' => ['validation.foo.required']]]); + $session->set( + 'messages.' . NotificationType::ERROR->value, + ['validation' => ['foo' => ['validation.foo.required']]] + ); $request = Request::create( '/foo/bar', 'POST', @@ -208,7 +212,7 @@ class ErrorHandlerTest extends TestCase $this->assertEquals(302, $return->getStatusCode()); $this->assertEquals('http://localhost/', $return->getHeaderLine('location')); $this->assertEquals([ - 'errors' => [ + 'messages.' . NotificationType::ERROR->value => [ 'validation' => [ 'foo' => [ 'validation.foo.required', diff --git a/tests/Unit/Renderer/Twig/Extensions/LegacyTest.php b/tests/Unit/Renderer/Twig/Extensions/LegacyTest.php index c52d4c4c..67da4567 100644 --- a/tests/Unit/Renderer/Twig/Extensions/LegacyTest.php +++ b/tests/Unit/Renderer/Twig/Extensions/LegacyTest.php @@ -27,7 +27,6 @@ class LegacyTest extends ExtensionTest $this->assertExtensionExists('menuUserHints', 'header_render_hints', $functions, $isSafeHtml); $this->assertExtensionExists('menuLanguages', 'make_language_select', $functions, $isSafeHtml); $this->assertExtensionExists('page', [$extension, 'getPage'], $functions); - $this->assertExtensionExists('msg', 'msg', $functions, $isSafeHtml); } /** diff --git a/tests/Unit/Renderer/Twig/Extensions/NotificationTest.php b/tests/Unit/Renderer/Twig/Extensions/NotificationTest.php new file mode 100644 index 00000000..989d69da --- /dev/null +++ b/tests/Unit/Renderer/Twig/Extensions/NotificationTest.php @@ -0,0 +1,59 @@ +getFunctions(); + $this->assertExtensionExists('notifications', [$extension, 'notifications'], $functions); + } + + /** + * @covers \Engelsystem\Renderer\Twig\Extensions\Notification::notifications + */ + public function testNotifications(): void + { + $session = new Session(new MockArraySessionStorage()); + + $extension = new Notification($session); + $this->app->instance('session', $session); + + $notificationsList = $extension->notifications()->toArray(); + $this->assertIsArray($notificationsList); + foreach ($notificationsList as $notification) { + $this->assertEmpty($notification); + } + + $session->set('messages.' . NotificationType::ERROR->value, 'some error'); + $session->set('messages.' . NotificationType::WARNING->value, 'a warning'); + $session->set('messages.' . NotificationType::INFORMATION->value, 'for your information'); + $session->set('messages.' . NotificationType::MESSAGE->value, 'i\'m a message'); + + $notifications = $extension->notifications(); + $this->assertEquals(['some error'], $notifications[NotificationType::ERROR->value]->toArray()); + $this->assertEquals(['a warning'], $notifications[NotificationType::WARNING->value]->toArray()); + $this->assertEquals(['for your information'], $notifications[NotificationType::INFORMATION->value]->toArray()); + $this->assertEquals(['i\'m a message'], $notifications[NotificationType::MESSAGE->value]->toArray()); + + $session->set('messages.' . NotificationType::ERROR->value, 'Test error'); + $notifications = $extension->notifications(NotificationType::ERROR->value); + $this->assertEquals(['Test error'], $notifications->toArray()); + } +}