From d27f0c6f2a674876367e699908dfb44bce00dad5 Mon Sep 17 00:00:00 2001 From: Dane Everitt Date: Sat, 4 Apr 2020 12:26:39 -0700 Subject: [PATCH] Basic backend support to at least store a backup model in the DB --- .../Api/Client/Servers/BackupController.php | 25 ++++++- .../Servers/Backups/StoreBackupRequest.php | 2 +- app/Models/Backup.php | 28 +++++--- .../Eloquent/BackupRepository.php | 16 +++++ .../Backups/InitiateBackupService.php | 69 +++++++++++++++++++ .../Api/Client/BackupTransformer.php | 4 +- ...2020_04_03_230614_create_backups_table.php | 2 +- .../api/server/backups/createServerBackup.ts | 2 +- .../api/server/backups/getServerBackups.ts | 4 +- .../server/backups/CreateBackupButton.tsx | 4 +- 10 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 app/Repositories/Eloquent/BackupRepository.php create mode 100644 app/Services/Backups/InitiateBackupService.php diff --git a/app/Http/Controllers/Api/Client/Servers/BackupController.php b/app/Http/Controllers/Api/Client/Servers/BackupController.php index c0d598da4..64703dd85 100644 --- a/app/Http/Controllers/Api/Client/Servers/BackupController.php +++ b/app/Http/Controllers/Api/Client/Servers/BackupController.php @@ -3,6 +3,7 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers; use Pterodactyl\Models\Server; +use Pterodactyl\Services\Backups\InitiateBackupService; use Pterodactyl\Transformers\Api\Client\BackupTransformer; use Pterodactyl\Http\Controllers\Api\Client\ClientApiController; use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\GetBackupsRequest; @@ -10,9 +11,21 @@ use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\StoreBackupRequest; class BackupController extends ClientApiController { - public function __construct() + /** + * @var \Pterodactyl\Services\Backups\InitiateBackupService + */ + private $initiateBackupService; + + /** + * BackupController constructor. + * + * @param \Pterodactyl\Services\Backups\InitiateBackupService $initiateBackupService + */ + public function __construct(InitiateBackupService $initiateBackupService) { parent::__construct(); + + $this->initiateBackupService = $initiateBackupService; } /** @@ -35,9 +48,19 @@ class BackupController extends ClientApiController * * @param \Pterodactyl\Http\Requests\Api\Client\Servers\Backups\StoreBackupRequest $request * @param \Pterodactyl\Models\Server $server + * @return array + * + * @throws \Exception */ public function store(StoreBackupRequest $request, Server $server) { + $backup = $this->initiateBackupService + ->setIgnoredFiles($request->input('ignored')) + ->handle($server, $request->input('name')); + + return $this->fractal->item($backup) + ->transformWith($this->getTransformer(BackupTransformer::class)) + ->toArray(); } public function view() diff --git a/app/Http/Requests/Api/Client/Servers/Backups/StoreBackupRequest.php b/app/Http/Requests/Api/Client/Servers/Backups/StoreBackupRequest.php index b5ef7110e..145cb4bb1 100644 --- a/app/Http/Requests/Api/Client/Servers/Backups/StoreBackupRequest.php +++ b/app/Http/Requests/Api/Client/Servers/Backups/StoreBackupRequest.php @@ -21,7 +21,7 @@ class StoreBackupRequest extends ClientApiRequest public function rules(): array { return [ - 'name' => 'nullable|string|max:255', + 'name' => 'nullable|string|max:255|regex:/^[w\][\w\s_.-]*[\w]$/', 'ignore' => 'nullable|string', ]; } diff --git a/app/Models/Backup.php b/app/Models/Backup.php index 3384d98ec..0bb181be9 100644 --- a/app/Models/Backup.php +++ b/app/Models/Backup.php @@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\SoftDeletes; * @property int $server_id * @property int $uuid * @property string $name - * @property string $ignore + * @property string $ignored_files * @property string $disk * @property string|null $sha256_hash * @property int $bytes @@ -52,15 +52,25 @@ class Backup extends Model ]; /** - * Returns dates from this model as immutable Carbon instances. - * - * @param mixed $value - * @return \Carbon\CarbonImmutable + * @var array */ - protected function asDateTime($value) - { - return $this->asImmutableDateTime($value); - } + protected $attributes = [ + 'sha256_hash' => null, + 'bytes' => 0, + ]; + + /** + * @var array + */ + public static $validationRules = [ + 'server_id' => 'bail|required|numeric|exists:servers,id', + 'uuid' => 'required|uuid', + 'name' => 'required|string|regex:/^[w\][\w\s_.-]*[\w]$/', + 'ignored_files' => 'string', + 'disk' => 'required|string', + 'sha256_hash' => 'nullable|string', + 'bytes' => 'numeric', + ]; /** * @return \Illuminate\Database\Eloquent\Relations\BelongsTo diff --git a/app/Repositories/Eloquent/BackupRepository.php b/app/Repositories/Eloquent/BackupRepository.php new file mode 100644 index 000000000..2ff206325 --- /dev/null +++ b/app/Repositories/Eloquent/BackupRepository.php @@ -0,0 +1,16 @@ +repository = $repository; + } + + /** + * Sets the files to be ignored by this backup. + * + * @param string|null $ignored + * @return $this + */ + public function setIgnoredFiles(?string $ignored) + { + $this->ignoredFiles = $ignored; + + return $this; + } + + /** + * Initiates the backup process for a server on the daemon. + * + * @param \Pterodactyl\Models\Server $server + * @param string|null $name + * @return \Pterodactyl\Models\Backup + * + * @throws \Exception + */ + public function handle(Server $server, string $name = null): Backup + { + /** @var \Pterodactyl\Models\Backup $backup */ + $backup = $this->repository->create([ + 'server_id' => $server->id, + 'uuid' => Uuid::uuid4()->toString(), + 'name' => Str::lower(str_replace(' ', '_', trim($name))) ?: sprintf('backup_%s', CarbonImmutable::create()->format('YmdHis')), + 'ignored_files' => $this->ignoredFiles ?? '', + 'disk' => 'local', + ], true, true); + + return $backup; + } +} diff --git a/app/Transformers/Api/Client/BackupTransformer.php b/app/Transformers/Api/Client/BackupTransformer.php index 2312b68d3..53966fc77 100644 --- a/app/Transformers/Api/Client/BackupTransformer.php +++ b/app/Transformers/Api/Client/BackupTransformer.php @@ -23,11 +23,11 @@ class BackupTransformer extends BaseClientTransformer return [ 'uuid' => $backup->uuid, 'name' => $backup->name, - 'ignore' => $backup->ignore, + 'ignored_files' => $backup->ignored_files, 'sha256_hash' => $backup->sha256_hash, 'bytes' => $backup->bytes, 'created_at' => $backup->created_at->toIso8601String(), - 'completed_at' => $backup->completed_at->toIso8601String(), + 'completed_at' => $backup->completed_at ? $backup->completed_at->toIso8601String() : null, ]; } } diff --git a/database/migrations/2020_04_03_230614_create_backups_table.php b/database/migrations/2020_04_03_230614_create_backups_table.php index db1a3ee12..63dad39a0 100644 --- a/database/migrations/2020_04_03_230614_create_backups_table.php +++ b/database/migrations/2020_04_03_230614_create_backups_table.php @@ -18,7 +18,7 @@ class CreateBackupsTable extends Migration $table->unsignedInteger('server_id'); $table->char('uuid', 36); $table->string('name'); - $table->text('ignored'); + $table->text('ignored_files'); $table->string('disk'); $table->string('sha256_hash')->nullable(); $table->integer('bytes')->default(0); diff --git a/resources/scripts/api/server/backups/createServerBackup.ts b/resources/scripts/api/server/backups/createServerBackup.ts index 4f0754a54..2616c2bf3 100644 --- a/resources/scripts/api/server/backups/createServerBackup.ts +++ b/resources/scripts/api/server/backups/createServerBackup.ts @@ -6,7 +6,7 @@ export default (uuid: string, name?: string, ignore?: string): Promise resolve(rawDataToServerBackup(data.attributes))) + .then(({ data }) => resolve(rawDataToServerBackup(data))) .catch(reject); }); }; diff --git a/resources/scripts/api/server/backups/getServerBackups.ts b/resources/scripts/api/server/backups/getServerBackups.ts index 6263bcf3a..49f3aa24c 100644 --- a/resources/scripts/api/server/backups/getServerBackups.ts +++ b/resources/scripts/api/server/backups/getServerBackups.ts @@ -3,7 +3,7 @@ import http, { FractalResponseData, getPaginationSet, PaginatedResult } from '@/ export interface ServerBackup { uuid: string; name: string; - contents: string; + ignoredFiles: string; sha256Hash: string; bytes: number; createdAt: Date; @@ -13,7 +13,7 @@ export interface ServerBackup { export const rawDataToServerBackup = ({ attributes }: FractalResponseData): ServerBackup => ({ uuid: attributes.uuid, name: attributes.name, - contents: attributes.contents, + ignoredFiles: attributes.ignored_files, sha256Hash: attributes.sha256_hash, bytes: attributes.bytes, createdAt: new Date(attributes.created_at), diff --git a/resources/scripts/components/server/backups/CreateBackupButton.tsx b/resources/scripts/components/server/backups/CreateBackupButton.tsx index 256a88325..c851bf922 100644 --- a/resources/scripts/components/server/backups/CreateBackupButton.tsx +++ b/resources/scripts/components/server/backups/CreateBackupButton.tsx @@ -96,7 +96,9 @@ export default ({ onBackupGenerated }: Props) => { onSubmit={submit} initialValues={{ name: '', ignored: '' }} validationSchema={object().shape({ - name: string().max(255), + name: string().required() + .matches(/^[w\][\w\s_.-]*[\w]$/, 'Backup name must only contain alpha-numeric characters, spaces, underscores, dashes, and periods. The name must start and end with an alpha-numeric character.') + .max(255), ignored: string(), })} >