mirror of
				https://github.com/BookStackApp/BookStack.git
				synced 2025-11-03 02:13:16 +03:00 
			
		
		
		
	Merge branch 'custom_role_system'
Conflicts: app/Repos/BookRepo.php app/Repos/ChapterRepo.php app/Repos/PageRepo.php
This commit is contained in:
		@@ -15,15 +15,11 @@ class Activity extends Model
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get the entity for this activity.
 | 
					     * Get the entity for this activity.
 | 
				
			||||||
     * @return bool
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function entity()
 | 
					    public function entity()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ($this->entity_id) {
 | 
					        if ($this->entity_type === '') $this->entity_type = null;
 | 
				
			||||||
            return $this->morphTo('entity')->first();
 | 
					        return $this->morphTo('entity');
 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,9 @@
 | 
				
			|||||||
<?php
 | 
					<?php namespace BookStack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace BookStack;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Illuminate\Database\Eloquent\Model;
 | 
					abstract class Entity extends Ownable
 | 
				
			||||||
 | 
					 | 
				
			||||||
abstract class Entity extends Model
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    use Ownable;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Compares this entity to another given entity.
 | 
					     * Compares this entity to another given entity.
 | 
				
			||||||
     * Matches by comparing class and id.
 | 
					     * Matches by comparing class and id.
 | 
				
			||||||
@@ -53,13 +48,31 @@ abstract class Entity extends Model
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get View objects for this entity.
 | 
					     * Get View objects for this entity.
 | 
				
			||||||
     * @return mixed
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function views()
 | 
					    public function views()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->morphMany('BookStack\View', 'viewable');
 | 
					        return $this->morphMany('BookStack\View', 'viewable');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get this entities restrictions.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function restrictions()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->morphMany('BookStack\Restriction', 'restrictable');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if this entity has a specific restriction set against it.
 | 
				
			||||||
 | 
					     * @param $role_id
 | 
				
			||||||
 | 
					     * @param $action
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function hasRestriction($role_id, $action)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->restrictions->where('role_id', $role_id)->where('action', $action)->count() > 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Allows checking of the exact class, Used to check entity type.
 | 
					     * Allows checking of the exact class, Used to check entity type.
 | 
				
			||||||
     * Cleaner method for is_a.
 | 
					     * Cleaner method for is_a.
 | 
				
			||||||
@@ -72,16 +85,7 @@ abstract class Entity extends Model
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Gets the class name.
 | 
					     * Gets a limited-length version of the entities name.
 | 
				
			||||||
     * @return string
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static function getClassName()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return strtolower(array_slice(explode('\\', static::class), -1, 1)[0]);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     *Gets a limited-length version of the entities name.
 | 
					 | 
				
			||||||
     * @param int $length
 | 
					     * @param int $length
 | 
				
			||||||
     * @return string
 | 
					     * @return string
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,7 +56,8 @@ class Handler extends ExceptionHandler
 | 
				
			|||||||
        // Which will include the basic message to point the user roughly to the cause.
 | 
					        // Which will include the basic message to point the user roughly to the cause.
 | 
				
			||||||
        if (($e instanceof PrettyException || $e->getPrevious() instanceof PrettyException)  && !config('app.debug')) {
 | 
					        if (($e instanceof PrettyException || $e->getPrevious() instanceof PrettyException)  && !config('app.debug')) {
 | 
				
			||||||
            $message = ($e instanceof PrettyException) ? $e->getMessage() : $e->getPrevious()->getMessage();
 | 
					            $message = ($e instanceof PrettyException) ? $e->getMessage() : $e->getPrevious()->getMessage();
 | 
				
			||||||
            return response()->view('errors/500', ['message' => $message], 500);
 | 
					            $code = ($e->getCode() === 0) ? 500 : $e->getCode();
 | 
				
			||||||
 | 
					            return response()->view('errors/' . $code, ['message' => $message], $code);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return parent::render($request, $e);
 | 
					        return parent::render($request, $e);
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										14
									
								
								app/Exceptions/NotFoundException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								app/Exceptions/NotFoundException.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					<?php namespace BookStack\Exceptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NotFoundException extends PrettyException {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * NotFoundException constructor.
 | 
				
			||||||
 | 
					     * @param string $message
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct($message = 'Item not found')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::__construct($message, 404);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										6
									
								
								app/Exceptions/PermissionsException.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/Exceptions/PermissionsException.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					<?php namespace BookStack\Exceptions;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Exception;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PermissionsException extends Exception {}
 | 
				
			||||||
@@ -3,6 +3,7 @@
 | 
				
			|||||||
namespace BookStack\Http\Controllers;
 | 
					namespace BookStack\Http\Controllers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Activity;
 | 
					use Activity;
 | 
				
			||||||
 | 
					use BookStack\Repos\UserRepo;
 | 
				
			||||||
use Illuminate\Http\Request;
 | 
					use Illuminate\Http\Request;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Illuminate\Support\Facades\Auth;
 | 
					use Illuminate\Support\Facades\Auth;
 | 
				
			||||||
@@ -19,18 +20,21 @@ class BookController extends Controller
 | 
				
			|||||||
    protected $bookRepo;
 | 
					    protected $bookRepo;
 | 
				
			||||||
    protected $pageRepo;
 | 
					    protected $pageRepo;
 | 
				
			||||||
    protected $chapterRepo;
 | 
					    protected $chapterRepo;
 | 
				
			||||||
 | 
					    protected $userRepo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * BookController constructor.
 | 
					     * BookController constructor.
 | 
				
			||||||
     * @param BookRepo    $bookRepo
 | 
					     * @param BookRepo $bookRepo
 | 
				
			||||||
     * @param PageRepo    $pageRepo
 | 
					     * @param PageRepo $pageRepo
 | 
				
			||||||
     * @param ChapterRepo $chapterRepo
 | 
					     * @param ChapterRepo $chapterRepo
 | 
				
			||||||
 | 
					     * @param UserRepo $userRepo
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(BookRepo $bookRepo, PageRepo $pageRepo, ChapterRepo $chapterRepo)
 | 
					    public function __construct(BookRepo $bookRepo, PageRepo $pageRepo, ChapterRepo $chapterRepo, UserRepo $userRepo)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->bookRepo = $bookRepo;
 | 
					        $this->bookRepo = $bookRepo;
 | 
				
			||||||
        $this->pageRepo = $pageRepo;
 | 
					        $this->pageRepo = $pageRepo;
 | 
				
			||||||
        $this->chapterRepo = $chapterRepo;
 | 
					        $this->chapterRepo = $chapterRepo;
 | 
				
			||||||
 | 
					        $this->userRepo = $userRepo;
 | 
				
			||||||
        parent::__construct();
 | 
					        parent::__construct();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -55,7 +59,7 @@ class BookController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function create()
 | 
					    public function create()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('book-create');
 | 
					        $this->checkPermission('book-create-all');
 | 
				
			||||||
        $this->setPageTitle('Create New Book');
 | 
					        $this->setPageTitle('Create New Book');
 | 
				
			||||||
        return view('books/create');
 | 
					        return view('books/create');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -68,9 +72,9 @@ class BookController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function store(Request $request)
 | 
					    public function store(Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('book-create');
 | 
					        $this->checkPermission('book-create-all');
 | 
				
			||||||
        $this->validate($request, [
 | 
					        $this->validate($request, [
 | 
				
			||||||
            'name'        => 'required|string|max:255',
 | 
					            'name' => 'required|string|max:255',
 | 
				
			||||||
            'description' => 'string|max:1000'
 | 
					            'description' => 'string|max:1000'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
        $book = $this->bookRepo->newFromInput($request->all());
 | 
					        $book = $this->bookRepo->newFromInput($request->all());
 | 
				
			||||||
@@ -105,8 +109,8 @@ class BookController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function edit($slug)
 | 
					    public function edit($slug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('book-update');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($slug);
 | 
					        $book = $this->bookRepo->getBySlug($slug);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('book-update', $book);
 | 
				
			||||||
        $this->setPageTitle('Edit Book ' . $book->getShortName());
 | 
					        $this->setPageTitle('Edit Book ' . $book->getShortName());
 | 
				
			||||||
        return view('books/edit', ['book' => $book, 'current' => $book]);
 | 
					        return view('books/edit', ['book' => $book, 'current' => $book]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -120,10 +124,10 @@ class BookController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function update(Request $request, $slug)
 | 
					    public function update(Request $request, $slug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('book-update');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($slug);
 | 
					        $book = $this->bookRepo->getBySlug($slug);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('book-update', $book);
 | 
				
			||||||
        $this->validate($request, [
 | 
					        $this->validate($request, [
 | 
				
			||||||
            'name'        => 'required|string|max:255',
 | 
					            'name' => 'required|string|max:255',
 | 
				
			||||||
            'description' => 'string|max:1000'
 | 
					            'description' => 'string|max:1000'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
        $book->fill($request->all());
 | 
					        $book->fill($request->all());
 | 
				
			||||||
@@ -141,8 +145,8 @@ class BookController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function showDelete($bookSlug)
 | 
					    public function showDelete($bookSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('book-delete');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('book-delete', $book);
 | 
				
			||||||
        $this->setPageTitle('Delete Book ' . $book->getShortName());
 | 
					        $this->setPageTitle('Delete Book ' . $book->getShortName());
 | 
				
			||||||
        return view('books/delete', ['book' => $book, 'current' => $book]);
 | 
					        return view('books/delete', ['book' => $book, 'current' => $book]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -154,8 +158,8 @@ class BookController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function sort($bookSlug)
 | 
					    public function sort($bookSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('book-update');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('book-update', $book);
 | 
				
			||||||
        $bookChildren = $this->bookRepo->getChildren($book);
 | 
					        $bookChildren = $this->bookRepo->getChildren($book);
 | 
				
			||||||
        $books = $this->bookRepo->getAll(false);
 | 
					        $books = $this->bookRepo->getAll(false);
 | 
				
			||||||
        $this->setPageTitle('Sort Book ' . $book->getShortName());
 | 
					        $this->setPageTitle('Sort Book ' . $book->getShortName());
 | 
				
			||||||
@@ -177,15 +181,14 @@ class BookController extends Controller
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Saves an array of sort mapping to pages and chapters.
 | 
					     * Saves an array of sort mapping to pages and chapters.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param  string $bookSlug
 | 
					     * @param  string $bookSlug
 | 
				
			||||||
     * @param Request $request
 | 
					     * @param Request $request
 | 
				
			||||||
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
					     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function saveSort($bookSlug, Request $request)
 | 
					    public function saveSort($bookSlug, Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('book-update');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('book-update', $book);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Return if no map sent
 | 
					        // Return if no map sent
 | 
				
			||||||
        if (!$request->has('sort-tree')) {
 | 
					        if (!$request->has('sort-tree')) {
 | 
				
			||||||
@@ -223,17 +226,48 @@ class BookController extends Controller
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Remove the specified book from storage.
 | 
					     * Remove the specified book from storage.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param $bookSlug
 | 
					     * @param $bookSlug
 | 
				
			||||||
     * @return Response
 | 
					     * @return Response
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function destroy($bookSlug)
 | 
					    public function destroy($bookSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('book-delete');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('book-delete', $book);
 | 
				
			||||||
        Activity::addMessage('book_delete', 0, $book->name);
 | 
					        Activity::addMessage('book_delete', 0, $book->name);
 | 
				
			||||||
        Activity::removeEntity($book);
 | 
					        Activity::removeEntity($book);
 | 
				
			||||||
        $this->bookRepo->destroyBySlug($bookSlug);
 | 
					        $this->bookRepo->destroyBySlug($bookSlug);
 | 
				
			||||||
        return redirect('/books');
 | 
					        return redirect('/books');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the Restrictions view.
 | 
				
			||||||
 | 
					     * @param $bookSlug
 | 
				
			||||||
 | 
					     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function showRestrict($bookSlug)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('restrictions-manage', $book);
 | 
				
			||||||
 | 
					        $roles = $this->userRepo->getRestrictableRoles();
 | 
				
			||||||
 | 
					        return view('books/restrictions', [
 | 
				
			||||||
 | 
					            'book' => $book,
 | 
				
			||||||
 | 
					            'roles' => $roles
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set the restrictions for this book.
 | 
				
			||||||
 | 
					     * @param $bookSlug
 | 
				
			||||||
 | 
					     * @param $bookSlug
 | 
				
			||||||
 | 
					     * @param Request $request
 | 
				
			||||||
 | 
					     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function restrict($bookSlug, Request $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('restrictions-manage', $book);
 | 
				
			||||||
 | 
					        $this->bookRepo->updateRestrictionsFromRequest($request, $book);
 | 
				
			||||||
 | 
					        session()->flash('success', 'Page Restrictions Updated');
 | 
				
			||||||
 | 
					        return redirect($book->getUrl());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,13 +1,9 @@
 | 
				
			|||||||
<?php
 | 
					<?php namespace BookStack\Http\Controllers;
 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace BookStack\Http\Controllers;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Activity;
 | 
					use Activity;
 | 
				
			||||||
 | 
					use BookStack\Repos\UserRepo;
 | 
				
			||||||
use Illuminate\Http\Request;
 | 
					use Illuminate\Http\Request;
 | 
				
			||||||
 | 
					 | 
				
			||||||
use Illuminate\Support\Facades\Auth;
 | 
					 | 
				
			||||||
use BookStack\Http\Requests;
 | 
					use BookStack\Http\Requests;
 | 
				
			||||||
use BookStack\Http\Controllers\Controller;
 | 
					 | 
				
			||||||
use BookStack\Repos\BookRepo;
 | 
					use BookStack\Repos\BookRepo;
 | 
				
			||||||
use BookStack\Repos\ChapterRepo;
 | 
					use BookStack\Repos\ChapterRepo;
 | 
				
			||||||
use Views;
 | 
					use Views;
 | 
				
			||||||
@@ -17,20 +13,22 @@ class ChapterController extends Controller
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    protected $bookRepo;
 | 
					    protected $bookRepo;
 | 
				
			||||||
    protected $chapterRepo;
 | 
					    protected $chapterRepo;
 | 
				
			||||||
 | 
					    protected $userRepo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * ChapterController constructor.
 | 
					     * ChapterController constructor.
 | 
				
			||||||
     * @param $bookRepo
 | 
					     * @param BookRepo $bookRepo
 | 
				
			||||||
     * @param $chapterRepo
 | 
					     * @param ChapterRepo $chapterRepo
 | 
				
			||||||
 | 
					     * @param UserRepo $userRepo
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(BookRepo $bookRepo, ChapterRepo $chapterRepo)
 | 
					    public function __construct(BookRepo $bookRepo, ChapterRepo $chapterRepo, UserRepo $userRepo)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->bookRepo = $bookRepo;
 | 
					        $this->bookRepo = $bookRepo;
 | 
				
			||||||
        $this->chapterRepo = $chapterRepo;
 | 
					        $this->chapterRepo = $chapterRepo;
 | 
				
			||||||
 | 
					        $this->userRepo = $userRepo;
 | 
				
			||||||
        parent::__construct();
 | 
					        parent::__construct();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Show the form for creating a new chapter.
 | 
					     * Show the form for creating a new chapter.
 | 
				
			||||||
     * @param $bookSlug
 | 
					     * @param $bookSlug
 | 
				
			||||||
@@ -38,8 +36,8 @@ class ChapterController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function create($bookSlug)
 | 
					    public function create($bookSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('chapter-create');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('chapter-create', $book);
 | 
				
			||||||
        $this->setPageTitle('Create New Chapter');
 | 
					        $this->setPageTitle('Create New Chapter');
 | 
				
			||||||
        return view('chapters/create', ['book' => $book, 'current' => $book]);
 | 
					        return view('chapters/create', ['book' => $book, 'current' => $book]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -52,12 +50,13 @@ class ChapterController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function store($bookSlug, Request $request)
 | 
					    public function store($bookSlug, Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('chapter-create');
 | 
					 | 
				
			||||||
        $this->validate($request, [
 | 
					        $this->validate($request, [
 | 
				
			||||||
            'name' => 'required|string|max:255'
 | 
					            'name' => 'required|string|max:255'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('chapter-create', $book);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $chapter = $this->chapterRepo->newFromInput($request->all());
 | 
					        $chapter = $this->chapterRepo->newFromInput($request->all());
 | 
				
			||||||
        $chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id);
 | 
					        $chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id);
 | 
				
			||||||
        $chapter->priority = $this->bookRepo->getNewPriority($book);
 | 
					        $chapter->priority = $this->bookRepo->getNewPriority($book);
 | 
				
			||||||
@@ -81,7 +80,14 @@ class ChapterController extends Controller
 | 
				
			|||||||
        $sidebarTree = $this->bookRepo->getChildren($book);
 | 
					        $sidebarTree = $this->bookRepo->getChildren($book);
 | 
				
			||||||
        Views::add($chapter);
 | 
					        Views::add($chapter);
 | 
				
			||||||
        $this->setPageTitle($chapter->getShortName());
 | 
					        $this->setPageTitle($chapter->getShortName());
 | 
				
			||||||
        return view('chapters/show', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter, 'sidebarTree' => $sidebarTree]);
 | 
					        $pages = $this->chapterRepo->getChildren($chapter);
 | 
				
			||||||
 | 
					        return view('chapters/show', [
 | 
				
			||||||
 | 
					            'book' => $book,
 | 
				
			||||||
 | 
					            'chapter' => $chapter,
 | 
				
			||||||
 | 
					            'current' => $chapter,
 | 
				
			||||||
 | 
					            'sidebarTree' => $sidebarTree,
 | 
				
			||||||
 | 
					            'pages' => $pages
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -92,9 +98,9 @@ class ChapterController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function edit($bookSlug, $chapterSlug)
 | 
					    public function edit($bookSlug, $chapterSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('chapter-update');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
 | 
					        $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('chapter-update', $chapter);
 | 
				
			||||||
        $this->setPageTitle('Edit Chapter' . $chapter->getShortName());
 | 
					        $this->setPageTitle('Edit Chapter' . $chapter->getShortName());
 | 
				
			||||||
        return view('chapters/edit', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]);
 | 
					        return view('chapters/edit', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -108,9 +114,9 @@ class ChapterController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function update(Request $request, $bookSlug, $chapterSlug)
 | 
					    public function update(Request $request, $bookSlug, $chapterSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('chapter-update');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
 | 
					        $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('chapter-update', $chapter);
 | 
				
			||||||
        $chapter->fill($request->all());
 | 
					        $chapter->fill($request->all());
 | 
				
			||||||
        $chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id, $chapter->id);
 | 
					        $chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id, $chapter->id);
 | 
				
			||||||
        $chapter->updated_by = auth()->user()->id;
 | 
					        $chapter->updated_by = auth()->user()->id;
 | 
				
			||||||
@@ -127,9 +133,9 @@ class ChapterController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function showDelete($bookSlug, $chapterSlug)
 | 
					    public function showDelete($bookSlug, $chapterSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('chapter-delete');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
 | 
					        $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('chapter-delete', $chapter);
 | 
				
			||||||
        $this->setPageTitle('Delete Chapter' . $chapter->getShortName());
 | 
					        $this->setPageTitle('Delete Chapter' . $chapter->getShortName());
 | 
				
			||||||
        return view('chapters/delete', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]);
 | 
					        return view('chapters/delete', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -142,11 +148,46 @@ class ChapterController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function destroy($bookSlug, $chapterSlug)
 | 
					    public function destroy($bookSlug, $chapterSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('chapter-delete');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
 | 
					        $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('chapter-delete', $chapter);
 | 
				
			||||||
        Activity::addMessage('chapter_delete', $book->id, $chapter->name);
 | 
					        Activity::addMessage('chapter_delete', $book->id, $chapter->name);
 | 
				
			||||||
        $this->chapterRepo->destroy($chapter);
 | 
					        $this->chapterRepo->destroy($chapter);
 | 
				
			||||||
        return redirect($book->getUrl());
 | 
					        return redirect($book->getUrl());
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the Restrictions view.
 | 
				
			||||||
 | 
					     * @param $bookSlug
 | 
				
			||||||
 | 
					     * @param $chapterSlug
 | 
				
			||||||
 | 
					     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function showRestrict($bookSlug, $chapterSlug)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('restrictions-manage', $chapter);
 | 
				
			||||||
 | 
					        $roles = $this->userRepo->getRestrictableRoles();
 | 
				
			||||||
 | 
					        return view('chapters/restrictions', [
 | 
				
			||||||
 | 
					            'chapter' => $chapter,
 | 
				
			||||||
 | 
					            'roles' => $roles
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set the restrictions for this chapter.
 | 
				
			||||||
 | 
					     * @param $bookSlug
 | 
				
			||||||
 | 
					     * @param $chapterSlug
 | 
				
			||||||
 | 
					     * @param Request $request
 | 
				
			||||||
 | 
					     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function restrict($bookSlug, $chapterSlug, Request $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('restrictions-manage', $chapter);
 | 
				
			||||||
 | 
					        $this->chapterRepo->updateRestrictionsFromRequest($request, $chapter);
 | 
				
			||||||
 | 
					        session()->flash('success', 'Page Restrictions Updated');
 | 
				
			||||||
 | 
					        return redirect($chapter->getUrl());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace BookStack\Http\Controllers;
 | 
					namespace BookStack\Http\Controllers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use BookStack\Ownable;
 | 
				
			||||||
use HttpRequestException;
 | 
					use HttpRequestException;
 | 
				
			||||||
use Illuminate\Foundation\Bus\DispatchesJobs;
 | 
					use Illuminate\Foundation\Bus\DispatchesJobs;
 | 
				
			||||||
use Illuminate\Http\Exception\HttpResponseException;
 | 
					use Illuminate\Http\Exception\HttpResponseException;
 | 
				
			||||||
@@ -61,21 +62,19 @@ abstract class Controller extends BaseController
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * On a permission error redirect to home and display
 | 
					     * On a permission error redirect to home and display.
 | 
				
			||||||
     * the error as a notification.
 | 
					     * the error as a notification.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected function showPermissionError()
 | 
					    protected function showPermissionError()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Session::flash('error', trans('errors.permission'));
 | 
					        Session::flash('error', trans('errors.permission'));
 | 
				
			||||||
        throw new HttpResponseException(
 | 
					        $response = request()->wantsJson() ? response()->json(['error' => trans('errors.permissionJson')], 403) : redirect('/');
 | 
				
			||||||
            redirect('/')
 | 
					        throw new HttpResponseException($response);
 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Checks for a permission.
 | 
					     * Checks for a permission.
 | 
				
			||||||
     *
 | 
					     * @param string $permissionName
 | 
				
			||||||
     * @param $permissionName
 | 
					 | 
				
			||||||
     * @return bool|\Illuminate\Http\RedirectResponse
 | 
					     * @return bool|\Illuminate\Http\RedirectResponse
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected function checkPermission($permissionName)
 | 
					    protected function checkPermission($permissionName)
 | 
				
			||||||
@@ -83,10 +82,21 @@ abstract class Controller extends BaseController
 | 
				
			|||||||
        if (!$this->currentUser || !$this->currentUser->can($permissionName)) {
 | 
					        if (!$this->currentUser || !$this->currentUser->can($permissionName)) {
 | 
				
			||||||
            $this->showPermissionError();
 | 
					            $this->showPermissionError();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check the current user's permissions against an ownable item.
 | 
				
			||||||
 | 
					     * @param $permission
 | 
				
			||||||
 | 
					     * @param Ownable $ownable
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected function checkOwnablePermission($permission, Ownable $ownable)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (userCan($permission, $ownable)) return true;
 | 
				
			||||||
 | 
					        return $this->showPermissionError();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Check if a user has a permission or bypass if the callback is true.
 | 
					     * Check if a user has a permission or bypass if the callback is true.
 | 
				
			||||||
     * @param $permissionName
 | 
					     * @param $permissionName
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,7 +64,7 @@ class ImageController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function uploadByType($type, Request $request)
 | 
					    public function uploadByType($type, Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('image-create');
 | 
					        $this->checkPermission('image-create-all');
 | 
				
			||||||
        $this->validate($request, [
 | 
					        $this->validate($request, [
 | 
				
			||||||
            'file' => 'image|mimes:jpeg,gif,png'
 | 
					            'file' => 'image|mimes:jpeg,gif,png'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
@@ -90,7 +90,7 @@ class ImageController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getThumbnail($id, $width, $height, $crop)
 | 
					    public function getThumbnail($id, $width, $height, $crop)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('image-create');
 | 
					        $this->checkPermission('image-create-all');
 | 
				
			||||||
        $image = $this->imageRepo->getById($id);
 | 
					        $image = $this->imageRepo->getById($id);
 | 
				
			||||||
        $thumbnailUrl = $this->imageRepo->getThumbnail($image, $width, $height, $crop == 'false');
 | 
					        $thumbnailUrl = $this->imageRepo->getThumbnail($image, $width, $height, $crop == 'false');
 | 
				
			||||||
        return response()->json(['url' => $thumbnailUrl]);
 | 
					        return response()->json(['url' => $thumbnailUrl]);
 | 
				
			||||||
@@ -104,11 +104,11 @@ class ImageController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function update($imageId, Request $request)
 | 
					    public function update($imageId, Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('image-update');
 | 
					 | 
				
			||||||
        $this->validate($request, [
 | 
					        $this->validate($request, [
 | 
				
			||||||
            'name' => 'required|min:2|string'
 | 
					            'name' => 'required|min:2|string'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
        $image = $this->imageRepo->getById($imageId);
 | 
					        $image = $this->imageRepo->getById($imageId);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('image-update', $image);
 | 
				
			||||||
        $image = $this->imageRepo->updateImageDetails($image, $request->all());
 | 
					        $image = $this->imageRepo->updateImageDetails($image, $request->all());
 | 
				
			||||||
        return response()->json($image);
 | 
					        return response()->json($image);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -123,8 +123,8 @@ class ImageController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function destroy(PageRepo $pageRepo, Request $request, $id)
 | 
					    public function destroy(PageRepo $pageRepo, Request $request, $id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('image-delete');
 | 
					 | 
				
			||||||
        $image = $this->imageRepo->getById($id);
 | 
					        $image = $this->imageRepo->getById($id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('image-delete', $image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Check if this image is used on any pages
 | 
					        // Check if this image is used on any pages
 | 
				
			||||||
        $isForced = ($request->has('force') && ($request->get('force') === 'true') || $request->get('force') === true);
 | 
					        $isForced = ($request->has('force') && ($request->get('force') === 'true') || $request->get('force') === true);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,12 +1,10 @@
 | 
				
			|||||||
<?php
 | 
					<?php namespace BookStack\Http\Controllers;
 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace BookStack\Http\Controllers;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Activity;
 | 
					use Activity;
 | 
				
			||||||
 | 
					use BookStack\Exceptions\NotFoundException;
 | 
				
			||||||
 | 
					use BookStack\Repos\UserRepo;
 | 
				
			||||||
use BookStack\Services\ExportService;
 | 
					use BookStack\Services\ExportService;
 | 
				
			||||||
use Illuminate\Http\Request;
 | 
					use Illuminate\Http\Request;
 | 
				
			||||||
 | 
					 | 
				
			||||||
use Illuminate\Support\Facades\Auth;
 | 
					 | 
				
			||||||
use BookStack\Http\Requests;
 | 
					use BookStack\Http\Requests;
 | 
				
			||||||
use BookStack\Repos\BookRepo;
 | 
					use BookStack\Repos\BookRepo;
 | 
				
			||||||
use BookStack\Repos\ChapterRepo;
 | 
					use BookStack\Repos\ChapterRepo;
 | 
				
			||||||
@@ -21,26 +19,28 @@ class PageController extends Controller
 | 
				
			|||||||
    protected $bookRepo;
 | 
					    protected $bookRepo;
 | 
				
			||||||
    protected $chapterRepo;
 | 
					    protected $chapterRepo;
 | 
				
			||||||
    protected $exportService;
 | 
					    protected $exportService;
 | 
				
			||||||
 | 
					    protected $userRepo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * PageController constructor.
 | 
					     * PageController constructor.
 | 
				
			||||||
     * @param PageRepo      $pageRepo
 | 
					     * @param PageRepo $pageRepo
 | 
				
			||||||
     * @param BookRepo      $bookRepo
 | 
					     * @param BookRepo $bookRepo
 | 
				
			||||||
     * @param ChapterRepo   $chapterRepo
 | 
					     * @param ChapterRepo $chapterRepo
 | 
				
			||||||
     * @param ExportService $exportService
 | 
					     * @param ExportService $exportService
 | 
				
			||||||
 | 
					     * @param UserRepo $userRepo
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(PageRepo $pageRepo, BookRepo $bookRepo, ChapterRepo $chapterRepo, ExportService $exportService)
 | 
					    public function __construct(PageRepo $pageRepo, BookRepo $bookRepo, ChapterRepo $chapterRepo, ExportService $exportService, UserRepo $userRepo)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->pageRepo = $pageRepo;
 | 
					        $this->pageRepo = $pageRepo;
 | 
				
			||||||
        $this->bookRepo = $bookRepo;
 | 
					        $this->bookRepo = $bookRepo;
 | 
				
			||||||
        $this->chapterRepo = $chapterRepo;
 | 
					        $this->chapterRepo = $chapterRepo;
 | 
				
			||||||
        $this->exportService = $exportService;
 | 
					        $this->exportService = $exportService;
 | 
				
			||||||
 | 
					        $this->userRepo = $userRepo;
 | 
				
			||||||
        parent::__construct();
 | 
					        parent::__construct();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Show the form for creating a new page.
 | 
					     * Show the form for creating a new page.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param      $bookSlug
 | 
					     * @param      $bookSlug
 | 
				
			||||||
     * @param bool $chapterSlug
 | 
					     * @param bool $chapterSlug
 | 
				
			||||||
     * @return Response
 | 
					     * @return Response
 | 
				
			||||||
@@ -48,23 +48,22 @@ class PageController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function create($bookSlug, $chapterSlug = false)
 | 
					    public function create($bookSlug, $chapterSlug = false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('page-create');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : false;
 | 
					        $chapter = $chapterSlug ? $this->chapterRepo->getBySlug($chapterSlug, $book->id) : false;
 | 
				
			||||||
 | 
					        $parent = $chapter ? $chapter : $book;
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('page-create', $parent);
 | 
				
			||||||
        $this->setPageTitle('Create New Page');
 | 
					        $this->setPageTitle('Create New Page');
 | 
				
			||||||
        return view('pages/create', ['book' => $book, 'chapter' => $chapter]);
 | 
					        return view('pages/create', ['book' => $book, 'chapter' => $chapter]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Store a newly created page in storage.
 | 
					     * Store a newly created page in storage.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param  Request $request
 | 
					     * @param  Request $request
 | 
				
			||||||
     * @param          $bookSlug
 | 
					     * @param          $bookSlug
 | 
				
			||||||
     * @return Response
 | 
					     * @return Response
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function store(Request $request, $bookSlug)
 | 
					    public function store(Request $request, $bookSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('page-create');
 | 
					 | 
				
			||||||
        $this->validate($request, [
 | 
					        $this->validate($request, [
 | 
				
			||||||
            'name'   => 'required|string|max:255'
 | 
					            'name'   => 'required|string|max:255'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
@@ -72,6 +71,8 @@ class PageController extends Controller
 | 
				
			|||||||
        $input = $request->all();
 | 
					        $input = $request->all();
 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $chapterId = ($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) ? $request->get('chapter') : null;
 | 
					        $chapterId = ($request->has('chapter') && $this->chapterRepo->idExists($request->get('chapter'))) ? $request->get('chapter') : null;
 | 
				
			||||||
 | 
					        $parent = $chapterId !== null ? $this->chapterRepo->getById($chapterId) : $book;
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('page-create', $parent);
 | 
				
			||||||
        $input['priority'] = $this->bookRepo->getNewPriority($book);
 | 
					        $input['priority'] = $this->bookRepo->getNewPriority($book);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $page = $this->pageRepo->saveNew($input, $book, $chapterId);
 | 
					        $page = $this->pageRepo->saveNew($input, $book, $chapterId);
 | 
				
			||||||
@@ -84,7 +85,6 @@ class PageController extends Controller
 | 
				
			|||||||
     * Display the specified page.
 | 
					     * Display the specified page.
 | 
				
			||||||
     * If the page is not found via the slug the
 | 
					     * If the page is not found via the slug the
 | 
				
			||||||
     * revisions are searched for a match.
 | 
					     * revisions are searched for a match.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param $bookSlug
 | 
					     * @param $bookSlug
 | 
				
			||||||
     * @param $pageSlug
 | 
					     * @param $pageSlug
 | 
				
			||||||
     * @return Response
 | 
					     * @return Response
 | 
				
			||||||
@@ -95,7 +95,7 @@ class PageController extends Controller
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
					            $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
				
			||||||
        } catch (NotFoundHttpException $e) {
 | 
					        } catch (NotFoundException $e) {
 | 
				
			||||||
            $page = $this->pageRepo->findPageUsingOldSlug($pageSlug, $bookSlug);
 | 
					            $page = $this->pageRepo->findPageUsingOldSlug($pageSlug, $bookSlug);
 | 
				
			||||||
            if ($page === null) abort(404);
 | 
					            if ($page === null) abort(404);
 | 
				
			||||||
            return redirect($page->getUrl());
 | 
					            return redirect($page->getUrl());
 | 
				
			||||||
@@ -109,23 +109,21 @@ class PageController extends Controller
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Show the form for editing the specified page.
 | 
					     * Show the form for editing the specified page.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param $bookSlug
 | 
					     * @param $bookSlug
 | 
				
			||||||
     * @param $pageSlug
 | 
					     * @param $pageSlug
 | 
				
			||||||
     * @return Response
 | 
					     * @return Response
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function edit($bookSlug, $pageSlug)
 | 
					    public function edit($bookSlug, $pageSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('page-update');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
					        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('page-update', $page);
 | 
				
			||||||
        $this->setPageTitle('Editing Page ' . $page->getShortName());
 | 
					        $this->setPageTitle('Editing Page ' . $page->getShortName());
 | 
				
			||||||
        return view('pages/edit', ['page' => $page, 'book' => $book, 'current' => $page]);
 | 
					        return view('pages/edit', ['page' => $page, 'book' => $book, 'current' => $page]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Update the specified page in storage.
 | 
					     * Update the specified page in storage.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param  Request $request
 | 
					     * @param  Request $request
 | 
				
			||||||
     * @param          $bookSlug
 | 
					     * @param          $bookSlug
 | 
				
			||||||
     * @param          $pageSlug
 | 
					     * @param          $pageSlug
 | 
				
			||||||
@@ -133,12 +131,12 @@ class PageController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function update(Request $request, $bookSlug, $pageSlug)
 | 
					    public function update(Request $request, $bookSlug, $pageSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('page-update');
 | 
					 | 
				
			||||||
        $this->validate($request, [
 | 
					        $this->validate($request, [
 | 
				
			||||||
            'name'   => 'required|string|max:255'
 | 
					            'name'   => 'required|string|max:255'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
					        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('page-update', $page);
 | 
				
			||||||
        $this->pageRepo->updatePage($page, $book->id, $request->all());
 | 
					        $this->pageRepo->updatePage($page, $book->id, $request->all());
 | 
				
			||||||
        Activity::add($page, 'page_update', $book->id);
 | 
					        Activity::add($page, 'page_update', $book->id);
 | 
				
			||||||
        return redirect($page->getUrl());
 | 
					        return redirect($page->getUrl());
 | 
				
			||||||
@@ -164,9 +162,9 @@ class PageController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function showDelete($bookSlug, $pageSlug)
 | 
					    public function showDelete($bookSlug, $pageSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('page-delete');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
					        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('page-delete', $page);
 | 
				
			||||||
        $this->setPageTitle('Delete Page ' . $page->getShortName());
 | 
					        $this->setPageTitle('Delete Page ' . $page->getShortName());
 | 
				
			||||||
        return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]);
 | 
					        return view('pages/delete', ['book' => $book, 'page' => $page, 'current' => $page]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -181,9 +179,9 @@ class PageController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function destroy($bookSlug, $pageSlug)
 | 
					    public function destroy($bookSlug, $pageSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('page-delete');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
					        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('page-delete', $page);
 | 
				
			||||||
        Activity::addMessage('page_delete', $book->id, $page->name);
 | 
					        Activity::addMessage('page_delete', $book->id, $page->name);
 | 
				
			||||||
        $this->pageRepo->destroy($page);
 | 
					        $this->pageRepo->destroy($page);
 | 
				
			||||||
        return redirect($book->getUrl());
 | 
					        return redirect($book->getUrl());
 | 
				
			||||||
@@ -229,9 +227,9 @@ class PageController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function restoreRevision($bookSlug, $pageSlug, $revisionId)
 | 
					    public function restoreRevision($bookSlug, $pageSlug, $revisionId)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('page-update');
 | 
					 | 
				
			||||||
        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
					        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('page-update', $page);
 | 
				
			||||||
        $page = $this->pageRepo->restoreRevision($page, $book, $revisionId);
 | 
					        $page = $this->pageRepo->restoreRevision($page, $book, $revisionId);
 | 
				
			||||||
        Activity::add($page, 'page_restore', $book->id);
 | 
					        Activity::add($page, 'page_restore', $book->id);
 | 
				
			||||||
        return redirect($page->getUrl());
 | 
					        return redirect($page->getUrl());
 | 
				
			||||||
@@ -315,4 +313,39 @@ class PageController extends Controller
 | 
				
			|||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the Restrictions view.
 | 
				
			||||||
 | 
					     * @param $bookSlug
 | 
				
			||||||
 | 
					     * @param $pageSlug
 | 
				
			||||||
 | 
					     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function showRestrict($bookSlug, $pageSlug)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('restrictions-manage', $page);
 | 
				
			||||||
 | 
					        $roles = $this->userRepo->getRestrictableRoles();
 | 
				
			||||||
 | 
					        return view('pages/restrictions', [
 | 
				
			||||||
 | 
					            'page' => $page,
 | 
				
			||||||
 | 
					            'roles' => $roles
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Set the restrictions for this page.
 | 
				
			||||||
 | 
					     * @param $bookSlug
 | 
				
			||||||
 | 
					     * @param $pageSlug
 | 
				
			||||||
 | 
					     * @param Request $request
 | 
				
			||||||
 | 
					     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function restrict($bookSlug, $pageSlug, Request $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = $this->bookRepo->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        $page = $this->pageRepo->getBySlug($pageSlug, $book->id);
 | 
				
			||||||
 | 
					        $this->checkOwnablePermission('restrictions-manage', $page);
 | 
				
			||||||
 | 
					        $this->pageRepo->updateRestrictionsFromRequest($request, $page);
 | 
				
			||||||
 | 
					        session()->flash('success', 'Page Restrictions Updated');
 | 
				
			||||||
 | 
					        return redirect($page->getUrl());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										129
									
								
								app/Http/Controllers/PermissionController.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								app/Http/Controllers/PermissionController.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,129 @@
 | 
				
			|||||||
 | 
					<?php namespace BookStack\Http\Controllers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use BookStack\Exceptions\PermissionsException;
 | 
				
			||||||
 | 
					use BookStack\Repos\PermissionsRepo;
 | 
				
			||||||
 | 
					use Illuminate\Http\Request;
 | 
				
			||||||
 | 
					use BookStack\Http\Requests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PermissionController extends Controller
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $permissionsRepo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * PermissionController constructor.
 | 
				
			||||||
 | 
					     * @param PermissionsRepo $permissionsRepo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(PermissionsRepo $permissionsRepo)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->permissionsRepo = $permissionsRepo;
 | 
				
			||||||
 | 
					        parent::__construct();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show a listing of the roles in the system.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function listRoles()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->checkPermission('user-roles-manage');
 | 
				
			||||||
 | 
					        $roles = $this->permissionsRepo->getAllRoles();
 | 
				
			||||||
 | 
					        return view('settings/roles/index', ['roles' => $roles]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the form to create a new role
 | 
				
			||||||
 | 
					     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function createRole()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->checkPermission('user-roles-manage');
 | 
				
			||||||
 | 
					        return view('settings/roles/create');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Store a new role in the system.
 | 
				
			||||||
 | 
					     * @param Request $request
 | 
				
			||||||
 | 
					     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function storeRole(Request $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->checkPermission('user-roles-manage');
 | 
				
			||||||
 | 
					        $this->validate($request, [
 | 
				
			||||||
 | 
					            'display_name' => 'required|min:3|max:200',
 | 
				
			||||||
 | 
					            'description' => 'max:250'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->permissionsRepo->saveNewRole($request->all());
 | 
				
			||||||
 | 
					        session()->flash('success', 'Role successfully created');
 | 
				
			||||||
 | 
					        return redirect('/settings/roles');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the form for editing a user role.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function editRole($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->checkPermission('user-roles-manage');
 | 
				
			||||||
 | 
					        $role = $this->permissionsRepo->getRoleById($id);
 | 
				
			||||||
 | 
					        return view('settings/roles/edit', ['role' => $role]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Updates a user role.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @param Request $request
 | 
				
			||||||
 | 
					     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function updateRole($id, Request $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->checkPermission('user-roles-manage');
 | 
				
			||||||
 | 
					        $this->validate($request, [
 | 
				
			||||||
 | 
					            'display_name' => 'required|min:3|max:200',
 | 
				
			||||||
 | 
					            'description' => 'max:250'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->permissionsRepo->updateRole($id, $request->all());
 | 
				
			||||||
 | 
					        session()->flash('success', 'Role successfully updated');
 | 
				
			||||||
 | 
					        return redirect('/settings/roles');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Show the view to delete a role.
 | 
				
			||||||
 | 
					     * Offers the chance to migrate users.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function showDeleteRole($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->checkPermission('user-roles-manage');
 | 
				
			||||||
 | 
					        $role = $this->permissionsRepo->getRoleById($id);
 | 
				
			||||||
 | 
					        $roles = $this->permissionsRepo->getAllRolesExcept($role);
 | 
				
			||||||
 | 
					        $blankRole = $role->newInstance(['display_name' => 'Don\'t migrate users']);
 | 
				
			||||||
 | 
					        $roles->prepend($blankRole);
 | 
				
			||||||
 | 
					        return view('settings/roles/delete', ['role' => $role, 'roles' => $roles]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Delete a role from the system,
 | 
				
			||||||
 | 
					     * Migrate from a previous role if set.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @param Request $request
 | 
				
			||||||
 | 
					     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function deleteRole($id, Request $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->checkPermission('user-roles-manage');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            $this->permissionsRepo->deleteRole($id, $request->get('migrate_role_id'));
 | 
				
			||||||
 | 
					        } catch (PermissionsException $e) {
 | 
				
			||||||
 | 
					            session()->flash('error', $e->getMessage());
 | 
				
			||||||
 | 
					            return redirect()->back();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        session()->flash('success', 'Role successfully deleted');
 | 
				
			||||||
 | 
					        return redirect('/settings/roles');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -17,7 +17,7 @@ class SettingController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function index()
 | 
					    public function index()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('settings-update');
 | 
					        $this->checkPermission('settings-manage');
 | 
				
			||||||
        $this->setPageTitle('Settings');
 | 
					        $this->setPageTitle('Settings');
 | 
				
			||||||
        return view('settings/index');
 | 
					        return view('settings/index');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -32,7 +32,7 @@ class SettingController extends Controller
 | 
				
			|||||||
    public function update(Request $request)
 | 
					    public function update(Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->preventAccessForDemoUsers();
 | 
					        $this->preventAccessForDemoUsers();
 | 
				
			||||||
        $this->checkPermission('settings-update');
 | 
					        $this->checkPermission('settings-manage');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Cycles through posted settings and update them
 | 
					        // Cycles through posted settings and update them
 | 
				
			||||||
        foreach($request->all() as $name => $value) {
 | 
					        foreach($request->all() as $name => $value) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,8 @@ class UserController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function index()
 | 
					    public function index()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $users = $this->user->all();
 | 
					        $this->checkPermission('users-manage');
 | 
				
			||||||
 | 
					        $users = $this->userRepo->getAllUsers();
 | 
				
			||||||
        $this->setPageTitle('Users');
 | 
					        $this->setPageTitle('Users');
 | 
				
			||||||
        return view('users/index', ['users' => $users]);
 | 
					        return view('users/index', ['users' => $users]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -46,7 +47,7 @@ class UserController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function create()
 | 
					    public function create()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('user-create');
 | 
					        $this->checkPermission('users-manage');
 | 
				
			||||||
        $authMethod = config('auth.method');
 | 
					        $authMethod = config('auth.method');
 | 
				
			||||||
        return view('users/create', ['authMethod' => $authMethod]);
 | 
					        return view('users/create', ['authMethod' => $authMethod]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -58,11 +59,10 @@ class UserController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function store(Request $request)
 | 
					    public function store(Request $request)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermission('user-create');
 | 
					        $this->checkPermission('users-manage');
 | 
				
			||||||
        $validationRules = [
 | 
					        $validationRules = [
 | 
				
			||||||
            'name'             => 'required',
 | 
					            'name'             => 'required',
 | 
				
			||||||
            'email'            => 'required|email|unique:users,email',
 | 
					            'email'            => 'required|email|unique:users,email'
 | 
				
			||||||
            'role'             => 'required|exists:roles,id'
 | 
					 | 
				
			||||||
        ];
 | 
					        ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $authMethod = config('auth.method');
 | 
					        $authMethod = config('auth.method');
 | 
				
			||||||
@@ -84,7 +84,11 @@ class UserController extends Controller
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $user->save();
 | 
					        $user->save();
 | 
				
			||||||
        $user->attachRoleId($request->get('role'));
 | 
					
 | 
				
			||||||
 | 
					        if ($request->has('roles')) {
 | 
				
			||||||
 | 
					            $roles = $request->get('roles');
 | 
				
			||||||
 | 
					            $user->roles()->sync($roles);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Get avatar from gravatar and save
 | 
					        // Get avatar from gravatar and save
 | 
				
			||||||
        if (!config('services.disable_services')) {
 | 
					        if (!config('services.disable_services')) {
 | 
				
			||||||
@@ -104,7 +108,7 @@ class UserController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function edit($id, SocialAuthService $socialAuthService)
 | 
					    public function edit($id, SocialAuthService $socialAuthService)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermissionOr('user-update', function () use ($id) {
 | 
					        $this->checkPermissionOr('users-manage', function () use ($id) {
 | 
				
			||||||
            return $this->currentUser->id == $id;
 | 
					            return $this->currentUser->id == $id;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -125,7 +129,7 @@ class UserController extends Controller
 | 
				
			|||||||
    public function update(Request $request, $id)
 | 
					    public function update(Request $request, $id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->preventAccessForDemoUsers();
 | 
					        $this->preventAccessForDemoUsers();
 | 
				
			||||||
        $this->checkPermissionOr('user-update', function () use ($id) {
 | 
					        $this->checkPermissionOr('users-manage', function () use ($id) {
 | 
				
			||||||
            return $this->currentUser->id == $id;
 | 
					            return $this->currentUser->id == $id;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -133,8 +137,7 @@ class UserController extends Controller
 | 
				
			|||||||
            'name'             => 'min:2',
 | 
					            'name'             => 'min:2',
 | 
				
			||||||
            'email'            => 'min:2|email|unique:users,email,' . $id,
 | 
					            'email'            => 'min:2|email|unique:users,email,' . $id,
 | 
				
			||||||
            'password'         => 'min:5|required_with:password_confirm',
 | 
					            'password'         => 'min:5|required_with:password_confirm',
 | 
				
			||||||
            'password-confirm' => 'same:password|required_with:password',
 | 
					            'password-confirm' => 'same:password|required_with:password'
 | 
				
			||||||
            'role'             => 'exists:roles,id'
 | 
					 | 
				
			||||||
        ], [
 | 
					        ], [
 | 
				
			||||||
            'password-confirm.required_with' => 'Password confirmation required'
 | 
					            'password-confirm.required_with' => 'Password confirmation required'
 | 
				
			||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
@@ -143,8 +146,9 @@ class UserController extends Controller
 | 
				
			|||||||
        $user->fill($request->all());
 | 
					        $user->fill($request->all());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Role updates
 | 
					        // Role updates
 | 
				
			||||||
        if ($this->currentUser->can('user-update') && $request->has('role')) {
 | 
					        if (userCan('users-manage') && $request->has('roles')) {
 | 
				
			||||||
            $user->attachRoleId($request->get('role'));
 | 
					            $roles = $request->get('roles');
 | 
				
			||||||
 | 
					            $user->roles()->sync($roles);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Password updates
 | 
					        // Password updates
 | 
				
			||||||
@@ -154,11 +158,12 @@ class UserController extends Controller
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // External auth id updates
 | 
					        // External auth id updates
 | 
				
			||||||
        if ($this->currentUser->can('user-update') && $request->has('external_auth_id')) {
 | 
					        if ($this->currentUser->can('users-manage') && $request->has('external_auth_id')) {
 | 
				
			||||||
            $user->external_auth_id = $request->get('external_auth_id');
 | 
					            $user->external_auth_id = $request->get('external_auth_id');
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $user->save();
 | 
					        $user->save();
 | 
				
			||||||
 | 
					        session()->flash('success', 'User successfully updated');
 | 
				
			||||||
        return redirect('/settings/users');
 | 
					        return redirect('/settings/users');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -169,7 +174,7 @@ class UserController extends Controller
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function delete($id)
 | 
					    public function delete($id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->checkPermissionOr('user-delete', function () use ($id) {
 | 
					        $this->checkPermissionOr('users-manage', function () use ($id) {
 | 
				
			||||||
            return $this->currentUser->id == $id;
 | 
					            return $this->currentUser->id == $id;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -186,7 +191,7 @@ class UserController extends Controller
 | 
				
			|||||||
    public function destroy($id)
 | 
					    public function destroy($id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->preventAccessForDemoUsers();
 | 
					        $this->preventAccessForDemoUsers();
 | 
				
			||||||
        $this->checkPermissionOr('user-delete', function () use ($id) {
 | 
					        $this->checkPermissionOr('users-manage', function () use ($id) {
 | 
				
			||||||
            return $this->currentUser->id == $id;
 | 
					            return $this->currentUser->id == $id;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,6 +19,8 @@ Route::group(['middleware' => 'auth'], function () {
 | 
				
			|||||||
        Route::delete('/{id}', 'BookController@destroy');
 | 
					        Route::delete('/{id}', 'BookController@destroy');
 | 
				
			||||||
        Route::get('/{slug}/sort-item', 'BookController@getSortItem');
 | 
					        Route::get('/{slug}/sort-item', 'BookController@getSortItem');
 | 
				
			||||||
        Route::get('/{slug}', 'BookController@show');
 | 
					        Route::get('/{slug}', 'BookController@show');
 | 
				
			||||||
 | 
					        Route::get('/{bookSlug}/restrict', 'BookController@showRestrict');
 | 
				
			||||||
 | 
					        Route::put('/{bookSlug}/restrict', 'BookController@restrict');
 | 
				
			||||||
        Route::get('/{slug}/delete', 'BookController@showDelete');
 | 
					        Route::get('/{slug}/delete', 'BookController@showDelete');
 | 
				
			||||||
        Route::get('/{bookSlug}/sort', 'BookController@sort');
 | 
					        Route::get('/{bookSlug}/sort', 'BookController@sort');
 | 
				
			||||||
        Route::put('/{bookSlug}/sort', 'BookController@saveSort');
 | 
					        Route::put('/{bookSlug}/sort', 'BookController@saveSort');
 | 
				
			||||||
@@ -32,6 +34,8 @@ Route::group(['middleware' => 'auth'], function () {
 | 
				
			|||||||
        Route::get('/{bookSlug}/page/{pageSlug}/export/plaintext', 'PageController@exportPlainText');
 | 
					        Route::get('/{bookSlug}/page/{pageSlug}/export/plaintext', 'PageController@exportPlainText');
 | 
				
			||||||
        Route::get('/{bookSlug}/page/{pageSlug}/edit', 'PageController@edit');
 | 
					        Route::get('/{bookSlug}/page/{pageSlug}/edit', 'PageController@edit');
 | 
				
			||||||
        Route::get('/{bookSlug}/page/{pageSlug}/delete', 'PageController@showDelete');
 | 
					        Route::get('/{bookSlug}/page/{pageSlug}/delete', 'PageController@showDelete');
 | 
				
			||||||
 | 
					        Route::get('/{bookSlug}/page/{pageSlug}/restrict', 'PageController@showRestrict');
 | 
				
			||||||
 | 
					        Route::put('/{bookSlug}/page/{pageSlug}/restrict', 'PageController@restrict');
 | 
				
			||||||
        Route::put('/{bookSlug}/page/{pageSlug}', 'PageController@update');
 | 
					        Route::put('/{bookSlug}/page/{pageSlug}', 'PageController@update');
 | 
				
			||||||
        Route::delete('/{bookSlug}/page/{pageSlug}', 'PageController@destroy');
 | 
					        Route::delete('/{bookSlug}/page/{pageSlug}', 'PageController@destroy');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -47,6 +51,8 @@ Route::group(['middleware' => 'auth'], function () {
 | 
				
			|||||||
        Route::get('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@show');
 | 
					        Route::get('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@show');
 | 
				
			||||||
        Route::put('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@update');
 | 
					        Route::put('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@update');
 | 
				
			||||||
        Route::get('/{bookSlug}/chapter/{chapterSlug}/edit', 'ChapterController@edit');
 | 
					        Route::get('/{bookSlug}/chapter/{chapterSlug}/edit', 'ChapterController@edit');
 | 
				
			||||||
 | 
					        Route::get('/{bookSlug}/chapter/{chapterSlug}/restrict', 'ChapterController@showRestrict');
 | 
				
			||||||
 | 
					        Route::put('/{bookSlug}/chapter/{chapterSlug}/restrict', 'ChapterController@restrict');
 | 
				
			||||||
        Route::get('/{bookSlug}/chapter/{chapterSlug}/delete', 'ChapterController@showDelete');
 | 
					        Route::get('/{bookSlug}/chapter/{chapterSlug}/delete', 'ChapterController@showDelete');
 | 
				
			||||||
        Route::delete('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@destroy');
 | 
					        Route::delete('/{bookSlug}/chapter/{chapterSlug}', 'ChapterController@destroy');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,6 +93,7 @@ Route::group(['middleware' => 'auth'], function () {
 | 
				
			|||||||
    Route::group(['prefix' => 'settings'], function() {
 | 
					    Route::group(['prefix' => 'settings'], function() {
 | 
				
			||||||
        Route::get('/', 'SettingController@index');
 | 
					        Route::get('/', 'SettingController@index');
 | 
				
			||||||
        Route::post('/', 'SettingController@update');
 | 
					        Route::post('/', 'SettingController@update');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Users
 | 
					        // Users
 | 
				
			||||||
        Route::get('/users', 'UserController@index');
 | 
					        Route::get('/users', 'UserController@index');
 | 
				
			||||||
        Route::get('/users/create', 'UserController@create');
 | 
					        Route::get('/users/create', 'UserController@create');
 | 
				
			||||||
@@ -95,6 +102,15 @@ Route::group(['middleware' => 'auth'], function () {
 | 
				
			|||||||
        Route::get('/users/{id}', 'UserController@edit');
 | 
					        Route::get('/users/{id}', 'UserController@edit');
 | 
				
			||||||
        Route::put('/users/{id}', 'UserController@update');
 | 
					        Route::put('/users/{id}', 'UserController@update');
 | 
				
			||||||
        Route::delete('/users/{id}', 'UserController@destroy');
 | 
					        Route::delete('/users/{id}', 'UserController@destroy');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Roles
 | 
				
			||||||
 | 
					        Route::get('/roles', 'PermissionController@listRoles');
 | 
				
			||||||
 | 
					        Route::get('/roles/new', 'PermissionController@createRole');
 | 
				
			||||||
 | 
					        Route::post('/roles/new', 'PermissionController@storeRole');
 | 
				
			||||||
 | 
					        Route::get('/roles/delete/{id}', 'PermissionController@showDeleteRole');
 | 
				
			||||||
 | 
					        Route::delete('/roles/delete/{id}', 'PermissionController@deleteRole');
 | 
				
			||||||
 | 
					        Route::get('/roles/{id}', 'PermissionController@editRole');
 | 
				
			||||||
 | 
					        Route::put('/roles/{id}', 'PermissionController@updateRole');
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,14 +1,9 @@
 | 
				
			|||||||
<?php
 | 
					<?php namespace BookStack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace BookStack;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use Illuminate\Database\Eloquent\Model;
 | 
					 | 
				
			||||||
use Images;
 | 
					use Images;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Image extends Model
 | 
					class Image extends Ownable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    use Ownable;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected $fillable = ['name'];
 | 
					    protected $fillable = ['name'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,8 @@
 | 
				
			|||||||
<?php namespace BookStack;
 | 
					<?php namespace BookStack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
trait Ownable
 | 
					abstract class Ownable extends Model
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Relation for the user that created this entity.
 | 
					     * Relation for the user that created this entity.
 | 
				
			||||||
@@ -20,4 +21,14 @@ trait Ownable
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->belongsTo('BookStack\User', 'updated_by');
 | 
					        return $this->belongsTo('BookStack\User', 'updated_by');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the class name.
 | 
				
			||||||
 | 
					     * @return string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static function getClassName()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return strtolower(array_slice(explode('\\', static::class), -1, 1)[0]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -13,4 +13,14 @@ class Permission extends Model
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->belongsToMany('BookStack\Permissions');
 | 
					        return $this->belongsToMany('BookStack\Permissions');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the permission object by name.
 | 
				
			||||||
 | 
					     * @param $roleName
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static function getByName($name)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return static::where('name', '=', $name)->first();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -28,11 +28,17 @@ class CustomFacadeProvider extends ServiceProvider
 | 
				
			|||||||
    public function register()
 | 
					    public function register()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->app->bind('activity', function() {
 | 
					        $this->app->bind('activity', function() {
 | 
				
			||||||
            return new ActivityService($this->app->make('BookStack\Activity'));
 | 
					            return new ActivityService(
 | 
				
			||||||
 | 
					                $this->app->make('BookStack\Activity'),
 | 
				
			||||||
 | 
					                $this->app->make('BookStack\Services\RestrictionService')
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->app->bind('views', function() {
 | 
					        $this->app->bind('views', function() {
 | 
				
			||||||
            return new ViewService($this->app->make('BookStack\View'));
 | 
					            return new ViewService(
 | 
				
			||||||
 | 
					                $this->app->make('BookStack\View'),
 | 
				
			||||||
 | 
					                $this->app->make('BookStack\Services\RestrictionService')
 | 
				
			||||||
 | 
					            );
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->app->bind('setting', function() {
 | 
					        $this->app->bind('setting', function() {
 | 
				
			||||||
@@ -41,6 +47,7 @@ class CustomFacadeProvider extends ServiceProvider
 | 
				
			|||||||
                $this->app->make('Illuminate\Contracts\Cache\Repository')
 | 
					                $this->app->make('Illuminate\Contracts\Cache\Repository')
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $this->app->bind('images', function() {
 | 
					        $this->app->bind('images', function() {
 | 
				
			||||||
            return new ImageService(
 | 
					            return new ImageService(
 | 
				
			||||||
                $this->app->make('Intervention\Image\ImageManager'),
 | 
					                $this->app->make('Intervention\Image\ImageManager'),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,18 +11,31 @@ class BookRepo
 | 
				
			|||||||
    protected $book;
 | 
					    protected $book;
 | 
				
			||||||
    protected $pageRepo;
 | 
					    protected $pageRepo;
 | 
				
			||||||
    protected $chapterRepo;
 | 
					    protected $chapterRepo;
 | 
				
			||||||
 | 
					    protected $restrictionService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * BookRepo constructor.
 | 
					     * BookRepo constructor.
 | 
				
			||||||
     * @param Book $book
 | 
					     * @param Book $book
 | 
				
			||||||
     * @param PageRepo $pageRepo
 | 
					     * @param PageRepo $pageRepo
 | 
				
			||||||
     * @param ChapterRepo $chapterRepo
 | 
					     * @param ChapterRepo $chapterRepo
 | 
				
			||||||
 | 
					     * @param RestrictionService $restrictionService
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(Book $book, PageRepo $pageRepo, ChapterRepo $chapterRepo)
 | 
					    public function __construct(Book $book, PageRepo $pageRepo, ChapterRepo $chapterRepo, RestrictionService $restrictionService)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->book = $book;
 | 
					        $this->book = $book;
 | 
				
			||||||
        $this->pageRepo = $pageRepo;
 | 
					        $this->pageRepo = $pageRepo;
 | 
				
			||||||
        $this->chapterRepo = $chapterRepo;
 | 
					        $this->chapterRepo = $chapterRepo;
 | 
				
			||||||
 | 
					        $this->restrictionService = $restrictionService;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Base query for getting books.
 | 
				
			||||||
 | 
					     * Takes into account any restrictions.
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function bookQuery()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->restrictionService->enforceBookRestrictions($this->book, 'view');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -32,7 +45,7 @@ class BookRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getById($id)
 | 
					    public function getById($id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->book->findOrFail($id);
 | 
					        return $this->bookQuery()->findOrFail($id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -42,7 +55,7 @@ class BookRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getAll($count = 10)
 | 
					    public function getAll($count = 10)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $bookQuery = $this->book->orderBy('name', 'asc');
 | 
					        $bookQuery = $this->bookQuery()->orderBy('name', 'asc');
 | 
				
			||||||
        if (!$count) return $bookQuery->get();
 | 
					        if (!$count) return $bookQuery->get();
 | 
				
			||||||
        return $bookQuery->take($count)->get();
 | 
					        return $bookQuery->take($count)->get();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -54,7 +67,8 @@ class BookRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getAllPaginated($count = 10)
 | 
					    public function getAllPaginated($count = 10)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->book->orderBy('name', 'asc')->paginate($count);
 | 
					        return $this->bookQuery()
 | 
				
			||||||
 | 
					            ->orderBy('name', 'asc')->paginate($count);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -65,7 +79,7 @@ class BookRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getLatest($count = 10)
 | 
					    public function getLatest($count = 10)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->book->orderBy('created_at', 'desc')->take($count)->get();
 | 
					        return $this->bookQuery()->orderBy('created_at', 'desc')->take($count)->get();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -76,6 +90,7 @@ class BookRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getRecentlyViewed($count = 10, $page = 0)
 | 
					    public function getRecentlyViewed($count = 10, $page = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO restrict
 | 
				
			||||||
        return Views::getUserRecentlyViewed($count, $page, $this->book);
 | 
					        return Views::getUserRecentlyViewed($count, $page, $this->book);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,6 +102,7 @@ class BookRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getPopular($count = 10, $page = 0)
 | 
					    public function getPopular($count = 10, $page = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO - Restrict
 | 
				
			||||||
        return Views::getPopular($count, $page, $this->book);
 | 
					        return Views::getPopular($count, $page, $this->book);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -94,11 +110,12 @@ class BookRepo
 | 
				
			|||||||
     * Get a book by slug
 | 
					     * Get a book by slug
 | 
				
			||||||
     * @param $slug
 | 
					     * @param $slug
 | 
				
			||||||
     * @return mixed
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     * @throws NotFoundException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getBySlug($slug)
 | 
					    public function getBySlug($slug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $book = $this->book->where('slug', '=', $slug)->first();
 | 
					        $book = $this->bookQuery()->where('slug', '=', $slug)->first();
 | 
				
			||||||
        if ($book === null) abort(404);
 | 
					        if ($book === null) throw new NotFoundException('Book not found');
 | 
				
			||||||
        return $book;
 | 
					        return $book;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -109,7 +126,7 @@ class BookRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function exists($id)
 | 
					    public function exists($id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->book->where('id', '=', $id)->exists();
 | 
					        return $this->bookQuery()->where('id', '=', $id)->exists();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -119,17 +136,7 @@ class BookRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function newFromInput($input)
 | 
					    public function newFromInput($input)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->book->fill($input);
 | 
					        return $this->book->newInstance($input);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Count the amount of books that have a specific slug.
 | 
					 | 
				
			||||||
     * @param $slug
 | 
					 | 
				
			||||||
     * @return mixed
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public function countBySlug($slug)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->book->where('slug', '=', $slug)->count();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -146,6 +153,7 @@ class BookRepo
 | 
				
			|||||||
            $this->chapterRepo->destroy($chapter);
 | 
					            $this->chapterRepo->destroy($chapter);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        $book->views()->delete();
 | 
					        $book->views()->delete();
 | 
				
			||||||
 | 
					        $book->restrictions()->delete();
 | 
				
			||||||
        $book->delete();
 | 
					        $book->delete();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -202,8 +210,15 @@ class BookRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getChildren(Book $book)
 | 
					    public function getChildren(Book $book)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $pages = $book->pages()->where('chapter_id', '=', 0)->get();
 | 
					        $pageQuery = $book->pages()->where('chapter_id', '=', 0);
 | 
				
			||||||
        $chapters = $book->chapters()->with('pages')->get();
 | 
					        $pageQuery = $this->restrictionService->enforcePageRestrictions($pageQuery, 'view');
 | 
				
			||||||
 | 
					        $pages = $pageQuery->get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $chapterQuery = $book->chapters()->with(['pages' => function($query) {
 | 
				
			||||||
 | 
					            $this->restrictionService->enforcePageRestrictions($query, 'view');
 | 
				
			||||||
 | 
					        }]);
 | 
				
			||||||
 | 
					        $chapterQuery = $this->restrictionService->enforceChapterRestrictions($chapterQuery, 'view');
 | 
				
			||||||
 | 
					        $chapters = $chapterQuery->get();
 | 
				
			||||||
        $children = $pages->merge($chapters);
 | 
					        $children = $pages->merge($chapters);
 | 
				
			||||||
        $bookSlug = $book->slug;
 | 
					        $bookSlug = $book->slug;
 | 
				
			||||||
        $children->each(function ($child) use ($bookSlug) {
 | 
					        $children->each(function ($child) use ($bookSlug) {
 | 
				
			||||||
@@ -236,7 +251,7 @@ class BookRepo
 | 
				
			|||||||
        if (!empty($term)) {
 | 
					        if (!empty($term)) {
 | 
				
			||||||
            $terms = array_merge($terms, explode(' ', $term));
 | 
					            $terms = array_merge($terms, explode(' ', $term));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        $books = $this->book->fullTextSearchQuery(['name', 'description'], $terms)
 | 
					        $books = $this->restrictionService->enforceBookRestrictions($this->book->fullTextSearchQuery(['name', 'description'], $terms))
 | 
				
			||||||
            ->paginate($count)->appends($paginationAppends);
 | 
					            ->paginate($count)->appends($paginationAppends);
 | 
				
			||||||
        $words = join('|', explode(' ', preg_quote(trim($term), '/')));
 | 
					        $words = join('|', explode(' ', preg_quote(trim($term), '/')));
 | 
				
			||||||
        foreach ($books as $book) {
 | 
					        foreach ($books as $book) {
 | 
				
			||||||
@@ -247,4 +262,27 @@ class BookRepo
 | 
				
			|||||||
        return $books;
 | 
					        return $books;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Updates books restrictions from a request
 | 
				
			||||||
 | 
					     * @param $request
 | 
				
			||||||
 | 
					     * @param $book
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function updateRestrictionsFromRequest($request, $book)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO - extract into shared repo
 | 
				
			||||||
 | 
					        $book->restricted = $request->has('restricted') && $request->get('restricted') === 'true';
 | 
				
			||||||
 | 
					        $book->restrictions()->delete();
 | 
				
			||||||
 | 
					        if ($request->has('restrictions')) {
 | 
				
			||||||
 | 
					            foreach ($request->get('restrictions') as $roleId => $restrictions) {
 | 
				
			||||||
 | 
					                foreach ($restrictions as $action => $value) {
 | 
				
			||||||
 | 
					                    $book->restrictions()->create([
 | 
				
			||||||
 | 
					                        'role_id' => $roleId,
 | 
				
			||||||
 | 
					                        'action' => strtolower($action)
 | 
				
			||||||
 | 
					                    ]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $book->save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										295
									
								
								app/Repos/BookRepo.php.orig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								app/Repos/BookRepo.php.orig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,295 @@
 | 
				
			|||||||
 | 
					<?php namespace BookStack\Repos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Activity;
 | 
				
			||||||
 | 
					use BookStack\Exceptions\NotFoundException;
 | 
				
			||||||
 | 
					use BookStack\Services\RestrictionService;
 | 
				
			||||||
 | 
					use Illuminate\Support\Str;
 | 
				
			||||||
 | 
					use BookStack\Book;
 | 
				
			||||||
 | 
					use Views;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BookRepo
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $book;
 | 
				
			||||||
 | 
					    protected $pageRepo;
 | 
				
			||||||
 | 
					    protected $chapterRepo;
 | 
				
			||||||
 | 
					    protected $restrictionService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * BookRepo constructor.
 | 
				
			||||||
 | 
					     * @param Book $book
 | 
				
			||||||
 | 
					     * @param PageRepo $pageRepo
 | 
				
			||||||
 | 
					     * @param ChapterRepo $chapterRepo
 | 
				
			||||||
 | 
					     * @param RestrictionService $restrictionService
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(Book $book, PageRepo $pageRepo, ChapterRepo $chapterRepo, RestrictionService $restrictionService)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->book = $book;
 | 
				
			||||||
 | 
					        $this->pageRepo = $pageRepo;
 | 
				
			||||||
 | 
					        $this->chapterRepo = $chapterRepo;
 | 
				
			||||||
 | 
					        $this->restrictionService = $restrictionService;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Base query for getting books.
 | 
				
			||||||
 | 
					     * Takes into account any restrictions.
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function bookQuery()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->restrictionService->enforceBookRestrictions($this->book, 'view');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the book that has the given id.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getById($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->bookQuery()->findOrFail($id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get all books, Limited by count.
 | 
				
			||||||
 | 
					     * @param int $count
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getAll($count = 10)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $bookQuery = $this->bookQuery()->orderBy('name', 'asc');
 | 
				
			||||||
 | 
					        if (!$count) return $bookQuery->get();
 | 
				
			||||||
 | 
					        return $bookQuery->take($count)->get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get all books paginated.
 | 
				
			||||||
 | 
					     * @param int $count
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getAllPaginated($count = 10)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->bookQuery()
 | 
				
			||||||
 | 
					            ->orderBy('name', 'asc')->paginate($count);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the latest books.
 | 
				
			||||||
 | 
					     * @param int $count
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getLatest($count = 10)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->bookQuery()->orderBy('created_at', 'desc')->take($count)->get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the most recently viewed for a user.
 | 
				
			||||||
 | 
					     * @param int $count
 | 
				
			||||||
 | 
					     * @param int $page
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getRecentlyViewed($count = 10, $page = 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO restrict
 | 
				
			||||||
 | 
					        return Views::getUserRecentlyViewed($count, $page, $this->book);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets the most viewed books.
 | 
				
			||||||
 | 
					     * @param int $count
 | 
				
			||||||
 | 
					     * @param int $page
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getPopular($count = 10, $page = 0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO - Restrict
 | 
				
			||||||
 | 
					        return Views::getPopular($count, $page, $this->book);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a book by slug
 | 
				
			||||||
 | 
					     * @param $slug
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     * @throws NotFoundException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getBySlug($slug)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = $this->bookQuery()->where('slug', '=', $slug)->first();
 | 
				
			||||||
 | 
					        if ($book === null) throw new NotFoundException('Book not found');
 | 
				
			||||||
 | 
					        return $book;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks if a book exists.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function exists($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->bookQuery()->where('id', '=', $id)->exists();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a new book instance from request input.
 | 
				
			||||||
 | 
					     * @param $input
 | 
				
			||||||
 | 
					     * @return Book
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function newFromInput($input)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->book->newInstance($input);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Destroy a book identified by the given slug.
 | 
				
			||||||
 | 
					     * @param $bookSlug
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function destroyBySlug($bookSlug)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = $this->getBySlug($bookSlug);
 | 
				
			||||||
 | 
					        foreach ($book->pages as $page) {
 | 
				
			||||||
 | 
					            $this->pageRepo->destroy($page);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        foreach ($book->chapters as $chapter) {
 | 
				
			||||||
 | 
					            $this->chapterRepo->destroy($chapter);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $book->views()->delete();
 | 
				
			||||||
 | 
					        $book->restrictions()->delete();
 | 
				
			||||||
 | 
					        $book->delete();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the next child element priority.
 | 
				
			||||||
 | 
					     * @param Book $book
 | 
				
			||||||
 | 
					     * @return int
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getNewPriority($book)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $lastElem = $this->getChildren($book)->pop();
 | 
				
			||||||
 | 
					        return $lastElem ? $lastElem->priority + 1 : 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param string $slug
 | 
				
			||||||
 | 
					     * @param bool|false $currentId
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function doesSlugExist($slug, $currentId = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $query = $this->book->where('slug', '=', $slug);
 | 
				
			||||||
 | 
					        if ($currentId) {
 | 
				
			||||||
 | 
					            $query = $query->where('id', '!=', $currentId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $query->count() > 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Provides a suitable slug for the given book name.
 | 
				
			||||||
 | 
					     * Ensures the returned slug is unique in the system.
 | 
				
			||||||
 | 
					     * @param string $name
 | 
				
			||||||
 | 
					     * @param bool|false $currentId
 | 
				
			||||||
 | 
					     * @return string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function findSuitableSlug($name, $currentId = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $originalSlug = Str::slug($name);
 | 
				
			||||||
 | 
					        $slug = $originalSlug;
 | 
				
			||||||
 | 
					        $count = 2;
 | 
				
			||||||
 | 
					        while ($this->doesSlugExist($slug, $currentId)) {
 | 
				
			||||||
 | 
					            $slug = $originalSlug . '-' . $count;
 | 
				
			||||||
 | 
					            $count++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $slug;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get all child objects of a book.
 | 
				
			||||||
 | 
					     * Returns a sorted collection of Pages and Chapters.
 | 
				
			||||||
 | 
					     * Loads the bookslug onto child elements to prevent access database access for getting the slug.
 | 
				
			||||||
 | 
					     * @param Book $book
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getChildren(Book $book)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $pageQuery = $book->pages()->where('chapter_id', '=', 0);
 | 
				
			||||||
 | 
					        $pageQuery = $this->restrictionService->enforcePageRestrictions($pageQuery, 'view');
 | 
				
			||||||
 | 
					        $pages = $pageQuery->get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $chapterQuery = $book->chapters()->with(['pages' => function($query) {
 | 
				
			||||||
 | 
					            $this->restrictionService->enforcePageRestrictions($query, 'view');
 | 
				
			||||||
 | 
					        }]);
 | 
				
			||||||
 | 
					        $chapterQuery = $this->restrictionService->enforceChapterRestrictions($chapterQuery, 'view');
 | 
				
			||||||
 | 
					        $chapters = $chapterQuery->get();
 | 
				
			||||||
 | 
					        $children = $pages->merge($chapters);
 | 
				
			||||||
 | 
					        $bookSlug = $book->slug;
 | 
				
			||||||
 | 
					        $children->each(function ($child) use ($bookSlug) {
 | 
				
			||||||
 | 
					            $child->setAttribute('bookSlug', $bookSlug);
 | 
				
			||||||
 | 
					            if ($child->isA('chapter')) {
 | 
				
			||||||
 | 
					                $child->pages->each(function ($page) use ($bookSlug) {
 | 
				
			||||||
 | 
					                    $page->setAttribute('bookSlug', $bookSlug);
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					        return $children->sortBy('priority');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get books by search term.
 | 
				
			||||||
 | 
					     * @param $term
 | 
				
			||||||
 | 
					     * @param int $count
 | 
				
			||||||
 | 
					     * @param array $paginationAppends
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getBySearch($term, $count = 20, $paginationAppends = [])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					<<<<<<< HEAD
 | 
				
			||||||
 | 
					        preg_match_all('/"(.*?)"/', $term, $matches);
 | 
				
			||||||
 | 
					        if (count($matches[1]) > 0) {
 | 
				
			||||||
 | 
					            $terms = $matches[1];
 | 
				
			||||||
 | 
					            $term = trim(preg_replace('/"(.*?)"/', '', $term));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $terms = [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!empty($term)) {
 | 
				
			||||||
 | 
					            $terms = array_merge($terms, explode(' ', $term));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $books = $this->book->fullTextSearchQuery(['name', 'description'], $terms)
 | 
				
			||||||
 | 
					=======
 | 
				
			||||||
 | 
					        $terms = explode(' ', $term);
 | 
				
			||||||
 | 
					        $books = $this->restrictionService->enforceBookRestrictions($this->book->fullTextSearchQuery(['name', 'description'], $terms))
 | 
				
			||||||
 | 
					>>>>>>> custom_role_system
 | 
				
			||||||
 | 
					            ->paginate($count)->appends($paginationAppends);
 | 
				
			||||||
 | 
					        $words = join('|', explode(' ', preg_quote(trim($term), '/')));
 | 
				
			||||||
 | 
					        foreach ($books as $book) {
 | 
				
			||||||
 | 
					            //highlight
 | 
				
			||||||
 | 
					            $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $book->getExcerpt(100));
 | 
				
			||||||
 | 
					            $book->searchSnippet = $result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $books;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Updates books restrictions from a request
 | 
				
			||||||
 | 
					     * @param $request
 | 
				
			||||||
 | 
					     * @param $book
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function updateRestrictionsFromRequest($request, $book)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO - extract into shared repo
 | 
				
			||||||
 | 
					        $book->restricted = $request->has('restricted') && $request->get('restricted') === 'true';
 | 
				
			||||||
 | 
					        $book->restrictions()->delete();
 | 
				
			||||||
 | 
					        if ($request->has('restrictions')) {
 | 
				
			||||||
 | 
					            foreach ($request->get('restrictions') as $roleId => $restrictions) {
 | 
				
			||||||
 | 
					                foreach ($restrictions as $action => $value) {
 | 
				
			||||||
 | 
					                    $book->restrictions()->create([
 | 
				
			||||||
 | 
					                        'role_id' => $roleId,
 | 
				
			||||||
 | 
					                        'action' => strtolower($action)
 | 
				
			||||||
 | 
					                    ]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $book->save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -2,6 +2,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Activity;
 | 
					use Activity;
 | 
				
			||||||
 | 
					use BookStack\Exceptions\NotFoundException;
 | 
				
			||||||
 | 
					use BookStack\Services\RestrictionService;
 | 
				
			||||||
use Illuminate\Support\Str;
 | 
					use Illuminate\Support\Str;
 | 
				
			||||||
use BookStack\Chapter;
 | 
					use BookStack\Chapter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -9,14 +11,26 @@ class ChapterRepo
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    protected $chapter;
 | 
					    protected $chapter;
 | 
				
			||||||
 | 
					    protected $restrictionService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * ChapterRepo constructor.
 | 
					     * ChapterRepo constructor.
 | 
				
			||||||
     * @param $chapter
 | 
					     * @param Chapter $chapter
 | 
				
			||||||
 | 
					     * @param RestrictionService $restrictionService
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(Chapter $chapter)
 | 
					    public function __construct(Chapter $chapter, RestrictionService $restrictionService)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->chapter = $chapter;
 | 
					        $this->chapter = $chapter;
 | 
				
			||||||
 | 
					        $this->restrictionService = $restrictionService;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Base query for getting chapters, Takes restrictions into account.
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function chapterQuery()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->restrictionService->enforceChapterRestrictions($this->chapter, 'view');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -26,7 +40,7 @@ class ChapterRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function idExists($id)
 | 
					    public function idExists($id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->chapter->where('id', '=', $id)->count() > 0;
 | 
					        return $this->chapterQuery()->where('id', '=', $id)->count() > 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -36,7 +50,7 @@ class ChapterRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getById($id)
 | 
					    public function getById($id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->chapter->findOrFail($id);
 | 
					        return $this->chapterQuery()->findOrFail($id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -45,7 +59,7 @@ class ChapterRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getAll()
 | 
					    public function getAll()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->chapter->all();
 | 
					        return $this->chapterQuery()->all();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -53,14 +67,24 @@ class ChapterRepo
 | 
				
			|||||||
     * @param $slug
 | 
					     * @param $slug
 | 
				
			||||||
     * @param $bookId
 | 
					     * @param $bookId
 | 
				
			||||||
     * @return mixed
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     * @throws NotFoundException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getBySlug($slug, $bookId)
 | 
					    public function getBySlug($slug, $bookId)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $chapter = $this->chapter->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
 | 
					        $chapter = $this->chapterQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
 | 
				
			||||||
        if ($chapter === null) abort(404);
 | 
					        if ($chapter === null) throw new NotFoundException('Chapter not found');
 | 
				
			||||||
        return $chapter;
 | 
					        return $chapter;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the child items for a chapter
 | 
				
			||||||
 | 
					     * @param Chapter $chapter
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getChildren(Chapter $chapter)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->restrictionService->enforcePageRestrictions($chapter->pages())->get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Create a new chapter from request input.
 | 
					     * Create a new chapter from request input.
 | 
				
			||||||
     * @param $input
 | 
					     * @param $input
 | 
				
			||||||
@@ -85,6 +109,7 @@ class ChapterRepo
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        Activity::removeEntity($chapter);
 | 
					        Activity::removeEntity($chapter);
 | 
				
			||||||
        $chapter->views()->delete();
 | 
					        $chapter->views()->delete();
 | 
				
			||||||
 | 
					        $chapter->restrictions()->delete();
 | 
				
			||||||
        $chapter->delete();
 | 
					        $chapter->delete();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -141,7 +166,7 @@ class ChapterRepo
 | 
				
			|||||||
        if (!empty($term)) {
 | 
					        if (!empty($term)) {
 | 
				
			||||||
            $terms = array_merge($terms, explode(' ', $term));
 | 
					            $terms = array_merge($terms, explode(' ', $term));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        $chapters = $this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms)
 | 
					        $chapters = $this->restrictionService->enforceChapterRestrictions($this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms))
 | 
				
			||||||
            ->paginate($count)->appends($paginationAppends);
 | 
					            ->paginate($count)->appends($paginationAppends);
 | 
				
			||||||
        $words = join('|', explode(' ', preg_quote(trim($term), '/')));
 | 
					        $words = join('|', explode(' ', preg_quote(trim($term), '/')));
 | 
				
			||||||
        foreach ($chapters as $chapter) {
 | 
					        foreach ($chapters as $chapter) {
 | 
				
			||||||
@@ -170,4 +195,27 @@ class ChapterRepo
 | 
				
			|||||||
        return $chapter;
 | 
					        return $chapter;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Updates pages restrictions from a request
 | 
				
			||||||
 | 
					     * @param $request
 | 
				
			||||||
 | 
					     * @param $chapter
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function updateRestrictionsFromRequest($request, $chapter)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO - extract into shared repo
 | 
				
			||||||
 | 
					        $chapter->restricted = $request->has('restricted') && $request->get('restricted') === 'true';
 | 
				
			||||||
 | 
					        $chapter->restrictions()->delete();
 | 
				
			||||||
 | 
					        if ($request->has('restrictions')) {
 | 
				
			||||||
 | 
					            foreach($request->get('restrictions') as $roleId => $restrictions) {
 | 
				
			||||||
 | 
					                foreach ($restrictions as $action => $value) {
 | 
				
			||||||
 | 
					                    $chapter->restrictions()->create([
 | 
				
			||||||
 | 
					                        'role_id' => $roleId,
 | 
				
			||||||
 | 
					                        'action'  => strtolower($action)
 | 
				
			||||||
 | 
					                    ]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $chapter->save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										226
									
								
								app/Repos/ChapterRepo.php.orig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								app/Repos/ChapterRepo.php.orig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,226 @@
 | 
				
			|||||||
 | 
					<?php namespace BookStack\Repos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Activity;
 | 
				
			||||||
 | 
					use BookStack\Exceptions\NotFoundException;
 | 
				
			||||||
 | 
					use BookStack\Services\RestrictionService;
 | 
				
			||||||
 | 
					use Illuminate\Support\Str;
 | 
				
			||||||
 | 
					use BookStack\Chapter;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ChapterRepo
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $chapter;
 | 
				
			||||||
 | 
					    protected $restrictionService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * ChapterRepo constructor.
 | 
				
			||||||
 | 
					     * @param Chapter $chapter
 | 
				
			||||||
 | 
					     * @param RestrictionService $restrictionService
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(Chapter $chapter, RestrictionService $restrictionService)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->chapter = $chapter;
 | 
				
			||||||
 | 
					        $this->restrictionService = $restrictionService;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Base query for getting chapters, Takes restrictions into account.
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function chapterQuery()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->restrictionService->enforceChapterRestrictions($this->chapter, 'view');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if an id exists.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function idExists($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->chapterQuery()->where('id', '=', $id)->count() > 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a chapter by a specific id.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getById($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->chapterQuery()->findOrFail($id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get all chapters.
 | 
				
			||||||
 | 
					     * @return \Illuminate\Database\Eloquent\Collection|static[]
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getAll()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->chapterQuery()->all();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a chapter that has the given slug within the given book.
 | 
				
			||||||
 | 
					     * @param $slug
 | 
				
			||||||
 | 
					     * @param $bookId
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     * @throws NotFoundException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getBySlug($slug, $bookId)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $chapter = $this->chapterQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
 | 
				
			||||||
 | 
					        if ($chapter === null) throw new NotFoundException('Chapter not found');
 | 
				
			||||||
 | 
					        return $chapter;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the child items for a chapter
 | 
				
			||||||
 | 
					     * @param Chapter $chapter
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getChildren(Chapter $chapter)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->restrictionService->enforcePageRestrictions($chapter->pages())->get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new chapter from request input.
 | 
				
			||||||
 | 
					     * @param $input
 | 
				
			||||||
 | 
					     * @return $this
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function newFromInput($input)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->chapter->fill($input);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Destroy a chapter and its relations by providing its slug.
 | 
				
			||||||
 | 
					     * @param Chapter $chapter
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function destroy(Chapter $chapter)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if (count($chapter->pages) > 0) {
 | 
				
			||||||
 | 
					            foreach ($chapter->pages as $page) {
 | 
				
			||||||
 | 
					                $page->chapter_id = 0;
 | 
				
			||||||
 | 
					                $page->save();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        Activity::removeEntity($chapter);
 | 
				
			||||||
 | 
					        $chapter->views()->delete();
 | 
				
			||||||
 | 
					        $chapter->restrictions()->delete();
 | 
				
			||||||
 | 
					        $chapter->delete();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if a chapter's slug exists.
 | 
				
			||||||
 | 
					     * @param            $slug
 | 
				
			||||||
 | 
					     * @param            $bookId
 | 
				
			||||||
 | 
					     * @param bool|false $currentId
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function doesSlugExist($slug, $bookId, $currentId = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $query = $this->chapter->where('slug', '=', $slug)->where('book_id', '=', $bookId);
 | 
				
			||||||
 | 
					        if ($currentId) {
 | 
				
			||||||
 | 
					            $query = $query->where('id', '!=', $currentId);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $query->count() > 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Finds a suitable slug for the provided name.
 | 
				
			||||||
 | 
					     * Checks database to prevent duplicate slugs.
 | 
				
			||||||
 | 
					     * @param            $name
 | 
				
			||||||
 | 
					     * @param            $bookId
 | 
				
			||||||
 | 
					     * @param bool|false $currentId
 | 
				
			||||||
 | 
					     * @return string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function findSuitableSlug($name, $bookId, $currentId = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $slug = Str::slug($name);
 | 
				
			||||||
 | 
					        while ($this->doesSlugExist($slug, $bookId, $currentId)) {
 | 
				
			||||||
 | 
					            $slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $slug;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get chapters by the given search term.
 | 
				
			||||||
 | 
					     * @param       $term
 | 
				
			||||||
 | 
					     * @param array $whereTerms
 | 
				
			||||||
 | 
					     * @param int $count
 | 
				
			||||||
 | 
					     * @param array $paginationAppends
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					<<<<<<< HEAD
 | 
				
			||||||
 | 
					        preg_match_all('/"(.*?)"/', $term, $matches);
 | 
				
			||||||
 | 
					        if (count($matches[1]) > 0) {
 | 
				
			||||||
 | 
					            $terms = $matches[1];
 | 
				
			||||||
 | 
					            $term = trim(preg_replace('/"(.*?)"/', '', $term));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $terms = [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!empty($term)) {
 | 
				
			||||||
 | 
					            $terms = array_merge($terms, explode(' ', $term));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $chapters = $this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms)
 | 
				
			||||||
 | 
					=======
 | 
				
			||||||
 | 
					        $terms = explode(' ', $term);
 | 
				
			||||||
 | 
					        $chapters = $this->restrictionService->enforceChapterRestrictions($this->chapter->fullTextSearchQuery(['name', 'description'], $terms, $whereTerms))
 | 
				
			||||||
 | 
					>>>>>>> custom_role_system
 | 
				
			||||||
 | 
					            ->paginate($count)->appends($paginationAppends);
 | 
				
			||||||
 | 
					        $words = join('|', explode(' ', preg_quote(trim($term), '/')));
 | 
				
			||||||
 | 
					        foreach ($chapters as $chapter) {
 | 
				
			||||||
 | 
					            //highlight
 | 
				
			||||||
 | 
					            $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $chapter->getExcerpt(100));
 | 
				
			||||||
 | 
					            $chapter->searchSnippet = $result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $chapters;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Changes the book relation of this chapter.
 | 
				
			||||||
 | 
					     * @param         $bookId
 | 
				
			||||||
 | 
					     * @param Chapter $chapter
 | 
				
			||||||
 | 
					     * @return Chapter
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function changeBook($bookId, Chapter $chapter)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $chapter->book_id = $bookId;
 | 
				
			||||||
 | 
					        foreach ($chapter->activity as $activity) {
 | 
				
			||||||
 | 
					            $activity->book_id = $bookId;
 | 
				
			||||||
 | 
					            $activity->save();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $chapter->slug = $this->findSuitableSlug($chapter->name, $bookId, $chapter->id);
 | 
				
			||||||
 | 
					        $chapter->save();
 | 
				
			||||||
 | 
					        return $chapter;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Updates pages restrictions from a request
 | 
				
			||||||
 | 
					     * @param $request
 | 
				
			||||||
 | 
					     * @param $chapter
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function updateRestrictionsFromRequest($request, $chapter)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO - extract into shared repo
 | 
				
			||||||
 | 
					        $chapter->restricted = $request->has('restricted') && $request->get('restricted') === 'true';
 | 
				
			||||||
 | 
					        $chapter->restrictions()->delete();
 | 
				
			||||||
 | 
					        if ($request->has('restrictions')) {
 | 
				
			||||||
 | 
					            foreach($request->get('restrictions') as $roleId => $restrictions) {
 | 
				
			||||||
 | 
					                foreach ($restrictions as $action => $value) {
 | 
				
			||||||
 | 
					                    $chapter->restrictions()->create([
 | 
				
			||||||
 | 
					                        'role_id' => $roleId,
 | 
				
			||||||
 | 
					                        'action'  => strtolower($action)
 | 
				
			||||||
 | 
					                    ]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $chapter->save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,6 +4,7 @@
 | 
				
			|||||||
use BookStack\Book;
 | 
					use BookStack\Book;
 | 
				
			||||||
use BookStack\Chapter;
 | 
					use BookStack\Chapter;
 | 
				
			||||||
use BookStack\Page;
 | 
					use BookStack\Page;
 | 
				
			||||||
 | 
					use BookStack\Services\RestrictionService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class EntityRepo
 | 
					class EntityRepo
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -11,18 +12,21 @@ class EntityRepo
 | 
				
			|||||||
    public $book;
 | 
					    public $book;
 | 
				
			||||||
    public $chapter;
 | 
					    public $chapter;
 | 
				
			||||||
    public $page;
 | 
					    public $page;
 | 
				
			||||||
 | 
					    private $restrictionService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * EntityService constructor.
 | 
					     * EntityService constructor.
 | 
				
			||||||
     * @param $book
 | 
					     * @param Book $book
 | 
				
			||||||
     * @param $chapter
 | 
					     * @param Chapter $chapter
 | 
				
			||||||
     * @param $page
 | 
					     * @param Page $page
 | 
				
			||||||
 | 
					     * @param RestrictionService $restrictionService
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(Book $book, Chapter $chapter, Page $page)
 | 
					    public function __construct(Book $book, Chapter $chapter, Page $page, RestrictionService $restrictionService)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->book = $book;
 | 
					        $this->book = $book;
 | 
				
			||||||
        $this->chapter = $chapter;
 | 
					        $this->chapter = $chapter;
 | 
				
			||||||
        $this->page = $page;
 | 
					        $this->page = $page;
 | 
				
			||||||
 | 
					        $this->restrictionService = $restrictionService;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -32,7 +36,8 @@ class EntityRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getRecentlyCreatedBooks($count = 20, $page = 0)
 | 
					    public function getRecentlyCreatedBooks($count = 20, $page = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->book->orderBy('created_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
					        return $this->restrictionService->enforceBookRestrictions($this->book)
 | 
				
			||||||
 | 
					            ->orderBy('created_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -43,7 +48,8 @@ class EntityRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getRecentlyUpdatedBooks($count = 20, $page = 0)
 | 
					    public function getRecentlyUpdatedBooks($count = 20, $page = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->book->orderBy('updated_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
					        return $this->restrictionService->enforceBookRestrictions($this->book)
 | 
				
			||||||
 | 
					            ->orderBy('updated_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -53,7 +59,8 @@ class EntityRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getRecentlyCreatedPages($count = 20, $page = 0)
 | 
					    public function getRecentlyCreatedPages($count = 20, $page = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->page->orderBy('created_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
					        return $this->restrictionService->enforcePageRestrictions($this->page)
 | 
				
			||||||
 | 
					            ->orderBy('created_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -64,7 +71,8 @@ class EntityRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getRecentlyUpdatedPages($count = 20, $page = 0)
 | 
					    public function getRecentlyUpdatedPages($count = 20, $page = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->page->orderBy('updated_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
					        return $this->restrictionService->enforcePageRestrictions($this->page)
 | 
				
			||||||
 | 
					            ->orderBy('updated_at', 'desc')->skip($page*$count)->take($count)->get();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,8 @@
 | 
				
			|||||||
use Activity;
 | 
					use Activity;
 | 
				
			||||||
use BookStack\Book;
 | 
					use BookStack\Book;
 | 
				
			||||||
use BookStack\Chapter;
 | 
					use BookStack\Chapter;
 | 
				
			||||||
 | 
					use BookStack\Exceptions\NotFoundException;
 | 
				
			||||||
 | 
					use BookStack\Services\RestrictionService;
 | 
				
			||||||
use Illuminate\Http\Request;
 | 
					use Illuminate\Http\Request;
 | 
				
			||||||
use Illuminate\Support\Facades\Auth;
 | 
					use Illuminate\Support\Facades\Auth;
 | 
				
			||||||
use Illuminate\Support\Facades\Log;
 | 
					use Illuminate\Support\Facades\Log;
 | 
				
			||||||
@@ -16,26 +18,28 @@ class PageRepo
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    protected $page;
 | 
					    protected $page;
 | 
				
			||||||
    protected $pageRevision;
 | 
					    protected $pageRevision;
 | 
				
			||||||
 | 
					    protected $restrictionService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * PageRepo constructor.
 | 
					     * PageRepo constructor.
 | 
				
			||||||
     * @param Page         $page
 | 
					     * @param Page $page
 | 
				
			||||||
     * @param PageRevision $pageRevision
 | 
					     * @param PageRevision $pageRevision
 | 
				
			||||||
 | 
					     * @param RestrictionService $restrictionService
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(Page $page, PageRevision $pageRevision)
 | 
					    public function __construct(Page $page, PageRevision $pageRevision, RestrictionService $restrictionService)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->page = $page;
 | 
					        $this->page = $page;
 | 
				
			||||||
        $this->pageRevision = $pageRevision;
 | 
					        $this->pageRevision = $pageRevision;
 | 
				
			||||||
 | 
					        $this->restrictionService = $restrictionService;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Check if a page id exists.
 | 
					     * Base query for getting pages, Takes restrictions into account.
 | 
				
			||||||
     * @param $id
 | 
					     * @return mixed
 | 
				
			||||||
     * @return bool
 | 
					 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function idExists($id)
 | 
					    private function pageQuery()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->page->where('page_id', '=', $id)->count() > 0;
 | 
					        return $this->restrictionService->enforcePageRestrictions($this->page, 'view');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -45,16 +49,7 @@ class PageRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getById($id)
 | 
					    public function getById($id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->page->findOrFail($id);
 | 
					        return $this->pageQuery()->findOrFail($id);
 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Get all pages.
 | 
					 | 
				
			||||||
     * @return \Illuminate\Database\Eloquent\Collection|static[]
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public function getAll()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return $this->page->all();
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -62,11 +57,12 @@ class PageRepo
 | 
				
			|||||||
     * @param $slug
 | 
					     * @param $slug
 | 
				
			||||||
     * @param $bookId
 | 
					     * @param $bookId
 | 
				
			||||||
     * @return mixed
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     * @throws NotFoundException
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getBySlug($slug, $bookId)
 | 
					    public function getBySlug($slug, $bookId)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $page = $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
 | 
					        $page = $this->pageQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
 | 
				
			||||||
        if ($page === null) throw new NotFoundHttpException('Page not found');
 | 
					        if ($page === null) throw new NotFoundException('Page not found');
 | 
				
			||||||
        return $page;
 | 
					        return $page;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,6 +77,9 @@ class PageRepo
 | 
				
			|||||||
    public function findPageUsingOldSlug($pageSlug, $bookSlug)
 | 
					    public function findPageUsingOldSlug($pageSlug, $bookSlug)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $revision = $this->pageRevision->where('slug', '=', $pageSlug)
 | 
					        $revision = $this->pageRevision->where('slug', '=', $pageSlug)
 | 
				
			||||||
 | 
					            ->whereHas('page', function($query) {
 | 
				
			||||||
 | 
					                $this->restrictionService->enforcePageRestrictions($query);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
            ->where('book_slug', '=', $bookSlug)->orderBy('created_at', 'desc')
 | 
					            ->where('book_slug', '=', $bookSlug)->orderBy('created_at', 'desc')
 | 
				
			||||||
            ->with('page')->first();
 | 
					            ->with('page')->first();
 | 
				
			||||||
        return $revision !== null ? $revision->page : null;
 | 
					        return $revision !== null ? $revision->page : null;
 | 
				
			||||||
@@ -211,7 +210,7 @@ class PageRepo
 | 
				
			|||||||
        if (!empty($term)) {
 | 
					        if (!empty($term)) {
 | 
				
			||||||
            $terms = array_merge($terms, explode(' ', $term));
 | 
					            $terms = array_merge($terms, explode(' ', $term));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        $pages = $this->page->fullTextSearchQuery(['name', 'text'], $terms, $whereTerms)
 | 
					        $pages = $this->restrictionService->enforcePageRestrictions($this->page->fullTextSearchQuery(['name', 'text'], $terms, $whereTerms))
 | 
				
			||||||
            ->paginate($count)->appends($paginationAppends);
 | 
					            ->paginate($count)->appends($paginationAppends);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // Add highlights to page text.
 | 
					        // Add highlights to page text.
 | 
				
			||||||
@@ -249,7 +248,7 @@ class PageRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function searchForImage($imageString)
 | 
					    public function searchForImage($imageString)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $pages = $this->page->where('html', 'like', '%' . $imageString . '%')->get();
 | 
					        $pages = $this->pageQuery()->where('html', 'like', '%' . $imageString . '%')->get();
 | 
				
			||||||
        foreach ($pages as $page) {
 | 
					        foreach ($pages as $page) {
 | 
				
			||||||
            $page->url = $page->getUrl();
 | 
					            $page->url = $page->getUrl();
 | 
				
			||||||
            $page->html = '';
 | 
					            $page->html = '';
 | 
				
			||||||
@@ -395,6 +394,7 @@ class PageRepo
 | 
				
			|||||||
        Activity::removeEntity($page);
 | 
					        Activity::removeEntity($page);
 | 
				
			||||||
        $page->views()->delete();
 | 
					        $page->views()->delete();
 | 
				
			||||||
        $page->revisions()->delete();
 | 
					        $page->revisions()->delete();
 | 
				
			||||||
 | 
					        $page->restrictions()->delete();
 | 
				
			||||||
        $page->delete();
 | 
					        $page->delete();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -404,7 +404,7 @@ class PageRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getRecentlyCreatedPaginated($count = 20)
 | 
					    public function getRecentlyCreatedPaginated($count = 20)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->page->orderBy('created_at', 'desc')->paginate($count);
 | 
					        return $this->pageQuery()->orderBy('created_at', 'desc')->paginate($count);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -413,7 +413,30 @@ class PageRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getRecentlyUpdatedPaginated($count = 20)
 | 
					    public function getRecentlyUpdatedPaginated($count = 20)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->page->orderBy('updated_at', 'desc')->paginate($count);
 | 
					        return $this->pageQuery()->orderBy('updated_at', 'desc')->paginate($count);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Updates pages restrictions from a request
 | 
				
			||||||
 | 
					     * @param $request
 | 
				
			||||||
 | 
					     * @param $page
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function updateRestrictionsFromRequest($request, $page)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO - extract into shared repo
 | 
				
			||||||
 | 
					        $page->restricted = $request->has('restricted') && $request->get('restricted') === 'true';
 | 
				
			||||||
 | 
					        $page->restrictions()->delete();
 | 
				
			||||||
 | 
					        if ($request->has('restrictions')) {
 | 
				
			||||||
 | 
					            foreach($request->get('restrictions') as $roleId => $restrictions) {
 | 
				
			||||||
 | 
					                foreach ($restrictions as $action => $value) {
 | 
				
			||||||
 | 
					                    $page->restrictions()->create([
 | 
				
			||||||
 | 
					                        'role_id' => $roleId,
 | 
				
			||||||
 | 
					                        'action'  => strtolower($action)
 | 
				
			||||||
 | 
					                    ]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $page->save();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										437
									
								
								app/Repos/PageRepo.php.orig
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										437
									
								
								app/Repos/PageRepo.php.orig
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,437 @@
 | 
				
			|||||||
 | 
					<?php namespace BookStack\Repos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Activity;
 | 
				
			||||||
 | 
					use BookStack\Book;
 | 
				
			||||||
 | 
					use BookStack\Chapter;
 | 
				
			||||||
 | 
					use BookStack\Exceptions\NotFoundException;
 | 
				
			||||||
 | 
					use BookStack\Services\RestrictionService;
 | 
				
			||||||
 | 
					use Illuminate\Http\Request;
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\Auth;
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\Log;
 | 
				
			||||||
 | 
					use Illuminate\Support\Str;
 | 
				
			||||||
 | 
					use BookStack\Page;
 | 
				
			||||||
 | 
					use BookStack\PageRevision;
 | 
				
			||||||
 | 
					use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PageRepo
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $page;
 | 
				
			||||||
 | 
					    protected $pageRevision;
 | 
				
			||||||
 | 
					    protected $restrictionService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * PageRepo constructor.
 | 
				
			||||||
 | 
					     * @param Page $page
 | 
				
			||||||
 | 
					     * @param PageRevision $pageRevision
 | 
				
			||||||
 | 
					     * @param RestrictionService $restrictionService
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(Page $page, PageRevision $pageRevision, RestrictionService $restrictionService)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->page = $page;
 | 
				
			||||||
 | 
					        $this->pageRevision = $pageRevision;
 | 
				
			||||||
 | 
					        $this->restrictionService = $restrictionService;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Base query for getting pages, Takes restrictions into account.
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function pageQuery()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->restrictionService->enforcePageRestrictions($this->page, 'view');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a page via a specific ID.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getById($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->pageQuery()->findOrFail($id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a page identified by the given slug.
 | 
				
			||||||
 | 
					     * @param $slug
 | 
				
			||||||
 | 
					     * @param $bookId
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     * @throws NotFoundException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getBySlug($slug, $bookId)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $page = $this->pageQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
 | 
				
			||||||
 | 
					        if ($page === null) throw new NotFoundException('Page not found');
 | 
				
			||||||
 | 
					        return $page;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Search through page revisions and retrieve
 | 
				
			||||||
 | 
					     * the last page in the current book that
 | 
				
			||||||
 | 
					     * has a slug equal to the one given.
 | 
				
			||||||
 | 
					     * @param $pageSlug
 | 
				
			||||||
 | 
					     * @param $bookSlug
 | 
				
			||||||
 | 
					     * @return null | Page
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function findPageUsingOldSlug($pageSlug, $bookSlug)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $revision = $this->pageRevision->where('slug', '=', $pageSlug)
 | 
				
			||||||
 | 
					            ->whereHas('page', function($query) {
 | 
				
			||||||
 | 
					                $this->restrictionService->enforcePageRestrictions($query);
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            ->where('book_slug', '=', $bookSlug)->orderBy('created_at', 'desc')
 | 
				
			||||||
 | 
					            ->with('page')->first();
 | 
				
			||||||
 | 
					        return $revision !== null ? $revision->page : null;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a new Page instance from the given input.
 | 
				
			||||||
 | 
					     * @param $input
 | 
				
			||||||
 | 
					     * @return Page
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function newFromInput($input)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $page = $this->page->fill($input);
 | 
				
			||||||
 | 
					        return $page;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Save a new page into the system.
 | 
				
			||||||
 | 
					     * Input validation must be done beforehand.
 | 
				
			||||||
 | 
					     * @param array $input
 | 
				
			||||||
 | 
					     * @param Book  $book
 | 
				
			||||||
 | 
					     * @param int   $chapterId
 | 
				
			||||||
 | 
					     * @return Page
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function saveNew(array $input, Book $book, $chapterId = null)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $page = $this->newFromInput($input);
 | 
				
			||||||
 | 
					        $page->slug = $this->findSuitableSlug($page->name, $book->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($chapterId) $page->chapter_id = $chapterId;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $page->html = $this->formatHtml($input['html']);
 | 
				
			||||||
 | 
					        $page->text = strip_tags($page->html);
 | 
				
			||||||
 | 
					        $page->created_by = auth()->user()->id;
 | 
				
			||||||
 | 
					        $page->updated_by = auth()->user()->id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $book->pages()->save($page);
 | 
				
			||||||
 | 
					        return $page;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Formats a page's html to be tagged correctly
 | 
				
			||||||
 | 
					     * within the system.
 | 
				
			||||||
 | 
					     * @param string $htmlText
 | 
				
			||||||
 | 
					     * @return string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected function formatHtml($htmlText)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if($htmlText == '') return $htmlText;
 | 
				
			||||||
 | 
					        libxml_use_internal_errors(true);
 | 
				
			||||||
 | 
					        $doc = new \DOMDocument();
 | 
				
			||||||
 | 
					        $doc->loadHTML(mb_convert_encoding($htmlText, 'HTML-ENTITIES', 'UTF-8'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $container = $doc->documentElement;
 | 
				
			||||||
 | 
					        $body = $container->childNodes->item(0);
 | 
				
			||||||
 | 
					        $childNodes = $body->childNodes;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Ensure no duplicate ids are used
 | 
				
			||||||
 | 
					        $idArray = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($childNodes as $index => $childNode) {
 | 
				
			||||||
 | 
					            /** @var \DOMElement $childNode */
 | 
				
			||||||
 | 
					            if (get_class($childNode) !== 'DOMElement') continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Overwrite id if not a BookStack custom id
 | 
				
			||||||
 | 
					            if ($childNode->hasAttribute('id')) {
 | 
				
			||||||
 | 
					                $id = $childNode->getAttribute('id');
 | 
				
			||||||
 | 
					                if (strpos($id, 'bkmrk') === 0 && array_search($id, $idArray) === false) {
 | 
				
			||||||
 | 
					                    $idArray[] = $id;
 | 
				
			||||||
 | 
					                    continue;
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Create an unique id for the element
 | 
				
			||||||
 | 
					            // Uses the content as a basis to ensure output is the same every time
 | 
				
			||||||
 | 
					            // the same content is passed through.
 | 
				
			||||||
 | 
					            $contentId = 'bkmrk-' . substr(strtolower(preg_replace('/\s+/', '-', trim($childNode->nodeValue))), 0, 20);
 | 
				
			||||||
 | 
					            $newId = urlencode($contentId);
 | 
				
			||||||
 | 
					            $loopIndex = 0;
 | 
				
			||||||
 | 
					            while (in_array($newId, $idArray)) {
 | 
				
			||||||
 | 
					                $newId = urlencode($contentId . '-' . $loopIndex);
 | 
				
			||||||
 | 
					                $loopIndex++;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $childNode->setAttribute('id', $newId);
 | 
				
			||||||
 | 
					            $idArray[] = $newId;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Generate inner html as a string
 | 
				
			||||||
 | 
					        $html = '';
 | 
				
			||||||
 | 
					        foreach ($childNodes as $childNode) {
 | 
				
			||||||
 | 
					            $html .= $doc->saveHTML($childNode);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $html;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets pages by a search term.
 | 
				
			||||||
 | 
					     * Highlights page content for showing in results.
 | 
				
			||||||
 | 
					     * @param string $term
 | 
				
			||||||
 | 
					     * @param array $whereTerms
 | 
				
			||||||
 | 
					     * @param int $count
 | 
				
			||||||
 | 
					     * @param array $paginationAppends
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getBySearch($term, $whereTerms = [], $count = 20, $paginationAppends = [])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					<<<<<<< HEAD
 | 
				
			||||||
 | 
					        preg_match_all('/"(.*?)"/', $term, $matches);
 | 
				
			||||||
 | 
					        if (count($matches[1]) > 0) {
 | 
				
			||||||
 | 
					            $terms = $matches[1];
 | 
				
			||||||
 | 
					            $term = trim(preg_replace('/"(.*?)"/', '', $term));
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            $terms = [];
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (!empty($term)) {
 | 
				
			||||||
 | 
					            $terms = array_merge($terms, explode(' ', $term));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $pages = $this->page->fullTextSearchQuery(['name', 'text'], $terms, $whereTerms)
 | 
				
			||||||
 | 
					=======
 | 
				
			||||||
 | 
					        $terms = explode(' ', $term);
 | 
				
			||||||
 | 
					        $pages = $this->restrictionService->enforcePageRestrictions($this->page->fullTextSearchQuery(['name', 'text'], $terms, $whereTerms))
 | 
				
			||||||
 | 
					>>>>>>> custom_role_system
 | 
				
			||||||
 | 
					            ->paginate($count)->appends($paginationAppends);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Add highlights to page text.
 | 
				
			||||||
 | 
					        $words = join('|', explode(' ', preg_quote(trim($term), '/')));
 | 
				
			||||||
 | 
					        //lookahead/behind assertions ensures cut between words
 | 
				
			||||||
 | 
					        $s = '\s\x00-/:-@\[-`{-~'; //character set for start/end of words
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($pages as $page) {
 | 
				
			||||||
 | 
					            preg_match_all('#(?<=[' . $s . ']).{1,30}((' . $words . ').{1,30})+(?=[' . $s . '])#uis', $page->text, $matches, PREG_SET_ORDER);
 | 
				
			||||||
 | 
					            //delimiter between occurrences
 | 
				
			||||||
 | 
					            $results = [];
 | 
				
			||||||
 | 
					            foreach ($matches as $line) {
 | 
				
			||||||
 | 
					                $results[] = htmlspecialchars($line[0], 0, 'UTF-8');
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $matchLimit = 6;
 | 
				
			||||||
 | 
					            if (count($results) > $matchLimit) {
 | 
				
			||||||
 | 
					                $results = array_slice($results, 0, $matchLimit);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $result = join('... ', $results);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            //highlight
 | 
				
			||||||
 | 
					            $result = preg_replace('#' . $words . '#iu', "<span class=\"highlight\">\$0</span>", $result);
 | 
				
			||||||
 | 
					            if (strlen($result) < 5) {
 | 
				
			||||||
 | 
					                $result = $page->getExcerpt(80);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            $page->searchSnippet = $result;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $pages;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Search for image usage.
 | 
				
			||||||
 | 
					     * @param $imageString
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function searchForImage($imageString)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $pages = $this->pageQuery()->where('html', 'like', '%' . $imageString . '%')->get();
 | 
				
			||||||
 | 
					        foreach ($pages as $page) {
 | 
				
			||||||
 | 
					            $page->url = $page->getUrl();
 | 
				
			||||||
 | 
					            $page->html = '';
 | 
				
			||||||
 | 
					            $page->text = '';
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return count($pages) > 0 ? $pages : false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Updates a page with any fillable data and saves it into the database.
 | 
				
			||||||
 | 
					     * @param Page   $page
 | 
				
			||||||
 | 
					     * @param int    $book_id
 | 
				
			||||||
 | 
					     * @param string $input
 | 
				
			||||||
 | 
					     * @return Page
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function updatePage(Page $page, $book_id, $input)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Save a revision before updating
 | 
				
			||||||
 | 
					        if ($page->html !== $input['html'] || $page->name !== $input['name']) {
 | 
				
			||||||
 | 
					            $this->saveRevision($page);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Prevent slug being updated if no name change
 | 
				
			||||||
 | 
					        if ($page->name !== $input['name']) {
 | 
				
			||||||
 | 
					            $page->slug = $this->findSuitableSlug($input['name'], $book_id, $page->id);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Update with new details
 | 
				
			||||||
 | 
					        $page->fill($input);
 | 
				
			||||||
 | 
					        $page->html = $this->formatHtml($input['html']);
 | 
				
			||||||
 | 
					        $page->text = strip_tags($page->html);
 | 
				
			||||||
 | 
					        $page->updated_by = auth()->user()->id;
 | 
				
			||||||
 | 
					        $page->save();
 | 
				
			||||||
 | 
					        return $page;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Restores a revision's content back into a page.
 | 
				
			||||||
 | 
					     * @param Page $page
 | 
				
			||||||
 | 
					     * @param Book $book
 | 
				
			||||||
 | 
					     * @param  int $revisionId
 | 
				
			||||||
 | 
					     * @return Page
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function restoreRevision(Page $page, Book $book, $revisionId)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->saveRevision($page);
 | 
				
			||||||
 | 
					        $revision = $this->getRevisionById($revisionId);
 | 
				
			||||||
 | 
					        $page->fill($revision->toArray());
 | 
				
			||||||
 | 
					        $page->slug = $this->findSuitableSlug($page->name, $book->id, $page->id);
 | 
				
			||||||
 | 
					        $page->text = strip_tags($page->html);
 | 
				
			||||||
 | 
					        $page->updated_by = auth()->user()->id;
 | 
				
			||||||
 | 
					        $page->save();
 | 
				
			||||||
 | 
					        return $page;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Saves a page revision into the system.
 | 
				
			||||||
 | 
					     * @param Page $page
 | 
				
			||||||
 | 
					     * @return $this
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function saveRevision(Page $page)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $revision = $this->pageRevision->fill($page->toArray());
 | 
				
			||||||
 | 
					        $revision->page_id = $page->id;
 | 
				
			||||||
 | 
					        $revision->slug = $page->slug;
 | 
				
			||||||
 | 
					        $revision->book_slug = $page->book->slug;
 | 
				
			||||||
 | 
					        $revision->created_by = auth()->user()->id;
 | 
				
			||||||
 | 
					        $revision->created_at = $page->updated_at;
 | 
				
			||||||
 | 
					        $revision->save();
 | 
				
			||||||
 | 
					        // Clear old revisions
 | 
				
			||||||
 | 
					        if ($this->pageRevision->where('page_id', '=', $page->id)->count() > 50) {
 | 
				
			||||||
 | 
					            $this->pageRevision->where('page_id', '=', $page->id)
 | 
				
			||||||
 | 
					                ->orderBy('created_at', 'desc')->skip(50)->take(5)->delete();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $revision;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets a single revision via it's id.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getRevisionById($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->pageRevision->findOrFail($id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks if a slug exists within a book already.
 | 
				
			||||||
 | 
					     * @param            $slug
 | 
				
			||||||
 | 
					     * @param            $bookId
 | 
				
			||||||
 | 
					     * @param bool|false $currentId
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function doesSlugExist($slug, $bookId, $currentId = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $query = $this->page->where('slug', '=', $slug)->where('book_id', '=', $bookId);
 | 
				
			||||||
 | 
					        if ($currentId) $query = $query->where('id', '!=', $currentId);
 | 
				
			||||||
 | 
					        return $query->count() > 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Changes the related book for the specified page.
 | 
				
			||||||
 | 
					     * Changes the book id of any relations to the page that store the book id.
 | 
				
			||||||
 | 
					     * @param int  $bookId
 | 
				
			||||||
 | 
					     * @param Page $page
 | 
				
			||||||
 | 
					     * @return Page
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function changeBook($bookId, Page $page)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $page->book_id = $bookId;
 | 
				
			||||||
 | 
					        foreach ($page->activity as $activity) {
 | 
				
			||||||
 | 
					            $activity->book_id = $bookId;
 | 
				
			||||||
 | 
					            $activity->save();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $page->slug = $this->findSuitableSlug($page->name, $bookId, $page->id);
 | 
				
			||||||
 | 
					        $page->save();
 | 
				
			||||||
 | 
					        return $page;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets a suitable slug for the resource
 | 
				
			||||||
 | 
					     * @param            $name
 | 
				
			||||||
 | 
					     * @param            $bookId
 | 
				
			||||||
 | 
					     * @param bool|false $currentId
 | 
				
			||||||
 | 
					     * @return string
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function findSuitableSlug($name, $bookId, $currentId = false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $slug = Str::slug($name);
 | 
				
			||||||
 | 
					        while ($this->doesSlugExist($slug, $bookId, $currentId)) {
 | 
				
			||||||
 | 
					            $slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return $slug;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Destroy a given page along with its dependencies.
 | 
				
			||||||
 | 
					     * @param $page
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function destroy($page)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Activity::removeEntity($page);
 | 
				
			||||||
 | 
					        $page->views()->delete();
 | 
				
			||||||
 | 
					        $page->revisions()->delete();
 | 
				
			||||||
 | 
					        $page->restrictions()->delete();
 | 
				
			||||||
 | 
					        $page->delete();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the latest pages added to the system.
 | 
				
			||||||
 | 
					     * @param $count
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getRecentlyCreatedPaginated($count = 20)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->pageQuery()->orderBy('created_at', 'desc')->paginate($count);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get the latest pages added to the system.
 | 
				
			||||||
 | 
					     * @param $count
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getRecentlyUpdatedPaginated($count = 20)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->pageQuery()->orderBy('updated_at', 'desc')->paginate($count);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Updates pages restrictions from a request
 | 
				
			||||||
 | 
					     * @param $request
 | 
				
			||||||
 | 
					     * @param $page
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function updateRestrictionsFromRequest($request, $page)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // TODO - extract into shared repo
 | 
				
			||||||
 | 
					        $page->restricted = $request->has('restricted') && $request->get('restricted') === 'true';
 | 
				
			||||||
 | 
					        $page->restrictions()->delete();
 | 
				
			||||||
 | 
					        if ($request->has('restrictions')) {
 | 
				
			||||||
 | 
					            foreach($request->get('restrictions') as $roleId => $restrictions) {
 | 
				
			||||||
 | 
					                foreach ($restrictions as $action => $value) {
 | 
				
			||||||
 | 
					                    $page->restrictions()->create([
 | 
				
			||||||
 | 
					                        'role_id' => $roleId,
 | 
				
			||||||
 | 
					                        'action'  => strtolower($action)
 | 
				
			||||||
 | 
					                    ]);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $page->save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										142
									
								
								app/Repos/PermissionsRepo.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								app/Repos/PermissionsRepo.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,142 @@
 | 
				
			|||||||
 | 
					<?php namespace BookStack\Repos;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use BookStack\Exceptions\PermissionsException;
 | 
				
			||||||
 | 
					use BookStack\Permission;
 | 
				
			||||||
 | 
					use BookStack\Role;
 | 
				
			||||||
 | 
					use Setting;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PermissionsRepo
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $permission;
 | 
				
			||||||
 | 
					    protected $role;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * PermissionsRepo constructor.
 | 
				
			||||||
 | 
					     * @param $permission
 | 
				
			||||||
 | 
					     * @param $role
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct(Permission $permission, Role $role)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->permission = $permission;
 | 
				
			||||||
 | 
					        $this->role = $role;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get all the user roles from the system.
 | 
				
			||||||
 | 
					     * @return \Illuminate\Database\Eloquent\Collection|static[]
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getAllRoles()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->role->all();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get all the roles except for the provided one.
 | 
				
			||||||
 | 
					     * @param Role $role
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getAllRolesExcept(Role $role)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->role->where('id', '!=', $role->id)->get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get a role via its ID.
 | 
				
			||||||
 | 
					     * @param $id
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getRoleById($id)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->role->findOrFail($id);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Save a new role into the system.
 | 
				
			||||||
 | 
					     * @param array $roleData
 | 
				
			||||||
 | 
					     * @return Role
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function saveNewRole($roleData)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $role = $this->role->newInstance($roleData);
 | 
				
			||||||
 | 
					        $role->name = str_replace(' ', '-', strtolower($roleData['display_name']));
 | 
				
			||||||
 | 
					        // Prevent duplicate names
 | 
				
			||||||
 | 
					        while ($this->role->where('name', '=', $role->name)->count() > 0) {
 | 
				
			||||||
 | 
					            $role->name .= strtolower(str_random(2));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $role->save();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : [];
 | 
				
			||||||
 | 
					        $this->assignRolePermissions($role, $permissions);
 | 
				
			||||||
 | 
					        return $role;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Updates an existing role.
 | 
				
			||||||
 | 
					     * Ensure Admin role always has all permissions.
 | 
				
			||||||
 | 
					     * @param $roleId
 | 
				
			||||||
 | 
					     * @param $roleData
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function updateRole($roleId, $roleData)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $role = $this->role->findOrFail($roleId);
 | 
				
			||||||
 | 
					        $permissions = isset($roleData['permissions']) ? array_keys($roleData['permissions']) : [];
 | 
				
			||||||
 | 
					        $this->assignRolePermissions($role, $permissions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($role->name === 'admin') {
 | 
				
			||||||
 | 
					            $permissions = $this->permission->all()->pluck('id')->toArray();
 | 
				
			||||||
 | 
					            $role->permissions()->sync($permissions);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $role->fill($roleData);
 | 
				
			||||||
 | 
					        $role->save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Assign an list of permission names to an role.
 | 
				
			||||||
 | 
					     * @param Role $role
 | 
				
			||||||
 | 
					     * @param array $permissionNameArray
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function assignRolePermissions(Role $role, $permissionNameArray = [])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $permissions = [];
 | 
				
			||||||
 | 
					        $permissionNameArray = array_values($permissionNameArray);
 | 
				
			||||||
 | 
					        if ($permissionNameArray && count($permissionNameArray) > 0) {
 | 
				
			||||||
 | 
					            $permissions = $this->permission->whereIn('name', $permissionNameArray)->pluck('id')->toArray();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $role->permissions()->sync($permissions);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Delete a role from the system.
 | 
				
			||||||
 | 
					     * Check it's not an admin role or set as default before deleting.
 | 
				
			||||||
 | 
					     * If an migration Role ID is specified the users assign to the current role
 | 
				
			||||||
 | 
					     * will be added to the role of the specified id.
 | 
				
			||||||
 | 
					     * @param $roleId
 | 
				
			||||||
 | 
					     * @param $migrateRoleId
 | 
				
			||||||
 | 
					     * @throws PermissionsException
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function deleteRole($roleId, $migrateRoleId)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $role = $this->role->findOrFail($roleId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Prevent deleting admin role or default registration role.
 | 
				
			||||||
 | 
					        if ($role->name === 'admin') {
 | 
				
			||||||
 | 
					            throw new PermissionsException('The admin role cannot be deleted');
 | 
				
			||||||
 | 
					        } else if ($role->id == Setting::get('registration-role')) {
 | 
				
			||||||
 | 
					            throw new PermissionsException('This role cannot be deleted while set as the default registration role.');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if ($migrateRoleId) {
 | 
				
			||||||
 | 
					            $newRole = $this->role->find($migrateRoleId);
 | 
				
			||||||
 | 
					            if ($newRole) {
 | 
				
			||||||
 | 
					                $users = $role->users->pluck('id')->toArray();
 | 
				
			||||||
 | 
					                $newRole->users()->sync($users);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $role->delete();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -42,6 +42,15 @@ class UserRepo
 | 
				
			|||||||
        return $this->user->findOrFail($id);
 | 
					        return $this->user->findOrFail($id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get all the users with their permissions.
 | 
				
			||||||
 | 
					     * @return \Illuminate\Database\Eloquent\Builder|static
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getAllUsers()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->user->with('roles', 'avatar')->orderBy('name', 'asc')->get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Creates a new user and attaches a role to them.
 | 
					     * Creates a new user and attaches a role to them.
 | 
				
			||||||
     * @param array $data
 | 
					     * @param array $data
 | 
				
			||||||
@@ -69,7 +78,7 @@ class UserRepo
 | 
				
			|||||||
    public function attachDefaultRole($user)
 | 
					    public function attachDefaultRole($user)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $roleId = Setting::get('registration-role');
 | 
					        $roleId = Setting::get('registration-role');
 | 
				
			||||||
        if ($roleId === false) $roleId = $this->role->getDefault()->id;
 | 
					        if ($roleId === false) $roleId = $this->role->first()->id;
 | 
				
			||||||
        $user->attachRoleId($roleId);
 | 
					        $user->attachRoleId($roleId);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -80,15 +89,10 @@ class UserRepo
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function isOnlyAdmin(User $user)
 | 
					    public function isOnlyAdmin(User $user)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ($user->role->name != 'admin') {
 | 
					        if (!$user->roles->pluck('name')->contains('admin')) return false;
 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        $adminRole = $this->role->where('name', '=', 'admin')->first();
 | 
					 | 
				
			||||||
        if (count($adminRole->users) > 1) {
 | 
					 | 
				
			||||||
            return false;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $adminRole = $this->role->getRole('admin');
 | 
				
			||||||
 | 
					        if ($adminRole->users->count() > 1) return false;
 | 
				
			||||||
        return true;
 | 
					        return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -160,4 +164,14 @@ class UserRepo
 | 
				
			|||||||
        ];
 | 
					        ];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get all the roles which can be given restricted access to
 | 
				
			||||||
 | 
					     * other entities in the system.
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function getRestrictableRoles()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->role->where('name', '!=', 'admin')->get();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								app/Restriction.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								app/Restriction.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace BookStack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Database\Eloquent\Model;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Restriction extends Model
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $fillable = ['role_id', 'action'];
 | 
				
			||||||
 | 
					    public $timestamps = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Get all this restriction's attached entity.
 | 
				
			||||||
 | 
					     * @return \Illuminate\Database\Eloquent\Relations\MorphTo
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function restrictable()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->morphTo();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								app/Role.php
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								app/Role.php
									
									
									
									
									
								
							@@ -6,11 +6,8 @@ use Illuminate\Database\Eloquent\Model;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class Role extends Model
 | 
					class Role extends Model
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    /**
 | 
					
 | 
				
			||||||
     * Sets the default role name for newly registered users.
 | 
					    protected $fillable = ['display_name', 'description'];
 | 
				
			||||||
     * @var string
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    protected static $default = 'viewer';
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The roles that belong to the role.
 | 
					     * The roles that belong to the role.
 | 
				
			||||||
@@ -28,6 +25,15 @@ class Role extends Model
 | 
				
			|||||||
        return $this->belongsToMany('BookStack\Permission');
 | 
					        return $this->belongsToMany('BookStack\Permission');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if this role has a permission.
 | 
				
			||||||
 | 
					     * @param $permission
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function hasPermission($permission)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $this->permissions->pluck('name')->contains($permission);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Add a permission to this role.
 | 
					     * Add a permission to this role.
 | 
				
			||||||
     * @param Permission $permission
 | 
					     * @param Permission $permission
 | 
				
			||||||
@@ -37,15 +43,6 @@ class Role extends Model
 | 
				
			|||||||
        $this->permissions()->attach($permission->id);
 | 
					        $this->permissions()->attach($permission->id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Get an instance of the default role.
 | 
					 | 
				
			||||||
     * @return Role
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    public static function getDefault()
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return static::getRole(static::$default);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get the role object for the specified role.
 | 
					     * Get the role object for the specified role.
 | 
				
			||||||
     * @param $roleName
 | 
					     * @param $roleName
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,14 +9,17 @@ class ActivityService
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    protected $activity;
 | 
					    protected $activity;
 | 
				
			||||||
    protected $user;
 | 
					    protected $user;
 | 
				
			||||||
 | 
					    protected $restrictionService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * ActivityService constructor.
 | 
					     * ActivityService constructor.
 | 
				
			||||||
     * @param $activity
 | 
					     * @param Activity $activity
 | 
				
			||||||
 | 
					     * @param RestrictionService $restrictionService
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(Activity $activity)
 | 
					    public function __construct(Activity $activity, RestrictionService $restrictionService)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->activity = $activity;
 | 
					        $this->activity = $activity;
 | 
				
			||||||
 | 
					        $this->restrictionService = $restrictionService;
 | 
				
			||||||
        $this->user = auth()->user();
 | 
					        $this->user = auth()->user();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -86,8 +89,10 @@ class ActivityService
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function latest($count = 20, $page = 0)
 | 
					    public function latest($count = 20, $page = 0)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $activityList =  $this->activity->orderBy('created_at', 'desc')
 | 
					        $activityList =  $this->restrictionService
 | 
				
			||||||
            ->skip($count * $page)->take($count)->get();
 | 
					            ->filterRestrictedEntityRelations($this->activity, 'activities', 'entity_id', 'entity_type')
 | 
				
			||||||
 | 
					            ->orderBy('created_at', 'desc')->skip($count * $page)->take($count)->get();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return $this->filterSimilar($activityList);
 | 
					        return $this->filterSimilar($activityList);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										272
									
								
								app/Services/RestrictionService.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								app/Services/RestrictionService.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,272 @@
 | 
				
			|||||||
 | 
					<?php namespace BookStack\Services;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use BookStack\Entity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RestrictionService
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $userRoles;
 | 
				
			||||||
 | 
					    protected $isAdmin;
 | 
				
			||||||
 | 
					    protected $currentAction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * RestrictionService constructor.
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function __construct()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $user = auth()->user();
 | 
				
			||||||
 | 
					        $this->userRoles = $user ? auth()->user()->roles->pluck('id') : [];
 | 
				
			||||||
 | 
					        $this->isAdmin = $user ? auth()->user()->hasRole('admin') : false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Checks if an entity has a restriction set upon it.
 | 
				
			||||||
 | 
					     * @param Entity $entity
 | 
				
			||||||
 | 
					     * @param $action
 | 
				
			||||||
 | 
					     * @return bool
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function checkIfEntityRestricted(Entity $entity, $action)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->isAdmin) return true;
 | 
				
			||||||
 | 
					        $this->currentAction = $action;
 | 
				
			||||||
 | 
					        $baseQuery = $entity->where('id', '=', $entity->id);
 | 
				
			||||||
 | 
					        if ($entity->isA('page')) {
 | 
				
			||||||
 | 
					            return $this->pageRestrictionQuery($baseQuery)->count() > 0;
 | 
				
			||||||
 | 
					        } elseif ($entity->isA('chapter')) {
 | 
				
			||||||
 | 
					            return $this->chapterRestrictionQuery($baseQuery)->count() > 0;
 | 
				
			||||||
 | 
					        } elseif ($entity->isA('book')) {
 | 
				
			||||||
 | 
					            return $this->bookRestrictionQuery($baseQuery)->count() > 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add restrictions for a page query
 | 
				
			||||||
 | 
					     * @param $query
 | 
				
			||||||
 | 
					     * @param string $action
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function enforcePageRestrictions($query, $action = 'view')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->isAdmin) return $query;
 | 
				
			||||||
 | 
					        $this->currentAction = $action;
 | 
				
			||||||
 | 
					        return $this->pageRestrictionQuery($query);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The base query for restricting pages.
 | 
				
			||||||
 | 
					     * @param $query
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function pageRestrictionQuery($query)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $query->where(function ($parentWhereQuery) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $parentWhereQuery
 | 
				
			||||||
 | 
					                // (Book & chapter & page) or (Book & page & NO CHAPTER) unrestricted
 | 
				
			||||||
 | 
					                ->where(function ($query) {
 | 
				
			||||||
 | 
					                    $query->where(function ($query) {
 | 
				
			||||||
 | 
					                        $query->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                            $query->select('*')->from('chapters')
 | 
				
			||||||
 | 
					                                ->whereRaw('chapters.id=pages.chapter_id')
 | 
				
			||||||
 | 
					                                ->where('restricted', '=', false);
 | 
				
			||||||
 | 
					                        })->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                            $query->select('*')->from('books')
 | 
				
			||||||
 | 
					                                ->whereRaw('books.id=pages.book_id')
 | 
				
			||||||
 | 
					                                ->where('restricted', '=', false);
 | 
				
			||||||
 | 
					                        })->where('restricted', '=', false);
 | 
				
			||||||
 | 
					                    })->orWhere(function ($query) {
 | 
				
			||||||
 | 
					                        $query->where('restricted', '=', false)->where('chapter_id', '=', 0)
 | 
				
			||||||
 | 
					                            ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                                $query->select('*')->from('books')
 | 
				
			||||||
 | 
					                                    ->whereRaw('books.id=pages.book_id')
 | 
				
			||||||
 | 
					                                    ->where('restricted', '=', false);
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                // Page unrestricted, Has no chapter & book has accepted restrictions
 | 
				
			||||||
 | 
					                ->orWhere(function ($query) {
 | 
				
			||||||
 | 
					                    $query->where('restricted', '=', false)
 | 
				
			||||||
 | 
					                        ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                            $query->select('*')->from('chapters')
 | 
				
			||||||
 | 
					                                ->whereRaw('chapters.id=pages.chapter_id');
 | 
				
			||||||
 | 
					                        }, 'and', true)
 | 
				
			||||||
 | 
					                        ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                            $query->select('*')->from('books')
 | 
				
			||||||
 | 
					                                ->whereRaw('books.id=pages.book_id')
 | 
				
			||||||
 | 
					                                ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                                    $this->checkRestrictionsQuery($query, 'books', 'Book');
 | 
				
			||||||
 | 
					                                });
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                // Page unrestricted, Has an unrestricted chapter & book has accepted restrictions
 | 
				
			||||||
 | 
					                ->orWhere(function ($query) {
 | 
				
			||||||
 | 
					                    $query->where('restricted', '=', false)
 | 
				
			||||||
 | 
					                        ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                            $query->select('*')->from('chapters')
 | 
				
			||||||
 | 
					                                ->whereRaw('chapters.id=pages.chapter_id')->where('restricted', '=', false);
 | 
				
			||||||
 | 
					                        })
 | 
				
			||||||
 | 
					                        ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                            $query->select('*')->from('books')
 | 
				
			||||||
 | 
					                                ->whereRaw('books.id=pages.book_id')
 | 
				
			||||||
 | 
					                                ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                                    $this->checkRestrictionsQuery($query, 'books', 'Book');
 | 
				
			||||||
 | 
					                                });
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                // Page unrestricted, Has a chapter with accepted permissions
 | 
				
			||||||
 | 
					                ->orWhere(function ($query) {
 | 
				
			||||||
 | 
					                    $query->where('restricted', '=', false)
 | 
				
			||||||
 | 
					                        ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                            $query->select('*')->from('chapters')
 | 
				
			||||||
 | 
					                                ->whereRaw('chapters.id=pages.chapter_id')
 | 
				
			||||||
 | 
					                                ->where('restricted', '=', true)
 | 
				
			||||||
 | 
					                                ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                                    $this->checkRestrictionsQuery($query, 'chapters', 'Chapter');
 | 
				
			||||||
 | 
					                                });
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                // Page has accepted permissions
 | 
				
			||||||
 | 
					                ->orWhereExists(function ($query) {
 | 
				
			||||||
 | 
					                    $this->checkRestrictionsQuery($query, 'pages', 'Page');
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add on permission restrictions to a chapter query.
 | 
				
			||||||
 | 
					     * @param $query
 | 
				
			||||||
 | 
					     * @param string $action
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function enforceChapterRestrictions($query, $action = 'view')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->isAdmin) return $query;
 | 
				
			||||||
 | 
					        $this->currentAction = $action;
 | 
				
			||||||
 | 
					        return $this->chapterRestrictionQuery($query);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The base query for restricting chapters.
 | 
				
			||||||
 | 
					     * @param $query
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function chapterRestrictionQuery($query)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $query->where(function ($parentWhereQuery) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            $parentWhereQuery
 | 
				
			||||||
 | 
					                // Book & chapter unrestricted
 | 
				
			||||||
 | 
					                ->where(function ($query) {
 | 
				
			||||||
 | 
					                    $query->where('restricted', '=', false)->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                        $query->select('*')->from('books')
 | 
				
			||||||
 | 
					                            ->whereRaw('books.id=chapters.book_id')
 | 
				
			||||||
 | 
					                            ->where('restricted', '=', false);
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                // Chapter unrestricted & book has accepted restrictions
 | 
				
			||||||
 | 
					                ->orWhere(function ($query) {
 | 
				
			||||||
 | 
					                    $query->where('restricted', '=', false)
 | 
				
			||||||
 | 
					                        ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                            $query->select('*')->from('books')
 | 
				
			||||||
 | 
					                                ->whereRaw('books.id=chapters.book_id')
 | 
				
			||||||
 | 
					                                ->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                                    $this->checkRestrictionsQuery($query, 'books', 'Book');
 | 
				
			||||||
 | 
					                                });
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                // Chapter has accepted permissions
 | 
				
			||||||
 | 
					                ->orWhereExists(function ($query) {
 | 
				
			||||||
 | 
					                    $this->checkRestrictionsQuery($query, 'chapters', 'Chapter');
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Add restrictions to a book query.
 | 
				
			||||||
 | 
					     * @param $query
 | 
				
			||||||
 | 
					     * @param string $action
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function enforceBookRestrictions($query, $action = 'view')
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->isAdmin) return $query;
 | 
				
			||||||
 | 
					        $this->currentAction = $action;
 | 
				
			||||||
 | 
					        return $this->bookRestrictionQuery($query);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The base query for restricting books.
 | 
				
			||||||
 | 
					     * @param $query
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function bookRestrictionQuery($query)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return $query->where(function ($parentWhereQuery) {
 | 
				
			||||||
 | 
					            $parentWhereQuery
 | 
				
			||||||
 | 
					                ->where('restricted', '=', false)
 | 
				
			||||||
 | 
					                ->orWhere(function ($query) {
 | 
				
			||||||
 | 
					                    $query->where('restricted', '=', true)->whereExists(function ($query) {
 | 
				
			||||||
 | 
					                        $this->checkRestrictionsQuery($query, 'books', 'Book');
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Filter items that have entities set a a polymorphic relation.
 | 
				
			||||||
 | 
					     * @param $query
 | 
				
			||||||
 | 
					     * @param string $tableName
 | 
				
			||||||
 | 
					     * @param string $entityIdColumn
 | 
				
			||||||
 | 
					     * @param string $entityTypeColumn
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function filterRestrictedEntityRelations($query, $tableName, $entityIdColumn, $entityTypeColumn)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        if ($this->isAdmin) return $query;
 | 
				
			||||||
 | 
					        $this->currentAction = 'view';
 | 
				
			||||||
 | 
					        $tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn, 'entityTypeColumn' => $entityTypeColumn];
 | 
				
			||||||
 | 
					        return $query->where(function ($query) use ($tableDetails) {
 | 
				
			||||||
 | 
					            $query->where(function ($query) use (&$tableDetails) {
 | 
				
			||||||
 | 
					                $query->where($tableDetails['entityTypeColumn'], '=', 'BookStack\Page')
 | 
				
			||||||
 | 
					                    ->whereExists(function ($query) use (&$tableDetails) {
 | 
				
			||||||
 | 
					                        $query->select('*')->from('pages')->whereRaw('pages.id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
 | 
				
			||||||
 | 
					                            ->where(function ($query) {
 | 
				
			||||||
 | 
					                                $this->pageRestrictionQuery($query);
 | 
				
			||||||
 | 
					                            });
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					            })->orWhere(function ($query) use (&$tableDetails) {
 | 
				
			||||||
 | 
					                $query->where($tableDetails['entityTypeColumn'], '=', 'BookStack\Book')->whereExists(function ($query) use (&$tableDetails) {
 | 
				
			||||||
 | 
					                    $query->select('*')->from('books')->whereRaw('books.id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
 | 
				
			||||||
 | 
					                        ->where(function ($query) {
 | 
				
			||||||
 | 
					                            $this->bookRestrictionQuery($query);
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            })->orWhere(function ($query) use (&$tableDetails) {
 | 
				
			||||||
 | 
					                $query->where($tableDetails['entityTypeColumn'], '=', 'BookStack\Chapter')->whereExists(function ($query) use (&$tableDetails) {
 | 
				
			||||||
 | 
					                    $query->select('*')->from('chapters')->whereRaw('chapters.id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
 | 
				
			||||||
 | 
					                        ->where(function ($query) {
 | 
				
			||||||
 | 
					                            $this->chapterRestrictionQuery($query);
 | 
				
			||||||
 | 
					                        });
 | 
				
			||||||
 | 
					                });
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The query to check the restrictions on an entity.
 | 
				
			||||||
 | 
					     * @param $query
 | 
				
			||||||
 | 
					     * @param $tableName
 | 
				
			||||||
 | 
					     * @param $modelName
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function checkRestrictionsQuery($query, $tableName, $modelName)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $query->select('*')->from('restrictions')
 | 
				
			||||||
 | 
					            ->whereRaw('restrictions.restrictable_id=' . $tableName . '.id')
 | 
				
			||||||
 | 
					            ->where('restrictions.restrictable_type', '=', 'BookStack\\' . $modelName)
 | 
				
			||||||
 | 
					            ->where('restrictions.action', '=', $this->currentAction)
 | 
				
			||||||
 | 
					            ->whereIn('restrictions.role_id', $this->userRoles);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -9,15 +9,18 @@ class ViewService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    protected $view;
 | 
					    protected $view;
 | 
				
			||||||
    protected $user;
 | 
					    protected $user;
 | 
				
			||||||
 | 
					    protected $restrictionService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * ViewService constructor.
 | 
					     * ViewService constructor.
 | 
				
			||||||
     * @param $view
 | 
					     * @param View $view
 | 
				
			||||||
 | 
					     * @param RestrictionService $restrictionService
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function __construct(View $view)
 | 
					    public function __construct(View $view, RestrictionService $restrictionService)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->view = $view;
 | 
					        $this->view = $view;
 | 
				
			||||||
        $this->user = auth()->user();
 | 
					        $this->user = auth()->user();
 | 
				
			||||||
 | 
					        $this->restrictionService = $restrictionService;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -27,7 +30,7 @@ class ViewService
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function add(Entity $entity)
 | 
					    public function add(Entity $entity)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if($this->user === null) return 0;
 | 
					        if ($this->user === null) return 0;
 | 
				
			||||||
        $view = $entity->views()->where('user_id', '=', $this->user->id)->first();
 | 
					        $view = $entity->views()->where('user_id', '=', $this->user->id)->first();
 | 
				
			||||||
        // Add view if model exists
 | 
					        // Add view if model exists
 | 
				
			||||||
        if ($view) {
 | 
					        if ($view) {
 | 
				
			||||||
@@ -47,18 +50,19 @@ class ViewService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get the entities with the most views.
 | 
					     * Get the entities with the most views.
 | 
				
			||||||
     * @param int        $count
 | 
					     * @param int $count
 | 
				
			||||||
     * @param int        $page
 | 
					     * @param int $page
 | 
				
			||||||
     * @param bool|false $filterModel
 | 
					     * @param bool|false $filterModel
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getPopular($count = 10, $page = 0, $filterModel = false)
 | 
					    public function getPopular($count = 10, $page = 0, $filterModel = false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $skipCount = $count * $page;
 | 
					        $skipCount = $count * $page;
 | 
				
			||||||
        $query = $this->view->select('id', 'viewable_id', 'viewable_type', \DB::raw('SUM(views) as view_count'))
 | 
					        $query = $this->restrictionService->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type')
 | 
				
			||||||
 | 
					            ->select('id', 'viewable_id', 'viewable_type', \DB::raw('SUM(views) as view_count'))
 | 
				
			||||||
            ->groupBy('viewable_id', 'viewable_type')
 | 
					            ->groupBy('viewable_id', 'viewable_type')
 | 
				
			||||||
            ->orderBy('view_count', 'desc');
 | 
					            ->orderBy('view_count', 'desc');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if($filterModel) $query->where('viewable_type', '=', get_class($filterModel));
 | 
					        if ($filterModel) $query->where('viewable_type', '=', get_class($filterModel));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $views = $query->with('viewable')->skip($skipCount)->take($count)->get();
 | 
					        $views = $query->with('viewable')->skip($skipCount)->take($count)->get();
 | 
				
			||||||
        $viewedEntities = $views->map(function ($item) {
 | 
					        $viewedEntities = $views->map(function ($item) {
 | 
				
			||||||
@@ -69,22 +73,24 @@ class ViewService
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get all recently viewed entities for the current user.
 | 
					     * Get all recently viewed entities for the current user.
 | 
				
			||||||
     * @param int         $count
 | 
					     * @param int $count
 | 
				
			||||||
     * @param int         $page
 | 
					     * @param int $page
 | 
				
			||||||
     * @param Entity|bool $filterModel
 | 
					     * @param Entity|bool $filterModel
 | 
				
			||||||
     * @return mixed
 | 
					     * @return mixed
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false)
 | 
					    public function getUserRecentlyViewed($count = 10, $page = 0, $filterModel = false)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if($this->user === null) return collect();
 | 
					        if ($this->user === null) return collect();
 | 
				
			||||||
        $skipCount = $count * $page;
 | 
					        $skipCount = $count * $page;
 | 
				
			||||||
        $query = $this->view->where('user_id', '=', auth()->user()->id);
 | 
					        $query = $this->restrictionService
 | 
				
			||||||
 | 
					            ->filterRestrictedEntityRelations($this->view, 'views', 'viewable_id', 'viewable_type');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if ($filterModel) $query->where('viewable_type', '=', get_class($filterModel));
 | 
					        if ($filterModel) $query = $query->where('viewable_type', '=', get_class($filterModel));
 | 
				
			||||||
 | 
					        $query = $query->where('user_id', '=', auth()->user()->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        $views = $query->with('viewable')->orderBy('updated_at', 'desc')->skip($skipCount)->take($count)->get();
 | 
					        $views = $query->with('viewable')->orderBy('updated_at', 'desc')->skip($skipCount)->take($count)->get();
 | 
				
			||||||
        $viewedEntities = $views->map(function ($item) {
 | 
					        $viewedEntities = $views->map(function ($item) {
 | 
				
			||||||
            return $item->viewable()->getResults();
 | 
					            return $item->viewable;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
        return $viewedEntities;
 | 
					        return $viewedEntities;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										44
									
								
								app/User.php
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								app/User.php
									
									
									
									
									
								
							@@ -14,21 +14,18 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The database table used by the model.
 | 
					     * The database table used by the model.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @var string
 | 
					     * @var string
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected $table = 'users';
 | 
					    protected $table = 'users';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The attributes that are mass assignable.
 | 
					     * The attributes that are mass assignable.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @var array
 | 
					     * @var array
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected $fillable = ['name', 'email', 'image_id'];
 | 
					    protected $fillable = ['name', 'email', 'image_id'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The attributes excluded from the model's JSON form.
 | 
					     * The attributes excluded from the model's JSON form.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @var array
 | 
					     * @var array
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    protected $hidden = ['password', 'remember_token'];
 | 
					    protected $hidden = ['password', 'remember_token'];
 | 
				
			||||||
@@ -50,10 +47,6 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
 | 
				
			|||||||
        ]);
 | 
					        ]);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Permissions and roles
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The roles that belong to the user.
 | 
					     * The roles that belong to the user.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -62,21 +55,30 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
 | 
				
			|||||||
        return $this->belongsToMany('BookStack\Role');
 | 
					        return $this->belongsToMany('BookStack\Role');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public function getRoleAttribute()
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check if the user has a role.
 | 
				
			||||||
 | 
					     * @param $role
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function hasRole($role)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        return $this->roles()->with('permissions')->first();
 | 
					        return $this->roles->pluck('name')->contains($role);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Loads the user's permissions from their role.
 | 
					     * Get all permissions belonging to a the current user.
 | 
				
			||||||
 | 
					     * @param bool $cache
 | 
				
			||||||
 | 
					     * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private function loadPermissions()
 | 
					    public function permissions($cache = true)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (isset($this->permissions)) return;
 | 
					        if(isset($this->permissions) && $cache) return $this->permissions;
 | 
				
			||||||
        $this->load('roles.permissions');
 | 
					        $this->load('roles.permissions');
 | 
				
			||||||
        $permissions = $this->roles[0]->permissions;
 | 
					        $permissions = $this->roles->map(function($role) {
 | 
				
			||||||
        $permissionsArray = $permissions->pluck('name')->all();
 | 
					            return $role->permissions;
 | 
				
			||||||
        $this->permissions = $permissionsArray;
 | 
					        })->flatten()->unique();
 | 
				
			||||||
 | 
					        $this->permissions = $permissions;
 | 
				
			||||||
 | 
					        return $permissions;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -86,11 +88,8 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function can($permissionName)
 | 
					    public function can($permissionName)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if ($this->email == 'guest') {
 | 
					        if ($this->email === 'guest') return false;
 | 
				
			||||||
            return false;
 | 
					        return $this->permissions()->pluck('name')->contains($permissionName);
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        $this->loadPermissions();
 | 
					 | 
				
			||||||
        return array_search($permissionName, $this->permissions) !== false;
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -108,12 +107,11 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    public function attachRoleId($id)
 | 
					    public function attachRoleId($id)
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $this->roles()->sync([$id]);
 | 
					        $this->roles()->attach($id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get the social account associated with this user.
 | 
					     * Get the social account associated with this user.
 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
 | 
					     * @return \Illuminate\Database\Eloquent\Relations\HasMany
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public function socialAccounts()
 | 
					    public function socialAccounts()
 | 
				
			||||||
@@ -138,8 +136,6 @@ class User extends Model implements AuthenticatableContract, CanResetPasswordCon
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Returns the user's avatar,
 | 
					     * Returns the user's avatar,
 | 
				
			||||||
     * Uses Gravatar as the avatar service.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @param int $size
 | 
					     * @param int $size
 | 
				
			||||||
     * @return string
 | 
					     * @return string
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if (! function_exists('versioned_asset')) {
 | 
					if (!function_exists('versioned_asset')) {
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get the path to a versioned file.
 | 
					     * Get the path to a versioned file.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param  string  $file
 | 
					     * @param  string $file
 | 
				
			||||||
     * @return string
 | 
					     * @return string
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @throws \InvalidArgumentException
 | 
					     * @throws \InvalidArgumentException
 | 
				
			||||||
@@ -28,3 +28,34 @@ if (! function_exists('versioned_asset')) {
 | 
				
			|||||||
        throw new InvalidArgumentException("File {$file} not defined in asset manifest.");
 | 
					        throw new InvalidArgumentException("File {$file} not defined in asset manifest.");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Check if the current user has a permission.
 | 
				
			||||||
 | 
					 * If an ownable element is passed in the permissions are checked against
 | 
				
			||||||
 | 
					 * that particular item.
 | 
				
			||||||
 | 
					 * @param $permission
 | 
				
			||||||
 | 
					 * @param \BookStack\Ownable $ownable
 | 
				
			||||||
 | 
					 * @return mixed
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					function userCan($permission, \BookStack\Ownable $ownable = null)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!auth()->check()) return false;
 | 
				
			||||||
 | 
					    if ($ownable === null) {
 | 
				
			||||||
 | 
					        return auth()->user() && auth()->user()->can($permission);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check permission on ownable item
 | 
				
			||||||
 | 
					    $permissionBaseName = strtolower($permission) . '-';
 | 
				
			||||||
 | 
					    $hasPermission = false;
 | 
				
			||||||
 | 
					    if (auth()->user()->can($permissionBaseName . 'all')) $hasPermission = true;
 | 
				
			||||||
 | 
					    if (auth()->user()->can($permissionBaseName . 'own') && $ownable->createdBy && $ownable->createdBy->id === auth()->user()->id) $hasPermission = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!$ownable instanceof \BookStack\Entity) return $hasPermission;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Check restrictions on the entitiy
 | 
				
			||||||
 | 
					    $restrictionService = app('BookStack\Services\RestrictionService');
 | 
				
			||||||
 | 
					    $explodedPermission = explode('-', $permission);
 | 
				
			||||||
 | 
					    $action = end($explodedPermission);
 | 
				
			||||||
 | 
					    $hasAccess = $restrictionService->checkIfEntityRestricted($ownable, $action);
 | 
				
			||||||
 | 
					    return $hasAccess && $hasPermission;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -17,6 +17,7 @@ $factory->define(BookStack\User::class, function ($faker) {
 | 
				
			|||||||
        'email' => $faker->email,
 | 
					        'email' => $faker->email,
 | 
				
			||||||
        'password' => str_random(10),
 | 
					        'password' => str_random(10),
 | 
				
			||||||
        'remember_token' => str_random(10),
 | 
					        'remember_token' => str_random(10),
 | 
				
			||||||
 | 
					        'email_confirmed' => 1
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -45,3 +46,10 @@ $factory->define(BookStack\Page::class, function ($faker) {
 | 
				
			|||||||
        'text' => strip_tags($html)
 | 
					        'text' => strip_tags($html)
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$factory->define(BookStack\Role::class, function ($faker) {
 | 
				
			||||||
 | 
					    return [
 | 
				
			||||||
 | 
					        'display_name' => $faker->sentence(3),
 | 
				
			||||||
 | 
					        'description' => $faker->sentence(10)
 | 
				
			||||||
 | 
					    ];
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
@@ -0,0 +1,99 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Database\Schema\Blueprint;
 | 
				
			||||||
 | 
					use Illuminate\Database\Migrations\Migration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UpdatePermissionsAndRoles extends Migration
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Run the migrations.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function up()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Get roles with permissions we need to change
 | 
				
			||||||
 | 
					        $adminRole = \BookStack\Role::getRole('admin');
 | 
				
			||||||
 | 
					        $editorRole = \BookStack\Role::getRole('editor');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Delete old permissions
 | 
				
			||||||
 | 
					        $permissions = \BookStack\Permission::all();
 | 
				
			||||||
 | 
					        $permissions->each(function ($permission) {
 | 
				
			||||||
 | 
					            $permission->delete();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Create & attach new admin permissions
 | 
				
			||||||
 | 
					        $permissionsToCreate = [
 | 
				
			||||||
 | 
					            'settings-manage' => 'Manage Settings',
 | 
				
			||||||
 | 
					            'users-manage' => 'Manage Users',
 | 
				
			||||||
 | 
					            'user-roles-manage' => 'Manage Roles & Permissions',
 | 
				
			||||||
 | 
					            'restrictions-manage-all' => 'Manage All Entity Restrictions',
 | 
				
			||||||
 | 
					            'restrictions-manage-own' => 'Manage Entity Restrictions On Own Content'
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					        foreach ($permissionsToCreate as $name => $displayName) {
 | 
				
			||||||
 | 
					            $newPermission = new \BookStack\Permission();
 | 
				
			||||||
 | 
					            $newPermission->name = $name;
 | 
				
			||||||
 | 
					            $newPermission->display_name = $displayName;
 | 
				
			||||||
 | 
					            $newPermission->save();
 | 
				
			||||||
 | 
					            $adminRole->attachPermission($newPermission);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Create & attach new entity permissions
 | 
				
			||||||
 | 
					        $entities = ['Book', 'Page', 'Chapter', 'Image'];
 | 
				
			||||||
 | 
					        $ops = ['Create All', 'Create Own', 'Update All', 'Update Own', 'Delete All', 'Delete Own'];
 | 
				
			||||||
 | 
					        foreach ($entities as $entity) {
 | 
				
			||||||
 | 
					            foreach ($ops as $op) {
 | 
				
			||||||
 | 
					                $newPermission = new \BookStack\Permission();
 | 
				
			||||||
 | 
					                $newPermission->name = strtolower($entity) . '-' . strtolower(str_replace(' ', '-', $op));
 | 
				
			||||||
 | 
					                $newPermission->display_name = $op . ' ' . $entity . 's';
 | 
				
			||||||
 | 
					                $newPermission->save();
 | 
				
			||||||
 | 
					                $adminRole->attachPermission($newPermission);
 | 
				
			||||||
 | 
					                if ($editorRole !== null) $editorRole->attachPermission($newPermission);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Reverse the migrations.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function down()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        // Get roles with permissions we need to change
 | 
				
			||||||
 | 
					        $adminRole = \BookStack\Role::getRole('admin');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Delete old permissions
 | 
				
			||||||
 | 
					        $permissions = \BookStack\Permission::all();
 | 
				
			||||||
 | 
					        $permissions->each(function ($permission) {
 | 
				
			||||||
 | 
					            $permission->delete();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Create default CRUD permissions and allocate to admins and editors
 | 
				
			||||||
 | 
					        $entities = ['Book', 'Page', 'Chapter', 'Image'];
 | 
				
			||||||
 | 
					        $ops = ['Create', 'Update', 'Delete'];
 | 
				
			||||||
 | 
					        foreach ($entities as $entity) {
 | 
				
			||||||
 | 
					            foreach ($ops as $op) {
 | 
				
			||||||
 | 
					                $newPermission = new \BookStack\Permission();
 | 
				
			||||||
 | 
					                $newPermission->name = strtolower($entity) . '-' . strtolower($op);
 | 
				
			||||||
 | 
					                $newPermission->display_name = $op . ' ' . $entity . 's';
 | 
				
			||||||
 | 
					                $newPermission->save();
 | 
				
			||||||
 | 
					                $adminRole->attachPermission($newPermission);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Create admin permissions
 | 
				
			||||||
 | 
					        $entities = ['Settings', 'User'];
 | 
				
			||||||
 | 
					        $ops = ['Create', 'Update', 'Delete'];
 | 
				
			||||||
 | 
					        foreach ($entities as $entity) {
 | 
				
			||||||
 | 
					            foreach ($ops as $op) {
 | 
				
			||||||
 | 
					                $newPermission = new \BookStack\Permission();
 | 
				
			||||||
 | 
					                $newPermission->name = strtolower($entity) . '-' . strtolower($op);
 | 
				
			||||||
 | 
					                $newPermission->display_name = $op . ' ' . $entity;
 | 
				
			||||||
 | 
					                $newPermission->save();
 | 
				
			||||||
 | 
					                $adminRole->attachPermission($newPermission);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,73 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Database\Schema\Blueprint;
 | 
				
			||||||
 | 
					use Illuminate\Database\Migrations\Migration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AddEntityAccessControls extends Migration
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Run the migrations.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function up()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Schema::table('images', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->integer('uploaded_to')->default(0);
 | 
				
			||||||
 | 
					            $table->index('uploaded_to');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::table('books', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->boolean('restricted')->default(false);
 | 
				
			||||||
 | 
					            $table->index('restricted');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::table('chapters', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->boolean('restricted')->default(false);
 | 
				
			||||||
 | 
					            $table->index('restricted');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::table('pages', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->boolean('restricted')->default(false);
 | 
				
			||||||
 | 
					            $table->index('restricted');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::create('restrictions', function(Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->increments('id');
 | 
				
			||||||
 | 
					            $table->integer('restrictable_id');
 | 
				
			||||||
 | 
					            $table->string('restrictable_type');
 | 
				
			||||||
 | 
					            $table->integer('role_id');
 | 
				
			||||||
 | 
					            $table->string('action');
 | 
				
			||||||
 | 
					            $table->index('role_id');
 | 
				
			||||||
 | 
					            $table->index('action');
 | 
				
			||||||
 | 
					            $table->index(['restrictable_id', 'restrictable_type']);
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Reverse the migrations.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function down()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Schema::table('images', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->dropColumn('uploaded_to');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::table('books', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->dropColumn('restricted');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::table('chapters', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->dropColumn('restricted');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::table('pages', function (Blueprint $table) {
 | 
				
			||||||
 | 
					            $table->dropColumn('restricted');
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Schema::drop('restrictions');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -12,7 +12,7 @@ class DummyContentSeeder extends Seeder
 | 
				
			|||||||
    public function run()
 | 
					    public function run()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $user = factory(BookStack\User::class, 1)->create();
 | 
					        $user = factory(BookStack\User::class, 1)->create();
 | 
				
			||||||
        $role = \BookStack\Role::getDefault();
 | 
					        $role = \BookStack\Role::getRole('editor');
 | 
				
			||||||
        $user->attachRole($role);
 | 
					        $user->attachRole($role);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,6 +21,7 @@
 | 
				
			|||||||
    </filter>
 | 
					    </filter>
 | 
				
			||||||
    <php>
 | 
					    <php>
 | 
				
			||||||
        <env name="APP_ENV" value="testing"/>
 | 
					        <env name="APP_ENV" value="testing"/>
 | 
				
			||||||
 | 
					        <env name="APP_DEBUG" value="false"/>
 | 
				
			||||||
        <env name="CACHE_DRIVER" value="array"/>
 | 
					        <env name="CACHE_DRIVER" value="array"/>
 | 
				
			||||||
        <env name="SESSION_DRIVER" value="array"/>
 | 
					        <env name="SESSION_DRIVER" value="array"/>
 | 
				
			||||||
        <env name="QUEUE_DRIVER" value="sync"/>
 | 
					        <env name="QUEUE_DRIVER" value="sync"/>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -118,6 +118,7 @@ module.exports = function (ngApp, events) {
 | 
				
			|||||||
                    page++;
 | 
					                    page++;
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            $scope.fetchData = fetchData;
 | 
					            $scope.fetchData = fetchData;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            /**
 | 
					            /**
 | 
				
			||||||
@@ -130,12 +131,16 @@ module.exports = function (ngApp, events) {
 | 
				
			|||||||
                $http.put(url, this.selectedImage).then((response) => {
 | 
					                $http.put(url, this.selectedImage).then((response) => {
 | 
				
			||||||
                    events.emit('success', 'Image details updated');
 | 
					                    events.emit('success', 'Image details updated');
 | 
				
			||||||
                }, (response) => {
 | 
					                }, (response) => {
 | 
				
			||||||
                    var errors = response.data;
 | 
					                    if (response.status === 422) {
 | 
				
			||||||
                    var message = '';
 | 
					                        var errors = response.data;
 | 
				
			||||||
                    Object.keys(errors).forEach((key) => {
 | 
					                        var message = '';
 | 
				
			||||||
                        message += errors[key].join('\n');
 | 
					                        Object.keys(errors).forEach((key) => {
 | 
				
			||||||
                    });
 | 
					                            message += errors[key].join('\n');
 | 
				
			||||||
                    events.emit('error', message);
 | 
					                        });
 | 
				
			||||||
 | 
					                        events.emit('error', message);
 | 
				
			||||||
 | 
					                    } else if (response.status === 403) {
 | 
				
			||||||
 | 
					                        events.emit('error', response.data.error);
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -158,6 +163,8 @@ module.exports = function (ngApp, events) {
 | 
				
			|||||||
                    // Pages failure
 | 
					                    // Pages failure
 | 
				
			||||||
                    if (response.status === 400) {
 | 
					                    if (response.status === 400) {
 | 
				
			||||||
                        $scope.dependantPages = response.data;
 | 
					                        $scope.dependantPages = response.data;
 | 
				
			||||||
 | 
					                    } else if (response.status === 403) {
 | 
				
			||||||
 | 
					                        events.emit('error', response.data.error);
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                });
 | 
					                });
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
@@ -167,7 +174,7 @@ module.exports = function (ngApp, events) {
 | 
				
			|||||||
             * @param stringDate
 | 
					             * @param stringDate
 | 
				
			||||||
             * @returns {Date}
 | 
					             * @returns {Date}
 | 
				
			||||||
             */
 | 
					             */
 | 
				
			||||||
            $scope.getDate = function(stringDate) {
 | 
					            $scope.getDate = function (stringDate) {
 | 
				
			||||||
                return new Date(stringDate);
 | 
					                return new Date(stringDate);
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -87,6 +87,9 @@ header {
 | 
				
			|||||||
      padding-top: $-s;
 | 
					      padding-top: $-s;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  .dropdown-container {
 | 
				
			||||||
 | 
					    font-size: 0.9em;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
form.search-box {
 | 
					form.search-box {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -95,13 +95,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Sidebar list
 | 
					// Sidebar list
 | 
				
			||||||
.book-tree {
 | 
					.book-tree {
 | 
				
			||||||
  padding: $-xl 0 0 0;
 | 
					  padding: $-l 0 0 0;
 | 
				
			||||||
  position: relative;
 | 
					  position: relative;
 | 
				
			||||||
  right: 0;
 | 
					  right: 0;
 | 
				
			||||||
  top: 0;
 | 
					  top: 0;
 | 
				
			||||||
  transition: ease-in-out 240ms;
 | 
					  transition: ease-in-out 240ms;
 | 
				
			||||||
  transition-property: right, border;
 | 
					  transition-property: right, border;
 | 
				
			||||||
  border-left: 0px solid #FFF;
 | 
					  border-left: 0px solid #FFF;
 | 
				
			||||||
 | 
					  background-color: #FFF;
 | 
				
			||||||
  &.fixed {
 | 
					  &.fixed {
 | 
				
			||||||
    position: fixed;
 | 
					    position: fixed;
 | 
				
			||||||
    top: 0;
 | 
					    top: 0;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,4 +8,5 @@ return [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Pages
 | 
					    // Pages
 | 
				
			||||||
    'permission' => 'You do not have permission to access the requested page.',
 | 
					    'permission' => 'You do not have permission to access the requested page.',
 | 
				
			||||||
 | 
					    'permissionJson' => 'You do not have permission to perform the requested action.'
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
@@ -43,7 +43,7 @@
 | 
				
			|||||||
                    <div class="float right">
 | 
					                    <div class="float right">
 | 
				
			||||||
                        <div class="links text-center">
 | 
					                        <div class="links text-center">
 | 
				
			||||||
                            <a href="/books"><i class="zmdi zmdi-book"></i>Books</a>
 | 
					                            <a href="/books"><i class="zmdi zmdi-book"></i>Books</a>
 | 
				
			||||||
                            @if(isset($currentUser) && $currentUser->can('settings-update'))
 | 
					                            @if(isset($currentUser) && $currentUser->can('settings-manage'))
 | 
				
			||||||
                                <a href="/settings"><i class="zmdi zmdi-settings"></i>Settings</a>
 | 
					                                <a href="/settings"><i class="zmdi zmdi-settings"></i>Settings</a>
 | 
				
			||||||
                            @endif
 | 
					                            @endif
 | 
				
			||||||
                            @if(!isset($signedIn) || !$signedIn)
 | 
					                            @if(!isset($signedIn) || !$signedIn)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
                <div class="col-xs-1"></div>
 | 
					                <div class="col-xs-1"></div>
 | 
				
			||||||
                <div class="col-xs-11 faded">
 | 
					                <div class="col-xs-11 faded">
 | 
				
			||||||
                    <div class="action-buttons">
 | 
					                    <div class="action-buttons">
 | 
				
			||||||
                        @if($currentUser->can('book-create'))
 | 
					                        @if($currentUser->can('book-create-all'))
 | 
				
			||||||
                            <a href="/books/create" class="text-pos text-button"><i class="zmdi zmdi-plus"></i>Add new book</a>
 | 
					                            <a href="/books/create" class="text-pos text-button"><i class="zmdi zmdi-plus"></i>Add new book</a>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
@@ -30,7 +30,9 @@
 | 
				
			|||||||
                    {!! $books->render() !!}
 | 
					                    {!! $books->render() !!}
 | 
				
			||||||
                @else
 | 
					                @else
 | 
				
			||||||
                    <p class="text-muted">No books have been created.</p>
 | 
					                    <p class="text-muted">No books have been created.</p>
 | 
				
			||||||
                    <a href="/books/create" class="text-pos"><i class="zmdi zmdi-edit"></i>Create one now</a>
 | 
					                    @if(userCan('books-create-all'))
 | 
				
			||||||
 | 
					                        <a href="/books/create" class="text-pos"><i class="zmdi zmdi-edit"></i>Create one now</a>
 | 
				
			||||||
 | 
					                    @endif
 | 
				
			||||||
                @endif
 | 
					                @endif
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="col-sm-4 col-sm-offset-1">
 | 
					            <div class="col-sm-4 col-sm-offset-1">
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										23
									
								
								resources/views/books/restrictions.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								resources/views/books/restrictions.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					@extends('base')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@section('content')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="faded-small toolbar">
 | 
				
			||||||
 | 
					        <div class="container">
 | 
				
			||||||
 | 
					            <div class="row">
 | 
				
			||||||
 | 
					                <div class="col-sm-12 faded">
 | 
				
			||||||
 | 
					                    <div class="breadcrumbs">
 | 
				
			||||||
 | 
					                        <a href="{{$book->getUrl()}}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $book->getShortName() }}</a>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="container" ng-non-bindable>
 | 
				
			||||||
 | 
					        <h1>Book Restrictions</h1>
 | 
				
			||||||
 | 
					        @include('form/restriction-form', ['model' => $book])
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@stop
 | 
				
			||||||
@@ -2,23 +2,35 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@section('content')
 | 
					@section('content')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="faded-small toolbar" ng-non-bindable>
 | 
					    <div class="faded-small toolbar">
 | 
				
			||||||
        <div class="container">
 | 
					        <div class="container">
 | 
				
			||||||
            <div class="row">
 | 
					            <div class="row">
 | 
				
			||||||
                <div class="col-md-12">
 | 
					                <div class="col-md-12">
 | 
				
			||||||
                    <div class="action-buttons faded">
 | 
					                    <div class="action-buttons faded">
 | 
				
			||||||
                        @if($currentUser->can('page-create'))
 | 
					                        @if(userCan('page-create', $book))
 | 
				
			||||||
                            <a href="{{$book->getUrl() . '/page/create'}}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i> New Page</a>
 | 
					                            <a href="{{$book->getUrl() . '/page/create'}}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i> New Page</a>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                        @if($currentUser->can('chapter-create'))
 | 
					                        @if(userCan('chapter-create', $book))
 | 
				
			||||||
                            <a href="{{$book->getUrl() . '/chapter/create'}}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i> New Chapter</a>
 | 
					                            <a href="{{$book->getUrl() . '/chapter/create'}}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i> New Chapter</a>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                        @if($currentUser->can('book-update'))
 | 
					                        @if(userCan('book-update', $book))
 | 
				
			||||||
                            <a href="{{$book->getEditUrl()}}" class="text-primary text-button"><i class="zmdi zmdi-edit"></i>Edit</a>
 | 
					                            <a href="{{$book->getEditUrl()}}" class="text-primary text-button"><i class="zmdi zmdi-edit"></i>Edit</a>
 | 
				
			||||||
                            <a href="{{ $book->getUrl() }}/sort" class="text-primary text-button"><i class="zmdi zmdi-sort"></i>Sort</a>
 | 
					 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                        @if($currentUser->can('book-delete'))
 | 
					                        @if(userCan('book-update', $book) || userCan('restrictions-manage', $book) || userCan('book-delete', $book))
 | 
				
			||||||
                            <a href="{{ $book->getUrl() }}/delete" class="text-neg text-button"><i class="zmdi zmdi-delete"></i>Delete</a>
 | 
					                            <div dropdown class="dropdown-container">
 | 
				
			||||||
 | 
					                                <a dropdown-toggle class="text-primary text-button"><i class="zmdi zmdi-more-vert"></i></a>
 | 
				
			||||||
 | 
					                                <ul>
 | 
				
			||||||
 | 
					                                    @if(userCan('book-update', $book))
 | 
				
			||||||
 | 
					                                        <li><a href="{{ $book->getUrl() }}/sort" class="text-primary"><i class="zmdi zmdi-sort"></i>Sort</a></li>
 | 
				
			||||||
 | 
					                                    @endif
 | 
				
			||||||
 | 
					                                    @if(userCan('restrictions-manage', $book))
 | 
				
			||||||
 | 
					                                        <li><a href="{{$book->getUrl()}}/restrict" class="text-primary"><i class="zmdi zmdi-lock-outline"></i>Restrict</a></li>
 | 
				
			||||||
 | 
					                                    @endif
 | 
				
			||||||
 | 
					                                    @if(userCan('book-delete', $book))
 | 
				
			||||||
 | 
					                                        <li><a href="{{ $book->getUrl() }}/delete" class="text-neg"><i class="zmdi zmdi-delete"></i>Delete</a></li>
 | 
				
			||||||
 | 
					                                    @endif
 | 
				
			||||||
 | 
					                                </ul>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
@@ -75,6 +87,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            <div class="col-md-4 col-md-offset-1">
 | 
					            <div class="col-md-4 col-md-offset-1">
 | 
				
			||||||
                <div class="margin-top large"></div>
 | 
					                <div class="margin-top large"></div>
 | 
				
			||||||
 | 
					                @if($book->restricted)
 | 
				
			||||||
 | 
					                    <p class="text-muted">
 | 
				
			||||||
 | 
					                        @if(userCan('restrictions-manage', $book))
 | 
				
			||||||
 | 
					                            <a href="{{ $book->getUrl() }}/restrict"><i class="zmdi zmdi-lock-outline"></i>Book Restricted</a>
 | 
				
			||||||
 | 
					                        @else
 | 
				
			||||||
 | 
					                            <i class="zmdi zmdi-lock-outline"></i>Book Restricted
 | 
				
			||||||
 | 
					                        @endif
 | 
				
			||||||
 | 
					                    </p>
 | 
				
			||||||
 | 
					                @endif
 | 
				
			||||||
                <div class="search-box">
 | 
					                <div class="search-box">
 | 
				
			||||||
                    <form ng-submit="searchBook($event)">
 | 
					                    <form ng-submit="searchBook($event)">
 | 
				
			||||||
                        <input ng-model="searchTerm" ng-change="checkSearchForm()" type="text" name="term" placeholder="Search This Book">
 | 
					                        <input ng-model="searchTerm" ng-change="checkSearchForm()" type="text" name="term" placeholder="Search This Book">
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								resources/views/chapters/restrictions.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								resources/views/chapters/restrictions.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					@extends('base')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@section('content')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="faded-small toolbar">
 | 
				
			||||||
 | 
					        <div class="container">
 | 
				
			||||||
 | 
					            <div class="row">
 | 
				
			||||||
 | 
					                <div class="col-sm-12 faded">
 | 
				
			||||||
 | 
					                    <div class="breadcrumbs">
 | 
				
			||||||
 | 
					                        <a href="{{$chapter->book->getUrl()}}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $chapter->book->getShortName() }}</a>
 | 
				
			||||||
 | 
					                        <span class="sep">»</span>
 | 
				
			||||||
 | 
					                        <a href="{{ $chapter->getUrl() }}" class="text-chapter text-button"><i class="zmdi zmdi-collection-bookmark"></i>{{$chapter->getShortName()}}</a>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="container" ng-non-bindable>
 | 
				
			||||||
 | 
					        <h1>Chapter Restrictions</h1>
 | 
				
			||||||
 | 
					        @include('form/restriction-form', ['model' => $chapter])
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@stop
 | 
				
			||||||
@@ -12,13 +12,16 @@
 | 
				
			|||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
                <div class="col-md-8 faded">
 | 
					                <div class="col-md-8 faded">
 | 
				
			||||||
                    <div class="action-buttons">
 | 
					                    <div class="action-buttons">
 | 
				
			||||||
                        @if($currentUser->can('chapter-create'))
 | 
					                        @if(userCan('page-create', $chapter))
 | 
				
			||||||
                            <a href="{{$chapter->getUrl() . '/create-page'}}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i>New Page</a>
 | 
					                            <a href="{{$chapter->getUrl() . '/create-page'}}" class="text-pos text-button"><i class="zmdi zmdi-plus"></i>New Page</a>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                        @if($currentUser->can('chapter-update'))
 | 
					                        @if(userCan('chapter-update', $chapter))
 | 
				
			||||||
                            <a href="{{$chapter->getUrl() . '/edit'}}" class="text-primary text-button"><i class="zmdi zmdi-edit"></i>Edit</a>
 | 
					                            <a href="{{$chapter->getUrl() . '/edit'}}" class="text-primary text-button"><i class="zmdi zmdi-edit"></i>Edit</a>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                        @if($currentUser->can('chapter-delete'))
 | 
					                        @if(userCan('restrictions-manage', $chapter))
 | 
				
			||||||
 | 
					                            <a href="{{$chapter->getUrl()}}/restrict" class="text-primary text-button"><i class="zmdi zmdi-lock-outline"></i>Restrict</a>
 | 
				
			||||||
 | 
					                        @endif
 | 
				
			||||||
 | 
					                        @if(userCan('chapter-delete', $chapter))
 | 
				
			||||||
                            <a href="{{$chapter->getUrl() . '/delete'}}" class="text-neg text-button"><i class="zmdi zmdi-delete"></i>Delete</a>
 | 
					                            <a href="{{$chapter->getUrl() . '/delete'}}" class="text-neg text-button"><i class="zmdi zmdi-delete"></i>Delete</a>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
@@ -34,10 +37,10 @@
 | 
				
			|||||||
                <h1>{{ $chapter->name }}</h1>
 | 
					                <h1>{{ $chapter->name }}</h1>
 | 
				
			||||||
                <p class="text-muted">{{ $chapter->description }}</p>
 | 
					                <p class="text-muted">{{ $chapter->description }}</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                @if(count($chapter->pages) > 0)
 | 
					                @if(count($pages) > 0)
 | 
				
			||||||
                    <div class="page-list">
 | 
					                    <div class="page-list">
 | 
				
			||||||
                        <hr>
 | 
					                        <hr>
 | 
				
			||||||
                        @foreach($chapter->pages as $page)
 | 
					                        @foreach($pages as $page)
 | 
				
			||||||
                            @include('pages/list-item', ['page' => $page])
 | 
					                            @include('pages/list-item', ['page' => $page])
 | 
				
			||||||
                            <hr>
 | 
					                            <hr>
 | 
				
			||||||
                        @endforeach
 | 
					                        @endforeach
 | 
				
			||||||
@@ -60,6 +63,29 @@
 | 
				
			|||||||
                </p>
 | 
					                </p>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="col-md-3 col-md-offset-1">
 | 
					            <div class="col-md-3 col-md-offset-1">
 | 
				
			||||||
 | 
					                <div class="margin-top large"></div>
 | 
				
			||||||
 | 
					                @if($book->restricted || $chapter->restricted)
 | 
				
			||||||
 | 
					                    <div class="text-muted">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        @if($book->restricted)
 | 
				
			||||||
 | 
					                            @if(userCan('restrictions-manage', $book))
 | 
				
			||||||
 | 
					                                <a href="{{ $book->getUrl() }}/restrict"><i class="zmdi zmdi-lock-outline"></i>Book Restricted</a>
 | 
				
			||||||
 | 
					                            @else
 | 
				
			||||||
 | 
					                                <i class="zmdi zmdi-lock-outline"></i>Book Restricted
 | 
				
			||||||
 | 
					                            @endif
 | 
				
			||||||
 | 
					                                <br>
 | 
				
			||||||
 | 
					                        @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        @if($chapter->restricted)
 | 
				
			||||||
 | 
					                            @if(userCan('restrictions-manage', $chapter))
 | 
				
			||||||
 | 
					                                <a href="{{ $chapter->getUrl() }}/restrict"><i class="zmdi zmdi-lock-outline"></i>Chapter Restricted</a>
 | 
				
			||||||
 | 
					                            @else
 | 
				
			||||||
 | 
					                                <i class="zmdi zmdi-lock-outline"></i>Chapter Restricted
 | 
				
			||||||
 | 
					                            @endif
 | 
				
			||||||
 | 
					                        @endif
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                @include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree])
 | 
					                @include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree])
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,7 +4,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div class="container">
 | 
					<div class="container">
 | 
				
			||||||
    <h1 class="text-muted">Page Not Found</h1>
 | 
					    <h1 class="text-muted">{{ $message or 'Page Not Found' }}</h1>
 | 
				
			||||||
    <p>Sorry, The page you were looking for could not be found.</p>
 | 
					    <p>Sorry, The page you were looking for could not be found.</p>
 | 
				
			||||||
    <a href="/" class="button">Return To Home</a>
 | 
					    <a href="/" class="button">Return To Home</a>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										12
									
								
								resources/views/form/checkbox.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								resources/views/form/checkbox.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					<label>
 | 
				
			||||||
 | 
					    <input value="true" id="{{$name}}" type="checkbox" name="{{$name}}"
 | 
				
			||||||
 | 
					           @if($errors->has($name)) class="neg" @endif
 | 
				
			||||||
 | 
					           @if(old($name) || (!old() && isset($model) && $model->$name)) checked="checked" @endif
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					    {{ $label }}
 | 
				
			||||||
 | 
					</label>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@if($errors->has($name))
 | 
				
			||||||
 | 
					    <div class="text-neg text-small">{{ $errors->first($name) }}</div>
 | 
				
			||||||
 | 
					@endif
 | 
				
			||||||
							
								
								
									
										7
									
								
								resources/views/form/restriction-checkbox.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								resources/views/form/restriction-checkbox.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					<label>
 | 
				
			||||||
 | 
					    <input value="true" id="{{$name}}[{{$role->id}}][{{$action}}]" type="checkbox" name="{{$name}}[{{$role->id}}][{{$action}}]"
 | 
				
			||||||
 | 
					           @if(old($name .'.'.$role->id.'.'.$action) || (!old() && isset($model) && $model->hasRestriction($role->id, $action))) checked="checked" @endif
 | 
				
			||||||
 | 
					    >
 | 
				
			||||||
 | 
					    {{ $label }}
 | 
				
			||||||
 | 
					</label>
 | 
				
			||||||
							
								
								
									
										29
									
								
								resources/views/form/restriction-form.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								resources/views/form/restriction-form.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
				
			|||||||
 | 
					<form action="{{ $model->getUrl() }}/restrict" method="POST">
 | 
				
			||||||
 | 
					    {!! csrf_field() !!}
 | 
				
			||||||
 | 
					    <input type="hidden" name="_method" value="PUT">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="form-group">
 | 
				
			||||||
 | 
					        @include('form/checkbox', ['name' => 'restricted', 'label' => 'Restrict this ' . $model->getClassName()])
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <table class="table">
 | 
				
			||||||
 | 
					        <tr>
 | 
				
			||||||
 | 
					            <th>Role</th>
 | 
				
			||||||
 | 
					            <th @if($model->isA('page')) colspan="3" @else colspan="4" @endif>Actions</th>
 | 
				
			||||||
 | 
					        </tr>
 | 
				
			||||||
 | 
					        @foreach($roles as $role)
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <td>{{ $role->display_name }}</td>
 | 
				
			||||||
 | 
					                <td>@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => 'View', 'action' => 'view'])</td>
 | 
				
			||||||
 | 
					                @if(!$model->isA('page'))
 | 
				
			||||||
 | 
					                    <td>@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => 'Create', 'action' => 'create'])</td>
 | 
				
			||||||
 | 
					                @endif
 | 
				
			||||||
 | 
					                <td>@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => 'Update', 'action' => 'update'])</td>
 | 
				
			||||||
 | 
					                <td>@include('form/restriction-checkbox', ['name'=>'restrictions', 'label' => 'Delete', 'action' => 'delete'])</td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					        @endforeach
 | 
				
			||||||
 | 
					    </table>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <a href="{{ $model->getUrl() }}" class="button muted">Cancel</a>
 | 
				
			||||||
 | 
					    <button type="submit" class="button pos">Save Restrictions</button>
 | 
				
			||||||
 | 
					</form>
 | 
				
			||||||
							
								
								
									
										14
									
								
								resources/views/form/role-checkboxes.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								resources/views/form/role-checkboxes.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					@foreach($roles as $role)
 | 
				
			||||||
 | 
					    <label>
 | 
				
			||||||
 | 
					        <input value="{{ $role->id }}" id="{{$name}}-{{$role->name}}" type="checkbox" name="{{$name}}[{{$role->name}}]"
 | 
				
			||||||
 | 
					               @if($errors->has($name)) class="neg" @endif
 | 
				
			||||||
 | 
					               @if(old($name . '.' . $role->name) || (!old('name') && isset($model) && $model->hasRole($role->name))) checked="checked" @endif
 | 
				
			||||||
 | 
					        >
 | 
				
			||||||
 | 
					        {{ $role->display_name }}
 | 
				
			||||||
 | 
					    </label>
 | 
				
			||||||
 | 
					@endforeach
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@if($errors->has($name))
 | 
				
			||||||
 | 
					    <div class="text-neg text-small">{{ $errors->first($name) }}</div>
 | 
				
			||||||
 | 
					@endif
 | 
				
			||||||
							
								
								
									
										31
									
								
								resources/views/pages/restrictions.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								resources/views/pages/restrictions.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					@extends('base')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@section('content')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="faded-small toolbar">
 | 
				
			||||||
 | 
					        <div class="container">
 | 
				
			||||||
 | 
					            <div class="row">
 | 
				
			||||||
 | 
					                <div class="col-sm-12 faded">
 | 
				
			||||||
 | 
					                    <div class="breadcrumbs">
 | 
				
			||||||
 | 
					                        <a href="{{$page->book->getUrl()}}" class="text-book text-button"><i class="zmdi zmdi-book"></i>{{ $page->book->getShortName() }}</a>
 | 
				
			||||||
 | 
					                        @if($page->hasChapter())
 | 
				
			||||||
 | 
					                            <span class="sep">»</span>
 | 
				
			||||||
 | 
					                            <a href="{{ $page->chapter->getUrl() }}" class="text-chapter text-button">
 | 
				
			||||||
 | 
					                                <i class="zmdi zmdi-collection-bookmark"></i>
 | 
				
			||||||
 | 
					                                {{$page->chapter->getShortName()}}
 | 
				
			||||||
 | 
					                            </a>
 | 
				
			||||||
 | 
					                        @endif
 | 
				
			||||||
 | 
					                        <span class="sep">»</span>
 | 
				
			||||||
 | 
					                        <a href="{{$page->getUrl()}}" class="text-book text-button"><i class="zmdi zmdi-file"></i>{{ $page->getShortName() }}</a>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="container" ng-non-bindable>
 | 
				
			||||||
 | 
					        <h1>Page Restrictions</h1>
 | 
				
			||||||
 | 
					        @include('form/restriction-form', ['model' => $page])
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@stop
 | 
				
			||||||
@@ -22,17 +22,20 @@
 | 
				
			|||||||
                        <span dropdown class="dropdown-container">
 | 
					                        <span dropdown class="dropdown-container">
 | 
				
			||||||
                            <div dropdown-toggle class="text-button text-primary"><i class="zmdi zmdi-open-in-new"></i>Export</div>
 | 
					                            <div dropdown-toggle class="text-button text-primary"><i class="zmdi zmdi-open-in-new"></i>Export</div>
 | 
				
			||||||
                            <ul class="wide">
 | 
					                            <ul class="wide">
 | 
				
			||||||
                                <li><a href="{{$page->getUrl() . '/export/html'}}" target="_blank">Contained Web File <span class="text-muted float right">.html</span></a></li>
 | 
					                                <li><a href="{{$page->getUrl()}}/export/html" target="_blank">Contained Web File <span class="text-muted float right">.html</span></a></li>
 | 
				
			||||||
                                <li><a href="{{$page->getUrl() . '/export/pdf'}}" target="_blank">PDF File <span class="text-muted float right">.pdf</span></a></li>
 | 
					                                <li><a href="{{$page->getUrl()}}/export/pdf" target="_blank">PDF File <span class="text-muted float right">.pdf</span></a></li>
 | 
				
			||||||
                                <li><a href="{{$page->getUrl() . '/export/plaintext'}}" target="_blank">Plain Text File <span class="text-muted float right">.txt</span></a></li>
 | 
					                                <li><a href="{{$page->getUrl()}}/export/plaintext" target="_blank">Plain Text File <span class="text-muted float right">.txt</span></a></li>
 | 
				
			||||||
                            </ul>
 | 
					                            </ul>
 | 
				
			||||||
                        </span>
 | 
					                        </span>
 | 
				
			||||||
                        @if($currentUser->can('page-update'))
 | 
					                        @if(userCan('page-update', $page))
 | 
				
			||||||
                            <a href="{{$page->getUrl() . '/revisions'}}" class="text-primary text-button"><i class="zmdi zmdi-replay"></i>Revisions</a>
 | 
					                            <a href="{{$page->getUrl()}}/revisions" class="text-primary text-button"><i class="zmdi zmdi-replay"></i>Revisions</a>
 | 
				
			||||||
                            <a href="{{$page->getUrl() . '/edit'}}" class="text-primary text-button" ><i class="zmdi zmdi-edit"></i>Edit</a>
 | 
					                            <a href="{{$page->getUrl()}}/edit" class="text-primary text-button" ><i class="zmdi zmdi-edit"></i>Edit</a>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                        @if($currentUser->can('page-delete'))
 | 
					                        @if(userCan('restrictions-manage', $page))
 | 
				
			||||||
                            <a href="{{$page->getUrl() . '/delete'}}" class="text-neg text-button"><i class="zmdi zmdi-delete"></i>Delete</a>
 | 
					                            <a href="{{$page->getUrl()}}/restrict" class="text-primary text-button"><i class="zmdi zmdi-lock-outline"></i>Restrict</a>
 | 
				
			||||||
 | 
					                        @endif
 | 
				
			||||||
 | 
					                        @if(userCan('page-delete', $page))
 | 
				
			||||||
 | 
					                            <a href="{{$page->getUrl()}}/delete" class="text-neg text-button"><i class="zmdi zmdi-delete"></i>Delete</a>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
@@ -67,7 +70,38 @@
 | 
				
			|||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
            <div class="col-md-3 print-hidden">
 | 
					            <div class="col-md-3 print-hidden">
 | 
				
			||||||
 | 
					                <div class="margin-top large"></div>
 | 
				
			||||||
 | 
					                @if($book->restricted || ($page->chapter && $page->chapter->restricted) || $page->restricted)
 | 
				
			||||||
 | 
					                    <div class="text-muted">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        @if($book->restricted)
 | 
				
			||||||
 | 
					                            @if(userCan('restrictions-manage', $book))
 | 
				
			||||||
 | 
					                                <a href="{{ $book->getUrl() }}/restrict"><i class="zmdi zmdi-lock-outline"></i>Book restricted</a>
 | 
				
			||||||
 | 
					                            @else
 | 
				
			||||||
 | 
					                                <i class="zmdi zmdi-lock-outline"></i>Book restricted
 | 
				
			||||||
 | 
					                            @endif
 | 
				
			||||||
 | 
					                            <br>
 | 
				
			||||||
 | 
					                        @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        @if($page->chapter && $page->chapter->restricted)
 | 
				
			||||||
 | 
					                            @if(userCan('restrictions-manage', $page->chapter))
 | 
				
			||||||
 | 
					                                <a href="{{ $page->chapter->getUrl() }}/restrict"><i class="zmdi zmdi-lock-outline"></i>Chapter restricted</a>
 | 
				
			||||||
 | 
					                            @else
 | 
				
			||||||
 | 
					                                <i class="zmdi zmdi-lock-outline"></i>Chapter restricted
 | 
				
			||||||
 | 
					                            @endif
 | 
				
			||||||
 | 
					                            <br>
 | 
				
			||||||
 | 
					                        @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        @if($page->restricted)
 | 
				
			||||||
 | 
					                            @if(userCan('restrictions-manage', $page))
 | 
				
			||||||
 | 
					                                <a href="{{ $page->getUrl() }}/restrict"><i class="zmdi zmdi-lock-outline"></i>Page restricted</a>
 | 
				
			||||||
 | 
					                            @else
 | 
				
			||||||
 | 
					                                <i class="zmdi zmdi-lock-outline"></i>Page restricted
 | 
				
			||||||
 | 
					                            @endif
 | 
				
			||||||
 | 
					                            <br>
 | 
				
			||||||
 | 
					                        @endif
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                @endif
 | 
				
			||||||
                @include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree])
 | 
					                @include('pages/sidebar-tree-list', ['book' => $book, 'sidebarTree' => $sidebarTree])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,8 +16,8 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    {{ $activity->getText() }}
 | 
					    {{ $activity->getText() }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @if($activity->entity())
 | 
					    @if($activity->entity)
 | 
				
			||||||
        <a href="{{ $activity->entity()->getUrl() }}">{{ $activity->entity()->name }}</a>
 | 
					        <a href="{{ $activity->entity->getUrl() }}">{{ $activity->entity->name }}</a>
 | 
				
			||||||
    @endif
 | 
					    @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @if($activity->extra) "{{$activity->extra}}" @endif
 | 
					    @if($activity->extra) "{{$activity->extra}}" @endif
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@
 | 
				
			|||||||
                    <select id="setting-registration-role" name="setting-registration-role" @if($errors->has('setting-registration-role')) class="neg" @endif>
 | 
					                    <select id="setting-registration-role" name="setting-registration-role" @if($errors->has('setting-registration-role')) class="neg" @endif>
 | 
				
			||||||
                        @foreach(\BookStack\Role::all() as $role)
 | 
					                        @foreach(\BookStack\Role::all() as $role)
 | 
				
			||||||
                            <option value="{{$role->id}}"
 | 
					                            <option value="{{$role->id}}"
 | 
				
			||||||
                                    @if(\Setting::get('registration-role', \BookStack\Role::getDefault()->id) == $role->id) selected @endif
 | 
					                                    @if(\Setting::get('registration-role', \BookStack\Role::first()->id) == $role->id) selected @endif
 | 
				
			||||||
                                    >
 | 
					                                    >
 | 
				
			||||||
                                {{ $role->display_name }}
 | 
					                                {{ $role->display_name }}
 | 
				
			||||||
                            </option>
 | 
					                            </option>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@
 | 
				
			|||||||
            <div class="col-md-12 setting-nav">
 | 
					            <div class="col-md-12 setting-nav">
 | 
				
			||||||
                <a href="/settings" @if($selected == 'settings') class="selected text-button" @endif><i class="zmdi zmdi-settings"></i>Settings</a>
 | 
					                <a href="/settings" @if($selected == 'settings') class="selected text-button" @endif><i class="zmdi zmdi-settings"></i>Settings</a>
 | 
				
			||||||
                <a href="/settings/users" @if($selected == 'users') class="selected text-button" @endif><i class="zmdi zmdi-accounts"></i>Users</a>
 | 
					                <a href="/settings/users" @if($selected == 'users') class="selected text-button" @endif><i class="zmdi zmdi-accounts"></i>Users</a>
 | 
				
			||||||
 | 
					                <a href="/settings/roles" @if($selected == 'roles') class="selected text-button" @endif><i class="zmdi zmdi-lock-open"></i>Roles</a>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
        </div>
 | 
					        </div>
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										3
									
								
								resources/views/settings/roles/checkbox.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								resources/views/settings/roles/checkbox.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					<input type="checkbox" name="permissions[{{ $permission }}]"
 | 
				
			||||||
 | 
					       @if(old('permissions.'.$permission, false)|| (!old('display_name', false) && (isset($role) && $role->hasPermission($permission)))) checked="checked" @endif
 | 
				
			||||||
 | 
					       value="true">
 | 
				
			||||||
							
								
								
									
										15
									
								
								resources/views/settings/roles/create.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								resources/views/settings/roles/create.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					@extends('base')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@section('content')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @include('settings/navbar', ['selected' => 'roles'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="container">
 | 
				
			||||||
 | 
					        <h1>Create New Role</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <form action="/settings/roles/new" method="POST">
 | 
				
			||||||
 | 
					            @include('settings/roles/form')
 | 
				
			||||||
 | 
					        </form>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@stop
 | 
				
			||||||
							
								
								
									
										28
									
								
								resources/views/settings/roles/delete.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								resources/views/settings/roles/delete.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					@extends('base')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@section('content')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @include('settings/navbar', ['selected' => 'roles'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="container small" ng-non-bindable>
 | 
				
			||||||
 | 
					        <h1>Delete Role</h1>
 | 
				
			||||||
 | 
					        <p>This will delete the role with the name '{{$role->display_name}}'.</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <form action="/settings/roles/delete/{{$role->id}}" method="POST">
 | 
				
			||||||
 | 
					            {!! csrf_field() !!}
 | 
				
			||||||
 | 
					            <input type="hidden" name="_method" value="DELETE">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            @if($role->users->count() > 0)
 | 
				
			||||||
 | 
					            <div class="form-group">
 | 
				
			||||||
 | 
					                    <p>This role has {{$role->users->count()}} users assigned to it. If you would like to migrate the users from this role select a new role below.</p>
 | 
				
			||||||
 | 
					                    @include('form/role-select', ['options' => $roles, 'name' => 'migration_role_id'])
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            <p class="text-neg">Are you sure you want to delete this role?</p>
 | 
				
			||||||
 | 
					            <a href="/settings/roles/{{ $role->id }}" class="button">Cancel</a>
 | 
				
			||||||
 | 
					            <button type="submit" class="button neg">Confirm</button>
 | 
				
			||||||
 | 
					        </form>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@stop
 | 
				
			||||||
							
								
								
									
										24
									
								
								resources/views/settings/roles/edit.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								resources/views/settings/roles/edit.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					@extends('base')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@section('content')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @include('settings/navbar', ['selected' => 'roles'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="container">
 | 
				
			||||||
 | 
					        <div class="row">
 | 
				
			||||||
 | 
					            <div class="col-sm-6">
 | 
				
			||||||
 | 
					                <h1>Edit Role <small> {{ $role->display_name }}</small></h1>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="col-sm-6">
 | 
				
			||||||
 | 
					                <p></p>
 | 
				
			||||||
 | 
					                <a href="/settings/roles/delete/{{ $role->id }}" class="button neg float right">Delete Role</a>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <form action="/settings/roles/{{ $role->id }}" method="POST">
 | 
				
			||||||
 | 
					            <input type="hidden" name="_method" value="PUT">
 | 
				
			||||||
 | 
					            @include('settings/roles/form', ['model' => $role])
 | 
				
			||||||
 | 
					        </form>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@stop
 | 
				
			||||||
							
								
								
									
										117
									
								
								resources/views/settings/roles/form.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								resources/views/settings/roles/form.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
				
			|||||||
 | 
					{!! csrf_field() !!}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div class="row">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="col-md-6">
 | 
				
			||||||
 | 
					        <h3>Role Details</h3>
 | 
				
			||||||
 | 
					        <div class="form-group">
 | 
				
			||||||
 | 
					            <label for="name">Role Name</label>
 | 
				
			||||||
 | 
					            @include('form/text', ['name' => 'display_name'])
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div class="form-group">
 | 
				
			||||||
 | 
					            <label for="name">Short Role Description</label>
 | 
				
			||||||
 | 
					            @include('form/text', ['name' => 'description'])
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <h3>System Permissions</h3>
 | 
				
			||||||
 | 
					        <div class="row">
 | 
				
			||||||
 | 
					            <div class="col-md-6">
 | 
				
			||||||
 | 
					                <label> @include('settings/roles/checkbox', ['permission' => 'users-manage']) Manage users</label>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="col-md-6">
 | 
				
			||||||
 | 
					                <label>@include('settings/roles/checkbox', ['permission' => 'user-roles-manage']) Manage user roles</label>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <hr class="even">
 | 
				
			||||||
 | 
					        <div class="row">
 | 
				
			||||||
 | 
					            <div class="col-md-6">
 | 
				
			||||||
 | 
					                <label>@include('settings/roles/checkbox', ['permission' => 'restrictions-manage-all']) Manage all restrictions</label>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div class="col-md-6">
 | 
				
			||||||
 | 
					                <label>@include('settings/roles/checkbox', ['permission' => 'restrictions-manage-own']) Manage restrictions on own content</label>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <hr class="even">
 | 
				
			||||||
 | 
					        <div class="form-group">
 | 
				
			||||||
 | 
					            <label>@include('settings/roles/checkbox', ['permission' => 'settings-manage']) Manage app settings</label>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <hr class="even">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="col-md-6">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <h3>Asset Permissions</h3>
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					            These permissions control default access to the assets within the system. <br>
 | 
				
			||||||
 | 
					            Restrictions on Books, Chapters and Pages will override these permissions.
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					        <table class="table">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <th></th>
 | 
				
			||||||
 | 
					                <th>Create</th>
 | 
				
			||||||
 | 
					                <th>Edit</th>
 | 
				
			||||||
 | 
					                <th>Delete</th>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <td>Books</td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'book-create-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'book-update-own']) Own</label>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'book-update-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'book-delete-own']) Own</label>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'book-delete-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <td>Chapters</td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'chapter-create-own']) Own</label>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'chapter-create-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'chapter-update-own']) Own</label>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'chapter-update-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'chapter-delete-own']) Own</label>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'chapter-delete-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <td>Pages</td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'page-create-own']) Own</label>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'page-create-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'page-update-own']) Own</label>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'page-update-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'page-delete-own']) Own</label>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'page-delete-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <td>Images</td>
 | 
				
			||||||
 | 
					                <td>@include('settings/roles/checkbox', ['permission' => 'image-create-all'])</td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'image-update-own']) Own</label>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'image-update-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					                <td>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'image-delete-own']) Own</label>
 | 
				
			||||||
 | 
					                    <label>@include('settings/roles/checkbox', ['permission' => 'image-delete-all']) All</label>
 | 
				
			||||||
 | 
					                </td>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<a href="/settings/roles" class="button muted">Cancel</a>
 | 
				
			||||||
 | 
					<button type="submit" class="button pos">Save Role</button>
 | 
				
			||||||
							
								
								
									
										31
									
								
								resources/views/settings/roles/index.blade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								resources/views/settings/roles/index.blade.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					@extends('base')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@section('content')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @include('settings/navbar', ['selected' => 'roles'])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <div class="container small">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <h1>User Roles</h1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <p>
 | 
				
			||||||
 | 
					            <a href="/settings/roles/new" class="text-pos"><i class="zmdi zmdi-lock-open"></i>Add new role</a>
 | 
				
			||||||
 | 
					        </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        <table class="table">
 | 
				
			||||||
 | 
					            <tr>
 | 
				
			||||||
 | 
					                <th>Role Name</th>
 | 
				
			||||||
 | 
					                <th></th>
 | 
				
			||||||
 | 
					                <th class="text-right">Users</th>
 | 
				
			||||||
 | 
					            </tr>
 | 
				
			||||||
 | 
					            @foreach($roles as $role)
 | 
				
			||||||
 | 
					                <tr>
 | 
				
			||||||
 | 
					                    <td><a href="/settings/roles/{{ $role->id }}">{{ $role->display_name }}</a></td>
 | 
				
			||||||
 | 
					                    <td>{{ $role->description }}</td>
 | 
				
			||||||
 | 
					                    <td class="text-right">{{ $role->users->count() }}</td>
 | 
				
			||||||
 | 
					                </tr>
 | 
				
			||||||
 | 
					            @endforeach
 | 
				
			||||||
 | 
					        </table>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@stop
 | 
				
			||||||
@@ -3,21 +3,21 @@
 | 
				
			|||||||
    @include('form.text', ['name' => 'name'])
 | 
					    @include('form.text', ['name' => 'name'])
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@if($currentUser->can('user-update'))
 | 
					@if(userCan('users-manage'))
 | 
				
			||||||
<div class="form-group">
 | 
					<div class="form-group">
 | 
				
			||||||
    <label for="email">Email</label>
 | 
					    <label for="email">Email</label>
 | 
				
			||||||
    @include('form.text', ['name' => 'email'])
 | 
					    @include('form.text', ['name' => 'email'])
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
@endif
 | 
					@endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@if($currentUser->can('user-update'))
 | 
					@if(userCan('users-manage'))
 | 
				
			||||||
    <div class="form-group">
 | 
					    <div class="form-group">
 | 
				
			||||||
        <label for="role">User Role</label>
 | 
					        <label for="role">User Role</label>
 | 
				
			||||||
        @include('form.role-select', ['name' => 'role', 'options' => \BookStack\Role::all(), 'displayKey' => 'display_name'])
 | 
					        @include('form/role-checkboxes', ['name' => 'roles', 'roles' => \BookStack\Role::all()])
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@endif
 | 
					@endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@if($currentUser->can('user-update'))
 | 
					@if(userCan('users-manage'))
 | 
				
			||||||
    <div class="form-group">
 | 
					    <div class="form-group">
 | 
				
			||||||
        <label for="external_auth_id">External Authentication ID</label>
 | 
					        <label for="external_auth_id">External Authentication ID</label>
 | 
				
			||||||
        @include('form.text', ['name' => 'external_auth_id'])
 | 
					        @include('form.text', ['name' => 'external_auth_id'])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,10 +8,10 @@
 | 
				
			|||||||
    @include('form.text', ['name' => 'email'])
 | 
					    @include('form.text', ['name' => 'email'])
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@if($currentUser->can('user-update'))
 | 
					@if(userCan('users-manage'))
 | 
				
			||||||
    <div class="form-group">
 | 
					    <div class="form-group">
 | 
				
			||||||
        <label for="role">User Role</label>
 | 
					        <label for="role">User Role</label>
 | 
				
			||||||
        @include('form.role-select', ['name' => 'role', 'options' => \BookStack\Role::all(), 'displayKey' => 'display_name'])
 | 
					        @include('form/role-checkboxes', ['name' => 'roles', 'roles' => \BookStack\Role::all()])
 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
@endif
 | 
					@endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,7 +8,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    <div class="container small" ng-non-bindable>
 | 
					    <div class="container small" ng-non-bindable>
 | 
				
			||||||
        <h1>Users</h1>
 | 
					        <h1>Users</h1>
 | 
				
			||||||
        @if($currentUser->can('user-create'))
 | 
					        @if(userCan('users-manage'))
 | 
				
			||||||
            <p>
 | 
					            <p>
 | 
				
			||||||
                <a href="/settings/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>Add new user</a>
 | 
					                <a href="/settings/users/create" class="text-pos"><i class="zmdi zmdi-account-add"></i>Add new user</a>
 | 
				
			||||||
            </p>
 | 
					            </p>
 | 
				
			||||||
@@ -18,30 +18,32 @@
 | 
				
			|||||||
                <th></th>
 | 
					                <th></th>
 | 
				
			||||||
                <th>Name</th>
 | 
					                <th>Name</th>
 | 
				
			||||||
                <th>Email</th>
 | 
					                <th>Email</th>
 | 
				
			||||||
                <th>User Type</th>
 | 
					                <th>User Roles</th>
 | 
				
			||||||
            </tr>
 | 
					            </tr>
 | 
				
			||||||
            @foreach($users as $user)
 | 
					            @foreach($users as $user)
 | 
				
			||||||
                <tr>
 | 
					                <tr>
 | 
				
			||||||
                    <td style="line-height: 0;"><img class="avatar med" src="{{$user->getAvatar(40)}}" alt="{{$user->name}}"></td>
 | 
					                    <td style="line-height: 0;"><img class="avatar med" src="{{$user->getAvatar(40)}}" alt="{{$user->name}}"></td>
 | 
				
			||||||
                    <td>
 | 
					                    <td>
 | 
				
			||||||
                        @if($currentUser->can('user-update') || $currentUser->id == $user->id)
 | 
					                        @if(userCan('users-manage') || $currentUser->id == $user->id)
 | 
				
			||||||
                            <a href="/settings/users/{{$user->id}}">
 | 
					                            <a href="/settings/users/{{$user->id}}">
 | 
				
			||||||
                                @endif
 | 
					                                @endif
 | 
				
			||||||
                                {{ $user->name }}
 | 
					                                {{ $user->name }}
 | 
				
			||||||
                                @if($currentUser->can('user-update') || $currentUser->id == $user->id)
 | 
					                                @if(userCan('users-manage') || $currentUser->id == $user->id)
 | 
				
			||||||
                            </a>
 | 
					                            </a>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                    </td>
 | 
					                    </td>
 | 
				
			||||||
                    <td>
 | 
					                    <td>
 | 
				
			||||||
                        @if($currentUser->can('user-update') || $currentUser->id == $user->id)
 | 
					                        @if(userCan('users-manage') || $currentUser->id == $user->id)
 | 
				
			||||||
                            <a href="/settings/users/{{$user->id}}">
 | 
					                            <a href="/settings/users/{{$user->id}}">
 | 
				
			||||||
                                @endif
 | 
					                                @endif
 | 
				
			||||||
                                {{ $user->email }}
 | 
					                                {{ $user->email }}
 | 
				
			||||||
                                @if($currentUser->can('user-update') || $currentUser->id == $user->id)
 | 
					                                @if(userCan('users-manage') || $currentUser->id == $user->id)
 | 
				
			||||||
                            </a>
 | 
					                            </a>
 | 
				
			||||||
                        @endif
 | 
					                        @endif
 | 
				
			||||||
                    </td>
 | 
					                    </td>
 | 
				
			||||||
                    <td>{{ $user->role->display_name }}</td>
 | 
					                    <td>
 | 
				
			||||||
 | 
					                       <small> {{ $user->roles->implode('display_name', ', ') }}</small>
 | 
				
			||||||
 | 
					                    </td>
 | 
				
			||||||
                </tr>
 | 
					                </tr>
 | 
				
			||||||
            @endforeach
 | 
					            @endforeach
 | 
				
			||||||
        </table>
 | 
					        </table>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -133,12 +133,12 @@ class AuthTest extends TestCase
 | 
				
			|||||||
            ->click('Add new user')
 | 
					            ->click('Add new user')
 | 
				
			||||||
            ->type($user->name, '#name')
 | 
					            ->type($user->name, '#name')
 | 
				
			||||||
            ->type($user->email, '#email')
 | 
					            ->type($user->email, '#email')
 | 
				
			||||||
            ->select(2, '#role')
 | 
					            ->check('roles[admin]')
 | 
				
			||||||
            ->type($user->password, '#password')
 | 
					            ->type($user->password, '#password')
 | 
				
			||||||
            ->type($user->password, '#password-confirm')
 | 
					            ->type($user->password, '#password-confirm')
 | 
				
			||||||
            ->press('Save')
 | 
					            ->press('Save')
 | 
				
			||||||
            ->seeInDatabase('users', $user->toArray())
 | 
					 | 
				
			||||||
            ->seePageIs('/settings/users')
 | 
					            ->seePageIs('/settings/users')
 | 
				
			||||||
 | 
					            ->seeInDatabase('users', $user->toArray())
 | 
				
			||||||
            ->see($user->name);
 | 
					            ->see($user->name);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										407
									
								
								tests/RestrictionsTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										407
									
								
								tests/RestrictionsTest.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,407 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RestrictionsTest extends TestCase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $user;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setUp()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::setUp();
 | 
				
			||||||
 | 
					        $this->user = $this->getNewUser();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Manually set some restrictions on an entity.
 | 
				
			||||||
 | 
					     * @param \BookStack\Entity $entity
 | 
				
			||||||
 | 
					     * @param $actions
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected function setEntityRestrictions(\BookStack\Entity $entity, $actions)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $entity->restricted = true;
 | 
				
			||||||
 | 
					        $entity->restrictions()->delete();
 | 
				
			||||||
 | 
					        $role = $this->user->roles->first();
 | 
				
			||||||
 | 
					        foreach ($actions as $action) {
 | 
				
			||||||
 | 
					            $entity->restrictions()->create([
 | 
				
			||||||
 | 
					                'role_id' => $role->id,
 | 
				
			||||||
 | 
					                'action' => strtolower($action)
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        $entity->save();
 | 
				
			||||||
 | 
					        $entity->load('restrictions');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_book_view_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = \BookStack\Book::first();
 | 
				
			||||||
 | 
					        $bookPage = $book->pages->first();
 | 
				
			||||||
 | 
					        $bookChapter = $book->chapters->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $bookUrl = $book->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($bookUrl)
 | 
				
			||||||
 | 
					            ->seePageIs($bookUrl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($book, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($bookUrl)
 | 
				
			||||||
 | 
					            ->see('Book not found');
 | 
				
			||||||
 | 
					        $this->forceVisit($bookPage->getUrl())
 | 
				
			||||||
 | 
					            ->see('Book not found');
 | 
				
			||||||
 | 
					        $this->forceVisit($bookChapter->getUrl())
 | 
				
			||||||
 | 
					            ->see('Book not found');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($book, ['view']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($bookUrl)
 | 
				
			||||||
 | 
					            ->see($book->name);
 | 
				
			||||||
 | 
					        $this->visit($bookPage->getUrl())
 | 
				
			||||||
 | 
					            ->see($bookPage->name);
 | 
				
			||||||
 | 
					        $this->visit($bookChapter->getUrl())
 | 
				
			||||||
 | 
					            ->see($bookChapter->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_book_create_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = \BookStack\Book::first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $bookUrl = $book->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($bookUrl)
 | 
				
			||||||
 | 
					            ->seeInElement('.action-buttons', 'New Page')
 | 
				
			||||||
 | 
					            ->seeInElement('.action-buttons', 'New Chapter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($book, ['view', 'delete', 'update']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($bookUrl . '/chapter/create')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->forceVisit($bookUrl . '/page/create')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->visit($bookUrl)->dontSeeInElement('.action-buttons', 'New Page')
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.action-buttons', 'New Chapter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($book, ['view', 'create']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($bookUrl . '/chapter/create')
 | 
				
			||||||
 | 
					            ->type('test chapter', 'name')
 | 
				
			||||||
 | 
					            ->type('test description for chapter', 'description')
 | 
				
			||||||
 | 
					            ->press('Save Chapter')
 | 
				
			||||||
 | 
					            ->seePageIs($bookUrl . '/chapter/test-chapter');
 | 
				
			||||||
 | 
					        $this->visit($bookUrl . '/page/create')
 | 
				
			||||||
 | 
					            ->type('test page', 'name')
 | 
				
			||||||
 | 
					            ->type('test content', 'html')
 | 
				
			||||||
 | 
					            ->press('Save Page')
 | 
				
			||||||
 | 
					            ->seePageIs($bookUrl . '/page/test-page');
 | 
				
			||||||
 | 
					        $this->visit($bookUrl)->seeInElement('.action-buttons', 'New Page')
 | 
				
			||||||
 | 
					            ->seeInElement('.action-buttons', 'New Chapter');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_book_update_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = \BookStack\Book::first();
 | 
				
			||||||
 | 
					        $bookPage = $book->pages->first();
 | 
				
			||||||
 | 
					        $bookChapter = $book->chapters->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $bookUrl = $book->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($bookUrl . '/edit')
 | 
				
			||||||
 | 
					            ->see('Edit Book');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($book, ['view', 'delete']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($bookUrl . '/edit')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->forceVisit($bookPage->getUrl() . '/edit')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->forceVisit($bookChapter->getUrl() . '/edit')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($book, ['view', 'update']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($bookUrl . '/edit')
 | 
				
			||||||
 | 
					            ->seePageIs($bookUrl . '/edit');
 | 
				
			||||||
 | 
					        $this->visit($bookPage->getUrl() . '/edit')
 | 
				
			||||||
 | 
					            ->seePageIs($bookPage->getUrl() . '/edit');
 | 
				
			||||||
 | 
					        $this->visit($bookChapter->getUrl() . '/edit')
 | 
				
			||||||
 | 
					            ->see('Edit Chapter');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_book_delete_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = \BookStack\Book::first();
 | 
				
			||||||
 | 
					        $bookPage = $book->pages->first();
 | 
				
			||||||
 | 
					        $bookChapter = $book->chapters->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $bookUrl = $book->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($bookUrl . '/delete')
 | 
				
			||||||
 | 
					            ->see('Delete Book');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($book, ['view', 'update']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($bookUrl . '/delete')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->forceVisit($bookPage->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->forceVisit($bookChapter->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($book, ['view', 'delete']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($bookUrl . '/delete')
 | 
				
			||||||
 | 
					            ->seePageIs($bookUrl . '/delete')->see('Delete Book');
 | 
				
			||||||
 | 
					        $this->visit($bookPage->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->seePageIs($bookPage->getUrl() . '/delete')->see('Delete Page');
 | 
				
			||||||
 | 
					        $this->visit($bookChapter->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->see('Delete Chapter');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_view_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $chapter = \BookStack\Chapter::first();
 | 
				
			||||||
 | 
					        $chapterPage = $chapter->pages->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $chapterUrl = $chapter->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($chapterUrl)
 | 
				
			||||||
 | 
					            ->seePageIs($chapterUrl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($chapter, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($chapterUrl)
 | 
				
			||||||
 | 
					            ->see('Chapter not found');
 | 
				
			||||||
 | 
					        $this->forceVisit($chapterPage->getUrl())
 | 
				
			||||||
 | 
					            ->see('Page not found');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($chapter, ['view']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($chapterUrl)
 | 
				
			||||||
 | 
					            ->see($chapter->name);
 | 
				
			||||||
 | 
					        $this->visit($chapterPage->getUrl())
 | 
				
			||||||
 | 
					            ->see($chapterPage->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_create_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $chapter = \BookStack\Chapter::first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $chapterUrl = $chapter->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($chapterUrl)
 | 
				
			||||||
 | 
					            ->seeInElement('.action-buttons', 'New Page');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($chapter, ['view', 'delete', 'update']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($chapterUrl . '/create-page')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->visit($chapterUrl)->dontSeeInElement('.action-buttons', 'New Page');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($chapter, ['view', 'create']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($chapterUrl . '/create-page')
 | 
				
			||||||
 | 
					            ->type('test page', 'name')
 | 
				
			||||||
 | 
					            ->type('test content', 'html')
 | 
				
			||||||
 | 
					            ->press('Save Page')
 | 
				
			||||||
 | 
					            ->seePageIs($chapter->book->getUrl() . '/page/test-page');
 | 
				
			||||||
 | 
					        $this->visit($chapterUrl)->seeInElement('.action-buttons', 'New Page');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_update_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $chapter = \BookStack\Chapter::first();
 | 
				
			||||||
 | 
					        $chapterPage = $chapter->pages->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $chapterUrl = $chapter->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($chapterUrl . '/edit')
 | 
				
			||||||
 | 
					            ->see('Edit Chapter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($chapter, ['view', 'delete']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($chapterUrl . '/edit')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->forceVisit($chapterPage->getUrl() . '/edit')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($chapter, ['view', 'update']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($chapterUrl . '/edit')
 | 
				
			||||||
 | 
					            ->seePageIs($chapterUrl . '/edit')->see('Edit Chapter');
 | 
				
			||||||
 | 
					        $this->visit($chapterPage->getUrl() . '/edit')
 | 
				
			||||||
 | 
					            ->seePageIs($chapterPage->getUrl() . '/edit');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_delete_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $chapter = \BookStack\Chapter::first();
 | 
				
			||||||
 | 
					        $chapterPage = $chapter->pages->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $chapterUrl = $chapter->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($chapterUrl . '/delete')
 | 
				
			||||||
 | 
					            ->see('Delete Chapter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($chapter, ['view', 'update']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($chapterUrl . '/delete')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->forceVisit($chapterPage->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($chapter, ['view', 'delete']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($chapterUrl . '/delete')
 | 
				
			||||||
 | 
					            ->seePageIs($chapterUrl . '/delete')->see('Delete Chapter');
 | 
				
			||||||
 | 
					        $this->visit($chapterPage->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->seePageIs($chapterPage->getUrl() . '/delete')->see('Delete Page');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_view_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $page = \BookStack\Page::first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $pageUrl = $page->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($pageUrl)
 | 
				
			||||||
 | 
					            ->seePageIs($pageUrl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($page, ['update', 'delete']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($pageUrl)
 | 
				
			||||||
 | 
					            ->see('Page not found');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($page, ['view']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($pageUrl)
 | 
				
			||||||
 | 
					            ->see($page->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_update_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $page = \BookStack\Chapter::first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $pageUrl = $page->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($pageUrl . '/edit')
 | 
				
			||||||
 | 
					            ->seeInField('name', $page->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($page, ['view', 'delete']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($pageUrl . '/edit')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($page, ['view', 'update']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($pageUrl . '/edit')
 | 
				
			||||||
 | 
					            ->seePageIs($pageUrl . '/edit')->seeInField('name', $page->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_delete_restriction()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $page = \BookStack\Page::first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $pageUrl = $page->getUrl();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($pageUrl . '/delete')
 | 
				
			||||||
 | 
					            ->see('Delete Page');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($page, ['view', 'update']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->forceVisit($pageUrl . '/delete')
 | 
				
			||||||
 | 
					            ->see('You do not have permission')->seePageIs('/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($page, ['view', 'delete']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($pageUrl . '/delete')
 | 
				
			||||||
 | 
					            ->seePageIs($pageUrl . '/delete')->see('Delete Page');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_book_restriction_form()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = \BookStack\Book::first();
 | 
				
			||||||
 | 
					        $this->asAdmin()->visit($book->getUrl() . '/restrict')
 | 
				
			||||||
 | 
					            ->see('Book Restrictions')
 | 
				
			||||||
 | 
					            ->check('restricted')
 | 
				
			||||||
 | 
					            ->check('restrictions[2][view]')
 | 
				
			||||||
 | 
					            ->press('Save Restrictions')
 | 
				
			||||||
 | 
					            ->seeInDatabase('books', ['id' => $book->id, 'restricted' => true])
 | 
				
			||||||
 | 
					            ->seeInDatabase('restrictions', [
 | 
				
			||||||
 | 
					                'restrictable_id' => $book->id,
 | 
				
			||||||
 | 
					                'restrictable_type' => 'BookStack\Book',
 | 
				
			||||||
 | 
					                'role_id' => '2',
 | 
				
			||||||
 | 
					                'action' => 'view'
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_restriction_form()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $chapter = \BookStack\Chapter::first();
 | 
				
			||||||
 | 
					        $this->asAdmin()->visit($chapter->getUrl() . '/restrict')
 | 
				
			||||||
 | 
					            ->see('Chapter Restrictions')
 | 
				
			||||||
 | 
					            ->check('restricted')
 | 
				
			||||||
 | 
					            ->check('restrictions[2][update]')
 | 
				
			||||||
 | 
					            ->press('Save Restrictions')
 | 
				
			||||||
 | 
					            ->seeInDatabase('chapters', ['id' => $chapter->id, 'restricted' => true])
 | 
				
			||||||
 | 
					            ->seeInDatabase('restrictions', [
 | 
				
			||||||
 | 
					                'restrictable_id' => $chapter->id,
 | 
				
			||||||
 | 
					                'restrictable_type' => 'BookStack\Chapter',
 | 
				
			||||||
 | 
					                'role_id' => '2',
 | 
				
			||||||
 | 
					                'action' => 'update'
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_restriction_form()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $page = \BookStack\Page::first();
 | 
				
			||||||
 | 
					        $this->asAdmin()->visit($page->getUrl() . '/restrict')
 | 
				
			||||||
 | 
					            ->see('Page Restrictions')
 | 
				
			||||||
 | 
					            ->check('restricted')
 | 
				
			||||||
 | 
					            ->check('restrictions[2][delete]')
 | 
				
			||||||
 | 
					            ->press('Save Restrictions')
 | 
				
			||||||
 | 
					            ->seeInDatabase('pages', ['id' => $page->id, 'restricted' => true])
 | 
				
			||||||
 | 
					            ->seeInDatabase('restrictions', [
 | 
				
			||||||
 | 
					                'restrictable_id' => $page->id,
 | 
				
			||||||
 | 
					                'restrictable_type' => 'BookStack\Page',
 | 
				
			||||||
 | 
					                'role_id' => '2',
 | 
				
			||||||
 | 
					                'action' => 'delete'
 | 
				
			||||||
 | 
					            ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_restricted_pages_not_visible_in_book_navigation_on_pages()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $chapter = \BookStack\Chapter::first();
 | 
				
			||||||
 | 
					        $page = $chapter->pages->first();
 | 
				
			||||||
 | 
					        $page2 = $chapter->pages[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($page, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($page2->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.sidebar-page-list', $page->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_restricted_pages_not_visible_in_book_navigation_on_chapters()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $chapter = \BookStack\Chapter::first();
 | 
				
			||||||
 | 
					        $page = $chapter->pages->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($page, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($chapter->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.sidebar-page-list', $page->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_restricted_pages_not_visible_on_chapter_pages()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $chapter = \BookStack\Chapter::first();
 | 
				
			||||||
 | 
					        $page = $chapter->pages->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->setEntityRestrictions($page, []);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)
 | 
				
			||||||
 | 
					            ->visit($chapter->getUrl())
 | 
				
			||||||
 | 
					            ->dontSee($page->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										510
									
								
								tests/RolesTest.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								tests/RolesTest.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,510 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class RolesTest extends TestCase
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $user;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function setUp()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        parent::setUp();
 | 
				
			||||||
 | 
					        $this->user = $this->getNewBlankUser();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Give the given user some permissions.
 | 
				
			||||||
 | 
					     * @param \BookStack\User $user
 | 
				
			||||||
 | 
					     * @param array $permissions
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected function giveUserPermissions(\BookStack\User $user, $permissions = [])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $newRole = $this->createNewRole($permissions);
 | 
				
			||||||
 | 
					        $user->attachRole($newRole);
 | 
				
			||||||
 | 
					        $user->load('roles');
 | 
				
			||||||
 | 
					        $user->permissions(false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Create a new basic role for testing purposes.
 | 
				
			||||||
 | 
					     * @param array $permissions
 | 
				
			||||||
 | 
					     * @return static
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected function createNewRole($permissions = [])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $permissionRepo = app('BookStack\Repos\PermissionsRepo');
 | 
				
			||||||
 | 
					        $roleData = factory(\BookStack\Role::class)->make()->toArray();
 | 
				
			||||||
 | 
					        $roleData['permissions'] = array_flip($permissions);
 | 
				
			||||||
 | 
					        return $permissionRepo->saveNewRole($roleData);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_admin_can_see_settings()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->asAdmin()->visit('/settings')->see('Settings');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_cannot_delete_admin_role()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $adminRole = \BookStack\Role::getRole('admin');
 | 
				
			||||||
 | 
					        $deletePageUrl = '/settings/roles/delete/' . $adminRole->id;
 | 
				
			||||||
 | 
					        $this->asAdmin()->visit($deletePageUrl)
 | 
				
			||||||
 | 
					            ->press('Confirm')
 | 
				
			||||||
 | 
					            ->seePageIs($deletePageUrl)
 | 
				
			||||||
 | 
					            ->see('cannot be deleted');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_role_cannot_be_deleted_if_default()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $newRole = $this->createNewRole();
 | 
				
			||||||
 | 
					        $this->setSettings(['registration-role' => $newRole->id]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $deletePageUrl = '/settings/roles/delete/' . $newRole->id;
 | 
				
			||||||
 | 
					        $this->asAdmin()->visit($deletePageUrl)
 | 
				
			||||||
 | 
					            ->press('Confirm')
 | 
				
			||||||
 | 
					            ->seePageIs($deletePageUrl)
 | 
				
			||||||
 | 
					            ->see('cannot be deleted');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_role_create_update_delete_flow()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $testRoleName = 'Test Role';
 | 
				
			||||||
 | 
					        $testRoleDesc = 'a little test description';
 | 
				
			||||||
 | 
					        $testRoleUpdateName = 'An Super Updated role';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Creation
 | 
				
			||||||
 | 
					        $this->asAdmin()->visit('/settings')
 | 
				
			||||||
 | 
					            ->click('Roles')
 | 
				
			||||||
 | 
					            ->seePageIs('/settings/roles')
 | 
				
			||||||
 | 
					            ->click('Add new role')
 | 
				
			||||||
 | 
					            ->type('Test Role', 'display_name')
 | 
				
			||||||
 | 
					            ->type('A little test description', 'description')
 | 
				
			||||||
 | 
					            ->press('Save Role')
 | 
				
			||||||
 | 
					            ->seeInDatabase('roles', ['display_name' => $testRoleName, 'name' => 'test-role', 'description' => $testRoleDesc])
 | 
				
			||||||
 | 
					            ->seePageIs('/settings/roles');
 | 
				
			||||||
 | 
					        // Updating
 | 
				
			||||||
 | 
					        $this->asAdmin()->visit('/settings/roles')
 | 
				
			||||||
 | 
					            ->see($testRoleDesc)
 | 
				
			||||||
 | 
					            ->click($testRoleName)
 | 
				
			||||||
 | 
					            ->type($testRoleUpdateName, '#display_name')
 | 
				
			||||||
 | 
					            ->press('Save Role')
 | 
				
			||||||
 | 
					            ->seeInDatabase('roles', ['display_name' => $testRoleUpdateName, 'name' => 'test-role', 'description' => $testRoleDesc])
 | 
				
			||||||
 | 
					            ->seePageIs('/settings/roles');
 | 
				
			||||||
 | 
					        // Deleting
 | 
				
			||||||
 | 
					        $this->asAdmin()->visit('/settings/roles')
 | 
				
			||||||
 | 
					            ->click($testRoleUpdateName)
 | 
				
			||||||
 | 
					            ->click('Delete Role')
 | 
				
			||||||
 | 
					            ->see($testRoleUpdateName)
 | 
				
			||||||
 | 
					            ->press('Confirm')
 | 
				
			||||||
 | 
					            ->seePageIs('/settings/roles')
 | 
				
			||||||
 | 
					            ->dontSee($testRoleUpdateName);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_manage_user_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit('/')->visit('/settings/users')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['users-manage']);
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit('/')->visit('/settings/users')
 | 
				
			||||||
 | 
					            ->seePageIs('/settings/users');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_user_roles_manage_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit('/')->visit('/settings/roles')
 | 
				
			||||||
 | 
					            ->seePageIs('/')->visit('/settings/roles/1')->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['user-roles-manage']);
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit('/settings/roles')
 | 
				
			||||||
 | 
					            ->seePageIs('/settings/roles')->click('Admin')
 | 
				
			||||||
 | 
					            ->see('Edit Role');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_settings_manage_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit('/')->visit('/settings')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['settings-manage']);
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit('/')->visit('/settings')
 | 
				
			||||||
 | 
					            ->seePageIs('/settings')->press('Save Settings')->see('Settings Saved');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_restrictions_manage_all_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $page = \BookStack\Page::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit($page->getUrl())
 | 
				
			||||||
 | 
					            ->dontSee('Restrict')
 | 
				
			||||||
 | 
					            ->visit($page->getUrl() . '/restrict')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['restrictions-manage-all']);
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit($page->getUrl())
 | 
				
			||||||
 | 
					            ->see('Restrict')
 | 
				
			||||||
 | 
					            ->click('Restrict')
 | 
				
			||||||
 | 
					            ->see('Page Restrictions')->seePageIs($page->getUrl() . '/restrict');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_restrictions_manage_own_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $otherUsersPage = \BookStack\Page::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $content = $this->createEntityChainBelongingToUser($this->user);
 | 
				
			||||||
 | 
					        // Check can't restrict other's content
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit($otherUsersPage->getUrl())
 | 
				
			||||||
 | 
					            ->dontSee('Restrict')
 | 
				
			||||||
 | 
					            ->visit($otherUsersPage->getUrl() . '/restrict')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					        // Check can't restrict own content
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit($content['page']->getUrl())
 | 
				
			||||||
 | 
					            ->dontSee('Restrict')
 | 
				
			||||||
 | 
					            ->visit($content['page']->getUrl() . '/restrict')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['restrictions-manage-own']);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check can't restrict other's content
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit($otherUsersPage->getUrl())
 | 
				
			||||||
 | 
					            ->dontSee('Restrict')
 | 
				
			||||||
 | 
					            ->visit($otherUsersPage->getUrl() . '/restrict')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					        // Check can restrict own content
 | 
				
			||||||
 | 
					        $this->actingAs($this->user)->visit($content['page']->getUrl())
 | 
				
			||||||
 | 
					            ->see('Restrict')
 | 
				
			||||||
 | 
					            ->click('Restrict')
 | 
				
			||||||
 | 
					            ->seePageIs($content['page']->getUrl() . '/restrict');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Check a standard entity access permission
 | 
				
			||||||
 | 
					     * @param string $permission
 | 
				
			||||||
 | 
					     * @param array $accessUrls Urls that are only accessible after having the permission
 | 
				
			||||||
 | 
					     * @param array $visibles Check this text, In the buttons toolbar, is only visible with the permission
 | 
				
			||||||
 | 
					     * @param null $callback
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private function checkAccessPermission($permission, $accessUrls = [], $visibles = [])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        foreach ($accessUrls as $url) {
 | 
				
			||||||
 | 
					            $this->actingAs($this->user)->visit('/')->visit($url)
 | 
				
			||||||
 | 
					                ->seePageIs('/');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        foreach ($visibles as $url => $text) {
 | 
				
			||||||
 | 
					            $this->actingAs($this->user)->visit('/')->visit($url)
 | 
				
			||||||
 | 
					                ->dontSeeInElement('.action-buttons',$text);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, [$permission]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        foreach ($accessUrls as $url) {
 | 
				
			||||||
 | 
					            $this->actingAs($this->user)->visit('/')->visit($url)
 | 
				
			||||||
 | 
					                ->seePageIs($url);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        foreach ($visibles as $url => $text) {
 | 
				
			||||||
 | 
					            $this->actingAs($this->user)->visit('/')->visit($url)
 | 
				
			||||||
 | 
					                ->see($text);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_books_create_all_permissions()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('book-create-all', [
 | 
				
			||||||
 | 
					            '/books/create'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            '/books' => 'Add new book'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit('/books/create')
 | 
				
			||||||
 | 
					            ->type('test book', 'name')
 | 
				
			||||||
 | 
					            ->type('book desc', 'description')
 | 
				
			||||||
 | 
					            ->press('Save Book')
 | 
				
			||||||
 | 
					            ->seePageIs('/books/test-book');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_books_edit_own_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $otherBook = \BookStack\Book::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('book-update-own', [
 | 
				
			||||||
 | 
					            $ownBook->getUrl() . '/edit'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $ownBook->getUrl() => 'Edit'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($otherBook->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.action-buttons', 'Edit')
 | 
				
			||||||
 | 
					            ->visit($otherBook->getUrl() . '/edit')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_books_edit_all_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $otherBook = \BookStack\Book::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('book-update-all', [
 | 
				
			||||||
 | 
					            $otherBook->getUrl() . '/edit'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $otherBook->getUrl() => 'Edit'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_books_delete_own_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['book-update-all']);
 | 
				
			||||||
 | 
					        $otherBook = \BookStack\Book::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('book-delete-own', [
 | 
				
			||||||
 | 
					            $ownBook->getUrl() . '/delete'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $ownBook->getUrl() => 'Delete'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($otherBook->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.action-buttons', 'Delete')
 | 
				
			||||||
 | 
					            ->visit($otherBook->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->visit($ownBook->getUrl())->visit($ownBook->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->press('Confirm')
 | 
				
			||||||
 | 
					            ->seePageIs('/books')
 | 
				
			||||||
 | 
					            ->dontSee($ownBook->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_books_delete_all_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['book-update-all']);
 | 
				
			||||||
 | 
					        $otherBook = \BookStack\Book::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('book-delete-all', [
 | 
				
			||||||
 | 
					            $otherBook->getUrl() . '/delete'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $otherBook->getUrl() => 'Delete'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($otherBook->getUrl())->visit($otherBook->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->press('Confirm')
 | 
				
			||||||
 | 
					            ->seePageIs('/books')
 | 
				
			||||||
 | 
					            ->dontSee($otherBook->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_create_own_permissions()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = \BookStack\Book::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $ownBook = $this->createEntityChainBelongingToUser($this->user)['book'];
 | 
				
			||||||
 | 
					        $baseUrl = $ownBook->getUrl() . '/chapter';
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('chapter-create-own', [
 | 
				
			||||||
 | 
					            $baseUrl . '/create'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $ownBook->getUrl() => 'New Chapter'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($baseUrl . '/create')
 | 
				
			||||||
 | 
					            ->type('test chapter', 'name')
 | 
				
			||||||
 | 
					            ->type('chapter desc', 'description')
 | 
				
			||||||
 | 
					            ->press('Save Chapter')
 | 
				
			||||||
 | 
					            ->seePageIs($baseUrl . '/test-chapter');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($book->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.action-buttons', 'New Chapter')
 | 
				
			||||||
 | 
					            ->visit($book->getUrl() . '/chapter/create')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_create_all_permissions()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = \BookStack\Book::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $baseUrl = $book->getUrl() . '/chapter';
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('chapter-create-all', [
 | 
				
			||||||
 | 
					            $baseUrl . '/create'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $book->getUrl() => 'New Chapter'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($baseUrl . '/create')
 | 
				
			||||||
 | 
					            ->type('test chapter', 'name')
 | 
				
			||||||
 | 
					            ->type('chapter desc', 'description')
 | 
				
			||||||
 | 
					            ->press('Save Chapter')
 | 
				
			||||||
 | 
					            ->seePageIs($baseUrl . '/test-chapter');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_edit_own_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $otherChapter = \BookStack\Chapter::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $ownChapter = $this->createEntityChainBelongingToUser($this->user)['chapter'];
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('chapter-update-own', [
 | 
				
			||||||
 | 
					            $ownChapter->getUrl() . '/edit'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $ownChapter->getUrl() => 'Edit'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($otherChapter->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.action-buttons', 'Edit')
 | 
				
			||||||
 | 
					            ->visit($otherChapter->getUrl() . '/edit')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_edit_all_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $otherChapter = \BookStack\Chapter::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('chapter-update-all', [
 | 
				
			||||||
 | 
					            $otherChapter->getUrl() . '/edit'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $otherChapter->getUrl() => 'Edit'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_delete_own_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['chapter-update-all']);
 | 
				
			||||||
 | 
					        $otherChapter = \BookStack\Chapter::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $ownChapter = $this->createEntityChainBelongingToUser($this->user)['chapter'];
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('chapter-delete-own', [
 | 
				
			||||||
 | 
					            $ownChapter->getUrl() . '/delete'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $ownChapter->getUrl() => 'Delete'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $bookUrl = $ownChapter->book->getUrl();
 | 
				
			||||||
 | 
					        $this->visit($otherChapter->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.action-buttons', 'Delete')
 | 
				
			||||||
 | 
					            ->visit($otherChapter->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->visit($ownChapter->getUrl())->visit($ownChapter->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->press('Confirm')
 | 
				
			||||||
 | 
					            ->seePageIs($bookUrl)
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.book-content', $ownChapter->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_chapter_delete_all_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['chapter-update-all']);
 | 
				
			||||||
 | 
					        $otherChapter = \BookStack\Chapter::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('chapter-delete-all', [
 | 
				
			||||||
 | 
					            $otherChapter->getUrl() . '/delete'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $otherChapter->getUrl() => 'Delete'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $bookUrl = $otherChapter->book->getUrl();
 | 
				
			||||||
 | 
					        $this->visit($otherChapter->getUrl())->visit($otherChapter->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->press('Confirm')
 | 
				
			||||||
 | 
					            ->seePageIs($bookUrl)
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.book-content', $otherChapter->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_create_own_permissions()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = \BookStack\Book::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $chapter = \BookStack\Chapter::take(1)->get()->first();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $entities = $this->createEntityChainBelongingToUser($this->user);
 | 
				
			||||||
 | 
					        $ownBook = $entities['book'];
 | 
				
			||||||
 | 
					        $ownChapter = $entities['chapter'];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $baseUrl = $ownBook->getUrl() . '/page';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('page-create-own', [
 | 
				
			||||||
 | 
					            $baseUrl . '/create',
 | 
				
			||||||
 | 
					            $ownChapter->getUrl() . '/create-page'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $ownBook->getUrl() => 'New Page',
 | 
				
			||||||
 | 
					            $ownChapter->getUrl() => 'New Page'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($baseUrl . '/create')
 | 
				
			||||||
 | 
					            ->type('test page', 'name')
 | 
				
			||||||
 | 
					            ->type('page desc', 'html')
 | 
				
			||||||
 | 
					            ->press('Save Page')
 | 
				
			||||||
 | 
					            ->seePageIs($baseUrl . '/test-page');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($book->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.action-buttons', 'New Page')
 | 
				
			||||||
 | 
					            ->visit($book->getUrl() . '/page/create')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->visit($chapter->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.action-buttons', 'New Page')
 | 
				
			||||||
 | 
					            ->visit($chapter->getUrl() . '/create-page')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_create_all_permissions()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $book = \BookStack\Book::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $chapter = \BookStack\Chapter::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $baseUrl = $book->getUrl() . '/page';
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('page-create-all', [
 | 
				
			||||||
 | 
					            $baseUrl . '/create',
 | 
				
			||||||
 | 
					            $chapter->getUrl() . '/create-page'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $book->getUrl() => 'New Page',
 | 
				
			||||||
 | 
					            $chapter->getUrl() => 'New Page'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($baseUrl . '/create')
 | 
				
			||||||
 | 
					            ->type('test page', 'name')
 | 
				
			||||||
 | 
					            ->type('page desc', 'html')
 | 
				
			||||||
 | 
					            ->press('Save Page')
 | 
				
			||||||
 | 
					            ->seePageIs($baseUrl . '/test-page');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($chapter->getUrl() . '/create-page')
 | 
				
			||||||
 | 
					            ->type('new test page', 'name')
 | 
				
			||||||
 | 
					            ->type('page desc', 'html')
 | 
				
			||||||
 | 
					            ->press('Save Page')
 | 
				
			||||||
 | 
					            ->seePageIs($baseUrl . '/new-test-page');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_edit_own_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $otherPage = \BookStack\Page::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('page-update-own', [
 | 
				
			||||||
 | 
					            $ownPage->getUrl() . '/edit'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $ownPage->getUrl() => 'Edit'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->visit($otherPage->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.action-buttons', 'Edit')
 | 
				
			||||||
 | 
					            ->visit($otherPage->getUrl() . '/edit')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_edit_all_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $otherPage = \BookStack\Page::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('page-update-all', [
 | 
				
			||||||
 | 
					            $otherPage->getUrl() . '/edit'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $otherPage->getUrl() => 'Edit'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_delete_own_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['page-update-all']);
 | 
				
			||||||
 | 
					        $otherPage = \BookStack\Page::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $ownPage = $this->createEntityChainBelongingToUser($this->user)['page'];
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('page-delete-own', [
 | 
				
			||||||
 | 
					            $ownPage->getUrl() . '/delete'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $ownPage->getUrl() => 'Delete'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $bookUrl = $ownPage->book->getUrl();
 | 
				
			||||||
 | 
					        $this->visit($otherPage->getUrl())
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.action-buttons', 'Delete')
 | 
				
			||||||
 | 
					            ->visit($otherPage->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->seePageIs('/');
 | 
				
			||||||
 | 
					        $this->visit($ownPage->getUrl())->visit($ownPage->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->press('Confirm')
 | 
				
			||||||
 | 
					            ->seePageIs($bookUrl)
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.book-content', $ownPage->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_page_delete_all_permission()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->giveUserPermissions($this->user, ['page-update-all']);
 | 
				
			||||||
 | 
					        $otherPage = \BookStack\Page::take(1)->get()->first();
 | 
				
			||||||
 | 
					        $this->checkAccessPermission('page-delete-all', [
 | 
				
			||||||
 | 
					            $otherPage->getUrl() . '/delete'
 | 
				
			||||||
 | 
					        ], [
 | 
				
			||||||
 | 
					            $otherPage->getUrl() => 'Delete'
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $bookUrl = $otherPage->book->getUrl();
 | 
				
			||||||
 | 
					        $this->visit($otherPage->getUrl())->visit($otherPage->getUrl() . '/delete')
 | 
				
			||||||
 | 
					            ->press('Confirm')
 | 
				
			||||||
 | 
					            ->seePageIs($bookUrl)
 | 
				
			||||||
 | 
					            ->dontSeeInElement('.book-content', $otherPage->name);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
<?php
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use Illuminate\Foundation\Testing\DatabaseTransactions;
 | 
					use Illuminate\Foundation\Testing\DatabaseTransactions;
 | 
				
			||||||
 | 
					use Symfony\Component\DomCrawler\Crawler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TestCase extends Illuminate\Foundation\Testing\TestCase
 | 
					class TestCase extends Illuminate\Foundation\Testing\TestCase
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@@ -32,7 +33,8 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
 | 
				
			|||||||
    public function asAdmin()
 | 
					    public function asAdmin()
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if($this->admin === null) {
 | 
					        if($this->admin === null) {
 | 
				
			||||||
            $this->admin = \BookStack\User::find(1);
 | 
					            $adminRole = \BookStack\Role::getRole('admin');
 | 
				
			||||||
 | 
					            $this->admin = $adminRole->users->first();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return $this->actingAs($this->admin);
 | 
					        return $this->actingAs($this->admin);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -78,8 +80,19 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
 | 
				
			|||||||
    protected function getNewUser($attributes = [])
 | 
					    protected function getNewUser($attributes = [])
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        $user = factory(\BookStack\User::class)->create($attributes);
 | 
					        $user = factory(\BookStack\User::class)->create($attributes);
 | 
				
			||||||
        $userRepo = app('BookStack\Repos\UserRepo');
 | 
					        $role = \BookStack\Role::getRole('editor');
 | 
				
			||||||
        $userRepo->attachDefaultRole($user);
 | 
					        $user->attachRole($role);;
 | 
				
			||||||
 | 
					        return $user;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Quick way to create a new user without any permissions
 | 
				
			||||||
 | 
					     * @param array $attributes
 | 
				
			||||||
 | 
					     * @return mixed
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected function getNewBlankUser($attributes = [])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $user = factory(\BookStack\User::class)->create($attributes);
 | 
				
			||||||
        return $user;
 | 
					        return $user;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -110,6 +123,40 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
 | 
				
			|||||||
        return $this;
 | 
					        return $this;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Assert that the current page matches a given URI.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param  string  $uri
 | 
				
			||||||
 | 
					     * @return $this
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected function seePageUrlIs($uri)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->assertEquals(
 | 
				
			||||||
 | 
					            $uri, $this->currentUri, "Did not land on expected page [{$uri}].\n"
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Do a forced visit that does not error out on exception.
 | 
				
			||||||
 | 
					     * @param string $uri
 | 
				
			||||||
 | 
					     * @param array $parameters
 | 
				
			||||||
 | 
					     * @param array $cookies
 | 
				
			||||||
 | 
					     * @param array $files
 | 
				
			||||||
 | 
					     * @return $this
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    protected function forceVisit($uri, $parameters = [], $cookies = [], $files = [])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $method = 'GET';
 | 
				
			||||||
 | 
					        $uri = $this->prepareUrlForRequest($uri);
 | 
				
			||||||
 | 
					        $this->call($method, $uri, $parameters, $cookies, $files);
 | 
				
			||||||
 | 
					        $this->clearInputs()->followRedirects();
 | 
				
			||||||
 | 
					        $this->currentUri = $this->app->make('request')->fullUrl();
 | 
				
			||||||
 | 
					        $this->crawler = new Crawler($this->response->getContent(), $uri);
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Click the text within the selected element.
 | 
					     * Click the text within the selected element.
 | 
				
			||||||
     * @param $parentElement
 | 
					     * @param $parentElement
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user