From f19bad89033ee31e9157341214ae3a7e3b0fbb40 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Oct 2022 13:17:28 +0100 Subject: [PATCH 01/19] Started item permission design revamp --- resources/icons/role.svg | 4 +++ resources/sass/_components.scss | 31 ++++++++++++++++--- resources/sass/_layout.scss | 4 +-- resources/sass/_spacing.scss | 14 ++++++++- .../form/entity-permissions-row.blade.php | 28 +++++++++++++++++ .../views/form/entity-permissions.blade.php | 25 ++------------- 6 files changed, 77 insertions(+), 29 deletions(-) create mode 100644 resources/icons/role.svg create mode 100644 resources/views/form/entity-permissions-row.blade.php diff --git a/resources/icons/role.svg b/resources/icons/role.svg new file mode 100644 index 000000000..e7cad506d --- /dev/null +++ b/resources/icons/role.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/resources/sass/_components.scss b/resources/sass/_components.scss index c00f57954..9f737f3be 100644 --- a/resources/sass/_components.scss +++ b/resources/sass/_components.scss @@ -798,11 +798,34 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { max-width: 500px; } -.permissions-table [permissions-table-toggle-all-in-row] { - display: none; +.content-permissions { + box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1); } -.permissions-table tr:hover [permissions-table-toggle-all-in-row] { - display: inline; +.content-permissions-row { + border: 1.5px solid #E2E2E2; + border-bottom-width: 0; + label { + padding-bottom: 0; + } + &:hover { + background-color: #F2F2F2; + } +} +.content-permissions-row:first-child { + border-radius: 4px 4px 0 0; +} +.content-permissions-row:last-child { + border-radius: 0 0 4px 4px; + border-bottom-width: 1.5px; +} +.content-permissions-row-toggle-all { + visibility: hidden; +} +.content-permissions-row:hover .content-permissions-row-toggle-all { + visibility: visible; +} +.content-permissions-row-label { + font-weight: bold; } .template-item { diff --git a/resources/sass/_layout.scss b/resources/sass/_layout.scss index 2cd57d496..cfb8397c9 100644 --- a/resources/sass/_layout.scss +++ b/resources/sass/_layout.scss @@ -158,8 +158,8 @@ body.flexbox { } } -.gap-m { - gap: $-m; +.flex-none { + flex: none; } .justify-flex-start { diff --git a/resources/sass/_spacing.scss b/resources/sass/_spacing.scss index 40217de9b..14f8918dc 100644 --- a/resources/sass/_spacing.scss +++ b/resources/sass/_spacing.scss @@ -29,4 +29,16 @@ } } @include spacing('margin', 'm'); -@include spacing('padding', 'p'); \ No newline at end of file +@include spacing('padding', 'p'); + +@each $sizeLetter, $size in $spacing { + .gap-#{$sizeLetter} { + gap: $size !important; + } + .gap-x-#{$sizeLetter} { + column-gap: $size !important; + } + .gap-y-#{$sizeLetter} { + row-gap: $size !important; + } +} diff --git a/resources/views/form/entity-permissions-row.blade.php b/resources/views/form/entity-permissions-row.blade.php new file mode 100644 index 000000000..023aa36d2 --- /dev/null +++ b/resources/views/form/entity-permissions-row.blade.php @@ -0,0 +1,28 @@ +
+
+
+ @icon('role') +
+ {{ $role->display_name }} + +
+
+
+ @include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.view'), 'action' => 'view']) +
+
+ @if(!$model->isA('page')) + @include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.create'), 'action' => 'create']) + @endif +
+
+ @include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.update'), 'action' => 'update']) +
+
+ @include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.delete'), 'action' => 'delete']) +
+
+
\ No newline at end of file diff --git a/resources/views/form/entity-permissions.blade.php b/resources/views/form/entity-permissions.blade.php index 206955fe9..18df0bb69 100644 --- a/resources/views/form/entity-permissions.blade.php +++ b/resources/views/form/entity-permissions.blade.php @@ -24,31 +24,12 @@

{{ trans('entities.shelves_permissions_cascade_warning') }}

@endif -
- - - - - +
@foreach(\BookStack\Auth\Role::restrictable() as $role) -
- - - @if(!$model->isA('page')) - - @endif - - - + @include('form.entity-permissions-row', ['role' => $role, 'model' => $model]) @endforeach -
{{ trans('common.role') }} - {{ trans('common.actions') }} - {{ trans('common.toggle_all') }} -
- {{ $role->display_name }} - {{ trans('common.toggle_all') }} - @include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.view'), 'action' => 'view'])@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.create'), 'action' => 'create'])@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.update'), 'action' => 'update'])@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.delete'), 'action' => 'delete'])
+
{{ trans('common.cancel') }} From b8b0afa0df6f9a63438c214fc08664e6b4cd3455 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Oct 2022 13:57:32 +0100 Subject: [PATCH 02/19] Cleaned up old permission JS code Removed now unused JS entity-permissions compontent. Updated existing permissions-table compontent to newer format. Removed now unused translation string. --- .../components/entity-permissions-editor.js | 20 ------------- resources/js/components/index.js | 2 -- resources/js/components/permissions-table.js | 15 +++++----- resources/lang/en/entities.php | 1 - .../form/entity-permissions-row.blade.php | 6 ++-- .../views/form/entity-permissions.blade.php | 9 +----- .../views/settings/roles/parts/form.blade.php | 30 +++++++++---------- 7 files changed, 26 insertions(+), 57 deletions(-) delete mode 100644 resources/js/components/entity-permissions-editor.js diff --git a/resources/js/components/entity-permissions-editor.js b/resources/js/components/entity-permissions-editor.js deleted file mode 100644 index a821792a0..000000000 --- a/resources/js/components/entity-permissions-editor.js +++ /dev/null @@ -1,20 +0,0 @@ - -class EntityPermissionsEditor { - - constructor(elem) { - this.permissionsTable = elem.querySelector('[permissions-table]'); - - // Handle toggle all event - this.restrictedCheckbox = elem.querySelector('[name=restricted]'); - this.restrictedCheckbox.addEventListener('change', this.updateTableVisibility.bind(this)); - } - - updateTableVisibility() { - this.permissionsTable.style.display = - this.restrictedCheckbox.checked - ? null - : 'none'; - } -} - -export default EntityPermissionsEditor; \ No newline at end of file diff --git a/resources/js/components/index.js b/resources/js/components/index.js index f360e2b0c..4b17dc403 100644 --- a/resources/js/components/index.js +++ b/resources/js/components/index.js @@ -18,7 +18,6 @@ import dropdown from "./dropdown.js" import dropdownSearch from "./dropdown-search.js" import dropzone from "./dropzone.js" import editorToolbox from "./editor-toolbox.js" -import entityPermissionsEditor from "./entity-permissions-editor.js" import entitySearch from "./entity-search.js" import entitySelector from "./entity-selector.js" import entitySelectorPopup from "./entity-selector-popup.js" @@ -75,7 +74,6 @@ const componentMapping = { "dropdown-search": dropdownSearch, "dropzone": dropzone, "editor-toolbox": editorToolbox, - "entity-permissions-editor": entityPermissionsEditor, "entity-search": entitySearch, "entity-selector": entitySelector, "entity-selector-popup": entitySelectorPopup, diff --git a/resources/js/components/permissions-table.js b/resources/js/components/permissions-table.js index baad75258..df3c055ca 100644 --- a/resources/js/components/permissions-table.js +++ b/resources/js/components/permissions-table.js @@ -1,22 +1,21 @@ class PermissionsTable { - constructor(elem) { - this.container = elem; + setup() { + this.container = this.$el; // Handle toggle all event - const toggleAll = elem.querySelector('[permissions-table-toggle-all]'); - toggleAll.addEventListener('click', this.toggleAllClick.bind(this)); + for (const toggleAllElem of (this.$manyRefs.toggleAll || [])) { + toggleAllElem.addEventListener('click', this.toggleAllClick.bind(this)); + } // Handle toggle row event - const toggleRowElems = elem.querySelectorAll('[permissions-table-toggle-all-in-row]'); - for (let toggleRowElem of toggleRowElems) { + for (const toggleRowElem of (this.$manyRefs.toggleRow || [])) { toggleRowElem.addEventListener('click', this.toggleRowClick.bind(this)); } // Handle toggle column event - const toggleColumnElems = elem.querySelectorAll('[permissions-table-toggle-all-in-column]'); - for (let toggleColElem of toggleColumnElems) { + for (const toggleColElem of (this.$manyRefs.toggleColumn || [])) { toggleColElem.addEventListener('click', this.toggleColumnClick.bind(this)); } } diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index 1720801d2..28ec591d7 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -43,7 +43,6 @@ return [ // Permissions and restrictions 'permissions' => 'Permissions', 'permissions_intro' => 'Once enabled, These permissions will take priority over any set role permissions.', - 'permissions_enable' => 'Enable Custom Permissions', 'permissions_save' => 'Save Permissions', 'permissions_owner' => 'Owner', diff --git a/resources/views/form/entity-permissions-row.blade.php b/resources/views/form/entity-permissions-row.blade.php index 023aa36d2..bff7315a0 100644 --- a/resources/views/form/entity-permissions-row.blade.php +++ b/resources/views/form/entity-permissions-row.blade.php @@ -1,4 +1,4 @@ -
+
@icon('role') @@ -6,7 +6,7 @@ {{ $role->display_name }}
@@ -14,7 +14,7 @@ @include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.view'), 'action' => 'view'])
- @if(!$model->isA('page')) + @if(!$model instanceof \BookStack\Entities\Models\Page) @include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.create'), 'action' => 'create']) @endif
diff --git a/resources/views/form/entity-permissions.blade.php b/resources/views/form/entity-permissions.blade.php index 18df0bb69..321e2f06c 100644 --- a/resources/views/form/entity-permissions.blade.php +++ b/resources/views/form/entity-permissions.blade.php @@ -1,16 +1,10 @@ -
+ {!! csrf_field() !!}

{{ trans('entities.permissions_intro') }}

-
- @include('form.checkbox', [ - 'name' => 'restricted', - 'label' => trans('entities.permissions_enable'), - ]) -
@@ -24,7 +18,6 @@

{{ trans('entities.shelves_permissions_cascade_warning') }}

@endif -
@foreach(\BookStack\Auth\Role::restrictable() as $role) @include('form.entity-permissions-row', ['role' => $role, 'model' => $model]) diff --git a/resources/views/settings/roles/parts/form.blade.php b/resources/views/settings/roles/parts/form.blade.php index 593791997..044b4ceb4 100644 --- a/resources/views/settings/roles/parts/form.blade.php +++ b/resources/views/settings/roles/parts/form.blade.php @@ -26,9 +26,9 @@
-
+
- {{ trans('common.toggle_all') }} + {{ trans('common.toggle_all') }}
@@ -56,20 +56,20 @@

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

@endif - +
- - - - + + + + @@ -187,7 +187,7 @@ @@ -205,7 +205,7 @@ From a03245e427d3257eeb2bbf137e8e6ce1388c1e69 Mon Sep 17 00:00:00 2001 From: Dan Brown Date: Sun, 2 Oct 2022 18:09:48 +0100 Subject: [PATCH 03/19] Added user-interface for "Everyone Else" entity permission item Nothing on back-end logic done to hook this new option up. Addition of permissions for role_id=0 works out of the box, but active "everyone else" permissions, with no priviliges, is currently not working. Needs change of permission gen logic also. --- app/Auth/Role.php | 13 +++++++ app/Entities/Models/Entity.php | 6 ++- resources/icons/groups.svg | 1 + resources/js/components/entity-permissions.js | 24 ++++++++++++ resources/js/components/index.js | 2 + resources/sass/_components.scss | 3 -- resources/sass/_forms.scss | 9 +++++ .../views/form/custom-checkbox.blade.php | 2 +- .../form/entity-permissions-row.blade.php | 38 ++++++++++++++----- .../views/form/entity-permissions.blade.php | 6 ++- 10 files changed, 87 insertions(+), 17 deletions(-) create mode 100644 resources/icons/groups.svg create mode 100644 resources/js/components/entity-permissions.js diff --git a/app/Auth/Role.php b/app/Auth/Role.php index 51b2ce301..3ae469b59 100644 --- a/app/Auth/Role.php +++ b/app/Auth/Role.php @@ -120,6 +120,19 @@ class Role extends Model implements Loggable ->get(); } + /** + * Get a role to represent the case of 'Everyone else' in the system. + * Used within the interface since the default-fallback for permissions uses role_id=0. + */ + public static function getEveryoneElseRole(): self + { + return (new static())->forceFill([ + 'id' => 0, + 'display_name' => 'Everyone Else', + 'description' => 'Set permissions for all roles not specifically overridden.' + ]); + } + /** * {@inheritdoc} */ diff --git a/app/Entities/Models/Entity.php b/app/Entities/Models/Entity.php index 26a52073e..3528eaf2b 100644 --- a/app/Entities/Models/Entity.php +++ b/app/Entities/Models/Entity.php @@ -184,8 +184,10 @@ abstract class Entity extends Model implements Sluggable, Favouritable, Viewable */ public function hasRestriction(int $role_id, string $action): bool { - return $this->permissions()->where('role_id', '=', $role_id) - ->where('action', '=', $action)->count() > 0; + return $this->permissions() + ->where('role_id', '=', $role_id) + ->where('action', '=', $action) + ->count() > 0; } /** diff --git a/resources/icons/groups.svg b/resources/icons/groups.svg new file mode 100644 index 000000000..c99a6b503 --- /dev/null +++ b/resources/icons/groups.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/resources/js/components/entity-permissions.js b/resources/js/components/entity-permissions.js new file mode 100644 index 000000000..8b57d3376 --- /dev/null +++ b/resources/js/components/entity-permissions.js @@ -0,0 +1,24 @@ + + +class EntityPermissions { + + setup() { + this.everyoneInheritToggle = this.$refs.everyoneInherit; + + this.setupListeners(); + } + + setupListeners() { + this.everyoneInheritToggle.addEventListener('change', event => { + const inherit = event.target.checked; + const permissions = document.querySelectorAll('input[type="checkbox"][name^="restrictions[0]["]'); + for (const permission of permissions) { + permission.disabled = inherit; + permission.checked = false; + } + }) + } + +} + +export default EntityPermissions; \ No newline at end of file diff --git a/resources/js/components/index.js b/resources/js/components/index.js index 4b17dc403..7d00cb671 100644 --- a/resources/js/components/index.js +++ b/resources/js/components/index.js @@ -18,6 +18,7 @@ import dropdown from "./dropdown.js" import dropdownSearch from "./dropdown-search.js" import dropzone from "./dropzone.js" import editorToolbox from "./editor-toolbox.js" +import entityPermissions from "./entity-permissions"; import entitySearch from "./entity-search.js" import entitySelector from "./entity-selector.js" import entitySelectorPopup from "./entity-selector-popup.js" @@ -74,6 +75,7 @@ const componentMapping = { "dropdown-search": dropdownSearch, "dropzone": dropzone, "editor-toolbox": editorToolbox, + "entity-permissions": entityPermissions, "entity-search": entitySearch, "entity-selector": entitySelector, "entity-selector-popup": entitySelectorPopup, diff --git a/resources/sass/_components.scss b/resources/sass/_components.scss index 9f737f3be..d0aadce6e 100644 --- a/resources/sass/_components.scss +++ b/resources/sass/_components.scss @@ -824,9 +824,6 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group { .content-permissions-row:hover .content-permissions-row-toggle-all { visibility: visible; } -.content-permissions-row-label { - font-weight: bold; -} .template-item { cursor: pointer; diff --git a/resources/sass/_forms.scss b/resources/sass/_forms.scss index 7025aa898..5c1c8b2e8 100644 --- a/resources/sass/_forms.scss +++ b/resources/sass/_forms.scss @@ -266,6 +266,15 @@ input[type=color] { background-color: rgba(0, 0, 0, 0.05); opacity: 0.8; } + input[type=checkbox][disabled] ~ * { + opacity: 0.8; + cursor: not-allowed; + } + input[type=checkbox][disabled] ~ .custom-checkbox { + border-color: #999; + color: #999 !important; + background: #f2f2f2; + } } .toggle-switch-list { .toggle-switch { diff --git a/resources/views/form/custom-checkbox.blade.php b/resources/views/form/custom-checkbox.blade.php index 2bf4e2232..de3ffe922 100644 --- a/resources/views/form/custom-checkbox.blade.php +++ b/resources/views/form/custom-checkbox.blade.php @@ -5,7 +5,7 @@ $checked $label --}}
- {{ trans('common.toggle_all') }} + {{ trans('common.toggle_all') }} {{ trans('common.create') }}{{ trans('common.view') }}{{ trans('common.edit') }}{{ trans('common.delete') }}{{ trans('common.create') }}{{ trans('common.view') }}{{ trans('common.edit') }}{{ trans('common.delete') }}
{{ trans('entities.shelves') }}
- {{ trans('common.toggle_all') }} + {{ trans('common.toggle_all') }}
@include('settings.roles.parts.checkbox', ['permission' => 'bookshelf-create-all', 'label' => trans('settings.role_all')]) @@ -93,7 +93,7 @@
{{ trans('entities.books') }}
- {{ trans('common.toggle_all') }} + {{ trans('common.toggle_all') }}
@include('settings.roles.parts.checkbox', ['permission' => 'book-create-all', 'label' => trans('settings.role_all')]) @@ -117,7 +117,7 @@
{{ trans('entities.chapters') }}
- {{ trans('common.toggle_all') }} + {{ trans('common.toggle_all') }}
@include('settings.roles.parts.checkbox', ['permission' => 'chapter-create-own', 'label' => trans('settings.role_own')]) @@ -143,7 +143,7 @@
{{ trans('entities.pages') }}
- {{ trans('common.toggle_all') }} + {{ trans('common.toggle_all') }}
@include('settings.roles.parts.checkbox', ['permission' => 'page-create-own', 'label' => trans('settings.role_own')]) @@ -169,7 +169,7 @@
{{ trans('entities.images') }}
- {{ trans('common.toggle_all') }} + {{ trans('common.toggle_all') }}
@include('settings.roles.parts.checkbox', ['permission' => 'image-create-all', 'label' => '']) {{ trans('settings.role_controlled_by_asset') }}1
{{ trans('entities.attachments') }}
- {{ trans('common.toggle_all') }} + {{ trans('common.toggle_all') }}
@include('settings.roles.parts.checkbox', ['permission' => 'attachment-create-all', 'label' => '']) {{ trans('settings.role_controlled_by_asset') }}
{{ trans('entities.comments') }}
- {{ trans('common.toggle_all') }} + {{ trans('common.toggle_all') }}
@include('settings.roles.parts.checkbox', ['permission' => 'comment-create-all', 'label' => '']) {{ trans('settings.role_controlled_by_asset') }}