mirror of
https://github.com/BookStackApp/BookStack.git
synced 2024-10-01 01:36:00 -04:00
Notifications: Added new preferences view and access control
- Added general user preferences view and updated link in profile menu to suit. - Made notification permission required for notification preferences view, added test to cover.
This commit is contained in:
parent
d9fdecd902
commit
371779205a
@ -17,6 +17,14 @@ class UserPreferencesController extends Controller
|
|||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the overview for user preferences.
|
||||||
|
*/
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
return view('users.preferences.index');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the user-specific interface shortcuts.
|
* Show the user-specific interface shortcuts.
|
||||||
*/
|
*/
|
||||||
@ -53,6 +61,8 @@ class UserPreferencesController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function showNotifications(PermissionApplicator $permissions)
|
public function showNotifications(PermissionApplicator $permissions)
|
||||||
{
|
{
|
||||||
|
$this->checkPermission('receive-notifications');
|
||||||
|
|
||||||
$preferences = (new UserNotificationPreferences(user()));
|
$preferences = (new UserNotificationPreferences(user()));
|
||||||
|
|
||||||
$query = Watch::query()->where('user_id', '=', user()->id);
|
$query = Watch::query()->where('user_id', '=', user()->id);
|
||||||
@ -70,6 +80,7 @@ class UserPreferencesController extends Controller
|
|||||||
*/
|
*/
|
||||||
public function updateNotifications(Request $request)
|
public function updateNotifications(Request $request)
|
||||||
{
|
{
|
||||||
|
$this->checkPermission('receive-notifications');
|
||||||
$data = $this->validate($request, [
|
$data = $this->validate($request, [
|
||||||
'preferences' => ['required', 'array'],
|
'preferences' => ['required', 'array'],
|
||||||
'preferences.*' => ['required', 'string'],
|
'preferences.*' => ['required', 'string'],
|
||||||
|
@ -42,6 +42,7 @@ return [
|
|||||||
'remove' => 'Remove',
|
'remove' => 'Remove',
|
||||||
'add' => 'Add',
|
'add' => 'Add',
|
||||||
'configure' => 'Configure',
|
'configure' => 'Configure',
|
||||||
|
'manage' => 'Manage',
|
||||||
'fullscreen' => 'Fullscreen',
|
'fullscreen' => 'Fullscreen',
|
||||||
'favourite' => 'Favourite',
|
'favourite' => 'Favourite',
|
||||||
'unfavourite' => 'Unfavourite',
|
'unfavourite' => 'Unfavourite',
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
'preferences' => 'Preferences',
|
||||||
|
|
||||||
'shortcuts' => 'Shortcuts',
|
'shortcuts' => 'Shortcuts',
|
||||||
'shortcuts_interface' => 'Interface Keyboard Shortcuts',
|
'shortcuts_interface' => 'Interface Keyboard Shortcuts',
|
||||||
'shortcuts_toggle_desc' => 'Here you can enable or disable keyboard system interface shortcuts, used for navigation and actions.',
|
'shortcuts_toggle_desc' => 'Here you can enable or disable keyboard system interface shortcuts, used for navigation and actions.',
|
||||||
@ -15,6 +17,7 @@ return [
|
|||||||
'shortcuts_save' => 'Save Shortcuts',
|
'shortcuts_save' => 'Save Shortcuts',
|
||||||
'shortcuts_overlay_desc' => 'Note: When shortcuts are enabled a helper overlay is available via pressing "?" which will highlight the available shortcuts for actions currently visible on the screen.',
|
'shortcuts_overlay_desc' => 'Note: When shortcuts are enabled a helper overlay is available via pressing "?" which will highlight the available shortcuts for actions currently visible on the screen.',
|
||||||
'shortcuts_update_success' => 'Shortcut preferences have been updated!',
|
'shortcuts_update_success' => 'Shortcut preferences have been updated!',
|
||||||
|
'shortcuts_overview_desc' => 'Manage keyboard shortcuts you can use to navigate the system user interface.',
|
||||||
|
|
||||||
'notifications' => 'Notification Preferences',
|
'notifications' => 'Notification Preferences',
|
||||||
'notifications_desc' => 'Control the email notifications you receive when certain activity is performed within the system.',
|
'notifications_desc' => 'Control the email notifications you receive when certain activity is performed within the system.',
|
||||||
@ -25,4 +28,6 @@ return [
|
|||||||
'notifications_update_success' => 'Notification preferences have been updated!',
|
'notifications_update_success' => 'Notification preferences have been updated!',
|
||||||
'notifications_watched' => 'Watched & Ignored Items',
|
'notifications_watched' => 'Watched & Ignored Items',
|
||||||
'notifications_watched_desc' => ' Below are the items that have custom watch preferences applied. To update your preferences for these, view the item then find the watch options in the sidebar.',
|
'notifications_watched_desc' => ' Below are the items that have custom watch preferences applied. To update your preferences for these, view the item then find the watch options in the sidebar.',
|
||||||
|
|
||||||
|
'profile_overview_desc' => ' Manage your user profile details including preferred language and authentication options.',
|
||||||
];
|
];
|
||||||
|
1
resources/icons/user-preferences.svg
Normal file
1
resources/icons/user-preferences.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><g><circle cx="10" cy="8" r="4"/><path d="M10.67,13.02C10.45,13.01,10.23,13,10,13c-2.42,0-4.68,0.67-6.61,1.82C2.51,15.34,2,16.32,2,17.35V20h9.26 C10.47,18.87,10,17.49,10,16C10,14.93,10.25,13.93,10.67,13.02z"/><path d="M20.75,16c0-0.22-0.03-0.42-0.06-0.63l1.14-1.01l-1-1.73l-1.45,0.49c-0.32-0.27-0.68-0.48-1.08-0.63L18,11h-2l-0.3,1.49 c-0.4,0.15-0.76,0.36-1.08,0.63l-1.45-0.49l-1,1.73l1.14,1.01c-0.03,0.21-0.06,0.41-0.06,0.63s0.03,0.42,0.06,0.63l-1.14,1.01 l1,1.73l1.45-0.49c0.32,0.27,0.68,0.48,1.08,0.63L16,21h2l0.3-1.49c0.4-0.15,0.76-0.36,1.08-0.63l1.45,0.49l1-1.73l-1.14-1.01 C20.72,16.42,20.75,16.22,20.75,16z M17,18c-1.1,0-2-0.9-2-2s0.9-2,2-2s2,0.9,2,2S18.1,18,17,18z"/></g></g></svg>
|
After Width: | Height: | Size: 752 B |
@ -104,9 +104,9 @@
|
|||||||
</li>
|
</li>
|
||||||
<li><hr></li>
|
<li><hr></li>
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ url('/preferences/shortcuts') }}" class="icon-item">
|
<a href="{{ url('/preferences') }}" class="icon-item">
|
||||||
@icon('shortcuts')
|
@icon('user-preferences')
|
||||||
<div>{{ trans('preferences.shortcuts') }}</div>
|
<div>{{ trans('preferences.preferences') }}</div>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
41
resources/views/users/preferences/index.blade.php
Normal file
41
resources/views/users/preferences/index.blade.php
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
@extends('layouts.simple')
|
||||||
|
|
||||||
|
@section('body')
|
||||||
|
<div class="container small my-xl">
|
||||||
|
|
||||||
|
<section class="card content-wrap auto-height items-center justify-space-between gap-m flex-container-row">
|
||||||
|
<div>
|
||||||
|
<h2 class="list-heading">{{ trans('preferences.shortcuts_interface') }}</h2>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
@if(userCan('receive-notifications'))
|
||||||
|
<section class="card content-wrap auto-height items-center justify-space-between gap-m flex-container-row">
|
||||||
|
<div>
|
||||||
|
<h2 class="list-heading">{{ trans('preferences.notifications') }}</h2>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@if(signedInUser())
|
||||||
|
<section class="card content-wrap auto-height items-center justify-space-between gap-m flex-container-row">
|
||||||
|
<div>
|
||||||
|
<h2 class="list-heading">{{ trans('settings.users_edit_profile') }}</h2>
|
||||||
|
<p class="text-muted">{{ trans('preferences.profile_overview_desc') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="text-right">
|
||||||
|
<a href="{{ user()->getEditUrl() }}" class="button outline">{{ trans('common.manage') }}</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
</div>
|
||||||
|
@stop
|
@ -11,7 +11,8 @@
|
|||||||
<h1 class="list-heading">{{ trans('preferences.notifications') }}</h1>
|
<h1 class="list-heading">{{ trans('preferences.notifications') }}</h1>
|
||||||
<p class="text-small text-muted">{{ trans('preferences.notifications_desc') }}</p>
|
<p class="text-small text-muted">{{ trans('preferences.notifications_desc') }}</p>
|
||||||
|
|
||||||
<div class="toggle-switch-list">
|
<div class="flex-container-row wrap justify-space-between pb-m">
|
||||||
|
<div class="toggle-switch-list min-width-l">
|
||||||
<div>
|
<div>
|
||||||
@include('form.toggle-switch', [
|
@include('form.toggle-switch', [
|
||||||
'name' => 'preferences[own-page-changes]',
|
'name' => 'preferences[own-page-changes]',
|
||||||
@ -35,9 +36,11 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group text-right">
|
<div class="mt-auto">
|
||||||
<button class="button">{{ trans('preferences.notifications_save') }}</button>
|
<button class="button">{{ trans('preferences.notifications_save') }}</button>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
@ -231,7 +231,7 @@ Route::middleware('auth')->group(function () {
|
|||||||
Route::delete('/settings/users/{id}', [UserControllers\UserController::class, 'destroy']);
|
Route::delete('/settings/users/{id}', [UserControllers\UserController::class, 'destroy']);
|
||||||
|
|
||||||
// User Preferences
|
// User Preferences
|
||||||
Route::redirect('/preferences', '/');
|
Route::get('/preferences', [UserControllers\UserPreferencesController::class, 'index']);
|
||||||
Route::get('/preferences/shortcuts', [UserControllers\UserPreferencesController::class, 'showShortcuts']);
|
Route::get('/preferences/shortcuts', [UserControllers\UserPreferencesController::class, 'showShortcuts']);
|
||||||
Route::put('/preferences/shortcuts', [UserControllers\UserPreferencesController::class, 'updateShortcuts']);
|
Route::put('/preferences/shortcuts', [UserControllers\UserPreferencesController::class, 'updateShortcuts']);
|
||||||
Route::get('/preferences/notifications', [UserControllers\UserPreferencesController::class, 'showNotifications']);
|
Route::get('/preferences/notifications', [UserControllers\UserPreferencesController::class, 'showNotifications']);
|
||||||
|
@ -6,6 +6,22 @@ use Tests\TestCase;
|
|||||||
|
|
||||||
class UserPreferencesTest extends TestCase
|
class UserPreferencesTest extends TestCase
|
||||||
{
|
{
|
||||||
|
public function test_index_view()
|
||||||
|
{
|
||||||
|
$resp = $this->asEditor()->get('/preferences');
|
||||||
|
$resp->assertOk();
|
||||||
|
$resp->assertSee('Interface Keyboard Shortcuts');
|
||||||
|
$resp->assertSee('Edit Profile');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_index_view_accessible_but_without_profile_for_guest_user()
|
||||||
|
{
|
||||||
|
$this->setSettings(['app-public' => 'true']);
|
||||||
|
$resp = $this->get('/preferences');
|
||||||
|
$resp->assertOk();
|
||||||
|
$resp->assertSee('Interface Keyboard Shortcuts');
|
||||||
|
$resp->assertDontSee('Edit Profile');
|
||||||
|
}
|
||||||
public function test_interface_shortcuts_updating()
|
public function test_interface_shortcuts_updating()
|
||||||
{
|
{
|
||||||
$this->asEditor();
|
$this->asEditor();
|
||||||
@ -45,12 +61,28 @@ class UserPreferencesTest extends TestCase
|
|||||||
$this->withHtml($this->get('/'))->assertElementExists('body[component="shortcuts"]');
|
$this->withHtml($this->get('/'))->assertElementExists('body[component="shortcuts"]');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_notification_routes_requires_notification_permission()
|
||||||
|
{
|
||||||
|
$viewer = $this->users->viewer();
|
||||||
|
$resp = $this->actingAs($viewer)->get('/preferences/notifications');
|
||||||
|
$this->assertPermissionError($resp);
|
||||||
|
|
||||||
|
$resp = $this->put('/preferences/notifications');
|
||||||
|
$this->assertPermissionError($resp);
|
||||||
|
|
||||||
|
$this->permissions->grantUserRolePermissions($viewer, ['receive-notifications']);
|
||||||
|
$resp = $this->get('/preferences/notifications');
|
||||||
|
$resp->assertOk();
|
||||||
|
$resp->assertSee('Notification Preferences');
|
||||||
|
}
|
||||||
|
|
||||||
public function test_notification_preferences_updating()
|
public function test_notification_preferences_updating()
|
||||||
{
|
{
|
||||||
$this->asEditor();
|
$editor = $this->users->editor();
|
||||||
|
$this->permissions->grantUserRolePermissions($editor, ['receive-notifications']);
|
||||||
|
|
||||||
// View preferences with defaults
|
// View preferences with defaults
|
||||||
$resp = $this->get('/preferences/notifications');
|
$resp = $this->actingAs($editor)->get('/preferences/notifications');
|
||||||
$resp->assertSee('Notification Preferences');
|
$resp->assertSee('Notification Preferences');
|
||||||
|
|
||||||
$html = $this->withHtml($resp);
|
$html = $this->withHtml($resp);
|
||||||
|
Loading…
Reference in New Issue
Block a user