- Moved preference views to more general "my-account" area.
- Started new layout for my-account with sidebar.
- Added MFA to prefeences view (to be moved).
--- /dev/null
+<?php
+
+namespace BookStack\Users\Controllers;
+
+use BookStack\Http\Controller;
+use BookStack\Permissions\PermissionApplicator;
+use BookStack\Settings\UserNotificationPreferences;
+use BookStack\Settings\UserShortcutMap;
+use BookStack\Users\UserRepo;
+use Illuminate\Http\Request;
+
+class UserAccountController extends Controller
+{
+ public function __construct(
+ protected UserRepo $userRepo
+ ) {
+ }
+
+ /**
+ * Show the overview for user preferences.
+ */
+ public function index()
+ {
+ $guest = user()->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');
+ }
+}
) {
}
- /**
- * 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.
*/
*/
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',
--- /dev/null
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"/></svg>
\ No newline at end of file
</li>
<li><hr></li>
<li>
- <a href="{{ url('/preferences') }}" class="icon-item">
+ <a href="{{ url('/my-account') }}" class="icon-item">
@icon('user-preferences')
- <div>{{ trans('preferences.preferences') }}</div>
+ <div>{{ trans('preferences.my_account') }}</div>
</a>
</li>
<li>
<p class="text-muted">{{ trans('preferences.shortcuts_overview_desc') }}</p>
</div>
<div class="text-right">
- <a href="{{ url('/preferences/shortcuts') }}" class="button outline">{{ trans('common.manage') }}</a>
+ <a href="{{ url('/my-account/shortcuts') }}" class="button outline">{{ trans('common.manage') }}</a>
</div>
</section>
<p class="text-muted">{{ trans('preferences.notifications_desc') }}</p>
</div>
<div class="text-right">
- <a href="{{ url('/preferences/notifications') }}" class="button outline">{{ trans('common.manage') }}</a>
+ <a href="{{ url('/my-account/notifications') }}" class="button outline">{{ trans('common.manage') }}</a>
</div>
</section>
@endif
</section>
@endif
+ @if(!user()->isGuest())
+ <section class="card content-wrap auto-height items-center flex-container-row gap-m gap-x-l wrap justify-space-between">
+ <div class="flex-min-width-m">
+ <h2 class="list-heading">{{ trans('settings.users_mfa') }}</h2>
+ <p class="text-muted">{{ trans('settings.users_mfa_desc') }}</p>
+ <p class="text-muted">
+ @if ($mfaMethods->count() > 0)
+ <span class="text-pos">@icon('check-circle')</span>
+ @else
+ <span class="text-neg">@icon('cancel')</span>
+ @endif
+ {{ trans_choice('settings.users_mfa_x_methods', $mfaMethods->count()) }}
+ </p>
+ </div>
+ <div class="text-right">
+ <a href="{{ url('/mfa/setup') }}"
+ class="button outline">{{ trans('common.manage') }}</a>
+ </div>
+ </section>
+ @endif
+
</div>
@stop
--- /dev/null
+@extends('layouts.simple')
+
+@section('body')
+ <div class="container medium">
+
+ <div class="grid gap-xxl right-focus my-xl">
+
+ <div>
+ <div class="sticky-top-m">
+ <h5>{{ trans('preferences.my_account') }}</h5>
+ <nav class="active-link-list in-sidebar">
+ <a href="{{ url('/my-account/shortcuts') }}" class="{{ 'shortcuts' === 'shortcuts' ? 'active' : '' }}">@icon('shortcuts') {{ trans('preferences.shortcuts_interface') }}</a>
+ <a href="{{ url('/my-account/notifications') }}" class="{{ '' === 'notifications' ? 'active' : '' }}">@icon('notifications') {{ trans('preferences.notifications') }}</a>
+ <a href="{{ url('/my-account/auth') }}" class="{{ '' === 'auth' ? 'active' : '' }}">@icon('lock') {{ 'Access & Security' }}</a>
+ </nav>
+ </div>
+ </div>
+
+ <div>
+ @yield('main')
+ </div>
+
+ </div>
+
+ </div>
+@stop
\ No newline at end of file
--- /dev/null
+@extends('users.account.layout')
+
+@section('main')
+ <section class="card content-wrap auto-height">
+ <form action="{{ url('/my-account/notifications') }}" method="post">
+ {{ method_field('put') }}
+ {{ csrf_field() }}
+
+ <h1 class="list-heading">{{ trans('preferences.notifications') }}</h1>
+ <p class="text-small text-muted">{{ trans('preferences.notifications_desc') }}</p>
+
+ <div class="flex-container-row wrap justify-space-between pb-m">
+ <div class="toggle-switch-list min-width-l">
+ <div>
+ @include('form.toggle-switch', [
+ 'name' => 'preferences[own-page-changes]',
+ 'value' => $preferences->notifyOnOwnPageChanges(),
+ 'label' => trans('preferences.notifications_opt_own_page_changes'),
+ ])
+ </div>
+ @if (!setting('app-disable-comments'))
+ <div>
+ @include('form.toggle-switch', [
+ 'name' => 'preferences[own-page-comments]',
+ 'value' => $preferences->notifyOnOwnPageComments(),
+ 'label' => trans('preferences.notifications_opt_own_page_comments'),
+ ])
+ </div>
+ <div>
+ @include('form.toggle-switch', [
+ 'name' => 'preferences[comment-replies]',
+ 'value' => $preferences->notifyOnCommentReplies(),
+ 'label' => trans('preferences.notifications_opt_comment_replies'),
+ ])
+ </div>
+ @endif
+ </div>
+
+ <div class="mt-auto">
+ <button class="button">{{ trans('preferences.notifications_save') }}</button>
+ </div>
+ </div>
+
+ </form>
+ </section>
+
+ <section class="card content-wrap auto-height">
+ <h2 class="list-heading">{{ trans('preferences.notifications_watched') }}</h2>
+ <p class="text-small text-muted">{{ trans('preferences.notifications_watched_desc') }}</p>
+
+ @if($watches->isEmpty())
+ <p class="text-muted italic">{{ trans('common.no_items') }}</p>
+ @else
+ <div class="item-list">
+ @foreach($watches as $watch)
+ <div class="flex-container-row justify-space-between item-list-row items-center wrap px-m py-s">
+ <div class="py-xs px-s min-width-m">
+ @include('entities.icon-link', ['entity' => $watch->watchable])
+ </div>
+ <div class="py-xs min-width-m text-m-right px-m">
+ @icon('watch' . ($watch->ignoring() ? '-ignore' : ''))
+ {{ trans('entities.watch_title_' . $watch->getLevelName()) }}
+ </div>
+ </div>
+ @endforeach
+ </div>
+ @endif
+
+ <div class="my-m">{{ $watches->links() }}</div>
+ </section>
+@stop
--- /dev/null
+@extends('users.account.layout')
+
+@section('main')
+ <section class="card content-wrap">
+ <form action="{{ url('/my-account/shortcuts') }}" method="post">
+ {{ method_field('put') }}
+ {{ csrf_field() }}
+
+ <h1 class="list-heading">{{ trans('preferences.shortcuts_interface') }}</h1>
+
+ <div class="flex-container-row items-center gap-m wrap mb-m">
+ <p class="flex mb-none min-width-m text-small text-muted">
+ {{ trans('preferences.shortcuts_toggle_desc') }}
+ {{ trans('preferences.shortcuts_customize_desc') }}
+ </p>
+ <div class="flex min-width-m text-m-center">
+ @include('form.toggle-switch', [
+ 'name' => 'enabled',
+ 'value' => $enabled,
+ 'label' => trans('preferences.shortcuts_toggle_label'),
+ ])
+ </div>
+ </div>
+
+ <hr>
+
+ <h2 class="list-heading mb-m">{{ trans('preferences.shortcuts_section_navigation') }}</h2>
+ <div class="flex-container-row wrap gap-m mb-xl">
+ <div class="flex min-width-l item-list">
+ @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'])
+ </div>
+ <div class="flex min-width-l item-list">
+ @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'])
+ </div>
+ </div>
+
+ <h2 class="list-heading mb-m">{{ trans('preferences.shortcuts_section_actions') }}</h2>
+ <div class="flex-container-row wrap gap-m mb-xl">
+ <div class="flex min-width-l item-list">
+ @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'])
+ </div>
+ <div class="flex min-width-l item-list">
+ @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'])
+ </div>
+ </div>
+
+ <p class="text-small text-muted">{{ trans('preferences.shortcuts_overlay_desc') }}</p>
+
+ <div class="form-group text-right">
+ <button class="button">{{ trans('preferences.shortcuts_save') }}</button>
+ </div>
+
+ </form>
+ </section>
+@stop
+++ /dev/null
-@extends('layouts.simple')
-
-@section('body')
- <div class="container small my-xl">
-
- <section class="card content-wrap auto-height">
- <form action="{{ url('/preferences/notifications') }}" method="post">
- {{ method_field('put') }}
- {{ csrf_field() }}
-
- <h1 class="list-heading">{{ trans('preferences.notifications') }}</h1>
- <p class="text-small text-muted">{{ trans('preferences.notifications_desc') }}</p>
-
- <div class="flex-container-row wrap justify-space-between pb-m">
- <div class="toggle-switch-list min-width-l">
- <div>
- @include('form.toggle-switch', [
- 'name' => 'preferences[own-page-changes]',
- 'value' => $preferences->notifyOnOwnPageChanges(),
- 'label' => trans('preferences.notifications_opt_own_page_changes'),
- ])
- </div>
- @if (!setting('app-disable-comments'))
- <div>
- @include('form.toggle-switch', [
- 'name' => 'preferences[own-page-comments]',
- 'value' => $preferences->notifyOnOwnPageComments(),
- 'label' => trans('preferences.notifications_opt_own_page_comments'),
- ])
- </div>
- <div>
- @include('form.toggle-switch', [
- 'name' => 'preferences[comment-replies]',
- 'value' => $preferences->notifyOnCommentReplies(),
- 'label' => trans('preferences.notifications_opt_comment_replies'),
- ])
- </div>
- @endif
- </div>
-
- <div class="mt-auto">
- <button class="button">{{ trans('preferences.notifications_save') }}</button>
- </div>
- </div>
-
- </form>
- </section>
-
- <section class="card content-wrap auto-height">
- <h2 class="list-heading">{{ trans('preferences.notifications_watched') }}</h2>
- <p class="text-small text-muted">{{ trans('preferences.notifications_watched_desc') }}</p>
-
- @if($watches->isEmpty())
- <p class="text-muted italic">{{ trans('common.no_items') }}</p>
- @else
- <div class="item-list">
- @foreach($watches as $watch)
- <div class="flex-container-row justify-space-between item-list-row items-center wrap px-m py-s">
- <div class="py-xs px-s min-width-m">
- @include('entities.icon-link', ['entity' => $watch->watchable])
- </div>
- <div class="py-xs min-width-m text-m-right px-m">
- @icon('watch' . ($watch->ignoring() ? '-ignore' : ''))
- {{ trans('entities.watch_title_' . $watch->getLevelName()) }}
- </div>
- </div>
- @endforeach
- </div>
- @endif
-
- <div class="my-m">{{ $watches->links() }}</div>
- </section>
-
- </div>
-@stop
+++ /dev/null
-@extends('layouts.simple')
-
-@section('body')
- <div class="container small my-xl">
-
- <section class="card content-wrap">
- <form action="{{ url('/preferences/shortcuts') }}" method="post">
- {{ method_field('put') }}
- {{ csrf_field() }}
-
- <h1 class="list-heading">{{ trans('preferences.shortcuts_interface') }}</h1>
-
- <div class="flex-container-row items-center gap-m wrap mb-m">
- <p class="flex mb-none min-width-m text-small text-muted">
- {{ trans('preferences.shortcuts_toggle_desc') }}
- {{ trans('preferences.shortcuts_customize_desc') }}
- </p>
- <div class="flex min-width-m text-m-center">
- @include('form.toggle-switch', [
- 'name' => 'enabled',
- 'value' => $enabled,
- 'label' => trans('preferences.shortcuts_toggle_label'),
- ])
- </div>
- </div>
-
- <hr>
-
- <h2 class="list-heading mb-m">{{ trans('preferences.shortcuts_section_navigation') }}</h2>
- <div class="flex-container-row wrap gap-m mb-xl">
- <div class="flex min-width-l item-list">
- @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'])
- </div>
- <div class="flex min-width-l item-list">
- @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'])
- </div>
- </div>
-
- <h2 class="list-heading mb-m">{{ trans('preferences.shortcuts_section_actions') }}</h2>
- <div class="flex-container-row wrap gap-m mb-xl">
- <div class="flex min-width-l item-list">
- @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'])
- </div>
- <div class="flex min-width-l item-list">
- @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'])
- </div>
- </div>
-
- <p class="text-small text-muted">{{ trans('preferences.shortcuts_overlay_desc') }}</p>
-
- <div class="form-group text-right">
- <button class="button">{{ trans('preferences.shortcuts_save') }}</button>
- </div>
-
- </form>
- </section>
-
- </div>
-@stop
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']);