212 lines
7.6 KiB
PHP
212 lines
7.6 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\Application;
|
|
use App\Models\ApplicationDocument;
|
|
use App\Models\Position;
|
|
use App\Models\PusatMengundi;
|
|
use App\Models\StaffAssignment;
|
|
use App\Models\User;
|
|
use Database\Seeders\DatabaseSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Tests\TestCase;
|
|
|
|
class DocumentDownloadAuthorizationTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
// ── Admin path ──────────────────────────────────────────────────────
|
|
|
|
public function test_admin_can_download_ic_document(): void
|
|
{
|
|
Storage::fake('local');
|
|
$this->seed(DatabaseSeeder::class);
|
|
|
|
$admin = User::query()->where('email', 'admin@prn.local')->firstOrFail();
|
|
|
|
$this->actingAs($admin)
|
|
->get(route('admin.documents.download', $this->document('ic_document')))
|
|
->assertOk();
|
|
}
|
|
|
|
public function test_admin_can_download_bank_statement(): void
|
|
{
|
|
Storage::fake('local');
|
|
$this->seed(DatabaseSeeder::class);
|
|
|
|
$admin = User::query()->where('email', 'admin@prn.local')->firstOrFail();
|
|
|
|
$this->actingAs($admin)
|
|
->get(route('admin.documents.download', $this->document('bank_statement')))
|
|
->assertOk();
|
|
}
|
|
|
|
public function test_unauthorized_role_cannot_access_admin_download_route(): void
|
|
{
|
|
Storage::fake('local');
|
|
$this->seed(DatabaseSeeder::class);
|
|
|
|
$ktm = User::query()->where('email', 'ktm@prn.local')->firstOrFail();
|
|
|
|
$this->actingAs($ktm)
|
|
->get(route('admin.documents.download', $this->document('bank_statement')))
|
|
->assertForbidden();
|
|
}
|
|
|
|
// ── Finance path ─────────────────────────────────────────────────────
|
|
|
|
public function test_finance_can_download_bank_statement(): void
|
|
{
|
|
Storage::fake('local');
|
|
$this->seed(DatabaseSeeder::class);
|
|
|
|
$finance = User::query()->where('email', 'kewangan@prn.local')->firstOrFail();
|
|
|
|
$this->actingAs($finance)
|
|
->get(route('kewangan.documents.download', $this->document('bank_statement')))
|
|
->assertOk();
|
|
}
|
|
|
|
public function test_finance_cannot_download_ic_document_via_finance_route(): void
|
|
{
|
|
Storage::fake('local');
|
|
$this->seed(DatabaseSeeder::class);
|
|
|
|
$finance = User::query()->where('email', 'kewangan@prn.local')->firstOrFail();
|
|
|
|
$this->actingAs($finance)
|
|
->get(route('kewangan.documents.download', $this->document('ic_document')))
|
|
->assertForbidden();
|
|
}
|
|
|
|
// ── PPM path ──────────────────────────────────────────────────────────
|
|
|
|
public function test_ppm_can_download_ic_document_from_own_pusat(): void
|
|
{
|
|
Storage::fake('local');
|
|
$this->seed(DatabaseSeeder::class);
|
|
|
|
$ppm = User::query()->where('email', 'ppm@prn.local')->firstOrFail();
|
|
$pusat = $this->ppmPusat($ppm);
|
|
$document = $this->documentForPusat($pusat, 'ic_document');
|
|
|
|
$this->actingAs($ppm)
|
|
->get(route('ppm.applications.documents.download', [
|
|
'application' => $document->application->public_uuid,
|
|
'document' => $document,
|
|
]))
|
|
->assertOk();
|
|
}
|
|
|
|
public function test_ppm_can_download_bank_statement_from_own_pusat(): void
|
|
{
|
|
Storage::fake('local');
|
|
$this->seed(DatabaseSeeder::class);
|
|
|
|
$ppm = User::query()->where('email', 'ppm@prn.local')->firstOrFail();
|
|
$pusat = $this->ppmPusat($ppm);
|
|
$document = $this->documentForPusat($pusat, 'bank_statement');
|
|
|
|
$this->actingAs($ppm)
|
|
->get(route('ppm.applications.documents.download', [
|
|
'application' => $document->application->public_uuid,
|
|
'document' => $document,
|
|
]))
|
|
->assertOk();
|
|
}
|
|
|
|
public function test_ppm_cannot_download_document_from_another_pusat(): void
|
|
{
|
|
Storage::fake('local');
|
|
$this->seed(DatabaseSeeder::class);
|
|
|
|
$ppm = User::query()->where('email', 'ppm@prn.local')->firstOrFail();
|
|
|
|
// Create a document belonging to a DIFFERENT pusat than PPM's assignment
|
|
$otherPusat = PusatMengundi::factory()->create([
|
|
'election_id' => PusatMengundi::query()->where('code', 'PM001')->value('election_id'),
|
|
'daerah_mengundi_id' => PusatMengundi::query()->where('code', 'PM001')->value('daerah_mengundi_id'),
|
|
]);
|
|
$document = $this->documentForPusat($otherPusat, 'ic_document');
|
|
|
|
$this->actingAs($ppm)
|
|
->get(route('ppm.applications.documents.download', [
|
|
'application' => $document->application->public_uuid,
|
|
'document' => $document,
|
|
]))
|
|
->assertForbidden();
|
|
}
|
|
|
|
public function test_ppm_download_records_activity_log(): void
|
|
{
|
|
Storage::fake('local');
|
|
$this->seed(DatabaseSeeder::class);
|
|
|
|
$ppm = User::query()->where('email', 'ppm@prn.local')->firstOrFail();
|
|
$pusat = $this->ppmPusat($ppm);
|
|
$document = $this->documentForPusat($pusat, 'ic_document');
|
|
|
|
$this->actingAs($ppm)
|
|
->get(route('ppm.applications.documents.download', [
|
|
'application' => $document->application->public_uuid,
|
|
'document' => $document,
|
|
]));
|
|
|
|
$this->assertDatabaseHas('activity_log', [
|
|
'log_name' => 'documents',
|
|
'description' => 'document_downloaded_by_ppm',
|
|
'causer_id' => $ppm->id,
|
|
]);
|
|
}
|
|
|
|
// ── Helpers ───────────────────────────────────────────────────────────
|
|
|
|
private function document(string $type, string $fileName = 'file.pdf'): ApplicationDocument
|
|
{
|
|
$pusat = PusatMengundi::query()->where('code', 'PM001')->firstOrFail();
|
|
|
|
return $this->documentForPusat($pusat, $type, $fileName);
|
|
}
|
|
|
|
private function documentForPusat(PusatMengundi $pusat, string $type, string $fileName = 'file.pdf'): ApplicationDocument
|
|
{
|
|
$position = Position::query()->where('code', 'PAPM')->firstOrFail();
|
|
$application = Application::factory()->create([
|
|
'election_id' => $pusat->election_id,
|
|
'pusat_mengundi_id' => $pusat->id,
|
|
'requested_position_id' => $position->id,
|
|
]);
|
|
$path = 'applications/'.$application->public_uuid.'/'.$fileName;
|
|
Storage::disk('local')->put($path, 'test content');
|
|
|
|
$document = ApplicationDocument::query()->create([
|
|
'application_id' => $application->id,
|
|
'document_type' => $type,
|
|
'disk' => 'local',
|
|
'path' => $path,
|
|
'original_name' => $fileName,
|
|
'mime_type' => 'application/pdf',
|
|
'size' => 12,
|
|
]);
|
|
|
|
$document->setRelation('application', $application);
|
|
|
|
return $document;
|
|
}
|
|
|
|
private function ppmPusat(User $ppm): PusatMengundi
|
|
{
|
|
$ppmPosition = Position::query()->where('code', 'PPM')->firstOrFail();
|
|
|
|
$assignment = StaffAssignment::query()
|
|
->where('user_id', $ppm->id)
|
|
->where('position_id', $ppmPosition->id)
|
|
->where('status', 'active')
|
|
->firstOrFail();
|
|
|
|
return PusatMengundi::query()->findOrFail($assignment->pusat_mengundi_id);
|
|
}
|
|
}
|