1 <?php namespace BookStack\Auth;
4 use BookStack\Entities\Models\Book;
5 use BookStack\Entities\Models\Bookshelf;
6 use BookStack\Entities\Models\Chapter;
7 use BookStack\Entities\Models\Page;
8 use BookStack\Exceptions\NotFoundException;
9 use BookStack\Exceptions\UserUpdateException;
10 use BookStack\Uploads\Image;
12 use Illuminate\Database\Eloquent\Builder;
13 use Illuminate\Pagination\LengthAwarePaginator;
24 * UserRepo constructor.
26 public function __construct(User $user, Role $role)
33 * Get a user by their email address.
35 public function getByEmail(string $email): ?User
37 return $this->user->where('email', '=', $email)->first();
44 public function getById($id)
46 return $this->user->newQuery()->findOrFail($id);
50 * Get all the users with their permissions.
51 * @return Builder|static
53 public function getAllUsers()
55 return $this->user->with('roles', 'avatar')->orderBy('name', 'asc')->get();
59 * Get all the users with their permissions in a paginated format.
61 public function getAllUsersPaginatedAndSorted(int $count, array $sortData): LengthAwarePaginator
63 $sort = $sortData['sort'];
64 if ($sort === 'latest_activity') {
65 $sort = \BookStack\Actions\Activity::query()->select('created_at')
66 ->whereColumn('activities.user_id', 'users.id')
71 $query = $this->user->with(['roles', 'avatar', 'latestActivity'])
72 ->orderBy($sort, $sortData['order']);
74 if ($sortData['search']) {
75 $term = '%' . $sortData['search'] . '%';
76 $query->where(function ($query) use ($term) {
77 $query->where('name', 'like', $term)
78 ->orWhere('email', 'like', $term);
82 return $query->paginate($count);
86 * Creates a new user and attaches a role to them.
88 public function registerNew(array $data, bool $emailConfirmed = false): User
90 $user = $this->create($data, $emailConfirmed);
91 $user->attachDefaultRole();
92 $this->downloadAndAssignUserAvatar($user);
98 * Assign a user to a system-level role.
100 * @param $systemRoleName
101 * @throws NotFoundException
103 public function attachSystemRole(User $user, $systemRoleName)
105 $role = $this->role->newQuery()->where('system_name', '=', $systemRoleName)->first();
106 if ($role === null) {
107 throw new NotFoundException("Role '{$systemRoleName}' not found");
109 $user->attachRole($role);
113 * Checks if the give user is the only admin.
117 public function isOnlyAdmin(User $user)
119 if (!$user->hasSystemRole('admin')) {
123 $adminRole = $this->role->getSystemRole('admin');
124 if ($adminRole->users->count() > 1) {
131 * Set the assigned user roles via an array of role IDs.
133 * @param array $roles
134 * @throws UserUpdateException
136 public function setUserRoles(User $user, array $roles)
138 if ($this->demotingLastAdmin($user, $roles)) {
139 throw new UserUpdateException(trans('errors.role_cannot_remove_only_admin'), $user->getEditUrl());
142 $user->roles()->sync($roles);
146 * Check if the given user is the last admin and their new roles no longer
147 * contains the admin role.
149 * @param array $newRoles
152 protected function demotingLastAdmin(User $user, array $newRoles) : bool
154 if ($this->isOnlyAdmin($user)) {
155 $adminRole = $this->role->getSystemRole('admin');
156 if (!in_array(strval($adminRole->id), $newRoles)) {
165 * Create a new basic instance of user.
167 public function create(array $data, bool $emailConfirmed = false): User
169 return $this->user->forceCreate([
170 'name' => $data['name'],
171 'email' => $data['email'],
172 'password' => bcrypt($data['password']),
173 'email_confirmed' => $emailConfirmed,
174 'external_auth_id' => $data['external_auth_id'] ?? '',
179 * Remove the given user from storage, Delete all related content.
183 public function destroy(User $user)
185 $user->socialAccounts()->delete();
186 $user->apiTokens()->delete();
189 // Delete user profile images
190 $profileImages = Image::where('type', '=', 'user')->where('uploaded_to', '=', $user->id)->get();
191 foreach ($profileImages as $image) {
192 Images::destroy($image);
197 * Get the latest activity for a user.
203 public function getActivity(User $user, $count = 20, $page = 0)
205 return Activity::userActivity($user, $count, $page);
209 * Get the recently created content for this given user.
211 public function getRecentlyCreated(User $user, int $count = 20): array
213 $query = function (Builder $query) use ($user, $count) {
214 return $query->orderBy('created_at', 'desc')
215 ->where('created_by', '=', $user->id)
221 'pages' => $query(Page::visible()->where('draft', '=', false)),
222 'chapters' => $query(Chapter::visible()),
223 'books' => $query(Book::visible()),
224 'shelves' => $query(Bookshelf::visible()),
229 * Get asset created counts for the give user.
231 public function getAssetCounts(User $user): array
233 $createdBy = ['created_by' => $user->id];
235 'pages' => Page::visible()->where($createdBy)->count(),
236 'chapters' => Chapter::visible()->where($createdBy)->count(),
237 'books' => Book::visible()->where($createdBy)->count(),
238 'shelves' => Bookshelf::visible()->where($createdBy)->count(),
243 * Get the roles in the system that are assignable to a user.
246 public function getAllRoles()
248 return $this->role->newQuery()->orderBy('display_name', 'asc')->get();
252 * Get an avatar image for a user and set it as their avatar.
253 * Returns early if avatars disabled or not set in config.
257 public function downloadAndAssignUserAvatar(User $user)
259 if (!Images::avatarFetchEnabled()) {
264 $avatar = Images::saveUserAvatar($user);
265 $user->avatar()->associate($avatar);
268 } catch (Exception $e) {
269 Log::error('Failed to save user avatar image');