3 namespace BookStack\Permissions;
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;
12 use Illuminate\Database\Eloquent\Collection;
16 protected array $systemRoles = ['admin', 'public'];
18 public function __construct(
19 protected JointPermissionBuilder $permissionBuilder
24 * Get all the user roles from the system.
26 public function getAllRoles(): Collection
28 return Role::query()->get();
32 * Get all the roles except for the provided one.
34 public function getAllRolesExcept(Role $role): Collection
36 return Role::query()->where('id', '!=', $role->id)->get();
40 * Get a role via its ID.
42 public function getRoleById(int $id): Role
44 return Role::query()->findOrFail($id);
48 * Save a new role into the system.
50 public function saveNewRole(array $roleData): Role
52 return (new DatabaseTransaction(function () use ($roleData) {
53 $role = new Role($roleData);
54 $role->mfa_enforced = boolval($roleData['mfa_enforced'] ?? false);
57 $permissions = $roleData['permissions'] ?? [];
58 $this->assignRolePermissions($role, $permissions);
59 $this->permissionBuilder->rebuildForRole($role);
61 Activity::add(ActivityType::ROLE_CREATE, $role);
68 * Updates an existing role.
69 * Ensures the Admin system role always has core permissions.
71 public function updateRole($roleId, array $roleData): Role
73 $role = $this->getRoleById($roleId);
75 return (new DatabaseTransaction(function () use ($role, $roleData) {
76 if (isset($roleData['permissions'])) {
77 $this->assignRolePermissions($role, $roleData['permissions']);
80 $role->fill($roleData);
82 $this->permissionBuilder->rebuildForRole($role);
84 Activity::add(ActivityType::ROLE_UPDATE, $role);
91 * Assign a list of permission names to the given role.
93 protected function assignRolePermissions(Role $role, array $permissionNameArray = []): void
96 $permissionNameArray = array_values($permissionNameArray);
98 // Ensure the admin system role retains vital system permissions
99 if ($role->system_name === 'admin') {
100 $permissionNameArray = array_unique(array_merge($permissionNameArray, [
103 'restrictions-manage-all',
104 'restrictions-manage-own',
109 if (!empty($permissionNameArray)) {
110 $permissions = RolePermission::query()
111 ->whereIn('name', $permissionNameArray)
116 $role->permissions()->sync($permissions);
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.
125 * @throws PermissionsException
128 public function deleteRole(int $roleId, int $migrateRoleId = 0): void
130 $role = $this->getRoleById($roleId);
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'));
139 (new DatabaseTransaction(function () use ($migrateRoleId, $role) {
140 if ($migrateRoleId !== 0) {
141 $newRole = Role::query()->find($migrateRoleId);
143 $users = $role->users()->pluck('id')->toArray();
144 $newRole->users()->sync($users);
148 $role->entityPermissions()->delete();
149 $role->jointPermissions()->delete();
150 Activity::add(ActivityType::ROLE_DELETE, $role);