Add asset import/export and local dev server setup
CI/CD Pipeline / deploy (push) Successful in 38s
CI/CD Pipeline / promote_stable (push) Successful in 2s

- Configure Vite dev server with localhost binding and public asset proxy
- Add npm scripts for concurrent Laravel/Vite development (dev:local, dev:test)
- Implement asset import/export in ACP via ZIP file upload/download
- Create AssetController for asset management endpoints
- Add asset management UI tab in admin panel
This commit is contained in:
2026-05-16 16:33:22 +02:00
parent a2fe31925f
commit d4d7934c89
7 changed files with 280 additions and 0 deletions
+101
View File
@@ -0,0 +1,101 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
use ZipArchive;
class AssetController extends Controller
{
public function export(): \Symfony\Component\HttpFoundation\StreamedResponse
{
$user = auth()->user();
if (!$user || !$user->roles()->where('name', 'ROLE_ADMIN')->exists()) {
abort(403, 'Forbidden');
}
$storagePublic = storage_path('app/public');
$zip = new ZipArchive();
$zipPath = storage_path('exports/assets-'.date('YmdHis').'.zip');
if (!is_dir(storage_path('exports'))) {
mkdir(storage_path('exports'), 0775, true);
}
if ($zip->open($zipPath, ZipArchive::CREATE) === true) {
$this->addDirectoryToZip($zip, $storagePublic, '');
$zip->close();
}
return response()->download($zipPath)->deleteFileAfterSend(true);
}
public function import(Request $request): JsonResponse
{
$user = $request->user();
if (!$user || !$user->roles()->where('name', 'ROLE_ADMIN')->exists()) {
return response()->json(['message' => 'Forbidden'], 403);
}
$data = $request->validate([
'file' => ['required', 'file', 'mimes:zip', 'max:104857600'],
]);
$file = $data['file'];
$zip = new ZipArchive();
$zipPath = $file->getPathname();
if ($zip->open($zipPath) !== true) {
return response()->json(['message' => 'Invalid zip file'], 400);
}
$storagePublic = storage_path('app/public');
for ($i = 0; $i < $zip->numFiles; $i++) {
$filename = $zip->getNameIndex($i);
$fileinfo = $zip->statIndex($i);
if ($fileinfo['crc'] == 0) {
continue;
}
$targetPath = $storagePublic.DIRECTORY_SEPARATOR.$filename;
$targetDir = dirname($targetPath);
if (!is_dir($targetDir)) {
mkdir($targetDir, 0775, true);
}
copy('zip://'.$zipPath.'#'.$filename, $targetPath);
}
$zip->close();
return response()->json([
'message' => 'Assets imported successfully',
]);
}
private function addDirectoryToZip(ZipArchive $zip, string $dir, string $zipPath): void
{
$files = scandir($dir);
foreach ($files as $file) {
if ($file === '.' || $file === '..') {
continue;
}
$path = $dir.DIRECTORY_SEPARATOR.$file;
$zipPath = $zipPath === '' ? $file : $zipPath.'/'.$file;
if (is_dir($path)) {
$zip->addEmptyDir($zipPath);
$this->addDirectoryToZip($zip, $path, $zipPath);
} else {
$zip->addFile($path, $zipPath);
}
}
}
}