Files
ladill-transfer/app/Http/Controllers/Transfer/TransferController.php
T
isaaccladandCursor e76955eaa4
Deploy Ladill Transfer / deploy (push) Successful in 40s
Reduce Transfer storage price to GHS 0.15 per GB per month.
Updates config default, env examples, and removes hardcoded GHS 1.00 copy on the dashboard.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-08 10:45:12 +00:00

158 lines
5.2 KiB
PHP

<?php
namespace App\Http\Controllers\Transfer;
use App\Http\Controllers\Controller;
use App\Models\Transfer;
use App\Services\Qr\QrImageGeneratorService;
use App\Services\Qr\QrPdfExporter;
use App\Services\Transfer\TransferService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\View\View;
use RuntimeException;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\StreamedResponse;
class TransferController extends Controller
{
public function __construct(
private TransferService $transfers,
private QrImageGeneratorService $imageGenerator,
private QrPdfExporter $pdfExporter,
) {}
public function index(Request $request): View
{
$account = ladill_account();
$transfers = Transfer::query()
->where('user_id', $account->id)
->where('status', Transfer::STATUS_ACTIVE)
->with(['qrCode', 'files'])
->latest()
->paginate(20);
return view('transfer.transfers.index', compact('transfers'));
}
public function create(): View
{
return view('transfer.transfers.create', [
'defaultRetentionDays' => (int) config('transfer.default_retention_days', 30),
'maxFiles' => (int) config('transfer.max_files_per_transfer', 20),
'pricePerGb' => (float) config('transfer.price_per_gb_month', 0.15),
]);
}
public function store(Request $request): RedirectResponse
{
$account = ladill_account();
$data = $request->validate([
'title' => 'required|string|max:120',
'message' => 'nullable|string|max:2000',
'password' => 'nullable|string|min:4|max:64',
'retention_days' => 'nullable|integer|min:1|max:365',
'files' => 'required|array|min:1',
'files.*' => 'required|file|max:'.((int) config('transfer.max_file_bytes', 524288000) / 1024),
]);
try {
$transfer = $this->transfers->create($account, $data, $request->file('files', []));
} catch (RuntimeException $e) {
return back()->withInput()->with('error', $e->getMessage());
}
return redirect()
->route('transfer.transfers.show', $transfer)
->with('success', 'Transfer created. Share the link or QR code with recipients.');
}
public function show(Transfer $transfer): View
{
$this->authorizeTransfer($transfer);
$transfer->load(['files', 'qrCode']);
$previewDataUri = $transfer->qrCode
? $this->imageGenerator->previewDataUri($transfer->qrCode)
: null;
return view('transfer.transfers.show', [
'transfer' => $transfer,
'previewDataUri' => $previewDataUri,
]);
}
public function destroy(Transfer $transfer): RedirectResponse
{
$this->authorizeTransfer($transfer);
$this->transfers->delete($transfer);
return redirect()
->route('transfer.transfers.index')
->with('success', 'Transfer deleted.');
}
public function preview(Transfer $transfer): Response
{
$this->authorizeTransfer($transfer);
$qrCode = $transfer->qrCode;
abort_unless($qrCode, 404);
$qrCode = $this->imageGenerator->ensureValidImages($qrCode);
$bytes = $this->imageGenerator->normalizeStoredPng($qrCode->png_path);
if ($bytes === null) {
$bytes = $this->imageGenerator->renderPng($qrCode->encodedPayload(), $qrCode->style());
$this->imageGenerator->generateAndStore($qrCode);
}
return response($bytes, 200, [
'Content-Type' => 'image/png',
'Cache-Control' => 'private, max-age=3600',
]);
}
public function download(Transfer $transfer, string $format): StreamedResponse
{
$this->authorizeTransfer($transfer);
$qrCode = $transfer->qrCode;
abort_unless($qrCode, 404);
$qrCode = $this->imageGenerator->ensureValidImages($qrCode);
$filename = Str::slug($qrCode->label).'-qr.'.($format === 'svg' ? 'svg' : 'png');
if ($format === 'png') {
$bytes = $this->imageGenerator->normalizeStoredPng($qrCode->png_path);
if ($bytes === null) {
$bytes = $this->imageGenerator->renderPng($qrCode->encodedPayload(), $qrCode->style());
$this->imageGenerator->generateAndStore($qrCode);
}
return response()->streamDownload(fn () => print($bytes), $filename, [
'Content-Type' => 'image/png',
]);
}
if ($format === 'svg') {
abort_unless($qrCode->svg_path, 404);
return response()->streamDownload(
fn () => print(file_get_contents(storage_path('app/private/qr/'.$qrCode->svg_path))),
$filename,
['Content-Type' => 'image/svg+xml'],
);
}
return $this->pdfExporter->download($qrCode);
}
private function authorizeTransfer(Transfer $transfer): void
{
abort_unless($transfer->user_id === ladill_account()->id, 403);
}
}