]> BookStack Code Mirror - bookstack/blob - app/Users/Controllers/UserApiController.php
Cleaned up namespacing in routes
[bookstack] / app / Users / Controllers / UserApiController.php
1 <?php
2
3 namespace BookStack\Users\Controllers;
4
5 use BookStack\Exceptions\UserUpdateException;
6 use BookStack\Http\ApiController;
7 use BookStack\Users\Models\User;
8 use BookStack\Users\UserRepo;
9 use Closure;
10 use Illuminate\Http\Request;
11 use Illuminate\Support\Facades\DB;
12 use Illuminate\Validation\Rules\Password;
13 use Illuminate\Validation\Rules\Unique;
14
15 class UserApiController extends ApiController
16 {
17     protected UserRepo $userRepo;
18
19     protected array $fieldsToExpose = [
20         'email', 'created_at', 'updated_at', 'last_activity_at', 'external_auth_id',
21     ];
22
23     public function __construct(UserRepo $userRepo)
24     {
25         $this->userRepo = $userRepo;
26
27         // Checks for all endpoints in this controller
28         $this->middleware(function ($request, $next) {
29             $this->checkPermission('users-manage');
30             $this->preventAccessInDemoMode();
31
32             return $next($request);
33         });
34     }
35
36     protected function rules(int $userId = null): array
37     {
38         return [
39             'create' => [
40                 'name'  => ['required', 'min:2', 'max:100'],
41                 'email' => [
42                     'required', 'min:2', 'email', new Unique('users', 'email'),
43                 ],
44                 'external_auth_id' => ['string'],
45                 'language'         => ['string', 'max:15', 'alpha_dash'],
46                 'password'         => [Password::default()],
47                 'roles'            => ['array'],
48                 'roles.*'          => ['integer'],
49                 'send_invite'      => ['boolean'],
50             ],
51             'update' => [
52                 'name'  => ['min:2', 'max:100'],
53                 'email' => [
54                     'min:2',
55                     'email',
56                     (new Unique('users', 'email'))->ignore($userId ?? null),
57                 ],
58                 'external_auth_id' => ['string'],
59                 'language'         => ['string', 'max:15', 'alpha_dash'],
60                 'password'         => [Password::default()],
61                 'roles'            => ['array'],
62                 'roles.*'          => ['integer'],
63             ],
64             'delete' => [
65                 'migrate_ownership_id' => ['integer', 'exists:users,id'],
66             ],
67         ];
68     }
69
70     /**
71      * Get a listing of users in the system.
72      * Requires permission to manage users.
73      */
74     public function list()
75     {
76         $users = User::query()->select(['*'])
77             ->scopes('withLastActivityAt')
78             ->with(['avatar']);
79
80         return $this->apiListingResponse($users, [
81             'id', 'name', 'slug', 'email', 'external_auth_id',
82             'created_at', 'updated_at', 'last_activity_at',
83         ], [Closure::fromCallable([$this, 'listFormatter'])]);
84     }
85
86     /**
87      * Create a new user in the system.
88      * Requires permission to manage users.
89      */
90     public function create(Request $request)
91     {
92         $data = $this->validate($request, $this->rules()['create']);
93         $sendInvite = ($data['send_invite'] ?? false) === true;
94
95         $user = null;
96         DB::transaction(function () use ($data, $sendInvite, &$user) {
97             $user = $this->userRepo->create($data, $sendInvite);
98         });
99
100         $this->singleFormatter($user);
101
102         return response()->json($user);
103     }
104
105     /**
106      * View the details of a single user.
107      * Requires permission to manage users.
108      */
109     public function read(string $id)
110     {
111         $user = $this->userRepo->getById($id);
112         $this->singleFormatter($user);
113
114         return response()->json($user);
115     }
116
117     /**
118      * Update an existing user in the system.
119      * Requires permission to manage users.
120      *
121      * @throws UserUpdateException
122      */
123     public function update(Request $request, string $id)
124     {
125         $data = $this->validate($request, $this->rules($id)['update']);
126         $user = $this->userRepo->getById($id);
127         $this->userRepo->update($user, $data, userCan('users-manage'));
128         $this->singleFormatter($user);
129
130         return response()->json($user);
131     }
132
133     /**
134      * Delete a user from the system.
135      * Can optionally accept a user id via `migrate_ownership_id` to indicate
136      * who should be the new owner of their related content.
137      * Requires permission to manage users.
138      */
139     public function delete(Request $request, string $id)
140     {
141         $user = $this->userRepo->getById($id);
142         $newOwnerId = $request->get('migrate_ownership_id', null);
143
144         $this->userRepo->destroy($user, $newOwnerId);
145
146         return response('', 204);
147     }
148
149     /**
150      * Format the given user model for single-result display.
151      */
152     protected function singleFormatter(User $user)
153     {
154         $this->listFormatter($user);
155         $user->load('roles:id,display_name');
156         $user->makeVisible(['roles']);
157     }
158
159     /**
160      * Format the given user model for a listing multi-result display.
161      */
162     protected function listFormatter(User $user)
163     {
164         $user->makeVisible($this->fieldsToExpose);
165         $user->setAttribute('profile_url', $user->getProfileUrl());
166         $user->setAttribute('edit_url', $user->getEditUrl());
167         $user->setAttribute('avatar_url', $user->getAvatar());
168     }
169 }