Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Зуев Егор
/
wiki.dev
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Commits
Issue Boards
Files
Commits
Network
Compare
Branches
Tags
Authored by
Dan Brown
2016-04-24 16:54:20 +0100
Browse Files
Options
Browse Files
Tag
Download
Email Patches
Plain Diff
Commit
a81a56706e8be77586631f3619ad84df36c8d84e
a81a5670
1 parent
ada7c83e
Rolled out new permissions system throughout application
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
294 additions
and
94 deletions
app/Entity.php
app/Http/Controllers/BookController.php
app/Http/Controllers/ChapterController.php
app/Http/Controllers/PermissionController.php
app/Permission.php
app/Repos/BookRepo.php
app/Repos/ChapterRepo.php
app/Repos/EntityRepo.php
app/Repos/PageRepo.php
app/Repos/PermissionsRepo.php
app/Role.php
app/Services/ActivityService.php
app/Services/RestrictionService.php
app/helpers.php
database/migrations/2016_04_09_100730_add_view_permissions_to_roles.php
tests/Permissions/RestrictionsTest.php
tests/Permissions/RolesTest.php
tests/TestCase.php
app/Entity.php
View file @
a81a567
...
...
@@ -70,7 +70,20 @@ abstract class Entity extends Ownable
*/
public
function
hasRestriction
(
$role_id
,
$action
)
{
return
$this
->
restrictions
->
where
(
'role_id'
,
$role_id
)
->
where
(
'action'
,
$action
)
->
count
()
>
0
;
return
$this
->
restrictions
()
->
where
(
'role_id'
,
'='
,
$role_id
)
->
where
(
'action'
,
'='
,
$action
)
->
count
()
>
0
;
}
/**
* Check if this entity has live (active) restrictions in place.
* @param $role_id
* @param $action
* @return bool
*/
public
function
hasActiveRestriction
(
$role_id
,
$action
)
{
return
$this
->
restricted
&&
$this
->
restrictions
()
->
where
(
'role_id'
,
'='
,
$role_id
)
->
where
(
'action'
,
'='
,
$action
)
->
count
()
>
0
;
}
/**
...
...
app/Http/Controllers/BookController.php
View file @
a81a567
...
...
@@ -71,11 +71,7 @@ class BookController extends Controller
'name'
=>
'required|string|max:255'
,
'description'
=>
'string|max:1000'
]);
$book
=
$this
->
bookRepo
->
newFromInput
(
$request
->
all
());
$book
->
slug
=
$this
->
bookRepo
->
findSuitableSlug
(
$book
->
name
);
$book
->
created_by
=
Auth
::
user
()
->
id
;
$book
->
updated_by
=
Auth
::
user
()
->
id
;
$book
->
save
();
$book
=
$this
->
bookRepo
->
createFromInput
(
$request
->
all
());
Activity
::
add
(
$book
,
'book_create'
,
$book
->
id
);
return
redirect
(
$book
->
getUrl
());
}
...
...
@@ -122,10 +118,7 @@ class BookController extends Controller
'name'
=>
'required|string|max:255'
,
'description'
=>
'string|max:1000'
]);
$book
->
fill
(
$request
->
all
());
$book
->
slug
=
$this
->
bookRepo
->
findSuitableSlug
(
$book
->
name
,
$book
->
id
);
$book
->
updated_by
=
Auth
::
user
()
->
id
;
$book
->
save
();
$book
=
$this
->
bookRepo
->
updateFromInput
(
$book
,
$request
->
all
());
Activity
::
add
(
$book
,
'book_update'
,
$book
->
id
);
return
redirect
(
$book
->
getUrl
());
}
...
...
@@ -210,6 +203,7 @@ class BookController extends Controller
// Add activity for books
foreach
(
$sortedBooks
as
$bookId
)
{
$updatedBook
=
$this
->
bookRepo
->
getById
(
$bookId
);
$this
->
bookRepo
->
updateBookPermissions
(
$updatedBook
);
Activity
::
add
(
$updatedBook
,
'book_sort'
,
$updatedBook
->
id
);
}
...
...
@@ -227,7 +221,7 @@ class BookController extends Controller
$this
->
checkOwnablePermission
(
'book-delete'
,
$book
);
Activity
::
addMessage
(
'book_delete'
,
0
,
$book
->
name
);
Activity
::
removeEntity
(
$book
);
$this
->
bookRepo
->
destroy
BySlug
(
$bookSlug
);
$this
->
bookRepo
->
destroy
(
$book
);
return
redirect
(
'/books'
);
}
...
...
app/Http/Controllers/ChapterController.php
View file @
a81a567
...
...
@@ -57,12 +57,9 @@ class ChapterController extends Controller
$book
=
$this
->
bookRepo
->
getBySlug
(
$bookSlug
);
$this
->
checkOwnablePermission
(
'chapter-create'
,
$book
);
$chapter
=
$this
->
chapterRepo
->
newFromInput
(
$request
->
all
());
$chapter
->
slug
=
$this
->
chapterRepo
->
findSuitableSlug
(
$chapter
->
name
,
$book
->
id
);
$chapter
->
priority
=
$this
->
bookRepo
->
getNewPriority
(
$book
);
$chapter
->
created_by
=
auth
()
->
user
()
->
id
;
$chapter
->
updated_by
=
auth
()
->
user
()
->
id
;
$book
->
chapters
()
->
save
(
$chapter
);
$input
=
$request
->
all
();
$input
[
'priority'
]
=
$this
->
bookRepo
->
getNewPriority
(
$book
);
$chapter
=
$this
->
chapterRepo
->
createFromInput
(
$request
->
all
(),
$book
);
Activity
::
add
(
$chapter
,
'chapter_create'
,
$book
->
id
);
return
redirect
(
$chapter
->
getUrl
());
}
...
...
app/Http/Controllers/PermissionController.php
View file @
a81a567
...
...
@@ -2,6 +2,7 @@
use
BookStack\Exceptions\PermissionsException
;
use
BookStack\Repos\PermissionsRepo
;
use
BookStack\Services\RestrictionService
;
use
Illuminate\Http\Request
;
use
BookStack\Http\Requests
;
...
...
app/Permission.php
View file @
a81a567
<?php
namespace
BookStack
;
<?php
namespace
BookStack
;
use
Illuminate\Database\Eloquent\Model
;
...
...
@@ -16,7 +14,7 @@ class Permission extends Model
/**
* Get the permission object by name.
* @param $
roleN
ame
* @param $
n
ame
* @return mixed
*/
public
static
function
getByName
(
$name
)
...
...
app/Repos/BookRepo.php
View file @
a81a567
<?php
namespace
BookStack\Repos
;
use
Alpha\B
;
use
BookStack\Exceptions\NotFoundException
;
use
Illuminate\Support\Str
;
use
BookStack\Book
;
...
...
@@ -123,21 +124,43 @@ class BookRepo extends EntityRepo
/**
* Get a new book instance from request input.
* @param array $input
* @return Book
*/
public
function
createFromInput
(
$input
)
{
$book
=
$this
->
book
->
newInstance
(
$input
);
$book
->
slug
=
$this
->
findSuitableSlug
(
$book
->
name
);
$book
->
created_by
=
auth
()
->
user
()
->
id
;
$book
->
updated_by
=
auth
()
->
user
()
->
id
;
$book
->
save
();
$this
->
restrictionService
->
buildEntityPermissionsForEntity
(
$book
);
return
$book
;
}
/**
* Update the given book from user input.
* @param Book $book
* @param $input
* @return Book
*/
public
function
newFromInput
(
$input
)
public
function
updateFromInput
(
Book
$book
,
$input
)
{
return
$this
->
book
->
newInstance
(
$input
);
$book
->
fill
(
$input
);
$book
->
slug
=
$this
->
findSuitableSlug
(
$book
->
name
,
$book
->
id
);
$book
->
updated_by
=
auth
()
->
user
()
->
id
;
$book
->
save
();
$this
->
restrictionService
->
buildEntityPermissionsForEntity
(
$book
);
return
$book
;
}
/**
* Destroy a book identified by the given slug.
* @param $bookSlug
* Destroy the given book.
* @param Book $book
* @throws \Exception
*/
public
function
destroy
BySlug
(
$bookSlug
)
public
function
destroy
(
Book
$book
)
{
$book
=
$this
->
getBySlug
(
$bookSlug
);
foreach
(
$book
->
pages
as
$page
)
{
$this
->
pageRepo
->
destroy
(
$page
);
}
...
...
@@ -146,10 +169,20 @@ class BookRepo extends EntityRepo
}
$book
->
views
()
->
delete
();
$book
->
restrictions
()
->
delete
();
$this
->
restrictionService
->
deleteEntityPermissionsForEntity
(
$book
);
$book
->
delete
();
}
/**
* Alias method to update the book permissions in the RestrictionService.
* @param Book $book
*/
public
function
updateBookPermissions
(
Book
$book
)
{
$this
->
restrictionService
->
buildEntityPermissionsForEntity
(
$book
);
}
/**
* Get the next child element priority.
* @param Book $book
* @return int
...
...
app/Repos/ChapterRepo.php
View file @
a81a567
...
...
@@ -2,6 +2,7 @@
use
Activity
;
use
BookStack\Book
;
use
BookStack\Exceptions\NotFoundException
;
use
Illuminate\Support\Str
;
use
BookStack\Chapter
;
...
...
@@ -78,11 +79,18 @@ class ChapterRepo extends EntityRepo
/**
* Create a new chapter from request input.
* @param $input
* @return $this
* @param Book $book
* @return Chapter
*/
public
function
newFromInput
(
$input
)
public
function
createFromInput
(
$input
,
Book
$book
)
{
return
$this
->
chapter
->
fill
(
$input
);
$chapter
=
$this
->
chapter
->
newInstance
(
$input
);
$chapter
->
slug
=
$this
->
findSuitableSlug
(
$chapter
->
name
,
$book
->
id
);
$chapter
->
created_by
=
auth
()
->
user
()
->
id
;
$chapter
->
updated_by
=
auth
()
->
user
()
->
id
;
$chapter
=
$book
->
chapters
()
->
save
(
$chapter
);
$this
->
restrictionService
->
buildEntityPermissionsForEntity
(
$chapter
);
return
$chapter
;
}
/**
...
...
@@ -100,6 +108,7 @@ class ChapterRepo extends EntityRepo
Activity
::
removeEntity
(
$chapter
);
$chapter
->
views
()
->
delete
();
$chapter
->
restrictions
()
->
delete
();
$this
->
restrictionService
->
deleteEntityPermissionsForEntity
(
$chapter
);
$chapter
->
delete
();
}
...
...
app/Repos/EntityRepo.php
View file @
a81a567
...
...
@@ -151,6 +151,7 @@ class EntityRepo
}
}
$entity
->
save
();
$this
->
restrictionService
->
buildEntityPermissionsForEntity
(
$entity
);
}
/**
...
...
app/Repos/PageRepo.php
View file @
a81a567
...
...
@@ -168,6 +168,7 @@ class PageRepo extends EntityRepo
if
(
$chapter
)
$page
->
chapter_id
=
$chapter
->
id
;
$book
->
pages
()
->
save
(
$page
);
$this
->
restrictionService
->
buildEntityPermissionsForEntity
(
$page
);
return
$page
;
}
...
...
@@ -583,6 +584,7 @@ class PageRepo extends EntityRepo
$page
->
views
()
->
delete
();
$page
->
revisions
()
->
delete
();
$page
->
restrictions
()
->
delete
();
$this
->
restrictionService
->
deleteEntityPermissionsForEntity
(
$page
);
$page
->
delete
();
}
...
...
app/Repos/PermissionsRepo.php
View file @
a81a567
...
...
@@ -4,6 +4,7 @@
use
BookStack\Exceptions\PermissionsException
;
use
BookStack\Permission
;
use
BookStack\Role
;
use
BookStack\Services\RestrictionService
;
use
Setting
;
class
PermissionsRepo
...
...
@@ -11,16 +12,19 @@ class PermissionsRepo
protected
$permission
;
protected
$role
;
protected
$restrictionService
;
/**
* PermissionsRepo constructor.
* @param $permission
* @param $role
* @param Permission $permission
* @param Role $role
* @param RestrictionService $restrictionService
*/
public
function
__construct
(
Permission
$permission
,
Role
$role
)
public
function
__construct
(
Permission
$permission
,
Role
$role
,
RestrictionService
$restrictionService
)
{
$this
->
permission
=
$permission
;
$this
->
role
=
$role
;
$this
->
restrictionService
=
$restrictionService
;
}
/**
...
...
@@ -69,6 +73,7 @@ class PermissionsRepo
$permissions
=
isset
(
$roleData
[
'permissions'
])
?
array_keys
(
$roleData
[
'permissions'
])
:
[];
$this
->
assignRolePermissions
(
$role
,
$permissions
);
$this
->
restrictionService
->
buildEntityPermissionForRole
(
$role
);
return
$role
;
}
...
...
@@ -91,6 +96,7 @@ class PermissionsRepo
$role
->
fill
(
$roleData
);
$role
->
save
();
$this
->
restrictionService
->
buildEntityPermissionForRole
(
$role
);
}
/**
...
...
@@ -136,6 +142,7 @@ class PermissionsRepo
}
}
$this
->
restrictionService
->
deleteEntityPermissionsForRole
(
$role
);
$role
->
delete
();
}
...
...
app/Role.php
View file @
a81a567
...
...
@@ -18,6 +18,15 @@ class Role extends Model
}
/**
* Get all related entity permissions.
* @return \Illuminate\Database\Eloquent\Relations\HasMany
*/
public
function
entityPermissions
()
{
return
$this
->
hasMany
(
EntityPermission
::
class
);
}
/**
* The permissions that belong to the role.
*/
public
function
permissions
()
...
...
app/Services/ActivityService.php
View file @
a81a567
...
...
@@ -105,8 +105,16 @@ class ActivityService
*/
public
function
entityActivity
(
$entity
,
$count
=
20
,
$page
=
0
)
{
$activity
=
$entity
->
hasMany
(
'BookStack\Activity'
)
->
orderBy
(
'created_at'
,
'desc'
)
->
skip
(
$count
*
$page
)
->
take
(
$count
)
->
get
();
if
(
$entity
->
isA
(
'book'
))
{
$query
=
$this
->
activity
->
where
(
'book_id'
,
'='
,
$entity
->
id
);
}
else
{
$query
=
$this
->
activity
->
where
(
'entity_type'
,
'='
,
get_class
(
$entity
))
->
where
(
'entity_id'
,
'='
,
$entity
->
id
);
}
$activity
=
$this
->
restrictionService
->
filterRestrictedEntityRelations
(
$query
,
'activities'
,
'entity_id'
,
'entity_type'
)
->
orderBy
(
'created_at'
,
'desc'
)
->
skip
(
$count
*
$page
)
->
take
(
$count
)
->
get
();
return
$this
->
filterSimilar
(
$activity
);
}
...
...
app/Services/RestrictionService.php
View file @
a81a567
...
...
@@ -23,11 +23,14 @@ class RestrictionService
protected
$entityPermission
;
protected
$role
;
/**
* The actions that have permissions attached throughout the application.
* @var array
*/
protected
$actions
=
[
'view'
,
'create'
,
'update'
,
'delete'
];
/**
* RestrictionService constructor.
* TODO - Handle events when roles or entities change.
* @param EntityPermission $entityPermission
* @param Book $book
* @param Chapter $chapter
...
...
@@ -74,6 +77,92 @@ class RestrictionService
}
/**
* Create the entity permissions for a particular entity.
* @param Entity $entity
*/
public
function
buildEntityPermissionsForEntity
(
Entity
$entity
)
{
$roles
=
$this
->
role
->
load
(
'permissions'
)
->
all
();
$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
);
}
$this
->
deleteManyEntityPermissionsForEntities
(
$entities
);
$this
->
createManyEntityPermissions
(
$entities
,
$roles
);
}
/**
* Build the entity permissions for a particular role.
* @param Role $role
*/
public
function
buildEntityPermissionForRole
(
Role
$role
)
{
$roles
=
collect
([
$role
]);
$this
->
deleteManyEntityPermissionsForRoles
(
$roles
);
// Chunk through all books
$this
->
book
->
chunk
(
500
,
function
(
$books
)
use
(
$roles
)
{
$this
->
createManyEntityPermissions
(
$books
,
$roles
);
});
// Chunk through all chapters
$this
->
chapter
->
with
(
'book'
)
->
chunk
(
500
,
function
(
$books
)
use
(
$roles
)
{
$this
->
createManyEntityPermissions
(
$books
,
$roles
);
});
// Chunk through all pages
$this
->
page
->
with
(
'book'
,
'chapter'
)
->
chunk
(
500
,
function
(
$books
)
use
(
$roles
)
{
$this
->
createManyEntityPermissions
(
$books
,
$roles
);
});
}
/**
* Delete the entity permissions attached to a particular role.
* @param Role $role
*/
public
function
deleteEntityPermissionsForRole
(
Role
$role
)
{
$this
->
deleteManyEntityPermissionsForRoles
([
$role
]);
}
/**
* Delete all of the entity permissions for a list of entities.
* @param Role[] $roles
*/
protected
function
deleteManyEntityPermissionsForRoles
(
$roles
)
{
foreach
(
$roles
as
$role
)
{
$role
->
entityPermissions
()
->
delete
();
}
}
/**
* Delete the entity permissions for a particular entity.
* @param Entity $entity
*/
public
function
deleteEntityPermissionsForEntity
(
Entity
$entity
)
{
$this
->
deleteManyEntityPermissionsForEntities
([
$entity
]);
}
/**
* Delete all of the entity permissions for a list of entities.
* @param Entity[] $entities
*/
protected
function
deleteManyEntityPermissionsForEntities
(
$entities
)
{
foreach
(
$entities
as
$entity
)
{
$entity
->
permissions
()
->
delete
();
}
}
/**
* Create & Save entity permissions for many entities and permissions.
* @param Collection $entities
* @param Collection $roles
...
...
@@ -88,10 +177,18 @@ class RestrictionService
}
}
}
\Log
::
info
(
collect
(
$entityPermissions
)
->
where
(
'entity_id'
,
1
)
->
where
(
'entity_type'
,
'BookStack\\Page'
)
->
where
(
'role_id'
,
2
)
->
all
());
$this
->
entityPermission
->
insert
(
$entityPermissions
);
}
/**
* Create entity permission data for an entity and role
* for a particular action.
* @param Entity $entity
* @param Role $role
* @param $action
* @return array
*/
protected
function
createEntityPermissionData
(
Entity
$entity
,
Role
$role
,
$action
)
{
$permissionPrefix
=
$entity
->
getType
()
.
'-'
.
$action
;
...
...
@@ -103,29 +200,39 @@ class RestrictionService
if
(
!
$entity
->
restricted
)
{
return
$this
->
createEntityPermissionDataArray
(
$entity
,
$role
,
$action
,
$roleHasPermission
,
$roleHasPermissionOwn
);
}
else
{
$hasAccess
=
$entity
->
hasRestriction
(
$role
->
id
,
$action
);
$hasAccess
=
$entity
->
has
Active
Restriction
(
$role
->
id
,
$action
);
return
$this
->
createEntityPermissionDataArray
(
$entity
,
$role
,
$action
,
$hasAccess
,
$hasAccess
);
}
}
elseif
(
$entity
->
isA
(
'chapter'
))
{
if
(
!
$entity
->
restricted
)
{
$hasAccessToBook
=
$entity
->
book
->
hasRestriction
(
$role
->
id
,
$action
);
$hasExplicitAccessToBook
=
$entity
->
book
->
hasActiveRestriction
(
$role
->
id
,
$action
);
$hasPermissiveAccessToBook
=
!
$entity
->
book
->
restricted
;
return
$this
->
createEntityPermissionDataArray
(
$entity
,
$role
,
$action
,
(
$roleHasPermission
&&
$hasAccessToBook
),
(
$roleHasPermissionOwn
&&
$hasAccessToBook
));
(
$hasExplicitAccessToBook
||
(
$roleHasPermission
&&
$hasPermissiveAccessToBook
)),
(
$hasExplicitAccessToBook
||
(
$roleHasPermissionOwn
&&
$hasPermissiveAccessToBook
)));
}
else
{
$hasAccess
=
$entity
->
hasRestriction
(
$role
->
id
,
$action
);
$hasAccess
=
$entity
->
has
Active
Restriction
(
$role
->
id
,
$action
);
return
$this
->
createEntityPermissionDataArray
(
$entity
,
$role
,
$action
,
$hasAccess
,
$hasAccess
);
}
}
elseif
(
$entity
->
isA
(
'page'
))
{
if
(
!
$entity
->
restricted
)
{
$hasAccessToBook
=
$entity
->
book
->
hasRestriction
(
$role
->
id
,
$action
);
$hasAccessToChapter
=
$entity
->
chapter
?
(
$entity
->
chapter
->
hasRestriction
(
$role
->
id
,
$action
))
:
true
;
$hasExplicitAccessToBook
=
$entity
->
book
->
hasActiveRestriction
(
$role
->
id
,
$action
);
$hasPermissiveAccessToBook
=
!
$entity
->
book
->
restricted
;
$hasExplicitAccessToChapter
=
$entity
->
chapter
&&
$entity
->
chapter
->
hasActiveRestriction
(
$role
->
id
,
$action
);
$hasPermissiveAccessToChapter
=
$entity
->
chapter
&&
!
$entity
->
chapter
->
restricted
;
$acknowledgeChapter
=
(
$entity
->
chapter
&&
$entity
->
chapter
->
restricted
);
$hasExplicitAccessToParents
=
$acknowledgeChapter
?
$hasExplicitAccessToChapter
:
$hasExplicitAccessToBook
;
$hasPermissiveAccessToParents
=
$acknowledgeChapter
?
$hasPermissiveAccessToChapter
:
$hasPermissiveAccessToBook
;
return
$this
->
createEntityPermissionDataArray
(
$entity
,
$role
,
$action
,
(
$roleHasPermission
&&
$hasAccessToBook
&&
$hasAccessToChapter
),
(
$roleHasPermissionOwn
&&
$hasAccessToBook
&&
$hasAccessToChapter
));
(
$hasExplicitAccessToParents
||
(
$roleHasPermission
&&
$hasPermissiveAccessToParents
)),
(
$hasExplicitAccessToParents
||
(
$roleHasPermissionOwn
&&
$hasPermissiveAccessToParents
))
);
}
else
{
$hasAccess
=
$entity
->
hasRestriction
(
$role
->
id
,
$action
);
return
$this
->
createEntityPermissionDataArray
(
$entity
,
$role
,
$action
,
$hasAccess
,
$hasAccess
);
...
...
@@ -134,6 +241,16 @@ class RestrictionService
}
}
/**
* Create an array of data with the information of an entity permissions.
* Used to build data for bulk insertion.
* @param Entity $entity
* @param Role $role
* @param $action
* @param $permissionAll
* @param $permissionOwn
* @return array
*/
protected
function
createEntityPermissionDataArray
(
Entity
$entity
,
Role
$role
,
$action
,
$permissionAll
,
$permissionOwn
)
{
$entityClass
=
get_class
(
$entity
);
...
...
@@ -151,22 +268,30 @@ class RestrictionService
/**
* Checks if an entity has a restriction set upon it.
* @param Entity $entity
* @param $
act
ion
* @param $
permiss
ion
* @return bool
*/
public
function
check
IfEntityRestricted
(
Entity
$entity
,
$act
ion
)
public
function
check
EntityUserAccess
(
Entity
$entity
,
$permiss
ion
)
{
if
(
$this
->
isAdmin
)
return
true
;
$this
->
currentAction
=
$action
;
$explodedPermission
=
explode
(
'-'
,
$permission
);
$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
;
$nonEntityPermissions
=
[
'restrictions'
];
// Handle non entity specific permissions
if
(
in_array
(
$explodedPermission
[
0
],
$nonEntityPermissions
))
{
$allPermission
=
$this
->
currentUser
&&
$this
->
currentUser
->
can
(
$permission
.
'-all'
);
$ownPermission
=
$this
->
currentUser
&&
$this
->
currentUser
->
can
(
$permission
.
'-own'
);
$this
->
currentAction
=
'view'
;
$isOwner
=
$this
->
currentUser
&&
$this
->
currentUser
->
id
===
$entity
->
created_by
;
return
(
$allPermission
||
(
$isOwner
&&
$ownPermission
));
}
return
false
;
$action
=
end
(
$explodedPermission
);
$this
->
currentAction
=
$action
;
return
$this
->
entityRestrictionQuery
(
$baseQuery
)
->
count
()
>
0
;
}
/**
...
...
@@ -189,29 +314,6 @@ class RestrictionService
}
/**
* Add restrictions for a page query
* @param $query
* @param string $action
* @return mixed
*/
public
function
enforcePageRestrictions
(
$query
,
$action
=
'view'
)
{
// 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
);
});
}
});
if
(
$this
->
isAdmin
)
return
$query
;
$this
->
currentAction
=
$action
;
return
$this
->
entityRestrictionQuery
(
$query
);
}
/**
* The general query filter to remove all entities
* that the current user does not have access to.
* @param $query
...
...
@@ -235,6 +337,29 @@ class RestrictionService
}
/**
* Add restrictions for a page query
* @param $query
* @param string $action
* @return mixed
*/
public
function
enforcePageRestrictions
(
$query
,
$action
=
'view'
)
{
// 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
);
});
}
});
if
(
$this
->
isAdmin
)
return
$query
;
$this
->
currentAction
=
$action
;
return
$this
->
entityRestrictionQuery
(
$query
);
}
/**
* Add on permission restrictions to a chapter query.
* @param $query
* @param string $action
...
...
@@ -316,7 +441,7 @@ class RestrictionService
->
where
(
function
(
$query
)
{
$query
->
where
(
'has_permission'
,
'='
,
true
)
->
orWhere
(
function
(
$query
)
{
$query
->
where
(
'has_permission_own'
,
'='
,
true
)
->
where
(
'created_by'
,
'='
,
$this
->
currentUser
->
id
);
->
where
(
'created_by'
,
'='
,
$this
->
currentUser
?
$this
->
currentUser
->
id
:
0
);
});
});
});
...
...
app/helpers.php
View file @
a81a567
...
...
@@ -45,20 +45,8 @@ function userCan($permission, \BookStack\Ownable $ownable = null)
}
// 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 entity
$restrictionService
=
app
(
'BookStack\Services\RestrictionService'
);
$explodedPermission
=
explode
(
'-'
,
$permission
);
$action
=
end
(
$explodedPermission
);
$hasAccess
=
$restrictionService
->
checkIfEntityRestricted
(
$ownable
,
$action
);
$restrictionsSet
=
$restrictionService
->
checkIfRestrictionsSet
(
$ownable
,
$action
);
return
(
$hasAccess
&&
$restrictionsSet
)
||
(
!
$restrictionsSet
&&
$hasPermission
);
return
$restrictionService
->
checkEntityUserAccess
(
$ownable
,
$permission
);
}
/**
...
...
database/migrations/2016_04_09_100730_add_view_permissions_to_roles.php
View file @
a81a567
...
...
@@ -23,6 +23,7 @@ class AddViewPermissionsToRoles extends Migration
$newPermission
->
name
=
strtolower
(
$entity
)
.
'-'
.
strtolower
(
str_replace
(
' '
,
'-'
,
$op
));
$newPermission
->
display_name
=
$op
.
' '
.
$entity
.
's'
;
$newPermission
->
save
();
// Assign view permissions to all current roles
foreach
(
$currentRoles
as
$role
)
{
$role
->
attachPermission
(
$newPermission
);
}
...
...
tests/Permissions/RestrictionsTest.php
View file @
a81a567
...
...
@@ -4,12 +4,14 @@ class RestrictionsTest extends TestCase
{
protected
$user
;
protected
$viewer
;
protected
$restrictionService
;
public
function
setUp
()
{
parent
::
setUp
();
$this
->
user
=
$this
->
getNewUser
();
$this
->
viewer
=
$this
->
getViewer
();
$this
->
restrictionService
=
$this
->
app
[
\BookStack\Services\RestrictionService
::
class
];
}
protected
function
getViewer
()
...
...
@@ -43,6 +45,8 @@ class RestrictionsTest extends TestCase
}
$entity
->
save
();
$entity
->
load
(
'restrictions'
);
$this
->
restrictionService
->
buildEntityPermissionsForEntity
(
$entity
);
$entity
->
load
(
'permissions'
);
}
public
function
test_book_view_restriction
()
...
...
tests/Permissions/RolesTest.php
View file @
a81a567
...
...
@@ -7,7 +7,15 @@ class RolesTest extends TestCase
public
function
setUp
()
{
parent
::
setUp
();
$this
->
user
=
$this
->
getNewBlankUser
();
$this
->
user
=
$this
->
getViewer
();
}
protected
function
getViewer
()
{
$role
=
\BookStack\Role
::
getRole
(
'viewer'
);
$viewer
=
$this
->
getNewBlankUser
();
$viewer
->
attachRole
(
$role
);;
return
$viewer
;
}
/**
...
...
@@ -141,7 +149,7 @@ class RolesTest extends TestCase
public
function
test_restrictions_manage_own_permission
()
{
$otherUsersPage
=
\BookStack\Page
::
take
(
1
)
->
get
()
->
first
();
$otherUsersPage
=
\BookStack\Page
::
first
();
$content
=
$this
->
createEntityChainBelongingToUser
(
$this
->
user
);
// Check can't restrict other's content
$this
->
actingAs
(
$this
->
user
)
->
visit
(
$otherUsersPage
->
getUrl
())
...
...
tests/TestCase.php
View file @
a81a567
...
...
@@ -65,6 +65,8 @@ class TestCase extends Illuminate\Foundation\Testing\TestCase
$page
=
factory
(
BookStack\Page
::
class
)
->
create
([
'created_by'
=>
$creatorUser
->
id
,
'updated_by'
=>
$updaterUser
->
id
,
'book_id'
=>
$book
->
id
]);
$book
->
chapters
()
->
saveMany
([
$chapter
]);
$chapter
->
pages
()
->
saveMany
([
$page
]);
$restrictionService
=
$this
->
app
[
\BookStack\Services\RestrictionService
::
class
];
$restrictionService
->
buildEntityPermissionsForEntity
(
$book
);
return
[
'book'
=>
$book
,
'chapter'
=>
$chapter
,
...
...
Please
register
or
sign in
to post a comment