2016-02-29 03:03:04 +08:00
< ? php namespace BookStack\Services ;
2016-04-21 04:37:57 +08:00
use BookStack\Book ;
use BookStack\Chapter ;
2016-03-01 04:31:21 +08:00
use BookStack\Entity ;
2016-05-02 04:20:50 +08:00
use BookStack\JointPermission ;
2016-07-02 03:11:49 +08:00
use BookStack\Ownable ;
2016-04-21 04:37:57 +08:00
use BookStack\Page ;
use BookStack\Role ;
2016-04-27 04:48:17 +08:00
use BookStack\User ;
2017-01-02 05:21:11 +08:00
use Illuminate\Database\Connection ;
2017-01-02 00:05:44 +08:00
use Illuminate\Database\Eloquent\Builder ;
2016-08-27 03:20:58 +08:00
use Illuminate\Support\Collection ;
2016-03-01 04:31:21 +08:00
2016-05-02 04:20:50 +08:00
class PermissionService
2016-02-29 03:03:04 +08:00
{
protected $currentAction ;
2016-09-18 01:22:04 +08:00
protected $isAdminUser ;
protected $userRoles = false ;
protected $currentUserModel = false ;
2016-02-29 03:03:04 +08:00
2016-04-21 04:37:57 +08:00
public $book ;
public $chapter ;
public $page ;
2017-01-02 05:21:11 +08:00
protected $db ;
2016-05-02 04:20:50 +08:00
protected $jointPermission ;
2016-04-21 04:37:57 +08:00
protected $role ;
2016-04-24 01:14:26 +08:00
2016-08-27 03:20:58 +08:00
protected $entityCache ;
2016-02-29 03:03:04 +08:00
/**
2016-05-02 04:20:50 +08:00
* PermissionService constructor .
* @ param JointPermission $jointPermission
2017-01-02 05:21:11 +08:00
* @ param Connection $db
2016-04-21 04:37:57 +08:00
* @ param Book $book
* @ param Chapter $chapter
* @ param Page $page
* @ param Role $role
2016-02-29 03:03:04 +08:00
*/
2017-01-02 05:21:11 +08:00
public function __construct ( JointPermission $jointPermission , Connection $db , Book $book , Chapter $chapter , Page $page , Role $role )
2016-02-29 03:03:04 +08:00
{
2017-01-02 05:21:11 +08:00
$this -> db = $db ;
2016-05-02 04:20:50 +08:00
$this -> jointPermission = $jointPermission ;
2016-04-21 04:37:57 +08:00
$this -> role = $role ;
$this -> book = $book ;
$this -> chapter = $chapter ;
$this -> page = $page ;
2017-01-02 05:21:11 +08:00
// TODO - Update so admin still goes through filters
2016-04-21 04:37:57 +08:00
}
2016-08-27 03:20:58 +08:00
/**
* Prepare the local entity cache and ensure it ' s empty
*/
protected function readyEntityCache ()
{
$this -> entityCache = [
'books' => collect (),
'chapters' => collect ()
];
}
/**
* Get a book via ID , Checks local cache
* @ param $bookId
* @ return Book
*/
protected function getBook ( $bookId )
{
if ( isset ( $this -> entityCache [ 'books' ]) && $this -> entityCache [ 'books' ] -> has ( $bookId )) {
return $this -> entityCache [ 'books' ] -> get ( $bookId );
}
$book = $this -> book -> find ( $bookId );
if ( $book === null ) $book = false ;
if ( isset ( $this -> entityCache [ 'books' ])) {
$this -> entityCache [ 'books' ] -> put ( $bookId , $book );
}
return $book ;
}
/**
* Get a chapter via ID , Checks local cache
* @ param $chapterId
* @ return Book
*/
protected function getChapter ( $chapterId )
{
if ( isset ( $this -> entityCache [ 'chapters' ]) && $this -> entityCache [ 'chapters' ] -> has ( $chapterId )) {
return $this -> entityCache [ 'chapters' ] -> get ( $chapterId );
}
$chapter = $this -> chapter -> find ( $chapterId );
if ( $chapter === null ) $chapter = false ;
if ( isset ( $this -> entityCache [ 'chapters' ])) {
$this -> entityCache [ 'chapters' ] -> put ( $chapterId , $chapter );
}
return $chapter ;
}
2016-05-02 02:36:53 +08:00
/**
* Get the roles for the current user ;
* @ return array | bool
*/
protected function getRoles ()
{
if ( $this -> userRoles !== false ) return $this -> userRoles ;
$roles = [];
if ( auth () -> guest ()) {
$roles [] = $this -> role -> getSystemRole ( 'public' ) -> id ;
return $roles ;
}
2016-09-18 01:22:04 +08:00
foreach ( $this -> currentUser () -> roles as $role ) {
2016-05-02 02:36:53 +08:00
$roles [] = $role -> id ;
}
return $roles ;
}
2016-04-21 04:37:57 +08:00
/**
* Re - generate all entity permission from scratch .
*/
2016-05-02 04:20:50 +08:00
public function buildJointPermissions ()
2016-04-21 04:37:57 +08:00
{
2016-05-02 04:20:50 +08:00
$this -> jointPermission -> truncate ();
2016-08-27 03:20:58 +08:00
$this -> readyEntityCache ();
2016-04-21 04:37:57 +08:00
// Get all roles (Should be the most limited dimension)
2016-05-01 00:16:06 +08:00
$roles = $this -> role -> with ( 'permissions' ) -> get ();
2016-04-21 04:37:57 +08:00
// Chunk through all books
2016-05-02 04:20:50 +08:00
$this -> book -> with ( 'permissions' ) -> chunk ( 500 , function ( $books ) use ( $roles ) {
$this -> createManyJointPermissions ( $books , $roles );
2016-04-21 04:37:57 +08:00
});
// Chunk through all chapters
2016-05-02 04:20:50 +08:00
$this -> chapter -> with ( 'book' , 'permissions' ) -> chunk ( 500 , function ( $chapters ) use ( $roles ) {
$this -> createManyJointPermissions ( $chapters , $roles );
2016-04-21 04:37:57 +08:00
});
// Chunk through all pages
2016-05-02 04:20:50 +08:00
$this -> page -> with ( 'book' , 'chapter' , 'permissions' ) -> chunk ( 500 , function ( $pages ) use ( $roles ) {
$this -> createManyJointPermissions ( $pages , $roles );
2016-04-21 04:37:57 +08:00
});
}
2016-04-24 23:54:20 +08:00
/**
2016-08-27 03:20:58 +08:00
* Rebuild the entity jointPermissions for a particular entity .
2016-04-24 23:54:20 +08:00
* @ param Entity $entity
*/
2016-05-02 04:20:50 +08:00
public function buildJointPermissionsForEntity ( Entity $entity )
2016-04-24 23:54:20 +08:00
{
2017-01-22 00:16:27 +08:00
$roles = $this -> role -> get ();
2016-04-24 23:54:20 +08:00
$entities = collect ([ $entity ]);
if ( $entity -> isA ( 'book' )) {
$entities = $entities -> merge ( $entity -> chapters );
$entities = $entities -> merge ( $entity -> pages );
} elseif ( $entity -> isA ( 'chapter' )) {
$entities = $entities -> merge ( $entity -> pages );
}
2016-05-02 04:20:50 +08:00
$this -> deleteManyJointPermissionsForEntities ( $entities );
$this -> createManyJointPermissions ( $entities , $roles );
2016-04-24 23:54:20 +08:00
}
2016-08-27 03:20:58 +08:00
/**
* Rebuild the entity jointPermissions for a collection of entities .
* @ param Collection $entities
*/
public function buildJointPermissionsForEntities ( Collection $entities )
{
2017-01-22 00:16:27 +08:00
$roles = $this -> role -> get ();
2016-08-27 03:20:58 +08:00
$this -> deleteManyJointPermissionsForEntities ( $entities );
$this -> createManyJointPermissions ( $entities , $roles );
}
2016-04-24 23:54:20 +08:00
/**
2016-05-02 04:20:50 +08:00
* Build the entity jointPermissions for a particular role .
2016-04-24 23:54:20 +08:00
* @ param Role $role
*/
2016-05-02 04:20:50 +08:00
public function buildJointPermissionForRole ( Role $role )
2016-04-24 23:54:20 +08:00
{
$roles = collect ([ $role ]);
2016-05-02 04:20:50 +08:00
$this -> deleteManyJointPermissionsForRoles ( $roles );
2016-04-24 23:54:20 +08:00
// Chunk through all books
2016-05-02 04:20:50 +08:00
$this -> book -> with ( 'permissions' ) -> chunk ( 500 , function ( $books ) use ( $roles ) {
$this -> createManyJointPermissions ( $books , $roles );
2016-04-24 23:54:20 +08:00
});
// Chunk through all chapters
2016-05-02 04:20:50 +08:00
$this -> chapter -> with ( 'book' , 'permissions' ) -> chunk ( 500 , function ( $books ) use ( $roles ) {
$this -> createManyJointPermissions ( $books , $roles );
2016-04-24 23:54:20 +08:00
});
// Chunk through all pages
2016-05-02 04:20:50 +08:00
$this -> page -> with ( 'book' , 'chapter' , 'permissions' ) -> chunk ( 500 , function ( $books ) use ( $roles ) {
$this -> createManyJointPermissions ( $books , $roles );
2016-04-24 23:54:20 +08:00
});
}
/**
2016-05-02 04:20:50 +08:00
* Delete the entity jointPermissions attached to a particular role .
2016-04-24 23:54:20 +08:00
* @ param Role $role
*/
2016-05-02 04:20:50 +08:00
public function deleteJointPermissionsForRole ( Role $role )
2016-04-24 23:54:20 +08:00
{
2016-05-02 04:20:50 +08:00
$this -> deleteManyJointPermissionsForRoles ([ $role ]);
2016-04-24 23:54:20 +08:00
}
/**
2016-05-02 04:20:50 +08:00
* Delete all of the entity jointPermissions for a list of entities .
2016-04-24 23:54:20 +08:00
* @ param Role [] $roles
*/
2016-05-02 04:20:50 +08:00
protected function deleteManyJointPermissionsForRoles ( $roles )
2016-04-24 23:54:20 +08:00
{
foreach ( $roles as $role ) {
2016-05-02 04:20:50 +08:00
$role -> jointPermissions () -> delete ();
2016-04-24 23:54:20 +08:00
}
}
/**
2016-05-02 04:20:50 +08:00
* Delete the entity jointPermissions for a particular entity .
2016-04-24 23:54:20 +08:00
* @ param Entity $entity
*/
2016-05-02 04:20:50 +08:00
public function deleteJointPermissionsForEntity ( Entity $entity )
2016-04-24 23:54:20 +08:00
{
2016-05-02 04:20:50 +08:00
$this -> deleteManyJointPermissionsForEntities ([ $entity ]);
2016-04-24 23:54:20 +08:00
}
/**
2016-05-02 04:20:50 +08:00
* Delete all of the entity jointPermissions for a list of entities .
2016-04-24 23:54:20 +08:00
* @ param Entity [] $entities
*/
2016-05-02 04:20:50 +08:00
protected function deleteManyJointPermissionsForEntities ( $entities )
2016-04-24 23:54:20 +08:00
{
2017-01-24 06:27:11 +08:00
if ( count ( $entities ) === 0 ) return ;
2016-08-27 03:20:58 +08:00
$query = $this -> jointPermission -> newQuery ();
2017-01-24 06:27:11 +08:00
foreach ( $entities as $entity ) {
$query -> orWhere ( function ( $query ) use ( $entity ) {
$query -> where ( 'entity_id' , '=' , $entity -> id )
-> where ( 'entity_type' , '=' , $entity -> getMorphClass ());
});
}
2016-08-27 03:20:58 +08:00
$query -> delete ();
2016-04-24 23:54:20 +08:00
}
2016-04-21 04:37:57 +08:00
/**
2016-05-02 04:20:50 +08:00
* Create & Save entity jointPermissions for many entities and jointPermissions .
2016-04-21 04:37:57 +08:00
* @ param Collection $entities
* @ param Collection $roles
*/
2016-05-02 04:20:50 +08:00
protected function createManyJointPermissions ( $entities , $roles )
2016-04-21 04:37:57 +08:00
{
2016-08-27 03:20:58 +08:00
$this -> readyEntityCache ();
2016-05-02 04:20:50 +08:00
$jointPermissions = [];
2016-04-21 04:37:57 +08:00
foreach ( $entities as $entity ) {
foreach ( $roles as $role ) {
2016-04-27 04:48:17 +08:00
foreach ( $this -> getActions ( $entity ) as $action ) {
2016-05-02 04:20:50 +08:00
$jointPermissions [] = $this -> createJointPermissionData ( $entity , $role , $action );
2016-04-24 01:14:26 +08:00
}
2016-04-21 04:37:57 +08:00
}
}
2016-05-02 04:20:50 +08:00
$this -> jointPermission -> insert ( $jointPermissions );
2016-04-21 04:37:57 +08:00
}
2016-04-27 04:48:17 +08:00
/**
* Get the actions related to an entity .
* @ param $entity
* @ return array
*/
protected function getActions ( $entity )
{
$baseActions = [ 'view' , 'update' , 'delete' ];
if ( $entity -> isA ( 'chapter' )) {
$baseActions [] = 'page-create' ;
} else if ( $entity -> isA ( 'book' )) {
$baseActions [] = 'page-create' ;
$baseActions [] = 'chapter-create' ;
}
return $baseActions ;
}
2016-04-24 23:54:20 +08:00
/**
* Create entity permission data for an entity and role
* for a particular action .
* @ param Entity $entity
* @ param Role $role
* @ param $action
* @ return array
*/
2016-05-02 04:20:50 +08:00
protected function createJointPermissionData ( Entity $entity , Role $role , $action )
2016-04-21 04:37:57 +08:00
{
2016-04-27 04:48:17 +08:00
$permissionPrefix = ( strpos ( $action , '-' ) === false ? ( $entity -> getType () . '-' ) : '' ) . $action ;
2016-04-24 01:14:26 +08:00
$roleHasPermission = $role -> hasPermission ( $permissionPrefix . '-all' );
$roleHasPermissionOwn = $role -> hasPermission ( $permissionPrefix . '-own' );
2016-04-27 04:48:17 +08:00
$explodedAction = explode ( '-' , $action );
$restrictionAction = end ( $explodedAction );
2016-04-24 01:14:26 +08:00
2017-01-02 05:21:11 +08:00
if ( $role -> system_name === 'admin' ) {
return $this -> createJointPermissionDataArray ( $entity , $role , $action , true , true );
}
2016-04-24 01:14:26 +08:00
if ( $entity -> isA ( 'book' )) {
if ( ! $entity -> restricted ) {
2016-05-02 04:20:50 +08:00
return $this -> createJointPermissionDataArray ( $entity , $role , $action , $roleHasPermission , $roleHasPermissionOwn );
2016-04-24 01:14:26 +08:00
} else {
2016-04-27 04:48:17 +08:00
$hasAccess = $entity -> hasActiveRestriction ( $role -> id , $restrictionAction );
2016-05-02 04:20:50 +08:00
return $this -> createJointPermissionDataArray ( $entity , $role , $action , $hasAccess , $hasAccess );
2016-04-24 01:14:26 +08:00
}
} elseif ( $entity -> isA ( 'chapter' )) {
if ( ! $entity -> restricted ) {
2016-08-27 03:20:58 +08:00
$book = $this -> getBook ( $entity -> book_id );
$hasExplicitAccessToBook = $book -> hasActiveRestriction ( $role -> id , $restrictionAction );
$hasPermissiveAccessToBook = ! $book -> restricted ;
2016-05-02 04:20:50 +08:00
return $this -> createJointPermissionDataArray ( $entity , $role , $action ,
2016-04-24 23:54:20 +08:00
( $hasExplicitAccessToBook || ( $roleHasPermission && $hasPermissiveAccessToBook )),
( $hasExplicitAccessToBook || ( $roleHasPermissionOwn && $hasPermissiveAccessToBook )));
2016-04-24 01:14:26 +08:00
} else {
2016-04-27 04:48:17 +08:00
$hasAccess = $entity -> hasActiveRestriction ( $role -> id , $restrictionAction );
2016-05-02 04:20:50 +08:00
return $this -> createJointPermissionDataArray ( $entity , $role , $action , $hasAccess , $hasAccess );
2016-04-24 01:14:26 +08:00
}
} elseif ( $entity -> isA ( 'page' )) {
if ( ! $entity -> restricted ) {
2016-08-27 03:20:58 +08:00
$book = $this -> getBook ( $entity -> book_id );
$hasExplicitAccessToBook = $book -> hasActiveRestriction ( $role -> id , $restrictionAction );
$hasPermissiveAccessToBook = ! $book -> restricted ;
$chapter = $this -> getChapter ( $entity -> chapter_id );
$hasExplicitAccessToChapter = $chapter && $chapter -> hasActiveRestriction ( $role -> id , $restrictionAction );
$hasPermissiveAccessToChapter = $chapter && ! $chapter -> restricted ;
$acknowledgeChapter = ( $chapter && $chapter -> restricted );
2016-04-24 23:54:20 +08:00
$hasExplicitAccessToParents = $acknowledgeChapter ? $hasExplicitAccessToChapter : $hasExplicitAccessToBook ;
$hasPermissiveAccessToParents = $acknowledgeChapter ? $hasPermissiveAccessToChapter : $hasPermissiveAccessToBook ;
2016-05-02 04:20:50 +08:00
return $this -> createJointPermissionDataArray ( $entity , $role , $action ,
2016-04-24 23:54:20 +08:00
( $hasExplicitAccessToParents || ( $roleHasPermission && $hasPermissiveAccessToParents )),
( $hasExplicitAccessToParents || ( $roleHasPermissionOwn && $hasPermissiveAccessToParents ))
);
2016-04-24 01:14:26 +08:00
} else {
$hasAccess = $entity -> hasRestriction ( $role -> id , $action );
2016-05-02 04:20:50 +08:00
return $this -> createJointPermissionDataArray ( $entity , $role , $action , $hasAccess , $hasAccess );
2016-04-24 01:14:26 +08:00
}
}
}
2016-04-24 23:54:20 +08:00
/**
2016-05-02 04:20:50 +08:00
* Create an array of data with the information of an entity jointPermissions .
2016-04-24 23:54:20 +08:00
* Used to build data for bulk insertion .
* @ param Entity $entity
* @ param Role $role
* @ param $action
* @ param $permissionAll
* @ param $permissionOwn
* @ return array
*/
2016-05-02 04:20:50 +08:00
protected function createJointPermissionDataArray ( Entity $entity , Role $role , $action , $permissionAll , $permissionOwn )
2016-04-24 01:14:26 +08:00
{
$entityClass = get_class ( $entity );
return [
2016-05-01 00:16:06 +08:00
'role_id' => $role -> getRawAttribute ( 'id' ),
'entity_id' => $entity -> getRawAttribute ( 'id' ),
2016-04-24 01:14:26 +08:00
'entity_type' => $entityClass ,
'action' => $action ,
'has_permission' => $permissionAll ,
'has_permission_own' => $permissionOwn ,
2016-05-01 00:16:06 +08:00
'created_by' => $entity -> getRawAttribute ( 'created_by' )
2016-04-24 01:14:26 +08:00
];
2016-03-01 04:31:21 +08:00
}
2016-03-06 02:09:21 +08:00
/**
* Checks if an entity has a restriction set upon it .
2016-07-02 03:11:49 +08:00
* @ param Ownable $ownable
2016-04-24 23:54:20 +08:00
* @ param $permission
2016-03-06 02:09:21 +08:00
* @ return bool
*/
2016-07-02 03:11:49 +08:00
public function checkOwnableUserAccess ( Ownable $ownable , $permission )
2016-03-01 04:31:21 +08:00
{
2016-09-18 01:22:04 +08:00
if ( $this -> isAdmin ()) {
$this -> clean ();
return true ;
}
2016-04-24 23:54:20 +08:00
$explodedPermission = explode ( '-' , $permission );
2016-07-02 03:11:49 +08:00
$baseQuery = $ownable -> where ( 'id' , '=' , $ownable -> id );
2016-04-27 04:48:17 +08:00
$action = end ( $explodedPermission );
$this -> currentAction = $action ;
2016-04-24 23:54:20 +08:00
2017-01-09 03:19:30 +08:00
$nonJointPermissions = [ 'restrictions' , 'image' , 'attachment' ];
2016-04-24 23:54:20 +08:00
2016-05-02 04:20:50 +08:00
// Handle non entity specific jointPermissions
if ( in_array ( $explodedPermission [ 0 ], $nonJointPermissions )) {
2016-09-18 01:22:04 +08:00
$allPermission = $this -> currentUser () && $this -> currentUser () -> can ( $permission . '-all' );
$ownPermission = $this -> currentUser () && $this -> currentUser () -> can ( $permission . '-own' );
2016-04-24 23:54:20 +08:00
$this -> currentAction = 'view' ;
2016-09-18 01:22:04 +08:00
$isOwner = $this -> currentUser () && $this -> currentUser () -> id === $ownable -> created_by ;
2016-04-24 23:54:20 +08:00
return ( $allPermission || ( $isOwner && $ownPermission ));
2016-03-01 04:31:21 +08:00
}
2016-04-24 23:54:20 +08:00
2016-05-02 04:20:50 +08:00
// Handle abnormal create jointPermissions
2016-04-27 04:48:17 +08:00
if ( $action === 'create' ) {
$this -> currentAction = $permission ;
}
2016-09-18 01:22:04 +08:00
$q = $this -> entityRestrictionQuery ( $baseQuery ) -> count () > 0 ;
$this -> clean ();
return $q ;
2016-02-29 03:03:04 +08:00
}
2016-03-31 03:15:44 +08:00
/**
* Check if an entity has restrictions set on itself or its
* parent tree .
* @ param Entity $entity
* @ param $action
* @ return bool | mixed
*/
public function checkIfRestrictionsSet ( Entity $entity , $action )
{
$this -> currentAction = $action ;
if ( $entity -> isA ( 'page' )) {
return $entity -> restricted || ( $entity -> chapter && $entity -> chapter -> restricted ) || $entity -> book -> restricted ;
} elseif ( $entity -> isA ( 'chapter' )) {
return $entity -> restricted || $entity -> book -> restricted ;
} elseif ( $entity -> isA ( 'book' )) {
return $entity -> restricted ;
}
}
2016-02-29 03:03:04 +08:00
/**
2016-04-24 01:14:26 +08:00
* The general query filter to remove all entities
* that the current user does not have access to .
2016-02-29 03:03:04 +08:00
* @ param $query
* @ return mixed
*/
2016-04-24 01:14:26 +08:00
protected function entityRestrictionQuery ( $query )
2016-02-29 03:03:04 +08:00
{
2016-09-18 01:22:04 +08:00
$q = $query -> where ( function ( $parentQuery ) {
2016-05-02 04:20:50 +08:00
$parentQuery -> whereHas ( 'jointPermissions' , function ( $permissionQuery ) {
2016-05-02 02:36:53 +08:00
$permissionQuery -> whereIn ( 'role_id' , $this -> getRoles ())
2016-04-24 01:14:26 +08:00
-> where ( 'action' , '=' , $this -> currentAction )
-> where ( function ( $query ) {
$query -> where ( 'has_permission' , '=' , true )
-> orWhere ( function ( $query ) {
$query -> where ( 'has_permission_own' , '=' , true )
2016-09-18 01:22:04 +08:00
-> where ( 'created_by' , '=' , $this -> currentUser () -> id );
2016-02-29 03:03:04 +08:00
});
});
2016-04-24 01:14:26 +08:00
});
2016-02-29 03:03:04 +08:00
});
2016-09-18 01:22:04 +08:00
$this -> clean ();
return $q ;
2016-02-29 03:03:04 +08:00
}
2017-01-15 23:00:29 +08:00
/**
* Get the children of a book in an efficient single query , Filtered by the permission system .
* @ param integer $book_id
2017-02-26 21:26:51 +08:00
* @ param bool $filterDrafts
* @ param bool $fetchPageContent
2017-01-15 23:00:29 +08:00
* @ return \Illuminate\Database\Query\Builder
*/
2017-02-26 21:26:51 +08:00
public function bookChildrenQuery ( $book_id , $filterDrafts = false , $fetchPageContent = false ) {
$pageContentSelect = $fetchPageContent ? 'html' : " '' " ;
$pageSelect = $this -> db -> table ( 'pages' ) -> selectRaw ( " 'BookStack \\ \\ Page' as entity_type, id, slug, name, text, { $pageContentSelect } as description, book_id, priority, chapter_id, draft " ) -> where ( 'book_id' , '=' , $book_id ) -> where ( function ( $query ) use ( $filterDrafts ) {
2017-01-15 23:00:29 +08:00
$query -> where ( 'draft' , '=' , 0 );
if ( ! $filterDrafts ) {
$query -> orWhere ( function ( $query ) {
$query -> where ( 'draft' , '=' , 1 ) -> where ( 'created_by' , '=' , $this -> currentUser () -> id );
});
}
});
$chapterSelect = $this -> db -> table ( 'chapters' ) -> selectRaw ( " 'BookStack \\ \\ Chapter' as entity_type, id, slug, name, '' as text, description, book_id, priority, 0 as chapter_id, 0 as draft " ) -> where ( 'book_id' , '=' , $book_id );
$query = $this -> db -> query () -> select ( '*' ) -> from ( $this -> db -> raw ( " ( { $pageSelect -> toSql () } UNION { $chapterSelect -> toSql () } ) AS U " ))
2017-01-22 20:02:30 +08:00
-> mergeBindings ( $pageSelect ) -> mergeBindings ( $chapterSelect );
if ( ! $this -> isAdmin ()) {
$whereQuery = $this -> db -> table ( 'joint_permissions as jp' ) -> selectRaw ( 'COUNT(*)' )
-> whereRaw ( 'jp.entity_id=U.id' ) -> whereRaw ( 'jp.entity_type=U.entity_type' )
-> where ( 'jp.action' , '=' , 'view' ) -> whereIn ( 'jp.role_id' , $this -> getRoles ())
-> where ( function ( $query ) {
$query -> where ( 'jp.has_permission' , '=' , 1 ) -> orWhere ( function ( $query ) {
$query -> where ( 'jp.has_permission_own' , '=' , 1 ) -> where ( 'jp.created_by' , '=' , $this -> currentUser () -> id );
});
});
$query -> whereRaw ( " ( { $whereQuery -> toSql () } ) > 0 " ) -> mergeBindings ( $whereQuery );
}
$query -> orderBy ( 'draft' , 'desc' ) -> orderBy ( 'priority' , 'asc' );
2017-01-02 05:21:11 +08:00
$this -> clean ();
2017-01-15 23:00:29 +08:00
return $query ;
2017-01-02 05:21:11 +08:00
}
2016-05-07 03:33:08 +08:00
/**
* Add restrictions for a generic entity
2017-01-02 00:05:44 +08:00
* @ param string $entityType
* @ param Builder | Entity $query
2016-05-07 03:33:08 +08:00
* @ param string $action
* @ return mixed
*/
2017-01-02 00:05:44 +08:00
public function enforceEntityRestrictions ( $entityType , $query , $action = 'view' )
2016-02-29 03:03:04 +08:00
{
2017-01-02 00:05:44 +08:00
if ( strtolower ( $entityType ) === 'page' ) {
// Prevent drafts being visible to others.
$query = $query -> where ( function ( $query ) {
$query -> where ( 'draft' , '=' , false );
if ( $this -> currentUser ()) {
$query -> orWhere ( function ( $query ) {
$query -> where ( 'draft' , '=' , true ) -> where ( 'created_by' , '=' , $this -> currentUser () -> id );
});
}
});
}
2016-09-18 01:22:04 +08:00
if ( $this -> isAdmin ()) {
$this -> clean ();
return $query ;
}
2017-01-02 00:05:44 +08:00
2016-02-29 03:03:04 +08:00
$this -> currentAction = $action ;
2016-04-24 01:14:26 +08:00
return $this -> entityRestrictionQuery ( $query );
2016-02-29 03:03:04 +08:00
}
/**
* 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 )
{
2016-09-18 01:22:04 +08:00
if ( $this -> isAdmin ()) {
$this -> clean ();
return $query ;
}
2016-02-29 03:03:04 +08:00
$this -> currentAction = 'view' ;
$tableDetails = [ 'tableName' => $tableName , 'entityIdColumn' => $entityIdColumn , 'entityTypeColumn' => $entityTypeColumn ];
2016-04-24 01:14:26 +08:00
2016-09-18 01:22:04 +08:00
$q = $query -> where ( function ( $query ) use ( $tableDetails ) {
2016-04-24 01:14:26 +08:00
$query -> whereExists ( function ( $permissionQuery ) use ( & $tableDetails ) {
2016-05-02 04:20:50 +08:00
$permissionQuery -> select ( 'id' ) -> from ( 'joint_permissions' )
-> whereRaw ( 'joint_permissions.entity_id=' . $tableDetails [ 'tableName' ] . '.' . $tableDetails [ 'entityIdColumn' ])
-> whereRaw ( 'joint_permissions.entity_type=' . $tableDetails [ 'tableName' ] . '.' . $tableDetails [ 'entityTypeColumn' ])
2016-04-24 01:14:26 +08:00
-> where ( 'action' , '=' , $this -> currentAction )
2016-05-02 02:36:53 +08:00
-> whereIn ( 'role_id' , $this -> getRoles ())
2016-04-24 01:14:26 +08:00
-> where ( function ( $query ) {
$query -> where ( 'has_permission' , '=' , true ) -> orWhere ( function ( $query ) {
$query -> where ( 'has_permission_own' , '=' , true )
2016-09-18 01:22:04 +08:00
-> where ( 'created_by' , '=' , $this -> currentUser () -> id );
2016-02-29 03:03:04 +08:00
});
2016-04-24 01:14:26 +08:00
});
2016-02-29 03:03:04 +08:00
});
});
2017-01-22 00:16:27 +08:00
$this -> clean ();
2016-09-18 01:22:04 +08:00
return $q ;
2016-02-29 03:03:04 +08:00
}
2016-03-13 21:30:47 +08:00
/**
* Filters pages that are a direct relation to another item .
* @ param $query
* @ param $tableName
* @ param $entityIdColumn
* @ return mixed
*/
public function filterRelatedPages ( $query , $tableName , $entityIdColumn )
{
2016-09-18 01:22:04 +08:00
if ( $this -> isAdmin ()) {
$this -> clean ();
return $query ;
}
2016-03-13 21:30:47 +08:00
$this -> currentAction = 'view' ;
$tableDetails = [ 'tableName' => $tableName , 'entityIdColumn' => $entityIdColumn ];
2016-04-24 01:14:26 +08:00
2016-09-18 01:22:04 +08:00
$q = $query -> where ( function ( $query ) use ( $tableDetails ) {
2016-03-13 21:30:47 +08:00
$query -> where ( function ( $query ) use ( & $tableDetails ) {
2016-04-24 01:14:26 +08:00
$query -> whereExists ( function ( $permissionQuery ) use ( & $tableDetails ) {
2016-05-02 04:20:50 +08:00
$permissionQuery -> select ( 'id' ) -> from ( 'joint_permissions' )
-> whereRaw ( 'joint_permissions.entity_id=' . $tableDetails [ 'tableName' ] . '.' . $tableDetails [ 'entityIdColumn' ])
2016-04-24 01:14:26 +08:00
-> where ( 'entity_type' , '=' , 'Bookstack\\Page' )
-> where ( 'action' , '=' , $this -> currentAction )
2016-05-02 02:36:53 +08:00
-> whereIn ( 'role_id' , $this -> getRoles ())
2016-03-13 21:30:47 +08:00
-> where ( function ( $query ) {
2016-04-24 01:14:26 +08:00
$query -> where ( 'has_permission' , '=' , true ) -> orWhere ( function ( $query ) {
$query -> where ( 'has_permission_own' , '=' , true )
2016-09-18 01:22:04 +08:00
-> where ( 'created_by' , '=' , $this -> currentUser () -> id );
2016-04-24 01:14:26 +08:00
});
2016-03-13 21:30:47 +08:00
});
2016-04-24 01:14:26 +08:00
});
}) -> orWhere ( $tableDetails [ 'entityIdColumn' ], '=' , 0 );
2016-03-13 21:30:47 +08:00
});
2016-09-18 01:22:04 +08:00
$this -> clean ();
return $q ;
}
/**
* Check if the current user is an admin .
* @ return bool
*/
private function isAdmin ()
{
if ( $this -> isAdminUser === null ) {
2017-01-02 05:21:11 +08:00
$this -> isAdminUser = ( $this -> currentUser () -> id !== null ) ? $this -> currentUser () -> hasSystemRole ( 'admin' ) : false ;
2016-09-18 01:22:04 +08:00
}
return $this -> isAdminUser ;
}
/**
* Get the current user
* @ return User
*/
private function currentUser ()
{
if ( $this -> currentUserModel === false ) {
2016-09-29 19:43:46 +08:00
$this -> currentUserModel = user ();
2016-09-18 01:22:04 +08:00
}
return $this -> currentUserModel ;
}
/**
* Clean the cached user elements .
*/
private function clean ()
{
$this -> currentUserModel = false ;
$this -> userRoles = false ;
$this -> isAdminUser = null ;
2016-03-13 21:30:47 +08:00
}
2016-02-29 03:03:04 +08:00
}