Skip to content

Commit 8e6248f

Browse files
committed
Added restriction tests and fixed any bugs in the process
Also updated many styles within areas affected by the new permission and roles system.
1 parent 268db6b commit 8e6248f

26 files changed

Lines changed: 680 additions & 32 deletions

app/Exceptions/Handler.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ public function render($request, Exception $e)
5656
// Which will include the basic message to point the user roughly to the cause.
5757
if (($e instanceof PrettyException || $e->getPrevious() instanceof PrettyException) && !config('app.debug')) {
5858
$message = ($e instanceof PrettyException) ? $e->getMessage() : $e->getPrevious()->getMessage();
59-
return response()->view('errors/500', ['message' => $message], 500);
59+
$code = ($e->getCode() === 0) ? 500 : $e->getCode();
60+
return response()->view('errors/' . $code, ['message' => $message], $code);
6061
}
6162

6263
return parent::render($request, $e);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php namespace BookStack\Exceptions;
2+
3+
4+
class NotFoundException extends PrettyException {
5+
6+
/**
7+
* NotFoundException constructor.
8+
* @param string $message
9+
*/
10+
public function __construct($message = 'Item not found')
11+
{
12+
parent::__construct($message, 404);
13+
}
14+
}

app/Http/Controllers/ChapterController.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,14 @@ public function show($bookSlug, $chapterSlug)
8080
$sidebarTree = $this->bookRepo->getChildren($book);
8181
Views::add($chapter);
8282
$this->setPageTitle($chapter->getShortName());
83-
return view('chapters/show', ['book' => $book, 'chapter' => $chapter, 'current' => $chapter, 'sidebarTree' => $sidebarTree]);
83+
$pages = $this->chapterRepo->getChildren($chapter);
84+
return view('chapters/show', [
85+
'book' => $book,
86+
'chapter' => $chapter,
87+
'current' => $chapter,
88+
'sidebarTree' => $sidebarTree,
89+
'pages' => $pages
90+
]);
8491
}
8592

8693
/**

app/Http/Controllers/PageController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php namespace BookStack\Http\Controllers;
22

33
use Activity;
4+
use BookStack\Exceptions\NotFoundException;
45
use BookStack\Repos\UserRepo;
56
use BookStack\Services\ExportService;
67
use Illuminate\Http\Request;
@@ -94,7 +95,7 @@ public function show($bookSlug, $pageSlug)
9495

9596
try {
9697
$page = $this->pageRepo->getBySlug($pageSlug, $book->id);
97-
} catch (NotFoundHttpException $e) {
98+
} catch (NotFoundException $e) {
9899
$page = $this->pageRepo->findPageUsingOldSlug($pageSlug, $bookSlug);
99100
if ($page === null) abort(404);
100101
return redirect($page->getUrl());

app/Repos/BookRepo.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php namespace BookStack\Repos;
22

33
use Activity;
4+
use BookStack\Exceptions\NotFoundException;
45
use BookStack\Services\RestrictionService;
56
use Illuminate\Support\Str;
67
use BookStack\Book;
@@ -111,11 +112,12 @@ public function getPopular($count = 10, $page = 0)
111112
* Get a book by slug
112113
* @param $slug
113114
* @return mixed
115+
* @throws NotFoundException
114116
*/
115117
public function getBySlug($slug)
116118
{
117119
$book = $this->bookQuery()->where('slug', '=', $slug)->first();
118-
if ($book === null) abort(404);
120+
if ($book === null) throw new NotFoundException('Book not found');
119121
return $book;
120122
}
121123

@@ -153,6 +155,7 @@ public function destroyBySlug($bookSlug)
153155
$this->chapterRepo->destroy($chapter);
154156
}
155157
$book->views()->delete();
158+
$book->restrictions()->delete();
156159
$book->delete();
157160
}
158161

@@ -210,11 +213,13 @@ public function findSuitableSlug($name, $currentId = false)
210213
public function getChildren(Book $book)
211214
{
212215
$pageQuery = $book->pages()->where('chapter_id', '=', 0);
213-
$this->restrictionService->enforcePageRestrictions($pageQuery, 'view');
216+
$pageQuery = $this->restrictionService->enforcePageRestrictions($pageQuery, 'view');
214217
$pages = $pageQuery->get();
215218

216-
$chapterQuery = $book->chapters()->with('pages');
217-
$this->restrictionService->enforceChapterRestrictions($chapterQuery, 'view');
219+
$chapterQuery = $book->chapters()->with(['pages' => function($query) {
220+
$this->restrictionService->enforcePageRestrictions($query, 'view');
221+
}]);
222+
$chapterQuery = $this->restrictionService->enforceChapterRestrictions($chapterQuery, 'view');
218223
$chapters = $chapterQuery->get();
219224
$children = $pages->merge($chapters);
220225
$bookSlug = $book->slug;

app/Repos/ChapterRepo.php

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
use Activity;
5+
use BookStack\Exceptions\NotFoundException;
56
use BookStack\Services\RestrictionService;
67
use Illuminate\Support\Str;
78
use BookStack\Chapter;
@@ -66,14 +67,24 @@ public function getAll()
6667
* @param $slug
6768
* @param $bookId
6869
* @return mixed
70+
* @throws NotFoundException
6971
*/
7072
public function getBySlug($slug, $bookId)
7173
{
7274
$chapter = $this->chapterQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
73-
if ($chapter === null) abort(404);
75+
if ($chapter === null) throw new NotFoundException('Chapter not found');
7476
return $chapter;
7577
}
7678

79+
/**
80+
* Get the child items for a chapter
81+
* @param Chapter $chapter
82+
*/
83+
public function getChildren(Chapter $chapter)
84+
{
85+
return $this->restrictionService->enforcePageRestrictions($chapter->pages())->get();
86+
}
87+
7788
/**
7889
* Create a new chapter from request input.
7990
* @param $input
@@ -98,6 +109,7 @@ public function destroy(Chapter $chapter)
98109
}
99110
Activity::removeEntity($chapter);
100111
$chapter->views()->delete();
112+
$chapter->restrictions()->delete();
101113
$chapter->delete();
102114
}
103115

app/Repos/PageRepo.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use Activity;
55
use BookStack\Book;
66
use BookStack\Chapter;
7+
use BookStack\Exceptions\NotFoundException;
78
use BookStack\Services\RestrictionService;
89
use Illuminate\Http\Request;
910
use Illuminate\Support\Facades\Auth;
@@ -56,11 +57,12 @@ public function getById($id)
5657
* @param $slug
5758
* @param $bookId
5859
* @return mixed
60+
* @throws NotFoundException
5961
*/
6062
public function getBySlug($slug, $bookId)
6163
{
6264
$page = $this->pageQuery()->where('slug', '=', $slug)->where('book_id', '=', $bookId)->first();
63-
if ($page === null) throw new NotFoundHttpException('Page not found');
65+
if ($page === null) throw new NotFoundException('Page not found');
6466
return $page;
6567
}
6668

@@ -373,6 +375,7 @@ public function destroy($page)
373375
Activity::removeEntity($page);
374376
$page->views()->delete();
375377
$page->revisions()->delete();
378+
$page->restrictions()->delete();
376379
$page->delete();
377380
}
378381

app/Services/RestrictionService.php

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,16 @@ class RestrictionService
1515
public function __construct()
1616
{
1717
$user = auth()->user();
18-
$this->userRoles = $user ? auth()->user()->roles->pluck('id') : false;
18+
$this->userRoles = $user ? auth()->user()->roles->pluck('id') : [];
1919
$this->isAdmin = $user ? auth()->user()->hasRole('admin') : false;
2020
}
2121

22+
/**
23+
* Checks if an entity has a restriction set upon it.
24+
* @param Entity $entity
25+
* @param $action
26+
* @return bool
27+
*/
2228
public function checkIfEntityRestricted(Entity $entity, $action)
2329
{
2430
if ($this->isAdmin) return true;
@@ -93,12 +99,28 @@ private function pageRestrictionQuery($query)
9399
});
94100
});
95101
})
102+
// Page unrestricted, Has an unrestricted chapter & book has accepted restrictions
103+
->orWhere(function ($query) {
104+
$query->where('restricted', '=', false)
105+
->whereExists(function ($query) {
106+
$query->select('*')->from('chapters')
107+
->whereRaw('chapters.id=pages.chapter_id')->where('restricted', '=', false);
108+
})
109+
->whereExists(function ($query) {
110+
$query->select('*')->from('books')
111+
->whereRaw('books.id=pages.book_id')
112+
->whereExists(function ($query) {
113+
$this->checkRestrictionsQuery($query, 'books', 'Book');
114+
});
115+
});
116+
})
96117
// Page unrestricted, Has a chapter with accepted permissions
97118
->orWhere(function ($query) {
98119
$query->where('restricted', '=', false)
99120
->whereExists(function ($query) {
100121
$query->select('*')->from('chapters')
101122
->whereRaw('chapters.id=pages.chapter_id')
123+
->where('restricted', '=', true)
102124
->whereExists(function ($query) {
103125
$this->checkRestrictionsQuery($query, 'chapters', 'Chapter');
104126
});
@@ -183,8 +205,10 @@ private function bookRestrictionQuery($query)
183205
return $query->where(function ($parentWhereQuery) {
184206
$parentWhereQuery
185207
->where('restricted', '=', false)
186-
->orWhereExists(function ($query) {
187-
$this->checkRestrictionsQuery($query, 'books', 'Book');
208+
->orWhere(function ($query) {
209+
$query->where('restricted', '=', true)->whereExists(function ($query) {
210+
$this->checkRestrictionsQuery($query, 'books', 'Book');
211+
});
188212
});
189213
});
190214
}

app/helpers.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<?php
22

3-
if (! function_exists('versioned_asset')) {
3+
if (!function_exists('versioned_asset')) {
44
/**
55
* Get the path to a versioned file.
66
*
7-
* @param string $file
7+
* @param string $file
88
* @return string
99
*
1010
* @throws \InvalidArgumentException
@@ -39,6 +39,7 @@ function versioned_asset($file)
3939
*/
4040
function userCan($permission, \BookStack\Ownable $ownable = null)
4141
{
42+
if (!auth()->check()) return false;
4243
if ($ownable === null) {
4344
return auth()->user() && auth()->user()->can($permission);
4445
}
@@ -47,9 +48,9 @@ function userCan($permission, \BookStack\Ownable $ownable = null)
4748
$permissionBaseName = strtolower($permission) . '-';
4849
$hasPermission = false;
4950
if (auth()->user()->can($permissionBaseName . 'all')) $hasPermission = true;
50-
if (auth()->user()->can($permissionBaseName . 'own') && $ownable->createdBy->id === auth()->user()->id) $hasPermission = true;
51+
if (auth()->user()->can($permissionBaseName . 'own') && $ownable->createdBy && $ownable->createdBy->id === auth()->user()->id) $hasPermission = true;
5152

52-
if(!$ownable instanceof \BookStack\Entity) return $hasPermission;
53+
if (!$ownable instanceof \BookStack\Entity) return $hasPermission;
5354

5455
// Check restrictions on the entitiy
5556
$restrictionService = app('BookStack\Services\RestrictionService');

database/seeds/DummyContentSeeder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class DummyContentSeeder extends Seeder
1212
public function run()
1313
{
1414
$user = factory(BookStack\User::class, 1)->create();
15-
$role = \BookStack\Role::getDefault();
15+
$role = \BookStack\Role::getRole('editor');
1616
$user->attachRole($role);
1717

1818

0 commit comments

Comments
 (0)