]> BookStack Code Mirror - bookstack/blob - app/Services/RestrictionService.php
87dcbf0b3228c8269830be43d76bf1b926480503
[bookstack] / app / Services / RestrictionService.php
1 <?php namespace BookStack\Services;
2
3 class RestrictionService
4 {
5
6     protected $userRoles;
7     protected $isAdmin;
8     protected $currentAction;
9
10     /**
11      * RestrictionService constructor.
12      */
13     public function __construct()
14     {
15         $this->userRoles = auth()->user()->roles->pluck('id');
16         $this->isAdmin = auth()->user()->hasRole('admin');
17     }
18
19     /**
20      * Add restrictions for a page query
21      * @param $query
22      * @param string $action
23      * @return mixed
24      */
25     public function enforcePageRestrictions($query, $action = 'view')
26     {
27         if ($this->isAdmin) return $query;
28         $this->currentAction = $action;
29         return $this->pageRestrictionQuery($query);
30     }
31
32     /**
33      * The base query for restricting pages.
34      * @param $query
35      * @return mixed
36      */
37     private function pageRestrictionQuery($query)
38     {
39         return $query->where(function ($parentWhereQuery) {
40
41             $parentWhereQuery
42                 // (Book & chapter & page) or (Book & page & NO CHAPTER) unrestricted
43                 ->where(function ($query) {
44                     $query->where(function ($query) {
45                         $query->whereExists(function ($query) {
46                             $query->select('*')->from('chapters')
47                                 ->whereRaw('chapters.id=pages.chapter_id')
48                                 ->where('restricted', '=', false);
49                         })->whereExists(function ($query) {
50                             $query->select('*')->from('books')
51                                 ->whereRaw('books.id=pages.book_id')
52                                 ->where('restricted', '=', false);
53                         })->where('restricted', '=', false);
54                     })->orWhere(function ($query) {
55                         $query->where('restricted', '=', false)->where('chapter_id', '=', 0)
56                             ->whereExists(function ($query) {
57                                 $query->select('*')->from('books')
58                                     ->whereRaw('books.id=pages.book_id')
59                                     ->where('restricted', '=', false);
60                             });
61                     });
62                 })
63                 // Page unrestricted, Has no chapter & book has accepted restrictions
64                 ->orWhere(function ($query) {
65                     $query->where('restricted', '=', false)
66                         ->whereExists(function ($query) {
67                             $query->select('*')->from('chapters')
68                                 ->whereRaw('chapters.id=pages.chapter_id');
69                         }, 'and', true)
70                         ->whereExists(function ($query) {
71                             $query->select('*')->from('books')
72                                 ->whereRaw('books.id=pages.book_id')
73                                 ->whereExists(function ($query) {
74                                     $this->checkRestrictionsQuery($query, 'books', 'Book');
75                                 });
76                         });
77                 })
78                 // Page unrestricted, Has a chapter with accepted permissions
79                 ->orWhere(function ($query) {
80                     $query->where('restricted', '=', false)
81                         ->whereExists(function ($query) {
82                             $query->select('*')->from('chapters')
83                                 ->whereRaw('chapters.id=pages.chapter_id')
84                                 ->whereExists(function ($query) {
85                                     $this->checkRestrictionsQuery($query, 'chapters', 'Chapter');
86                                 });
87                         });
88                 })
89                 // Page has accepted permissions
90                 ->orWhereExists(function ($query) {
91                     $this->checkRestrictionsQuery($query, 'pages', 'Page');
92                 });
93         });
94     }
95
96     /**
97      * Add on permission restrictions to a chapter query.
98      * @param $query
99      * @param string $action
100      * @return mixed
101      */
102     public function enforceChapterRestrictions($query, $action = 'view')
103     {
104         if ($this->isAdmin) return $query;
105         $this->currentAction = $action;
106         return $this->chapterRestrictionQuery($query);
107     }
108
109     /**
110      * The base query for restricting chapters.
111      * @param $query
112      * @return mixed
113      */
114     private function chapterRestrictionQuery($query)
115     {
116         return $query->where(function ($parentWhereQuery) {
117
118             $parentWhereQuery
119                 // Book & chapter unrestricted
120                 ->where(function ($query) {
121                     $query->where('restricted', '=', false)->whereExists(function ($query) {
122                         $query->select('*')->from('books')
123                             ->whereRaw('books.id=chapters.book_id')
124                             ->where('restricted', '=', false);
125                     });
126                 })
127                 // Chapter unrestricted & book has accepted restrictions
128                 ->orWhere(function ($query) {
129                     $query->where('restricted', '=', false)
130                         ->whereExists(function ($query) {
131                             $query->select('*')->from('books')
132                                 ->whereRaw('books.id=chapters.book_id')
133                                 ->whereExists(function ($query) {
134                                     $this->checkRestrictionsQuery($query, 'books', 'Book');
135                                 });
136                         });
137                 })
138                 // Chapter has accepted permissions
139                 ->orWhereExists(function ($query) {
140                     $this->checkRestrictionsQuery($query, 'chapters', 'Chapter');
141                 });
142         });
143     }
144
145     /**
146      * Add restrictions to a book query.
147      * @param $query
148      * @param string $action
149      * @return mixed
150      */
151     public function enforceBookRestrictions($query, $action = 'view')
152     {
153         if ($this->isAdmin) return $query;
154         $this->currentAction = $action;
155         return $this->bookRestrictionQuery($query);
156     }
157
158     /**
159      * The base query for restricting books.
160      * @param $query
161      * @return mixed
162      */
163     private function bookRestrictionQuery($query)
164     {
165         return $query->where(function ($parentWhereQuery) {
166             $parentWhereQuery
167                 ->where('restricted', '=', false)
168                 ->orWhereExists(function ($query) {
169                     $this->checkRestrictionsQuery($query, 'books', 'Book');
170                 });
171         });
172     }
173
174     /**
175      * Filter items that have entities set a a polymorphic relation.
176      * @param $query
177      * @param string $tableName
178      * @param string $entityIdColumn
179      * @param string $entityTypeColumn
180      * @return mixed
181      */
182     public function filterRestrictedEntityRelations($query, $tableName, $entityIdColumn, $entityTypeColumn)
183     {
184         if ($this->isAdmin) return $query;
185         $this->currentAction = 'view';
186         $tableDetails = ['tableName' => $tableName, 'entityIdColumn' => $entityIdColumn, 'entityTypeColumn' => $entityTypeColumn];
187         return $query->where(function($query) use ($tableDetails) {
188             $query->where(function ($query) use (&$tableDetails) {
189                 $query->where($tableDetails['entityTypeColumn'], '=', 'BookStack\Page')
190                     ->whereExists(function ($query) use (&$tableDetails) {
191                         $query->select('*')->from('pages')->whereRaw('pages.id='.$tableDetails['tableName'].'.'.$tableDetails['entityIdColumn'])
192                             ->where(function ($query) {
193                                 $this->pageRestrictionQuery($query);
194                             });
195                     });
196             })->orWhere(function ($query) use (&$tableDetails) {
197                 $query->where($tableDetails['entityTypeColumn'], '=', 'BookStack\Book')->whereExists(function ($query) use (&$tableDetails) {
198                     $query->select('*')->from('books')->whereRaw('books.id='.$tableDetails['tableName'].'.'.$tableDetails['entityIdColumn'])
199                         ->where(function ($query) {
200                             $this->bookRestrictionQuery($query);
201                         });
202                 });
203             })->orWhere(function ($query) use (&$tableDetails) {
204                 $query->where($tableDetails['entityTypeColumn'], '=', 'BookStack\Chapter')->whereExists(function ($query) use (&$tableDetails) {
205                     $query->select('*')->from('chapters')->whereRaw('chapters.id='.$tableDetails['tableName'].'.'.$tableDetails['entityIdColumn'])
206                         ->where(function ($query) {
207                             $this->chapterRestrictionQuery($query);
208                         });
209                 });
210             });
211         });
212     }
213
214     /**
215      * The query to check the restrictions on an entity.
216      * @param $query
217      * @param $tableName
218      * @param $modelName
219      */
220     private function checkRestrictionsQuery($query, $tableName, $modelName)
221     {
222         $query->select('*')->from('restrictions')
223             ->whereRaw('restrictions.restrictable_id=' . $tableName . '.id')
224             ->where('restrictions.restrictable_type', '=', 'BookStack\\' . $modelName)
225             ->where('restrictions.action', '=', $this->currentAction)
226             ->whereIn('restrictions.role_id', $this->userRoles);
227     }
228
229
230 }