]> BookStack Code Mirror - bookstack/blob - app/Permissions/ContentPermissionApiController.php
Fix issue BookStackApp#5542 Sorting by name
[bookstack] / app / Permissions / ContentPermissionApiController.php
1 <?php
2
3 namespace BookStack\Permissions;
4
5 use BookStack\Entities\EntityProvider;
6 use BookStack\Entities\Models\Entity;
7 use BookStack\Entities\Tools\PermissionsUpdater;
8 use BookStack\Http\ApiController;
9 use Illuminate\Http\Request;
10
11 class ContentPermissionApiController extends ApiController
12 {
13     public function __construct(
14         protected PermissionsUpdater $permissionsUpdater,
15         protected EntityProvider $entities
16     ) {
17     }
18
19     protected $rules = [
20         'update' => [
21             'owner_id'  => ['int'],
22
23             'role_permissions' => ['array'],
24             'role_permissions.*.role_id' => ['required', 'int', 'exists:roles,id'],
25             'role_permissions.*.view' => ['required', 'boolean'],
26             'role_permissions.*.create' => ['required', 'boolean'],
27             'role_permissions.*.update' => ['required', 'boolean'],
28             'role_permissions.*.delete' => ['required', 'boolean'],
29
30             'fallback_permissions' => ['nullable'],
31             'fallback_permissions.inheriting' => ['required_with:fallback_permissions', 'boolean'],
32             'fallback_permissions.view' => ['required_if:fallback_permissions.inheriting,false', 'boolean'],
33             'fallback_permissions.create' => ['required_if:fallback_permissions.inheriting,false', 'boolean'],
34             'fallback_permissions.update' => ['required_if:fallback_permissions.inheriting,false', 'boolean'],
35             'fallback_permissions.delete' => ['required_if:fallback_permissions.inheriting,false', 'boolean'],
36         ]
37     ];
38
39     /**
40      * Read the configured content-level permissions for the item of the given type and ID.
41      *
42      * 'contentType' should be one of: page, book, chapter, bookshelf.
43      * 'contentId' should be the relevant ID of that item type you'd like to handle permissions for.
44      *
45      * The permissions shown are those that override the default for just the specified item, they do not show the
46      * full evaluated permission for a role, nor do they reflect permissions inherited from other items in the hierarchy.
47      * Fallback permission values may be `null` when inheriting is active.
48      */
49     public function read(string $contentType, string $contentId)
50     {
51         $entity = $this->entities->get($contentType)
52             ->newQuery()->scopes(['visible'])->findOrFail($contentId);
53
54         $this->checkOwnablePermission('restrictions-manage', $entity);
55
56         return response()->json($this->formattedPermissionDataForEntity($entity));
57     }
58
59     /**
60      * Update the configured content-level permission overrides for the item of the given type and ID.
61      * 'contentType' should be one of: page, book, chapter, bookshelf.
62      *
63      * 'contentId' should be the relevant ID of that item type you'd like to handle permissions for.
64      * Providing an empty `role_permissions` array will remove any existing configured role permissions,
65      * so you may want to fetch existing permissions beforehand if just adding/removing a single item.
66      * You should completely omit the `owner_id`, `role_permissions` and/or the `fallback_permissions` properties
67      * from your request data if you don't wish to update details within those categories.
68      */
69     public function update(Request $request, string $contentType, string $contentId)
70     {
71         $entity = $this->entities->get($contentType)
72             ->newQuery()->scopes(['visible'])->findOrFail($contentId);
73
74         $this->checkOwnablePermission('restrictions-manage', $entity);
75
76         $data = $this->validate($request, $this->rules()['update']);
77         $this->permissionsUpdater->updateFromApiRequestData($entity, $data);
78
79         return response()->json($this->formattedPermissionDataForEntity($entity));
80     }
81
82     protected function formattedPermissionDataForEntity(Entity $entity): array
83     {
84         $rolePermissions = $entity->permissions()
85             ->where('role_id', '!=', 0)
86             ->with(['role:id,display_name'])
87             ->get();
88
89         $fallback = $entity->permissions()->where('role_id', '=', 0)->first();
90         $fallbackData = [
91             'inheriting' => is_null($fallback),
92             'view' => $fallback->view ?? null,
93             'create' => $fallback->create ?? null,
94             'update' => $fallback->update ?? null,
95             'delete' => $fallback->delete ?? null,
96         ];
97
98         return [
99             'owner' => $entity->ownedBy()->first(),
100             'role_permissions' => $rolePermissions,
101             'fallback_permissions' => $fallbackData,
102         ];
103     }
104 }