Files
ladill-transfer/app/Http/Controllers/Api/TransferFilesController.php
T
isaaccladandCursor ea58a13fce
Deploy Ladill Transfer / deploy (push) Successful in 1m8s
Add service API to list mailbox files for Ladill Mail.
Expose GET /api/v1/transfers/files so webmail can sync the mobile Files tab with Transfer storage.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-14 00:39:37 +00:00

105 lines
3.8 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\Transfer;
use App\Models\TransferFile;
use App\Services\Identity\MailboxUserResolver;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use RuntimeException;
/** Service-to-service file listing for Ladill Mail (synced with Transfer Files). */
class TransferFilesController extends Controller
{
public function __construct(private MailboxUserResolver $users) {}
public function index(Request $request): JsonResponse
{
if ($request->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';
}
}