mirror of
				https://github.com/BookStackApp/BookStack.git
				synced 2025-11-03 02:13:16 +03:00 
			
		
		
		
	Merge branch 'mark-james-Copy-For-View-Only'
This commit is contained in:
		@@ -556,6 +556,32 @@ class PermissionService
 | 
				
			|||||||
        return $q;
 | 
					        return $q;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks if a user has the given permission for any items in the system.
 | 
				
			||||||
 | 
					     * @param string $permission
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function checkUserHasPermissionOnAnything(string $permission)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $userRoleIds = $this->currentUser()->roles()->select('id')->pluck('id')->toArray();
 | 
				
			||||||
 | 
					        $userId = $this->currentUser()->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $canCreatePage = $this->db->table('joint_permissions')
 | 
				
			||||||
 | 
					            ->where('action', '=', $permission)
 | 
				
			||||||
 | 
					            ->whereIn('role_id', $userRoleIds)
 | 
				
			||||||
 | 
					            ->where(function ($query) use ($userId) {
 | 
				
			||||||
 | 
					                $query->where('has_permission', '=', 1)
 | 
				
			||||||
 | 
					                ->orWhere(function ($query2) use ($userId) {
 | 
				
			||||||
 | 
					                    $query2->where('has_permission_own', '=', 1)
 | 
				
			||||||
 | 
					                    ->where('created_by', '=', $userId);
 | 
				
			||||||
 | 
					                });       
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            ->get()->count() > 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->clean();
 | 
				
			||||||
 | 
					        return $canCreatePage;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Check if an entity has restrictions set on itself or its
 | 
					     * Check if an entity has restrictions set on itself or its
 | 
				
			||||||
     * parent tree.
 | 
					     * parent tree.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -643,7 +643,7 @@ class PageController extends Controller
 | 
				
			|||||||
    public function showCopy($bookSlug, $pageSlug)
 | 
					    public function showCopy($bookSlug, $pageSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
					        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
				
			||||||
        $this->checkOwnablePermission('page-update', $page);
 | 
					        $this->checkOwnablePermission('page-view', $page);
 | 
				
			||||||
        session()->flashInput(['name' => $page->name]);
 | 
					        session()->flashInput(['name' => $page->name]);
 | 
				
			||||||
        return view('pages/copy', [
 | 
					        return view('pages/copy', [
 | 
				
			||||||
            'book' => $page->book,
 | 
					            'book' => $page->book,
 | 
				
			||||||
@@ -662,7 +662,7 @@ class PageController extends Controller
 | 
				
			|||||||
    public function copy($bookSlug, $pageSlug, Request $request)
 | 
					    public function copy($bookSlug, $pageSlug, Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
					        $page = $this->pageRepo->getPageBySlug($pageSlug, $bookSlug);
 | 
				
			||||||
        $this->checkOwnablePermission('page-update', $page);
 | 
					        $this->checkOwnablePermission('page-view', $page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $entitySelection = $request->get('entity_selection', null);
 | 
					        $entitySelection = $request->get('entity_selection', null);
 | 
				
			||||||
        if ($entitySelection === null || $entitySelection === '') {
 | 
					        if ($entitySelection === null || $entitySelection === '') {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use BookStack\Auth\Permissions\PermissionService;
 | 
				
			||||||
use BookStack\Ownable;
 | 
					use BookStack\Ownable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@@ -50,21 +51,33 @@ function signedInUser()
 | 
				
			|||||||
 * Check if the current user has a permission.
 | 
					 * Check if the current user has a permission.
 | 
				
			||||||
 * If an ownable element is passed in the jointPermissions are checked against
 | 
					 * If an ownable element is passed in the jointPermissions are checked against
 | 
				
			||||||
 * that particular item.
 | 
					 * that particular item.
 | 
				
			||||||
 * @param $permission
 | 
					 * @param string $permission
 | 
				
			||||||
 * @param Ownable $ownable
 | 
					 * @param Ownable $ownable
 | 
				
			||||||
 * @return mixed
 | 
					 * @return mixed
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function userCan($permission, Ownable $ownable = null)
 | 
					function userCan(string $permission, Ownable $ownable = null)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if ($ownable === null) {
 | 
					    if ($ownable === null) {
 | 
				
			||||||
        return user() && user()->can($permission);
 | 
					        return user() && user()->can($permission);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Check permission on ownable item
 | 
					    // Check permission on ownable item
 | 
				
			||||||
    $permissionService = app(\BookStack\Auth\Permissions\PermissionService::class);
 | 
					    $permissionService = app(PermissionService::class);
 | 
				
			||||||
    return $permissionService->checkOwnableUserAccess($ownable, $permission);
 | 
					    return $permissionService->checkOwnableUserAccess($ownable, $permission);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Check if the current user has the given permission
 | 
				
			||||||
 | 
					 * on any item in the system.
 | 
				
			||||||
 | 
					 * @param string $permission
 | 
				
			||||||
 | 
					 * @return bool
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function userCanOnAny(string $permission)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    $permissionService = app(PermissionService::class);
 | 
				
			||||||
 | 
					    return $permissionService->checkUserHasPermissionOnAnything($permission);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Helper to access system settings.
 | 
					 * Helper to access system settings.
 | 
				
			||||||
 * @param $key
 | 
					 * @param $key
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,15 +17,17 @@
 | 
				
			|||||||
            @if(userCan('page-update', $page))
 | 
					            @if(userCan('page-update', $page))
 | 
				
			||||||
                <a href="{{ $page->getUrl('/edit') }}" class="text-primary text-button" >@icon('edit'){{ trans('common.edit') }}</a>
 | 
					                <a href="{{ $page->getUrl('/edit') }}" class="text-primary text-button" >@icon('edit'){{ trans('common.edit') }}</a>
 | 
				
			||||||
            @endif
 | 
					            @endif
 | 
				
			||||||
            @if(userCan('page-update', $page) || userCan('restrictions-manage', $page) || userCan('page-delete', $page))
 | 
					            @if((userCan('page-view', $page) && userCanOnAny('page-create')) || userCan('page-update', $page) || userCan('restrictions-manage', $page) || userCan('page-delete', $page))
 | 
				
			||||||
                <div dropdown class="dropdown-container">
 | 
					                <div dropdown class="dropdown-container">
 | 
				
			||||||
                    <a dropdown-toggle class="text-primary text-button">@icon('more') {{ trans('common.more') }}</a>
 | 
					                    <a dropdown-toggle class="text-primary text-button">@icon('more') {{ trans('common.more') }}</a>
 | 
				
			||||||
                    <ul>
 | 
					                    <ul>
 | 
				
			||||||
                        @if(userCan('page-update', $page))
 | 
					                        @if(userCanOnAny('page-create'))
 | 
				
			||||||
                            <li><a href="{{ $page->getUrl('/copy') }}" class="text-primary" >@icon('copy'){{ trans('common.copy') }}</a></li>
 | 
					                            <li><a href="{{ $page->getUrl('/copy') }}" class="text-primary" >@icon('copy'){{ trans('common.copy') }}</a></li>
 | 
				
			||||||
                            @if(userCan('page-delete', $page))
 | 
					                        @endif
 | 
				
			||||||
 | 
					                        @if(userCan('page-delete', $page) && userCan('page-update', $page))
 | 
				
			||||||
                            <li><a href="{{ $page->getUrl('/move') }}" class="text-primary" >@icon('folder'){{ trans('common.move') }}</a></li>
 | 
					                            <li><a href="{{ $page->getUrl('/move') }}" class="text-primary" >@icon('folder'){{ trans('common.move') }}</a></li>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
 | 
					                        @if(userCan('page-update', $page))
 | 
				
			||||||
                            <li><a href="{{ $page->getUrl('/revisions') }}" class="text-primary">@icon('history'){{ trans('entities.revisions') }}</a></li>
 | 
					                            <li><a href="{{ $page->getUrl('/revisions') }}" class="text-primary">@icon('history'){{ trans('entities.revisions') }}</a></li>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                        @if(userCan('restrictions-manage', $page))
 | 
					                        @if(userCan('restrictions-manage', $page))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,6 @@
 | 
				
			|||||||
<?php namespace Tests;
 | 
					<?php namespace Tests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use BookStack\Auth\Role;
 | 
				
			||||||
use BookStack\Entities\Book;
 | 
					use BookStack\Entities\Book;
 | 
				
			||||||
use BookStack\Entities\Chapter;
 | 
					use BookStack\Entities\Chapter;
 | 
				
			||||||
use BookStack\Entities\Page;
 | 
					use BookStack\Entities\Page;
 | 
				
			||||||
@@ -239,4 +240,35 @@ class SortTest extends TestCase
 | 
				
			|||||||
        $this->assertTrue($pageCopy->id !== $page->id, 'Page copy is not the same instance');
 | 
					        $this->assertTrue($pageCopy->id !== $page->id, 'Page copy is not the same instance');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_can_be_copied_without_edit_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $page = Page::first();
 | 
				
			||||||
 | 
					        $currentBook = $page->book;
 | 
				
			||||||
 | 
					        $newBook = Book::where('id', '!=', $currentBook->id)->first();
 | 
				
			||||||
 | 
					        $viewer = $this->getViewer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $resp = $this->actingAs($viewer)->get($page->getUrl());
 | 
				
			||||||
 | 
					        $resp->assertDontSee($page->getUrl('/copy'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $newBook->created_by = $viewer->id;
 | 
				
			||||||
 | 
					        $newBook->save();
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($viewer, ['page-create-own']);
 | 
				
			||||||
 | 
					        $this->regenEntityPermissions($newBook);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $resp = $this->actingAs($viewer)->get($page->getUrl());
 | 
				
			||||||
 | 
					        $resp->assertSee($page->getUrl('/copy'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $movePageResp = $this->post($page->getUrl('/copy'), [
 | 
				
			||||||
 | 
					            'entity_selection' => 'book:' . $newBook->id,
 | 
				
			||||||
 | 
					            'name' => 'My copied test page'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					        $movePageResp->assertRedirect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->assertDatabaseHas('pages', [
 | 
				
			||||||
 | 
					            'name' => 'My copied test page',
 | 
				
			||||||
 | 
					            'created_by' => $viewer->id,
 | 
				
			||||||
 | 
					            'book_id' => $newBook->id,
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
		Reference in New Issue
	
	Block a user