]> BookStack Code Mirror - bookstack/blob - tests/Api/UsersApiTest.php
Users API: Fixed incorrect created_at date on index endpoint
[bookstack] / tests / Api / UsersApiTest.php
1 <?php
2
3 namespace Tests\Api;
4
5 use BookStack\Activity\ActivityType;
6 use BookStack\Activity\Models\Activity as ActivityModel;
7 use BookStack\Entities\Models\Entity;
8 use BookStack\Facades\Activity;
9 use BookStack\Notifications\UserInvite;
10 use BookStack\Users\Models\Role;
11 use BookStack\Users\Models\User;
12 use Illuminate\Support\Facades\Hash;
13 use Illuminate\Support\Facades\Notification;
14 use Tests\TestCase;
15
16 class UsersApiTest extends TestCase
17 {
18     use TestsApi;
19
20     protected string $baseEndpoint = '/api/users';
21
22     protected array $endpointMap = [
23         ['get', '/api/users'],
24         ['post', '/api/users'],
25         ['get', '/api/users/1'],
26         ['put', '/api/users/1'],
27         ['delete', '/api/users/1'],
28     ];
29
30     public function test_users_manage_permission_needed_for_all_endpoints()
31     {
32         $this->actingAsApiEditor();
33         foreach ($this->endpointMap as [$method, $uri]) {
34             $resp = $this->json($method, $uri);
35             $resp->assertStatus(403);
36             $resp->assertJson($this->permissionErrorResponse());
37         }
38     }
39
40     public function test_no_endpoints_accessible_in_demo_mode()
41     {
42         config()->set('app.env', 'demo');
43         $this->actingAsApiAdmin();
44
45         foreach ($this->endpointMap as [$method, $uri]) {
46             $resp = $this->json($method, $uri);
47             $resp->assertStatus(403);
48             $resp->assertJson($this->permissionErrorResponse());
49         }
50     }
51
52     public function test_index_endpoint_returns_expected_user()
53     {
54         $this->actingAsApiAdmin();
55         /** @var User $firstUser */
56         $firstUser = User::query()->orderBy('id', 'asc')->first();
57
58         $resp = $this->getJson($this->baseEndpoint . '?count=1&sort=+id');
59         $resp->assertJson(['data' => [
60             [
61                 'id'          => $firstUser->id,
62                 'name'        => $firstUser->name,
63                 'slug'        => $firstUser->slug,
64                 'email'       => $firstUser->email,
65                 'profile_url' => $firstUser->getProfileUrl(),
66                 'edit_url'    => $firstUser->getEditUrl(),
67                 'avatar_url'  => $firstUser->getAvatar(),
68             ],
69         ]]);
70     }
71
72     public function test_index_endpoint_has_correct_created_and_last_activity_dates()
73     {
74         $user = $this->users->editor();
75         $user->created_at = now()->subYear();
76         $user->save();
77
78         $this->actingAs($user);
79         Activity::add(ActivityType::AUTH_LOGIN, 'test login activity');
80         /** @var ActivityModel $activity */
81         $activity = ActivityModel::query()->where('user_id', '=', $user->id)->latest()->first();
82
83         $resp = $this->asAdmin()->getJson($this->baseEndpoint . '?filter[id]=3');
84         $resp->assertJson(['data' => [
85             [
86                 'id'          => $user->id,
87                 'created_at' => $user->created_at->toJSON(),
88                 'last_activity_at' => $activity->created_at->toJson(),
89             ],
90         ]]);
91     }
92
93     public function test_create_endpoint()
94     {
95         $this->actingAsApiAdmin();
96         /** @var Role $role */
97         $role = Role::query()->first();
98
99         $resp = $this->postJson($this->baseEndpoint, [
100             'name'        => 'Benny Boris',
101             'email'       => '[email protected]',
102             'password'    => 'mysuperpass',
103             'language'    => 'it',
104             'roles'       => [$role->id],
105             'send_invite' => false,
106         ]);
107
108         $resp->assertStatus(200);
109         $resp->assertJson([
110             'name'             => 'Benny Boris',
111             'email'            => '[email protected]',
112             'external_auth_id' => '',
113             'roles'            => [
114                 [
115                     'id'           => $role->id,
116                     'display_name' => $role->display_name,
117                 ],
118             ],
119         ]);
120         $this->assertDatabaseHas('users', ['email' => '[email protected]']);
121
122         /** @var User $user */
123         $user = User::query()->where('email', '=', '[email protected]')->first();
124         $this->assertActivityExists(ActivityType::USER_CREATE, null, $user->logDescriptor());
125         $this->assertEquals(1, $user->roles()->count());
126         $this->assertEquals('it', setting()->getUser($user, 'language'));
127     }
128
129     public function test_create_with_send_invite()
130     {
131         $this->actingAsApiAdmin();
132         Notification::fake();
133
134         $resp = $this->postJson($this->baseEndpoint, [
135             'name'        => 'Benny Boris',
136             'email'       => '[email protected]',
137             'send_invite' => true,
138         ]);
139
140         $resp->assertStatus(200);
141         /** @var User $user */
142         $user = User::query()->where('email', '=', '[email protected]')->first();
143         Notification::assertSentTo($user, UserInvite::class);
144     }
145
146     public function test_create_name_and_email_validation()
147     {
148         $this->actingAsApiAdmin();
149         /** @var User $existingUser */
150         $existingUser = User::query()->first();
151
152         $resp = $this->postJson($this->baseEndpoint, [
153             'email' => '[email protected]',
154         ]);
155         $resp->assertStatus(422);
156         $resp->assertJson($this->validationResponse(['name' => ['The name field is required.']]));
157
158         $resp = $this->postJson($this->baseEndpoint, [
159             'name' => 'Benny Boris',
160         ]);
161         $resp->assertStatus(422);
162         $resp->assertJson($this->validationResponse(['email' => ['The email field is required.']]));
163
164         $resp = $this->postJson($this->baseEndpoint, [
165             'email' => $existingUser->email,
166             'name'  => 'Benny Boris',
167         ]);
168         $resp->assertStatus(422);
169         $resp->assertJson($this->validationResponse(['email' => ['The email has already been taken.']]));
170     }
171
172     public function test_read_endpoint()
173     {
174         $this->actingAsApiAdmin();
175         /** @var User $user */
176         $user = User::query()->first();
177         /** @var Role $userRole */
178         $userRole = $user->roles()->first();
179
180         $resp = $this->getJson($this->baseEndpoint . "/{$user->id}");
181
182         $resp->assertStatus(200);
183         $resp->assertJson([
184             'id'               => $user->id,
185             'slug'             => $user->slug,
186             'email'            => $user->email,
187             'external_auth_id' => $user->external_auth_id,
188             'roles'            => [
189                 [
190                     'id'           => $userRole->id,
191                     'display_name' => $userRole->display_name,
192                 ],
193             ],
194         ]);
195     }
196
197     public function test_update_endpoint()
198     {
199         $this->actingAsApiAdmin();
200         /** @var User $user */
201         $user = $this->users->admin();
202         $roles = Role::query()->pluck('id');
203         $resp = $this->putJson($this->baseEndpoint . "/{$user->id}", [
204             'name'             => 'My updated user',
205             'email'            => '[email protected]',
206             'roles'            => $roles,
207             'external_auth_id' => 'btest',
208             'password'         => 'barrytester',
209             'language'         => 'fr',
210         ]);
211
212         $resp->assertStatus(200);
213         $resp->assertJson([
214             'id'               => $user->id,
215             'name'             => 'My updated user',
216             'email'            => '[email protected]',
217             'external_auth_id' => 'btest',
218         ]);
219         $user->refresh();
220         $this->assertEquals('fr', setting()->getUser($user, 'language'));
221         $this->assertEquals(count($roles), $user->roles()->count());
222         $this->assertNotEquals('barrytester', $user->password);
223         $this->assertTrue(Hash::check('barrytester', $user->password));
224     }
225
226     public function test_update_endpoint_does_not_remove_info_if_not_provided()
227     {
228         $this->actingAsApiAdmin();
229         /** @var User $user */
230         $user = $this->users->admin();
231         $roleCount = $user->roles()->count();
232         $resp = $this->putJson($this->baseEndpoint . "/{$user->id}", []);
233
234         $resp->assertStatus(200);
235         $this->assertDatabaseHas('users', [
236             'id'       => $user->id,
237             'name'     => $user->name,
238             'email'    => $user->email,
239             'password' => $user->password,
240         ]);
241         $this->assertEquals($roleCount, $user->roles()->count());
242     }
243
244     public function test_delete_endpoint()
245     {
246         $this->actingAsApiAdmin();
247         /** @var User $user */
248         $user = User::query()->where('id', '!=', $this->users->admin()->id)
249             ->whereNull('system_name')
250             ->first();
251
252         $resp = $this->deleteJson($this->baseEndpoint . "/{$user->id}");
253
254         $resp->assertStatus(204);
255         $this->assertActivityExists('user_delete', null, $user->logDescriptor());
256     }
257
258     public function test_delete_endpoint_with_ownership_migration_user()
259     {
260         $this->actingAsApiAdmin();
261         /** @var User $user */
262         $user = User::query()->where('id', '!=', $this->users->admin()->id)
263             ->whereNull('system_name')
264             ->first();
265         $entityChain = $this->entities->createChainBelongingToUser($user);
266         /** @var User $newOwner */
267         $newOwner = User::query()->where('id', '!=', $user->id)->first();
268
269         /** @var Entity $entity */
270         foreach ($entityChain as $entity) {
271             $this->assertEquals($user->id, $entity->owned_by);
272         }
273
274         $resp = $this->deleteJson($this->baseEndpoint . "/{$user->id}", [
275             'migrate_ownership_id' => $newOwner->id,
276         ]);
277
278         $resp->assertStatus(204);
279         /** @var Entity $entity */
280         foreach ($entityChain as $entity) {
281             $this->assertEquals($newOwner->id, $entity->refresh()->owned_by);
282         }
283     }
284
285     public function test_delete_endpoint_fails_deleting_only_admin()
286     {
287         $this->actingAsApiAdmin();
288         $adminRole = Role::getSystemRole('admin');
289         $adminToDelete = $adminRole->users()->first();
290         $adminRole->users()->where('id', '!=', $adminToDelete->id)->delete();
291
292         $resp = $this->deleteJson($this->baseEndpoint . "/{$adminToDelete->id}");
293
294         $resp->assertStatus(500);
295         $resp->assertJson($this->errorResponse('You cannot delete the only admin', 500));
296     }
297
298     public function test_delete_endpoint_fails_deleting_public_user()
299     {
300         $this->actingAsApiAdmin();
301         /** @var User $publicUser */
302         $publicUser = User::query()->where('system_name', '=', 'public')->first();
303
304         $resp = $this->deleteJson($this->baseEndpoint . "/{$publicUser->id}");
305
306         $resp->assertStatus(500);
307         $resp->assertJson($this->errorResponse('You cannot delete the guest user', 500));
308     }
309 }