61 lines
2.5 KiB
PHP
61 lines
2.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\GoodsReceipt;
|
|
use App\Models\ReceiptDocument;
|
|
use App\Models\User;
|
|
use App\Services\ReceiptDocuments;
|
|
use Illuminate\Http\RedirectResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Gate;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Symfony\Component\HttpFoundation\StreamedResponse;
|
|
|
|
class ReceiptDocumentController extends Controller
|
|
{
|
|
public function store(Request $request, GoodsReceipt $receipt, ReceiptDocuments $documents): RedirectResponse
|
|
{
|
|
$actor = $request->user('web');
|
|
abort_unless($actor instanceof User, 403);
|
|
Gate::authorize('view', $receipt);
|
|
abort_unless($documents->canRead($actor, $receipt), 403);
|
|
abort_unless($documents->canAdd($actor, $receipt), 403);
|
|
$file = $request->file('file');
|
|
abort_unless($file instanceof UploadedFile, 422);
|
|
$documents->add($actor, $receipt, $request->only(['operation_key', 'document_type']), $file);
|
|
|
|
return redirect('/recepcoes/'.$receipt->id.'#receipt-documents');
|
|
}
|
|
|
|
public function download(Request $request, GoodsReceipt $receipt, int $document, ReceiptDocuments $documents): StreamedResponse
|
|
{
|
|
$actor = $request->user('web');
|
|
abort_unless($actor instanceof User && $documents->canRead($actor, $receipt), 403);
|
|
Gate::authorize('view', $receipt);
|
|
abort_unless($documents->ready(), 503);
|
|
$file = ReceiptDocument::query()->where('goods_receipt_id', $receipt->id)->findOrFail($document);
|
|
$disk = Storage::disk('receipt_documents');
|
|
abort_unless($disk->exists($file->path), 404);
|
|
$stream = $disk->readStream($file->path);
|
|
abort_unless(is_resource($stream), 404);
|
|
$hash = hash_init('sha256');
|
|
hash_update_stream($hash, $stream);
|
|
if (! hash_equals($file->sha256, hash_final($hash))) {
|
|
fclose($stream);
|
|
abort(409, 'Documento indisponível para descarga. Solicite conferência ao responsável.');
|
|
}
|
|
rewind($stream);
|
|
|
|
return response()->streamDownload(function () use ($stream) {
|
|
try {
|
|
fpassthru($stream);
|
|
} finally {
|
|
fclose($stream);
|
|
}
|
|
}, $file->original_name, ['Content-Type' => 'application/octet-stream', 'X-Content-Type-Options' => 'nosniff',
|
|
'Cache-Control' => 'private, no-store', 'Content-Security-Policy' => "default-src 'none'; sandbox"]);
|
|
}
|
|
}
|