]> BookStack Code Mirror - bookstack/blob - app/Entities/Tools/PermissionsUpdater.php
Played around with a new app structure
[bookstack] / app / Entities / Tools / PermissionsUpdater.php
1 <?php
2
3 namespace BookStack\Entities\Tools;
4
5 use BookStack\Activity\ActivityType;
6 use BookStack\Entities\Models\Book;
7 use BookStack\Entities\Models\Bookshelf;
8 use BookStack\Entities\Models\Entity;
9 use BookStack\Facades\Activity;
10 use BookStack\Permissions\Models\EntityPermission;
11 use BookStack\Users\Models\Role;
12 use BookStack\Users\Models\User;
13 use Illuminate\Http\Request;
14
15 class PermissionsUpdater
16 {
17     /**
18      * Update an entities permissions from a permission form submit request.
19      */
20     public function updateFromPermissionsForm(Entity $entity, Request $request): void
21     {
22         $permissions = $request->get('permissions', null);
23         $ownerId = $request->get('owned_by', null);
24
25         $entity->permissions()->delete();
26
27         if (!is_null($permissions)) {
28             $entityPermissionData = $this->formatPermissionsFromRequestToEntityPermissions($permissions);
29             $entity->permissions()->createMany($entityPermissionData);
30         }
31
32         if (!is_null($ownerId)) {
33             $this->updateOwnerFromId($entity, intval($ownerId));
34         }
35
36         $entity->save();
37         $entity->rebuildPermissions();
38
39         Activity::add(ActivityType::PERMISSIONS_UPDATE, $entity);
40     }
41
42     /**
43      * Update permissions from API request data.
44      */
45     public function updateFromApiRequestData(Entity $entity, array $data): void
46     {
47         if (isset($data['role_permissions'])) {
48             $entity->permissions()->where('role_id', '!=', 0)->delete();
49             $rolePermissionData = $this->formatPermissionsFromApiRequestToEntityPermissions($data['role_permissions'] ?? [], false);
50             $entity->permissions()->createMany($rolePermissionData);
51         }
52
53         if (array_key_exists('fallback_permissions', $data)) {
54             $entity->permissions()->where('role_id', '=', 0)->delete();
55         }
56
57         if (isset($data['fallback_permissions']['inheriting']) && $data['fallback_permissions']['inheriting'] !== true) {
58             $data = $data['fallback_permissions'];
59             $data['role_id'] = 0;
60             $rolePermissionData = $this->formatPermissionsFromApiRequestToEntityPermissions([$data], true);
61             $entity->permissions()->createMany($rolePermissionData);
62         }
63
64         if (isset($data['owner_id'])) {
65             $this->updateOwnerFromId($entity, intval($data['owner_id']));
66         }
67
68         $entity->save();
69         $entity->rebuildPermissions();
70
71         Activity::add(ActivityType::PERMISSIONS_UPDATE, $entity);
72     }
73
74     /**
75      * Update the owner of the given entity.
76      * Checks the user exists in the system first.
77      * Does not save the model, just updates it.
78      */
79     protected function updateOwnerFromId(Entity $entity, int $newOwnerId): void
80     {
81         $newOwner = User::query()->find($newOwnerId);
82         if (!is_null($newOwner)) {
83             $entity->owned_by = $newOwner->id;
84         }
85     }
86
87     /**
88      * Format permissions provided from a permission form to be EntityPermission data.
89      */
90     protected function formatPermissionsFromRequestToEntityPermissions(array $permissions): array
91     {
92         $formatted = [];
93
94         foreach ($permissions as $roleId => $info) {
95             $entityPermissionData = ['role_id' => $roleId];
96             foreach (EntityPermission::PERMISSIONS as $permission) {
97                 $entityPermissionData[$permission] = (($info[$permission] ?? false) === "true");
98             }
99             $formatted[] = $entityPermissionData;
100         }
101
102         return $this->filterEntityPermissionDataUponRole($formatted, true);
103     }
104
105     protected function formatPermissionsFromApiRequestToEntityPermissions(array $permissions, bool $allowFallback): array
106     {
107         $formatted = [];
108
109         foreach ($permissions as $requestPermissionData) {
110             $entityPermissionData = ['role_id' => $requestPermissionData['role_id']];
111             foreach (EntityPermission::PERMISSIONS as $permission) {
112                 $entityPermissionData[$permission] = boolval($requestPermissionData[$permission] ?? false);
113             }
114             $formatted[] = $entityPermissionData;
115         }
116
117         return $this->filterEntityPermissionDataUponRole($formatted, $allowFallback);
118     }
119
120     protected function filterEntityPermissionDataUponRole(array $entityPermissionData, bool $allowFallback): array
121     {
122         $roleIds = [];
123         foreach ($entityPermissionData as $permissionEntry) {
124             $roleIds[] = intval($permissionEntry['role_id']);
125         }
126
127         $actualRoleIds = array_unique(array_values(array_filter($roleIds)));
128         $rolesById = Role::query()->whereIn('id', $actualRoleIds)->get('id')->keyBy('id');
129
130         return array_values(array_filter($entityPermissionData, function ($data) use ($rolesById, $allowFallback) {
131             if (intval($data['role_id']) === 0) {
132                 return $allowFallback;
133             }
134
135             return $rolesById->has($data['role_id']);
136         }));
137     }
138
139     /**
140      * Copy down the permissions of the given shelf to all child books.
141      */
142     public function updateBookPermissionsFromShelf(Bookshelf $shelf, $checkUserPermissions = true): int
143     {
144         $shelfPermissions = $shelf->permissions()->get(['role_id', 'view', 'create', 'update', 'delete'])->toArray();
145         $shelfBooks = $shelf->books()->get(['id', 'owned_by']);
146         $updatedBookCount = 0;
147
148         /** @var Book $book */
149         foreach ($shelfBooks as $book) {
150             if ($checkUserPermissions && !userCan('restrictions-manage', $book)) {
151                 continue;
152             }
153             $book->permissions()->delete();
154             $book->permissions()->createMany($shelfPermissions);
155             $book->rebuildPermissions();
156             $updatedBookCount++;
157         }
158
159         return $updatedBookCount;
160     }
161 }