1 <?php namespace BookStack\Services;
5 class RestrictionService
10 protected $currentAction;
13 * RestrictionService constructor.
15 public function __construct()
17 $user = auth()->user();
18 $this->userRoles = $user ? auth()->user()->roles->pluck('id') : [];
19 $this->isAdmin = $user ? auth()->user()->hasRole('admin') : false;
23 * Checks if an entity has a restriction set upon it.
24 * @param Entity $entity
28 public function checkIfEntityRestricted(Entity $entity, $action)
30 if ($this->isAdmin) return true;
31 $this->currentAction = $action;
32 $baseQuery = $entity->where('id', '=', $entity->id);
33 if ($entity->isA('page')) {
34 return $this->pageRestrictionQuery($baseQuery)->count() > 0;
35 } elseif ($entity->isA('chapter')) {
36 return $this->chapterRestrictionQuery($baseQuery)->count() > 0;
37 } elseif ($entity->isA('book')) {
38 return $this->bookRestrictionQuery($baseQuery)->count() > 0;
44 * Add restrictions for a page query
46 * @param string $action
49 public function enforcePageRestrictions($query, $action = 'view')
51 if ($this->isAdmin) return $query;
52 $this->currentAction = $action;
53 return $this->pageRestrictionQuery($query);
57 * The base query for restricting pages.
61 private function pageRestrictionQuery($query)
63 return $query->where(function ($parentWhereQuery) {
66 // (Book & chapter & page) or (Book & page & NO CHAPTER) unrestricted
67 ->where(function ($query) {
68 $query->where(function ($query) {
69 $query->whereExists(function ($query) {
70 $query->select('*')->from('chapters')
71 ->whereRaw('chapters.id=pages.chapter_id')
72 ->where('restricted', '=', false);
73 })->whereExists(function ($query) {
74 $query->select('*')->from('books')
75 ->whereRaw('books.id=pages.book_id')
76 ->where('restricted', '=', false);
77 })->where('restricted', '=', false);
78 })->orWhere(function ($query) {
79 $query->where('restricted', '=', false)->where('chapter_id', '=', 0)
80 ->whereExists(function ($query) {
81 $query->select('*')->from('books')
82 ->whereRaw('books.id=pages.book_id')
83 ->where('restricted', '=', false);
87 // Page unrestricted, Has no chapter & book has accepted restrictions
88 ->orWhere(function ($query) {
89 $query->where('restricted', '=', false)
90 ->whereExists(function ($query) {
91 $query->select('*')->from('chapters')
92 ->whereRaw('chapters.id=pages.chapter_id');
94 ->whereExists(function ($query) {
95 $query->select('*')->from('books')
96 ->whereRaw('books.id=pages.book_id')
97 ->whereExists(function ($query) {
98 $this->checkRestrictionsQuery($query, 'books', 'Book');
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);
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');
117 // Page unrestricted, Has a chapter with accepted permissions
118 ->orWhere(function ($query) {
119 $query->where('restricted', '=', false)
120 ->whereExists(function ($query) {
121 $query->select('*')->from('chapters')
122 ->whereRaw('chapters.id=pages.chapter_id')
123 ->where('restricted', '=', true)
124 ->whereExists(function ($query) {
125 $this->checkRestrictionsQuery($query, 'chapters', 'Chapter');
129 // Page has accepted permissions
130 ->orWhereExists(function ($query) {
131 $this->checkRestrictionsQuery($query, 'pages', 'Page');
137 * Add on permission restrictions to a chapter query.
139 * @param string $action
142 public function enforceChapterRestrictions($query, $action = 'view')
144 if ($this->isAdmin) return $query;
145 $this->currentAction = $action;
146 return $this->chapterRestrictionQuery($query);
150 * The base query for restricting chapters.
154 private function chapterRestrictionQuery($query)
156 return $query->where(function ($parentWhereQuery) {
159 // Book & chapter unrestricted
160 ->where(function ($query) {
161 $query->where('restricted', '=', false)->whereExists(function ($query) {
162 $query->select('*')->from('books')
163 ->whereRaw('books.id=chapters.book_id')
164 ->where('restricted', '=', false);
167 // Chapter unrestricted & book has accepted restrictions
168 ->orWhere(function ($query) {
169 $query->where('restricted', '=', false)
170 ->whereExists(function ($query) {
171 $query->select('*')->from('books')
172 ->whereRaw('books.id=chapters.book_id')
173 ->whereExists(function ($query) {
174 $this->checkRestrictionsQuery($query, 'books', 'Book');
178 // Chapter has accepted permissions
179 ->orWhereExists(function ($query) {
180 $this->checkRestrictionsQuery($query, 'chapters', 'Chapter');
186 * Add restrictions to a book query.
188 * @param string $action
191 public function enforceBookRestrictions($query, $action = 'view')
193 if ($this->isAdmin) return $query;
194 $this->currentAction = $action;
195 return $this->bookRestrictionQuery($query);
199 * The base query for restricting books.
203 private function bookRestrictionQuery($query)
205 return $query->where(function ($parentWhereQuery) {
207 ->where('restricted', '=', false)
208 ->orWhere(function ($query) {
209 $query->where('restricted', '=', true)->whereExists(function ($query) {
210 $this->checkRestrictionsQuery($query, 'books', 'Book');
217 * Filter items that have entities set a a polymorphic relation.
219 * @param string $tableName
220 * @param string $entityIdColumn
221 * @param string $entityTypeColumn
224 public function filterRestrictedEntityRelations($query, $tableName, $entityIdColumn, $entityTypeColumn)
226 if ($this->isAdmin) return $query;
227 $this->currentAction = 'view';
228 $tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn, 'entityTypeColumn' => $entityTypeColumn];
229 return $query->where(function ($query) use ($tableDetails) {
230 $query->where(function ($query) use (&$tableDetails) {
231 $query->where($tableDetails['entityTypeColumn'], '=', 'BookStack\Page')
232 ->whereExists(function ($query) use (&$tableDetails) {
233 $query->select('*')->from('pages')->whereRaw('pages.id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
234 ->where(function ($query) {
235 $this->pageRestrictionQuery($query);
238 })->orWhere(function ($query) use (&$tableDetails) {
239 $query->where($tableDetails['entityTypeColumn'], '=', 'BookStack\Book')->whereExists(function ($query) use (&$tableDetails) {
240 $query->select('*')->from('books')->whereRaw('books.id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
241 ->where(function ($query) {
242 $this->bookRestrictionQuery($query);
245 })->orWhere(function ($query) use (&$tableDetails) {
246 $query->where($tableDetails['entityTypeColumn'], '=', 'BookStack\Chapter')->whereExists(function ($query) use (&$tableDetails) {
247 $query->select('*')->from('chapters')->whereRaw('chapters.id=' . $tableDetails['tableName'] . '.' . $tableDetails['entityIdColumn'])
248 ->where(function ($query) {
249 $this->chapterRestrictionQuery($query);
257 * The query to check the restrictions on an entity.
262 private function checkRestrictionsQuery($query, $tableName, $modelName)
264 $query->select('*')->from('restrictions')
265 ->whereRaw('restrictions.restrictable_id=' . $tableName . '.id')
266 ->where('restrictions.restrictable_type', '=', 'BookStack\\' . $modelName)
267 ->where('restrictions.action', '=', $this->currentAction)
268 ->whereIn('restrictions.role_id', $this->userRoles);