]> BookStack Code Mirror - bookstack/blobdiff - tests/Api/UsersApiTest.php
respective book and chapter structure added.
[bookstack] / tests / Api / UsersApiTest.php
index 4a3c4724af731a9505f683218199cd0f5686e2eb..a0c67d0d281f73612d2f2f9ada724fed833c1859 100644 (file)
@@ -2,30 +2,54 @@
 
 namespace Tests\Api;
 
-use BookStack\Auth\Role;
-use BookStack\Auth\User;
+use BookStack\Access\Notifications\UserInviteNotification;
+use BookStack\Activity\ActivityType;
+use BookStack\Activity\Models\Activity as ActivityModel;
+use BookStack\Entities\Models\Entity;
+use BookStack\Facades\Activity;
+use BookStack\Users\Models\Role;
+use BookStack\Users\Models\User;
+use Illuminate\Support\Facades\Hash;
+use Illuminate\Support\Facades\Notification;
 use Tests\TestCase;
 
 class UsersApiTest extends TestCase
 {
     use TestsApi;
 
-    protected $baseEndpoint = '/api/users';
+    protected string $baseEndpoint = '/api/users';
+
+    protected array $endpointMap = [
+        ['get', '/api/users'],
+        ['post', '/api/users'],
+        ['get', '/api/users/1'],
+        ['put', '/api/users/1'],
+        ['delete', '/api/users/1'],
+    ];
 
     public function test_users_manage_permission_needed_for_all_endpoints()
     {
-        // TODO
+        $this->actingAsApiEditor();
+        foreach ($this->endpointMap as [$method, $uri]) {
+            $resp = $this->json($method, $uri);
+            $resp->assertStatus(403);
+            $resp->assertJson($this->permissionErrorResponse());
+        }
     }
 
     public function test_no_endpoints_accessible_in_demo_mode()
     {
-        // TODO
-        // $this->preventAccessInDemoMode();
-        // Can't use directly in constructor as blocks access to docs
-        // Maybe via route middleware
+        config()->set('app.env', 'demo');
+        $this->actingAsApiAdmin();
+
+        foreach ($this->endpointMap as [$method, $uri]) {
+            $resp = $this->json($method, $uri);
+            $resp->assertStatus(403);
+            $resp->assertJson($this->permissionErrorResponse());
+        }
     }
 
-    public function test_index_endpoint_returns_expected_shelf()
+    public function test_index_endpoint_returns_expected_user()
     {
         $this->actingAsApiAdmin();
         /** @var User $firstUser */
@@ -34,17 +58,134 @@ class UsersApiTest extends TestCase
         $resp = $this->getJson($this->baseEndpoint . '?count=1&sort=+id');
         $resp->assertJson(['data' => [
             [
-                'id'   => $firstUser->id,
-                'name' => $firstUser->name,
-                'slug' => $firstUser->slug,
-                'email' => $firstUser->email,
+                'id'          => $firstUser->id,
+                'name'        => $firstUser->name,
+                'slug'        => $firstUser->slug,
+                'email'       => $firstUser->email,
                 'profile_url' => $firstUser->getProfileUrl(),
-                'edit_url' => $firstUser->getEditUrl(),
-                'avatar_url' => $firstUser->getAvatar(),
+                'edit_url'    => $firstUser->getEditUrl(),
+                'avatar_url'  => $firstUser->getAvatar(),
             ],
         ]]);
     }
 
+    public function test_index_endpoint_has_correct_created_and_last_activity_dates()
+    {
+        $user = $this->users->editor();
+        $user->created_at = now()->subYear();
+        $user->save();
+
+        $this->actingAs($user);
+        Activity::add(ActivityType::AUTH_LOGIN, 'test login activity');
+        /** @var ActivityModel $activity */
+        $activity = ActivityModel::query()->where('user_id', '=', $user->id)->latest()->first();
+
+        $resp = $this->asAdmin()->getJson($this->baseEndpoint . '?filter[id]=3');
+        $resp->assertJson(['data' => [
+            [
+                'id'          => $user->id,
+                'created_at' => $user->created_at->toJSON(),
+                'last_activity_at' => $activity->created_at->toJson(),
+            ],
+        ]]);
+    }
+
+    public function test_create_endpoint()
+    {
+        $this->actingAsApiAdmin();
+        /** @var Role $role */
+        $role = Role::query()->first();
+
+        $resp = $this->postJson($this->baseEndpoint, [
+            'name'        => 'Benny Boris',
+            'email'       => '[email protected]',
+            'password'    => 'mysuperpass',
+            'language'    => 'it',
+            'roles'       => [$role->id],
+            'send_invite' => false,
+        ]);
+
+        $resp->assertStatus(200);
+        $resp->assertJson([
+            'name'             => 'Benny Boris',
+            'email'            => '[email protected]',
+            'external_auth_id' => '',
+            'roles'            => [
+                [
+                    'id'           => $role->id,
+                    'display_name' => $role->display_name,
+                ],
+            ],
+        ]);
+        $this->assertDatabaseHas('users', ['email' => '[email protected]']);
+
+        /** @var User $user */
+        $user = User::query()->where('email', '=', '[email protected]')->first();
+        $this->assertActivityExists(ActivityType::USER_CREATE, null, $user->logDescriptor());
+        $this->assertEquals(1, $user->roles()->count());
+        $this->assertEquals('it', setting()->getUser($user, 'language'));
+    }
+
+    public function test_create_with_send_invite()
+    {
+        $this->actingAsApiAdmin();
+        Notification::fake();
+
+        $resp = $this->postJson($this->baseEndpoint, [
+            'name'        => 'Benny Boris',
+            'email'       => '[email protected]',
+            'send_invite' => true,
+        ]);
+
+        $resp->assertStatus(200);
+        /** @var User $user */
+        $user = User::query()->where('email', '=', '[email protected]')->first();
+        Notification::assertSentTo($user, UserInviteNotification::class);
+    }
+
+    public function test_create_with_send_invite_works_with_value_of_1()
+    {
+        $this->actingAsApiAdmin();
+        Notification::fake();
+
+        $resp = $this->postJson($this->baseEndpoint, [
+            'name'        => 'Benny Boris',
+            'email'       => '[email protected]',
+            'send_invite' => '1', // Submissions via x-www-form-urlencoded/form-data may use 1 instead of boolean
+        ]);
+
+        $resp->assertStatus(200);
+        /** @var User $user */
+        $user = User::query()->where('email', '=', '[email protected]')->first();
+        Notification::assertSentTo($user, UserInviteNotification::class);
+    }
+
+    public function test_create_name_and_email_validation()
+    {
+        $this->actingAsApiAdmin();
+        /** @var User $existingUser */
+        $existingUser = User::query()->first();
+
+        $resp = $this->postJson($this->baseEndpoint, [
+            'email' => '[email protected]',
+        ]);
+        $resp->assertStatus(422);
+        $resp->assertJson($this->validationResponse(['name' => ['The name field is required.']]));
+
+        $resp = $this->postJson($this->baseEndpoint, [
+            'name' => 'Benny Boris',
+        ]);
+        $resp->assertStatus(422);
+        $resp->assertJson($this->validationResponse(['email' => ['The email field is required.']]));
+
+        $resp = $this->postJson($this->baseEndpoint, [
+            'email' => $existingUser->email,
+            'name'  => 'Benny Boris',
+        ]);
+        $resp->assertStatus(422);
+        $resp->assertJson($this->validationResponse(['email' => ['The email has already been taken.']]));
+    }
+
     public function test_read_endpoint()
     {
         $this->actingAsApiAdmin();
@@ -57,24 +198,71 @@ class UsersApiTest extends TestCase
 
         $resp->assertStatus(200);
         $resp->assertJson([
-            'id'         => $user->id,
-            'slug'       => $user->slug,
-            'email'      => $user->email,
+            'id'               => $user->id,
+            'slug'             => $user->slug,
+            'email'            => $user->email,
             'external_auth_id' => $user->external_auth_id,
-            'roles' => [
+            'roles'            => [
                 [
-                    'id' => $userRole->id,
+                    'id'           => $userRole->id,
                     'display_name' => $userRole->display_name,
-                ]
+                ],
             ],
         ]);
     }
 
+    public function test_update_endpoint()
+    {
+        $this->actingAsApiAdmin();
+        /** @var User $user */
+        $user = $this->users->admin();
+        $roles = Role::query()->pluck('id');
+        $resp = $this->putJson($this->baseEndpoint . "/{$user->id}", [
+            'name'             => 'My updated user',
+            'email'            => '[email protected]',
+            'roles'            => $roles,
+            'external_auth_id' => 'btest',
+            'password'         => 'barrytester',
+            'language'         => 'fr',
+        ]);
+
+        $resp->assertStatus(200);
+        $resp->assertJson([
+            'id'               => $user->id,
+            'name'             => 'My updated user',
+            'email'            => '[email protected]',
+            'external_auth_id' => 'btest',
+        ]);
+        $user->refresh();
+        $this->assertEquals('fr', setting()->getUser($user, 'language'));
+        $this->assertEquals(count($roles), $user->roles()->count());
+        $this->assertNotEquals('barrytester', $user->password);
+        $this->assertTrue(Hash::check('barrytester', $user->password));
+    }
+
+    public function test_update_endpoint_does_not_remove_info_if_not_provided()
+    {
+        $this->actingAsApiAdmin();
+        /** @var User $user */
+        $user = $this->users->admin();
+        $roleCount = $user->roles()->count();
+        $resp = $this->putJson($this->baseEndpoint . "/{$user->id}", []);
+
+        $resp->assertStatus(200);
+        $this->assertDatabaseHas('users', [
+            'id'       => $user->id,
+            'name'     => $user->name,
+            'email'    => $user->email,
+            'password' => $user->password,
+        ]);
+        $this->assertEquals($roleCount, $user->roles()->count());
+    }
+
     public function test_delete_endpoint()
     {
         $this->actingAsApiAdmin();
         /** @var User $user */
-        $user = User::query()->where('id', '!=', $this->getAdmin()->id)
+        $user = User::query()->where('id', '!=', $this->users->admin()->id)
             ->whereNull('system_name')
             ->first();
 
@@ -84,6 +272,33 @@ class UsersApiTest extends TestCase
         $this->assertActivityExists('user_delete', null, $user->logDescriptor());
     }
 
+    public function test_delete_endpoint_with_ownership_migration_user()
+    {
+        $this->actingAsApiAdmin();
+        /** @var User $user */
+        $user = User::query()->where('id', '!=', $this->users->admin()->id)
+            ->whereNull('system_name')
+            ->first();
+        $entityChain = $this->entities->createChainBelongingToUser($user);
+        /** @var User $newOwner */
+        $newOwner = User::query()->where('id', '!=', $user->id)->first();
+
+        /** @var Entity $entity */
+        foreach ($entityChain as $entity) {
+            $this->assertEquals($user->id, $entity->owned_by);
+        }
+
+        $resp = $this->deleteJson($this->baseEndpoint . "/{$user->id}", [
+            'migrate_ownership_id' => $newOwner->id,
+        ]);
+
+        $resp->assertStatus(204);
+        /** @var Entity $entity */
+        foreach ($entityChain as $entity) {
+            $this->assertEquals($newOwner->id, $entity->refresh()->owned_by);
+        }
+    }
+
     public function test_delete_endpoint_fails_deleting_only_admin()
     {
         $this->actingAsApiAdmin();