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