| 
									
										
										
										
											2021-06-26 23:23:15 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace BookStack\Entities\Tools; | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | use BookStack\Activity\ActivityType; | 
					
						
							| 
									
										
										
										
											2022-10-09 23:36:03 +08:00
										 |  |  | use BookStack\Entities\Models\Book; | 
					
						
							|  |  |  | use BookStack\Entities\Models\Bookshelf; | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  | use BookStack\Entities\Models\Entity; | 
					
						
							|  |  |  | use BookStack\Facades\Activity; | 
					
						
							| 
									
										
										
										
											2023-05-18 00:56:55 +08:00
										 |  |  | use BookStack\Permissions\Models\EntityPermission; | 
					
						
							|  |  |  | use BookStack\Users\Models\Role; | 
					
						
							|  |  |  | use BookStack\Users\Models\User; | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  | use Illuminate\Http\Request; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class PermissionsUpdater | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Update an entities permissions from a permission form submit request. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-03-13 21:18:33 +08:00
										 |  |  |     public function updateFromPermissionsForm(Entity $entity, Request $request): void | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-10-08 20:52:59 +08:00
										 |  |  |         $permissions = $request->get('permissions', null); | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  |         $ownerId = $request->get('owned_by', null); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $entity->permissions()->delete(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!is_null($permissions)) { | 
					
						
							|  |  |  |             $entityPermissionData = $this->formatPermissionsFromRequestToEntityPermissions($permissions); | 
					
						
							|  |  |  |             $entity->permissions()->createMany($entityPermissionData); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!is_null($ownerId)) { | 
					
						
							| 
									
										
										
										
											2021-01-02 02:38:54 +08:00
										 |  |  |             $this->updateOwnerFromId($entity, intval($ownerId)); | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $entity->save(); | 
					
						
							|  |  |  |         $entity->rebuildPermissions(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-12 01:29:33 +08:00
										 |  |  |         Activity::add(ActivityType::PERMISSIONS_UPDATE, $entity); | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-13 21:18:33 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Update permissions from API request data. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function updateFromApiRequestData(Entity $entity, array $data): void | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2023-03-14 04:06:52 +08:00
										 |  |  |         if (isset($data['role_permissions'])) { | 
					
						
							| 
									
										
										
										
											2023-03-13 21:18:33 +08:00
										 |  |  |             $entity->permissions()->where('role_id', '!=', 0)->delete(); | 
					
						
							| 
									
										
										
										
											2023-03-14 04:06:52 +08:00
										 |  |  |             $rolePermissionData = $this->formatPermissionsFromApiRequestToEntityPermissions($data['role_permissions'] ?? [], false); | 
					
						
							| 
									
										
										
										
											2023-03-13 21:18:33 +08:00
										 |  |  |             $entity->permissions()->createMany($rolePermissionData); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-14 04:06:52 +08:00
										 |  |  |         if (array_key_exists('fallback_permissions', $data)) { | 
					
						
							| 
									
										
										
										
											2023-03-13 21:18:33 +08:00
										 |  |  |             $entity->permissions()->where('role_id', '=', 0)->delete(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-14 04:06:52 +08:00
										 |  |  |         if (isset($data['fallback_permissions']['inheriting']) && $data['fallback_permissions']['inheriting'] !== true) { | 
					
						
							| 
									
										
										
										
											2023-06-20 21:13:26 +08:00
										 |  |  |             $fallbackData = $data['fallback_permissions']; | 
					
						
							|  |  |  |             $fallbackData['role_id'] = 0; | 
					
						
							|  |  |  |             $rolePermissionData = $this->formatPermissionsFromApiRequestToEntityPermissions([$fallbackData], true); | 
					
						
							| 
									
										
										
										
											2023-03-13 21:18:33 +08:00
										 |  |  |             $entity->permissions()->createMany($rolePermissionData); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (isset($data['owner_id'])) { | 
					
						
							|  |  |  |             $this->updateOwnerFromId($entity, intval($data['owner_id'])); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $entity->save(); | 
					
						
							|  |  |  |         $entity->rebuildPermissions(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Activity::add(ActivityType::PERMISSIONS_UPDATE, $entity); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  |     /** | 
					
						
							|  |  |  |      * Update the owner of the given entity. | 
					
						
							|  |  |  |      * Checks the user exists in the system first. | 
					
						
							|  |  |  |      * Does not save the model, just updates it. | 
					
						
							|  |  |  |      */ | 
					
						
							| 
									
										
										
										
											2023-03-13 21:18:33 +08:00
										 |  |  |     protected function updateOwnerFromId(Entity $entity, int $newOwnerId): void | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  |     { | 
					
						
							|  |  |  |         $newOwner = User::query()->find($newOwnerId); | 
					
						
							|  |  |  |         if (!is_null($newOwner)) { | 
					
						
							|  |  |  |             $entity->owned_by = $newOwner->id; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							| 
									
										
										
										
											2022-10-08 20:52:59 +08:00
										 |  |  |      * Format permissions provided from a permission form to be EntityPermission data. | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  |      */ | 
					
						
							| 
									
										
										
										
											2022-10-08 20:52:59 +08:00
										 |  |  |     protected function formatPermissionsFromRequestToEntityPermissions(array $permissions): array | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2022-10-08 20:52:59 +08:00
										 |  |  |         $formatted = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($permissions as $roleId => $info) { | 
					
						
							|  |  |  |             $entityPermissionData = ['role_id' => $roleId]; | 
					
						
							|  |  |  |             foreach (EntityPermission::PERMISSIONS as $permission) { | 
					
						
							|  |  |  |                 $entityPermissionData[$permission] = (($info[$permission] ?? false) === "true"); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             $formatted[] = $entityPermissionData; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-13 21:18:33 +08:00
										 |  |  |         return $this->filterEntityPermissionDataUponRole($formatted, true); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected function formatPermissionsFromApiRequestToEntityPermissions(array $permissions, bool $allowFallback): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $formatted = []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         foreach ($permissions as $requestPermissionData) { | 
					
						
							|  |  |  |             $entityPermissionData = ['role_id' => $requestPermissionData['role_id']]; | 
					
						
							|  |  |  |             foreach (EntityPermission::PERMISSIONS as $permission) { | 
					
						
							|  |  |  |                 $entityPermissionData[$permission] = boolval($requestPermissionData[$permission] ?? false); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             $formatted[] = $entityPermissionData; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $this->filterEntityPermissionDataUponRole($formatted, $allowFallback); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     protected function filterEntityPermissionDataUponRole(array $entityPermissionData, bool $allowFallback): array | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $roleIds = []; | 
					
						
							|  |  |  |         foreach ($entityPermissionData as $permissionEntry) { | 
					
						
							|  |  |  |             $roleIds[] = intval($permissionEntry['role_id']); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $actualRoleIds = array_unique(array_values(array_filter($roleIds))); | 
					
						
							|  |  |  |         $rolesById = Role::query()->whereIn('id', $actualRoleIds)->get('id')->keyBy('id'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return array_values(array_filter($entityPermissionData, function ($data) use ($rolesById, $allowFallback) { | 
					
						
							|  |  |  |             if (intval($data['role_id']) === 0) { | 
					
						
							|  |  |  |                 return $allowFallback; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return $rolesById->has($data['role_id']); | 
					
						
							|  |  |  |         })); | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-10-09 23:36:03 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * Copy down the permissions of the given shelf to all child books. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public function updateBookPermissionsFromShelf(Bookshelf $shelf, $checkUserPermissions = true): int | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $shelfPermissions = $shelf->permissions()->get(['role_id', 'view', 'create', 'update', 'delete'])->toArray(); | 
					
						
							| 
									
										
										
										
											2022-10-10 23:58:26 +08:00
										 |  |  |         $shelfBooks = $shelf->books()->get(['id', 'owned_by']); | 
					
						
							| 
									
										
										
										
											2022-10-09 23:36:03 +08:00
										 |  |  |         $updatedBookCount = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /** @var Book $book */ | 
					
						
							|  |  |  |         foreach ($shelfBooks as $book) { | 
					
						
							|  |  |  |             if ($checkUserPermissions && !userCan('restrictions-manage', $book)) { | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             $book->permissions()->delete(); | 
					
						
							|  |  |  |             $book->permissions()->createMany($shelfPermissions); | 
					
						
							|  |  |  |             $book->rebuildPermissions(); | 
					
						
							|  |  |  |             $updatedBookCount++; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $updatedBookCount; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-02 01:49:48 +08:00
										 |  |  | } |