]> BookStack Code Mirror - bookstack/blob - app/Auth/Permissions/MassEntityPermissionEvaluator.php
1bd2ec44a057f43cb3c05cf5a73ebe37ad20667c
[bookstack] / app / Auth / Permissions / MassEntityPermissionEvaluator.php
1 <?php
2
3 namespace BookStack\Auth\Permissions;
4
5 class MassEntityPermissionEvaluator extends EntityPermissionEvaluator
6 {
7     /**
8      * @var SimpleEntityData[]
9      */
10     protected array $entitiesInvolved;
11     protected array $permissionMapCache;
12
13     public function __construct(array $entitiesInvolved, string $action)
14     {
15         $this->entitiesInvolved = $entitiesInvolved;
16         parent::__construct($action);
17     }
18
19     public function evaluateEntityForRole(SimpleEntityData $entity, int $roleId): ?bool
20     {
21         $typeIdChain = $this->gatherEntityChainTypeIds($entity);
22         $relevantPermissions = $this->getPermissionMapByTypeIdForChainAndRole($typeIdChain, $roleId);
23         $permitsByType = $this->collapseAndCategorisePermissions($typeIdChain, $relevantPermissions);
24
25         return $this->evaluatePermitsByType($permitsByType);
26     }
27
28     /**
29      * @param string[] $typeIdChain
30      * @return array<string, EntityPermission[]>
31      */
32     protected function getPermissionMapByTypeIdForChainAndRole(array $typeIdChain, int $roleId): array
33     {
34         $allPermissions = $this->getPermissionMapByTypeIdAndRoleForAllInvolved();
35         $relevantPermissions = [];
36
37         // Filter down permissions to just those for current typeId
38         // and current roleID or fallback permissions.
39         foreach ($typeIdChain as $typeId) {
40             $relevantPermissions[$typeId] = [
41                 ...($allPermissions[$typeId][$roleId] ?? []),
42                 ...($allPermissions[$typeId][0] ?? [])
43             ];
44         }
45
46         return $relevantPermissions;
47     }
48
49     /**
50      * @return array<string, array<int, EntityPermission[]>>
51      */
52     protected function getPermissionMapByTypeIdAndRoleForAllInvolved(): array
53     {
54         if (isset($this->permissionMapCache)) {
55             return $this->permissionMapCache;
56         }
57
58         $entityTypeIdChain = [];
59         foreach ($this->entitiesInvolved as $entity) {
60             $entityTypeIdChain[] = $entity->type . ':' . $entity->id;
61         }
62
63         $permissionMap = $this->getPermissionsMapByTypeId($entityTypeIdChain, []);
64
65        // Manipulate permission map to also be keyed by roleId.
66         foreach ($permissionMap as $typeId => $permissions) {
67             $permissionMap[$typeId] = [];
68             foreach ($permissions as $permission) {
69                 $roleId = $permission->getRawAttribute('role_id');
70                 if (!isset($permissionMap[$typeId][$roleId])) {
71                     $permissionMap[$typeId][$roleId] = [];
72                 }
73                 $permissionMap[$typeId][$roleId][] = $permission;
74             }
75         }
76
77         $this->permissionMapCache = $permissionMap;
78
79         return $this->permissionMapCache;
80     }
81 }