first commit
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Auth;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Support\Enum\UserStatus;
|
||||
use Vanguard\User;
|
||||
|
||||
class AuthControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function login()
|
||||
{
|
||||
$credentials = $this->defaultCredentials();
|
||||
|
||||
$user = User::factory()->create($credentials);
|
||||
|
||||
$credentials['device_name'] = 'test';
|
||||
|
||||
$this->postJson("/api/login", $credentials)->assertOk();
|
||||
|
||||
$this->assertNotNull($user->tokens()->first());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function last_login_timestamp_is_updated_after_login()
|
||||
{
|
||||
$credentials = $this->defaultCredentials();
|
||||
|
||||
$now = Carbon::now();
|
||||
|
||||
Carbon::setTestNow($now);
|
||||
|
||||
$user = User::factory()->create($credentials);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'last_login' => null
|
||||
]);
|
||||
|
||||
$credentials['device_name'] = 'test';
|
||||
|
||||
$this->postJson("/api/login", $credentials)->assertOk();
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'last_login' => $now
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function login_with_invalid_credentials()
|
||||
{
|
||||
$credentials = $this->defaultCredentials();
|
||||
|
||||
User::factory()->create($credentials);
|
||||
|
||||
$this->postJson("/api/login", [
|
||||
'username' => 'foo',
|
||||
'password' => 'invalid',
|
||||
'device_name' => 'test'
|
||||
])->assertJsonValidationErrors('username');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function login_when_credentials_are_not_provided()
|
||||
{
|
||||
$this->postJson("/api/login")
|
||||
->assertStatus(422)
|
||||
->assertJsonFragment([
|
||||
'username' => [
|
||||
trans('validation.required', ['attribute' => 'username'])
|
||||
],
|
||||
'password' => [
|
||||
trans('validation.required', ['attribute' => 'password'])
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function banned_user_cannot_log_in()
|
||||
{
|
||||
$credentials = $this->defaultCredentials();
|
||||
|
||||
$user = User::factory()->create(array_merge($credentials, [
|
||||
'status' => UserStatus::BANNED
|
||||
]));
|
||||
|
||||
$credentials['device_name'] = 'test';
|
||||
|
||||
$this->postJson("/api/login", $credentials)
|
||||
->assertStatus(401)
|
||||
->assertJson([
|
||||
'message' => "Your account is banned by administrators."
|
||||
]);
|
||||
|
||||
$this->assertDatabaseMissing('personal_access_tokens', ['tokenable_id' => $user->id]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function unconfirmed_user_can_log_in()
|
||||
{
|
||||
$credentials = $this->defaultCredentials();
|
||||
|
||||
User::factory()->create(array_merge($credentials, [
|
||||
'status' => UserStatus::UNCONFIRMED
|
||||
]));
|
||||
|
||||
$credentials['device_name'] = 'test';
|
||||
|
||||
$this->postJson("/api/login", $credentials)->assertOk();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function logout()
|
||||
{
|
||||
$credentials = $this->defaultCredentials();
|
||||
|
||||
Carbon::setTestNow(Carbon::now());
|
||||
|
||||
$user = User::factory()->create($credentials);
|
||||
|
||||
$credentials['device_name'] = 'test';
|
||||
|
||||
$response = $this->postJson("/api/login", $credentials);
|
||||
|
||||
$token = $user->tokens()->first();
|
||||
|
||||
auth('sanctum')->user()->withAccessToken($token);
|
||||
|
||||
$this->postJson("/api/logout", [], [
|
||||
'Authorization' => "Bearer {$response->original['token']}"
|
||||
]);
|
||||
|
||||
$this->assertDatabaseMissing('personal_access_tokens', ['id' => $token->id]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function logout_if_token_is_not_provided()
|
||||
{
|
||||
$this->postJson("/api/logout")->assertStatus(401);
|
||||
}
|
||||
|
||||
private function defaultCredentials(array $override = [])
|
||||
{
|
||||
return array_merge([
|
||||
'username' => 'foo',
|
||||
'password' => 'bar'
|
||||
], $override);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Auth\Password;
|
||||
|
||||
use Mail;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Mail\ResetPassword;
|
||||
use Vanguard\User;
|
||||
|
||||
class RemindControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function send_password_reminder()
|
||||
{
|
||||
$this->setSettings(['forgot_password' => true]);
|
||||
|
||||
Mail::fake();
|
||||
|
||||
$user = User::factory()->create(['email' => 'test@test.com']);
|
||||
|
||||
$this->postJson('api/password/remind', ['email' => 'test@test.com'])
|
||||
->assertOk();
|
||||
|
||||
Mail::assertQueued(ResetPassword::class, function ($mail) use ($user) {
|
||||
return $mail->hasTo($user->email);
|
||||
});
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function password_reminder_with_wrong_email()
|
||||
{
|
||||
$this->setSettings(['forgot_password' => true]);
|
||||
|
||||
$this->postJson('api/password/remind', ['email' => 'test@test.com'])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors('email');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Auth\Password;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use DB;
|
||||
use Hash;
|
||||
use Illuminate\Support\Str;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\User;
|
||||
|
||||
class ResetControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function password_reset()
|
||||
{
|
||||
$this->setSettings(['forgot_password' => true]);
|
||||
|
||||
$user = User::factory()->create(['email' => 'test@test.com']);
|
||||
|
||||
$token = $this->createNewToken();
|
||||
|
||||
DB::table('password_resets')->insert([
|
||||
'email' => $user->email,
|
||||
'token' => Hash::make($token),
|
||||
'created_at' => Carbon::now()
|
||||
]);
|
||||
|
||||
$this->resetPassword($token, $user->email)
|
||||
->assertOk();
|
||||
|
||||
$this->assertTrue(Hash::check('123123123', $user->fresh()->password));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function password_reset_with_expired_token()
|
||||
{
|
||||
$this->setSettings(['forgot_password' => true]);
|
||||
|
||||
$user = User::factory()->create(['email' => 'test@test.com']);
|
||||
|
||||
$token = $this->createNewToken();
|
||||
|
||||
DB::table('password_resets')->insert([
|
||||
'email' => $user->email,
|
||||
'token' => Hash::make($token),
|
||||
'created_at' => Carbon::now()->subHours(2)
|
||||
]);
|
||||
|
||||
$this->resetPassword($token, $user->email)
|
||||
->assertJson([
|
||||
'message' => "This password reset token is invalid."
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function password_reset_with_invalid_email()
|
||||
{
|
||||
$this->setSettings(['forgot_password' => true]);
|
||||
|
||||
$user = User::factory()->create(['email' => 'test@test.com']);
|
||||
|
||||
$token = $this->createNewToken();
|
||||
|
||||
DB::table('password_resets')->insert([
|
||||
'email' => $user->email,
|
||||
'token' => Hash::make($token),
|
||||
'created_at' => Carbon::now()
|
||||
]);
|
||||
|
||||
$this->resetPassword($token, 'foo@bar.com')
|
||||
->assertJson([
|
||||
'message' => "We can't find a user with that e-mail address."
|
||||
]);
|
||||
}
|
||||
|
||||
private function resetPassword($token, $email)
|
||||
{
|
||||
return $this->postJson('api/password/reset', [
|
||||
'token' => $token,
|
||||
'email' => $email,
|
||||
'password' => '123123123',
|
||||
'password_confirmation' => '123123123'
|
||||
]);
|
||||
}
|
||||
|
||||
private function createNewToken()
|
||||
{
|
||||
$key = $this->app['config']['app.key'];
|
||||
|
||||
if (Str::startsWith($key, 'base64:')) {
|
||||
$key = base64_decode(substr($key, 7));
|
||||
}
|
||||
|
||||
return hash_hmac('sha256', Str::random(40), $key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Auth;
|
||||
|
||||
use Illuminate\Auth\Notifications\VerifyEmail;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\User;
|
||||
|
||||
class RegistrationControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function register_user_when_registration_is_disabled()
|
||||
{
|
||||
$this->setSettings(['reg_enabled' => false]);
|
||||
|
||||
$this->postJson('api/register')->assertStatus(404);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function register_user()
|
||||
{
|
||||
$this->setSettings([
|
||||
'reg_enabled' => true,
|
||||
'reg_email_confirmation' => false,
|
||||
'registration.captcha.enabled' => false,
|
||||
'tos' => false
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'email' => 'john.doe@test.com',
|
||||
'username' => 'john.doe',
|
||||
'password' => '123123123',
|
||||
'password_confirmation' => '123123123'
|
||||
];
|
||||
|
||||
$expected = Arr::except($data, ['password', 'password_confirmation']);
|
||||
|
||||
$this->postJson("/api/register", $data)
|
||||
->assertStatus(201)
|
||||
->assertJson([
|
||||
'requires_email_confirmation' => false
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('users', $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function register_user_with_email_confirmation()
|
||||
{
|
||||
$this->setSettings([
|
||||
'reg_enabled' => true,
|
||||
'reg_email_confirmation' => true,
|
||||
'registration.captcha.enabled' => false,
|
||||
'tos' => false
|
||||
]);
|
||||
|
||||
Notification::fake();
|
||||
|
||||
$data = [
|
||||
'email' => 'john.doe@test.com',
|
||||
'username' => 'john.doe',
|
||||
'password' => '123123123',
|
||||
'password_confirmation' => '123123123'
|
||||
];
|
||||
|
||||
$expected = Arr::except($data, ['password', 'password_confirmation']);
|
||||
|
||||
$this->postJson("/api/register", $data)
|
||||
->assertStatus(201)
|
||||
->assertJson(['requires_email_confirmation' => true]);
|
||||
|
||||
$this->assertDatabaseHas('users', $expected);
|
||||
|
||||
$user = User::where('email', $data['email'])->first();
|
||||
|
||||
Notification::assertSentTo($user, VerifyEmail::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function register_with_tos()
|
||||
{
|
||||
$this->setSettings([
|
||||
'reg_enabled' => true,
|
||||
'reg_email_confirmation' => false,
|
||||
'registration.captcha.enabled' => false,
|
||||
'tos' => true
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'email' => 'john.doe@test.com',
|
||||
'username' => 'john.doe',
|
||||
'password' => '123123123',
|
||||
'password_confirmation' => '123123123'
|
||||
];
|
||||
|
||||
$this->postJson("/api/register", $data)
|
||||
->assertStatus(422)
|
||||
->assertJsonFragment([
|
||||
'tos' => ["You have to accept Terms of Service."]
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Auth;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Laravel\Socialite\Contracts\User as SocialUserContract;
|
||||
use Laravel\Socialite\Two\FacebookProvider;
|
||||
use Mockery as m;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Repositories\User\UserRepository;
|
||||
use Vanguard\Support\Enum\UserStatus;
|
||||
use Vanguard\User;
|
||||
|
||||
class SocialLoginControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function social_authentication_for_first_time()
|
||||
{
|
||||
$this->setSettings(['reg_enabled' => true]);
|
||||
|
||||
$socialUser = new StubSocialUser;
|
||||
|
||||
$this->mockFacebookProvider($socialUser);
|
||||
|
||||
$now = Carbon::now()->addHours(2);
|
||||
Carbon::setTestNow($now);
|
||||
|
||||
$this->postJson("/api/login/social", $this->defaultParams())
|
||||
->assertOk();
|
||||
|
||||
$user = User::whereEmail($socialUser->getEmail())->first();
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe',
|
||||
'email' => $socialUser->getEmail(),
|
||||
'status' => UserStatus::ACTIVE,
|
||||
'avatar' => $socialUser->getAvatar(),
|
||||
'last_login' => $now
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('social_logins', [
|
||||
'user_id' => $user->id,
|
||||
'provider' => 'facebook',
|
||||
'provider_id' => $socialUser->getId(),
|
||||
'avatar' => $socialUser->getAvatar()
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function associate_social_account_with_existing_user()
|
||||
{
|
||||
$this->setSettings(['reg_enabled' => true]);
|
||||
|
||||
$socialUser = new StubSocialUser;
|
||||
|
||||
$this->mockFacebookProvider($socialUser);
|
||||
|
||||
$user = User::factory()->create([
|
||||
'email' => $socialUser->getEmail()
|
||||
]);
|
||||
|
||||
$this->postJson("/api/login/social", $this->defaultParams())
|
||||
->assertOk();
|
||||
|
||||
$this->assertDatabaseHas('social_logins', [
|
||||
'user_id' => $user->id,
|
||||
'provider' => 'facebook',
|
||||
'provider_id' => $socialUser->getId(),
|
||||
'avatar' => $socialUser->getAvatar()
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function social_login_if_registration_is_disabled()
|
||||
{
|
||||
$this->setSettings(['reg_enabled' => false]);
|
||||
|
||||
$socialUser = new StubSocialUser;
|
||||
|
||||
$this->mockFacebookProvider($socialUser);
|
||||
|
||||
$this->postJson("/api/login/social", $this->defaultParams())
|
||||
->assertForbidden()
|
||||
->assertJson([
|
||||
'message' => "Only users who already created an account can log in."
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function social_login_with_invalid_provider()
|
||||
{
|
||||
$this->postJson("/api/login/social", $this->defaultParams(['network' => 'foo']))
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors('network');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function social_login_for_banned_user()
|
||||
{
|
||||
$socialUser = new StubSocialUser;
|
||||
|
||||
$this->mockFacebookProvider($socialUser);
|
||||
|
||||
$user = User::factory()->create([
|
||||
'email' => $socialUser->getEmail(),
|
||||
'status' => UserStatus::BANNED
|
||||
]);
|
||||
|
||||
app(UserRepository::class)->associateSocialAccountForUser($user->id, 'facebook', $socialUser);
|
||||
|
||||
$this->postJson("/api/login/social", $this->defaultParams())
|
||||
->assertForbidden()
|
||||
->assertJson([
|
||||
'message' => 'Your account is banned by administrators.'
|
||||
]);
|
||||
}
|
||||
|
||||
private function defaultParams(array $overrides = [])
|
||||
{
|
||||
return array_merge([
|
||||
'network' => 'facebook',
|
||||
'social_token' => 'foo',
|
||||
'device_name' => 'test',
|
||||
], $overrides);
|
||||
}
|
||||
|
||||
private function mockFacebookProvider($socialUser)
|
||||
{
|
||||
$provider = m::mock(FacebookProvider::class);
|
||||
$provider->shouldReceive('userFromToken')->with('foo')->andReturn($socialUser);
|
||||
|
||||
\Socialite::shouldReceive('driver')->with('facebook')->andReturn($provider);
|
||||
}
|
||||
}
|
||||
|
||||
class StubSocialUser implements SocialUserContract
|
||||
{
|
||||
public $avatar_original = 'http://www.gravatar.com/avatar';
|
||||
|
||||
public function getId()
|
||||
{
|
||||
return '123';
|
||||
}
|
||||
|
||||
public function getNickname()
|
||||
{
|
||||
return 'johndoe';
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'John Doe';
|
||||
}
|
||||
|
||||
public function getEmail()
|
||||
{
|
||||
return 'john@doe.com';
|
||||
}
|
||||
|
||||
public function getAvatar()
|
||||
{
|
||||
return 'http://www.gravatar.com/avatar';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Authorization;
|
||||
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Http\Resources\PermissionResource;
|
||||
use Vanguard\Permission;
|
||||
use Vanguard\User;
|
||||
|
||||
class PermissionsControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function unauthenticated()
|
||||
{
|
||||
$this->getJson('/api/permissions')->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_users_without_permission()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->getJson('/api/permissions')
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_permissions()
|
||||
{
|
||||
Permission::factory()->times(3)->create();
|
||||
|
||||
$response = $this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->getJson("/api/permissions")
|
||||
->assertOk();
|
||||
|
||||
// 7 default permissions + 3 newly created
|
||||
$this->assertCount(10, $response->original);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_permission()
|
||||
{
|
||||
$permission = Permission::factory()->create();
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->getJson("/api/permissions/{$permission->id}")
|
||||
->assertOk()
|
||||
->assertJson([
|
||||
'data' => (new PermissionResource($permission))->toArray(request())
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function create_permission()
|
||||
{
|
||||
$data = [
|
||||
'name' => 'foo',
|
||||
'display_name' => 'Foo Permission',
|
||||
'description' => 'This is foo permission.'
|
||||
];
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->postJson("/api/permissions", $data)
|
||||
->assertStatus(201)
|
||||
->assertJsonFragment($data);
|
||||
|
||||
$this->assertDatabaseHas('permissions', $data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function create_permission_with_invalid_name()
|
||||
{
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->postJson("/api/permissions")
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors('name');
|
||||
|
||||
$existingPermission = Permission::first();
|
||||
|
||||
$this->postJson("/api/permissions", ['name' => $existingPermission->name])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors('name');
|
||||
|
||||
$this->postJson("/api/permissions", ['name' => 'foo bar'])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors('name');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function partially_update_permission()
|
||||
{
|
||||
$this->getUser();
|
||||
|
||||
$permission = Permission::factory()->create();
|
||||
|
||||
$data = ['name' => 'foo'];
|
||||
$expected = $data + ['id' => $permission->id];
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->patchJson("/api/permissions/{$permission->id}", $data)
|
||||
->assertJsonFragment($expected);
|
||||
|
||||
$this->assertDatabaseHas('permissions', $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_permission()
|
||||
{
|
||||
$permission = Permission::factory()->create();
|
||||
|
||||
$data = [
|
||||
'name' => 'foo',
|
||||
'display_name' => 'Foo Role',
|
||||
'description' => 'This is foo role.'
|
||||
];
|
||||
$expected = $data + ['id' => $permission->id];
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->patchJson("/api/permissions/{$permission->id}", $data)
|
||||
->assertJsonFragment($expected);
|
||||
|
||||
$this->assertDatabaseHas('permissions', $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function remove_permission()
|
||||
{
|
||||
$permission = Permission::factory()->create(['removable' => true]);
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->deleteJson("/api/permissions/{$permission->id}")
|
||||
->assertOk()
|
||||
->assertJson(['success' => true]);
|
||||
|
||||
$this->assertDatabaseMissing('permissions', ['id' => $permission->id]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function remove_non_removable_permission()
|
||||
{
|
||||
$permission = Permission::factory()->create(['removable' => false]);
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->deleteJson("/api/permissions/{$permission->id}")
|
||||
->assertStatus(403);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
private function getUser()
|
||||
{
|
||||
return UserFactory::user()->withPermissions('permissions.manage')->create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Authorization;
|
||||
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Http\Resources\PermissionResource;
|
||||
use Vanguard\Permission;
|
||||
use Vanguard\Role;
|
||||
use Vanguard\User;
|
||||
|
||||
class RolePermissionsControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function unauthenticated()
|
||||
{
|
||||
$role = Role::factory()->create();
|
||||
|
||||
$this->getJson("/api/roles/{$role->id}/permissions")
|
||||
->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_settings_without_permission()
|
||||
{
|
||||
$role = Role::factory()->create();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->getJson("/api/roles/{$role->id}/permissions")
|
||||
->assertStatus(403);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_role_permissions()
|
||||
{
|
||||
$role = Role::factory()->create();
|
||||
$permission = Permission::factory()->create();
|
||||
|
||||
$role->attachPermission($permission);
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->getJson("/api/roles/{$role->id}/permissions")
|
||||
->assertOk()
|
||||
->assertJsonFragment(
|
||||
PermissionResource::collection([$permission])->toArray(request())
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_role_permissions()
|
||||
{
|
||||
$role = Role::factory()->create();
|
||||
$permissions1 = Permission::factory()->times(2)->create();
|
||||
$permissions2 = Permission::factory()->times(3)->create();
|
||||
|
||||
$role->attachPermissions($permissions1);
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->putJson("/api/roles/{$role->id}/permissions", [
|
||||
'permissions' => $permissions2->pluck('id')
|
||||
])
|
||||
->assertOk()
|
||||
->assertJsonFragment(
|
||||
(new PermissionResource($permissions2[0]))->toArray(null)
|
||||
)
|
||||
->assertJsonFragment(
|
||||
(new PermissionResource($permissions2[1]))->toArray(null)
|
||||
)
|
||||
->assertJsonFragment(
|
||||
(new PermissionResource($permissions2[2]))->toArray(null)
|
||||
);
|
||||
|
||||
|
||||
foreach ($permissions2 as $perm) {
|
||||
$this->assertDatabaseHas('permission_role', [
|
||||
'permission_id' => $perm->id,
|
||||
'role_id' => $role->id
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
private function getUser()
|
||||
{
|
||||
return UserFactory::user()->withPermissions('permissions.manage')->create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Authorization;
|
||||
|
||||
use Facades\Tests\Setup\RoleFactory;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Http\Resources\RoleResource;
|
||||
use Vanguard\Role;
|
||||
use Vanguard\User;
|
||||
|
||||
class RolesControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function unauthenticated()
|
||||
{
|
||||
$this->getJson('/api/roles')
|
||||
->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_settings_without_permission()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->getJson('/api/roles')
|
||||
->assertStatus(403);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_roles()
|
||||
{
|
||||
Role::factory()->times(4)->create();
|
||||
|
||||
$response = $this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->getJson("/api/roles")
|
||||
->assertOk();
|
||||
|
||||
$this->assertCount(7, $response->original);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_role()
|
||||
{
|
||||
$userRole = Role::whereName('User')->first();
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->getJson("/api/roles/{$userRole->id}")
|
||||
->assertOk()
|
||||
->assertJson([
|
||||
'data' => (new RoleResource($userRole))->resolve()
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function create_role()
|
||||
{
|
||||
$this->getUser();
|
||||
|
||||
$data = [
|
||||
'name' => 'foo',
|
||||
'display_name' => 'Foo Role',
|
||||
'description' => 'This is foo role.'
|
||||
];
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->postJson("/api/roles", $data)
|
||||
->assertStatus(201)
|
||||
->assertJsonFragment($data);
|
||||
|
||||
$this->assertDatabaseHas('roles', $data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function create_role_with_invalid_name()
|
||||
{
|
||||
$this->be($this->getUser(), self::API_GUARD);
|
||||
|
||||
$this->postJson("/api/roles")
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors('name');
|
||||
|
||||
$this->postJson("/api/roles", ['name' => 'User'])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors('name');
|
||||
|
||||
$this->postJson("/api/roles", ['name' => 'foo bar'])
|
||||
->assertStatus(422)
|
||||
->assertJsonValidationErrors('name');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_role()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
$data = ['name' => 'foo'];
|
||||
$expected = $data + ['id' => $user->role_id];
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->patchJson("/api/roles/{$user->role_id}", $data)
|
||||
->assertOk()
|
||||
->assertJsonFragment($expected);
|
||||
|
||||
$this->assertDatabaseHas('roles', $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function partially_update_role()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
|
||||
$data = [
|
||||
'name' => 'foo',
|
||||
'display_name' => 'Foo Role',
|
||||
'description' => 'This is foo role.'
|
||||
];
|
||||
$expected = $data + ['id' => $user->role_id];
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->patchJson("/api/roles/{$user->role_id}", $data)
|
||||
->assertOk()
|
||||
->assertJsonFragment($expected);
|
||||
|
||||
$this->assertDatabaseHas('roles', $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function remove_role()
|
||||
{
|
||||
$userRole = Role::whereName('User')->first();
|
||||
$role = RoleFactory::removable()->withPermissions('roles.manage')->create();
|
||||
$user = UserFactory::role($role)->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->deleteJson("/api/roles/{$role->id}")
|
||||
->assertOk()
|
||||
->assertJson(['success' => true]);
|
||||
|
||||
$this->assertDatabaseMissing('roles', ['id' => $role->id]);
|
||||
$this->assertEquals($userRole->id, $user->fresh()->role_id);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function remove_non_removable_role()
|
||||
{
|
||||
$role = RoleFactory::withPermissions('roles.manage')->create();
|
||||
|
||||
$this->actingAs($this->getUser(), self::API_GUARD)
|
||||
->deleteJson("/api/roles/{$role->id}")
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
private function getUser()
|
||||
{
|
||||
return UserFactory::user()->withPermissions('roles.manage')->create();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api;
|
||||
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Country;
|
||||
use Vanguard\Http\Resources\CountryResource;
|
||||
|
||||
class CountriesControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function unauthenticated()
|
||||
{
|
||||
$this->getJson('/api/countries')->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_all_countries()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
$this->getJson("/api/countries")
|
||||
->assertOk()
|
||||
->assertJson([
|
||||
'data' => CountryResource::collection(Country::all())->resolve()
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Profile;
|
||||
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
|
||||
class AuthDetailsControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function user_can_update_his_authentication_details()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$this->patch('/api/me/details/auth', [
|
||||
'email' => 'foo@example.com',
|
||||
'username' => 'john.doe',
|
||||
'password' => '12345678',
|
||||
'password_confirmation' => '12345678'
|
||||
])->assertOk()
|
||||
->assertJsonFragment(['email' => 'foo@example.com', 'username' => 'john.doe']);
|
||||
|
||||
$this->assertTrue(password_verify('12345678', $user->fresh()->password));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_can_update_only_email_and_leave_other_fields_unchanged()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$this->patch('/api/me/details/auth', [
|
||||
'email' => 'foo@example.com',
|
||||
])->assertOk()
|
||||
->assertJsonFragment(['email' => 'foo@example.com']);
|
||||
|
||||
$this->assertEquals($user->username, $user->fresh()->username);
|
||||
$this->assertEquals($user->password, $user->fresh()->password);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function email_field_is_required()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
$this->patch('/api/me/details/auth')
|
||||
->assertJsonValidationErrors('email');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function email_field_must_be_valid_email()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
$this->patch('/api/me/details/auth', [
|
||||
'email' => 'invalid email'
|
||||
])->assertJsonValidationErrors('email');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function email_field_must_be_unique()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
UserFactory::email('john.doe@test.com')->create();
|
||||
|
||||
$this->patch('/api/me/details/auth', [
|
||||
'email' => 'john.doe@test.com',
|
||||
])->assertJsonValidationErrors('email');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function username_field_must_be_unique()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
UserFactory::withCredentials('john.doe', '123123')->create();
|
||||
|
||||
$this->patch('/api/me/details/auth', [
|
||||
'email' => 'john.doe@test.com',
|
||||
'username' => 'john.doe'
|
||||
])->assertJsonValidationErrors('username');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Profile;
|
||||
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Storage;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
|
||||
class AvatarControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function only_authenticated_user_can_update_avatar()
|
||||
{
|
||||
$this->post('/api/me/avatar')->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function upload_avatar_image()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
Storage::fake('public');
|
||||
|
||||
$file = UploadedFile::fake()->image('avatar.png', 500, 500);
|
||||
|
||||
$response = $this->post('api/me/avatar', [
|
||||
'file' => $file
|
||||
]);
|
||||
|
||||
$this->assertNotNull($response->json('data.avatar'));
|
||||
|
||||
$uploadedFile = str_replace(url(''), '', $response->json('data.avatar'));
|
||||
$uploadedFile = ltrim($uploadedFile, "/");
|
||||
|
||||
Storage::disk('public')->assertExists($uploadedFile);
|
||||
|
||||
list($width, $height) = getimagesizefromstring(
|
||||
Storage::disk('public')->get($uploadedFile)
|
||||
);
|
||||
|
||||
$this->assertEquals(160, $width);
|
||||
$this->assertEquals(160, $height);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function upload_invalid_image()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
Storage::fake('public');
|
||||
|
||||
$file = UploadedFile::fake()->create('avatar.txt', 500);
|
||||
|
||||
$this->post('/api/me/avatar', ['file' => $file])
|
||||
->assertStatus(422)
|
||||
->assertJsonFragment([
|
||||
'file' => [
|
||||
trans('validation.image', ['attribute' => 'file'])
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_avatar_from_external_source()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
$url = 'http://google.com';
|
||||
|
||||
$this->putJson('/api/me/avatar/external', ['url' => $url])
|
||||
->assertOk()
|
||||
->assertJsonFragment(['avatar' => $url]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_avatar_with_invalid_external_source()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
$this->putJson('/api/me/avatar/external', ['url' => 'foo'])
|
||||
->assertStatus(422);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function delete_avatar()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$user->forceFill(['avatar' => 'http://google.com'])->save();
|
||||
|
||||
$this->deleteJson("api/me/avatar")
|
||||
->assertOk()
|
||||
->assertJsonFragment([
|
||||
'avatar' => url('assets/img/profile.png') // default profile image
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Profile;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Http\Resources\UserResource;
|
||||
|
||||
class DetailsControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function get_user_profile_unauthenticated()
|
||||
{
|
||||
$this->getJson('/api/me')->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_user_profile()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$this->getJson('/api/me')
|
||||
->assertOk()
|
||||
->assertJson(['data' => (new UserResource($user))->resolve()]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_user_profile_unauthenticated()
|
||||
{
|
||||
$this->patchJson('/api/me/details')->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_user_profile()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
$response = $this->patchJson("/api/me/details", $data);
|
||||
|
||||
$transformed = (new UserResource($user->fresh()))->resolve();
|
||||
|
||||
$response->assertJsonFragment($transformed);
|
||||
|
||||
$this->assertDatabaseHas('users', array_merge($data, ['id' => $user->id]));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function partially_update_user_details()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$data = [
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe'
|
||||
];
|
||||
|
||||
$response = $this->patchJson("/api/me/details", $data);
|
||||
|
||||
$transformed = (new UserResource($user->fresh()))->resolve();
|
||||
|
||||
$response->assertJsonFragment($transformed);
|
||||
|
||||
$this->assertDatabaseHas('users', array_merge($data, [
|
||||
'id' => $user->id,
|
||||
'birthday' => $user->birthday->format('Y-m-d'),
|
||||
'phone' => $user->phone,
|
||||
'address' => $user->address,
|
||||
'country_id' => $user->country_id,
|
||||
]));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_without_country_id()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$data = $this->getData();
|
||||
|
||||
unset($data['country_id']);
|
||||
|
||||
$response = $this->patchJson("/api/me/details", $data);
|
||||
|
||||
$transformed = (new UserResource($user->fresh()))->resolve();
|
||||
|
||||
$response->assertJsonFragment($transformed);
|
||||
|
||||
$this->assertDatabaseHas('users', array_merge($data, ['id' => $user->id]));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_with_invalid_date_format()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
$this->patchJson("/api/me/details", ['birthday' => 'foo'])
|
||||
->assertStatus(422)
|
||||
->assertJsonFragment([
|
||||
'birthday' => [
|
||||
trans('validation.date', ['attribute' => 'birthday'])
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $attrs
|
||||
* @return array
|
||||
*/
|
||||
private function getData(array $attrs = [])
|
||||
{
|
||||
return array_merge([
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe',
|
||||
'birthday' => Carbon::now()->subYears(25)->format('Y-m-d'),
|
||||
'phone' => '(123) 456 789',
|
||||
'address' => 'some address 1',
|
||||
'country_id' => 688,
|
||||
], $attrs);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Profile;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Http\Resources\SessionResource;
|
||||
use Vanguard\Repositories\Session\SessionRepository;
|
||||
use Vanguard\User;
|
||||
|
||||
class SessionsControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function get_user_sessions_unauthenticated()
|
||||
{
|
||||
$this->getJson('/api/me/sessions')->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_sessions_if_non_database_driver_is_used()
|
||||
{
|
||||
config(['session.driver' => 'array']);
|
||||
|
||||
$this->login();
|
||||
|
||||
$this->getJson('/api/me/sessions')->assertStatus(404);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_user_sessions()
|
||||
{
|
||||
config(['session.driver' => 'database']);
|
||||
|
||||
$user = $this->login();
|
||||
|
||||
$sessions = $this->generateNonExpiredSessions($user);
|
||||
|
||||
$this->getJson('/api/me/sessions')
|
||||
->assertOk()
|
||||
->assertJsonFragment([
|
||||
'data' => SessionResource::collection($sessions)->resolve()
|
||||
]);
|
||||
}
|
||||
|
||||
private function generateNonExpiredSessions(User $user, $count = 5)
|
||||
{
|
||||
$sessions = [];
|
||||
$faker = $this->app->make(\Faker\Generator::class);
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
array_push($sessions, [
|
||||
'id' => Str::random(40),
|
||||
'user_id' => $user->id,
|
||||
'ip_address' => $faker->ipv4,
|
||||
'user_agent' => $faker->userAgent,
|
||||
'payload' => Str::random(),
|
||||
'last_activity' => Carbon::now()->subMinute()->timestamp
|
||||
]);
|
||||
}
|
||||
|
||||
\DB::table('sessions')->insert($sessions);
|
||||
|
||||
return app(SessionRepository::class)->getUserSessions($user->id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Profile;
|
||||
|
||||
use Authy;
|
||||
use Event;
|
||||
use Mockery;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Events\User\TwoFactorEnabled;
|
||||
use Vanguard\Http\Resources\UserResource;
|
||||
use Vanguard\User;
|
||||
|
||||
class TwoFactorControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function update_2fa_unathenticated()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
User::factory()->create();
|
||||
|
||||
$this->putJson("api/me/2fa")
|
||||
->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function enable_two_factor_auth()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
Event::fake([
|
||||
TwoFactorEnabled::class,
|
||||
]);
|
||||
|
||||
$user = $this->login();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('register')->andReturnNull();
|
||||
Authy::shouldReceive('sendTwoFactorVerificationToken');
|
||||
|
||||
$data = ['country_code' => '1', 'phone_number' => '123'];
|
||||
|
||||
$this->putJson("api/me/2fa", $data)
|
||||
->assertOk()
|
||||
->assertJson(['message' => 'Verification token sent.']);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_country_code' => $data['country_code'],
|
||||
'two_factor_phone' => $data['phone_number']
|
||||
]);
|
||||
|
||||
Event::assertNotDispatched(TwoFactorEnabled::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function verify_user_phone_with_correct_token()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
Event::fake([
|
||||
TwoFactorEnabled::class,
|
||||
]);
|
||||
|
||||
$user = $this->login();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('tokenIsValid')->with(Mockery::any(), '123123')->andReturn(true);
|
||||
|
||||
$response = $this->postJson("api/me/2fa/verify", ['token' => '123123']);
|
||||
|
||||
$updatedUser = (new UserResource($user->fresh()))->resolve();
|
||||
|
||||
$response->assertOk()
|
||||
->assertJsonFragment($updatedUser);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_options' => '{"enabled":true}'
|
||||
]);
|
||||
|
||||
Event::assertDispatched(TwoFactorEnabled::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function verify_user_phone_with_invalid_token()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = $this->login();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('tokenIsValid')->andReturn(false);
|
||||
|
||||
$this->postJson("api/me/2fa/verify", ['token' => '123123'])
|
||||
->assertStatus(422)
|
||||
->assertJson(['message' => 'Invalid 2FA token.']);
|
||||
|
||||
$this->assertDatabaseMissing('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_options' => '{"enabled":true}'
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function enable_two_factor_auth_when_it_is_already_enabled()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->login();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
|
||||
$data = ['country_code' => '1', 'phone_number' => '123'];
|
||||
|
||||
$this->putJson("api/me/2fa", $data)
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => '2FA is already enabled for this user.'
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function disable_two_factor_auth()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = User::factory()->create([
|
||||
'two_factor_country_code' => '1',
|
||||
'two_factor_phone' => '123'
|
||||
]);
|
||||
|
||||
$this->be($user, self::API_GUARD);
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
Authy::shouldReceive('delete')->andReturnNull();
|
||||
|
||||
$response = $this->deleteJson("api/me/2fa");
|
||||
|
||||
$user = (new UserResource($user->fresh()))->resolve();
|
||||
|
||||
$response->assertOk()
|
||||
->assertJsonFragment($user);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function disable_2fa_when_it_is_already_disabled()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->login();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
|
||||
$this->deleteJson("api/me/2fa")
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => '2FA is not enabled for this user.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Support\Str;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Http\Resources\SessionResource;
|
||||
use Vanguard\Repositories\Session\SessionRepository;
|
||||
use Vanguard\User;
|
||||
|
||||
class SessionsControllerTest extends ApiTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
config(['session.driver' => 'database']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function unauthenticated()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$session = $this->createSession($user);
|
||||
|
||||
$this->getJson("/api/sessions/{$session->id}")
|
||||
->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_session_which_belongs_to_other_user()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
$user2 = User::factory()->create();
|
||||
|
||||
$session = $this->createSession($user2);
|
||||
|
||||
$this->getJson("/api/sessions/{$session->id}")
|
||||
->assertStatus(403);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_session()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$session = $this->createSession($user);
|
||||
|
||||
$this->getJson("/api/sessions/{$session->id}")
|
||||
->assertStatus(200)
|
||||
->assertJson([
|
||||
'data' => (new SessionResource($session))->resolve()
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function invalidate_his_own_session()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$session = $this->createSession($user);
|
||||
|
||||
$this->deleteJson("/api/sessions/{$session->id}")
|
||||
->assertStatus(200)
|
||||
->assertJson(['success' => true]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function invalidate_session_for_other_user()
|
||||
{
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
$user2 = User::factory()->create();
|
||||
$session = $this->createSession($user2);
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->deleteJson("/api/sessions/{$session->id}")
|
||||
->assertOk()
|
||||
->assertJson(['success' => true]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function invalidate_session_for_other_user_without_permission()
|
||||
{
|
||||
$this->login();
|
||||
$user2 = User::factory()->create();
|
||||
$session = $this->createSession($user2);
|
||||
|
||||
$this->deleteJson("/api/sessions/{$session->id}")
|
||||
->assertStatus(403);
|
||||
}
|
||||
|
||||
private function createSession(User $user)
|
||||
{
|
||||
$sessionId = Str::random(40);
|
||||
|
||||
$data = [
|
||||
'id' => $sessionId,
|
||||
'user_id' => $user->id,
|
||||
'ip_address' => "127.0.0.1",
|
||||
'user_agent' => 'foo',
|
||||
'payload' => Str::random(),
|
||||
'last_activity' => Carbon::now()->timestamp
|
||||
];
|
||||
|
||||
\DB::table('sessions')->insert($data);
|
||||
|
||||
return app(SessionRepository::class)->find($sessionId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api;
|
||||
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Setting;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\User;
|
||||
|
||||
class SettingsControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function only_authenticated_users_can_view_app_settings()
|
||||
{
|
||||
$this->getJson('/api/settings')->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_settings_without_permission()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->getJson('/api/settings')
|
||||
->assertStatus(403);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_settings()
|
||||
{
|
||||
$user = UserFactory::withPermissions('settings.general')->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->getJson("/api/settings")
|
||||
->assertOk()
|
||||
->assertJson(Setting::all());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Http\Resources\UserResource;
|
||||
use Vanguard\Repositories\User\UserRepository;
|
||||
use Vanguard\Role;
|
||||
use Vanguard\Support\Enum\UserStatus;
|
||||
use Vanguard\User;
|
||||
|
||||
class StatsControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function unauthenticated()
|
||||
{
|
||||
$this->getJson('/api/stats')->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_stats_as_admin()
|
||||
{
|
||||
\DB::table('users')->delete();
|
||||
|
||||
$adminRole = Role::whereName('Admin')->first();
|
||||
|
||||
$user = User::factory()->create(['role_id' => $adminRole->id]);
|
||||
|
||||
$this->be($user, self::API_GUARD);
|
||||
|
||||
Carbon::setTestNow(Carbon::now()->startOfYear());
|
||||
|
||||
User::factory()->times(4)->create(['status' => UserStatus::ACTIVE]);
|
||||
|
||||
Carbon::setTestNow(null);
|
||||
|
||||
User::factory()->times(2)->create(['status' => UserStatus::BANNED]);
|
||||
|
||||
User::factory()->times(7)->create(['status' => UserStatus::UNCONFIRMED]);
|
||||
|
||||
$users = app(UserRepository::class);
|
||||
|
||||
$response = $this->getJson("/api/stats");
|
||||
|
||||
$usersPerMonth = $users->countOfNewUsersPerMonth(
|
||||
now()->subYear()->startOfMonth(),
|
||||
now()->endOfMonth()
|
||||
);
|
||||
|
||||
$latestRegistrations = $users->latest(7);
|
||||
|
||||
$response->assertOk()
|
||||
->assertJson([
|
||||
'users_per_month' => $usersPerMonth,
|
||||
'users_per_status' => [
|
||||
'total' => 14,
|
||||
'new' => $users->newUsersCount(),
|
||||
'banned' => 2,
|
||||
'unconfirmed' => 7
|
||||
],
|
||||
'latest_registrations' => UserResource::collection($latestRegistrations)->resolve()
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function non_admin_users_cannot_get_user_stats()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)->getJson("/api/stats")->assertForbidden();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Users;
|
||||
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Storage;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Events\User\TwoFactorEnabledByAdmin;
|
||||
use Vanguard\Events\User\UpdatedByAdmin;
|
||||
use Vanguard\User;
|
||||
|
||||
class AvatarControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function upload_user_avatar_unauthenticated()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->post("/api/users/{$user->id}/avatar")
|
||||
->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function upload_avatar_without_permission()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->post("/api/users/{$user->id}/avatar")
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function upload_avatar_image()
|
||||
{
|
||||
\Event::fake([UpdatedByAdmin::class]);
|
||||
|
||||
Storage::fake('public');
|
||||
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$file = UploadedFile::fake()->image('avatar.png', 500, 500);
|
||||
|
||||
$response = $this->actingAs($user, self::API_GUARD)
|
||||
->post("/api/users/{$user->id}/avatar", ['file' => $file])
|
||||
->assertOk();
|
||||
|
||||
$avatar = $response->json('data.avatar');
|
||||
$this->assertNotNull($avatar);
|
||||
|
||||
$uploadedFile = str_replace(url(''), '', $avatar);
|
||||
$uploadedFile = ltrim($uploadedFile, "/");
|
||||
|
||||
Storage::disk('public')->assertExists($uploadedFile);
|
||||
|
||||
list($width, $height) = getimagesizefromstring(
|
||||
Storage::disk('public')->get($uploadedFile)
|
||||
);
|
||||
|
||||
$this->assertEquals(160, $width);
|
||||
$this->assertEquals(160, $height);
|
||||
|
||||
\Event::assertDispatched(UpdatedByAdmin::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function upload_invalid_image()
|
||||
{
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
Storage::fake('public');
|
||||
|
||||
$file = UploadedFile::fake()->create('avatar.txt', 500);
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->post("/api/users/{$user->id}/avatar", ['file' => $file])
|
||||
->assertStatus(422)
|
||||
->assertJsonFragment([
|
||||
'file' => [
|
||||
trans('validation.image', ['attribute' => 'file'])
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_avatar_from_external_source()
|
||||
{
|
||||
\Event::fake([UpdatedByAdmin::class]);
|
||||
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$url = 'http://google.com';
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->putJson("/api/users/{$user->id}/avatar/external", ['url' => $url])
|
||||
->assertOk()
|
||||
->assertJsonFragment(['avatar' => $url]);
|
||||
|
||||
\Event::assertDispatched(UpdatedByAdmin::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_avatar_with_invalid_external_source()
|
||||
{
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->putJson("/api/users/{$user->id}/avatar/external", ['url' => 'foo'])
|
||||
->assertStatus(422);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function delete_user_avatar()
|
||||
{
|
||||
\Event::fake([UpdatedByAdmin::class]);
|
||||
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$user->forceFill(['avatar' => 'http://google.com'])->save();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->deleteJson("api/users/{$user->id}/avatar")
|
||||
->assertOk()
|
||||
->assertJsonFragment([
|
||||
'avatar' => url('assets/img/profile.png') // default profile image
|
||||
]);
|
||||
|
||||
\Event::assertDispatched(UpdatedByAdmin::class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Users;
|
||||
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Support\Str;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Http\Resources\SessionResource;
|
||||
use Vanguard\Repositories\Session\SessionRepository;
|
||||
use Vanguard\User;
|
||||
|
||||
class SessionsControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function get_sessions_unauthenticated()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->getJson("/api/users/{$user->id}/sessions")->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_user_sessions_without_permission()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->getJson("/api/users/{$user->id}/sessions")
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_user_sessions()
|
||||
{
|
||||
config(['session.driver' => 'database']);
|
||||
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$sessions = $this->generateNonExpiredSessions($user);
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->getJson("/api/users/{$user->id}/sessions")
|
||||
->assertOk()
|
||||
->assertJson([
|
||||
'data' => SessionResource::collection($sessions)->resolve()
|
||||
]);
|
||||
}
|
||||
|
||||
private function generateNonExpiredSessions(User $user, $count = 5)
|
||||
{
|
||||
$sessions = [];
|
||||
$faker = $this->app->make(\Faker\Generator::class);
|
||||
$lifetime = config('session.lifetime') - 1;
|
||||
|
||||
for ($i = 0; $i < $count; $i++) {
|
||||
array_push($sessions, [
|
||||
'id' => Str::random(40),
|
||||
'user_id' => $user->id,
|
||||
'ip_address' => $faker->ipv4,
|
||||
'user_agent' => $faker->userAgent,
|
||||
'payload' => Str::random(),
|
||||
'last_activity' => $faker->dateTimeBetween("-{$lifetime} minutes")->getTimestamp()
|
||||
]);
|
||||
}
|
||||
|
||||
\DB::table('sessions')->insert($sessions);
|
||||
|
||||
return app(SessionRepository::class)->getUserSessions($user->id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Users;
|
||||
|
||||
use Authy;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Mockery;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Events\User\TwoFactorDisabledByAdmin;
|
||||
use Vanguard\Events\User\TwoFactorEnabledByAdmin;
|
||||
use Vanguard\Http\Resources\UserResource;
|
||||
use Vanguard\User;
|
||||
|
||||
class TwoFactorControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function update_2fa_unathenticated()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->putJson("api/users/{$user->id}/2fa")
|
||||
->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_2fa_without_permission()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->putJson("api/users/{$user->id}/2fa")
|
||||
->assertForbidden();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function enable_two_factor_auth_for_user()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
\Event::fake([TwoFactorEnabledByAdmin::class]);
|
||||
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('register')->andReturnNull();
|
||||
Authy::shouldReceive('sendTwoFactorVerificationToken');
|
||||
|
||||
$data = ['country_code' => '1', 'phone_number' => '123'];
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)->putJson("api/users/{$user->id}/2fa", $data)
|
||||
->assertOk()
|
||||
->assertJson(['message' => 'Verification token sent.']);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_country_code' => $data['country_code'],
|
||||
'two_factor_phone' => $data['phone_number']
|
||||
]);
|
||||
|
||||
\Event::assertNotDispatched(TwoFactorEnabledByAdmin::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function verify_user_phone_with_correct_token()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
\Event::fake([TwoFactorEnabledByAdmin::class]);
|
||||
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('tokenIsValid')->with(Mockery::any(), '123123')->andReturn(true);
|
||||
|
||||
$response = $this->actingAs($user, self::API_GUARD)
|
||||
->postJson("api/users/{$user->id}/2fa/verify", ['token' => '123123']);
|
||||
|
||||
$updatedUser = (new UserResource($user->fresh()))->resolve();
|
||||
|
||||
$response->assertOk()
|
||||
->assertJsonFragment($updatedUser);
|
||||
|
||||
$this->assertTrue($user->fresh()->getTwoFactorAuthProviderOptions()['enabled']);
|
||||
|
||||
\Event::assertDispatched(TwoFactorEnabledByAdmin::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function verify_user_phone_with_invalid_token()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('tokenIsValid')->andReturn(false);
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->postJson("api/users/{$user->id}/2fa/verify", ['token' => '123123'])
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => 'Invalid 2FA token.'
|
||||
]);
|
||||
|
||||
$this->assertDatabaseMissing('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_options' => '{"enabled":true}'
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function enable_two_factor_auth_for_user_when_it_is_already_enabled()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
|
||||
$data = ['country_code' => '1', 'phone_number' => '123'];
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->putJson("api/users/{$user->id}/2fa", $data)
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => '2FA is already enabled for this user.'
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function disable_two_factor_auth_for_user()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
\Event::fake([TwoFactorDisabledByAdmin::class]);
|
||||
|
||||
$user = UserFactory::withPermissions('users.manage')->twoFactor('1', '123')->create();
|
||||
|
||||
$this->be($user, self::API_GUARD);
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
Authy::shouldReceive('delete')->andReturnNull();
|
||||
|
||||
$response = $this->deleteJson("api/users/{$user->id}/2fa");
|
||||
|
||||
$user = (new UserResource($user->fresh()))->resolve();
|
||||
|
||||
$response->assertOk()
|
||||
->assertJsonFragment($user);
|
||||
|
||||
\Event::assertDispatched(TwoFactorDisabledByAdmin::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function disable_2fa_for_user_when_it_is_already_disabled()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->deleteJson("api/users/{$user->id}/2fa")
|
||||
->assertStatus(422)
|
||||
->assertJson([
|
||||
'message' => '2FA is not enabled for this user.'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Api\Users;
|
||||
|
||||
use Event;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Support\Arr;
|
||||
use Tests\Feature\ApiTestCase;
|
||||
use Vanguard\Country;
|
||||
use Vanguard\Events\User\Deleted;
|
||||
use Vanguard\Events\User\UpdatedByAdmin;
|
||||
use Vanguard\Http\Resources\UserResource;
|
||||
use Vanguard\Role;
|
||||
use Vanguard\Support\Enum\UserStatus;
|
||||
use Vanguard\User;
|
||||
|
||||
class UsersControllerTest extends ApiTestCase
|
||||
{
|
||||
/** @test */
|
||||
public function only_authenticated_users_can_list_all_users()
|
||||
{
|
||||
$this->getJson('/api/users')->assertStatus(401);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_users_without_permission()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user, self::API_GUARD)
|
||||
->getJson('/api/users')
|
||||
->assertStatus(403);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function paginate_all_users()
|
||||
{
|
||||
\DB::table('users')->delete();
|
||||
|
||||
$user = $this->login();
|
||||
|
||||
$users = User::factory()->times(20)->create();
|
||||
$users->push($user);
|
||||
|
||||
$response = $this->getJson('/api/users');
|
||||
|
||||
$transformed = UserResource::collection($users->sortBy('id')->take(20))->resolve();
|
||||
|
||||
$this->assertEquals($response->json('data'), $transformed);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function paginate_users_with_country_included()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
$country = Country::factory()->create();
|
||||
|
||||
User::factory()->create(['country_id' => null]);
|
||||
User::factory()->create(['country_id' => $country->id]);
|
||||
|
||||
$response = $this->getJson('/api/users?include=country')
|
||||
->assertOk()
|
||||
->json();
|
||||
|
||||
$this->assertNull($response['data'][0]['country']);
|
||||
$this->assertNotNull($response['data'][1]['country_id']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function paginate_users_by_status()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
User::factory()->times(2)->create(['status' => UserStatus::ACTIVE]);
|
||||
User::factory()->times(5)->create(['status' => UserStatus::BANNED]);
|
||||
|
||||
$response = $this->getJson('/api/users?filter[status]=' . UserStatus::BANNED);
|
||||
|
||||
$this->assertCount(5, $response->json('data'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function paginate_users_on_search()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$user1 = User::factory()->create([
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe',
|
||||
'email' => 'john.doe@vanguardapp.io'
|
||||
]);
|
||||
|
||||
$user2 = User::factory()->create([
|
||||
'first_name' => 'Jane',
|
||||
'last_name' => 'Doe',
|
||||
'email' => 'jane.doe@vanguardapp.io'
|
||||
]);
|
||||
|
||||
$user3 = User::factory()->create([
|
||||
'first_name' => 'Brad',
|
||||
'last_name' => 'Pitt',
|
||||
'email' => 'b.pitt@vanguardapp.io'
|
||||
]);
|
||||
|
||||
$response = $this->getJson('/api/users?filter[search]=doe');
|
||||
|
||||
$this->assertCount(2, $response->json('data'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function create_user()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
$newUser = User::factory()->make();
|
||||
|
||||
$data = array_merge($newUser->toArray(), [
|
||||
'birthday' => $newUser->birthday->format('Y-m-d'),
|
||||
'role' => $newUser->role_id,
|
||||
'password' => '123123',
|
||||
'password_confirmation' => '123123'
|
||||
]);
|
||||
|
||||
$response = $this->postJson('api/users', $data);
|
||||
|
||||
$expected = [
|
||||
'first_name' => $newUser->first_name,
|
||||
'last_name' => $newUser->last_name,
|
||||
'email' => $newUser->email,
|
||||
'username' => $newUser->username,
|
||||
'country_id' => $newUser->country_id,
|
||||
'birthday' => $newUser->birthday->format('Y-m-d'),
|
||||
'phone' => $newUser->phone,
|
||||
'address' => $newUser->address,
|
||||
'status' => UserStatus::ACTIVE,
|
||||
'role_id' => $newUser->role_id
|
||||
];
|
||||
|
||||
$response->assertStatus(201)
|
||||
->assertJsonFragment($expected);
|
||||
|
||||
$this->assertDatabaseHas('users', $expected);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_user()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$this->getJson("api/users/{$user->id}")
|
||||
->assertOk()
|
||||
->assertJson([
|
||||
'data' => (new UserResource($user->fresh()))->resolve()
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function get_user_which_does_not_exist()
|
||||
{
|
||||
$this->login();
|
||||
|
||||
$this->getJson("api/users/222")->assertStatus(404);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_user()
|
||||
{
|
||||
Event::fake([UpdatedByAdmin::class]);
|
||||
|
||||
$user = $this->login();
|
||||
|
||||
$data = [
|
||||
'email' => 'john.doe@test.com',
|
||||
'username' => 'john.doe',
|
||||
'password' => '123123',
|
||||
'password_confirmation' => '123123',
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe',
|
||||
'phone' => '+38123456789',
|
||||
'address' => 'Some random address',
|
||||
'country_id' => Country::first()->id,
|
||||
'birthday' => '1990-10-18',
|
||||
'status' => UserStatus::BANNED,
|
||||
'role_id' => Role::whereName('User')->first()->id
|
||||
];
|
||||
|
||||
$expected = Arr::except($data, ['password', 'password_confirmation']);
|
||||
$expected += ['id' => $user->id];
|
||||
|
||||
$this->patchJson("api/users/{$user->id}", $data)
|
||||
->assertOk()
|
||||
->assertJsonFragment($expected);
|
||||
|
||||
$this->assertDatabaseHas('users', $expected);
|
||||
|
||||
Event::assertDispatched(UpdatedByAdmin::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_only_specific_field()
|
||||
{
|
||||
Event::fake([UpdatedByAdmin::class]);
|
||||
|
||||
$user = $this->login();
|
||||
|
||||
$data = ['email' => 'john.doe@test.com'];
|
||||
|
||||
$expected = array_merge(
|
||||
$user->toArray(),
|
||||
$data,
|
||||
['birthday' => $user->birthday->format('Y-m-d')]
|
||||
);
|
||||
|
||||
$expected = Arr::except($expected, ['created_at', 'updated_at', 'avatar', 'role']);
|
||||
|
||||
$this->patchJson("api/users/{$user->id}", $data)
|
||||
->assertOk()
|
||||
->assertJsonFragment($expected);
|
||||
|
||||
$this->assertDatabaseHas('users', $expected);
|
||||
|
||||
Event::assertDispatched(UpdatedByAdmin::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function delete_user()
|
||||
{
|
||||
Event::fake([Deleted::class]);
|
||||
|
||||
$user = $this->login();
|
||||
|
||||
$user2 = User::factory()->create();
|
||||
|
||||
$this->deleteJson("api/users/{$user2->id}")
|
||||
->assertOk()
|
||||
->assertJson(['success' => true]);
|
||||
|
||||
Event::assertDispatched(Deleted::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function delete_yourself()
|
||||
{
|
||||
$user = $this->login();
|
||||
|
||||
$this->deleteJson("api/users/{$user->id}")
|
||||
->assertStatus(403)
|
||||
->assertJson(['message' => "You cannot delete yourself."]);
|
||||
}
|
||||
|
||||
protected function login()
|
||||
{
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$this->be($user, self::API_GUARD);
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Testing\TestResponse;
|
||||
use Tests\TestCase;
|
||||
use Tests\UpdatesSettings;
|
||||
use Vanguard\User;
|
||||
|
||||
class ApiTestCase extends TestCase
|
||||
{
|
||||
use RefreshDatabase, UpdatesSettings;
|
||||
|
||||
const API_GUARD = 'sanctum';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
|
||||
$this->setSettings(['auth.expose_api' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
protected function login()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->be($user, self::API_GUARD);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
protected function loginSuperUser()
|
||||
{
|
||||
$user = $this->createSuperUser();
|
||||
|
||||
$this->be($user, self::API_GUARD);
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform provided collection of items.
|
||||
* @param Collection $collection
|
||||
* @param $transformer
|
||||
* @return array
|
||||
*/
|
||||
protected function transformCollection(Collection $collection, $transformer)
|
||||
{
|
||||
$transformed = [];
|
||||
|
||||
foreach ($collection as $item) {
|
||||
$transformed[] = $transformer->transform($item);
|
||||
}
|
||||
|
||||
return $transformed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web;
|
||||
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
use Vanguard\User;
|
||||
|
||||
class ImpersonateUsersTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed --class=RolesSeeder');
|
||||
$this->artisan('db:seed --class=PermissionsSeeder');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function unverified_users_cannot_impersonate_other_users()
|
||||
{
|
||||
$user = UserFactory::withPermissions('users.manage')->unverified()->create();
|
||||
|
||||
User::factory()->create();
|
||||
|
||||
$this->actingAs($user)->get('/users')->assertRedirect("/email/verify");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_user_with_appropriate_permission_can_impersonate_other_users_from_a_user_list_page()
|
||||
{
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
User::factory()->create();
|
||||
|
||||
$this->actingAs($user)->get('/users')->assertSee("Impersonate");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function a_user_dont_see_impersonate_button_next_to_his_name_in_the_user_list()
|
||||
{
|
||||
$user = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$this->actingAs($user)->get('/user')->assertDontSee("Impersonate");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function clicking_on_impersonate_button_will_impersonate_the_user()
|
||||
{
|
||||
$userA = UserFactory::withPermissions('users.manage')->create();
|
||||
$userB = UserFactory::user()->create();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->get(route('impersonate', $userB))
|
||||
->assertRedirect("/");
|
||||
|
||||
$this->assertTrue(auth()->user()->is($userB));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function while_impersonating_user_can_stop_impersonating_by_clicking_on_the_header_button()
|
||||
{
|
||||
$userA = UserFactory::withPermissions('users.manage')->create();
|
||||
$userB = UserFactory::user()->create();
|
||||
|
||||
$this->actingAs($userA)->get(route('impersonate', $userB));
|
||||
|
||||
$this->assertTrue(auth()->user()->is($userB));
|
||||
|
||||
$this->get("/")->assertSee("Stop Impersonating");
|
||||
|
||||
$this->get(route('impersonate.leave'));
|
||||
|
||||
$this->assertTrue(auth()->user()->is($userA));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function while_impersonating_user_cannot_impersonate_other_user_even_if_he_has_a_permission()
|
||||
{
|
||||
$userA = UserFactory::withPermissions('users.manage')->create();
|
||||
$userB = UserFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$this->actingAs($userA)->get(route('impersonate', $userB));
|
||||
|
||||
$this->get("/user")
|
||||
->assertDontSee("Impersonate");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web;
|
||||
|
||||
use Authy;
|
||||
use Carbon\Carbon;
|
||||
use Event;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Cache\RateLimiter;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Mockery as m;
|
||||
use Setting;
|
||||
use Tests\TestCase;
|
||||
use Tests\UpdatesSettings;
|
||||
use Vanguard\Events\User\LoggedIn;
|
||||
use Vanguard\User;
|
||||
|
||||
class LoginTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, UpdatesSettings;
|
||||
|
||||
/** @test */
|
||||
public function successful_login()
|
||||
{
|
||||
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
||||
|
||||
$this->loginUser('foo', 'bar')
|
||||
->assertRedirect('/');
|
||||
|
||||
$this->assertTrue(auth()->check());
|
||||
$this->assertTrue($user->is(auth()->user()));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function last_login_timestamp_is_updated_after_successful_login()
|
||||
{
|
||||
$testDate = Carbon::now();
|
||||
|
||||
Carbon::setTestNow($testDate);
|
||||
|
||||
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
||||
|
||||
$this->assertNull($user->last_login);
|
||||
|
||||
$this->loginUser('foo', 'bar');
|
||||
|
||||
$this->assertEquals($testDate->timestamp, $user->fresh()->last_login->timestamp);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function login_with_wrong_credentials_will_fail()
|
||||
{
|
||||
$this->loginUser('foo', 'bar')
|
||||
->assertRedirect('/login');
|
||||
|
||||
$this->assertFalse(auth()->check());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function country_id_remains_the_same_after_login()
|
||||
{
|
||||
$user = User::factory()->create([
|
||||
'username' => 'foo',
|
||||
'password' => 'bar',
|
||||
'country_id' => 688
|
||||
]);
|
||||
|
||||
$this->loginUser('foo', 'bar')
|
||||
->assertRedirect("/");
|
||||
|
||||
$this->assertEquals(688, $user->fresh()->country_id);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function throttling()
|
||||
{
|
||||
$this->setSettings([
|
||||
'throttle_enabled' => true,
|
||||
'throttle_attempts' => 3,
|
||||
'throttle_lockout_time' => 2 // 2 minutes
|
||||
]);
|
||||
|
||||
for ($i = 0; $i < 3; $i++) {
|
||||
$this->loginUser('foo', 'bar');
|
||||
}
|
||||
|
||||
$this->loginUser('foo', 'bar')
|
||||
->assertRedirect('login')
|
||||
->assertSessionHasErrors('username');
|
||||
|
||||
$this->assertTrue(app(RateLimiter::class)->tooManyAttempts('foo|127.0.0.1', 3));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function login_with_remember()
|
||||
{
|
||||
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
||||
|
||||
Setting::set('remember_me', false);
|
||||
|
||||
$this->get('login')
|
||||
->assertDontSeeText('name="remember"', false);
|
||||
|
||||
Setting::set('remember_me', true);
|
||||
|
||||
$this->get('login')
|
||||
->assertSee('name="remember"', false);
|
||||
|
||||
$this->loginUser('foo', 'bar', true)
|
||||
->assertRedirect('/');
|
||||
|
||||
$this->assertNotNull($user->fresh()->remember_token);
|
||||
$this->assertNotNull($user->fresh()->last_login);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function banned_user_cannot_log_in()
|
||||
{
|
||||
UserFactory::withCredentials('foo', 'bar')->banned()->create();
|
||||
|
||||
$this->loginUser('foo', 'bar')
|
||||
->assertRedirect('/login');
|
||||
|
||||
$this->assertSessionHasError("Your account is banned by administrator.");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function login_with_2fa_enabled()
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
Event::fake([LoggedIn::class]);
|
||||
|
||||
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
Authy::shouldReceive('tokenIsValid')->with(m::any(), '123')->andReturn(true);
|
||||
|
||||
$this->loginUser('foo', 'bar')
|
||||
->assertRedirect('auth/two-factor-authentication')
|
||||
->assertSessionHas('auth.2fa.id', $user->id);
|
||||
|
||||
$this->post('auth/two-factor-authentication', ['token' => '123'])
|
||||
->assertRedirect('/');
|
||||
|
||||
$this->assertTrue(auth()->check());
|
||||
|
||||
Event::assertDispatched(LoggedIn::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function login_with_wrong_2fa_token()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
Authy::shouldReceive('tokenIsValid')->with(m::any(), '123')->andReturn(false);
|
||||
|
||||
$this->loginUser('foo', 'bar')
|
||||
->assertRedirect('auth/two-factor-authentication')
|
||||
->assertSessionHas('auth.2fa.id', $user->id);
|
||||
|
||||
$this->post('auth/two-factor-authentication', ['token' => '123'])
|
||||
->assertRedirect('login');
|
||||
|
||||
$this->assertSessionHasError('2FA Token is invalid!');
|
||||
}
|
||||
|
||||
private function loginUser($username, $password, $remember = false): \Illuminate\Testing\TestResponse
|
||||
{
|
||||
return $this->post('/login', [
|
||||
'username' => $username,
|
||||
'password' => $password,
|
||||
'remember' => $remember
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,370 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web;
|
||||
|
||||
use Event;
|
||||
use Facades\Tests\Setup\RoleFactory;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
use Vanguard\Events\Permission\Created;
|
||||
use Vanguard\Events\Permission\Deleted;
|
||||
use Vanguard\Events\Permission\Updated;
|
||||
use Vanguard\Events\Role\PermissionsUpdated;
|
||||
use Vanguard\Permission;
|
||||
use Vanguard\Role;
|
||||
|
||||
class PermissionsTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
|
||||
$this->be(UserFactory::admin()->create());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function permissions_list()
|
||||
{
|
||||
$permission = Permission::factory()->create();
|
||||
|
||||
$this->get('permissions')
|
||||
->assertSee($permission->display_name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_users_with_appropriate_permissions_can_access_the_permissions_list_page()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('permissions.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$this->actingAs($userA)->get('/permissions')->assertStatus(403);
|
||||
$this->actingAs($userB)->get('/permissions')->assertOk();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function permission_list_with_roles()
|
||||
{
|
||||
$permission = Permission::factory()->create();
|
||||
$role = Role::first();
|
||||
|
||||
$role->permissions()->attach($permission->id);
|
||||
|
||||
$this->get('permissions')
|
||||
->assertSee($permission->display_name)
|
||||
->assertSee("roles[$role->id][]");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function save_role_permissions()
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
Event::fake([
|
||||
PermissionsUpdated::class,
|
||||
]);
|
||||
|
||||
$permission = Permission::factory()->create();
|
||||
$role = Role::factory()->create();
|
||||
|
||||
$this->post('permissions/save', [
|
||||
'roles' => [
|
||||
$role->id => [$permission->id]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertSessionHasSuccess('Permissions saved successfully.');
|
||||
|
||||
$this->assertDatabaseHas('permission_role', [
|
||||
'role_id' => $role->id,
|
||||
'permission_id' => $permission->id
|
||||
]);
|
||||
|
||||
Event::assertDispatched(PermissionsUpdated::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_users_with_appropriate_permissions_can_save_role_permissions()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('permissions.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$permission = Permission::factory()->create();
|
||||
$role = Role::factory()->create();
|
||||
|
||||
$data = [$role->id => [$permission->id]];
|
||||
|
||||
$this->actingAs($userA)
|
||||
->post('permissions/save', ['roles' => $data])
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertDatabaseMissing('permission_role', [
|
||||
'role_id' => $role->id,
|
||||
'permission_id' => $permission->id
|
||||
]);
|
||||
|
||||
$this->actingAs($userB)
|
||||
->post('permissions/save', ['roles' => $data]);
|
||||
|
||||
$this->assertDatabaseHas('permission_role', [
|
||||
'role_id' => $role->id,
|
||||
'permission_id' => $permission->id
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function save_role_permissions_if_no_permission_is_selected_for_specific_role()
|
||||
{
|
||||
Event::fake([
|
||||
PermissionsUpdated::class,
|
||||
]);
|
||||
|
||||
$role1 = Role::factory()->create();
|
||||
$permission1 = Permission::factory()->create();
|
||||
$role1->permissions()->attach($permission1->id);
|
||||
|
||||
$role2 = Role::factory()->create();
|
||||
$permission2 = Permission::factory()->create();
|
||||
$role2->permissions()->attach($permission2->id);
|
||||
|
||||
$this->post('/permissions/save', [
|
||||
'roles' => [
|
||||
$role1->id => [$permission1->id]
|
||||
]
|
||||
]);
|
||||
|
||||
$this->assertSessionHasSuccess('Permissions saved successfully.');
|
||||
|
||||
$this->assertDatabaseHas('permission_role', [
|
||||
'role_id' => $role1->id,
|
||||
'permission_id' => $permission1->id
|
||||
]);
|
||||
|
||||
$this->assertDatabaseMissing('permission_role', [
|
||||
'role_id' => $role2->id,
|
||||
'permission_id' => $permission2->id
|
||||
]);
|
||||
|
||||
Event::assertDispatched(PermissionsUpdated::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function create_permission()
|
||||
{
|
||||
$this->app->instance('middleware.disable', false);
|
||||
|
||||
Event::fake([
|
||||
Created::class,
|
||||
]);
|
||||
|
||||
$data = $this->validParams();
|
||||
|
||||
$this->post('permissions', $data)
|
||||
->assertRedirect('/permissions');
|
||||
|
||||
$this->assertSessionHasSuccess('Permission created successfully.');
|
||||
$this->assertDatabaseHas('permissions', $data);
|
||||
|
||||
Event::assertDispatched(Created::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_users_with_appropriate_permission_can_create_new_permissions()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('permissions.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$data = $this->validParams();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->post('permissions', $data)
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertDatabaseMissing('permissions', $data);
|
||||
|
||||
$this->actingAs($userB)
|
||||
->post('permissions', $data)
|
||||
->assertRedirect('/permissions');
|
||||
|
||||
$this->assertDatabaseHas('permissions', $data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function permission_name_must_have_valid_format()
|
||||
{
|
||||
$this->app->instance('middleware.disable', false);
|
||||
|
||||
$data = $this->validParams();
|
||||
|
||||
$response = $this->post('permissions', $this->validParams(['name' => 'invalid name']));
|
||||
$response->assertSessionHasErrors('name');
|
||||
$this->assertDatabaseMissing('permissions', $data);
|
||||
|
||||
$response = $this->post('permissions', $this->validParams(['name' => 'invalid*name']));
|
||||
$response->assertSessionHasErrors('name');
|
||||
$this->assertDatabaseMissing('permissions', $data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_permission()
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
Event::fake([
|
||||
Updated::class,
|
||||
]);
|
||||
|
||||
$permission = Permission::factory()->create();
|
||||
|
||||
$this->get("permissions/{$permission->id}/edit")
|
||||
->assertOk()
|
||||
->assertSee($permission->id)
|
||||
->assertSee($permission->name)
|
||||
->assertSee($permission->display_name);
|
||||
|
||||
$data = $this->validParams();
|
||||
|
||||
$this->put("permissions/{$permission->id}", $data);
|
||||
|
||||
$this->assertSessionHasSuccess('Permission updated successfully.');
|
||||
$this->assertDatabaseHas('permissions', $data + ['id' => $permission->id]);
|
||||
|
||||
Event::assertDispatched(Updated::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_users_with_appropriate_permission_can_update_existing_permissions()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('permissions.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$permission = Permission::factory()->create();
|
||||
|
||||
$data = $this->validParams();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->put("permissions/{$permission->id}", $data)
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertEquals($permission->toArray(), $permission->fresh()->toArray());
|
||||
|
||||
$this->actingAs($userB)
|
||||
->put("permissions/{$permission->id}", $data)
|
||||
->assertRedirect('/permissions');
|
||||
|
||||
$permission->refresh();
|
||||
|
||||
$this->assertEquals($permission->name, $data['name']);
|
||||
$this->assertEquals($permission->display_name, $data['display_name']);
|
||||
$this->assertEquals($permission->description, $data['description']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function removable_attribute_cannot_be_changed_on_update()
|
||||
{
|
||||
$permission = Permission::factory()->create(['removable' => false]);
|
||||
|
||||
$data = $this->validParams(['removable' => true]);
|
||||
|
||||
$this->put("permissions/{$permission->id}", $data);
|
||||
|
||||
$permission->refresh();
|
||||
|
||||
$this->assertEquals($permission->name, $data['name']);
|
||||
$this->assertEquals($permission->display_name, $data['display_name']);
|
||||
$this->assertEquals($permission->description, $data['description']);
|
||||
$this->assertFalse($permission->removable);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function permission_name_must_have_valid_format_while_updating_the_permission()
|
||||
{
|
||||
$permission = Permission::factory()->create(['name' => 'foo']);
|
||||
|
||||
$response = $this->put('permissions/' . $permission->id, $this->validParams(['name' => 'invalid name']));
|
||||
$response->assertSessionHasErrors('name');
|
||||
$this->assertEquals('foo', $permission->fresh()->name);
|
||||
|
||||
$response = $this->put('permissions/' . $permission->id, $this->validParams(['name' => 'invalid*name']));
|
||||
$response->assertSessionHasErrors('name');
|
||||
$this->assertEquals('foo', $permission->fresh()->name);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function delete_permission()
|
||||
{
|
||||
Event::fake([
|
||||
Deleted::class,
|
||||
]);
|
||||
|
||||
$permission = Permission::factory()->create();
|
||||
|
||||
$this->delete(route('permissions.destroy', $permission->id))
|
||||
->assertRedirect('/permissions');
|
||||
|
||||
$this->assertSessionHasSuccess('Permission deleted successfully.');
|
||||
$this->assertDatabaseMissing('permissions', ['id' => $permission->id]);
|
||||
|
||||
Event::assertDispatched(Deleted::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_users_with_appropriate_permission_can_delete_permissions()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('permissions.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$permission = Permission::factory()->create();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->delete("permissions/{$permission->id}")
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertNotNull($permission->fresh());
|
||||
|
||||
$this->actingAs($userB)
|
||||
->delete("permissions/{$permission->id}")
|
||||
->assertRedirect('/permissions');
|
||||
|
||||
$this->assertNull($permission->fresh());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function non_removable_permissions_cannot_be_removed()
|
||||
{
|
||||
$permission = Permission::factory()->create(['removable' => false]);
|
||||
|
||||
$this->delete(route('permissions.destroy', $permission->id))
|
||||
->assertStatus(404);
|
||||
|
||||
$this->assertNotNull($permission->fresh());
|
||||
}
|
||||
|
||||
private function validParams(array $override = []): array
|
||||
{
|
||||
return array_merge([
|
||||
'name' => 'foo_permission',
|
||||
'display_name' => 'Foo Permission',
|
||||
'description' => 'the description'
|
||||
], $override);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web;
|
||||
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Auth\Notifications\VerifyEmail;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Notification;
|
||||
use Mail;
|
||||
use Tests\TestCase;
|
||||
use Tests\UpdatesSettings;
|
||||
use Vanguard\Support\Enum\UserStatus;
|
||||
use Vanguard\User;
|
||||
|
||||
class RegistrationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, UpdatesSettings;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function when_registration_is_disabled_a_visitor_cannot_see_the_registration_form()
|
||||
{
|
||||
$this->setSettings(['reg_enabled' => false]);
|
||||
|
||||
$this->get('register')->assertStatus(404);
|
||||
|
||||
$this->get('login')->assertDontSee('You don\'t have an account?');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function registration_with_email_confirmation()
|
||||
{
|
||||
$this->setSettings([
|
||||
'reg_enabled' => true,
|
||||
'reg_email_confirmation' => true,
|
||||
'registration.captcha.enabled' => false,
|
||||
'tos' => true
|
||||
]);
|
||||
|
||||
Notification::fake();
|
||||
|
||||
$data = $this->getRegistrationFormStubData();
|
||||
|
||||
$this->post('/register', $data)->assertRedirect('/');
|
||||
|
||||
$expected = Arr::except($data, ['password', 'password_confirmation', 'tos']);
|
||||
$expected += ['status' => UserStatus::UNCONFIRMED];
|
||||
|
||||
$this->assertDatabaseHas('users', $expected);
|
||||
|
||||
$user = User::where('email', $data['email'])->first();
|
||||
|
||||
Notification::assertSentTo($user, VerifyEmail::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function registration_without_email_confirmation()
|
||||
{
|
||||
$this->setSettings([
|
||||
'reg_enabled' => true,
|
||||
'reg_email_confirmation' => false,
|
||||
'notifications_signup_email' => false,
|
||||
'registration.captcha.enabled' => false,
|
||||
'tos' => true
|
||||
]);
|
||||
|
||||
Notification::fake();
|
||||
|
||||
$data = $this->getRegistrationFormStubData();
|
||||
|
||||
$this->post('/register', $data)->assertRedirect('/');
|
||||
|
||||
$expected = Arr::except($data, ['password', 'password_confirmation', 'tos']);
|
||||
$expected += ['status' => UserStatus::ACTIVE];
|
||||
|
||||
$this->assertDatabaseHas('users', $expected);
|
||||
|
||||
Notification::assertNotSentTo(
|
||||
User::where('email', $data['email'])->first(),
|
||||
VerifyEmail::class
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function email_notification_is_being_sent_when_new_user_registers()
|
||||
{
|
||||
$this->setSettings([
|
||||
'app_name' => 'foo',
|
||||
'reg_enabled' => true,
|
||||
'reg_email_confirmation' => false,
|
||||
'notifications_signup_email' => true,
|
||||
'registration.captcha.enabled' => false,
|
||||
'tos' => true
|
||||
]);
|
||||
|
||||
Mail::fake();
|
||||
|
||||
$admin = UserFactory::admin()->email('john.doe@test.com')->create();
|
||||
$user1 = UserFactory::user()->email('jane.doe@test.com')->create();
|
||||
$user2 = UserFactory::user()->email('josh.doe@test.com')->create();
|
||||
|
||||
$this->post('/register', $this->getRegistrationFormStubData());
|
||||
|
||||
Mail::assertQueued(\Vanguard\Mail\UserRegistered::class, 2);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function redirect_to_custom_page_after_login()
|
||||
{
|
||||
UserFactory::withCredentials('foo', 'bar')->create();
|
||||
|
||||
$this->post('/login', [
|
||||
'username' => 'foo',
|
||||
'password' => 'bar',
|
||||
'to' => 'http://www.google.com'
|
||||
])->assertRedirect('http://www.google.com');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function custom_redirect_page_is_available_after_failed_login_attempt()
|
||||
{
|
||||
$to = 'http://www.google.com';
|
||||
|
||||
$this->post('/login', [
|
||||
'username' => 'foo',
|
||||
'password' => 'bar',
|
||||
'to' => 'http://www.google.com'
|
||||
])->assertRedirect('login?to=' . $to);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function access_to_auth_pages_is_not_allowed_for_authenticated_users()
|
||||
{
|
||||
$this->setSettings([
|
||||
'reg_enabled' => true,
|
||||
'2fa.enabled' => true,
|
||||
'forgot_password' => true
|
||||
]);
|
||||
|
||||
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
||||
$this->be($user);
|
||||
|
||||
$forbiddenGetRoutes = [
|
||||
'login', 'register', 'password/reset', 'password/reset/123',
|
||||
'auth/facebook/login', 'auth/facebook/callback',
|
||||
];
|
||||
|
||||
foreach ($forbiddenGetRoutes as $route) {
|
||||
$this->get($route)->assertRedirect('/');
|
||||
}
|
||||
|
||||
$this->get('auth/two-factor-authentication')->assertRedirect("/login");
|
||||
}
|
||||
|
||||
private function getRegistrationFormStubData()
|
||||
{
|
||||
return [
|
||||
'email' => 'test@test.com',
|
||||
'username' => 'johndoe',
|
||||
'password' => '123123123',
|
||||
'password_confirmation' => '123123123',
|
||||
'tos' => 1
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web;
|
||||
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Facades\Tests\Setup\RoleFactory;
|
||||
use Illuminate\Auth\Middleware\EnsureEmailIsVerified;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
use Vanguard\Role;
|
||||
|
||||
class RolesTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function guests_cannot_view_role_list()
|
||||
{
|
||||
$this->get('/roles')->assertRedirect('/login');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permission_cannot_view_role_list()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('roles.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$this->actingAs($userA)->get('/roles')->assertStatus(403);
|
||||
$this->actingAs($userB)->get('/roles')->assertOk();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function roles_list_is_displayed_properly()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::create();
|
||||
|
||||
$roles = $this->actingAsAdmin()->get('/roles')->viewData('roles');
|
||||
|
||||
$this->assertCount(4, $roles); // 2 default roles are created when db is seeded
|
||||
$this->assertTrue($roles->contains($roleA));
|
||||
$this->assertTrue($roles->contains($roleB));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function create_role()
|
||||
{
|
||||
$data = Role::factory()->raw();
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->post('/roles', $data)
|
||||
->assertRedirect('/roles');
|
||||
|
||||
$this->assertSessionHasSuccess('Role created successfully.');
|
||||
$this->assertDatabaseHas('roles', $data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permission_cannot_create_new_roles()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('roles.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$data = Role::factory()->raw();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->post('/roles', $data)
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertDatabaseMissing('roles', $data);
|
||||
|
||||
$this->actingAs($userB)
|
||||
->post('/roles', $data)
|
||||
->assertRedirect('roles');
|
||||
|
||||
$this->assertDatabaseHas('roles', $data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_role()
|
||||
{
|
||||
$role = Role::factory()->create(['name' => 'foo']);
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->get("roles/{$role->id}/edit")
|
||||
->assertOk()
|
||||
->assertSee($role->name)
|
||||
->assertSee($role->display_name)
|
||||
->assertSee($role->description);
|
||||
|
||||
$data = Role::factory()->raw();
|
||||
|
||||
$this->put("/roles/{$role->id}", $data);
|
||||
|
||||
$this->assertSessionHasSuccess('Role updated successfully.');
|
||||
$this->assertDatabaseHas('roles', $data + ['id' => $role->id]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permission_cannot_update_role()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('roles.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$role = Role::factory()->create(['name' => 'foo']);
|
||||
|
||||
$data = Role::factory()->raw();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->put("/roles/{$role->id}", $data)
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertEquals($role->toArray(), $role->fresh()->toArray());
|
||||
|
||||
$this->actingAs($userB)
|
||||
->put("/roles/{$role->id}", $data)
|
||||
->assertRedirect('roles');
|
||||
|
||||
$role->refresh();
|
||||
|
||||
$this->assertEquals($role->name, $data['name']);
|
||||
$this->assertEquals($role->display_name, $data['display_name']);
|
||||
$this->assertEquals($role->description, $data['description']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function removable_attribute_cannot_be_changed_on_update()
|
||||
{
|
||||
$role = RoleFactory::unremovable()->create();
|
||||
|
||||
$data = Role::factory()->raw(['removable' => true]);
|
||||
|
||||
$this->actingAsAdmin()->put("/roles/{$role->id}", $data);
|
||||
|
||||
$role->refresh();
|
||||
|
||||
$this->assertEquals($role->name, $data['name']);
|
||||
$this->assertEquals($role->display_name, $data['display_name']);
|
||||
$this->assertEquals($role->description, $data['description']);
|
||||
$this->assertFalse($role->removable);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function delete_role()
|
||||
{
|
||||
$role = RoleFactory::removable()->create();
|
||||
|
||||
$this->actingAsAdmin()->delete(route('roles.destroy', $role));
|
||||
|
||||
$this->assertNull($role->fresh());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permission_cannot_delete_role()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('roles.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$role = Role::factory()->create(['name' => 'foo']);
|
||||
|
||||
$this->actingAs($userA)
|
||||
->delete(route('roles.destroy', $role->id))
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertNotNull($role->fresh());
|
||||
|
||||
$this->actingAs($userB)
|
||||
->delete(route('roles.destroy', $role->id))
|
||||
->assertRedirect('roles');
|
||||
|
||||
$this->assertNull($role->fresh());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_receive_default_role_after_their_role_is_deleted()
|
||||
{
|
||||
$user = UserFactory::create();
|
||||
$role = Role::factory()->create(['removable' => true]);
|
||||
$userRole = Role::where('name', 'User')->first();
|
||||
|
||||
$user->setRole($role);
|
||||
|
||||
$this->assertTrue($user->fresh()->hasRole($role->name));
|
||||
|
||||
$this->actingAsAdmin()->delete(route('roles.destroy', $role));
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'role_id' => $userRole->id,
|
||||
'id' => $user->id
|
||||
]);
|
||||
|
||||
$user = $user->fresh();
|
||||
|
||||
$this->assertFalse($user->hasRole($role->name));
|
||||
$this->assertTrue($user->hasRole($userRole->name));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_removable_roles_can_be_deleted()
|
||||
{
|
||||
$removableRole = Role::factory()->create(['removable' => true]);
|
||||
$nonRemovableRole = Role::factory()->create(['removable' => false]);
|
||||
|
||||
$this->beAdmin();
|
||||
|
||||
$this->delete(route('roles.destroy', $removableRole->id));
|
||||
|
||||
$this->assertNull($removableRole->fresh());
|
||||
|
||||
$this->delete(route('roles.destroy', $nonRemovableRole->id))
|
||||
->assertStatus(404);
|
||||
|
||||
$this->assertNotNull($nonRemovableRole->fresh());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web\Settings;
|
||||
|
||||
use Facades\Tests\Setup\RoleFactory;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Setting;
|
||||
use Tests\TestCase;
|
||||
|
||||
class AuthSettingsTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_auth_settings()
|
||||
{
|
||||
Setting::set('app_name', 'bar');
|
||||
|
||||
$data = $this->getAuthSettingsData();
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from('/settings/auth')
|
||||
->post('/settings/auth', $data)
|
||||
->assertRedirect('/settings/auth');
|
||||
|
||||
$this->assertAuthSettingsUpdated($data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_users_with_appropriate_permission_can_update_auth_settings()
|
||||
{
|
||||
Setting::set('app_name', 'bar');
|
||||
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('settings.auth')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$data = $this->getAuthSettingsData();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->from('/settings/auth')
|
||||
->post('/settings/auth', $data)
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertAuthSettingsNotUpdated($data);
|
||||
|
||||
$this->actingAs($userB)
|
||||
->from('/settings/auth')
|
||||
->post('/settings/auth', $data)
|
||||
->assertRedirect('/settings/auth');
|
||||
|
||||
$this->assertAuthSettingsUpdated($data);
|
||||
}
|
||||
|
||||
private function assertAuthSettingsUpdated(array $data)
|
||||
{
|
||||
$this->assertEquals($data['remember_me'], Setting::get('remember_me'));
|
||||
$this->assertEquals($data['forgot_password'], Setting::get('forgot_password'));
|
||||
$this->assertEquals($data['login_reset_token_lifetime'], Setting::get('login_reset_token_lifetime'));
|
||||
$this->assertEquals($data['throttle_enabled'], Setting::get('throttle_enabled'));
|
||||
$this->assertEquals($data['throttle_attempts'], Setting::get('throttle_attempts'));
|
||||
$this->assertEquals($data['throttle_lockout_time'], Setting::get('throttle_lockout_time'));
|
||||
$this->assertEquals($data['reg_enabled'], Setting::get('reg_enabled'));
|
||||
$this->assertEquals($data['tos'], Setting::get('tos'));
|
||||
$this->assertEquals($data['reg_email_confirmation'], Setting::get('reg_email_confirmation'));
|
||||
}
|
||||
|
||||
private function assertAuthSettingsNotUpdated(array $data)
|
||||
{
|
||||
$this->assertNotEquals($data['remember_me'], Setting::get('remember_me'));
|
||||
$this->assertNotEquals($data['forgot_password'], Setting::get('forgot_password'));
|
||||
$this->assertNotEquals($data['login_reset_token_lifetime'], Setting::get('login_reset_token_lifetime'));
|
||||
$this->assertNotEquals($data['throttle_enabled'], Setting::get('throttle_enabled'));
|
||||
$this->assertNotEquals($data['throttle_attempts'], Setting::get('throttle_attempts'));
|
||||
$this->assertNotEquals($data['throttle_lockout_time'], Setting::get('throttle_lockout_time'));
|
||||
$this->assertNotEquals($data['reg_enabled'], Setting::get('reg_enabled'));
|
||||
$this->assertNotEquals($data['tos'], Setting::get('tos'));
|
||||
$this->assertNotEquals($data['reg_email_confirmation'], Setting::get('reg_email_confirmation'));
|
||||
}
|
||||
|
||||
private function getAuthSettingsData()
|
||||
{
|
||||
return [
|
||||
'remember_me' => 1,
|
||||
'forgot_password' => 1,
|
||||
'login_reset_token_lifetime' => 123,
|
||||
'throttle_enabled' => 1,
|
||||
'throttle_attempts' => 10,
|
||||
'throttle_lockout_time' => 2,
|
||||
'reg_enabled' => 1,
|
||||
'tos' => 1,
|
||||
'reg_email_confirmation' => 1
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web\Settings;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Setting;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CaptchaSettingsTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function enable_captcha()
|
||||
{
|
||||
Setting::set('registration.captcha.enabled', false);
|
||||
|
||||
$this->assertFalse(Setting::get('registration.captcha.enabled'));
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from('/settings/auth')
|
||||
->post('/settings/auth/registration/captcha/enable')
|
||||
->assertRedirect('/settings/auth');
|
||||
|
||||
$this->assertTrue(Setting::get('registration.captcha.enabled'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function disable_two_factor()
|
||||
{
|
||||
Setting::set('registration.captcha.enabled', true);
|
||||
|
||||
$this->assertTrue(Setting::get('registration.captcha.enabled'));
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from('/settings/auth')
|
||||
->post('/settings/auth/registration/captcha/disable')
|
||||
->assertRedirect('/settings/auth');
|
||||
|
||||
$this->assertFalse(Setting::get('registration.captcha.enabled'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web\Settings;
|
||||
|
||||
use Facades\Tests\Setup\RoleFactory;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Setting;
|
||||
use Tests\TestCase;
|
||||
|
||||
class GeneralSettingsTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_general_settings()
|
||||
{
|
||||
Setting::set('app_name', 'bar');
|
||||
|
||||
$this->assertEquals('bar', Setting::get('app_name'));
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from('/settings/general')
|
||||
->post('/settings/general', ['app_name' => 'foo'])
|
||||
->assertRedirect('/settings/general');
|
||||
|
||||
$this->assertEquals('foo', Setting::get('app_name'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_users_with_appropriate_permission_can_update_general_settings()
|
||||
{
|
||||
Setting::set('app_name', 'bar');
|
||||
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('settings.general')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->from('/settings/general')
|
||||
->post('/settings/general', ['app_name' => 'foo'])
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertEquals('bar', Setting::get('app_name'));
|
||||
|
||||
$this->actingAs($userB)
|
||||
->from('/settings/general')
|
||||
->post('/settings/general', ['app_name' => 'foo'])
|
||||
->assertRedirect('/settings/general');
|
||||
|
||||
$this->assertEquals('foo', Setting::get('app_name'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web\Settings;
|
||||
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Setting;
|
||||
use Tests\TestCase;
|
||||
|
||||
class TwoFactorSettingsTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function enable_two_factor()
|
||||
{
|
||||
Setting::set('2fa.enabled', false);
|
||||
|
||||
$this->assertFalse(Setting::get('2fa.enabled'));
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from('/settings/auth')
|
||||
->post('/settings/auth/2fa/enable')
|
||||
->assertRedirect('/settings/auth');
|
||||
|
||||
$this->assertTrue(Setting::get('2fa.enabled'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function disable_two_factor()
|
||||
{
|
||||
Setting::set('2fa.enabled', true);
|
||||
|
||||
$this->assertTrue(Setting::get('2fa.enabled'));
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from('/settings/auth')
|
||||
->post('/settings/auth/2fa/disable')
|
||||
->assertRedirect('/settings/auth');
|
||||
|
||||
$this->assertFalse(Setting::get('2fa.enabled'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web;
|
||||
|
||||
use Facades\Tests\Setup\RoleFactory;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Setting;
|
||||
use Tests\TestCase;
|
||||
|
||||
class SettingsTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_general_settings()
|
||||
{
|
||||
Setting::set('app_name', 'bar');
|
||||
|
||||
$this->assertEquals('bar', Setting::get('app_name'));
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from('/settings/general')
|
||||
->post('/settings/general', ['app_name' => 'foo'])
|
||||
->assertRedirect('/settings/general');
|
||||
|
||||
$this->assertEquals('foo', Setting::get('app_name'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_users_with_appropriate_permission_can_update_general_settings()
|
||||
{
|
||||
Setting::set('app_name', 'bar');
|
||||
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('settings.general')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->from('/settings/general')
|
||||
->post('/settings/general', ['app_name' => 'foo'])
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertEquals('bar', Setting::get('app_name'));
|
||||
|
||||
$this->actingAs($userB)
|
||||
->from('/settings/general')
|
||||
->post('/settings/general', ['app_name' => 'foo'])
|
||||
->assertRedirect('/settings/general');
|
||||
|
||||
$this->assertEquals('foo', Setting::get('app_name'));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_auth_settings()
|
||||
{
|
||||
Setting::set('app_name', 'bar');
|
||||
|
||||
$data = $this->getAuthSettingsData();
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from('/settings/auth')
|
||||
->post('/settings/auth', $data)
|
||||
->assertRedirect('/settings/auth');
|
||||
|
||||
$this->assertAuthSettingsUpdated($data);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_users_with_appropriate_permission_can_update_auth_settings()
|
||||
{
|
||||
Setting::set('app_name', 'bar');
|
||||
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('settings.auth')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$data = $this->getAuthSettingsData();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->from('/settings/auth')
|
||||
->post('/settings/auth', $data)
|
||||
->assertStatus(403);
|
||||
|
||||
$this->assertAuthSettingsNotUpdated($data);
|
||||
|
||||
$this->actingAs($userB)
|
||||
->from('/settings/auth')
|
||||
->post('/settings/auth', $data)
|
||||
->assertRedirect('/settings/auth');
|
||||
|
||||
$this->assertAuthSettingsUpdated($data);
|
||||
}
|
||||
|
||||
private function assertAuthSettingsUpdated(array $data)
|
||||
{
|
||||
$this->assertEquals($data['remember_me'], Setting::get('remember_me'));
|
||||
$this->assertEquals($data['forgot_password'], Setting::get('forgot_password'));
|
||||
$this->assertEquals($data['login_reset_token_lifetime'], Setting::get('login_reset_token_lifetime'));
|
||||
$this->assertEquals($data['throttle_enabled'], Setting::get('throttle_enabled'));
|
||||
$this->assertEquals($data['throttle_attempts'], Setting::get('throttle_attempts'));
|
||||
$this->assertEquals($data['throttle_lockout_time'], Setting::get('throttle_lockout_time'));
|
||||
}
|
||||
|
||||
private function assertAuthSettingsNotUpdated(array $data)
|
||||
{
|
||||
$this->assertNotEquals($data['remember_me'], Setting::get('remember_me'));
|
||||
$this->assertNotEquals($data['forgot_password'], Setting::get('forgot_password'));
|
||||
$this->assertNotEquals($data['login_reset_token_lifetime'], Setting::get('login_reset_token_lifetime'));
|
||||
$this->assertNotEquals($data['throttle_enabled'], Setting::get('throttle_enabled'));
|
||||
$this->assertNotEquals($data['throttle_attempts'], Setting::get('throttle_attempts'));
|
||||
$this->assertNotEquals($data['throttle_lockout_time'], Setting::get('throttle_lockout_time'));
|
||||
}
|
||||
|
||||
private function getAuthSettingsData()
|
||||
{
|
||||
return [
|
||||
'remember_me' => 1,
|
||||
'forgot_password' => 1,
|
||||
'login_reset_token_lifetime' => 123,
|
||||
'throttle_enabled' => 1,
|
||||
'throttle_attempts' => 10,
|
||||
'throttle_lockout_time' => 2,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web;
|
||||
|
||||
use Auth;
|
||||
use DB;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Laravel\Socialite\Contracts\Provider as SocialiteProvider;
|
||||
use Socialite;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Tests\TestCase;
|
||||
use Tests\UpdatesSettings;
|
||||
use Vanguard\Support\Enum\UserStatus;
|
||||
use Vanguard\User;
|
||||
use Laravel\Socialite\Contracts\User as SocialUserContract;
|
||||
use Mockery as m;
|
||||
|
||||
class SocialAuthenticationTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, UpdatesSettings;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function social_login_for_new_user()
|
||||
{
|
||||
$this->setSettings(['reg_enabled' => true]);
|
||||
|
||||
$socialUser = new StubSocialUser;
|
||||
|
||||
$driver = m::mock(SocialiteProvider::class);
|
||||
$driver->shouldReceive('user')->andReturn($socialUser);
|
||||
|
||||
Socialite::shouldReceive('driver')->with('foo')->andReturn($driver);
|
||||
|
||||
$this->get("auth/foo/callback");
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'username' => null,
|
||||
'email' => $socialUser->getEmail(),
|
||||
'first_name' => 'John',
|
||||
'last_name' => 'Doe',
|
||||
'status' => UserStatus::ACTIVE,
|
||||
'email_verified_at' => now(),
|
||||
]);
|
||||
|
||||
$user = User::where('email', $socialUser->getEmail())->first();
|
||||
|
||||
$this->assertDatabaseHas('social_logins', [
|
||||
'user_id' => $user->id,
|
||||
'provider' => 'foo',
|
||||
'provider_id' => $socialUser->getId(),
|
||||
'avatar' => $socialUser->getAvatar()
|
||||
]);
|
||||
|
||||
$this->assertEquals($user->id, Auth::id());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function social_login_for_new_user_if_registration_is_disabled()
|
||||
{
|
||||
$this->setSettings(['reg_enabled' => false]);
|
||||
|
||||
$socialUser = new StubSocialUser;
|
||||
|
||||
$driver = m::mock(SocialiteProvider::class);
|
||||
$driver->shouldReceive('user')->andReturn($socialUser);
|
||||
|
||||
Socialite::shouldReceive('driver')->with('foo')->andReturn($driver);
|
||||
|
||||
$this->get("auth/foo/callback")
|
||||
->assertRedirect('/login');
|
||||
|
||||
$this->assertSessionHasError('Only users who already created an account can log in.');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function social_login_for_banned_user()
|
||||
{
|
||||
$user = UserFactory::banned()->create();
|
||||
$socialUser = new StubSocialUser;
|
||||
|
||||
$driver = m::mock(SocialiteProvider::class);
|
||||
$driver->shouldReceive('user')->andReturn($socialUser);
|
||||
|
||||
Socialite::shouldReceive('driver')->with('foo')->andReturn($driver);
|
||||
|
||||
DB::table('social_logins')->insert([
|
||||
'user_id' => $user->id,
|
||||
'provider' => 'foo',
|
||||
'provider_id' => $socialUser->getId(),
|
||||
'avatar' => $socialUser->getAvatar(),
|
||||
'created_at' => \Carbon\Carbon::now()
|
||||
]);
|
||||
|
||||
$this->get("auth/foo/callback")
|
||||
->assertRedirect('/login');
|
||||
|
||||
$this->assertSessionHasError('Your account is banned by administrator.');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function social_login_for_existing_user()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
$socialUser = new StubSocialUser;
|
||||
|
||||
$driver = m::mock(SocialiteProvider::class);
|
||||
$driver->shouldReceive('user')->andReturn($socialUser);
|
||||
|
||||
Socialite::shouldReceive('driver')->with('foo')->andReturn($driver);
|
||||
|
||||
DB::table('social_logins')->insert([
|
||||
'user_id' => $user->id,
|
||||
'provider' => 'foo',
|
||||
'provider_id' => $socialUser->getId(),
|
||||
'avatar' => $socialUser->getAvatar(),
|
||||
'created_at' => \Carbon\Carbon::now()
|
||||
]);
|
||||
|
||||
$this->get("auth/foo/callback")
|
||||
->assertRedirect('/');
|
||||
|
||||
$this->assertEquals($user->id, Auth::id());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function missing_email_login()
|
||||
{
|
||||
$this->setSettings(['reg_enabled' => true]);
|
||||
|
||||
$socialUser = new StubSocialUserWithoutEmail;
|
||||
$driver = m::mock(SocialiteProvider::class);
|
||||
$driver->shouldReceive('user')->andReturn($socialUser);
|
||||
Socialite::shouldReceive('driver')->with('foo')->andReturn($driver);
|
||||
|
||||
$this->get("auth/foo/callback")
|
||||
->assertRedirect('login');
|
||||
|
||||
$this->assertSessionHasError("You have to provide your email address.");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function social_login_for_user_with_one_word_name()
|
||||
{
|
||||
$this->setSettings(['reg_enabled' => true]);
|
||||
|
||||
$socialUser = new StubSocialUserWithOneWordName;
|
||||
|
||||
$driver = m::mock(SocialiteProvider::class);
|
||||
$driver->shouldReceive('user')->andReturn($socialUser);
|
||||
|
||||
Socialite::shouldReceive('driver')->with('foo')->andReturn($driver);
|
||||
|
||||
$this->get("auth/foo/callback")
|
||||
->assertRedirect('/');
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'username' => null,
|
||||
'email' => $socialUser->getEmail(),
|
||||
'first_name' => 'John',
|
||||
'last_name' => '',
|
||||
'status' => UserStatus::ACTIVE
|
||||
]);
|
||||
|
||||
$user = User::where('email', $socialUser->getEmail())->first();
|
||||
|
||||
$this->assertDatabaseHas('social_logins', [
|
||||
'user_id' => $user->id,
|
||||
'provider' => 'foo',
|
||||
'provider_id' => $socialUser->getId(),
|
||||
'avatar' => $socialUser->getAvatar()
|
||||
]);
|
||||
|
||||
$this->assertEquals($user->id, Auth::id());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class StubSocialUser implements SocialUserContract
|
||||
{
|
||||
public function getId()
|
||||
{
|
||||
return '123';
|
||||
}
|
||||
|
||||
public function getNickname()
|
||||
{
|
||||
return 'johndoe';
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'John Doe';
|
||||
}
|
||||
|
||||
public function getEmail()
|
||||
{
|
||||
return 'john@doe.com';
|
||||
}
|
||||
|
||||
public function getAvatar()
|
||||
{
|
||||
return 'http://www.gravatar.com/avatar';
|
||||
}
|
||||
}
|
||||
|
||||
class StubSocialUserWithoutEmail extends StubSocialUser
|
||||
{
|
||||
public $email = null;
|
||||
|
||||
public function getEmail()
|
||||
{
|
||||
return $this->email;
|
||||
}
|
||||
}
|
||||
|
||||
class StubSocialUserWithOneWordName extends StubSocialUser
|
||||
{
|
||||
public function getName()
|
||||
{
|
||||
return 'John';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,438 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web;
|
||||
|
||||
use Authy;
|
||||
use Event;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
use Tests\UpdatesSettings;
|
||||
use Vanguard\Events\User\TwoFactorEnabled;
|
||||
use Vanguard\Events\User\TwoFactorEnabledByAdmin;
|
||||
use Vanguard\Repositories\User\UserRepository;
|
||||
use Vanguard\User;
|
||||
|
||||
class TwoFactorAuthTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, UpdatesSettings;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_2fa_form_is_visible_on_profile_page_if_2fa_is_enabled()
|
||||
{
|
||||
config(['services.authy.key' => 'test']);
|
||||
|
||||
$this->setSettings(['2fa.enabled' => false]);
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->get("profile")
|
||||
->assertDontSee('Two-Factor Authentication');
|
||||
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->get("profile")
|
||||
->assertSee('Two-Factor Authentication');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_2fa_form_is_visible_on_edit_user_page_if_2fa_is_enabled()
|
||||
{
|
||||
config(['services.authy.key' => 'test']);
|
||||
|
||||
$this->setSettings(['2fa.enabled' => false]);
|
||||
|
||||
$user = UserFactory::create();
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->get("/users/{$user->id}/edit")
|
||||
->assertDontSee('Two-Factor Authentication');
|
||||
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->get("/users/{$user->id}/edit")
|
||||
->assertSee('Two-Factor Authentication');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function enable_2fa_from_profile_page()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = UserFactory::user()->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('register')->andReturnNull();
|
||||
Authy::shouldReceive('sendTwoFactorVerificationToken')->andReturnNull();
|
||||
|
||||
$this->actingAs($user)
|
||||
->post('/two-factor/enable', ['country_code' => '1', 'phone_number' => '123'])
|
||||
->assertRedirect('/two-factor/verification');
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_country_code' => 1,
|
||||
'two_factor_phone' => 123
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function enable_2fa_from_edit_user_page()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('register')->andReturnNull();
|
||||
Authy::shouldReceive('sendTwoFactorVerificationToken')->andReturnNull();
|
||||
|
||||
$user = UserFactory::user()->create();
|
||||
$formData = ['country_code' => '1', 'phone_number' => '123', 'user' => $user->id];
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->post("users/{$user->id}/two-factor/enable", $formData)
|
||||
->assertRedirect("two-factor/verification?user={$user->id}");
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_country_code' => 1,
|
||||
'two_factor_phone' => 123
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permissions_cannot_enable_2fa_for_other_users()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->be(UserFactory::user()->create());
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('register')->andReturnNull();
|
||||
Authy::shouldReceive('sendTwoFactorVerificationToken')->andReturnNull();
|
||||
|
||||
$user = UserFactory::user()->create();
|
||||
|
||||
$this->post('two-factor/enable', [
|
||||
'user' => $user->id,
|
||||
'country_code' => '1',
|
||||
'phone_number' => '123'
|
||||
])->assertStatus(403);
|
||||
|
||||
$this->assertDatabaseMissing('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_country_code' => 1,
|
||||
'two_factor_phone' => 123
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function phone_verification_page_is_not_accessible_if_2fa_is_disabled_on_global_level()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => false]);
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->get("two-factor/verification")
|
||||
->assertNotFound();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function phone_verification_page_is_not_accessible_if_user_phone_is_not_set()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user1 = UserFactory::user()->twoFactor(null, null)->create();
|
||||
$user2 = UserFactory::user()->twoFactor(1, null)->create();
|
||||
$user3 = UserFactory::user()->twoFactor(null, '123456')->create();
|
||||
|
||||
$this->actingAs($user1)->get("two-factor/verification")->assertNotFound();
|
||||
$this->actingAs($user2)->get("two-factor/verification")->assertNotFound();
|
||||
$this->actingAs($user3)->get("two-factor/verification")->assertNotFound();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_who_have_already_enabled_2fa_cannot_view_the_phone_verification_page()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->be(UserFactory::user()->create());
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
|
||||
$this->get("two-factor/verification")->assertNotFound();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_who_have_already_enabled_2fa_cannot_submit_enable_2fa_form()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->be(UserFactory::user()->create());
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
|
||||
$this->post("two-factor/enable", ['country_code' => '1', 'phone_number' => '123'])
|
||||
->assertNotFound();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_who_have_already_enabled_2fa_cannot_submit_verification_form()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->be(UserFactory::user()->create());
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
|
||||
$this->post("two-factor/verify")->assertNotFound();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function token_field_is_required_during_2fa_phone_verification()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = UserFactory::user()->twoFactor('1', '123456')->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->post("two-factor/verify")
|
||||
->assertSessionHasErrors('token');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function the_2fa_verification_with_wrong_token_will_fail()
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = UserFactory::user()->twoFactor("1", "123123")->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('tokenIsValid')->with($user, "123123")->andReturn(false);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post("two-factor/verify", ['token' => '123123']);
|
||||
|
||||
$this->assertSessionHasError('Invalid 2FA token.');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function successful_2fa_phone_verification()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
Event::fake([
|
||||
TwoFactorEnabled::class,
|
||||
]);
|
||||
|
||||
$user = UserFactory::user()->twoFactor("1", "123123")->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('tokenIsValid')->with($user, '123123')->andReturn(true);
|
||||
|
||||
$this->actingAs($user)
|
||||
->post("two-factor/verify", ['token' => '123123'])
|
||||
->assertRedirect("/profile");
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_options' => '{"enabled":true}'
|
||||
]);
|
||||
|
||||
Event::assertDispatched(TwoFactorEnabled::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function successful_2fa_phone_verification_for_other_user()
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
Event::fake([
|
||||
TwoFactorEnabledByAdmin::class,
|
||||
]);
|
||||
|
||||
$user = UserFactory::user()->twoFactor("1", "123123")->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('tokenIsValid')->once()->andReturn(true);
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->post("two-factor/verify", ['token' => '123123', 'user' => $user->id])
|
||||
->assertRedirect("/users/{$user->id}/edit");
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_options' => '{"enabled":true}'
|
||||
]);
|
||||
|
||||
Event::assertDispatched(TwoFactorEnabledByAdmin::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_cannot_submit_phone_verification_form_if_phone_is_not_provided()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user1 = UserFactory::user()->twoFactor(null, null)->create();
|
||||
$user2 = UserFactory::user()->twoFactor(1, null)->create();
|
||||
$user3 = UserFactory::user()->twoFactor(null, '123456')->create();
|
||||
|
||||
$this->actingAs($user1)->post("two-factor/verify")->assertNotFound();
|
||||
$this->actingAs($user2)->post("two-factor/verify")->assertNotFound();
|
||||
$this->actingAs($user3)->post("two-factor/verify")->assertNotFound();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_can_request_a_new_sms_with_a_code_once_per_minute()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user = UserFactory::user()->twoFactor("1", "123123")->create();
|
||||
|
||||
$this->be($user);
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('sendTwoFactorVerificationToken')->once()->andReturn(false);
|
||||
|
||||
$this->post("/two-factor/resend");
|
||||
$this->post("/two-factor/resend");
|
||||
$this->post("/two-factor/resend");
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function only_user_with_appropriate_permissions_can_request_new_2fa_token_for_another_user()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->be(UserFactory::user()->create());
|
||||
|
||||
$user = UserFactory::user()->twoFactor("1", "123123")->create();
|
||||
|
||||
$this->post("/two-factor/resend", ['user' => $user->id])
|
||||
->assertStatus(403);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_can_request_a_new_sms_with_a_code_once_per_minute_while_enabling_2fa_for_other_user()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->beAdmin();
|
||||
|
||||
$user = UserFactory::user()->twoFactor("1", "123123")->create();
|
||||
|
||||
$repo = \Mockery::mock(UserRepository::class);
|
||||
$repo->shouldReceive('find')->with($user->id)->andReturn($user);
|
||||
$this->app->instance(UserRepository::class, $repo);
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(false);
|
||||
Authy::shouldReceive('sendTwoFactorVerificationToken')->once()->with($user)->andReturn(false);
|
||||
|
||||
$this->post("/two-factor/resend", ['user' => $user->id]);
|
||||
$this->post("/two-factor/resend", ['user' => $user->id]);
|
||||
$this->post("/two-factor/resend", ['user' => $user->id]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_cannot_request_new_codes_if_they_already_have_2fa_enabled()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->be(UserFactory::user()->create());
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
Authy::shouldReceive('sendTwoFactorVerificationToken')->never();
|
||||
|
||||
$this->post("/two-factor/resend")->assertNotFound();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_cannot_hit_resend_endpoint_if_phone_is_not_provided()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$user1 = UserFactory::user()->twoFactor(null, null)->create();
|
||||
$user2 = UserFactory::user()->twoFactor(1, null)->create();
|
||||
$user3 = UserFactory::user()->twoFactor(null, '123456')->create();
|
||||
|
||||
$this->actingAs($user1)->post("/two-factor/resend")->assertNotFound();
|
||||
$this->actingAs($user2)->post("/two-factor/resend")->assertNotFound();
|
||||
$this->actingAs($user3)->post("/two-factor/resend")->assertNotFound();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_can_disable_2fa()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->be(UserFactory::user()->create());
|
||||
|
||||
Event::fake([
|
||||
\Vanguard\Events\User\TwoFactorDisabled::class,
|
||||
]);
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
Authy::shouldReceive('delete')->andReturnNull();
|
||||
|
||||
$this->from('/profile')
|
||||
->post('two-factor/disable')
|
||||
->assertRedirect("/profile");
|
||||
|
||||
$this->assertSessionHasSuccess('Two-Factor Authentication disabled successfully.');
|
||||
|
||||
Event::assertDispatched(\Vanguard\Events\User\TwoFactorDisabled::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_can_disable_2fa_for_another_user()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
Event::fake([
|
||||
\Vanguard\Events\User\TwoFactorDisabled::class,
|
||||
]);
|
||||
|
||||
$this->beAdmin();
|
||||
|
||||
$user = UserFactory::user()->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
Authy::shouldReceive('delete')->andReturnNull();
|
||||
|
||||
$this->from("/users/{$user->id}/edit")
|
||||
->post("users/{$user->id}/two-factor/disable")
|
||||
->assertRedirect("/users/{$user->id}/edit");
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'id' => $user->id,
|
||||
'two_factor_country_code' => null,
|
||||
'two_factor_phone' => null
|
||||
]);
|
||||
|
||||
$this->assertSessionHasSuccess('Two-Factor Authentication disabled successfully.');
|
||||
Event::assertDispatched(\Vanguard\Events\User\TwoFactorDisabled::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_without_appropriate_permissions_cannot_disable_2fa_for_another_user()
|
||||
{
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->be(UserFactory::user()->create());
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
Authy::shouldReceive('isEnabled')->andReturn(true);
|
||||
|
||||
$this->post("two-factor/disable", ['user' => $user->id])->assertForbidden();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Event;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Hash;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Storage;
|
||||
use Tests\TestCase;
|
||||
use Vanguard\Events\User\ChangedAvatar;
|
||||
use Vanguard\Events\User\UpdatedProfileDetails;
|
||||
use Vanguard\Role;
|
||||
use Vanguard\Support\Enum\UserStatus;
|
||||
|
||||
class UpdateProfileTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->be(UserFactory::create());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_can_access_his_profile_page()
|
||||
{
|
||||
$this->get('/profile')->assertOk();
|
||||
}
|
||||
|
||||
/** @test
|
||||
*/
|
||||
public function user_can_update_his_profile_details()
|
||||
{
|
||||
Event::fake([
|
||||
UpdatedProfileDetails::class,
|
||||
]);
|
||||
|
||||
$data = $this->getStubDetailsData();
|
||||
|
||||
$this->from('/profile')
|
||||
->put('profile/details', $data)
|
||||
->assertRedirect('/profile');
|
||||
|
||||
$this->assertSessionHasSuccess('Profile updated successfully.');
|
||||
$this->assertDatabaseHas('users', $data + ['id' => auth()->id()]);
|
||||
|
||||
Event::assertDispatched(UpdatedProfileDetails::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_cannot_change_his_status_while_updating_the_profile()
|
||||
{
|
||||
$data = $this->getStubDetailsData();
|
||||
|
||||
$this->from('/profile')
|
||||
->put('profile/details', $data + ['status' => UserStatus::BANNED])
|
||||
->assertRedirect('/profile');
|
||||
|
||||
$this->assertSessionHasSuccess('Profile updated successfully.');
|
||||
$this->assertDatabaseHas('users', $data + [
|
||||
'id' => auth()->id(),
|
||||
'status' => UserStatus::ACTIVE,
|
||||
]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_cannot_change_his_role_while_updating_the_profile()
|
||||
{
|
||||
$data = $this->getStubDetailsData();
|
||||
|
||||
$role = Role::factory()->create();
|
||||
|
||||
$this->from('/profile')
|
||||
->put('profile/details', $data + ['role_id' => $role])
|
||||
->assertRedirect('/profile');
|
||||
|
||||
$this->assertSessionHasSuccess('Profile updated successfully.');
|
||||
|
||||
$this->assertNotEquals($role->id, auth()->user()->role_id);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_avatar()
|
||||
{
|
||||
Event::fake([
|
||||
ChangedAvatar::class,
|
||||
]);
|
||||
|
||||
Storage::fake('public');
|
||||
|
||||
$data = [
|
||||
'avatar' => UploadedFile::fake()->image('photo1.jpg', 300, 300),
|
||||
'points' => [
|
||||
'x1' => 0,
|
||||
'y1' => 0,
|
||||
'x2' => 200,
|
||||
'y2' => 200
|
||||
]
|
||||
];
|
||||
|
||||
$this->from('profile')
|
||||
->post('/profile/avatar', $data)
|
||||
->assertRedirect('profile');
|
||||
|
||||
$this->assertSessionHasSuccess('Avatar changed successfully.');
|
||||
|
||||
$user = auth()->user()->fresh();
|
||||
|
||||
$this->assertNotNull($user->avatar);
|
||||
Storage::disk('public')->assertExists("upload/users/{$user->avatar}");
|
||||
|
||||
list($width, $height) = getimagesizefromstring(
|
||||
Storage::disk('public')->get("upload/users/{$user->avatar}")
|
||||
);
|
||||
|
||||
$this->assertEquals(160, $width);
|
||||
$this->assertEquals(160, $height);
|
||||
|
||||
Event::assertDispatched(ChangedAvatar::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_avatar_with_invalid_image_file()
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$data = [
|
||||
'avatar' => UploadedFile::fake()->create('foo.txt', 123),
|
||||
'points' => [
|
||||
'x1' => 0,
|
||||
'y1' => 0,
|
||||
'x2' => 200,
|
||||
'y2' => 200
|
||||
]
|
||||
];
|
||||
|
||||
$this->from('profile')
|
||||
->post('/profile/avatar', $data)
|
||||
->assertRedirect('profile')
|
||||
->assertSessionHasErrors('avatar');
|
||||
|
||||
$user = auth()->user()->fresh();
|
||||
|
||||
Storage::disk('public')->assertMissing("upload/users/{$user->avatar}");
|
||||
$this->assertNull($user->avatar);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_avatar_external()
|
||||
{
|
||||
Event::fake([
|
||||
ChangedAvatar::class,
|
||||
]);
|
||||
|
||||
$data = ['url' => '//www.gravatar.com/avatar'];
|
||||
$this->post(route('profile.update.avatar-external', auth()->id()), $data)
|
||||
->assertRedirect();
|
||||
|
||||
$this->assertSessionHasSuccess('Avatar changed successfully.');
|
||||
|
||||
$this->assertEquals($data['url'], auth()->user()->fresh()->avatar);
|
||||
|
||||
Event::assertDispatched(ChangedAvatar::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_user_login_details()
|
||||
{
|
||||
$data = [
|
||||
'email' => 'john@doe.com',
|
||||
'username' => 'milos',
|
||||
'password' => 'milos123123',
|
||||
'password_confirmation' => 'milos123123'
|
||||
];
|
||||
|
||||
$this->from('/profile')
|
||||
->put('profile/login-details', $data)
|
||||
->assertRedirect('/profile');
|
||||
|
||||
$this->assertSessionHasSuccess('Login details updated successfully.');
|
||||
|
||||
$user = auth()->user()->fresh();
|
||||
|
||||
$this->assertEquals($data['email'], $user->email);
|
||||
$this->assertEquals($data['username'], $user->username);
|
||||
$this->assertTrue(Hash::check($data['password'], $user->password));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function password_is_not_changed_if_omited_on_update()
|
||||
{
|
||||
auth()->user()->update([
|
||||
'email' => 'john@example.com',
|
||||
'password' => '123123'
|
||||
]);
|
||||
|
||||
$data = [
|
||||
'email' => 'test@test.com',
|
||||
'password' => '',
|
||||
'password_confirmation' => ''
|
||||
];
|
||||
|
||||
$this->from('/profile')
|
||||
->put('profile/login-details', $data)
|
||||
->assertRedirect('/profile');
|
||||
|
||||
$user = auth()->user()->fresh();
|
||||
|
||||
$this->assertEquals($data['email'], $user->email);
|
||||
$this->assertTrue(Hash::check('123123', $user->password));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_session_invalidation()
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
config(['session.driver' => 'database']);
|
||||
|
||||
$user = UserFactory::withCredentials('foo', 'bar')->create();
|
||||
|
||||
$this->be($user);
|
||||
|
||||
$agent = $this->app['agent'];
|
||||
$device = $agent->device() ?: 'Unknown';
|
||||
$platform = $agent->platform() ?: 'Unknown';
|
||||
|
||||
// Log-in manually to actually create session record in DB
|
||||
$this->post('/login', ['username' => 'foo', 'password' => 'bar']);
|
||||
|
||||
$this->get('/profile/sessions')
|
||||
->assertSee('127.0.0.1')
|
||||
->assertSee($device)
|
||||
->assertSee($platform)
|
||||
->assertSee($agent->browser());
|
||||
|
||||
$sessionId = \DB::table('sessions')->where('user_id', $user->id)->first()->id;
|
||||
$this->delete("profile/sessions/{$sessionId}/invalidate");
|
||||
|
||||
$this->assertDatabaseMissing('sessions', ['user_id' => $user->id]);
|
||||
}
|
||||
|
||||
private function getStubDetailsData(): array
|
||||
{
|
||||
return [
|
||||
'first_name' => 'foo',
|
||||
'last_name' => 'bar',
|
||||
'birthday' => Carbon::now()->subYears(25)->format('Y-m-d'),
|
||||
'phone' => '12345667',
|
||||
'address' => 'the address',
|
||||
'country_id' => 688 //Serbia,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,710 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Web;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Event;
|
||||
use Facades\Tests\Setup\RoleFactory;
|
||||
use Facades\Tests\Setup\UserFactory;
|
||||
use Hash;
|
||||
use Illuminate\Contracts\Pagination\Paginator;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Str;
|
||||
use Storage;
|
||||
use Tests\TestCase;
|
||||
use Tests\UpdatesSettings;
|
||||
use Vanguard\Events\User\UpdatedByAdmin;
|
||||
use Vanguard\Role;
|
||||
use Vanguard\Support\Enum\UserStatus;
|
||||
use Vanguard\User;
|
||||
|
||||
class UsersTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, UpdatesSettings;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->artisan('db:seed', ['--class' => 'RolesSeeder']);
|
||||
$this->artisan('db:seed', ['--class' => 'PermissionsSeeder']);
|
||||
$this->artisan('db:seed', ['--class' => 'CountriesSeeder']);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function guests_cannot_view_the_user_list_page()
|
||||
{
|
||||
$this->get('/users')->assertRedirect('/login');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permission_cannot_view_user_list_page()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$this->actingAs($userA)->get('/users')->assertForbidden();
|
||||
$this->actingAs($userB)->get('/users')->assertOk();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_collection_is_being_properly_passed_to_the_view()
|
||||
{
|
||||
$admin = UserFactory::admin()->create();
|
||||
$active = UserFactory::user()->create();
|
||||
$banned = UserFactory::user()->banned()->create();
|
||||
$unconfirmed = UserFactory::user()->unconfirmed()->create();
|
||||
|
||||
$users = $this->actingAs($admin)->get('users')->viewData('users');
|
||||
|
||||
$this->assertCount(4, $users);
|
||||
$this->assertTrue($users->contains($admin));
|
||||
$this->assertTrue($users->contains($active));
|
||||
$this->assertTrue($users->contains($banned));
|
||||
$this->assertTrue($users->contains($unconfirmed));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_list_is_paginated()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$users = $this->get('users')->viewData('users');
|
||||
|
||||
$this->assertInstanceOf(Paginator::class, $users);
|
||||
$this->assertCount(1, $users->items());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_can_be_filtered_out_by_search_term()
|
||||
{
|
||||
$user1 = User::factory()->create(['first_name' => 'Milos', 'last_name' => 'Stojanovic']);
|
||||
$user2 = User::factory()->create(['first_name' => 'John', 'last_name' => 'Doe']);
|
||||
$user3 = User::factory()->create(['first_name' => 'Jane', 'last_name' => 'Doe']);
|
||||
|
||||
$users = $this->actingAsAdmin()->get('users?search=doe')->viewData('users');
|
||||
|
||||
$this->assertCount(2, $users);
|
||||
$this->assertTrue($users->contains($user3));
|
||||
$this->assertTrue($users->contains($user2));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_can_be_filtered_out_by_status()
|
||||
{
|
||||
User::factory()->times(2)->create();
|
||||
User::factory()->times(3)->create(['status' => UserStatus::UNCONFIRMED]);
|
||||
|
||||
$users = $this->actingAsAdmin()
|
||||
->get('users?status=' . UserStatus::BANNED)
|
||||
->viewData('users');
|
||||
|
||||
$this->assertCount(0, $users);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function admin_can_successfully_create_new_users()
|
||||
{
|
||||
$data = $this->validParams();
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users');
|
||||
|
||||
$this->assertSessionHasSuccess('User created successfully.');
|
||||
|
||||
$user = User::where('email', $data['email'])->first();
|
||||
|
||||
$this->assertDatabaseHas('users', Arr::except($data, ['password', 'password_confirmation']));
|
||||
$this->assertTrue(Hash::check('123123', $user->password));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permissions_cannot_create_new_users()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$data = $this->validParams();
|
||||
|
||||
$this->actingAs($userA)->post('/users', $data)->assertForbidden();
|
||||
$this->assertNUll(User::where('email', $data['email'])->first());
|
||||
|
||||
$this->actingAs($userB)->post('/users', $data)->assertRedirect('/users');
|
||||
$this->assertNotNull(User::where('email', $data['email'])->first());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function email_field_is_required_while_creating_a_user()
|
||||
{
|
||||
$data = Arr::except($this->validParams(), ['email']);
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('email');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function email_field_must_be_a_valid_email_while_creating_a_user()
|
||||
{
|
||||
$data = $this->validParams(['email' => 'foo']);
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('email');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function email_must_be_unique_while_creating_a_user()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
UserFactory::user()->email('john@example.com')->create();
|
||||
|
||||
$data = $this->validParams(['email' => 'john@example.com']);
|
||||
|
||||
$this->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('email');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function username_is_not_required()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$data = $this->validParams();
|
||||
unset($data['username']);
|
||||
|
||||
$this->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users');
|
||||
|
||||
$this->assertNotNull(User::where('email', $data['email'])->first());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function username_must_be_unique_while_creating_a_user()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
User::factory()->create(['username' => 'johndoe']);
|
||||
|
||||
$data = $this->validParams(['username' => 'johndoe']);
|
||||
|
||||
$this->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('username');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function password_is_required_while_creating_a_user()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$data = $this->validParams();
|
||||
unset($data['password']);
|
||||
|
||||
$this->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('password');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function password_must_be_at_least_6_characters_long_while_creating_a_user()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$data = $this->validParams(['password' => '12345']);
|
||||
|
||||
$this->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('password');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function password_must_be_confirmed_while_creating_a_user()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$data = $this->validParams();
|
||||
unset($data['password_confirmation']);
|
||||
|
||||
$this->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('password');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function birthday_must_be_a_valid_date_while_creating_a_user()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$data = $this->validParams(['birthday' => 'foo']);
|
||||
|
||||
$this->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('birthday');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function role_field_is_required_while_creating_a_user()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$data = $this->validParams();
|
||||
unset($data['role_id']);
|
||||
|
||||
$this->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('role_id');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function selected_role_must_exist_inside_the_system_while_creating_a_user()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$data = $this->validParams(['role_id' => 123]);
|
||||
|
||||
$this->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('role_id');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function country_id_field_is_not_required_while_creating_a_user()
|
||||
{
|
||||
$data = $this->validParams(['country_id' => 0]);
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users');
|
||||
|
||||
$this->assertSessionHasSuccess('User created successfully.');
|
||||
|
||||
$user = User::where('email', $data['email'])->first();
|
||||
|
||||
$expected = Arr::except($data, ['password', 'password_confirmation']);
|
||||
$expected['country_id'] = null;
|
||||
|
||||
$this->assertDatabaseHas('users', $expected);
|
||||
$this->assertTrue(Hash::check('123123', $user->password));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function country_id_must_exist_inside_the_system_while_creating_a_user()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$data = $this->validParams(['country_id' => 12345]);
|
||||
|
||||
$this->from('/users')
|
||||
->post('/users', $data)
|
||||
->assertRedirect('/users')
|
||||
->assertSessionHasErrors('country_id');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function admin_can_view_users_profile()
|
||||
{
|
||||
$user = UserFactory::user()->create();
|
||||
|
||||
$this->actingAsAdmin()->get("users/{$user->id}")->assertOk();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permissions_cannot_view_profile_for_another_user()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$this->actingAs($userA)->get("users/{$userB->id}")->assertForbidden();
|
||||
$this->actingAs($userB)->get("users/{$userA->id}")->assertOk();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function update_user_details()
|
||||
{
|
||||
\Event::fake([
|
||||
UpdatedByAdmin::class,
|
||||
]);
|
||||
|
||||
$this->beAdmin();
|
||||
|
||||
$user = UserFactory::user()->create();
|
||||
|
||||
$data = $this->validParams();
|
||||
|
||||
$this->from("users/{$user->id}/edit")
|
||||
->put("/users/{$user->id}/update/details", $data)
|
||||
->assertRedirect("users/{$user->id}/edit");
|
||||
|
||||
$expected = Arr::except($data, ['password', 'password_confirmation']);
|
||||
|
||||
$this->assertDatabaseHas('users', $expected + ['id' => $user->id]);
|
||||
$this->assertSessionHasSuccess('User updated successfully.');
|
||||
|
||||
Event::assertDispatched(UpdatedByAdmin::class);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permissions_cannot_update_other_users()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$data = $this->validParams();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->from("users/{$userB->id}/edit")
|
||||
->put("/users/{$userB->id}/update/details", $data)
|
||||
->assertForbidden();
|
||||
|
||||
$this->assertNotEquals($data['email'], $userB->fresh()->email);
|
||||
|
||||
$this->actingAs($userB)
|
||||
->from("users/{$userA->id}/edit")
|
||||
->put("/users/{$userA->id}/update/details", $data)
|
||||
->assertRedirect("users/{$userA->id}/edit");
|
||||
|
||||
$this->assertEquals($data['email'], $userA->fresh()->email);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function banning_a_user_will_invalidate_all_his_sessions()
|
||||
{
|
||||
config(['session.driver' => 'database']);
|
||||
|
||||
$this->beAdmin();
|
||||
|
||||
$user = UserFactory::user()->create(['remember_token' => Str::random(60)]);
|
||||
|
||||
\DB::table('sessions')->insert([
|
||||
'id' => Str::random(40),
|
||||
'user_id' => $user->id,
|
||||
'ip_address' => "127.0.0.1",
|
||||
'user_agent' => 'Foo',
|
||||
'payload' => Str::random(),
|
||||
'last_activity' => Carbon::now()->subMinute()->timestamp
|
||||
]);
|
||||
|
||||
$data = $this->validParams(['status' => UserStatus::BANNED]);
|
||||
|
||||
$this->put("/users/{$user->id}/update/details", $data);
|
||||
|
||||
$this->assertDatabaseMissing('sessions', ['user_id' => $user->id]);
|
||||
$this->assertNull($user->fresh()->remember_token);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function admin_can_update_users_login_details()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$user = UserFactory::user()->create();
|
||||
|
||||
$data = [
|
||||
'email' => 'john@doe.com',
|
||||
'username' => 'milos',
|
||||
'password' => '123123123',
|
||||
'password_confirmation' => '123123123'
|
||||
];
|
||||
|
||||
$this->put("users/{$user->id}/update/login-details", $data)
|
||||
->assertRedirect("users/{$user->id}/edit");
|
||||
|
||||
$this->assertSessionHasSuccess('Login details updated successfully.');
|
||||
|
||||
$user = $user->fresh();
|
||||
|
||||
$this->assertEquals($data['email'], $user->email);
|
||||
$this->assertEquals($data['username'], $user->username);
|
||||
$this->assertTrue(Hash::check($data['password'], $user->password));
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permissions_cannot_update_other_users_login_details()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$data = [
|
||||
'email' => 'john@doe.com',
|
||||
'username' => 'milos',
|
||||
'password' => '123123123',
|
||||
'password_confirmation' => '123123123'
|
||||
];
|
||||
|
||||
$this->actingAs($userA)
|
||||
->from("users/{$userB->id}/edit")
|
||||
->put("users/{$userB->id}/update/login-details", $data)
|
||||
->assertForbidden();
|
||||
|
||||
$this->assertNotEquals($data['email'], $userB->fresh()->email);
|
||||
|
||||
$this->actingAs($userB)
|
||||
->from("users/{$userA->id}/edit")
|
||||
->put("users/{$userA->id}/update/login-details", $data)
|
||||
->assertRedirect("users/{$userA->id}/edit");
|
||||
|
||||
$this->assertEquals($data['email'], $userA->fresh()->email);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function two_factor_form_visibility()
|
||||
{
|
||||
config(['services.authy.key' => 'test']);
|
||||
|
||||
$this->setSettings(['2fa.enabled' => false]);
|
||||
|
||||
$user = UserFactory::user()->create();
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->get("users/{$user->id}/edit")
|
||||
->assertDontSee('Two-Factor Authentication');
|
||||
|
||||
$this->setSettings(['2fa.enabled' => true]);
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->get("users/{$user->id}/edit")
|
||||
->assertSee('Two-Factor Authentication');
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function admin_can_update_avatar_on_behalf_of_a_user()
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$data = [
|
||||
'avatar' => UploadedFile::fake()->image('photo1.jpg', 300, 300),
|
||||
'points' => [
|
||||
'x1' => 0,
|
||||
'y1' => 0,
|
||||
'x2' => 200,
|
||||
'y2' => 200
|
||||
]
|
||||
];
|
||||
|
||||
$user = UserFactory::user()->create();
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from("users/{$user->id}/edit")
|
||||
->post("users/{$user->id}/update/avatar", $data)
|
||||
->assertRedirect("users/{$user->id}/edit");
|
||||
|
||||
$this->assertSessionHasSuccess('Avatar changed successfully.');
|
||||
|
||||
$user->refresh();
|
||||
|
||||
$this->assertNotNull($user->avatar);
|
||||
Storage::disk('public')->assertExists("upload/users/{$user->avatar}");
|
||||
|
||||
list($width, $height) = getimagesizefromstring(
|
||||
Storage::disk('public')->get("upload/users/{$user->avatar}")
|
||||
);
|
||||
|
||||
$this->assertEquals(160, $width);
|
||||
$this->assertEquals(160, $height);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function admin_can_update_avatar_on_behalf_of_a_user_only_if_valid_file_is_selected()
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$data = [
|
||||
'avatar' => UploadedFile::fake()->create('foo.txt', 123),
|
||||
'points' => [
|
||||
'x1' => 0,
|
||||
'y1' => 0,
|
||||
'x2' => 200,
|
||||
'y2' => 200
|
||||
]
|
||||
];
|
||||
|
||||
$user = UserFactory::user()->create();
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->from("users/{$user->id}/edit")
|
||||
->post("users/{$user->id}/update/avatar", $data)
|
||||
->assertRedirect("users/{$user->id}/edit");
|
||||
|
||||
$this->assertNull($user->fresh()->avatar);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permissions_cannot_update_avatar_for_other_users()
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$data = [
|
||||
'avatar' => UploadedFile::fake()->image('photo1.jpg', 300, 300),
|
||||
'points' => [
|
||||
'x1' => 0,
|
||||
'y1' => 0,
|
||||
'x2' => 200,
|
||||
'y2' => 200
|
||||
]
|
||||
];
|
||||
|
||||
$this->actingAs($userA)
|
||||
->from("users/{$userB->id}/edit")
|
||||
->post("users/{$userB->id}/update/avatar", $data)
|
||||
->assertForbidden();
|
||||
|
||||
$this->assertNull($userB->fresh()->avatar);
|
||||
|
||||
$this->actingAs($userB)
|
||||
->from("users/{$userA->id}/edit")
|
||||
->post("users/{$userA->id}/update/avatar", $data)
|
||||
->assertRedirect("users/{$userA->id}/edit");
|
||||
|
||||
$this->assertNotNull($userA->fresh()->avatar);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function session_page_is_not_available_for_non_database_driver()
|
||||
{
|
||||
config(['session.driver' => 'array']);
|
||||
|
||||
$user = UserFactory::admin()->create();
|
||||
|
||||
$this->actingAs($user)
|
||||
->get('users')
|
||||
->assertDontSee('User Sessions');
|
||||
|
||||
// this page should not be accessible if
|
||||
// database session driver is not being used
|
||||
$this->get("users/{$user->id}/sessions")->assertNotFound();
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function invalidate_session()
|
||||
{
|
||||
config(['session.driver' => 'database']);
|
||||
|
||||
Carbon::setTestNow(Carbon::now());
|
||||
|
||||
$user = UserFactory::admin()->withCredentials('foo', 'bar')->create();
|
||||
|
||||
$agent = $this->app['agent'];
|
||||
$device = $agent->device() ?: 'Unknown';
|
||||
$platform = $agent->platform() ?: 'Unknown';
|
||||
|
||||
// Log-in manually to actually create session record in DB
|
||||
$this->post('/login', ['username' => 'foo', 'password' => 'bar']);
|
||||
|
||||
$this->get("users/{$user->id}/sessions")
|
||||
->assertSee('127.0.0.1')
|
||||
->assertSee($device)
|
||||
->assertSee($platform)
|
||||
->assertSee($agent->browser());
|
||||
|
||||
$sessionId = \DB::table('sessions')->where('user_id', $user->id)->first()->id;
|
||||
$this->delete("users/{$user->id}/sessions/{$sessionId}/invalidate");
|
||||
|
||||
$this->assertDatabaseMissing('sessions', ['user_id' => $user->id]);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function admins_can_delete_other_users()
|
||||
{
|
||||
$user = UserFactory::user()->create();
|
||||
|
||||
$this->actingAsAdmin()
|
||||
->delete(route('users.destroy', $user))
|
||||
->assertRedirect('users');
|
||||
|
||||
$this->assertSessionHasSuccess("User deleted successfully.");
|
||||
|
||||
$this->assertNull($user->fresh());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function users_without_appropriate_permissions_cannot_delete_other_users()
|
||||
{
|
||||
$roleA = RoleFactory::create();
|
||||
$roleB = RoleFactory::withPermissions('users.manage')->create();
|
||||
|
||||
$userA = UserFactory::role($roleA)->create();
|
||||
$userB = UserFactory::role($roleB)->create();
|
||||
|
||||
$this->actingAs($userA)
|
||||
->delete(route('users.destroy', $userB))
|
||||
->assertForbidden();
|
||||
|
||||
$this->assertNotNull($userB->fresh());
|
||||
|
||||
$this->actingAs($userB)
|
||||
->delete(route('users.destroy', $userA))
|
||||
->assertRedirect('/users');
|
||||
|
||||
$this->assertNull($userA->fresh());
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function user_cannot_delete_himself()
|
||||
{
|
||||
$this->beAdmin();
|
||||
|
||||
$this->delete(route('users.destroy', auth()->id()))
|
||||
->assertRedirect('/users');
|
||||
|
||||
$this->assertNotNull(auth()->user()->fresh());
|
||||
$this->assertSessionHasError("You cannot delete yourself.");
|
||||
}
|
||||
|
||||
protected function validParams(array $overrides = [])
|
||||
{
|
||||
return array_merge([
|
||||
'role_id' => Role::whereName('User')->first()->id,
|
||||
'status' => UserStatus::ACTIVE,
|
||||
'first_name' => 'foo',
|
||||
'last_name' => 'bar',
|
||||
'birthday' => Carbon::now()->subYears(25)->format('Y-m-d'),
|
||||
'phone' => '12345667',
|
||||
'address' => 'the address',
|
||||
'country_id' => 688, //Serbia,
|
||||
'email' => 'john@doe.com',
|
||||
'username' => 'johndoe',
|
||||
'password' => '123123',
|
||||
'password_confirmation' => '123123'
|
||||
], $overrides);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user