Dan Brown

Merge branch 'master' into release

...@@ -49,6 +49,7 @@ class RegeneratePermissions extends Command ...@@ -49,6 +49,7 @@ class RegeneratePermissions extends Command
49 $connection = \DB::getDefaultConnection(); 49 $connection = \DB::getDefaultConnection();
50 if ($this->option('database') !== null) { 50 if ($this->option('database') !== null) {
51 \DB::setDefaultConnection($this->option('database')); 51 \DB::setDefaultConnection($this->option('database'));
52 + $this->permissionService->setConnection(\DB::connection($this->option('database')));
52 } 53 }
53 54
54 $this->permissionService->buildJointPermissions(); 55 $this->permissionService->buildJointPermissions();
......
...@@ -44,6 +44,7 @@ class RegenerateSearch extends Command ...@@ -44,6 +44,7 @@ class RegenerateSearch extends Command
44 $connection = \DB::getDefaultConnection(); 44 $connection = \DB::getDefaultConnection();
45 if ($this->option('database') !== null) { 45 if ($this->option('database') !== null) {
46 \DB::setDefaultConnection($this->option('database')); 46 \DB::setDefaultConnection($this->option('database'));
47 + $this->searchService->setConnection(\DB::connection($this->option('database')));
47 } 48 }
48 49
49 $this->searchService->indexAllEntities(); 50 $this->searchService->indexAllEntities();
......
...@@ -95,17 +95,6 @@ class Entity extends Ownable ...@@ -95,17 +95,6 @@ class Entity extends Ownable
95 } 95 }
96 96
97 /** 97 /**
98 - * Check if this entity has live (active) restrictions in place.
99 - * @param $role_id
100 - * @param $action
101 - * @return bool
102 - */
103 - public function hasActiveRestriction($role_id, $action)
104 - {
105 - return $this->getRawAttribute('restricted') && $this->hasRestriction($role_id, $action);
106 - }
107 -
108 - /**
109 * Get the entity jointPermissions this is connected to. 98 * Get the entity jointPermissions this is connected to.
110 * @return \Illuminate\Database\Eloquent\Relations\MorphMany 99 * @return \Illuminate\Database\Eloquent\Relations\MorphMany
111 */ 100 */
...@@ -176,5 +165,11 @@ class Entity extends Ownable ...@@ -176,5 +165,11 @@ class Entity extends Ownable
176 */ 165 */
177 public function entityRawQuery(){return '';} 166 public function entityRawQuery(){return '';}
178 167
168 + /**
169 + * Get the url of this entity
170 + * @param $path
171 + * @return string
172 + */
173 + public function getUrl($path){return '/';}
179 174
180 } 175 }
......
1 <?php namespace BookStack\Http\Controllers; 1 <?php namespace BookStack\Http\Controllers;
2 2
3 use Activity; 3 use Activity;
4 +use BookStack\Book;
4 use BookStack\Repos\EntityRepo; 5 use BookStack\Repos\EntityRepo;
5 use BookStack\Repos\UserRepo; 6 use BookStack\Repos\UserRepo;
6 use BookStack\Services\ExportService; 7 use BookStack\Services\ExportService;
...@@ -207,13 +208,12 @@ class BookController extends Controller ...@@ -207,13 +208,12 @@ class BookController extends Controller
207 208
208 // Add activity for books 209 // Add activity for books
209 foreach ($sortedBooks as $bookId) { 210 foreach ($sortedBooks as $bookId) {
211 + /** @var Book $updatedBook */
210 $updatedBook = $this->entityRepo->getById('book', $bookId); 212 $updatedBook = $this->entityRepo->getById('book', $bookId);
213 + $this->entityRepo->buildJointPermissionsForBook($updatedBook);
211 Activity::add($updatedBook, 'book_sort', $updatedBook->id); 214 Activity::add($updatedBook, 'book_sort', $updatedBook->id);
212 } 215 }
213 216
214 - // Update permissions on changed models
215 - if (count($updatedModels) === 0) $this->entityRepo->buildJointPermissions($updatedModels);
216 -
217 return redirect($book->getUrl()); 217 return redirect($book->getUrl());
218 } 218 }
219 219
......
...@@ -46,7 +46,7 @@ class HomeController extends Controller ...@@ -46,7 +46,7 @@ class HomeController extends Controller
46 * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response 46 * @return \Illuminate\Contracts\Routing\ResponseFactory|\Symfony\Component\HttpFoundation\Response
47 */ 47 */
48 public function getTranslations() { 48 public function getTranslations() {
49 - $locale = trans()->getLocale(); 49 + $locale = app()->getLocale();
50 $cacheKey = 'GLOBAL_TRANSLATIONS_' . $locale; 50 $cacheKey = 'GLOBAL_TRANSLATIONS_' . $locale;
51 if (cache()->has($cacheKey) && config('app.env') !== 'development') { 51 if (cache()->has($cacheKey) && config('app.env') !== 'development') {
52 $resp = cache($cacheKey); 52 $resp = cache($cacheKey);
......
...@@ -15,7 +15,17 @@ class Localization ...@@ -15,7 +15,17 @@ class Localization
15 public function handle($request, Closure $next) 15 public function handle($request, Closure $next)
16 { 16 {
17 $defaultLang = config('app.locale'); 17 $defaultLang = config('app.locale');
18 + if (user()->isDefault()) {
19 + $locale = $defaultLang;
20 + $availableLocales = config('app.locales');
21 + foreach ($request->getLanguages() as $lang) {
22 + if (!in_array($lang, $availableLocales)) continue;
23 + $locale = $lang;
24 + break;
25 + }
26 + } else {
18 $locale = setting()->getUser(user(), 'language', $defaultLang); 27 $locale = setting()->getUser(user(), 'language', $defaultLang);
28 + }
19 app()->setLocale($locale); 29 app()->setLocale($locale);
20 Carbon::setLocale($locale); 30 Carbon::setLocale($locale);
21 return $next($request); 31 return $next($request);
......
...@@ -533,11 +533,11 @@ class EntityRepo ...@@ -533,11 +533,11 @@ class EntityRepo
533 533
534 /** 534 /**
535 * Alias method to update the book jointPermissions in the PermissionService. 535 * Alias method to update the book jointPermissions in the PermissionService.
536 - * @param Collection $collection collection on entities 536 + * @param Book $book
537 */ 537 */
538 - public function buildJointPermissions(Collection $collection) 538 + public function buildJointPermissionsForBook(Book $book)
539 { 539 {
540 - $this->permissionService->buildJointPermissionsForEntities($collection); 540 + $this->permissionService->buildJointPermissionsForEntity($book);
541 } 541 }
542 542
543 /** 543 /**
...@@ -730,6 +730,7 @@ class EntityRepo ...@@ -730,6 +730,7 @@ class EntityRepo
730 if ($chapter) $page->chapter_id = $chapter->id; 730 if ($chapter) $page->chapter_id = $chapter->id;
731 731
732 $book->pages()->save($page); 732 $book->pages()->save($page);
733 + $page = $this->page->find($page->id);
733 $this->permissionService->buildJointPermissionsForEntity($page); 734 $this->permissionService->buildJointPermissionsForEntity($page);
734 return $page; 735 return $page;
735 } 736 }
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
3 use BookStack\Book; 3 use BookStack\Book;
4 use BookStack\Chapter; 4 use BookStack\Chapter;
5 use BookStack\Entity; 5 use BookStack\Entity;
6 +use BookStack\EntityPermission;
6 use BookStack\JointPermission; 7 use BookStack\JointPermission;
7 use BookStack\Ownable; 8 use BookStack\Ownable;
8 use BookStack\Page; 9 use BookStack\Page;
...@@ -10,6 +11,7 @@ use BookStack\Role; ...@@ -10,6 +11,7 @@ use BookStack\Role;
10 use BookStack\User; 11 use BookStack\User;
11 use Illuminate\Database\Connection; 12 use Illuminate\Database\Connection;
12 use Illuminate\Database\Eloquent\Builder; 13 use Illuminate\Database\Eloquent\Builder;
14 +use Illuminate\Database\Query\Builder as QueryBuilder;
13 use Illuminate\Support\Collection; 15 use Illuminate\Support\Collection;
14 16
15 class PermissionService 17 class PermissionService
...@@ -28,22 +30,25 @@ class PermissionService ...@@ -28,22 +30,25 @@ class PermissionService
28 30
29 protected $jointPermission; 31 protected $jointPermission;
30 protected $role; 32 protected $role;
33 + protected $entityPermission;
31 34
32 protected $entityCache; 35 protected $entityCache;
33 36
34 /** 37 /**
35 * PermissionService constructor. 38 * PermissionService constructor.
36 * @param JointPermission $jointPermission 39 * @param JointPermission $jointPermission
40 + * @param EntityPermission $entityPermission
37 * @param Connection $db 41 * @param Connection $db
38 * @param Book $book 42 * @param Book $book
39 * @param Chapter $chapter 43 * @param Chapter $chapter
40 * @param Page $page 44 * @param Page $page
41 * @param Role $role 45 * @param Role $role
42 */ 46 */
43 - public function __construct(JointPermission $jointPermission, Connection $db, Book $book, Chapter $chapter, Page $page, Role $role) 47 + public function __construct(JointPermission $jointPermission, EntityPermission $entityPermission, Connection $db, Book $book, Chapter $chapter, Page $page, Role $role)
44 { 48 {
45 $this->db = $db; 49 $this->db = $db;
46 $this->jointPermission = $jointPermission; 50 $this->jointPermission = $jointPermission;
51 + $this->entityPermission = $entityPermission;
47 $this->role = $role; 52 $this->role = $role;
48 $this->book = $book; 53 $this->book = $book;
49 $this->chapter = $chapter; 54 $this->chapter = $chapter;
...@@ -52,6 +57,15 @@ class PermissionService ...@@ -52,6 +57,15 @@ class PermissionService
52 } 57 }
53 58
54 /** 59 /**
60 + * Set the database connection
61 + * @param Connection $connection
62 + */
63 + public function setConnection(Connection $connection)
64 + {
65 + $this->db = $connection;
66 + }
67 +
68 + /**
55 * Prepare the local entity cache and ensure it's empty 69 * Prepare the local entity cache and ensure it's empty
56 */ 70 */
57 protected function readyEntityCache() 71 protected function readyEntityCache()
...@@ -133,22 +147,48 @@ class PermissionService ...@@ -133,22 +147,48 @@ class PermissionService
133 $this->readyEntityCache(); 147 $this->readyEntityCache();
134 148
135 // Get all roles (Should be the most limited dimension) 149 // Get all roles (Should be the most limited dimension)
136 - $roles = $this->role->with('permissions')->get(); 150 + $roles = $this->role->with('permissions')->get()->all();
137 151
138 // Chunk through all books 152 // Chunk through all books
139 - $this->book->with('permissions')->chunk(500, function ($books) use ($roles) { 153 + $this->bookFetchQuery()->chunk(5, function ($books) use ($roles) {
140 - $this->createManyJointPermissions($books, $roles); 154 + $this->buildJointPermissionsForBooks($books, $roles);
141 }); 155 });
156 + }
142 157
143 - // Chunk through all chapters 158 + /**
144 - $this->chapter->with('book', 'permissions')->chunk(500, function ($chapters) use ($roles) { 159 + * Get a query for fetching a book with it's children.
145 - $this->createManyJointPermissions($chapters, $roles); 160 + * @return QueryBuilder
146 - }); 161 + */
162 + protected function bookFetchQuery()
163 + {
164 + return $this->book->newQuery()->select(['id', 'restricted', 'created_by'])->with(['chapters' => function($query) {
165 + $query->select(['id', 'restricted', 'created_by', 'book_id']);
166 + }, 'pages' => function($query) {
167 + $query->select(['id', 'restricted', 'created_by', 'book_id', 'chapter_id']);
168 + }]);
169 + }
147 170
148 - // Chunk through all pages 171 + /**
149 - $this->page->with('book', 'chapter', 'permissions')->chunk(500, function ($pages) use ($roles) { 172 + * Build joint permissions for an array of books
150 - $this->createManyJointPermissions($pages, $roles); 173 + * @param Collection $books
151 - }); 174 + * @param array $roles
175 + * @param bool $deleteOld
176 + */
177 + protected function buildJointPermissionsForBooks($books, $roles, $deleteOld = false) {
178 + $entities = clone $books;
179 +
180 + /** @var Book $book */
181 + foreach ($books->all() as $book) {
182 + foreach ($book->getRelation('chapters') as $chapter) {
183 + $entities->push($chapter);
184 + }
185 + foreach ($book->getRelation('pages') as $page) {
186 + $entities->push($page);
187 + }
188 + }
189 +
190 + if ($deleteOld) $this->deleteManyJointPermissionsForEntities($entities->all());
191 + $this->createManyJointPermissions($entities, $roles);
152 } 192 }
153 193
154 /** 194 /**
...@@ -157,18 +197,22 @@ class PermissionService ...@@ -157,18 +197,22 @@ class PermissionService
157 */ 197 */
158 public function buildJointPermissionsForEntity(Entity $entity) 198 public function buildJointPermissionsForEntity(Entity $entity)
159 { 199 {
160 - $roles = $this->role->get(); 200 + $entities = [$entity];
161 - $entities = collect([$entity]);
162 -
163 if ($entity->isA('book')) { 201 if ($entity->isA('book')) {
164 - $entities = $entities->merge($entity->chapters); 202 + $books = $this->bookFetchQuery()->where('id', '=', $entity->id)->get();
165 - $entities = $entities->merge($entity->pages); 203 + $this->buildJointPermissionsForBooks($books, $this->role->newQuery()->get(), true);
166 - } elseif ($entity->isA('chapter')) { 204 + return;
167 - $entities = $entities->merge($entity->pages);
168 } 205 }
169 206
207 + $entities[] = $entity->book;
208 + if ($entity->isA('page') && $entity->chapter_id) $entities[] = $entity->chapter;
209 + if ($entity->isA('chapter')) {
210 + foreach ($entity->pages as $page) {
211 + $entities[] = $page;
212 + }
213 + }
170 $this->deleteManyJointPermissionsForEntities($entities); 214 $this->deleteManyJointPermissionsForEntities($entities);
171 - $this->createManyJointPermissions($entities, $roles); 215 + $this->buildJointPermissionsForEntities(collect($entities));
172 } 216 }
173 217
174 /** 218 /**
...@@ -177,8 +221,8 @@ class PermissionService ...@@ -177,8 +221,8 @@ class PermissionService
177 */ 221 */
178 public function buildJointPermissionsForEntities(Collection $entities) 222 public function buildJointPermissionsForEntities(Collection $entities)
179 { 223 {
180 - $roles = $this->role->get(); 224 + $roles = $this->role->newQuery()->get();
181 - $this->deleteManyJointPermissionsForEntities($entities); 225 + $this->deleteManyJointPermissionsForEntities($entities->all());
182 $this->createManyJointPermissions($entities, $roles); 226 $this->createManyJointPermissions($entities, $roles);
183 } 227 }
184 228
...@@ -188,23 +232,12 @@ class PermissionService ...@@ -188,23 +232,12 @@ class PermissionService
188 */ 232 */
189 public function buildJointPermissionForRole(Role $role) 233 public function buildJointPermissionForRole(Role $role)
190 { 234 {
191 - $roles = collect([$role]); 235 + $roles = [$role];
192 -
193 $this->deleteManyJointPermissionsForRoles($roles); 236 $this->deleteManyJointPermissionsForRoles($roles);
194 237
195 // Chunk through all books 238 // Chunk through all books
196 - $this->book->with('permissions')->chunk(500, function ($books) use ($roles) { 239 + $this->bookFetchQuery()->chunk(5, function ($books) use ($roles) {
197 - $this->createManyJointPermissions($books, $roles); 240 + $this->buildJointPermissionsForBooks($books, $roles);
198 - });
199 -
200 - // Chunk through all chapters
201 - $this->chapter->with('book', 'permissions')->chunk(500, function ($books) use ($roles) {
202 - $this->createManyJointPermissions($books, $roles);
203 - });
204 -
205 - // Chunk through all pages
206 - $this->page->with('book', 'chapter', 'permissions')->chunk(500, function ($books) use ($roles) {
207 - $this->createManyJointPermissions($books, $roles);
208 }); 241 });
209 } 242 }
210 243
...@@ -223,9 +256,10 @@ class PermissionService ...@@ -223,9 +256,10 @@ class PermissionService
223 */ 256 */
224 protected function deleteManyJointPermissionsForRoles($roles) 257 protected function deleteManyJointPermissionsForRoles($roles)
225 { 258 {
226 - foreach ($roles as $role) { 259 + $roleIds = array_map(function($role) {
227 - $role->jointPermissions()->delete(); 260 + return $role->id;
228 - } 261 + }, $roles);
262 + $this->jointPermission->newQuery()->whereIn('id', $roleIds)->delete();
229 } 263 }
230 264
231 /** 265 /**
...@@ -244,9 +278,13 @@ class PermissionService ...@@ -244,9 +278,13 @@ class PermissionService
244 protected function deleteManyJointPermissionsForEntities($entities) 278 protected function deleteManyJointPermissionsForEntities($entities)
245 { 279 {
246 if (count($entities) === 0) return; 280 if (count($entities) === 0) return;
247 - $query = $this->jointPermission->newQuery(); 281 +
248 - foreach ($entities as $entity) { 282 + $this->db->transaction(function() use ($entities) {
249 - $query->orWhere(function($query) use ($entity) { 283 +
284 + foreach (array_chunk($entities, 1000) as $entityChunk) {
285 + $query = $this->db->table('joint_permissions');
286 + foreach ($entityChunk as $entity) {
287 + $query->orWhere(function(QueryBuilder $query) use ($entity) {
250 $query->where('entity_id', '=', $entity->id) 288 $query->where('entity_id', '=', $entity->id)
251 ->where('entity_type', '=', $entity->getMorphClass()); 289 ->where('entity_type', '=', $entity->getMorphClass());
252 }); 290 });
...@@ -254,42 +292,73 @@ class PermissionService ...@@ -254,42 +292,73 @@ class PermissionService
254 $query->delete(); 292 $query->delete();
255 } 293 }
256 294
295 + });
296 + }
297 +
257 /** 298 /**
258 * Create & Save entity jointPermissions for many entities and jointPermissions. 299 * Create & Save entity jointPermissions for many entities and jointPermissions.
259 * @param Collection $entities 300 * @param Collection $entities
260 - * @param Collection $roles 301 + * @param array $roles
261 */ 302 */
262 protected function createManyJointPermissions($entities, $roles) 303 protected function createManyJointPermissions($entities, $roles)
263 { 304 {
264 $this->readyEntityCache(); 305 $this->readyEntityCache();
265 $jointPermissions = []; 306 $jointPermissions = [];
307 +
308 + // Fetch Entity Permissions and create a mapping of entity restricted statuses
309 + $entityRestrictedMap = [];
310 + $permissionFetch = $this->entityPermission->newQuery();
311 + foreach ($entities as $entity) {
312 + $entityRestrictedMap[$entity->getMorphClass() . ':' . $entity->id] = boolval($entity->getRawAttribute('restricted'));
313 + $permissionFetch->orWhere(function($query) use ($entity) {
314 + $query->where('restrictable_id', '=', $entity->id)->where('restrictable_type', '=', $entity->getMorphClass());
315 + });
316 + }
317 + $permissions = $permissionFetch->get();
318 +
319 + // Create a mapping of explicit entity permissions
320 + $permissionMap = [];
321 + foreach ($permissions as $permission) {
322 + $key = $permission->restrictable_type . ':' . $permission->restrictable_id . ':' . $permission->role_id . ':' . $permission->action;
323 + $isRestricted = $entityRestrictedMap[$permission->restrictable_type . ':' . $permission->restrictable_id];
324 + $permissionMap[$key] = $isRestricted;
325 + }
326 +
327 + // Create a mapping of role permissions
328 + $rolePermissionMap = [];
329 + foreach ($roles as $role) {
330 + foreach ($role->getRelationValue('permissions') as $permission) {
331 + $rolePermissionMap[$role->getRawAttribute('id') . ':' . $permission->getRawAttribute('name')] = true;
332 + }
333 + }
334 +
335 + // Create Joint Permission Data
266 foreach ($entities as $entity) { 336 foreach ($entities as $entity) {
267 foreach ($roles as $role) { 337 foreach ($roles as $role) {
268 foreach ($this->getActions($entity) as $action) { 338 foreach ($this->getActions($entity) as $action) {
269 - $jointPermissions[] = $this->createJointPermissionData($entity, $role, $action); 339 + $jointPermissions[] = $this->createJointPermissionData($entity, $role, $action, $permissionMap, $rolePermissionMap);
270 } 340 }
271 } 341 }
272 } 342 }
273 - $this->jointPermission->insert($jointPermissions); 343 +
344 + $this->db->transaction(function() use ($jointPermissions) {
345 + foreach (array_chunk($jointPermissions, 1000) as $jointPermissionChunk) {
346 + $this->db->table('joint_permissions')->insert($jointPermissionChunk);
347 + }
348 + });
274 } 349 }
275 350
276 351
277 /** 352 /**
278 * Get the actions related to an entity. 353 * Get the actions related to an entity.
279 - * @param $entity 354 + * @param Entity $entity
280 * @return array 355 * @return array
281 */ 356 */
282 - protected function getActions($entity) 357 + protected function getActions(Entity $entity)
283 { 358 {
284 $baseActions = ['view', 'update', 'delete']; 359 $baseActions = ['view', 'update', 'delete'];
285 - 360 + if ($entity->isA('chapter') || $entity->isA('book')) $baseActions[] = 'page-create';
286 - if ($entity->isA('chapter')) { 361 + if ($entity->isA('book')) $baseActions[] = 'chapter-create';
287 - $baseActions[] = 'page-create';
288 - } else if ($entity->isA('book')) {
289 - $baseActions[] = 'page-create';
290 - $baseActions[] = 'chapter-create';
291 - }
292 -
293 return $baseActions; 362 return $baseActions;
294 } 363 }
295 364
...@@ -298,14 +367,16 @@ class PermissionService ...@@ -298,14 +367,16 @@ class PermissionService
298 * for a particular action. 367 * for a particular action.
299 * @param Entity $entity 368 * @param Entity $entity
300 * @param Role $role 369 * @param Role $role
301 - * @param $action 370 + * @param string $action
371 + * @param array $permissionMap
372 + * @param array $rolePermissionMap
302 * @return array 373 * @return array
303 */ 374 */
304 - protected function createJointPermissionData(Entity $entity, Role $role, $action) 375 + protected function createJointPermissionData(Entity $entity, Role $role, $action, $permissionMap, $rolePermissionMap)
305 { 376 {
306 $permissionPrefix = (strpos($action, '-') === false ? ($entity->getType() . '-') : '') . $action; 377 $permissionPrefix = (strpos($action, '-') === false ? ($entity->getType() . '-') : '') . $action;
307 - $roleHasPermission = $role->hasPermission($permissionPrefix . '-all'); 378 + $roleHasPermission = isset($rolePermissionMap[$role->getRawAttribute('id') . ':' . $permissionPrefix . '-all']);
308 - $roleHasPermissionOwn = $role->hasPermission($permissionPrefix . '-own'); 379 + $roleHasPermissionOwn = isset($rolePermissionMap[$role->getRawAttribute('id') . ':' . $permissionPrefix . '-own']);
309 $explodedAction = explode('-', $action); 380 $explodedAction = explode('-', $action);
310 $restrictionAction = end($explodedAction); 381 $restrictionAction = end($explodedAction);
311 382
...@@ -313,54 +384,46 @@ class PermissionService ...@@ -313,54 +384,46 @@ class PermissionService
313 return $this->createJointPermissionDataArray($entity, $role, $action, true, true); 384 return $this->createJointPermissionDataArray($entity, $role, $action, true, true);
314 } 385 }
315 386
316 - if ($entity->isA('book')) { 387 + if ($entity->restricted) {
317 - 388 + $hasAccess = $this->mapHasActiveRestriction($permissionMap, $entity, $role, $restrictionAction);
318 - if (!$entity->restricted) {
319 - return $this->createJointPermissionDataArray($entity, $role, $action, $roleHasPermission, $roleHasPermissionOwn);
320 - } else {
321 - $hasAccess = $entity->hasActiveRestriction($role->id, $restrictionAction);
322 return $this->createJointPermissionDataArray($entity, $role, $action, $hasAccess, $hasAccess); 389 return $this->createJointPermissionDataArray($entity, $role, $action, $hasAccess, $hasAccess);
323 } 390 }
324 391
325 - } elseif ($entity->isA('chapter')) { 392 + if ($entity->isA('book')) {
326 - 393 + return $this->createJointPermissionDataArray($entity, $role, $action, $roleHasPermission, $roleHasPermissionOwn);
327 - if (!$entity->restricted) {
328 - $book = $this->getBook($entity->book_id);
329 - $hasExplicitAccessToBook = $book->hasActiveRestriction($role->id, $restrictionAction);
330 - $hasPermissiveAccessToBook = !$book->restricted;
331 - return $this->createJointPermissionDataArray($entity, $role, $action,
332 - ($hasExplicitAccessToBook || ($roleHasPermission && $hasPermissiveAccessToBook)),
333 - ($hasExplicitAccessToBook || ($roleHasPermissionOwn && $hasPermissiveAccessToBook)));
334 - } else {
335 - $hasAccess = $entity->hasActiveRestriction($role->id, $restrictionAction);
336 - return $this->createJointPermissionDataArray($entity, $role, $action, $hasAccess, $hasAccess);
337 } 394 }
338 395
339 - } elseif ($entity->isA('page')) { 396 + // For chapters and pages, Check if explicit permissions are set on the Book.
340 -
341 - if (!$entity->restricted) {
342 $book = $this->getBook($entity->book_id); 397 $book = $this->getBook($entity->book_id);
343 - $hasExplicitAccessToBook = $book->hasActiveRestriction($role->id, $restrictionAction); 398 + $hasExplicitAccessToParents = $this->mapHasActiveRestriction($permissionMap, $book, $role, $restrictionAction);
344 - $hasPermissiveAccessToBook = !$book->restricted; 399 + $hasPermissiveAccessToParents = !$book->restricted;
345 400
401 + // For pages with a chapter, Check if explicit permissions are set on the Chapter
402 + if ($entity->isA('page') && $entity->chapter_id !== 0) {
346 $chapter = $this->getChapter($entity->chapter_id); 403 $chapter = $this->getChapter($entity->chapter_id);
347 - $hasExplicitAccessToChapter = $chapter && $chapter->hasActiveRestriction($role->id, $restrictionAction); 404 + $hasPermissiveAccessToParents = $hasPermissiveAccessToParents && !$chapter->restricted;
348 - $hasPermissiveAccessToChapter = $chapter && !$chapter->restricted; 405 + if ($chapter->restricted) {
349 - $acknowledgeChapter = ($chapter && $chapter->restricted); 406 + $hasExplicitAccessToParents = $this->mapHasActiveRestriction($permissionMap, $chapter, $role, $restrictionAction);
350 - 407 + }
351 - $hasExplicitAccessToParents = $acknowledgeChapter ? $hasExplicitAccessToChapter : $hasExplicitAccessToBook; 408 + }
352 - $hasPermissiveAccessToParents = $acknowledgeChapter ? $hasPermissiveAccessToChapter : $hasPermissiveAccessToBook;
353 409
354 return $this->createJointPermissionDataArray($entity, $role, $action, 410 return $this->createJointPermissionDataArray($entity, $role, $action,
355 ($hasExplicitAccessToParents || ($roleHasPermission && $hasPermissiveAccessToParents)), 411 ($hasExplicitAccessToParents || ($roleHasPermission && $hasPermissiveAccessToParents)),
356 ($hasExplicitAccessToParents || ($roleHasPermissionOwn && $hasPermissiveAccessToParents)) 412 ($hasExplicitAccessToParents || ($roleHasPermissionOwn && $hasPermissiveAccessToParents))
357 ); 413 );
358 - } else {
359 - $hasAccess = $entity->hasRestriction($role->id, $action);
360 - return $this->createJointPermissionDataArray($entity, $role, $action, $hasAccess, $hasAccess);
361 } 414 }
362 415
363 - } 416 + /**
417 + * Check for an active restriction in an entity map.
418 + * @param $entityMap
419 + * @param Entity $entity
420 + * @param Role $role
421 + * @param $action
422 + * @return bool
423 + */
424 + protected function mapHasActiveRestriction($entityMap, Entity $entity, Role $role, $action) {
425 + $key = $entity->getMorphClass() . ':' . $entity->getRawAttribute('id') . ':' . $role->getRawAttribute('id') . ':' . $action;
426 + return isset($entityMap[$key]) ? $entityMap[$key] : false;
364 } 427 }
365 428
366 /** 429 /**
...@@ -375,11 +438,10 @@ class PermissionService ...@@ -375,11 +438,10 @@ class PermissionService
375 */ 438 */
376 protected function createJointPermissionDataArray(Entity $entity, Role $role, $action, $permissionAll, $permissionOwn) 439 protected function createJointPermissionDataArray(Entity $entity, Role $role, $action, $permissionAll, $permissionOwn)
377 { 440 {
378 - $entityClass = get_class($entity);
379 return [ 441 return [
380 'role_id' => $role->getRawAttribute('id'), 442 'role_id' => $role->getRawAttribute('id'),
381 'entity_id' => $entity->getRawAttribute('id'), 443 'entity_id' => $entity->getRawAttribute('id'),
382 - 'entity_type' => $entityClass, 444 + 'entity_type' => $entity->getMorphClass(),
383 'action' => $action, 445 'action' => $action,
384 'has_permission' => $permissionAll, 446 'has_permission' => $permissionAll,
385 'has_permission_own' => $permissionOwn, 447 'has_permission_own' => $permissionOwn,
...@@ -476,7 +538,7 @@ class PermissionService ...@@ -476,7 +538,7 @@ class PermissionService
476 * @param integer $book_id 538 * @param integer $book_id
477 * @param bool $filterDrafts 539 * @param bool $filterDrafts
478 * @param bool $fetchPageContent 540 * @param bool $fetchPageContent
479 - * @return \Illuminate\Database\Query\Builder 541 + * @return QueryBuilder
480 */ 542 */
481 public function bookChildrenQuery($book_id, $filterDrafts = false, $fetchPageContent = false) { 543 public function bookChildrenQuery($book_id, $filterDrafts = false, $fetchPageContent = false) {
482 $pageSelect = $this->db->table('pages')->selectRaw($this->page->entityRawQuery($fetchPageContent))->where('book_id', '=', $book_id)->where(function($query) use ($filterDrafts) { 544 $pageSelect = $this->db->table('pages')->selectRaw($this->page->entityRawQuery($fetchPageContent))->where('book_id', '=', $book_id)->where(function($query) use ($filterDrafts) {
......
...@@ -51,6 +51,15 @@ class SearchService ...@@ -51,6 +51,15 @@ class SearchService
51 } 51 }
52 52
53 /** 53 /**
54 + * Set the database connection
55 + * @param Connection $connection
56 + */
57 + public function setConnection(Connection $connection)
58 + {
59 + $this->db = $connection;
60 + }
61 +
62 + /**
54 * Search all entities in the system. 63 * Search all entities in the system.
55 * @param string $searchString 64 * @param string $searchString
56 * @param string $entityType 65 * @param string $entityType
......
...@@ -58,6 +58,7 @@ return [ ...@@ -58,6 +58,7 @@ return [
58 */ 58 */
59 59
60 'locale' => env('APP_LANG', 'en'), 60 'locale' => env('APP_LANG', 'en'),
61 + 'locales' => ['en', 'de', 'es', 'fr', 'nl', 'pt_BR', 'sk'],
61 62
62 /* 63 /*
63 |-------------------------------------------------------------------------- 64 |--------------------------------------------------------------------------
......
...@@ -28,6 +28,12 @@ class DummyContentSeeder extends Seeder ...@@ -28,6 +28,12 @@ class DummyContentSeeder extends Seeder
28 $book->pages()->saveMany($pages); 28 $book->pages()->saveMany($pages);
29 }); 29 });
30 30
31 + $largeBook = factory(\BookStack\Book::class)->create(['name' => 'Large book' . str_random(10), 'created_by' => $user->id, 'updated_by' => $user->id]);
32 + $pages = factory(\BookStack\Page::class, 200)->make(['created_by' => $user->id, 'updated_by' => $user->id]);
33 + $chapters = factory(\BookStack\Chapter::class, 50)->make(['created_by' => $user->id, 'updated_by' => $user->id]);
34 + $largeBook->pages()->saveMany($pages);
35 + $largeBook->chapters()->saveMany($chapters);
36 +
31 app(\BookStack\Services\PermissionService::class)->buildJointPermissions(); 37 app(\BookStack\Services\PermissionService::class)->buildJointPermissions();
32 app(\BookStack\Services\SearchService::class)->indexAllEntities(); 38 app(\BookStack\Services\SearchService::class)->indexAllEntities();
33 } 39 }
......
...@@ -44,6 +44,8 @@ Once done you can run `phpunit` in the application root directory to run all tes ...@@ -44,6 +44,8 @@ Once done you can run `phpunit` in the application root directory to run all tes
44 44
45 As part of BookStack v0.14 support for translations has been built in. All text strings can be found in the `resources/lang` folder where each language option has its own folder. To add a new language you should copy the `en` folder to an new folder (eg. `fr` for french) then go through and translate all text strings in those files, leaving the keys and file-names intact. If a language string is missing then the `en` translation will be used. To show the language option in the user preferences language drop-down you will need to add your language to the options found at the bottom of the `resources/lang/en/settings.php` file. A system-wide language can also be set in the `.env` file like so: `APP_LANG=en`. 45 As part of BookStack v0.14 support for translations has been built in. All text strings can be found in the `resources/lang` folder where each language option has its own folder. To add a new language you should copy the `en` folder to an new folder (eg. `fr` for french) then go through and translate all text strings in those files, leaving the keys and file-names intact. If a language string is missing then the `en` translation will be used. To show the language option in the user preferences language drop-down you will need to add your language to the options found at the bottom of the `resources/lang/en/settings.php` file. A system-wide language can also be set in the `.env` file like so: `APP_LANG=en`.
46 46
47 +You will also need to add the language to the `locales` array in the `config/app.php` file.
48 +
47 Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time. 49 Some strings have colon-prefixed variables in such as `:userName`. Leave these values as they are as they will be replaced at run-time.
48 50
49 ## Contributing 51 ## Contributing
......
...@@ -215,7 +215,7 @@ module.exports = function (ngApp, events) { ...@@ -215,7 +215,7 @@ module.exports = function (ngApp, events) {
215 } 215 }
216 }]); 216 }]);
217 217
218 - const md = new MarkdownIt(); 218 + const md = new MarkdownIt({html: true});
219 md.use(mdTasksLists, {label: true}); 219 md.use(mdTasksLists, {label: true});
220 220
221 /** 221 /**
......
...@@ -166,7 +166,7 @@ return [ ...@@ -166,7 +166,7 @@ return [
166 'start_a' => ':count usuarios han comenzado a editar esta página', 166 'start_a' => ':count usuarios han comenzado a editar esta página',
167 'start_b' => ':userName ha comenzado a editar esta página', 167 'start_b' => ':userName ha comenzado a editar esta página',
168 'time_a' => 'desde que las página fue actualizada', 168 'time_a' => 'desde que las página fue actualizada',
169 - 'time_b' => 'en los Ãltimos :minCount minutos', 169 + 'time_b' => 'en los últimos :minCount minutos',
170 'message' => ':start :time. Ten cuidado de no sobreescribir los cambios del otro usuario', 170 'message' => ':start :time. Ten cuidado de no sobreescribir los cambios del otro usuario',
171 ], 171 ],
172 'pages_draft_discarded' => 'Borrador descartado, el editor ha sido actualizado con el contenido de la página actual', 172 'pages_draft_discarded' => 'Borrador descartado, el editor ha sido actualizado con el contenido de la página actual',
...@@ -189,7 +189,7 @@ return [ ...@@ -189,7 +189,7 @@ return [
189 'attachments_set_link' => 'Setear Link', 189 'attachments_set_link' => 'Setear Link',
190 'attachments_delete_confirm' => 'Haga click en borrar nuevamente para confirmar que quiere borrar este adjunto.', 190 'attachments_delete_confirm' => 'Haga click en borrar nuevamente para confirmar que quiere borrar este adjunto.',
191 'attachments_dropzone' => 'Arrastre ficheros aquío haga click aquípara adjuntar un fichero', 191 'attachments_dropzone' => 'Arrastre ficheros aquío haga click aquípara adjuntar un fichero',
192 - 'attachments_no_files' => 'NingÃn fichero ha sido adjuntado', 192 + 'attachments_no_files' => 'Ningún fichero ha sido adjuntado',
193 'attachments_explain_link' => 'Ud. puede agregar un link o si lo prefiere puede agregar un fichero. Esto puede ser un link a otra página o un link a un fichero en la nube.', 193 'attachments_explain_link' => 'Ud. puede agregar un link o si lo prefiere puede agregar un fichero. Esto puede ser un link a otra página o un link a un fichero en la nube.',
194 'attachments_link_name' => 'Nombre de Link', 194 'attachments_link_name' => 'Nombre de Link',
195 'attachment_link' => 'Link adjunto', 195 'attachment_link' => 'Link adjunto',
......
1 <?php namespace Tests; 1 <?php namespace Tests;
2 2
3 use BookStack\Role; 3 use BookStack\Role;
4 +use BookStack\Services\PermissionService;
4 use Illuminate\Contracts\Console\Kernel; 5 use Illuminate\Contracts\Console\Kernel;
5 use Illuminate\Foundation\Testing\DatabaseTransactions; 6 use Illuminate\Foundation\Testing\DatabaseTransactions;
6 use Laravel\BrowserKitTesting\TestCase; 7 use Laravel\BrowserKitTesting\TestCase;
...@@ -105,11 +106,9 @@ abstract class BrowserKitTest extends TestCase ...@@ -105,11 +106,9 @@ abstract class BrowserKitTest extends TestCase
105 { 106 {
106 if ($updaterUser === false) $updaterUser = $creatorUser; 107 if ($updaterUser === false) $updaterUser = $creatorUser;
107 $book = factory(\BookStack\Book::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id]); 108 $book = factory(\BookStack\Book::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id]);
108 - $chapter = factory(\BookStack\Chapter::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id]); 109 + $chapter = factory(\BookStack\Chapter::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id, 'book_id' => $book->id]);
109 - $page = factory(\BookStack\Page::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id, 'book_id' => $book->id]); 110 + $page = factory(\BookStack\Page::class)->create(['created_by' => $creatorUser->id, 'updated_by' => $updaterUser->id, 'book_id' => $book->id, 'chapter_id' => $chapter->id]);
110 - $book->chapters()->saveMany([$chapter]); 111 + $restrictionService = $this->app[PermissionService::class];
111 - $chapter->pages()->saveMany([$page]);
112 - $restrictionService = $this->app[\BookStack\Services\PermissionService::class];
113 $restrictionService->buildJointPermissionsForEntity($book); 112 $restrictionService->buildJointPermissionsForEntity($book);
114 return [ 113 return [
115 'book' => $book, 114 'book' => $book,
......
...@@ -42,7 +42,7 @@ class EntitySearchTest extends TestCase ...@@ -42,7 +42,7 @@ class EntitySearchTest extends TestCase
42 42
43 public function test_book_search() 43 public function test_book_search()
44 { 44 {
45 - $book = \BookStack\Book::all()->first(); 45 + $book = \BookStack\Book::first();
46 $page = $book->pages->last(); 46 $page = $book->pages->last();
47 $chapter = $book->chapters->last(); 47 $chapter = $book->chapters->last();
48 48
......
1 <?php namespace Tests; 1 <?php namespace Tests;
2 2
3 +use BookStack\Role;
3 use BookStack\Tag; 4 use BookStack\Tag;
4 use BookStack\Page; 5 use BookStack\Page;
5 use BookStack\Services\PermissionService; 6 use BookStack\Services\PermissionService;
......
...@@ -14,6 +14,23 @@ class LanguageTest extends TestCase ...@@ -14,6 +14,23 @@ class LanguageTest extends TestCase
14 $this->langs = array_diff(scandir(resource_path('lang')), ['..', '.']); 14 $this->langs = array_diff(scandir(resource_path('lang')), ['..', '.']);
15 } 15 }
16 16
17 + public function test_locales_config_key_set_properly()
18 + {
19 + $configLocales = config('app.locales');
20 + sort($configLocales);
21 + sort($this->langs);
22 + $this->assertTrue(implode(':', $this->langs) === implode(':', $configLocales), 'app.locales configuration variable matches found lang files');
23 + }
24 +
25 + public function test_correct_language_if_not_logged_in()
26 + {
27 + $loginReq = $this->get('/login');
28 + $loginReq->assertSee('Log In');
29 +
30 + $loginPageFrenchReq = $this->get('/login', ['Accept-Language' => 'fr']);
31 + $loginPageFrenchReq->assertSee('Se Connecter');
32 + }
33 +
17 public function test_js_endpoint_for_each_language() 34 public function test_js_endpoint_for_each_language()
18 { 35 {
19 36
......
...@@ -226,6 +226,7 @@ class RestrictionsTest extends BrowserKitTest ...@@ -226,6 +226,7 @@ class RestrictionsTest extends BrowserKitTest
226 ->type('test content', 'html') 226 ->type('test content', 'html')
227 ->press('Save Page') 227 ->press('Save Page')
228 ->seePageIs($chapter->book->getUrl() . '/page/test-page'); 228 ->seePageIs($chapter->book->getUrl() . '/page/test-page');
229 +
229 $this->visit($chapterUrl)->seeInElement('.action-buttons', 'New Page'); 230 $this->visit($chapterUrl)->seeInElement('.action-buttons', 'New Page');
230 } 231 }
231 232
......
1 <?php namespace Tests; 1 <?php namespace Tests;
2 2
3 +use BookStack\Repos\PermissionsRepo;
4 +use BookStack\Role;
5 +
3 class RolesTest extends BrowserKitTest 6 class RolesTest extends BrowserKitTest
4 { 7 {
5 protected $user; 8 protected $user;
...@@ -34,11 +37,11 @@ class RolesTest extends BrowserKitTest ...@@ -34,11 +37,11 @@ class RolesTest extends BrowserKitTest
34 /** 37 /**
35 * Create a new basic role for testing purposes. 38 * Create a new basic role for testing purposes.
36 * @param array $permissions 39 * @param array $permissions
37 - * @return static 40 + * @return Role
38 */ 41 */
39 protected function createNewRole($permissions = []) 42 protected function createNewRole($permissions = [])
40 { 43 {
41 - $permissionRepo = app('BookStack\Repos\PermissionsRepo'); 44 + $permissionRepo = app(PermissionsRepo::class);
42 $roleData = factory(\BookStack\Role::class)->make()->toArray(); 45 $roleData = factory(\BookStack\Role::class)->make()->toArray();
43 $roleData['permissions'] = array_flip($permissions); 46 $roleData['permissions'] = array_flip($permissions);
44 return $permissionRepo->saveNewRole($roleData); 47 return $permissionRepo->saveNewRole($roleData);
...@@ -107,16 +110,16 @@ class RolesTest extends BrowserKitTest ...@@ -107,16 +110,16 @@ class RolesTest extends BrowserKitTest
107 110
108 public function test_manage_user_permission() 111 public function test_manage_user_permission()
109 { 112 {
110 - $this->actingAs($this->user)->visit('/')->visit('/settings/users') 113 + $this->actingAs($this->user)->visit('/settings/users')
111 ->seePageIs('/'); 114 ->seePageIs('/');
112 $this->giveUserPermissions($this->user, ['users-manage']); 115 $this->giveUserPermissions($this->user, ['users-manage']);
113 - $this->actingAs($this->user)->visit('/')->visit('/settings/users') 116 + $this->actingAs($this->user)->visit('/settings/users')
114 ->seePageIs('/settings/users'); 117 ->seePageIs('/settings/users');
115 } 118 }
116 119
117 public function test_user_roles_manage_permission() 120 public function test_user_roles_manage_permission()
118 { 121 {
119 - $this->actingAs($this->user)->visit('/')->visit('/settings/roles') 122 + $this->actingAs($this->user)->visit('/settings/roles')
120 ->seePageIs('/')->visit('/settings/roles/1')->seePageIs('/'); 123 ->seePageIs('/')->visit('/settings/roles/1')->seePageIs('/');
121 $this->giveUserPermissions($this->user, ['user-roles-manage']); 124 $this->giveUserPermissions($this->user, ['user-roles-manage']);
122 $this->actingAs($this->user)->visit('/settings/roles') 125 $this->actingAs($this->user)->visit('/settings/roles')
...@@ -126,10 +129,10 @@ class RolesTest extends BrowserKitTest ...@@ -126,10 +129,10 @@ class RolesTest extends BrowserKitTest
126 129
127 public function test_settings_manage_permission() 130 public function test_settings_manage_permission()
128 { 131 {
129 - $this->actingAs($this->user)->visit('/')->visit('/settings') 132 + $this->actingAs($this->user)->visit('/settings')
130 ->seePageIs('/'); 133 ->seePageIs('/');
131 $this->giveUserPermissions($this->user, ['settings-manage']); 134 $this->giveUserPermissions($this->user, ['settings-manage']);
132 - $this->actingAs($this->user)->visit('/')->visit('/settings') 135 + $this->actingAs($this->user)->visit('/settings')
133 ->seePageIs('/settings')->press('Save Settings')->see('Settings Saved'); 136 ->seePageIs('/settings')->press('Save Settings')->see('Settings Saved');
134 } 137 }
135 138
...@@ -181,27 +184,26 @@ class RolesTest extends BrowserKitTest ...@@ -181,27 +184,26 @@ class RolesTest extends BrowserKitTest
181 * @param string $permission 184 * @param string $permission
182 * @param array $accessUrls Urls that are only accessible after having the permission 185 * @param array $accessUrls Urls that are only accessible after having the permission
183 * @param array $visibles Check this text, In the buttons toolbar, is only visible with the permission 186 * @param array $visibles Check this text, In the buttons toolbar, is only visible with the permission
184 - * @param null $callback
185 */ 187 */
186 private function checkAccessPermission($permission, $accessUrls = [], $visibles = []) 188 private function checkAccessPermission($permission, $accessUrls = [], $visibles = [])
187 { 189 {
188 foreach ($accessUrls as $url) { 190 foreach ($accessUrls as $url) {
189 - $this->actingAs($this->user)->visit('/')->visit($url) 191 + $this->actingAs($this->user)->visit($url)
190 ->seePageIs('/'); 192 ->seePageIs('/');
191 } 193 }
192 foreach ($visibles as $url => $text) { 194 foreach ($visibles as $url => $text) {
193 - $this->actingAs($this->user)->visit('/')->visit($url) 195 + $this->actingAs($this->user)->visit($url)
194 ->dontSeeInElement('.action-buttons',$text); 196 ->dontSeeInElement('.action-buttons',$text);
195 } 197 }
196 198
197 $this->giveUserPermissions($this->user, [$permission]); 199 $this->giveUserPermissions($this->user, [$permission]);
198 200
199 foreach ($accessUrls as $url) { 201 foreach ($accessUrls as $url) {
200 - $this->actingAs($this->user)->visit('/')->visit($url) 202 + $this->actingAs($this->user)->visit($url)
201 ->seePageIs($url); 203 ->seePageIs($url);
202 } 204 }
203 foreach ($visibles as $url => $text) { 205 foreach ($visibles as $url => $text) {
204 - $this->actingAs($this->user)->visit('/')->visit($url) 206 + $this->actingAs($this->user)->visit($url)
205 ->see($text); 207 ->see($text);
206 } 208 }
207 } 209 }
...@@ -391,8 +393,8 @@ class RolesTest extends BrowserKitTest ...@@ -391,8 +393,8 @@ class RolesTest extends BrowserKitTest
391 393
392 public function test_page_create_own_permissions() 394 public function test_page_create_own_permissions()
393 { 395 {
394 - $book = \BookStack\Book::take(1)->get()->first(); 396 + $book = \BookStack\Book::first();
395 - $chapter = \BookStack\Chapter::take(1)->get()->first(); 397 + $chapter = \BookStack\Chapter::first();
396 398
397 $entities = $this->createEntityChainBelongingToUser($this->user); 399 $entities = $this->createEntityChainBelongingToUser($this->user);
398 $ownBook = $entities['book']; 400 $ownBook = $entities['book'];
...@@ -405,7 +407,7 @@ class RolesTest extends BrowserKitTest ...@@ -405,7 +407,7 @@ class RolesTest extends BrowserKitTest
405 $accessUrls = [$createUrl, $createUrlChapter]; 407 $accessUrls = [$createUrl, $createUrlChapter];
406 408
407 foreach ($accessUrls as $url) { 409 foreach ($accessUrls as $url) {
408 - $this->actingAs($this->user)->visit('/')->visit($url) 410 + $this->actingAs($this->user)->visit($url)
409 ->seePageIs('/'); 411 ->seePageIs('/');
410 } 412 }
411 413
...@@ -417,7 +419,7 @@ class RolesTest extends BrowserKitTest ...@@ -417,7 +419,7 @@ class RolesTest extends BrowserKitTest
417 $this->giveUserPermissions($this->user, ['page-create-own']); 419 $this->giveUserPermissions($this->user, ['page-create-own']);
418 420
419 foreach ($accessUrls as $index => $url) { 421 foreach ($accessUrls as $index => $url) {
420 - $this->actingAs($this->user)->visit('/')->visit($url); 422 + $this->actingAs($this->user)->visit($url);
421 $expectedUrl = \BookStack\Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl(); 423 $expectedUrl = \BookStack\Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl();
422 $this->seePageIs($expectedUrl); 424 $this->seePageIs($expectedUrl);
423 } 425 }
...@@ -449,7 +451,7 @@ class RolesTest extends BrowserKitTest ...@@ -449,7 +451,7 @@ class RolesTest extends BrowserKitTest
449 $accessUrls = [$createUrl, $createUrlChapter]; 451 $accessUrls = [$createUrl, $createUrlChapter];
450 452
451 foreach ($accessUrls as $url) { 453 foreach ($accessUrls as $url) {
452 - $this->actingAs($this->user)->visit('/')->visit($url) 454 + $this->actingAs($this->user)->visit($url)
453 ->seePageIs('/'); 455 ->seePageIs('/');
454 } 456 }
455 457
...@@ -461,7 +463,7 @@ class RolesTest extends BrowserKitTest ...@@ -461,7 +463,7 @@ class RolesTest extends BrowserKitTest
461 $this->giveUserPermissions($this->user, ['page-create-all']); 463 $this->giveUserPermissions($this->user, ['page-create-all']);
462 464
463 foreach ($accessUrls as $index => $url) { 465 foreach ($accessUrls as $index => $url) {
464 - $this->actingAs($this->user)->visit('/')->visit($url); 466 + $this->actingAs($this->user)->visit($url);
465 $expectedUrl = \BookStack\Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl(); 467 $expectedUrl = \BookStack\Page::where('draft', '=', true)->orderBy('id', 'desc')->first()->getUrl();
466 $this->seePageIs($expectedUrl); 468 $this->seePageIs($expectedUrl);
467 } 469 }
......