Basic backend support to at least store a backup model in the DB

This commit is contained in:
Dane Everitt 2020-04-04 12:26:39 -07:00
parent 6d426e45d9
commit d27f0c6f2a
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
10 changed files with 138 additions and 18 deletions

View file

@ -3,6 +3,7 @@
namespace Pterodactyl\Http\Controllers\Api\Client\Servers; namespace Pterodactyl\Http\Controllers\Api\Client\Servers;
use Pterodactyl\Models\Server; use Pterodactyl\Models\Server;
use Pterodactyl\Services\Backups\InitiateBackupService;
use Pterodactyl\Transformers\Api\Client\BackupTransformer; use Pterodactyl\Transformers\Api\Client\BackupTransformer;
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController; use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;
use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\GetBackupsRequest; 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 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(); 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\Http\Requests\Api\Client\Servers\Backups\StoreBackupRequest $request
* @param \Pterodactyl\Models\Server $server * @param \Pterodactyl\Models\Server $server
* @return array
*
* @throws \Exception
*/ */
public function store(StoreBackupRequest $request, Server $server) 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() public function view()

View file

@ -21,7 +21,7 @@ class StoreBackupRequest extends ClientApiRequest
public function rules(): array public function rules(): array
{ {
return [ return [
'name' => 'nullable|string|max:255', 'name' => 'nullable|string|max:255|regex:/^[w\][\w\s_.-]*[\w]$/',
'ignore' => 'nullable|string', 'ignore' => 'nullable|string',
]; ];
} }

View file

@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\SoftDeletes;
* @property int $server_id * @property int $server_id
* @property int $uuid * @property int $uuid
* @property string $name * @property string $name
* @property string $ignore * @property string $ignored_files
* @property string $disk * @property string $disk
* @property string|null $sha256_hash * @property string|null $sha256_hash
* @property int $bytes * @property int $bytes
@ -52,15 +52,25 @@ class Backup extends Model
]; ];
/** /**
* Returns dates from this model as immutable Carbon instances. * @var array
*
* @param mixed $value
* @return \Carbon\CarbonImmutable
*/ */
protected function asDateTime($value) protected $attributes = [
{ 'sha256_hash' => null,
return $this->asImmutableDateTime($value); '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 * @return \Illuminate\Database\Eloquent\Relations\BelongsTo

View file

@ -0,0 +1,16 @@
<?php
namespace Pterodactyl\Repositories\Eloquent;
use Pterodactyl\Models\Backup;
class BackupRepository extends EloquentRepository
{
/**
* @return string
*/
public function model()
{
return Backup::class;
}
}

View file

@ -0,0 +1,69 @@
<?php
namespace Pterodactyl\Services\Backups;
use Ramsey\Uuid\Uuid;
use Carbon\CarbonImmutable;
use Illuminate\Support\Str;
use Pterodactyl\Models\Backup;
use Pterodactyl\Models\Server;
use Pterodactyl\Repositories\Eloquent\BackupRepository;
class InitiateBackupService
{
/**
* @var string|null
*/
private $ignoredFiles;
/**
* @var \Pterodactyl\Repositories\Eloquent\BackupRepository
*/
private $repository;
/**
* InitiateBackupService constructor.
*
* @param \Pterodactyl\Repositories\Eloquent\BackupRepository $repository
*/
public function __construct(BackupRepository $repository)
{
$this->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;
}
}

View file

@ -23,11 +23,11 @@ class BackupTransformer extends BaseClientTransformer
return [ return [
'uuid' => $backup->uuid, 'uuid' => $backup->uuid,
'name' => $backup->name, 'name' => $backup->name,
'ignore' => $backup->ignore, 'ignored_files' => $backup->ignored_files,
'sha256_hash' => $backup->sha256_hash, 'sha256_hash' => $backup->sha256_hash,
'bytes' => $backup->bytes, 'bytes' => $backup->bytes,
'created_at' => $backup->created_at->toIso8601String(), 'created_at' => $backup->created_at->toIso8601String(),
'completed_at' => $backup->completed_at->toIso8601String(), 'completed_at' => $backup->completed_at ? $backup->completed_at->toIso8601String() : null,
]; ];
} }
} }

View file

@ -18,7 +18,7 @@ class CreateBackupsTable extends Migration
$table->unsignedInteger('server_id'); $table->unsignedInteger('server_id');
$table->char('uuid', 36); $table->char('uuid', 36);
$table->string('name'); $table->string('name');
$table->text('ignored'); $table->text('ignored_files');
$table->string('disk'); $table->string('disk');
$table->string('sha256_hash')->nullable(); $table->string('sha256_hash')->nullable();
$table->integer('bytes')->default(0); $table->integer('bytes')->default(0);

View file

@ -6,7 +6,7 @@ export default (uuid: string, name?: string, ignore?: string): Promise<ServerBac
http.post(`/api/client/servers/${uuid}/backups`, { http.post(`/api/client/servers/${uuid}/backups`, {
name, ignore, name, ignore,
}) })
.then(({ data }) => resolve(rawDataToServerBackup(data.attributes))) .then(({ data }) => resolve(rawDataToServerBackup(data)))
.catch(reject); .catch(reject);
}); });
}; };

View file

@ -3,7 +3,7 @@ import http, { FractalResponseData, getPaginationSet, PaginatedResult } from '@/
export interface ServerBackup { export interface ServerBackup {
uuid: string; uuid: string;
name: string; name: string;
contents: string; ignoredFiles: string;
sha256Hash: string; sha256Hash: string;
bytes: number; bytes: number;
createdAt: Date; createdAt: Date;
@ -13,7 +13,7 @@ export interface ServerBackup {
export const rawDataToServerBackup = ({ attributes }: FractalResponseData): ServerBackup => ({ export const rawDataToServerBackup = ({ attributes }: FractalResponseData): ServerBackup => ({
uuid: attributes.uuid, uuid: attributes.uuid,
name: attributes.name, name: attributes.name,
contents: attributes.contents, ignoredFiles: attributes.ignored_files,
sha256Hash: attributes.sha256_hash, sha256Hash: attributes.sha256_hash,
bytes: attributes.bytes, bytes: attributes.bytes,
createdAt: new Date(attributes.created_at), createdAt: new Date(attributes.created_at),

View file

@ -96,7 +96,9 @@ export default ({ onBackupGenerated }: Props) => {
onSubmit={submit} onSubmit={submit}
initialValues={{ name: '', ignored: '' }} initialValues={{ name: '', ignored: '' }}
validationSchema={object().shape({ 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(), ignored: string(),
})} })}
> >