322 lines
11 KiB
PHP
322 lines
11 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Api\V1\Admin;
|
|
|
|
use App\Models\Barangay;
|
|
use App\Models\DriverProfile;
|
|
use App\Models\Household;
|
|
use App\Models\HouseholdMember;
|
|
use App\Models\ResidentProfile;
|
|
use App\Models\User;
|
|
use Database\Seeders\RoleSeeder;
|
|
use Database\Seeders\SamplePsgcSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Laravel\Sanctum\Sanctum;
|
|
use MatanYadaev\EloquentSpatial\Objects\Point;
|
|
use Tests\TestCase;
|
|
|
|
class AdminUserCrudTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private User $admin;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->seed(RoleSeeder::class);
|
|
$this->admin = User::factory()->create([
|
|
'role' => User::ROLE_ADMIN,
|
|
'status' => User::STATUS_ACTIVE,
|
|
]);
|
|
}
|
|
|
|
public function test_admin_can_list_users_with_filters(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
User::factory()->count(3)->create(['role' => User::ROLE_RESIDENT]);
|
|
User::factory()->count(2)->create(['role' => User::ROLE_DRIVER]);
|
|
|
|
$response = $this->getJson('/api/v1/admin/users?role=resident');
|
|
|
|
$response->assertOk();
|
|
$items = $response->json('data');
|
|
$this->assertGreaterThanOrEqual(3, count($items));
|
|
foreach ($items as $u) {
|
|
$this->assertSame('resident', $u['role']);
|
|
}
|
|
}
|
|
|
|
public function test_admin_can_search_users_by_name_or_email(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
User::factory()->create(['email' => 'unique-find@example.com']);
|
|
|
|
$response = $this->getJson('/api/v1/admin/users?q=unique-find');
|
|
|
|
$response->assertOk()
|
|
->assertJsonFragment(['email' => 'unique-find@example.com']);
|
|
}
|
|
|
|
public function test_admin_can_show_user_with_profile(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
$user = User::factory()->create(['role' => User::ROLE_RESIDENT]);
|
|
ResidentProfile::create(['user_id' => $user->id, 'occupation' => 'Teacher']);
|
|
|
|
$response = $this->getJson("/api/v1/admin/users/{$user->uuid}");
|
|
|
|
$response->assertOk()
|
|
->assertJsonPath('data.id', $user->uuid)
|
|
->assertJsonPath('data.profile.occupation', 'Teacher');
|
|
}
|
|
|
|
public function test_admin_can_update_user(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
$user = User::factory()->create();
|
|
|
|
$response = $this->patchJson("/api/v1/admin/users/{$user->uuid}", [
|
|
'first_name' => 'Updated',
|
|
'preferred_language' => 'tl',
|
|
]);
|
|
|
|
$response->assertOk()
|
|
->assertJsonPath('data.first_name', 'Updated')
|
|
->assertJsonPath('data.preferred_language', 'tl');
|
|
}
|
|
|
|
public function test_admin_can_suspend_and_activate_user(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
$user = User::factory()->create([
|
|
'role' => User::ROLE_DRIVER,
|
|
'status' => User::STATUS_ACTIVE,
|
|
]);
|
|
|
|
$this->postJson("/api/v1/admin/users/{$user->uuid}/suspend")
|
|
->assertOk()
|
|
->assertJsonPath('data.status', User::STATUS_SUSPENDED);
|
|
|
|
$this->postJson("/api/v1/admin/users/{$user->uuid}/activate")
|
|
->assertOk()
|
|
->assertJsonPath('data.status', User::STATUS_ACTIVE);
|
|
}
|
|
|
|
public function test_admin_cannot_suspend_other_admin(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
$otherAdmin = User::factory()->create(['role' => User::ROLE_ADMIN]);
|
|
|
|
$response = $this->postJson("/api/v1/admin/users/{$otherAdmin->uuid}/suspend");
|
|
|
|
$response->assertStatus(422);
|
|
}
|
|
|
|
public function test_admin_can_soft_delete_user(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
$user = User::factory()->create(['role' => User::ROLE_RESIDENT]);
|
|
|
|
$response = $this->deleteJson("/api/v1/admin/users/{$user->uuid}");
|
|
|
|
$response->assertOk();
|
|
$this->assertSoftDeleted('users', ['id' => $user->id]);
|
|
}
|
|
|
|
public function test_admin_can_approve_driver_profile(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
$driver = User::factory()->create([
|
|
'role' => User::ROLE_DRIVER,
|
|
'status' => User::STATUS_PENDING,
|
|
]);
|
|
DriverProfile::create(['user_id' => $driver->id, 'license_number' => 'D-1234']);
|
|
|
|
$response = $this->postJson("/api/v1/admin/users/{$driver->uuid}/approve-profile");
|
|
|
|
$response->assertOk()
|
|
->assertJsonPath('data.status', User::STATUS_ACTIVE)
|
|
->assertJsonPath('data.profile.verification_status', 'approved');
|
|
|
|
$this->assertDatabaseHas('driver_profiles', [
|
|
'user_id' => $driver->id,
|
|
'verification_status' => 'approved',
|
|
]);
|
|
}
|
|
|
|
public function test_admin_can_reject_driver_profile_with_reason(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
$driver = User::factory()->create(['role' => User::ROLE_DRIVER]);
|
|
DriverProfile::create(['user_id' => $driver->id, 'license_number' => 'D-9999']);
|
|
|
|
$response = $this->postJson("/api/v1/admin/users/{$driver->uuid}/reject-profile", [
|
|
'reason' => 'License photo unreadable',
|
|
]);
|
|
|
|
$response->assertOk()
|
|
->assertJsonPath('data.profile.verification_status', 'rejected')
|
|
->assertJsonPath('data.profile.rejection_reason', 'License photo unreadable');
|
|
}
|
|
|
|
public function test_resident_blocked_from_admin_users(): void
|
|
{
|
|
$resident = User::factory()->create([
|
|
'role' => User::ROLE_RESIDENT,
|
|
'status' => User::STATUS_ACTIVE,
|
|
]);
|
|
Sanctum::actingAs($resident);
|
|
|
|
$this->getJson('/api/v1/admin/users')->assertStatus(403);
|
|
}
|
|
|
|
public function test_unauthed_blocked_from_admin_users(): void
|
|
{
|
|
$this->getJson('/api/v1/admin/users')->assertStatus(401);
|
|
}
|
|
|
|
public function test_resident_activation_requires_super_admin_and_coordinates(): void
|
|
{
|
|
$resident = User::factory()->create([
|
|
'role' => User::ROLE_RESIDENT,
|
|
'status' => User::STATUS_PENDING,
|
|
]);
|
|
|
|
Sanctum::actingAs($this->admin);
|
|
$this->postJson("/api/v1/admin/users/{$resident->uuid}/activate")
|
|
->assertStatus(403);
|
|
|
|
$superAdmin = User::factory()->create([
|
|
'role' => User::ROLE_SUPER_ADMIN,
|
|
'status' => User::STATUS_ACTIVE,
|
|
]);
|
|
|
|
Sanctum::actingAs($superAdmin);
|
|
$this->postJson("/api/v1/admin/users/{$resident->uuid}/activate")
|
|
->assertStatus(422)
|
|
->assertJsonFragment(['message' => 'Resident household must have coordinates pinned before activation']);
|
|
|
|
$household = Household::factory()->create([
|
|
'head_user_id' => $resident->id,
|
|
'coordinates' => new Point(14.5995, 120.9842, 4326),
|
|
]);
|
|
HouseholdMember::create([
|
|
'household_id' => $household->id,
|
|
'user_id' => $resident->id,
|
|
'relationship' => HouseholdMember::RELATIONSHIP_HEAD,
|
|
'full_name' => $resident->full_name,
|
|
]);
|
|
|
|
$this->postJson("/api/v1/admin/users/{$resident->uuid}/activate")
|
|
->assertOk()
|
|
->assertJsonPath('data.status', User::STATUS_ACTIVE);
|
|
}
|
|
|
|
public function test_admin_can_group_resident_into_existing_household(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
|
|
$resident = User::factory()->create([
|
|
'role' => User::ROLE_RESIDENT,
|
|
'status' => User::STATUS_PENDING,
|
|
]);
|
|
|
|
$household = Household::factory()->create();
|
|
|
|
$response = $this->postJson("/api/v1/admin/users/{$resident->uuid}/group-into-household", [
|
|
'household_id' => $household->id,
|
|
]);
|
|
|
|
$response->assertOk()
|
|
->assertJsonPath('data.household.id', $household->uuid);
|
|
|
|
$this->assertDatabaseHas('household_members', [
|
|
'household_id' => $household->id,
|
|
'user_id' => $resident->id,
|
|
'relationship' => HouseholdMember::RELATIONSHIP_OTHER,
|
|
]);
|
|
}
|
|
|
|
public function test_admin_can_group_resident_into_new_household(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
$this->seed(SamplePsgcSeeder::class);
|
|
$barangay = Barangay::firstOrFail();
|
|
|
|
$resident = User::factory()->create([
|
|
'role' => User::ROLE_RESIDENT,
|
|
'status' => User::STATUS_PENDING,
|
|
]);
|
|
|
|
$response = $this->postJson("/api/v1/admin/users/{$resident->uuid}/group-into-household", [
|
|
'address_line' => '123 New Pin Street',
|
|
'barangay_id' => $barangay->id,
|
|
'household_size' => 3,
|
|
'lat' => 14.5995,
|
|
'lng' => 120.9842,
|
|
]);
|
|
|
|
$response->assertOk()
|
|
->assertJsonPath('data.household.address_line', '123 New Pin Street')
|
|
->assertJsonPath('data.household.household_size', 3);
|
|
|
|
$this->assertDatabaseHas('households', [
|
|
'head_user_id' => $resident->id,
|
|
'address_line' => '123 New Pin Street',
|
|
'household_size' => 3,
|
|
]);
|
|
|
|
$this->assertDatabaseHas('household_members', [
|
|
'user_id' => $resident->id,
|
|
'relationship' => HouseholdMember::RELATIONSHIP_HEAD,
|
|
]);
|
|
}
|
|
|
|
public function test_admin_can_group_resident_with_existing_household_and_clean_it_up(): void
|
|
{
|
|
Sanctum::actingAs($this->admin);
|
|
|
|
$resident = User::factory()->create([
|
|
'role' => User::ROLE_RESIDENT,
|
|
'status' => User::STATUS_ACTIVE,
|
|
]);
|
|
|
|
$oldHousehold = Household::factory()->create([
|
|
'head_user_id' => $resident->id,
|
|
]);
|
|
|
|
$oldMember = HouseholdMember::create([
|
|
'household_id' => $oldHousehold->id,
|
|
'user_id' => $resident->id,
|
|
'relationship' => HouseholdMember::RELATIONSHIP_HEAD,
|
|
'full_name' => $resident->full_name,
|
|
]);
|
|
|
|
$newHousehold = Household::factory()->create();
|
|
|
|
$response = $this->postJson("/api/v1/admin/users/{$resident->uuid}/group-into-household", [
|
|
'household_id' => $newHousehold->id,
|
|
]);
|
|
|
|
$response->assertOk();
|
|
|
|
// Check new membership
|
|
$this->assertDatabaseHas('household_members', [
|
|
'household_id' => $newHousehold->id,
|
|
'user_id' => $resident->id,
|
|
'relationship' => HouseholdMember::RELATIONSHIP_OTHER,
|
|
]);
|
|
|
|
// Check old membership deleted
|
|
$this->assertSoftDeleted('household_members', [
|
|
'id' => $oldMember->id,
|
|
]);
|
|
|
|
// Check old household deleted
|
|
$this->assertSoftDeleted('households', [
|
|
'id' => $oldHousehold->id,
|
|
]);
|
|
}
|
|
}
|