diff --git a/app/Users/Controllers/UserAccountController.php b/app/Users/Controllers/UserAccountController.php new file mode 100644 index 000000000..9152eb5e8 --- /dev/null +++ b/app/Users/Controllers/UserAccountController.php @@ -0,0 +1,105 @@ +isGuest(); + $mfaMethods = $guest ? [] : user()->mfaValues->groupBy('method'); + + return view('users.account.index', [ + 'mfaMethods' => $mfaMethods, + ]); + } + + /** + * Show the user-specific interface shortcuts. + */ + public function showShortcuts() + { + $shortcuts = UserShortcutMap::fromUserPreferences(); + $enabled = setting()->getForCurrentUser('ui-shortcuts-enabled', false); + + $this->setPageTitle(trans('preferences.shortcuts_interface')); + + return view('users.account.shortcuts', [ + 'shortcuts' => $shortcuts, + 'enabled' => $enabled, + ]); + } + + /** + * Update the user-specific interface shortcuts. + */ + public function updateShortcuts(Request $request) + { + $enabled = $request->get('enabled') === 'true'; + $providedShortcuts = $request->get('shortcut', []); + $shortcuts = new UserShortcutMap($providedShortcuts); + + setting()->putForCurrentUser('ui-shortcuts', $shortcuts->toJson()); + setting()->putForCurrentUser('ui-shortcuts-enabled', $enabled); + + $this->showSuccessNotification(trans('preferences.shortcuts_update_success')); + + return redirect('/my-account/shortcuts'); + } + + /** + * Show the notification preferences for the current user. + */ + public function showNotifications(PermissionApplicator $permissions) + { + $this->checkPermission('receive-notifications'); + $this->preventGuestAccess(); + + $preferences = (new UserNotificationPreferences(user())); + + $query = user()->watches()->getQuery(); + $query = $permissions->restrictEntityRelationQuery($query, 'watches', 'watchable_id', 'watchable_type'); + $query = $permissions->filterDeletedFromEntityRelationQuery($query, 'watches', 'watchable_id', 'watchable_type'); + $watches = $query->with('watchable')->paginate(20); + + $this->setPageTitle(trans('preferences.notifications')); + return view('users.account.notifications', [ + 'preferences' => $preferences, + 'watches' => $watches, + ]); + } + + /** + * Update the notification preferences for the current user. + */ + public function updateNotifications(Request $request) + { + $this->checkPermission('receive-notifications'); + $this->preventGuestAccess(); + $data = $this->validate($request, [ + 'preferences' => ['required', 'array'], + 'preferences.*' => ['required', 'string'], + ]); + + $preferences = (new UserNotificationPreferences(user())); + $preferences->updateFromSettingsArray($data['preferences']); + $this->showSuccessNotification(trans('preferences.notifications_update_success')); + + return redirect('/my-account/notifications'); + } +} diff --git a/app/Users/Controllers/UserPreferencesController.php b/app/Users/Controllers/UserPreferencesController.php index 08d65743b..3600dc55f 100644 --- a/app/Users/Controllers/UserPreferencesController.php +++ b/app/Users/Controllers/UserPreferencesController.php @@ -16,88 +16,6 @@ class UserPreferencesController extends Controller ) { } - /** - * Show the overview for user preferences. - */ - public function index() - { - return view('users.preferences.index'); - } - - /** - * Show the user-specific interface shortcuts. - */ - public function showShortcuts() - { - $shortcuts = UserShortcutMap::fromUserPreferences(); - $enabled = setting()->getForCurrentUser('ui-shortcuts-enabled', false); - - $this->setPageTitle(trans('preferences.shortcuts_interface')); - - return view('users.preferences.shortcuts', [ - 'shortcuts' => $shortcuts, - 'enabled' => $enabled, - ]); - } - - /** - * Update the user-specific interface shortcuts. - */ - public function updateShortcuts(Request $request) - { - $enabled = $request->get('enabled') === 'true'; - $providedShortcuts = $request->get('shortcut', []); - $shortcuts = new UserShortcutMap($providedShortcuts); - - setting()->putForCurrentUser('ui-shortcuts', $shortcuts->toJson()); - setting()->putForCurrentUser('ui-shortcuts-enabled', $enabled); - - $this->showSuccessNotification(trans('preferences.shortcuts_update_success')); - - return redirect('/preferences/shortcuts'); - } - - /** - * Show the notification preferences for the current user. - */ - public function showNotifications(PermissionApplicator $permissions) - { - $this->checkPermission('receive-notifications'); - $this->preventGuestAccess(); - - $preferences = (new UserNotificationPreferences(user())); - - $query = user()->watches()->getQuery(); - $query = $permissions->restrictEntityRelationQuery($query, 'watches', 'watchable_id', 'watchable_type'); - $query = $permissions->filterDeletedFromEntityRelationQuery($query, 'watches', 'watchable_id', 'watchable_type'); - $watches = $query->with('watchable')->paginate(20); - - $this->setPageTitle(trans('preferences.notifications')); - return view('users.preferences.notifications', [ - 'preferences' => $preferences, - 'watches' => $watches, - ]); - } - - /** - * Update the notification preferences for the current user. - */ - public function updateNotifications(Request $request) - { - $this->checkPermission('receive-notifications'); - $this->preventGuestAccess(); - $data = $this->validate($request, [ - 'preferences' => ['required', 'array'], - 'preferences.*' => ['required', 'string'], - ]); - - $preferences = (new UserNotificationPreferences(user())); - $preferences->updateFromSettingsArray($data['preferences']); - $this->showSuccessNotification(trans('preferences.notifications_update_success')); - - return redirect('/preferences/notifications'); - } - /** * Update the preferred view format for a list view of the given type. */ diff --git a/lang/en/preferences.php b/lang/en/preferences.php index 118e8ba82..cf1ee2b37 100644 --- a/lang/en/preferences.php +++ b/lang/en/preferences.php @@ -5,10 +5,10 @@ */ return [ - 'preferences' => 'Preferences', + 'my_account' => 'My Account', 'shortcuts' => 'Shortcuts', - 'shortcuts_interface' => 'Interface Keyboard Shortcuts', + 'shortcuts_interface' => 'UI Shortcut Preferences', 'shortcuts_toggle_desc' => 'Here you can enable or disable keyboard system interface shortcuts, used for navigation and actions.', 'shortcuts_customize_desc' => 'You can customize each of the shortcuts below. Just press your desired key combination after selecting the input for a shortcut.', 'shortcuts_toggle_label' => 'Keyboard shortcuts enabled', diff --git a/resources/icons/notifications.svg b/resources/icons/notifications.svg new file mode 100644 index 000000000..52786954d --- /dev/null +++ b/resources/icons/notifications.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/views/layouts/parts/header-user-menu.blade.php b/resources/views/layouts/parts/header-user-menu.blade.php index 8ba750f95..694b7b87a 100644 --- a/resources/views/layouts/parts/header-user-menu.blade.php +++ b/resources/views/layouts/parts/header-user-menu.blade.php @@ -35,9 +35,9 @@

  • - + @icon('user-preferences') -
    {{ trans('preferences.preferences') }}
    +
    {{ trans('preferences.my_account') }}
  • diff --git a/resources/views/users/preferences/index.blade.php b/resources/views/users/account/index.blade.php similarity index 56% rename from resources/views/users/preferences/index.blade.php rename to resources/views/users/account/index.blade.php index f8576ed9e..11a5bc9c9 100644 --- a/resources/views/users/preferences/index.blade.php +++ b/resources/views/users/account/index.blade.php @@ -9,7 +9,7 @@

    {{ trans('preferences.shortcuts_overview_desc') }}

    - {{ trans('common.manage') }} + {{ trans('common.manage') }}
    @@ -20,7 +20,7 @@

    {{ trans('preferences.notifications_desc') }}

    - {{ trans('common.manage') }} + {{ trans('common.manage') }}
    @endif @@ -37,5 +37,26 @@ @endif + @if(!user()->isGuest()) +
    +
    +

    {{ trans('settings.users_mfa') }}

    +

    {{ trans('settings.users_mfa_desc') }}

    +

    + @if ($mfaMethods->count() > 0) + @icon('check-circle') + @else + @icon('cancel') + @endif + {{ trans_choice('settings.users_mfa_x_methods', $mfaMethods->count()) }} +

    +
    + +
    + @endif + @stop diff --git a/resources/views/users/account/layout.blade.php b/resources/views/users/account/layout.blade.php new file mode 100644 index 000000000..9eaa1eca1 --- /dev/null +++ b/resources/views/users/account/layout.blade.php @@ -0,0 +1,26 @@ +@extends('layouts.simple') + +@section('body') +
    + + + +
    +@stop \ No newline at end of file diff --git a/resources/views/users/account/notifications.blade.php b/resources/views/users/account/notifications.blade.php new file mode 100644 index 000000000..b3b082bd7 --- /dev/null +++ b/resources/views/users/account/notifications.blade.php @@ -0,0 +1,71 @@ +@extends('users.account.layout') + +@section('main') +
    +
    + {{ method_field('put') }} + {{ csrf_field() }} + +

    {{ trans('preferences.notifications') }}

    +

    {{ trans('preferences.notifications_desc') }}

    + +
    +
    +
    + @include('form.toggle-switch', [ + 'name' => 'preferences[own-page-changes]', + 'value' => $preferences->notifyOnOwnPageChanges(), + 'label' => trans('preferences.notifications_opt_own_page_changes'), + ]) +
    + @if (!setting('app-disable-comments')) +
    + @include('form.toggle-switch', [ + 'name' => 'preferences[own-page-comments]', + 'value' => $preferences->notifyOnOwnPageComments(), + 'label' => trans('preferences.notifications_opt_own_page_comments'), + ]) +
    +
    + @include('form.toggle-switch', [ + 'name' => 'preferences[comment-replies]', + 'value' => $preferences->notifyOnCommentReplies(), + 'label' => trans('preferences.notifications_opt_comment_replies'), + ]) +
    + @endif +
    + +
    + +
    +
    + +
    +
    + +
    +

    {{ trans('preferences.notifications_watched') }}

    +

    {{ trans('preferences.notifications_watched_desc') }}

    + + @if($watches->isEmpty()) +

    {{ trans('common.no_items') }}

    + @else +
    + @foreach($watches as $watch) +
    +
    + @include('entities.icon-link', ['entity' => $watch->watchable]) +
    +
    + @icon('watch' . ($watch->ignoring() ? '-ignore' : '')) + {{ trans('entities.watch_title_' . $watch->getLevelName()) }} +
    +
    + @endforeach +
    + @endif + +
    {{ $watches->links() }}
    +
    +@stop diff --git a/resources/views/users/preferences/parts/shortcut-control.blade.php b/resources/views/users/account/parts/shortcut-control.blade.php similarity index 100% rename from resources/views/users/preferences/parts/shortcut-control.blade.php rename to resources/views/users/account/parts/shortcut-control.blade.php diff --git a/resources/views/users/account/shortcuts.blade.php b/resources/views/users/account/shortcuts.blade.php new file mode 100644 index 000000000..d7d0f23ba --- /dev/null +++ b/resources/views/users/account/shortcuts.blade.php @@ -0,0 +1,71 @@ +@extends('users.account.layout') + +@section('main') +
    +
    + {{ method_field('put') }} + {{ csrf_field() }} + +

    {{ trans('preferences.shortcuts_interface') }}

    + +
    +

    + {{ trans('preferences.shortcuts_toggle_desc') }} + {{ trans('preferences.shortcuts_customize_desc') }} +

    +
    + @include('form.toggle-switch', [ + 'name' => 'enabled', + 'value' => $enabled, + 'label' => trans('preferences.shortcuts_toggle_label'), + ]) +
    +
    + +
    + +

    {{ trans('preferences.shortcuts_section_navigation') }}

    +
    +
    + @include('users.account.parts.shortcut-control', ['label' => trans('common.homepage'), 'id' => 'home_view']) + @include('users.account.parts.shortcut-control', ['label' => trans('entities.shelves'), 'id' => 'shelves_view']) + @include('users.account.parts.shortcut-control', ['label' => trans('entities.books'), 'id' => 'books_view']) + @include('users.account.parts.shortcut-control', ['label' => trans('settings.settings'), 'id' => 'settings_view']) + @include('users.account.parts.shortcut-control', ['label' => trans('entities.my_favourites'), 'id' => 'favourites_view']) +
    +
    + @include('users.account.parts.shortcut-control', ['label' => trans('common.view_profile'), 'id' => 'profile_view']) + @include('users.account.parts.shortcut-control', ['label' => trans('auth.logout'), 'id' => 'logout']) + @include('users.account.parts.shortcut-control', ['label' => trans('common.global_search'), 'id' => 'global_search']) + @include('users.account.parts.shortcut-control', ['label' => trans('common.next'), 'id' => 'next']) + @include('users.account.parts.shortcut-control', ['label' => trans('common.previous'), 'id' => 'previous']) +
    +
    + +

    {{ trans('preferences.shortcuts_section_actions') }}

    +
    +
    + @include('users.account.parts.shortcut-control', ['label' => trans('common.new'), 'id' => 'new']) + @include('users.account.parts.shortcut-control', ['label' => trans('common.edit'), 'id' => 'edit']) + @include('users.account.parts.shortcut-control', ['label' => trans('common.copy'), 'id' => 'copy']) + @include('users.account.parts.shortcut-control', ['label' => trans('common.delete'), 'id' => 'delete']) + @include('users.account.parts.shortcut-control', ['label' => trans('common.favourite'), 'id' => 'favourite']) +
    +
    + @include('users.account.parts.shortcut-control', ['label' => trans('entities.export'), 'id' => 'export']) + @include('users.account.parts.shortcut-control', ['label' => trans('common.sort'), 'id' => 'sort']) + @include('users.account.parts.shortcut-control', ['label' => trans('entities.permissions'), 'id' => 'permissions']) + @include('users.account.parts.shortcut-control', ['label' => trans('common.move'), 'id' => 'move']) + @include('users.account.parts.shortcut-control', ['label' => trans('entities.revisions'), 'id' => 'revisions']) +
    +
    + +

    {{ trans('preferences.shortcuts_overlay_desc') }}

    + +
    + +
    + +
    +
    +@stop diff --git a/resources/views/users/preferences/notifications.blade.php b/resources/views/users/preferences/notifications.blade.php deleted file mode 100644 index 9817aac4d..000000000 --- a/resources/views/users/preferences/notifications.blade.php +++ /dev/null @@ -1,75 +0,0 @@ -@extends('layouts.simple') - -@section('body') -
    - -
    -
    - {{ method_field('put') }} - {{ csrf_field() }} - -

    {{ trans('preferences.notifications') }}

    -

    {{ trans('preferences.notifications_desc') }}

    - -
    -
    -
    - @include('form.toggle-switch', [ - 'name' => 'preferences[own-page-changes]', - 'value' => $preferences->notifyOnOwnPageChanges(), - 'label' => trans('preferences.notifications_opt_own_page_changes'), - ]) -
    - @if (!setting('app-disable-comments')) -
    - @include('form.toggle-switch', [ - 'name' => 'preferences[own-page-comments]', - 'value' => $preferences->notifyOnOwnPageComments(), - 'label' => trans('preferences.notifications_opt_own_page_comments'), - ]) -
    -
    - @include('form.toggle-switch', [ - 'name' => 'preferences[comment-replies]', - 'value' => $preferences->notifyOnCommentReplies(), - 'label' => trans('preferences.notifications_opt_comment_replies'), - ]) -
    - @endif -
    - -
    - -
    -
    - -
    -
    - -
    -

    {{ trans('preferences.notifications_watched') }}

    -

    {{ trans('preferences.notifications_watched_desc') }}

    - - @if($watches->isEmpty()) -

    {{ trans('common.no_items') }}

    - @else -
    - @foreach($watches as $watch) -
    -
    - @include('entities.icon-link', ['entity' => $watch->watchable]) -
    -
    - @icon('watch' . ($watch->ignoring() ? '-ignore' : '')) - {{ trans('entities.watch_title_' . $watch->getLevelName()) }} -
    -
    - @endforeach -
    - @endif - -
    {{ $watches->links() }}
    -
    - -
    -@stop diff --git a/resources/views/users/preferences/shortcuts.blade.php b/resources/views/users/preferences/shortcuts.blade.php deleted file mode 100644 index 677892bc6..000000000 --- a/resources/views/users/preferences/shortcuts.blade.php +++ /dev/null @@ -1,75 +0,0 @@ -@extends('layouts.simple') - -@section('body') -
    - -
    -
    - {{ method_field('put') }} - {{ csrf_field() }} - -

    {{ trans('preferences.shortcuts_interface') }}

    - -
    -

    - {{ trans('preferences.shortcuts_toggle_desc') }} - {{ trans('preferences.shortcuts_customize_desc') }} -

    -
    - @include('form.toggle-switch', [ - 'name' => 'enabled', - 'value' => $enabled, - 'label' => trans('preferences.shortcuts_toggle_label'), - ]) -
    -
    - -
    - -

    {{ trans('preferences.shortcuts_section_navigation') }}

    -
    -
    - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.homepage'), 'id' => 'home_view']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('entities.shelves'), 'id' => 'shelves_view']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('entities.books'), 'id' => 'books_view']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('settings.settings'), 'id' => 'settings_view']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('entities.my_favourites'), 'id' => 'favourites_view']) -
    -
    - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.view_profile'), 'id' => 'profile_view']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('auth.logout'), 'id' => 'logout']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.global_search'), 'id' => 'global_search']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.next'), 'id' => 'next']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.previous'), 'id' => 'previous']) -
    -
    - -

    {{ trans('preferences.shortcuts_section_actions') }}

    -
    -
    - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.new'), 'id' => 'new']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.edit'), 'id' => 'edit']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.copy'), 'id' => 'copy']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.delete'), 'id' => 'delete']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.favourite'), 'id' => 'favourite']) -
    -
    - @include('users.preferences.parts.shortcut-control', ['label' => trans('entities.export'), 'id' => 'export']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.sort'), 'id' => 'sort']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('entities.permissions'), 'id' => 'permissions']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('common.move'), 'id' => 'move']) - @include('users.preferences.parts.shortcut-control', ['label' => trans('entities.revisions'), 'id' => 'revisions']) -
    -
    - -

    {{ trans('preferences.shortcuts_overlay_desc') }}

    - -
    - -
    - -
    -
    - -
    -@stop diff --git a/routes/web.php b/routes/web.php index 06dffa636..df845bfbc 100644 --- a/routes/web.php +++ b/routes/web.php @@ -232,18 +232,17 @@ Route::middleware('auth')->group(function () { Route::put('/settings/users/{id}', [UserControllers\UserController::class, 'update']); Route::delete('/settings/users/{id}', [UserControllers\UserController::class, 'destroy']); - // User Preferences - Route::get('/preferences', [UserControllers\UserPreferencesController::class, 'index']); - Route::get('/preferences/shortcuts', [UserControllers\UserPreferencesController::class, 'showShortcuts']); - Route::put('/preferences/shortcuts', [UserControllers\UserPreferencesController::class, 'updateShortcuts']); - Route::get('/preferences/notifications', [UserControllers\UserPreferencesController::class, 'showNotifications']); - Route::put('/preferences/notifications', [UserControllers\UserPreferencesController::class, 'updateNotifications']); + // User Account + Route::get('/my-account', [UserControllers\UserAccountController::class, 'index']); + Route::get('/my-account/shortcuts', [UserControllers\UserAccountController::class, 'showShortcuts']); + Route::put('/my-account/shortcuts', [UserControllers\UserAccountController::class, 'updateShortcuts']); + Route::get('/my-account/notifications', [UserControllers\UserAccountController::class, 'showNotifications']); + Route::put('/my-account/notifications', [UserControllers\UserAccountController::class, 'updateNotifications']); Route::patch('/preferences/change-view/{type}', [UserControllers\UserPreferencesController::class, 'changeView']); Route::patch('/preferences/change-sort/{type}', [UserControllers\UserPreferencesController::class, 'changeSort']); Route::patch('/preferences/change-expansion/{type}', [UserControllers\UserPreferencesController::class, 'changeExpansion']); Route::patch('/preferences/toggle-dark-mode', [UserControllers\UserPreferencesController::class, 'toggleDarkMode']); Route::patch('/preferences/update-code-language-favourite', [UserControllers\UserPreferencesController::class, 'updateCodeLanguageFavourite']); - Route::patch('/preferences/update-boolean', [UserControllers\UserPreferencesController::class, 'updateBooleanPreference']); // User API Tokens Route::get('/settings/users/{userId}/create-api-token', [UserApiTokenController::class, 'create']);