namespace Tests\User;
+use BookStack\Access\Mfa\MfaValue;
use BookStack\Activity\Tools\UserEntityWatchOptions;
use BookStack\Activity\WatchLevels;
+use BookStack\Api\ApiToken;
+use BookStack\Uploads\Image;
+use Illuminate\Support\Facades\Hash;
+use Illuminate\Support\Str;
use Tests\TestCase;
class UserMyAccountTest extends TestCase
$resp->assertRedirect('/');
}
}
+
+ public function test_profile_updating()
+ {
+ $editor = $this->users->editor();
+
+ $resp = $this->actingAs($editor)->get('/my-account/profile');
+ $resp->assertSee('Profile Details');
+
+ $html = $this->withHtml($resp);
+ $html->assertFieldHasValue('name', $editor->name);
+ $html->assertFieldHasValue('email', $editor->email);
+
+ $resp = $this->put('/my-account/profile', [
+ 'name' => 'Barryius',
+ 'language' => 'fr',
+ ]);
+
+ $resp->assertRedirect('/my-account/profile');
+ $this->assertDatabaseHas('users', [
+ 'name' => 'Barryius',
+ 'email' => $editor->email, // No email change due to not having permissions
+ ]);
+ $this->assertEquals(setting()->getUser($editor, 'language'), 'fr');
+ }
+
+ public function test_profile_user_avatar_update_and_reset()
+ {
+ $user = $this->users->viewer();
+ $avatarFile = $this->files->uploadedImage('avatar-icon.png');
+
+ $this->assertEquals(0, $user->image_id);
+
+ $upload = $this->actingAs($user)->call('PUT', "/my-account/profile", [
+ 'name' => 'Barry Scott',
+ ], [], ['profile_image' => $avatarFile], []);
+ $upload->assertRedirect('/my-account/profile');
+
+
+ $user->refresh();
+ $this->assertNotEquals(0, $user->image_id);
+ /** @var Image $image */
+ $image = Image::query()->findOrFail($user->image_id);
+ $this->assertFileExists(public_path($image->path));
+
+ $reset = $this->put("/my-account/profile", [
+ 'name' => 'Barry Scott',
+ 'profile_image_reset' => 'true',
+ ]);
+ $upload->assertRedirect('/my-account/profile');
+
+ $user->refresh();
+ $this->assertFileDoesNotExist(public_path($image->path));
+ $this->assertEquals(0, $user->image_id);
+ }
+
+ public function test_profile_admin_options_link_shows_if_permissions_allow()
+ {
+ $editor = $this->users->editor();
+
+ $resp = $this->actingAs($editor)->get('/my-account/profile');
+ $resp->assertDontSee('Administrator Options');
+ $this->withHtml($resp)->assertLinkNotExists(url("/settings/users/{$editor->id}"));
+
+ $this->permissions->grantUserRolePermissions($editor, ['users-manage']);
+
+ $resp = $this->actingAs($editor)->get('/my-account/profile');
+ $resp->assertSee('Administrator Options');
+ $this->withHtml($resp)->assertLinkExists(url("/settings/users/{$editor->id}"));
+ }
+
+ public function test_profile_self_delete()
+ {
+ $editor = $this->users->editor();
+
+ $resp = $this->actingAs($editor)->get('/my-account/profile');
+ $this->withHtml($resp)->assertLinkExists(url('/my-account/delete'), 'Delete Account');
+
+ $resp = $this->get('/my-account/delete');
+ $resp->assertSee('Delete My Account');
+ $this->withHtml($resp)->assertElementContains('form[action$="/my-account"] button', 'Confirm');
+
+ $resp = $this->delete('/my-account');
+ $resp->assertRedirect('/');
+
+ $this->assertDatabaseMissing('users', ['id' => $editor->id]);
+ }
+
+ public function test_profile_self_delete_shows_ownership_migration_if_can_manage_users()
+ {
+ $editor = $this->users->editor();
+
+ $resp = $this->actingAs($editor)->get('/my-account/delete');
+ $resp->assertDontSee('Migrate Ownership');
+
+ $this->permissions->grantUserRolePermissions($editor, ['users-manage']);
+
+ $resp = $this->actingAs($editor)->get('/my-account/delete');
+ $resp->assertSee('Migrate Ownership');
+ }
+
+ public function test_auth_password_change()
+ {
+ $editor = $this->users->editor();
+
+ $resp = $this->actingAs($editor)->get('/my-account/auth');
+ $resp->assertSee('Change Password');
+ $this->withHtml($resp)->assertElementExists('form[action$="/my-account/auth/password"]');
+
+ $password = Str::random();
+ $resp = $this->put('/my-account/auth/password', [
+ 'password' => $password,
+ 'password-confirm' => $password,
+ ]);
+ $resp->assertRedirect('/my-account/auth');
+
+ $editor->refresh();
+ $this->assertTrue(Hash::check($password, $editor->password));
+ }
+
+ public function test_auth_password_change_hides_if_not_using_email_auth()
+ {
+ $editor = $this->users->editor();
+
+ $resp = $this->actingAs($editor)->get('/my-account/auth');
+ $resp->assertSee('Change Password');
+
+ config()->set('auth.method', 'oidc');
+
+ $resp = $this->actingAs($editor)->get('/my-account/auth');
+ $resp->assertDontSee('Change Password');
+ }
+
+ public function test_auth_page_has_mfa_links()
+ {
+ $editor = $this->users->editor();
+ $resp = $this->actingAs($editor)->get('/my-account/auth');
+ $resp->assertSee('0 methods configured');
+ $this->withHtml($resp)->assertLinkExists(url('/mfa/setup'));
+
+ MfaValue::upsertWithValue($editor, 'totp', 'testval');
+
+ $resp = $this->get('/my-account/auth');
+ $resp->assertSee('1 method configured');
+ }
+
+ public function test_auth_page_api_tokens()
+ {
+ $editor = $this->users->editor();
+ $resp = $this->actingAs($editor)->get('/my-account/auth');
+ $resp->assertSee('API Tokens');
+ $this->withHtml($resp)->assertLinkExists(url("/api-tokens/{$editor->id}/create?context=my-account"));
+
+ ApiToken::factory()->create(['user_id' => $editor->id, 'name' => 'My great token']);
+ $editor->unsetRelations();
+
+ $resp = $this->get('/my-account/auth');
+ $resp->assertSee('My great token');
+ }
+
public function test_interface_shortcuts_updating()
{
$this->asEditor();