From: Dan Brown Date: Thu, 3 Feb 2022 11:38:55 +0000 (+0000) Subject: Merge branch 'api-endpoint-users' into users_api X-Git-Tag: v22.02~1^2~18^2~6 X-Git-Url: http://source.bookstackapp.com/bookstack/commitdiff_plain/8d7febe482f92a34093127c60c6e2dda342b4223?ds=inline;hp=-c Merge branch 'api-endpoint-users' into users_api --- 8d7febe482f92a34093127c60c6e2dda342b4223 diff --combined app/Api/ListingResponseBuilder.php index 02b3f680c,06802808e..3dbe954b8 --- a/app/Api/ListingResponseBuilder.php +++ b/app/Api/ListingResponseBuilder.php @@@ -1,6 -1,4 +1,6 @@@ - '=', @@@ -19,17 -19,18 +20,18 @@@ 'lt' => '<', 'gte' => '>=', 'lte' => '<=', - 'like' => 'like' + 'like' => 'like', ]; /** * ListingResponseBuilder constructor. */ - public function __construct(Builder $query, Request $request, array $fields) + public function __construct(Builder $query, Request $request, array $fields, array $hiddenFields ) { $this->query = $query; $this->request = $request; $this->fields = $fields; + $this->hiddenFields = $hiddenFields; } /** @@@ -41,9 -42,10 +43,10 @@@ $total = $filteredQuery->count(); $data = $this->fetchData($filteredQuery); + $data = $data->makeVisible($this->hiddenFields); return response()->json([ - 'data' => $data, + 'data' => $data, 'total' => $total, ]); } @@@ -55,7 -57,6 +58,7 @@@ { $query = $this->countAndOffsetQuery($query); $query = $this->sortQuery($query); + return $query->get($this->fields); } @@@ -97,7 -98,6 +100,7 @@@ } $queryOperator = $this->filterOperators[$filterOperator]; + return [$field, $queryOperator, $value]; } diff --combined app/Auth/UserRepo.php index ff2e91ee2,4444c734c..0dea41725 --- a/app/Auth/UserRepo.php +++ b/app/Auth/UserRepo.php @@@ -1,7 -1,6 +1,7 @@@ -with('roles', 'avatar')->orderBy('name', 'asc')->get(); } + /** + * Get all users as Builder for API + */ + public function getUsersBuilder(int $id = null ) : Builder + { + $query = User::query()->select(['*']) + ->withLastActivityAt() + ->with(['roles', 'avatar']); + return $query; + } /** * Get all the users with their permissions in a paginated format. + * Note: Due to the use of email search this should only be used when + * user is assumed to be trusted. (Admin users). + * Email search can be abused to extract email addresses. */ public function getAllUsersPaginatedAndSorted(int $count, array $sortData): LengthAwarePaginator { $sort = $sortData['sort']; $query = User::query()->select(['*']) - ->withLastActivityAt() + ->scopes(['withLastActivityAt']) ->with(['roles', 'avatar']) + ->withCount('mfaValues') ->orderBy($sort, $sortData['order']); if ($sortData['search']) { @@@ -87,7 -94,7 +97,7 @@@ return $query->paginate($count); } - /** + /** * Creates a new user and attaches a role to them. */ public function registerNew(array $data, bool $emailConfirmed = false): User @@@ -101,7 -108,6 +111,7 @@@ /** * Assign a user to a system-level role. + * * @throws NotFoundException */ public function attachSystemRole(User $user, string $systemRoleName) @@@ -132,7 -138,6 +142,7 @@@ /** * Set the assigned user roles via an array of role IDs. + * * @throws UserUpdateException */ public function setUserRoles(User $user, array $roles) @@@ -148,7 -153,7 +158,7 @@@ * Check if the given user is the last admin and their new roles no longer * contains the admin role. */ - protected function demotingLastAdmin(User $user, array $newRoles) : bool + protected function demotingLastAdmin(User $user, array $newRoles): bool { if ($this->isOnlyAdmin($user)) { $adminRole = Role::getSystemRole('admin'); @@@ -166,10 -171,10 +176,10 @@@ public function create(array $data, bool $emailConfirmed = false): User { $details = [ - 'name' => $data['name'], - 'email' => $data['email'], - 'password' => bcrypt($data['password']), - 'email_confirmed' => $emailConfirmed, + 'name' => $data['name'], + 'email' => $data['email'], + 'password' => bcrypt($data['password']), + 'email_confirmed' => $emailConfirmed, 'external_auth_id' => $data['external_auth_id'] ?? '', ]; @@@ -183,19 -188,22 +193,19 @@@ /** * Remove the given user from storage, Delete all related content. + * * @throws Exception */ 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 = Image::query()->where('type', '=', 'user') - ->where('uploaded_to', '=', $user->id) - ->get(); - foreach ($profileImages as $image) { - Images::destroy($image); - } + // Delete user profile images + $this->userAvatar->destroyAllForUser($user); if (!empty($newOwnerId)) { $newOwner = User::query()->find($newOwnerId); @@@ -210,13 -218,21 +220,13 @@@ */ protected function migrateOwnership(User $fromUser, User $toUser) { - $entities = (new EntityProvider)->all(); + $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. - */ - 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. */ @@@ -243,12 -259,11 +253,12 @@@ public function getAssetCounts(User $user): array { $createdBy = ['created_by' => $user->id]; + return [ - 'pages' => Page::visible()->where($createdBy)->count(), - 'chapters' => Chapter::visible()->where($createdBy)->count(), - 'books' => Book::visible()->where($createdBy)->count(), - 'shelves' => Bookshelf::visible()->where($createdBy)->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(), ]; } diff --combined app/Http/Controllers/Api/ApiController.php index 3f049a08c,5eb8b1e3d..5d6f4a926 --- a/app/Http/Controllers/Api/ApiController.php +++ b/app/Http/Controllers/Api/ApiController.php @@@ -1,6 -1,4 +1,6 @@@ -toResponse(); } /** * Get the validation rules for this controller. + * Defaults to a $rules property but can be a rules() method. */ public function getValdationRules(): array { + if (method_exists($this, 'rules')) { + return $this->rules(); + } + return $this->rules; } } diff --combined routes/api.php index 7876ba6d4,063fbd72a..cd8dd355a --- a/routes/api.php +++ b/routes/api.php @@@ -1,67 -1,49 +1,70 @@@