Will show error message if last admin and admin role is removed.
Closes #1124
Also cleaned up user controller a little.
use Activity;
use BookStack\Entities\Repos\EntityRepo;
use BookStack\Exceptions\NotFoundException;
+use BookStack\Exceptions\UserUpdateException;
use BookStack\Uploads\Image;
use Exception;
use Images;
*/
public function getById($id)
{
- return $this->user->findOrFail($id);
+ return $this->user->newQuery()->findOrFail($id);
}
/**
return true;
}
+ /**
+ * Set the assigned user roles via an array of role IDs.
+ * @param User $user
+ * @param array $roles
+ * @throws UserUpdateException
+ */
+ public function setUserRoles(User $user, array $roles)
+ {
+ if ($this->demotingLastAdmin($user, $roles)) {
+ throw new UserUpdateException(trans('errors.role_cannot_remove_only_admin'), $user->getEditUrl());
+ }
+
+ $user->roles()->sync($roles);
+ }
+
+ /**
+ * Check if the given user is the last admin and their new roles no longer
+ * contains the admin role.
+ * @param User $user
+ * @param array $newRoles
+ * @return bool
+ */
+ protected function demotingLastAdmin(User $user, array $newRoles) : bool
+ {
+ if ($this->isOnlyAdmin($user)) {
+ $adminRole = $this->role->getSystemRole('admin');
+ if (!in_array(strval($adminRole->id), $newRoles)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/**
* Create a new basic instance of user.
* @param array $data
*/
public function create(array $data, $verifyEmail = false)
{
-
return $this->user->forceCreate([
'name' => $data['name'],
'email' => $data['email'],
* @param string $message
* @param string $redirectLocation
*/
- public function __construct($message, $redirectLocation)
+ public function __construct(string $message, string $redirectLocation = "/")
{
$this->message = $message;
$this->redirectLocation = $redirectLocation;
--- /dev/null
+<?php namespace BookStack\Exceptions;
+
+class UserUpdateException extends NotifyException {}
use BookStack\Auth\Access\SocialAuthService;
use BookStack\Auth\User;
use BookStack\Auth\UserRepo;
+use BookStack\Exceptions\UserUpdateException;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
/**
* UserController constructor.
* @param User $user
- * @param \BookStack\Auth\UserRepo $userRepo
+ * @param UserRepo $userRepo
*/
public function __construct(User $user, UserRepo $userRepo)
{
* Store a newly created user in storage.
* @param Request $request
* @return Response
+ * @throws UserUpdateException
*/
public function store(Request $request)
{
if ($request->filled('roles')) {
$roles = $request->get('roles');
- $user->roles()->sync($roles);
+ $this->userRepo->setUserRoles($user, $roles);
}
$this->userRepo->downloadAndAssignUserAvatar($user);
/**
* Update the specified user in storage.
* @param Request $request
- * @param int $id
+ * @param int $id
* @return Response
+ * @throws UserUpdateException
*/
public function update(Request $request, $id)
{
'setting' => 'array'
]);
- $user = $this->user->findOrFail($id);
+ $user = $this->userRepo->getById($id);
$user->fill($request->all());
// Role updates
if (userCan('users-manage') && $request->filled('roles')) {
$roles = $request->get('roles');
- $user->roles()->sync($roles);
+ $this->userRepo->setUserRoles($user, $roles);
}
// Password updates
return $this->currentUser->id == $id;
});
- $user = $this->user->findOrFail($id);
+ $user = $this->userRepo->getById($id);
$this->setPageTitle(trans('settings.users_delete_named', ['userName' => $user->name]));
return view('users/delete', ['user' => $user]);
}
* Remove the specified user from storage.
* @param int $id
* @return Response
+ * @throws \Exception
*/
public function destroy($id)
{
$viewType = 'list';
}
- $user = $this->user->findOrFail($id);
+ $user = $this->userRepo->getById($id);
setting()->putUser($user, 'bookshelves_view_type', $viewType);
return redirect()->back(302, [], "/settings/users/$id");
'role_cannot_be_edited' => 'This role cannot be edited',
'role_system_cannot_be_deleted' => 'This role is a system role and cannot be deleted',
'role_registration_default_cannot_delete' => 'This role cannot be deleted while set as the default registration role',
+ 'role_cannot_remove_only_admin' => 'This user is the only user assigned to the administrator role. Assign the administrator role to another user before attempting to remove it here.',
// Comments
'comment_list' => 'An error occurred while fetching the comments.',
->dontSee($testRoleUpdateName);
}
+ public function test_admin_role_cannot_be_removed_if_last_admin()
+ {
+ $adminRole = Role::where('system_name', '=', 'admin')->first();
+ $adminUser = $this->getAdmin();
+ $adminRole->users()->where('id', '!=', $adminUser->id)->delete();
+ $this->assertEquals($adminRole->users()->count(), 1);
+
+ $viewerRole = $this->getViewer()->roles()->first();
+
+ $editUrl = '/settings/users/' . $adminUser->id;
+ $this->actingAs($adminUser)->put($editUrl, [
+ 'name' => $adminUser->name,
+ 'email' => $adminUser->email,
+ 'roles' => [
+ 'viewer' => strval($viewerRole->id),
+ ]
+ ])->followRedirects();
+
+ $this->seePageIs($editUrl);
+ $this->see('This user is the only user assigned to the administrator role');
+ }
+
public function test_manage_user_permission()
{
$this->actingAs($this->user)->visit('/settings/users')