Add Files page upload flow with manual folders and duplicate handling.
Deploy Ladill Transfer / deploy (push) Successful in 44s
Deploy Ladill Transfer / deploy (push) Successful in 44s
Users can create folders, upload files or folders, and choose replace or keep both on name conflicts instead of auto-grouping by transfer. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,6 +5,8 @@ namespace App\Http\Controllers\Transfer;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Transfer;
|
||||
use App\Models\TransferFile;
|
||||
use App\Models\User;
|
||||
use App\Services\Transfer\FileStorageService;
|
||||
use App\Services\Transfer\TransferRecipientMailService;
|
||||
use App\Services\Transfer\TransferService;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -21,6 +23,7 @@ class FilesController extends Controller
|
||||
{
|
||||
public function __construct(
|
||||
private TransferService $transfers,
|
||||
private FileStorageService $storage,
|
||||
) {}
|
||||
|
||||
public function index(Request $request): View
|
||||
@@ -35,6 +38,7 @@ class FilesController extends Controller
|
||||
if ($folderId) {
|
||||
$folderTransfer = Transfer::query()
|
||||
->where('user_id', $account->id)
|
||||
->where('is_folder', true)
|
||||
->where('status', '!=', Transfer::STATUS_DELETED)
|
||||
->findOrFail($folderId);
|
||||
}
|
||||
@@ -42,8 +46,9 @@ class FilesController extends Controller
|
||||
$filesQuery = TransferFile::query()
|
||||
->whereHas('transfer', fn ($q) => $q
|
||||
->where('user_id', $account->id)
|
||||
->where('status', '!=', Transfer::STATUS_DELETED))
|
||||
->when($folderTransfer, fn ($q) => $q->where('transfer_id', $folderTransfer->id))
|
||||
->where('status', '!=', Transfer::STATUS_DELETED)
|
||||
->when($folderTransfer, fn ($inner) => $inner->whereKey($folderTransfer->id),
|
||||
fn ($inner) => $inner->where('is_folder', false)))
|
||||
->when($search !== '', fn ($q) => $q->where('original_name', 'like', '%'.$search.'%'))
|
||||
->with(['transfer.qrCode'])
|
||||
->when($sort === 'oldest', fn ($q) => $q->oldest())
|
||||
@@ -56,8 +61,8 @@ class FilesController extends Controller
|
||||
|
||||
$folders = Transfer::query()
|
||||
->where('user_id', $account->id)
|
||||
->where('is_folder', true)
|
||||
->where('status', '!=', Transfer::STATUS_DELETED)
|
||||
->whereHas('files')
|
||||
->withCount('files')
|
||||
->when($search !== '', fn ($q) => $q->where('title', 'like', '%'.$search.'%'))
|
||||
->orderBy('title')
|
||||
@@ -65,9 +70,12 @@ class FilesController extends Controller
|
||||
|
||||
$moveTargets = Transfer::query()
|
||||
->where('user_id', $account->id)
|
||||
->accessible()
|
||||
->where('status', '!=', Transfer::STATUS_DELETED)
|
||||
->where(function ($query) {
|
||||
$query->where('is_folder', true)->orWhere('is_root_storage', true);
|
||||
})
|
||||
->orderBy('title')
|
||||
->get(['id', 'title']);
|
||||
->get(['id', 'title', 'is_root_storage']);
|
||||
|
||||
$storageBytes = Transfer::query()
|
||||
->where('user_id', $account->id)
|
||||
@@ -184,14 +192,17 @@ class FilesController extends Controller
|
||||
|
||||
$destination = Transfer::query()
|
||||
->where('user_id', ladill_account()->id)
|
||||
->accessible()
|
||||
->where('status', '!=', Transfer::STATUS_DELETED)
|
||||
->where(function ($query) {
|
||||
$query->where('is_folder', true)->orWhere('is_root_storage', true);
|
||||
})
|
||||
->findOrFail($data['destination']);
|
||||
|
||||
$files = $this->authorizedFiles($data['files']);
|
||||
$this->transfers->moveFiles($destination, $files->all());
|
||||
|
||||
return redirect()
|
||||
->route('transfer.files.index', ['folder' => $destination->id])
|
||||
->route('transfer.files.index', $destination->is_folder ? ['folder' => $destination->id] : [])
|
||||
->with('success', $files->count().' file'.($files->count() === 1 ? '' : 's').' moved to '.$destination->title.'.');
|
||||
}
|
||||
|
||||
@@ -273,6 +284,105 @@ class FilesController extends Controller
|
||||
return redirect()->away($url);
|
||||
}
|
||||
|
||||
public function storeFolder(Request $request): RedirectResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'name' => 'required|string|max:120',
|
||||
'folder' => 'nullable|integer|exists:transfers,id',
|
||||
]);
|
||||
|
||||
$account = ladill_account();
|
||||
$parent = null;
|
||||
if (! empty($data['folder'])) {
|
||||
$parent = Transfer::query()
|
||||
->where('user_id', $account->id)
|
||||
->where('is_folder', true)
|
||||
->findOrFail($data['folder']);
|
||||
}
|
||||
|
||||
try {
|
||||
$folder = $this->storage->createFolder($account, $data['name'], $parent);
|
||||
} catch (RuntimeException $e) {
|
||||
return back()->with('error', $e->getMessage());
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->route('transfer.files.index', ['folder' => $folder->id])
|
||||
->with('success', 'Folder created.');
|
||||
}
|
||||
|
||||
public function checkUpload(Request $request): JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'filenames' => 'required|array|min:1',
|
||||
'filenames.*' => 'required|string|max:255',
|
||||
'folder' => 'nullable|integer|exists:transfers,id',
|
||||
]);
|
||||
|
||||
$account = ladill_account();
|
||||
$folder = $this->resolveUploadFolder($account, $data['folder'] ?? null);
|
||||
|
||||
$conflicts = $this->storage->findConflicts(
|
||||
$account,
|
||||
$folder,
|
||||
$data['filenames'],
|
||||
);
|
||||
|
||||
return response()->json(['conflicts' => $conflicts]);
|
||||
}
|
||||
|
||||
public function storeUpload(Request $request): RedirectResponse|JsonResponse
|
||||
{
|
||||
$data = $request->validate([
|
||||
'files' => 'required|array|min:1',
|
||||
'files.*' => 'required|file',
|
||||
'folder' => 'nullable|integer|exists:transfers,id',
|
||||
'resolutions' => 'nullable|array',
|
||||
'resolutions.*' => 'in:replace,keep_both',
|
||||
]);
|
||||
|
||||
$account = ladill_account();
|
||||
$folder = $this->resolveUploadFolder($account, $data['folder'] ?? null);
|
||||
$files = array_values($request->file('files', []) ?? []);
|
||||
|
||||
try {
|
||||
$uploaded = $this->storage->uploadFiles(
|
||||
$account,
|
||||
$folder,
|
||||
$files,
|
||||
$data['resolutions'] ?? [],
|
||||
);
|
||||
} catch (RuntimeException $e) {
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json(['message' => $e->getMessage()], 422);
|
||||
}
|
||||
|
||||
return back()->with('error', $e->getMessage());
|
||||
}
|
||||
|
||||
$count = count($uploaded);
|
||||
$message = $count.' file'.($count === 1 ? '' : 's').' uploaded.';
|
||||
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json(['message' => $message, 'count' => $count]);
|
||||
}
|
||||
|
||||
return back()->with('success', $message);
|
||||
}
|
||||
|
||||
private function resolveUploadFolder(User $user, ?int $folderId): ?Transfer
|
||||
{
|
||||
if ($folderId === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return Transfer::query()
|
||||
->where('user_id', $user->id)
|
||||
->where('is_folder', true)
|
||||
->where('status', '!=', Transfer::STATUS_DELETED)
|
||||
->findOrFail($folderId);
|
||||
}
|
||||
|
||||
/** @param array<int|string>|null $ids */
|
||||
private function authorizedFiles(?array $ids): Collection
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user