Files
panel-pelican-dev/app/Http/Controllers/Api/Remote/Backups/BackupRemoteUploadController.php

66 lines
2.4 KiB
PHP
Raw Normal View History

<?php
2024-03-12 22:39:16 -04:00
namespace App\Http\Controllers\Api\Remote\Backups;
2025-09-24 13:34:19 +02:00
use App\Exceptions\Http\HttpForbiddenException;
2026-01-16 21:52:24 +01:00
use App\Extensions\BackupAdapter\BackupAdapterService;
use App\Extensions\BackupAdapter\Schemas\S3BackupSchema;
2025-09-24 13:34:19 +02:00
use App\Http\Controllers\Controller;
use App\Models\Backup;
use App\Models\Node;
2025-09-24 13:34:19 +02:00
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\JsonResponse;
2025-09-24 13:34:19 +02:00
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
2025-09-24 13:34:19 +02:00
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
class BackupRemoteUploadController extends Controller
{
public const DEFAULT_MAX_PART_SIZE = 5 * 1024 * 1024 * 1024;
/**
* BackupRemoteUploadController constructor.
*/
2026-01-16 21:52:24 +01:00
public function __construct(private BackupAdapterService $backupService) {}
/**
* Returns the required presigned urls to upload a backup to S3 cloud storage.
*
2026-01-16 21:52:24 +01:00
* @throws BadRequestHttpException
* @throws ModelNotFoundException
2026-01-16 21:52:24 +01:00
* @throws HttpForbiddenException
* @throws ConflictHttpException
*/
public function __invoke(Request $request, string $backup): JsonResponse
{
/** @var Node $node */
$node = $request->attributes->get('node');
$size = (int) $request->query('size');
if (empty($size)) {
throw new BadRequestHttpException('A non-empty "size" query parameter must be provided.');
}
2026-01-16 21:52:24 +01:00
$backup = Backup::where('uuid', $backup)->firstOrFail();
// Check that the backup is "owned" by the node making the request. This avoids other nodes
// from messing with backups that they don't own.
2026-01-16 21:52:24 +01:00
if ($backup->server->node_id !== $node->id) {
throw new HttpForbiddenException('You do not have permission to access that backup.');
}
2026-01-16 21:52:24 +01:00
// Prevent backups that have already been completed from trying to be uploaded again.
if (!is_null($backup->completed_at)) {
2020-12-27 11:34:55 -08:00
throw new ConflictHttpException('This backup is already in a completed state.');
}
2026-01-16 21:52:24 +01:00
// Ensure we are using the S3 schema.
$schema = $this->backupService->get(collect($node->backupHosts)->first()->schema);
if (!$schema || !$schema instanceof S3BackupSchema) {
throw new BadRequestHttpException('The configured backup schema is not an S3 compatible.');
}
2026-01-16 21:52:24 +01:00
return new JsonResponse($schema->getUploadParts($backup, $size));
}
}