130 lines
7.8 KiB
PHP
130 lines
7.8 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Models\User;
|
|
use App\Services\Malware\MalwareScanner;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Crypt;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Support\Str;
|
|
use Tests\Support\CleanScannerFixture;
|
|
use Tests\TestCase;
|
|
|
|
class InvestmentZoneAttachmentTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->app->bind(MalwareScanner::class, fn () => new CleanScannerFixture);
|
|
}
|
|
|
|
public function test_upload_is_private_until_administrative_review_and_explicit_public_selection(): void
|
|
{
|
|
Storage::fake('local');
|
|
$manager = $this->manager(true);
|
|
$zoneId = $this->draft($manager);
|
|
$response = $this->actingAs($manager)->post('/api/v2/investment/admin/zones/'.$zoneId.'/attachments', [
|
|
'file' => UploadedFile::fake()->createWithContent('decreto.pdf', "%PDF-1.7\nconteudo sintetico de ensaio\n"),
|
|
'kind' => 'legal_instrument', 'caption' => 'Diploma de ensaio', 'source_reference' => 'Arquivo oficial, referência sintética',
|
|
'source_date' => '2026-01-01', 'rights_status' => 'pending', 'rights_basis' => '',
|
|
], ['Accept' => 'application/json'])->assertCreated();
|
|
$attachment = $response->json();
|
|
|
|
$this->assertSame('pending', $attachment['review_status']);
|
|
$this->assertFalse($attachment['publicly_selected']);
|
|
$this->assertSame($manager->id, $attachment['uploaded_by']);
|
|
$document = DB::table('documents')->where('id', $attachment['document_id'])->first();
|
|
$this->assertSame('active', $document->status);
|
|
$this->assertSame('clean', $document->malware_scan_status);
|
|
$this->assertSame($document->sha256, $document->malware_scanned_sha256);
|
|
$this->assertSame('confidential', $document->data_classification);
|
|
$this->assertDatabaseHas('investment_zone_attachment_events', ['attachment_id' => $attachment['id'], 'action' => 'uploaded']);
|
|
$this->get('/zonas/'.$zoneId.'/anexos/'.$attachment['id'])->assertNotFound();
|
|
$this->actingAs($manager)->get('/management/investment/zones/'.$zoneId.'/attachments/'.$attachment['id'])->assertOk();
|
|
|
|
$this->actingAs($manager)->postJson('/api/v2/investment/admin/zone-attachments/'.$attachment['id'].'/review', [
|
|
'version_no' => 1, 'decision' => 'reviewed', 'rights_status' => 'confirmed', 'rights_basis' => 'Permissão documentada para o ensaio',
|
|
'personal_data_status' => 'none',
|
|
])->assertOk()->assertJsonPath('independent_review', false)->assertJsonPath('review_status', 'reviewed');
|
|
$this->assertDatabaseHas('investment_zone_attachment_events', ['attachment_id' => $attachment['id'], 'action' => 'review']);
|
|
|
|
$this->makeVisibleWithoutOperator($zoneId, $manager);
|
|
$this->actingAs($manager)->postJson('/api/v2/investment/admin/zone-attachments/'.$attachment['id'].'/select-public', ['version_no' => 2])->assertOk()->assertJsonPath('publicly_selected', true);
|
|
$this->getJson('/api/v2/investment/zones/'.$zoneId)->assertOk()
|
|
->assertJsonPath('attachments.0.caption', 'Diploma de ensaio')
|
|
->assertJsonMissingPath('attachments.0.uploaded_by')
|
|
->assertJsonMissingPath('attachments.0.rights_basis');
|
|
$this->get('/zonas/'.$zoneId.'/anexos/'.$attachment['id'])->assertOk();
|
|
|
|
$this->actingAs($manager)->postJson('/api/v2/investment/admin/zone-attachments/'.$attachment['id'].'/withdraw-public', ['version_no' => 3])->assertOk()->assertJsonPath('publicly_selected', false);
|
|
$this->get('/zonas/'.$zoneId.'/anexos/'.$attachment['id'])->assertNotFound();
|
|
}
|
|
|
|
public function test_public_selection_rejects_unknown_rights_or_personal_data_and_invalid_file_content(): void
|
|
{
|
|
Storage::fake('local');
|
|
$manager = $this->manager(true);
|
|
$zoneId = $this->draft($manager);
|
|
$this->actingAs($manager)->post('/api/v2/investment/admin/zones/'.$zoneId.'/attachments', [
|
|
'file' => UploadedFile::fake()->createWithContent('bad.pdf', 'not a PDF document'),
|
|
'kind' => 'study', 'caption' => 'Invalid test file', 'source_reference' => 'Synthetic test source', 'rights_status' => 'pending',
|
|
], ['Accept' => 'application/json'])->assertUnprocessable();
|
|
$this->actingAs($manager)->post('/api/v2/investment/admin/zones/'.$zoneId.'/attachments', [
|
|
'file' => UploadedFile::fake()->create('large.pdf', 20481, 'application/pdf'),
|
|
'kind' => 'study', 'caption' => 'Oversized test file', 'source_reference' => 'Synthetic test source', 'rights_status' => 'pending',
|
|
], ['Accept' => 'application/json'])->assertUnprocessable();
|
|
|
|
$attachment = $this->actingAs($manager)->post('/api/v2/investment/admin/zones/'.$zoneId.'/attachments', [
|
|
'file' => UploadedFile::fake()->createWithContent('study.pdf', "%PDF-1.7\nsynthetic test\n"),
|
|
'kind' => 'study', 'caption' => 'Study under review', 'source_reference' => 'Synthetic test source', 'rights_status' => 'pending',
|
|
], ['Accept' => 'application/json'])->assertCreated()->json();
|
|
$this->actingAs($manager)->postJson('/api/v2/investment/admin/zone-attachments/'.$attachment['id'].'/review', [
|
|
'version_no' => 1, 'decision' => 'reviewed', 'rights_status' => 'pending', 'personal_data_status' => 'unknown',
|
|
])->assertOk()->assertJsonPath('review_status', 'reviewed')->assertJsonPath('independent_review', false);
|
|
$this->makeVisibleWithoutOperator($zoneId, $manager);
|
|
$this->actingAs($manager)->postJson('/api/v2/investment/admin/zone-attachments/'.$attachment['id'].'/select-public', ['version_no' => 2])->assertUnprocessable();
|
|
$this->get('/zonas/'.$zoneId.'/anexos/'.$attachment['id'])->assertNotFound();
|
|
}
|
|
|
|
private function manager(bool $publisher): User
|
|
{
|
|
$user = User::factory()->create(['email_verified_at' => now()]);
|
|
$user->forceFill(['two_factor_secret' => Crypt::encryptString('synthetic-test-secret'), 'two_factor_confirmed_at' => now()])->save();
|
|
config(['portal.managers' => [...config('portal.managers', []), $user->email]]);
|
|
if ($publisher) {
|
|
config(['investment-zones.publishers' => [...config('investment-zones.publishers', []), $user->email]]);
|
|
}
|
|
|
|
return $user;
|
|
}
|
|
|
|
private function draft(User $manager): string
|
|
{
|
|
return $this->actingAs($manager)->postJson('/api/v2/investment/admin/zones', [
|
|
'code' => 'ATTACHMENT-TEST-'.Str::uuid(), 'category' => 'zee', 'physical_category' => 'economic_zone',
|
|
'legal_regime' => 'zee', 'name' => 'Zona de ensaio', 'description' => 'Descrição de ensaio para anexo.',
|
|
])->assertCreated()->json('id');
|
|
}
|
|
|
|
private function makeVisibleWithoutOperator(string $zoneId, User $editor): void
|
|
{
|
|
$reviewer = $this->manager(false);
|
|
$sourceId = (string) Str::uuid();
|
|
DB::table('investment_legal_sources')->insert([
|
|
'id' => $sourceId, 'title' => 'Fonte de ensaio', 'url' => 'https://example.test/zone-source', 'diploma' => 'Documento sintético',
|
|
'article' => 'Artigo de ensaio', 'competent_entity' => 'Entidade sintética', 'valid_from' => today()->toDateString(),
|
|
'validation_status' => 'validated', 'owner_id' => $editor->id, 'validator_id' => $reviewer->id,
|
|
'validated_at' => now(), 'version_no' => 1, 'created_at' => now(), 'updated_at' => now(),
|
|
]);
|
|
DB::table('investment_zones')->where('id', $zoneId)->update([
|
|
'legal_source_id' => $sourceId, 'publication_status' => 'published', 'validation_status' => 'validated',
|
|
'reviewer_id' => $reviewer->id, 'published_at' => now(), 'version_no' => 2,
|
|
]);
|
|
}
|
|
}
|