X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/3286f29a61833327b5701b28db626d0a480b07f9..refs/pull/3081/head:/app/Auth/UserRepo.php diff --git a/app/Auth/UserRepo.php b/app/Auth/UserRepo.php index b2ff0bc58..6d48f1240 100644 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@ -1,69 +1,78 @@ -userAvatar = $userAvatar; + } + + /** + * Get a user by their email address. + */ + public function getByEmail(string $email): ?User { - $this->user = $user; - $this->role = $role; - $this->entityRepo = $entityRepo; + return User::query()->where('email', '=', $email)->first(); } /** - * @param string $email - * @return User|null + * Get a user by their ID. */ - public function getByEmail($email) + public function getById(int $id): User { - return $this->user->where('email', '=', $email)->first(); + return User::query()->findOrFail($id); } /** - * @param int $id - * @return User + * Get a user by their slug. */ - public function getById($id) + public function getBySlug(string $slug): User { - return $this->user->newQuery()->findOrFail($id); + return User::query()->where('slug', '=', $slug)->firstOrFail(); } /** * Get all the users with their permissions. - * @return \Illuminate\Database\Eloquent\Builder|static */ - public function getAllUsers() + public function getAllUsers(): Collection { - return $this->user->with('roles', 'avatar')->orderBy('name', 'asc')->get(); + return User::query()->with('roles', 'avatar')->orderBy('name', 'asc')->get(); } /** * Get all the users with their permissions in a paginated format. - * @param int $count - * @param $sortData - * @return \Illuminate\Database\Eloquent\Builder|static */ - public function getAllUsersPaginatedAndSorted($count, $sortData) + public function getAllUsersPaginatedAndSorted(int $count, array $sortData): LengthAwarePaginator { - $query = $this->user->with('roles', 'avatar')->orderBy($sortData['sort'], $sortData['order']); + $sort = $sortData['sort']; + + $query = User::query()->select(['*']) + ->withLastActivityAt() + ->with(['roles', 'avatar']) + ->withCount('mfaValues') + ->orderBy($sort, $sortData['order']); if ($sortData['search']) { $term = '%' . $sortData['search'] . '%'; @@ -76,43 +85,27 @@ class UserRepo return $query->paginate($count); } - /** + /** * 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); + $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 - * @param $systemRoleName + * * @throws NotFoundException */ - public function attachSystemRole(User $user, $systemRoleName) + public function attachSystemRole(User $user, string $systemRoleName) { - $role = $this->role->newQuery()->where('system_name', '=', $systemRoleName)->first(); - if ($role === null) { + $role = Role::getSystemRole($systemRoleName); + if (is_null($role)) { throw new NotFoundException("Role '{$systemRoleName}' not found"); } $user->attachRole($role); @@ -120,26 +113,24 @@ class UserRepo /** * Checks if the give user is the only admin. - * @param \BookStack\Auth\User $user - * @return bool */ - public function isOnlyAdmin(User $user) + public function isOnlyAdmin(User $user): bool { if (!$user->hasSystemRole('admin')) { return false; } - $adminRole = $this->role->getSystemRole('admin'); - if ($adminRole->users->count() > 1) { + $adminRole = Role::getSystemRole('admin'); + if ($adminRole->users()->count() > 1) { return false; } + 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) @@ -154,14 +145,11 @@ class UserRepo /** * 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 + protected function demotingLastAdmin(User $user, array $newRoles): bool { if ($this->isOnlyAdmin($user)) { - $adminRole = $this->role->getSystemRole('admin'); + $adminRole = Role::getSystemRole('admin'); if (!in_array(strval($adminRole->id), $newRoles)) { return true; } @@ -172,123 +160,122 @@ class UserRepo /** * Create a new basic instance of user. - * @param array $data - * @param boolean $verifyEmail - * @return \BookStack\Auth\User */ - public function create(array $data, $verifyEmail = false) + 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 - ]); + $details = [ + 'name' => $data['name'], + 'email' => $data['email'], + 'password' => bcrypt($data['password']), + 'email_confirmed' => $emailConfirmed, + 'external_auth_id' => $data['external_auth_id'] ?? '', + ]; + + $user = new User(); + $user->forceFill($details); + $user->refreshSlug(); + $user->save(); + + return $user; } /** * Remove the given user from storage, Delete all related content. - * @param \BookStack\Auth\User $user + * * @throws Exception */ - public function destroy(User $user) + public function destroy(User $user, ?int $newOwnerId = null) { $user->socialAccounts()->delete(); + $user->apiTokens()->delete(); + $user->favourites()->delete(); + $user->mfaValues()->delete(); $user->delete(); - + // Delete user profile images - $profileImages = $images = Image::where('type', '=', 'user')->where('created_by', '=', $user->id)->get(); - foreach ($profileImages as $image) { - Images::destroy($image); + $this->userAvatar->destroyAllForUser($user); + + if (!empty($newOwnerId)) { + $newOwner = User::query()->find($newOwnerId); + if (!is_null($newOwner)) { + $this->migrateOwnership($user, $newOwner); + } + } + } + + /** + * Migrate ownership of items in the system from one user to another. + */ + protected function migrateOwnership(User $fromUser, User $toUser) + { + $entities = (new EntityProvider())->all(); + foreach ($entities as $instance) { + $instance->newQuery()->where('owned_by', '=', $fromUser->id) + ->update(['owned_by' => $toUser->id]); } } /** * Get the latest activity for a user. - * @param \BookStack\Auth\User $user - * @param int $count - * @param int $page - * @return array */ - public function getActivity(User $user, $count = 20, $page = 0) + public function getActivity(User $user, int $count = 20, int $page = 0): array { return Activity::userActivity($user, $count, $page); } /** * 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->getUserTotalCreated('page', $user), - 'chapters' => $this->entityRepo->getUserTotalCreated('chapter', $user), - 'books' => $this->entityRepo->getUserTotalCreated('book', $user), + 'pages' => Page::visible()->where($createdBy)->count(), + 'chapters' => Chapter::visible()->where($createdBy)->count(), + 'books' => Book::visible()->where($createdBy)->count(), + 'shelves' => Bookshelf::visible()->where($createdBy)->count(), ]; } /** * Get the roles in the system that are assignable to a user. - * @return mixed - */ - public function getAllRoles() - { - return $this->role->newQuery()->orderBy('name', 'asc')->get(); - } - - /** - * Get all the roles which can be given restricted access to - * other entities in the system. - * @return mixed */ - public function getRestrictableRoles() + public function getAllRoles(): Collection { - return $this->role->where('system_name', '!=', 'admin')->get(); + return Role::query()->orderBy('display_name', 'asc')->get(); } /** * 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 downloadAndAssignUserAvatar(User $user) + public function downloadAndAssignUserAvatar(User $user): void { - if (!Images::avatarFetchEnabled()) { - return false; - } - try { - $avatar = Images::saveUserAvatar($user); - $user->avatar()->associate($avatar); - $user->save(); - return true; + $this->userAvatar->fetchAndAssignToUser($user); } catch (Exception $e) { - \Log::error('Failed to save user avatar image'); - return false; + Log::error('Failed to save user avatar image'); } } }