]> BookStack Code Mirror - bookstack/blob - app/Auth/UserRepo.php
Extend /users API endpoint
[bookstack] / app / Auth / UserRepo.php
1 <?php namespace BookStack\Auth;
2
3 use Activity;
4 use BookStack\Entities\EntityProvider;
5 use BookStack\Entities\Models\Book;
6 use BookStack\Entities\Models\Bookshelf;
7 use BookStack\Entities\Models\Chapter;
8 use BookStack\Entities\Models\Page;
9 use BookStack\Exceptions\NotFoundException;
10 use BookStack\Exceptions\UserUpdateException;
11 use BookStack\Uploads\Image;
12 use BookStack\Uploads\UserAvatars;
13 use Exception;
14 use Illuminate\Database\Eloquent\Builder;
15 use Illuminate\Database\Eloquent\Collection;
16 use Illuminate\Pagination\LengthAwarePaginator;
17 use Images;
18 use Log;
19
20 class UserRepo
21 {
22     protected $userAvatar;
23
24     /**
25      * UserRepo constructor.
26      */
27     public function __construct(UserAvatars $userAvatar)
28     {
29         $this->userAvatar = $userAvatar;
30     }
31
32     /**
33      * Get a user by their email address.
34      */
35     public function getByEmail(string $email): ?User
36     {
37         return User::query()->where('email', '=', $email)->first();
38     }
39
40     /**
41      * Get a user by their ID.
42      */
43     public function getById(int $id): User
44     {
45         return User::query()->findOrFail($id);
46     }
47
48     /**
49      * Get a user by their slug.
50      */
51     public function getBySlug(string $slug): User
52     {
53         return User::query()->where('slug', '=', $slug)->firstOrFail();
54     }
55
56     /**
57      * Get all the users with their permissions.
58      */
59     public function getAllUsers(): Collection
60     {
61         return User::query()->with('roles', 'avatar')->orderBy('name', 'asc')->get();
62     }
63
64     /**
65      * Get all users as Builder for API
66      */
67     public function getUsersBuilder(int $id = null ) : Builder
68     {
69         $query = User::query()->select(['*'])
70             ->withLastActivityAt()
71             ->with(['roles', 'avatar']);
72         return $query;
73     }
74     /**
75      * Get all the users with their permissions in a paginated format.
76      */
77     public function getAllUsersPaginatedAndSorted(int $count, array $sortData): LengthAwarePaginator
78     {
79         $sort = $sortData['sort'];
80
81         $query = User::query()->select(['*'])
82             ->withLastActivityAt()
83             ->with(['roles', 'avatar'])
84             ->orderBy($sort, $sortData['order']);
85
86         if ($sortData['search']) {
87             $term = '%' . $sortData['search'] . '%';
88             $query->where(function ($query) use ($term) {
89                 $query->where('name', 'like', $term)
90                     ->orWhere('email', 'like', $term);
91             });
92         }
93
94         return $query->paginate($count);
95     }
96
97      /**
98      * Creates a new user and attaches a role to them.
99      */
100     public function registerNew(array $data, bool $emailConfirmed = false): User
101     {
102         $user = $this->create($data, $emailConfirmed);
103         $user->attachDefaultRole();
104         $this->downloadAndAssignUserAvatar($user);
105
106         return $user;
107     }
108
109     /**
110      * Assign a user to a system-level role.
111      * @throws NotFoundException
112      */
113     public function attachSystemRole(User $user, string $systemRoleName)
114     {
115         $role = Role::getSystemRole($systemRoleName);
116         if (is_null($role)) {
117             throw new NotFoundException("Role '{$systemRoleName}' not found");
118         }
119         $user->attachRole($role);
120     }
121
122     /**
123      * Checks if the give user is the only admin.
124      */
125     public function isOnlyAdmin(User $user): bool
126     {
127         if (!$user->hasSystemRole('admin')) {
128             return false;
129         }
130
131         $adminRole = Role::getSystemRole('admin');
132         if ($adminRole->users()->count() > 1) {
133             return false;
134         }
135
136         return true;
137     }
138
139     /**
140      * Set the assigned user roles via an array of role IDs.
141      * @throws UserUpdateException
142      */
143     public function setUserRoles(User $user, array $roles)
144     {
145         if ($this->demotingLastAdmin($user, $roles)) {
146             throw new UserUpdateException(trans('errors.role_cannot_remove_only_admin'), $user->getEditUrl());
147         }
148
149         $user->roles()->sync($roles);
150     }
151
152     /**
153      * Check if the given user is the last admin and their new roles no longer
154      * contains the admin role.
155      */
156     protected function demotingLastAdmin(User $user, array $newRoles) : bool
157     {
158         if ($this->isOnlyAdmin($user)) {
159             $adminRole = Role::getSystemRole('admin');
160             if (!in_array(strval($adminRole->id), $newRoles)) {
161                 return true;
162             }
163         }
164
165         return false;
166     }
167
168     /**
169      * Create a new basic instance of user.
170      */
171     public function create(array $data, bool $emailConfirmed = false): User
172     {
173         $details = [
174             'name'     => $data['name'],
175             'email'    => $data['email'],
176             'password' => bcrypt($data['password']),
177             'email_confirmed' => $emailConfirmed,
178             'external_auth_id' => $data['external_auth_id'] ?? '',
179         ];
180
181         $user = new User();
182         $user->forceFill($details);
183         $user->refreshSlug();
184         $user->save();
185
186         return $user;
187     }
188
189     /**
190      * Remove the given user from storage, Delete all related content.
191      * @throws Exception
192      */
193     public function destroy(User $user, ?int $newOwnerId = null)
194     {
195         $user->socialAccounts()->delete();
196         $user->apiTokens()->delete();
197         $user->delete();
198         
199         // Delete user profile images
200         $profileImages = Image::query()->where('type', '=', 'user')
201             ->where('uploaded_to', '=', $user->id)
202             ->get();
203
204         foreach ($profileImages as $image) {
205             Images::destroy($image);
206         }
207
208         if (!empty($newOwnerId)) {
209             $newOwner = User::query()->find($newOwnerId);
210             if (!is_null($newOwner)) {
211                 $this->migrateOwnership($user, $newOwner);
212             }
213         }
214     }
215
216     /**
217      * Migrate ownership of items in the system from one user to another.
218      */
219     protected function migrateOwnership(User $fromUser, User $toUser)
220     {
221         $entities = (new EntityProvider)->all();
222         foreach ($entities as $instance) {
223             $instance->newQuery()->where('owned_by', '=', $fromUser->id)
224                 ->update(['owned_by' => $toUser->id]);
225         }
226     }
227
228     /**
229      * Get the latest activity for a user.
230      */
231     public function getActivity(User $user, int $count = 20, int $page = 0): array
232     {
233         return Activity::userActivity($user, $count, $page);
234     }
235
236     /**
237      * Get the recently created content for this given user.
238      */
239     public function getRecentlyCreated(User $user, int $count = 20): array
240     {
241         $query = function (Builder $query) use ($user, $count) {
242             return $query->orderBy('created_at', 'desc')
243                 ->where('created_by', '=', $user->id)
244                 ->take($count)
245                 ->get();
246         };
247
248         return [
249             'pages'    => $query(Page::visible()->where('draft', '=', false)),
250             'chapters' => $query(Chapter::visible()),
251             'books'    => $query(Book::visible()),
252             'shelves'  => $query(Bookshelf::visible()),
253         ];
254     }
255
256     /**
257      * Get asset created counts for the give user.
258      */
259     public function getAssetCounts(User $user): array
260     {
261         $createdBy = ['created_by' => $user->id];
262         return [
263             'pages'    =>  Page::visible()->where($createdBy)->count(),
264             'chapters'    =>  Chapter::visible()->where($createdBy)->count(),
265             'books'    =>  Book::visible()->where($createdBy)->count(),
266             'shelves'    =>  Bookshelf::visible()->where($createdBy)->count(),
267         ];
268     }
269
270     /**
271      * Get the roles in the system that are assignable to a user.
272      */
273     public function getAllRoles(): Collection
274     {
275         return Role::query()->orderBy('display_name', 'asc')->get();
276     }
277
278     /**
279      * Get an avatar image for a user and set it as their avatar.
280      * Returns early if avatars disabled or not set in config.
281      */
282     public function downloadAndAssignUserAvatar(User $user): void
283     {
284         try {
285             $this->userAvatar->fetchAndAssignToUser($user);
286         } catch (Exception $e) {
287             Log::error('Failed to save user avatar image');
288         }
289     }
290 }