diff --git a/app/Http/Controllers/Api/TransferFilesController.php b/app/Http/Controllers/Api/TransferFilesController.php new file mode 100644 index 0000000..cf51b19 --- /dev/null +++ b/app/Http/Controllers/Api/TransferFilesController.php @@ -0,0 +1,104 @@ +attributes->get('service_caller') !== 'webmail') { + return response()->json(['message' => 'Forbidden.'], 403); + } + + $data = $request->validate([ + 'mailbox' => ['required', 'email', 'max:255'], + 'q' => ['nullable', 'string', 'max:120'], + 'page' => ['nullable', 'integer', 'min:1'], + 'sort' => ['nullable', 'in:newest,oldest,name,size'], + ]); + + try { + $user = $this->users->resolve((string) $data['mailbox']); + } catch (RuntimeException $e) { + return response()->json(['message' => $e->getMessage()], 422); + } + + $search = trim((string) ($data['q'] ?? '')); + $sort = (string) ($data['sort'] ?? 'newest'); + + $filesQuery = TransferFile::query() + ->whereHas('transfer', fn ($q) => $q + ->where('user_id', $user->id) + ->where('status', '!=', Transfer::STATUS_DELETED) + ->where(function ($query) { + $query->where('is_root_storage', true) + ->orWhere(function ($nested) { + $nested->where('is_folder', false)->where('is_root_storage', false); + }); + })) + ->when($search !== '', fn ($q) => $q->where('original_name', 'like', '%'.$search.'%')) + ->with(['transfer.qrCode']) + ->when($sort === 'oldest', fn ($q) => $q->oldest()) + ->when($sort === 'name', fn ($q) => $q->orderBy('original_name')) + ->when($sort === 'size', fn ($q) => $q->orderByDesc('size_bytes')) + ->when($sort === 'newest', fn ($q) => $q->latest()); + + $paginator = $filesQuery->paginate(30, ['*'], 'page', (int) ($data['page'] ?? 1)); + + $items = collect($paginator->items())->map(function (TransferFile $file) { + $transfer = $file->transfer; + $title = (string) ($transfer?->title ?? ''); + + return [ + 'id' => $file->id, + 'name' => $file->original_name, + 'size_bytes' => (int) $file->size_bytes, + 'mime_type' => $file->mime_type, + 'source' => $this->sourceFor($transfer), + 'public_url' => $transfer?->qrCode?->publicUrl(), + 'transfer_id' => $transfer?->id, + 'transfer_title' => $title !== '' ? $title : null, + 'created_at' => $file->created_at?->toIso8601String(), + ]; + })->values(); + + return response()->json([ + 'data' => $items, + 'meta' => [ + 'current_page' => $paginator->currentPage(), + 'last_page' => $paginator->lastPage(), + 'per_page' => $paginator->perPage(), + 'total' => $paginator->total(), + ], + ]); + } + + private function sourceFor(?Transfer $transfer): string + { + if ($transfer === null) { + return 'transfer'; + } + + if ($transfer->is_root_storage) { + return 'transfer'; + } + + $title = strtolower(trim($transfer->title)); + if (str_starts_with($title, 'email:') || str_starts_with($title, 'email attachment:')) { + return 'mail'; + } + + return 'transfer'; + } +} diff --git a/routes/api.php b/routes/api.php index fa466ae..dfaf7df 100644 --- a/routes/api.php +++ b/routes/api.php @@ -8,6 +8,7 @@ use Illuminate\Support\Facades\Route; Route::middleware('auth.service:transfer')->prefix('v1')->group(function () { Route::post('/transfers', [TransferController::class, 'store']); + Route::get('/transfers/files', [\App\Http\Controllers\Api\TransferFilesController::class, 'index']); Route::post('/transfers/upload/init', [ChunkedUploadController::class, 'init']); Route::post('/transfers/upload/chunk', [ChunkedUploadController::class, 'chunk']); Route::post('/transfers/upload/finalize', [ChunkedUploadController::class, 'finalize']);