Merge branch 'develop' into feature/server-transfers-actually
This commit is contained in:
commit
fd4de9168a
49 changed files with 1000 additions and 37 deletions
77
app/Http/Controllers/Api/Client/Servers/BackupController.php
Normal file
77
app/Http/Controllers/Api/Client/Servers/BackupController.php
Normal file
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
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;
|
||||
use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\StoreBackupRequest;
|
||||
|
||||
class BackupController extends ClientApiController
|
||||
{
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all of the backups for a given server instance in a paginated
|
||||
* result set.
|
||||
*
|
||||
* @param \Pterodactyl\Http\Requests\Api\Client\Servers\Backups\GetBackupsRequest $request
|
||||
* @param \Pterodactyl\Models\Server $server
|
||||
* @return array
|
||||
*/
|
||||
public function index(GetBackupsRequest $request, Server $server)
|
||||
{
|
||||
return $this->fractal->collection($server->backups()->paginate(20))
|
||||
->transformWith($this->getTransformer(BackupTransformer::class))
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the backup process for a server.
|
||||
*
|
||||
* @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()
|
||||
{
|
||||
}
|
||||
|
||||
public function update()
|
||||
{
|
||||
}
|
||||
|
||||
public function delete()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Backups;
|
||||
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||
|
||||
class GetBackupsRequest extends ClientApiRequest
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function permission()
|
||||
{
|
||||
return Permission::ACTION_BACKUP_READ;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Http\Requests\Api\Client\Servers\Backups;
|
||||
|
||||
use Pterodactyl\Models\Permission;
|
||||
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;
|
||||
|
||||
class StoreBackupRequest extends ClientApiRequest
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function permission()
|
||||
{
|
||||
return Permission::ACTION_BACKUP_CREATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'name' => 'nullable|string|max:255',
|
||||
'ignore' => 'nullable|string',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ namespace Pterodactyl\Models;
|
|||
* @property \Pterodactyl\Models\Server|null $server
|
||||
* @property \Pterodactyl\Models\Node $node
|
||||
*/
|
||||
class Allocation extends Validable
|
||||
class Allocation extends Model
|
||||
{
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
@ -75,7 +75,7 @@ class Allocation extends Validable
|
|||
/**
|
||||
* Accessor to automatically provide the IP alias if defined.
|
||||
*
|
||||
* @param null|string $value
|
||||
* @param string|null $value
|
||||
* @return string
|
||||
*/
|
||||
public function getAliasAttribute($value)
|
||||
|
@ -86,7 +86,7 @@ class Allocation extends Validable
|
|||
/**
|
||||
* Accessor to quickly determine if this allocation has an alias.
|
||||
*
|
||||
* @param null|string $value
|
||||
* @param string|null $value
|
||||
* @return bool
|
||||
*/
|
||||
public function getHasAliasAttribute($value)
|
||||
|
|
|
@ -16,7 +16,7 @@ use Pterodactyl\Services\Acl\Api\AdminAcl;
|
|||
* @property \Carbon\Carbon $created_at
|
||||
* @property \Carbon\Carbon $updated_at
|
||||
*/
|
||||
class ApiKey extends Validable
|
||||
class ApiKey extends Model
|
||||
{
|
||||
const RESOURCE_NAME = 'api_key';
|
||||
|
||||
|
|
82
app/Models/Backup.php
Normal file
82
app/Models/Backup.php
Normal file
|
@ -0,0 +1,82 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\SoftDeletes;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $server_id
|
||||
* @property int $uuid
|
||||
* @property string $name
|
||||
* @property string $ignored_files
|
||||
* @property string $disk
|
||||
* @property string|null $sha256_hash
|
||||
* @property int $bytes
|
||||
* @property \Carbon\CarbonImmutable|null $completed_at
|
||||
* @property \Carbon\CarbonImmutable $created_at
|
||||
* @property \Carbon\CarbonImmutable $updated_at
|
||||
* @property \Carbon\CarbonImmutable|null $deleted_at
|
||||
*
|
||||
* @property \Pterodactyl\Models\Server $server
|
||||
*/
|
||||
class Backup extends Model
|
||||
{
|
||||
use SoftDeletes;
|
||||
|
||||
const RESOURCE_NAME = 'backup';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'backups';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $immutableDates = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'id' => 'int',
|
||||
'bytes' => 'int',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $dates = [
|
||||
'completed_at',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
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',
|
||||
'ignored_files' => 'string',
|
||||
'disk' => 'required|string',
|
||||
'sha256_hash' => 'nullable|string',
|
||||
'bytes' => 'numeric',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
*/
|
||||
public function server()
|
||||
{
|
||||
return $this->belongsTo(Server::class);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@ namespace Pterodactyl\Models;
|
|||
|
||||
use Znck\Eloquent\Traits\BelongsToThrough;
|
||||
|
||||
class DaemonKey extends Validable
|
||||
class DaemonKey extends Model
|
||||
{
|
||||
use BelongsToThrough;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
class Database extends Validable
|
||||
class Database extends Model
|
||||
{
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
class DatabaseHost extends Validable
|
||||
class DatabaseHost extends Model
|
||||
{
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace Pterodactyl\Models;
|
|||
* @property \Pterodactyl\Models\Egg|null $scriptFrom
|
||||
* @property \Pterodactyl\Models\Egg|null $configFrom
|
||||
*/
|
||||
class Egg extends Validable
|
||||
class Egg extends Model
|
||||
{
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
class EggVariable extends Validable
|
||||
class EggVariable extends Model
|
||||
{
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
class Location extends Validable
|
||||
class Location extends Model
|
||||
{
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
|
|
@ -5,11 +5,18 @@ namespace Pterodactyl\Models;
|
|||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\Rule;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Contracts\Validation\Factory;
|
||||
use Illuminate\Database\Eloquent\Model as IlluminateModel;
|
||||
|
||||
abstract class Validable extends Model
|
||||
abstract class Model extends IlluminateModel
|
||||
{
|
||||
/**
|
||||
* Set to true to return immutable Carbon date instances from the model.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $immutableDates = false;
|
||||
|
||||
/**
|
||||
* Determines if the model should undergo data validation before it is saved
|
||||
* to the database.
|
||||
|
@ -47,7 +54,7 @@ abstract class Validable extends Model
|
|||
|
||||
static::$validatorFactory = Container::getInstance()->make(Factory::class);
|
||||
|
||||
static::saving(function (Validable $model) {
|
||||
static::saving(function (Model $model) {
|
||||
return $model->validate();
|
||||
});
|
||||
}
|
||||
|
@ -148,4 +155,19 @@ abstract class Validable extends Model
|
|||
)
|
||||
)->passes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a timestamp as DateTime object.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return \Illuminate\Support\Carbon|\Carbon\CarbonImmutable
|
||||
*/
|
||||
protected function asDateTime($value)
|
||||
{
|
||||
if (! $this->immutableDates) {
|
||||
return parent::asDateTime($value);
|
||||
}
|
||||
|
||||
return parent::asDateTime($value)->toImmutable();
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ namespace Pterodactyl\Models;
|
|||
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Egg[] $eggs
|
||||
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Pack[] $packs
|
||||
*/
|
||||
class Nest extends Validable
|
||||
class Nest extends Model
|
||||
{
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
|
|
@ -32,9 +32,10 @@ use Pterodactyl\Models\Traits\Searchable;
|
|||
* @property \Pterodactyl\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers
|
||||
* @property \Pterodactyl\Models\Allocation[]|\Illuminate\Database\Eloquent\Collection $allocations
|
||||
*/
|
||||
class Node extends Validable
|
||||
class Node extends Model
|
||||
{
|
||||
use Notifiable, Searchable;
|
||||
use Notifiable;
|
||||
use Searchable;
|
||||
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
|
|
@ -20,7 +20,7 @@ use Pterodactyl\Models\Traits\Searchable;
|
|||
* @property \Pterodactyl\Models\Egg|null $egg
|
||||
* @property \Illuminate\Database\Eloquent\Collection|\Pterodactyl\Models\Server[] $servers
|
||||
*/
|
||||
class Pack extends Validable
|
||||
class Pack extends Model
|
||||
{
|
||||
use Searchable;
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ namespace Pterodactyl\Models;
|
|||
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class Permission extends Validable
|
||||
class Permission extends Model
|
||||
{
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
@ -37,6 +37,12 @@ class Permission extends Validable
|
|||
const ACTION_USER_UPDATE = 'user.update';
|
||||
const ACTION_USER_DELETE = 'user.delete';
|
||||
|
||||
const ACTION_BACKUP_READ = 'backup.read';
|
||||
const ACTION_BACKUP_CREATE = 'backup.create';
|
||||
const ACTION_BACKUP_UPDATE = 'backup.update';
|
||||
const ACTION_BACKUP_DELETE = 'backup.delete';
|
||||
const ACTION_BACKUP_DOWNLOAD = 'backup.download';
|
||||
|
||||
const ACTION_ALLOCATION_READ = 'allocation.read';
|
||||
const ACTION_ALLOCIATION_UPDATE = 'allocation.update';
|
||||
|
||||
|
@ -135,6 +141,17 @@ class Permission extends Validable
|
|||
],
|
||||
],
|
||||
|
||||
'backup' => [
|
||||
'description' => 'Permissions that control a user\'s ability to generate and manage server backups.',
|
||||
'keys' => [
|
||||
'create' => 'Allows a user to create new backups for this server.',
|
||||
'read' => 'Allows a user to view all backups that exist for this server.',
|
||||
'update' => '',
|
||||
'delete' => 'Allows a user to remove backups from the system.',
|
||||
'download' => 'Allows a user to download backups.',
|
||||
],
|
||||
],
|
||||
|
||||
// Controls permissions for editing or viewing a server's allocations.
|
||||
'allocation' => [
|
||||
'description' => 'Permissions that control a user\'s ability to modify the port allocations for this server.',
|
||||
|
|
|
@ -25,7 +25,7 @@ use Pterodactyl\Contracts\Extensions\HashidsInterface;
|
|||
* @property \Pterodactyl\Models\Server $server
|
||||
* @property \Pterodactyl\Models\Task[]|\Illuminate\Support\Collection $tasks
|
||||
*/
|
||||
class Schedule extends Validable
|
||||
class Schedule extends Model
|
||||
{
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
|
|
@ -52,10 +52,13 @@ use Znck\Eloquent\Traits\BelongsToThrough;
|
|||
* @property \Pterodactyl\Models\DaemonKey $key
|
||||
* @property \Pterodactyl\Models\DaemonKey[]|\Illuminate\Database\Eloquent\Collection $keys
|
||||
* @property \Pterodactyl\Models\ServerTransfer $transfer
|
||||
* @property \Pterodactyl\Models\Backup[]|\Illuminate\Database\Eloquent\Collection $backups
|
||||
*/
|
||||
class Server extends Validable
|
||||
class Server extends Model
|
||||
{
|
||||
use BelongsToThrough, Notifiable, Searchable;
|
||||
use BelongsToThrough;
|
||||
use Notifiable;
|
||||
use Searchable;
|
||||
|
||||
/**
|
||||
* The resource name for this model when it is transformed into an
|
||||
|
@ -340,7 +343,7 @@ class Server extends Validable
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns all of the daemon keys belonging to this server.
|
||||
* Returns the associated server transfer.
|
||||
*
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasOne
|
||||
*/
|
||||
|
@ -348,4 +351,12 @@ class Server extends Validable
|
|||
{
|
||||
return $this->hasOne(ServerTransfer::class)->orderByDesc('id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
*/
|
||||
public function backups()
|
||||
{
|
||||
return $this->hasMany(Backup::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Pterodactyl\Models;
|
||||
|
||||
class Setting extends Validable
|
||||
class Setting extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
|
|
|
@ -15,7 +15,7 @@ use Illuminate\Notifications\Notifiable;
|
|||
* @property \Pterodactyl\Models\User $user
|
||||
* @property \Pterodactyl\Models\Server $server
|
||||
*/
|
||||
class Subuser extends Validable
|
||||
class Subuser extends Model
|
||||
{
|
||||
use Notifiable;
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ use Pterodactyl\Contracts\Extensions\HashidsInterface;
|
|||
* @property \Pterodactyl\Models\Schedule $schedule
|
||||
* @property \Pterodactyl\Models\Server $server
|
||||
*/
|
||||
class Task extends Validable
|
||||
class Task extends Model
|
||||
{
|
||||
use BelongsToThrough;
|
||||
|
||||
|
|
|
@ -40,12 +40,17 @@ use Pterodactyl\Notifications\SendPasswordReset as ResetPasswordNotification;
|
|||
* @property \Pterodactyl\Models\Server[]|\Illuminate\Database\Eloquent\Collection $servers
|
||||
* @property \Pterodactyl\Models\DaemonKey[]|\Illuminate\Database\Eloquent\Collection $keys
|
||||
*/
|
||||
class User extends Validable implements
|
||||
class User extends Model implements
|
||||
AuthenticatableContract,
|
||||
AuthorizableContract,
|
||||
CanResetPasswordContract
|
||||
{
|
||||
use Authenticatable, Authorizable, AvailableLanguages, CanResetPassword, Notifiable, Searchable;
|
||||
use Authenticatable;
|
||||
use Authorizable;
|
||||
use AvailableLanguages;
|
||||
use CanResetPassword;
|
||||
use Notifiable;
|
||||
use Searchable;
|
||||
|
||||
const USER_LEVEL_USER = 0;
|
||||
const USER_LEVEL_ADMIN = 1;
|
||||
|
|
16
app/Repositories/Eloquent/BackupRepository.php
Normal file
16
app/Repositories/Eloquent/BackupRepository.php
Normal 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;
|
||||
}
|
||||
}
|
68
app/Services/Backups/InitiateBackupService.php
Normal file
68
app/Services/Backups/InitiateBackupService.php
Normal file
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Services\Backups;
|
||||
|
||||
use Ramsey\Uuid\Uuid;
|
||||
use Carbon\CarbonImmutable;
|
||||
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' => trim($name) ?: sprintf('Backup at %s', CarbonImmutable::now()->toDateTimeString()),
|
||||
'ignored_files' => $this->ignoredFiles ?? '',
|
||||
'disk' => 'local',
|
||||
], true, true);
|
||||
|
||||
return $backup;
|
||||
}
|
||||
}
|
33
app/Transformers/Api/Client/BackupTransformer.php
Normal file
33
app/Transformers/Api/Client/BackupTransformer.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Pterodactyl\Transformers\Api\Client;
|
||||
|
||||
use Pterodactyl\Models\Backup;
|
||||
|
||||
class BackupTransformer extends BaseClientTransformer
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getResourceName(): string
|
||||
{
|
||||
return Backup::RESOURCE_NAME;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Pterodactyl\Models\Backup $backup
|
||||
* @return array
|
||||
*/
|
||||
public function transform(Backup $backup)
|
||||
{
|
||||
return [
|
||||
'uuid' => $backup->uuid,
|
||||
'name' => $backup->name,
|
||||
'ignored_files' => $backup->ignored_files,
|
||||
'sha256_hash' => $backup->sha256_hash,
|
||||
'bytes' => $backup->bytes,
|
||||
'created_at' => $backup->created_at->toIso8601String(),
|
||||
'completed_at' => $backup->completed_at ? $backup->completed_at->toIso8601String() : null,
|
||||
];
|
||||
}
|
||||
}
|
Reference in a new issue