@@ -5,9 +5,11 @@ namespace App\Http\Controllers;
|
||||
use App\Jobs\ScanDocumentForMalware;
|
||||
use App\Models\InterestRequest;
|
||||
use App\Models\Sector;
|
||||
use App\Services\CountryCatalogue;
|
||||
use App\Services\IdempotencyConflict;
|
||||
use App\Services\InterestSubmission;
|
||||
use App\Services\Malware\MalwareScanner;
|
||||
use App\Services\VerifiedDocumentBinary;
|
||||
use App\Services\VirtualDesk;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Database\QueryException;
|
||||
@@ -37,7 +39,7 @@ class PortalServicesController extends Controller
|
||||
$essentialResources = collect();
|
||||
}
|
||||
|
||||
return Inertia::render('PortalInvestidor', ['essentialResources' => $essentialResources]);
|
||||
return Inertia::render('PortalInvestidor', ['essentialResources' => $essentialResources, 'countries' => app(CountryCatalogue::class)->all()]);
|
||||
}
|
||||
|
||||
private function resources(): Builder
|
||||
@@ -64,7 +66,7 @@ class PortalServicesController extends Controller
|
||||
'stage' => ['nullable', 'array', 'max:10'], 'stage.*' => ['string', 'max:80'],
|
||||
'module' => ['nullable', 'array', 'max:10'], 'module.*' => ['string', 'max:80'],
|
||||
]);
|
||||
$props = ['section' => $page, 'filters' => $filters];
|
||||
$props = ['section' => $page, 'filters' => $filters, 'countries' => app(CountryCatalogue::class)->all()];
|
||||
if ($page === 'sectors') {
|
||||
$props['sectors'] = Sector::where('is_active', true)->withCount(['opportunities' => fn ($q) => $q->published()])->orderBy('sort_order')->get(['id', 'name', 'slug', 'short_description']);
|
||||
}
|
||||
@@ -222,7 +224,8 @@ class PortalServicesController extends Controller
|
||||
$data = $request->validate([
|
||||
'kind' => ['required', 'in:support,investor,company,partnership'],
|
||||
'fullName' => ['required', 'string', 'min:3', 'max:150'], 'email' => ['required', 'email:rfc', 'max:150'],
|
||||
'phone' => ['nullable', 'string', 'max:30'], 'country' => ['required', 'string', 'max:100'],
|
||||
'phone' => ['nullable', 'string', 'max:30'], 'country' => ['required', 'string', 'max:100', app(CountryCatalogue::class)->legacyCountryRule()],
|
||||
'declared_origin_country_code' => ['nullable', app(CountryCatalogue::class)->rule()],
|
||||
'company' => ['nullable', 'required_if:kind,company', 'string', 'max:150'],
|
||||
'sectorInterest' => ['required', 'string', 'max:150'], 'message' => ['required', 'string', 'min:20', 'max:2000'],
|
||||
'privacyConsent' => ['required', 'accepted'], 'submission_key' => ['required', 'uuid'],
|
||||
@@ -240,7 +243,8 @@ class PortalServicesController extends Controller
|
||||
'sector_interest' => $data['sectorInterest'], 'message' => $data['message'],
|
||||
'privacy_consent' => true, 'consented_at' => now(), 'status' => 'received', 'source_page' => '/apoio',
|
||||
'metadata' => ['kind' => $data['kind'], 'company' => $data['company'] ?? null,
|
||||
'portal_user_id' => $data['portal_user_id'], 'partnership_id' => $data['partnership_id'] ?? null],
|
||||
'portal_user_id' => $data['portal_user_id'], 'partnership_id' => $data['partnership_id'] ?? null,
|
||||
'declared_origin_country_code' => $data['declared_origin_country_code'] ?? null],
|
||||
]));
|
||||
} catch (IdempotencyConflict) {
|
||||
abort(409, 'Este envio já foi usado com dados diferentes. Recarregue o formulário.');
|
||||
@@ -260,17 +264,12 @@ class PortalServicesController extends Controller
|
||||
return back()->with('success', 'Proposta recebida para publicação. Acompanhe no Balcão Virtual.');
|
||||
}
|
||||
|
||||
public function download(int $id): BinaryFileResponse
|
||||
public function download(int $id): BinaryFileResponse|\Illuminate\Http\Response
|
||||
{
|
||||
$resource = $this->resources()->where('r.id', $id)->first(['d.storage_key', 'd.file_name', 'd.sha256']);
|
||||
$resource = $this->resources()->where('r.id', $id)->first(['d.*']);
|
||||
abort_unless($resource !== null, 404);
|
||||
$root = realpath(Storage::disk('local')->path(''));
|
||||
$path = realpath(Storage::disk('local')->path($resource->storage_key));
|
||||
abort_unless($root && $path && str_starts_with(strtolower($path), strtolower($root.DIRECTORY_SEPARATOR)) && is_file($path), 404);
|
||||
$checksum = hash_file('sha256', $path);
|
||||
abort_unless($checksum !== false && hash_equals($resource->sha256, $checksum), 404);
|
||||
|
||||
return response()->download($path, basename($resource->file_name), ['X-Content-Type-Options' => 'nosniff', 'Cache-Control' => 'private, no-store']);
|
||||
return app(VerifiedDocumentBinary::class)->respond($resource);
|
||||
}
|
||||
|
||||
public function showDocument(Request $request, int $id): Response
|
||||
@@ -306,42 +305,21 @@ class PortalServicesController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function viewDocument(int $id): BinaryFileResponse
|
||||
public function viewDocument(int $id): BinaryFileResponse|\Illuminate\Http\Response
|
||||
{
|
||||
$document = $this->resources()->where('r.id', $id)->first([
|
||||
'd.storage_key', 'd.file_name', 'd.sha256', 'd.media_type',
|
||||
]);
|
||||
$document = $this->resources()->where('r.id', $id)->first(['d.*']);
|
||||
abort_unless($document && in_array($document->media_type, ['application/pdf', 'image/jpeg', 'image/png', 'image/webp'], true), 404);
|
||||
$root = realpath(Storage::disk('local')->path(''));
|
||||
$path = realpath(Storage::disk('local')->path($document->storage_key));
|
||||
abort_unless($root && $path && str_starts_with(strtolower($path), strtolower($root.DIRECTORY_SEPARATOR)) && is_file($path), 404);
|
||||
$checksum = hash_file('sha256', $path);
|
||||
abort_unless($checksum !== false && hash_equals($document->sha256, $checksum), 404);
|
||||
|
||||
return response()->file($path, [
|
||||
'Content-Type' => $document->media_type,
|
||||
'X-Content-Type-Options' => 'nosniff',
|
||||
'Content-Security-Policy' => "sandbox; default-src 'none'; style-src 'unsafe-inline'",
|
||||
'Cache-Control' => 'private, no-store',
|
||||
])->setContentDisposition('inline', basename($document->file_name));
|
||||
return app(VerifiedDocumentBinary::class)->respond($document, true);
|
||||
}
|
||||
|
||||
public function downloadForManager(string $id): BinaryFileResponse
|
||||
public function downloadForManager(string $id): BinaryFileResponse|\Illuminate\Http\Response
|
||||
{
|
||||
$document = DB::table('documents')->where('id', $id)->whereNull('deleted_at')->first([
|
||||
'storage_key', 'file_name', 'sha256', 'status', 'malware_scan_status', 'malware_scanned_sha256',
|
||||
]);
|
||||
$document = DB::table('documents')->where('id', $id)->whereNull('deleted_at')->first();
|
||||
abort_unless($document && $document->status === 'active' && $document->malware_scan_status === 'clean'
|
||||
&& hash_equals(trim($document->sha256), trim((string) $document->malware_scanned_sha256)), 404);
|
||||
$root = realpath(Storage::disk('local')->path(''));
|
||||
$path = realpath(Storage::disk('local')->path($document->storage_key));
|
||||
abort_unless($root && $path && str_starts_with(strtolower($path), strtolower($root.DIRECTORY_SEPARATOR)) && is_file($path), 404);
|
||||
$checksum = hash_file('sha256', $path);
|
||||
abort_unless($checksum !== false && hash_equals($document->sha256, $checksum), 404);
|
||||
|
||||
return response()->download($path, basename($document->file_name), [
|
||||
'X-Content-Type-Options' => 'nosniff', 'Cache-Control' => 'private, no-store',
|
||||
]);
|
||||
return app(VerifiedDocumentBinary::class)->respond($document);
|
||||
}
|
||||
|
||||
public function manage(MalwareScanner $scanner): Response
|
||||
@@ -437,8 +415,8 @@ class PortalServicesController extends Controller
|
||||
$id = DB::table('portal_resources')->insertGetId([...$fields, 'approved_by' => null, 'published' => false, 'created_at' => now(), 'updated_at' => now()]);
|
||||
$this->syncResourceLinks($id, $data['associations'] ?? []);
|
||||
$this->recordResourceRevision($id, 'created', $request->user()->id, 1);
|
||||
DB::table('documents')->where('id', $document->id)->update(['issuer' => $data['issuer'] ?: $document->issuer,
|
||||
'issued_on' => $data['document_date'] ?: $document->issued_on, 'rights_status' => $data['rights_status'],
|
||||
DB::table('documents')->where('id', $document->id)->update(['issuer' => ($data['issuer'] ?? null) ?: $document->issuer,
|
||||
'issued_on' => ($data['document_date'] ?? null) ?: $document->issued_on, 'rights_status' => $data['rights_status'],
|
||||
'data_classification' => $data['data_classification'] ?? $document->data_classification, 'updated_at' => now()]);
|
||||
$this->audit($request, $duplicate ? 'resource_registered_possible_duplicate' : 'resource_registered', 'portal_resources', $id);
|
||||
|
||||
@@ -475,8 +453,8 @@ class PortalServicesController extends Controller
|
||||
DB::table('portal_resource_links')->where('resource_id', $id)->delete();
|
||||
$this->syncResourceLinks($id, $data['associations'] ?? []);
|
||||
$this->recordResourceRevision($id, 'metadata_updated', $request->user()->id, $expectedVersion + 1);
|
||||
DB::table('documents')->where('id', $document->id)->update(['issuer' => $data['issuer'] ?: $document->issuer,
|
||||
'issued_on' => $data['document_date'] ?: $document->issued_on, 'rights_status' => $data['rights_status'],
|
||||
DB::table('documents')->where('id', $document->id)->update(['issuer' => ($data['issuer'] ?? null) ?: $document->issuer,
|
||||
'issued_on' => ($data['document_date'] ?? null) ?: $document->issued_on, 'rights_status' => $data['rights_status'],
|
||||
'data_classification' => $data['data_classification'] ?? $document->data_classification, 'updated_at' => now()]);
|
||||
$this->audit($request, 'resource_metadata_updated', 'portal_resources', $id);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user