Files
coolify/app/Jobs/PrepareFileDownloadJob.php
T
Andras Bacsai fa1895c99a feat(dashboard): add canvas view with active deployment overlay
Add a /dashboard/canvas page that renders every team server with its
resources and their running or queued deployments, backed by a new
ServerCanvasController::dashboard endpoint and a per-server usage
endpoint for zone headers. The dashboard remembers the list/canvas
choice and each section (projects, servers) its own table/grid view.

- Show Deploying/Queued pills on canvas cards and a foldable recent
  deployments panel; add shared CanvasControls component
- Allow backup downloads from the server host via the S3 download
  storage (PrepareFileDownloadJob accepts a null container)
- Extract backup toggle/run actions into ManagesDatabaseBackup and
  surface them in backup execution headers; merge S3 and retention
  sections into the general backup settings
- Move deployments indicator to the top bar and add a main nav
  resource menu with submenus; simplify breadcrumbs and settings
  layouts
- Add shared variables overview canvas and scheduled task modals
- Add feature tests for dashboard canvas, view modes, navbar
  submenus, backup S3 downloads and scheduled task modals
2026-10-14 23:55:28 +02:00

82 lines
3.2 KiB
PHP

<?php
namespace App\Jobs;
use App\Models\S3Storage;
use App\Models\Server;
use App\Services\ContainerFilesystemService;
use App\Services\FileDownloadStorageService;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
/**
* Uploads a download from the managed server to the instance download S3
* storage and stores a presigned link for the Livewire component to open.
* The source is a path in $container, or a file on the server host (for
* example a backup) when $container is null.
*/
class PrepareFileDownloadJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable;
public int $tries = 1;
public int $timeout = 3700;
public function __construct(
public string $downloadId,
public int $userId,
public int $serverId,
public ?string $container,
public string $path,
public bool $isDir,
public string $downloadName,
public int $s3StorageId,
) {}
public static function cacheKey(string $downloadId): string
{
return 'file-browser-s3-download:'.$downloadId;
}
public function handle(FileDownloadStorageService $downloads): void
{
try {
$storage = S3Storage::query()->whereTeamId(0)->where('is_usable', true)->find($this->s3StorageId);
if (! $storage) {
throw new \RuntimeException('The file download storage is not available.');
}
$server = Server::findOrFail($this->serverId);
$key = FileDownloadStorageService::newObjectKey();
// Queue the delete first, so a partial upload is removed as well.
DeleteFileDownloadJob::dispatch($storage->id, $key)->delay(now()->addHours(FileDownloadStorageService::OBJECT_TTL_HOURS));
$upload = $downloads->uploadUrl($storage, $key, $this->downloadName);
if ($this->container === null) {
instant_remote_process([FileDownloadStorageService::buildHostFileUploadCommand($this->path, $upload['url'], $upload['headers'])], $server, timeout: 3600);
} else {
(new ContainerFilesystemService($server, $this->container))->uploadToS3($this->path, $this->isDir, $upload['url'], $upload['headers']);
}
$this->store(['status' => 'ready', 'url' => $downloads->downloadUrl($storage, $key)]);
} catch (\Throwable $e) {
// The message can contain the S3 endpoint or a presigned URL; keep it in the log only.
Log::warning('S3 download failed', ['download_id' => $this->downloadId, 'error' => $e->getMessage()]);
$this->store(['status' => 'failed', 'message' => 'Download failed. The file could not be uploaded to the download storage. Try again, or ask your administrator to check the storage settings.']);
}
}
/**
* @param array<string, string> $result
*/
private function store(array $result): void
{
Cache::put(self::cacheKey($this->downloadId), ['user_id' => $this->userId, ...$result], now()->addMinutes(FileDownloadStorageService::LINK_TTL_MINUTES));
}
}