X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/919660678bec2b94eaa84ac60d0313f5ef07dfb7..refs/pull/2023/head:/app/Auth/UserRepo.php diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index 87c0328d6..cfa7bfce1 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -1,39 +1,37 @@ user = $user; $this->role = $role; - $this->entityRepo = $entityRepo; } /** - * @param string $email - * @return User|null + * Get a user by their email address. */ - public function getByEmail($email) + public function getByEmail(string $email): ?User { return $this->user->where('email', '=', $email)->first(); } @@ -44,12 +42,12 @@ class UserRepo */ public function getById($id) { - return $this->user->findOrFail($id); + return $this->user->newQuery()->findOrFail($id); } /** * Get all the users with their permissions. - * @return \Illuminate\Database\Eloquent\Builder|static + * @return Builder|static */ public function getAllUsers() { @@ -60,7 +58,7 @@ class UserRepo * Get all the users with their permissions in a paginated format. * @param int $count * @param $sortData - * @return \Illuminate\Database\Eloquent\Builder|static + * @return Builder|static */ public function getAllUsersPaginatedAndSorted($count, $sortData) { @@ -79,33 +77,16 @@ class UserRepo /** * Creates a new user and attaches a role to them. - * @param array $data - * @param boolean $verifyEmail - * @return \BookStack\Auth\User */ - public function registerNew(array $data, $verifyEmail = false) + public function registerNew(array $data, bool $emailConfirmed = false): User { - $user = $this->create($data, $verifyEmail); - $this->attachDefaultRole($user); - - // Get avatar from gravatar and save - $this->downloadGravatarToUserAvatar($user); + $user = $this->create($data, $emailConfirmed); + $user->attachDefaultRole(); + $this->downloadAndAssignUserAvatar($user); return $user; } - /** - * Give a user the default role. Used when creating a new user. - * @param User $user - */ - public function attachDefaultRole(User $user) - { - $roleId = setting('registration-role'); - if ($roleId !== false && $user->roles()->where('id', '=', $roleId)->count() === 0) { - $user->attachRoleId($roleId); - } - } - /** * Assign a user to a system-level role. * @param User $user @@ -123,7 +104,7 @@ class UserRepo /** * Checks if the give user is the only admin. - * @param \BookStack\Auth\User $user + * @param User $user * @return bool */ public function isOnlyAdmin(User $user) @@ -140,34 +121,66 @@ class UserRepo } /** - * Create a new basic instance of user. - * @param array $data - * @param boolean $verifyEmail - * @return \BookStack\Auth\User + * 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 */ - public function create(array $data, $verifyEmail = false) + 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. + */ + public function create(array $data, bool $emailConfirmed = false): User + { return $this->user->forceCreate([ 'name' => $data['name'], 'email' => $data['email'], 'password' => bcrypt($data['password']), - 'email_confirmed' => $verifyEmail + 'email_confirmed' => $emailConfirmed, + 'external_auth_id' => $data['external_auth_id'] ?? '', ]); } /** * Remove the given user from storage, Delete all related content. - * @param \BookStack\Auth\User $user + * @param User $user * @throws Exception */ public function destroy(User $user) { $user->socialAccounts()->delete(); + $user->apiTokens()->delete(); $user->delete(); // Delete user profile images - $profileImages = $images = Image::where('type', '=', 'user')->where('created_by', '=', $user->id)->get(); + $profileImages = Image::where('type', '=', 'user')->where('uploaded_to', '=', $user->id)->get(); foreach ($profileImages as $image) { Images::destroy($image); } @@ -175,7 +188,7 @@ class UserRepo /** * Get the latest activity for a user. - * @param \BookStack\Auth\User $user + * @param User $user * @param int $count * @param int $page * @return array @@ -187,36 +200,35 @@ class UserRepo /** * Get the recently created content for this given user. - * @param \BookStack\Auth\User $user - * @param int $count - * @return mixed */ - public function getRecentlyCreated(User $user, $count = 20) + public function getRecentlyCreated(User $user, int $count = 20): array { + $query = function (Builder $query) use ($user, $count) { + return $query->orderBy('created_at', 'desc') + ->where('created_by', '=', $user->id) + ->take($count) + ->get(); + }; + return [ - 'pages' => $this->entityRepo->getRecentlyCreated('page', $count, 0, function ($query) use ($user) { - $query->where('created_by', '=', $user->id); - }), - 'chapters' => $this->entityRepo->getRecentlyCreated('chapter', $count, 0, function ($query) use ($user) { - $query->where('created_by', '=', $user->id); - }), - 'books' => $this->entityRepo->getRecentlyCreated('book', $count, 0, function ($query) use ($user) { - $query->where('created_by', '=', $user->id); - }) + 'pages' => $query(Page::visible()->where('draft', '=', false)), + 'chapters' => $query(Chapter::visible()), + 'books' => $query(Book::visible()), + 'shelves' => $query(Bookshelf::visible()), ]; } /** * Get asset created counts for the give user. - * @param \BookStack\Auth\User $user - * @return array */ - public function getAssetCounts(User $user) + public function getAssetCounts(User $user): array { + $createdBy = ['created_by' => $user->id]; return [ - 'pages' => $this->entityRepo->page->where('created_by', '=', $user->id)->count(), - 'chapters' => $this->entityRepo->chapter->where('created_by', '=', $user->id)->count(), - 'books' => $this->entityRepo->book->where('created_by', '=', $user->id)->count(), + 'pages' => Page::visible()->where($createdBy)->count(), + 'chapters' => Chapter::visible()->where($createdBy)->count(), + 'books' => Book::visible()->where($createdBy)->count(), + 'shelves' => Bookshelf::visible()->where($createdBy)->count(), ]; } @@ -226,39 +238,28 @@ class UserRepo */ public function getAllRoles() { - return $this->role->all(); - } - - /** - * Get all the roles which can be given restricted access to - * other entities in the system. - * @return mixed - */ - public function getRestrictableRoles() - { - return $this->role->where('system_name', '!=', 'admin')->get(); + return $this->role->newQuery()->orderBy('name', 'asc')->get(); } /** - * Get a gravatar image for a user and set it as their avatar. - * Does not run if gravatar disabled in config. + * Get an avatar image for a user and set it as their avatar. + * Returns early if avatars disabled or not set in config. * @param User $user * @return bool */ - public function downloadGravatarToUserAvatar(User $user) + public function downloadAndAssignUserAvatar(User $user) { - // Get avatar from gravatar and save - if (!config('services.gravatar')) { + if (!Images::avatarFetchEnabled()) { return false; } try { - $avatar = Images::saveUserGravatar($user); + $avatar = Images::saveUserAvatar($user); $user->avatar()->associate($avatar); $user->save(); return true; } catch (Exception $e) { - \Log::error('Failed to save user gravatar image'); + Log::error('Failed to save user avatar image'); return false; } }