]> BookStack Code Mirror - bookstack/blob - app/Permissions/PermissionsRepo.php
Perms: Fixed some issues made when adding transactions
[bookstack] / app / Permissions / PermissionsRepo.php
1 <?php
2
3 namespace BookStack\Permissions;
4
5 use BookStack\Activity\ActivityType;
6 use BookStack\Exceptions\PermissionsException;
7 use BookStack\Facades\Activity;
8 use BookStack\Permissions\Models\RolePermission;
9 use BookStack\Users\Models\Role;
10 use BookStack\Util\DatabaseTransaction;
11 use Exception;
12 use Illuminate\Database\Eloquent\Collection;
13
14 class PermissionsRepo
15 {
16     protected array $systemRoles = ['admin', 'public'];
17
18     public function __construct(
19         protected JointPermissionBuilder $permissionBuilder
20     ) {
21     }
22
23     /**
24      * Get all the user roles from the system.
25      */
26     public function getAllRoles(): Collection
27     {
28         return Role::query()->get();
29     }
30
31     /**
32      * Get all the roles except for the provided one.
33      */
34     public function getAllRolesExcept(Role $role): Collection
35     {
36         return Role::query()->where('id', '!=', $role->id)->get();
37     }
38
39     /**
40      * Get a role via its ID.
41      */
42     public function getRoleById(int $id): Role
43     {
44         return Role::query()->findOrFail($id);
45     }
46
47     /**
48      * Save a new role into the system.
49      */
50     public function saveNewRole(array $roleData): Role
51     {
52         return (new DatabaseTransaction(function () use ($roleData) {
53             $role = new Role($roleData);
54             $role->mfa_enforced = boolval($roleData['mfa_enforced'] ?? false);
55             $role->save();
56
57             $permissions = $roleData['permissions'] ?? [];
58             $this->assignRolePermissions($role, $permissions);
59             $this->permissionBuilder->rebuildForRole($role);
60
61             Activity::add(ActivityType::ROLE_CREATE, $role);
62
63             return $role;
64         }))->run();
65     }
66
67     /**
68      * Updates an existing role.
69      * Ensures the Admin system role always has core permissions.
70      */
71     public function updateRole($roleId, array $roleData): Role
72     {
73         $role = $this->getRoleById($roleId);
74
75         return (new DatabaseTransaction(function () use ($role, $roleData) {
76             if (isset($roleData['permissions'])) {
77                 $this->assignRolePermissions($role, $roleData['permissions']);
78             }
79
80             $role->fill($roleData);
81             $role->save();
82             $this->permissionBuilder->rebuildForRole($role);
83
84             Activity::add(ActivityType::ROLE_UPDATE, $role);
85
86             return $role;
87         }))->run();
88     }
89
90     /**
91      * Assign a list of permission names to the given role.
92      */
93     protected function assignRolePermissions(Role $role, array $permissionNameArray = []): void
94     {
95         $permissions = [];
96         $permissionNameArray = array_values($permissionNameArray);
97
98         // Ensure the admin system role retains vital system permissions
99         if ($role->system_name === 'admin') {
100             $permissionNameArray = array_unique(array_merge($permissionNameArray, [
101                 'users-manage',
102                 'user-roles-manage',
103                 'restrictions-manage-all',
104                 'restrictions-manage-own',
105                 'settings-manage',
106             ]));
107         }
108
109         if (!empty($permissionNameArray)) {
110             $permissions = RolePermission::query()
111                 ->whereIn('name', $permissionNameArray)
112                 ->pluck('id')
113                 ->toArray();
114         }
115
116         $role->permissions()->sync($permissions);
117     }
118
119     /**
120      * Delete a role from the system.
121      * Check it's not an admin role or set as default before deleting.
122      * If a migration Role ID is specified, the users assigned to the current role
123      * will be added to the role of the specified id.
124      *
125      * @throws PermissionsException
126      * @throws Exception
127      */
128     public function deleteRole(int $roleId, int $migrateRoleId = 0): void
129     {
130         $role = $this->getRoleById($roleId);
131
132         // Prevent deleting admin role or default registration role.
133         if ($role->system_name && in_array($role->system_name, $this->systemRoles)) {
134             throw new PermissionsException(trans('errors.role_system_cannot_be_deleted'));
135         } elseif ($role->id === intval(setting('registration-role'))) {
136             throw new PermissionsException(trans('errors.role_registration_default_cannot_delete'));
137         }
138
139         (new DatabaseTransaction(function () use ($migrateRoleId, $role) {
140             if ($migrateRoleId !== 0) {
141                 $newRole = Role::query()->find($migrateRoleId);
142                 if ($newRole) {
143                     $users = $role->users()->pluck('id')->toArray();
144                     $newRole->users()->sync($users);
145                 }
146             }
147
148             $role->entityPermissions()->delete();
149             $role->jointPermissions()->delete();
150             Activity::add(ActivityType::ROLE_DELETE, $role);
151             $role->delete();
152         }))->run();
153     }
154 }