From 3c2321c32f3eb6f80e55f7c21bf37e22ec9b7b51 Mon Sep 17 00:00:00 2001 From: Federico Salvetti Date: Tue, 28 Jan 2020 15:19:33 +0100 Subject: [PATCH 1/3] Add shared drafts, can be enabled from app settings --- app/Auth/Permissions/PermissionService.php | 18 ++++++------ app/Entities/Managers/PageEditActivity.php | 21 ++++++++++++-- app/Entities/Repos/PageRepo.php | 33 ++++++++++++++++++++-- app/Http/Controllers/PageController.php | 21 ++++++++------ resources/lang/en/entities.php | 5 ++++ resources/lang/en/settings.php | 3 ++ resources/views/pages/form.blade.php | 8 ++++-- resources/views/settings/index.blade.php | 14 +++++++++ 8 files changed, 98 insertions(+), 25 deletions(-) diff --git a/app/Auth/Permissions/PermissionService.php b/app/Auth/Permissions/PermissionService.php index 97cc1ca241e..f5e2b63d1bb 100644 --- a/app/Auth/Permissions/PermissionService.php +++ b/app/Auth/Permissions/PermissionService.php @@ -656,15 +656,19 @@ public function restrictEntityQuery(Builder $query, string $ability = 'view'): B /** * Extend the given page query to ensure draft items are not visible - * unless created by the given user. + * unless created by the given user, or editable by the given user if + * app-shared-drafts setting is enabled. */ public function enforceDraftVisiblityOnQuery(Builder $query): Builder { return $query->where(function (Builder $query) { $query->where('draft', '=', false) ->orWhere(function (Builder $query) { - $query->where('draft', '=', true) - ->where('created_by', '=', $this->currentUser()->id); + if (setting('app-shared-drafts')) { + $this->restrictEntityQuery($query, 'update'); + } else { + $query->where('created_by', '=', $this->currentUser()->id); + } }); }); } @@ -680,13 +684,7 @@ public function enforceEntityRestrictions($entityType, $query, $action = 'view') { if (strtolower($entityType) === 'page') { // Prevent drafts being visible to others. - $query = $query->where(function ($query) { - $query->where('draft', '=', false) - ->orWhere(function ($query) { - $query->where('draft', '=', true) - ->where('created_by', '=', $this->currentUser()->id); - }); - }); + $query = $this->enforceDraftVisiblityOnQuery($query); } $this->currentAction = $action; diff --git a/app/Entities/Managers/PageEditActivity.php b/app/Entities/Managers/PageEditActivity.php index cebbf8720f1..2ca78a47ae1 100644 --- a/app/Entities/Managers/PageEditActivity.php +++ b/app/Entities/Managers/PageEditActivity.php @@ -1,5 +1,6 @@ updated_at->diffForHumans(); + $user = user(); + error_log('$draft->updated_by: ' . $draft->updated_by); + error_log('$user->id: ' . $user->id); + if ($draft->created_by === $user->id) { + return trans('entities.pages_editing_shared_draft_notification.message', ['timeDiff' => $time, 'userName' => trans('entities.pages_editing_shared_draft_notification.you')]); + } + $createdUser = User::find($draft->created_by); + $userName = '_user'.$draft->created_by.'_'; + if ($createdUser) { + $userName = $createdUser->name; + } + return trans('entities.pages_editing_shared_draft_notification.message', ['timeDiff' => $time, 'userName' => $userName]) . "\n" . + trans('entities.pages_editing_shared_draft_notification.warn'); + } $message = trans('entities.pages_editing_draft_notification', ['timeDiff' => $draft->updated_at->diffForHumans()]); if ($draft->page->updated_at->timestamp <= $draft->updated_at->timestamp) { return $message; diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php index e49eeb1ef55..fd326614394 100644 --- a/app/Entities/Repos/PageRepo.php +++ b/app/Entities/Repos/PageRepo.php @@ -120,6 +120,15 @@ public function getUserDraft(Page $page): ?PageRevision return $revision; } + /** + * Get the draft copy of the given page. + */ + public function getDraft(Page $page): ?PageRevision + { + $revision = $this->getDraftQuery($page)->first(); + return $revision; + } + /** * Get a new draft page belonging to the given parent entity. */ @@ -195,7 +204,11 @@ public function update(Page $page, array $input): Page $page->save(); // Remove all update drafts for this user & page. - $this->getUserDraftQuery($page)->delete(); + if (setting('app-shared-drafts')) { + $this->getDraftQuery($page)->delete(); + } else { + $this->getUserDraftQuery($page)->delete(); + } // Save a revision after updating $summary = $input['summary'] ?? null; @@ -250,6 +263,7 @@ public function updatePageDraft(Page $page, array $input) // Otherwise save the data to a revision $draft = $this->getPageRevisionToUpdate($page); $draft->fill($input); + $draft->created_by = user()->id; // Update the user that last updated the draft, just in case of shared draft if (setting('app-editor') !== 'markdown') { $draft->markdown = ''; } @@ -400,7 +414,11 @@ protected function changeParent(Page $page, Entity $parent) */ protected function getPageRevisionToUpdate(Page $page): PageRevision { - $drafts = $this->getUserDraftQuery($page)->get(); + if (setting('app-shared-drafts')) { + $drafts = $this->getDraftQuery($page)->get(); + } else { + $drafts = $this->getUserDraftQuery($page)->get(); + } if ($drafts->count() > 0) { return $drafts->first(); } @@ -458,4 +476,15 @@ protected function getUserDraftQuery(Page $page) ->where('page_id', '=', $page->id) ->orderBy('created_at', 'desc'); } + + /** + * Get the query to find the draft copies of the given page. + */ + protected function getDraftQuery(Page $page) + { + return PageRevision::query() + ->where('type', 'update_draft') + ->where('page_id', '=', $page->id) + ->orderBy('updated_at', 'desc'); + } } diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index b216c19a8e7..9f34fa04e12 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -78,7 +78,7 @@ public function createAsGuest(Request $request, string $bookSlug, string $chapte public function editDraft(string $bookSlug, int $pageId) { $draft = $this->pageRepo->getById($pageId); - $this->checkOwnablePermission('page-create', $draft->parent()); + $this->checkOwnablePermission('page-update', $draft->parent()); $this->setPageTitle(trans('entities.pages_edit_draft')); $draftsEnabled = $this->isSignedIn(); @@ -175,21 +175,26 @@ public function edit(string $bookSlug, string $pageSlug) $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); $this->checkOwnablePermission('page-update', $page); + $sharedDrafts = setting('app-shared-drafts'); $page->isDraft = false; $editActivity = new PageEditActivity($page); // Check for active editing $warnings = []; - if ($editActivity->hasActiveEditing()) { + if (!$sharedDrafts && $editActivity->hasActiveEditing()) { $warnings[] = $editActivity->activeEditingMessage(); } // Check for a current draft version for this user - $userDraft = $this->pageRepo->getUserDraft($page); - if ($userDraft !== null) { - $page->forceFill($userDraft->only(['name', 'html', 'markdown'])); + if ($sharedDrafts) { + $draft = $this->pageRepo->getDraft($page); + } else { + $draft = $this->pageRepo->getUserDraft($page); + } + if ($draft !== null) { + $page->forceFill($draft->only(['name', 'html', 'markdown'])); $page->isDraft = true; - $warnings[] = $editActivity->getEditingActiveDraftMessage($userDraft); + $warnings[] = $editActivity->getEditingActiveDraftMessage($draft, $sharedDrafts); } if (count($warnings) > 0) { @@ -283,7 +288,7 @@ public function showDelete(string $bookSlug, string $pageSlug) public function showDeleteDraft(string $bookSlug, int $pageId) { $page = $this->pageRepo->getById($pageId); - $this->checkOwnablePermission('page-update', $page); + $this->checkOwnablePermission('page-delete', $page); $this->setPageTitle(trans('entities.pages_delete_draft_named', ['pageName'=>$page->getShortName()])); return view('pages.delete', [ 'book' => $page->book, @@ -323,7 +328,7 @@ public function destroyDraft(string $bookSlug, int $pageId) $page = $this->pageRepo->getById($pageId); $book = $page->book; $chapter = $page->chapter; - $this->checkOwnablePermission('page-update', $page); + $this->checkOwnablePermission('page-delete', $page); $this->pageRepo->destroy($page); diff --git a/resources/lang/en/entities.php b/resources/lang/en/entities.php index 6bbc723b0ab..ec67251cce6 100644 --- a/resources/lang/en/entities.php +++ b/resources/lang/en/entities.php @@ -224,6 +224,11 @@ 'pages_initial_revision' => 'Initial publish', 'pages_initial_name' => 'New Page', 'pages_editing_draft_notification' => 'You are currently editing a draft that was last saved :timeDiff.', + 'pages_editing_shared_draft_notification' => [ + 'message' => 'You are currently editing a draft that was last saved :timeDiff by :userName.', + 'you' => 'you', + 'warn' => 'Take care not to overwrite each other\'s updates!', + ], 'pages_draft_edited_notification' => 'This page has been updated by since that time. It is recommended that you discard this draft.', 'pages_draft_edit_active' => [ 'start_a' => ':count users have started editing this page', diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index ab274256f20..5d41b50cb3b 100755 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -40,6 +40,9 @@ 'app_disable_comments' => 'Disable Comments', 'app_disable_comments_toggle' => 'Disable comments', 'app_disable_comments_desc' => 'Disables comments across all pages in the application.
Existing comments are not shown.', + 'app_shared_drafts' => 'Shared Drafts', + 'app_shared_drafts_toggle' => 'Enable shared drafts', + 'app_shared_drafts_desc' => 'Enable shared drafts across all users with edit permission on the page.
Existing drafts on the same page are overwritten, the last edited take precedence over the others.', // Color settings 'content_colors' => 'Content Colors', diff --git a/resources/views/pages/form.blade.php b/resources/views/pages/form.blade.php index ffc286c2cad..2b2a3f3e155 100644 --- a/resources/views/pages/form.blade.php +++ b/resources/views/pages/form.blade.php @@ -32,9 +32,11 @@
  • -
  • - @icon('delete'){{ trans('entities.pages_edit_delete_draft') }} -
  • + @if(userCan('page-delete', $model)) +
  • + @icon('delete'){{ trans('entities.pages_edit_delete_draft') }} +
  • + @endif
  • diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php index b3a11955dcd..c8c851f522b 100644 --- a/resources/views/settings/index.blade.php +++ b/resources/views/settings/index.blade.php @@ -70,6 +70,20 @@ +
    +
    + +

    {!! trans('settings.app_shared_drafts_desc') !!}

    +
    +
    + @include('components.toggle-switch', [ + 'name' => 'setting-app-shared-drafts', + 'value' => setting('app-shared-drafts'), + 'label' => trans('settings.app_shared_drafts_toggle'), + ]) +
    +
    + From c1a40c4e1258adfc8323ee2e2d60b52fb921aa4a Mon Sep 17 00:00:00 2001 From: Federico Salvetti Date: Thu, 30 Jan 2020 11:55:29 +0100 Subject: [PATCH 2/3] Add page-editdraft-all permission --- app/Auth/Permissions/PermissionService.php | 25 ++++++- app/Http/Controllers/PageController.php | 12 +++- ...01_29_171400_add_edit_draft_permission.php | 65 +++++++++++++++++++ resources/lang/en/common.php | 2 + .../views/form/entity-permissions.blade.php | 3 +- resources/views/pages/form.blade.php | 24 +++---- resources/views/pages/show.blade.php | 2 +- resources/views/settings/roles/form.blade.php | 2 + 8 files changed, 118 insertions(+), 17 deletions(-) create mode 100644 database/migrations/2020_01_29_171400_add_edit_draft_permission.php diff --git a/app/Auth/Permissions/PermissionService.php b/app/Auth/Permissions/PermissionService.php index f5e2b63d1bb..6c574e37d9c 100644 --- a/app/Auth/Permissions/PermissionService.php +++ b/app/Auth/Permissions/PermissionService.php @@ -426,6 +426,9 @@ protected function getActions(Entity $entity) if ($entity->isA('book')) { $baseActions[] = 'chapter-create'; } + if ($entity->isA('page')) { + $baseActions[] = 'editdraft'; + } return $baseActions; } @@ -665,7 +668,27 @@ public function enforceDraftVisiblityOnQuery(Builder $query): Builder $query->where('draft', '=', false) ->orWhere(function (Builder $query) { if (setting('app-shared-drafts')) { - $this->restrictEntityQuery($query, 'update'); + $this->clean(); + $query->where(function (Builder $parentQuery) { + $parentQuery->whereHas('jointPermissions', function (Builder $permissionQuery) { + $permissionQuery->whereIn('role_id', $this->getRoles()) + ->where(function (Builder $query) { + $query->where(function (Builder $query) { + $query->where('action', '=', 'editdraft') + ->where('has_permission', '=', true); + })->orWhere(function (Builder $query) { + $query->where('action', '=', 'update') + ->where(function (Builder $query) { + $query->where('has_permission', '=', true) + ->orWhere(function (Builder $query) { + $query->where('has_permission_own', '=', true) + ->where('created_by', '=', $this->currentUser()->id); + }); + }); + }); + }); + }); + }); } else { $query->where('created_by', '=', $this->currentUser()->id); } diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index 9f34fa04e12..ff541e637df 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -78,7 +78,9 @@ public function createAsGuest(Request $request, string $bookSlug, string $chapte public function editDraft(string $bookSlug, int $pageId) { $draft = $this->pageRepo->getById($pageId); - $this->checkOwnablePermission('page-update', $draft->parent()); + if (!(userCan('page-update', $draft) || userCan('page-editdraft', $draft))) { + $this->showPermissionError(); + } $this->setPageTitle(trans('entities.pages_edit_draft')); $draftsEnabled = $this->isSignedIn(); @@ -173,7 +175,9 @@ public function getPageAjax(int $pageId) public function edit(string $bookSlug, string $pageSlug) { $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); - $this->checkOwnablePermission('page-update', $page); + if (!(userCan('page-update', $page) || userCan('page-editdraft', $page))) { + $this->showPermissionError(); + } $sharedDrafts = setting('app-shared-drafts'); $page->isDraft = false; @@ -239,7 +243,9 @@ public function update(Request $request, string $bookSlug, string $pageSlug) public function saveDraft(Request $request, int $pageId) { $page = $this->pageRepo->getById($pageId); - $this->checkOwnablePermission('page-update', $page); + if (!(userCan('page-update', $page) || userCan('page-editdraft', $page))) { + $this->showPermissionError(); + } if (!$this->isSignedIn()) { return $this->jsonError(trans('errors.guests_cannot_save_drafts'), 500); diff --git a/database/migrations/2020_01_29_171400_add_edit_draft_permission.php b/database/migrations/2020_01_29_171400_add_edit_draft_permission.php new file mode 100644 index 00000000000..793059ba7ba --- /dev/null +++ b/database/migrations/2020_01_29_171400_add_edit_draft_permission.php @@ -0,0 +1,65 @@ +insertGetId([ + 'name' => strtolower($entity) . '-' . strtolower($p) . '-' . strtolower($o), + 'display_name' => $p . ' ' . $o . ' ' . $entity . 's', + 'created_at' => \Carbon\Carbon::now()->toDateTimeString(), + 'updated_at' => \Carbon\Carbon::now()->toDateTimeString() + ]); + + // Find all current roles that already have update permission + $roleIdsWithUdatePermission = DB::table('role_permissions') + ->leftJoin('permission_role', 'role_permissions.id', '=', 'permission_role.permission_id') + ->leftJoin('roles', 'roles.id', '=', 'permission_role.role_id') + ->where('role_permissions.name', '=', strtolower($entity) . '-' . strtolower($pu) . '-' . strtolower($o))->get(['roles.id'])->pluck('id'); + + // Generate permission_role entry + $rowsToInsert = $roleIdsWithUdatePermission->filter(function($roleId) { + return !is_null($roleId); + })->map(function($roleId) use ($permId) { + return [ + 'role_id' => $roleId, + 'permission_id' => $permId + ]; + })->toArray(); + + // Assign editdraft permission to roles + DB::table('permission_role')->insert($rowsToInsert); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + // Delete the new editdraft permission + $entity = 'Page'; + $op = 'EditDraft All'; + + $permissionName = strtolower($entity) . '-' . strtolower(str_replace(' ', '-', $op)); + $permission = DB::table('role_permissions')->where('name', '=', $permissionName)->first(); + DB::table('permission_role')->where('permission_id', '=', $permission->id)->delete(); + DB::table('role_permissions')->where('name', '=', $permissionName)->delete(); + } +} diff --git a/resources/lang/en/common.php b/resources/lang/en/common.php index c8b4a2b223e..57c680c30ce 100644 --- a/resources/lang/en/common.php +++ b/resources/lang/en/common.php @@ -28,6 +28,8 @@ 'create' => 'Create', 'update' => 'Update', 'edit' => 'Edit', + 'drafts' => 'Drafts', + 'edit_draft' => 'Edit Draft', 'sort' => 'Sort', 'move' => 'Move', 'copy' => 'Copy', diff --git a/resources/views/form/entity-permissions.blade.php b/resources/views/form/entity-permissions.blade.php index 3581a545b1c..a15bdcb1ff4 100644 --- a/resources/views/form/entity-permissions.blade.php +++ b/resources/views/form/entity-permissions.blade.php @@ -14,7 +14,7 @@ - @@ -29,6 +29,7 @@ @if(!$model->isA('page')) @endif + diff --git a/resources/views/pages/form.blade.php b/resources/views/pages/form.blade.php index 2b2a3f3e155..edc8caabc1b 100644 --- a/resources/views/pages/form.blade.php +++ b/resources/views/pages/form.blade.php @@ -45,18 +45,20 @@
    - + @if(userCan('page-update', $model)) + - + + @endif
    diff --git a/resources/views/pages/show.blade.php b/resources/views/pages/show.blade.php index dfe0a9d7d2f..b5c2512793d 100644 --- a/resources/views/pages/show.blade.php +++ b/resources/views/pages/show.blade.php @@ -118,7 +118,7 @@
    {{ trans('common.role') }}isA('page')) colspan="3" @else colspan="4" @endif> + isA('page')) colspan="4" @else colspan="5" @endif> {{ trans('common.actions') }} {{ trans('common.toggle_all') }} @include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.create'), 'action' => 'create'])@include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.edit_draft'), 'action' => 'editdraft']) @include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.update'), 'action' => 'update']) @include('form.restriction-checkbox', ['name'=>'restrictions', 'label' => trans('common.delete'), 'action' => 'delete'])
    @include('settings.roles.checkbox', ['permission' => 'page-delete-own', 'label' => trans('settings.role_own')]) From 20898ab31628a2e969054a9d4f4027ba14755cfc Mon Sep 17 00:00:00 2001 From: Federico Salvetti Date: Fri, 31 Jan 2020 15:15:24 +0100 Subject: [PATCH 3/3] Fix draft pages visibility inside chapters --- app/Auth/Permissions/PermissionService.php | 40 +++++++-------- app/Entities/Chapter.php | 6 +-- app/Entities/Managers/PageEditActivity.php | 5 +- app/Entities/Repos/PageRepo.php | 6 +-- app/Http/Controllers/ChapterController.php | 2 +- app/Http/Controllers/Controller.php | 16 ++++++ app/Http/Controllers/PageController.php | 20 ++------ resources/views/chapters/child-menu.blade.php | 4 +- resources/views/chapters/list-item.blade.php | 4 +- resources/views/partials/book-tree.blade.php | 2 +- resources/views/settings/index.blade.php | 51 +++++++------------ 11 files changed, 68 insertions(+), 88 deletions(-) diff --git a/app/Auth/Permissions/PermissionService.php b/app/Auth/Permissions/PermissionService.php index 6c574e37d9c..e69ac5527e7 100644 --- a/app/Auth/Permissions/PermissionService.php +++ b/app/Auth/Permissions/PermissionService.php @@ -665,34 +665,28 @@ public function restrictEntityQuery(Builder $query, string $ability = 'view'): B public function enforceDraftVisiblityOnQuery(Builder $query): Builder { return $query->where(function (Builder $query) { - $query->where('draft', '=', false) - ->orWhere(function (Builder $query) { - if (setting('app-shared-drafts')) { - $this->clean(); - $query->where(function (Builder $parentQuery) { - $parentQuery->whereHas('jointPermissions', function (Builder $permissionQuery) { - $permissionQuery->whereIn('role_id', $this->getRoles()) - ->where(function (Builder $query) { - $query->where(function (Builder $query) { - $query->where('action', '=', 'editdraft') - ->where('has_permission', '=', true); - })->orWhere(function (Builder $query) { - $query->where('action', '=', 'update') - ->where(function (Builder $query) { - $query->where('has_permission', '=', true) - ->orWhere(function (Builder $query) { - $query->where('has_permission_own', '=', true) - ->where('created_by', '=', $this->currentUser()->id); - }); + $query->where('draft', '=', false)->orWhere(function (Builder $query) { + if (setting('app-shared-drafts')) { + $this->clean(); + $query->where(function (Builder $parentQuery) { + $parentQuery->whereHas('jointPermissions', function (Builder $permissionQuery) { + $permissionQuery->whereIn('role_id', $this->getRoles())->where(function (Builder $query) { + $query->where(function (Builder $query) { + $query->where('action', '=', 'editdraft')->where('has_permission', '=', true); + })->orWhere(function (Builder $query) { + $query->where('action', '=', 'update')->where(function (Builder $query) { + $query->where('has_permission', '=', true)->orWhere(function (Builder $query) { + $query->where('has_permission_own', '=', true)->where('created_by', '=', $this->currentUser()->id); }); }); }); }); }); - } else { - $query->where('created_by', '=', $this->currentUser()->id); - } - }); + }); + } else { + $query->where('created_by', '=', $this->currentUser()->id); + } + }); }); } diff --git a/app/Entities/Chapter.php b/app/Entities/Chapter.php index 848bc6448bd..338909b0e83 100644 --- a/app/Entities/Chapter.php +++ b/app/Entities/Chapter.php @@ -52,12 +52,12 @@ public function getExcerpt(int $length = 100) } /** - * Check if this chapter has any child pages. + * Check if this chapter has visible child pages. * @return bool */ - public function hasChildren() + public function hasVisibleChildren() { - return count($this->pages) > 0; + return $this->pages()->visible()->count() > 0; } /** diff --git a/app/Entities/Managers/PageEditActivity.php b/app/Entities/Managers/PageEditActivity.php index 2ca78a47ae1..c82a755bd54 100644 --- a/app/Entities/Managers/PageEditActivity.php +++ b/app/Entities/Managers/PageEditActivity.php @@ -57,10 +57,7 @@ public function getEditingActiveDraftMessage(PageRevision $draft, bool $sharedDr return trans('entities.pages_editing_shared_draft_notification.message', ['timeDiff' => $time, 'userName' => trans('entities.pages_editing_shared_draft_notification.you')]); } $createdUser = User::find($draft->created_by); - $userName = '_user'.$draft->created_by.'_'; - if ($createdUser) { - $userName = $createdUser->name; - } + $userName = $createdUser ? $createdUser->name : '_user'.$draft->created_by.'_'; return trans('entities.pages_editing_shared_draft_notification.message', ['timeDiff' => $time, 'userName' => $userName]) . "\n" . trans('entities.pages_editing_shared_draft_notification.warn'); } diff --git a/app/Entities/Repos/PageRepo.php b/app/Entities/Repos/PageRepo.php index fd326614394..3d3f31f96d6 100644 --- a/app/Entities/Repos/PageRepo.php +++ b/app/Entities/Repos/PageRepo.php @@ -204,11 +204,7 @@ public function update(Page $page, array $input): Page $page->save(); // Remove all update drafts for this user & page. - if (setting('app-shared-drafts')) { - $this->getDraftQuery($page)->delete(); - } else { - $this->getUserDraftQuery($page)->delete(); - } + setting('app-shared-drafts') ? $this->getDraftQuery($page)->delete() : $this->getUserDraftQuery($page)->delete(); // Save a revision after updating $summary = $input['summary'] ?? null; diff --git a/app/Http/Controllers/ChapterController.php b/app/Http/Controllers/ChapterController.php index 1355979107e..667afb27683 100644 --- a/app/Http/Controllers/ChapterController.php +++ b/app/Http/Controllers/ChapterController.php @@ -64,7 +64,7 @@ public function show(string $bookSlug, string $chapterSlug) $chapter = $this->chapterRepo->getBySlug($bookSlug, $chapterSlug); $this->checkOwnablePermission('chapter-view', $chapter); - $sidebarTree = (new BookContents($chapter->book))->getTree(); + $sidebarTree = (new BookContents($chapter->book))->getTree(true); $pages = $chapter->getVisiblePages(); Views::add($chapter); diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index b9576f2febd..320eb8fb967 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -92,6 +92,22 @@ protected function checkOwnablePermission($permission, Ownable $ownable) return $this->showPermissionError(); } + /** + * Check the current user's permissions in or against an ownable item. + * @param Collection $permissions + * @param Ownable $ownable + * @return bool + */ + protected function checkOwnableOrPermissions($permissions, Ownable $ownable) + { + foreach ($permissions as $permission) { + if (userCan($permission, $ownable)) { + return true; + } + } + return $this->showPermissionError(); + } + /** * Check if a user has a permission or bypass if the callback is true. * @param $permissionName diff --git a/app/Http/Controllers/PageController.php b/app/Http/Controllers/PageController.php index ff541e637df..616106cf113 100644 --- a/app/Http/Controllers/PageController.php +++ b/app/Http/Controllers/PageController.php @@ -78,9 +78,7 @@ public function createAsGuest(Request $request, string $bookSlug, string $chapte public function editDraft(string $bookSlug, int $pageId) { $draft = $this->pageRepo->getById($pageId); - if (!(userCan('page-update', $draft) || userCan('page-editdraft', $draft))) { - $this->showPermissionError(); - } + $this->checkOwnableOrPermissions(['page-update', 'page-editdraft'], $draft); $this->setPageTitle(trans('entities.pages_edit_draft')); $draftsEnabled = $this->isSignedIn(); @@ -137,7 +135,7 @@ public function show(string $bookSlug, string $pageSlug) $pageContent = (new PageContent($page)); $page->html = $pageContent->render(); - $sidebarTree = (new BookContents($page->book))->getTree(); + $sidebarTree = (new BookContents($page->book))->getTree(true); $pageNav = $pageContent->getNavigation($page->html); // Check if page comments are enabled @@ -175,9 +173,7 @@ public function getPageAjax(int $pageId) public function edit(string $bookSlug, string $pageSlug) { $page = $this->pageRepo->getBySlug($bookSlug, $pageSlug); - if (!(userCan('page-update', $page) || userCan('page-editdraft', $page))) { - $this->showPermissionError(); - } + $this->checkOwnableOrPermissions(['page-update', 'page-editdraft'], $page); $sharedDrafts = setting('app-shared-drafts'); $page->isDraft = false; @@ -190,11 +186,7 @@ public function edit(string $bookSlug, string $pageSlug) } // Check for a current draft version for this user - if ($sharedDrafts) { - $draft = $this->pageRepo->getDraft($page); - } else { - $draft = $this->pageRepo->getUserDraft($page); - } + $draft = $sharedDrafts ? $this->pageRepo->getDraft($page) : $this->pageRepo->getUserDraft($page); if ($draft !== null) { $page->forceFill($draft->only(['name', 'html', 'markdown'])); $page->isDraft = true; @@ -243,9 +235,7 @@ public function update(Request $request, string $bookSlug, string $pageSlug) public function saveDraft(Request $request, int $pageId) { $page = $this->pageRepo->getById($pageId); - if (!(userCan('page-update', $page) || userCan('page-editdraft', $page))) { - $this->showPermissionError(); - } + $this->checkOwnableOrPermissions(['page-update', 'page-editdraft'], $page); if (!$this->isSignedIn()) { return $this->jsonError(trans('errors.guests_cannot_save_drafts'), 500); diff --git a/resources/views/chapters/child-menu.blade.php b/resources/views/chapters/child-menu.blade.php index 6137c34e8fc..bfebc4c6f1c 100644 --- a/resources/views/chapters/child-menu.blade.php +++ b/resources/views/chapters/child-menu.blade.php @@ -1,10 +1,10 @@
    -@if ($chapter->hasChildren()) +@if ($chapter->hasVisibleChildren())
    @icon('page')
    diff --git a/resources/views/partials/book-tree.blade.php b/resources/views/partials/book-tree.blade.php index c288e63674f..039aa12be59 100644 --- a/resources/views/partials/book-tree.blade.php +++ b/resources/views/partials/book-tree.blade.php @@ -12,7 +12,7 @@
  • @include('partials.entity-list-item-basic', ['entity' => $bookChild, 'classes' => $current->matches($bookChild)? 'selected' : '']) - @if($bookChild->isA('chapter') && count($bookChild->pages) > 0) + @if($bookChild->isA('chapter') && $bookChild->hasVisibleChildren())
    diff --git a/resources/views/settings/index.blade.php b/resources/views/settings/index.blade.php index c8c851f522b..5d4dff41b06 100644 --- a/resources/views/settings/index.blade.php +++ b/resources/views/settings/index.blade.php @@ -8,9 +8,7 @@ @include('settings.navbar', ['selected' => 'settings'])
    @@ -22,7 +20,6 @@
    -
    @@ -37,8 +34,7 @@ @include('components.toggle-switch', [ 'name' => 'setting-app-public', 'value' => setting('app-public'), - 'label' => trans('settings.app_public_access_toggle'), - ]) + 'label' => trans('settings.app_public_access_toggle')])
    @@ -51,8 +47,7 @@ @include('components.toggle-switch', [ 'name' => 'setting-app-secure-images', 'value' => setting('app-secure-images'), - 'label' => trans('settings.app_secure_images_toggle'), - ]) + 'label' => trans('settings.app_secure_images_toggle')])
  • @@ -65,8 +60,7 @@ @include('components.toggle-switch', [ 'name' => 'setting-app-disable-comments', 'value' => setting('app-disable-comments'), - 'label' => trans('settings.app_disable_comments_toggle'), - ]) + 'label' => trans('settings.app_disable_comments_toggle')])
    @@ -79,12 +73,10 @@ @include('components.toggle-switch', [ 'name' => 'setting-app-shared-drafts', 'value' => setting('app-shared-drafts'), - 'label' => trans('settings.app_shared_drafts_toggle'), - ]) + 'label' => trans('settings.app_shared_drafts_toggle')]) -
    @@ -111,8 +103,7 @@ @include('components.toggle-switch', [ 'name' => 'setting-app-name-header', 'value' => setting('app-name-header'), - 'label' => trans('settings.app_name_header'), - ]) + 'label' => trans('settings.app_name_header')])
    @@ -136,13 +127,12 @@
    @include('components.image-picker', [ - 'removeName' => 'setting-app-logo', - 'removeValue' => 'none', - 'defaultImage' => url('/logo.png'), - 'currentImage' => setting('app-logo'), - 'name' => 'app_logo', - 'imageClass' => 'logo-image', - ]) + 'removeName' => 'setting-app-logo', + 'removeValue' => 'none', + 'defaultImage' => url('/logo.png'), + 'currentImage' => setting('app-logo'), + 'name' => 'app_logo', + 'imageClass' => 'logo-image'])
    @@ -195,12 +185,14 @@ -

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

    @@ -208,7 +200,6 @@

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

    -
    @@ -233,8 +224,7 @@ @include('components.toggle-switch', [ 'name' => 'setting-registration-enabled', 'value' => setting('registration-enabled'), - 'label' => trans('settings.reg_enable_toggle') - ]) + 'label' => trans('settings.reg_enable_toggle')]) @if(in_array(config('auth.method'), ['ldap', 'saml2']))
    {{ trans('settings.reg_enable_external_warning') }}
    @@ -243,9 +233,7 @@