diff --git a/app/Http/Controllers/Api/Client/Servers/BackupController.php b/app/Http/Controllers/Api/Client/Servers/BackupController.php index 1cbecf262..cc8ba0917 100644 --- a/app/Http/Controllers/Api/Client/Servers/BackupController.php +++ b/app/Http/Controllers/Api/Client/Servers/BackupController.php @@ -2,7 +2,6 @@ namespace Pterodactyl\Http\Controllers\Api\Client\Servers; -use Carbon\Carbon; use Pterodactyl\Models\Backup; use Pterodactyl\Models\Server; use Illuminate\Http\JsonResponse; @@ -11,7 +10,6 @@ use Pterodactyl\Repositories\Eloquent\BackupRepository; use Pterodactyl\Services\Backups\InitiateBackupService; use Pterodactyl\Transformers\Api\Client\BackupTransformer; use Pterodactyl\Http\Controllers\Api\Client\ClientApiController; -use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\GetBackupsRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\StoreBackupRequest; use Pterodactyl\Http\Requests\Api\Client\Servers\Backups\DeleteBackupRequest; @@ -78,14 +76,6 @@ class BackupController extends ClientApiController */ public function store(StoreBackupRequest $request, Server $server) { - $previous = $this->repository->getBackupsGeneratedDuringTimespan($server->id, 10); - if ($previous->count() >= 2) { - throw new TooManyRequestsHttpException( - Carbon::now()->diffInSeconds($previous->last()->created_at->addMinutes(10)), - 'Only two backups may be generated within a 10 minute span of time.' - ); - } - $backup = $this->initiateBackupService ->setIgnoredFiles( explode(PHP_EOL, $request->input('ignored') ?? '') diff --git a/app/Http/Requests/Api/Client/Servers/Schedules/StoreTaskRequest.php b/app/Http/Requests/Api/Client/Servers/Schedules/StoreTaskRequest.php index 86ec50f67..839fe2eac 100644 --- a/app/Http/Requests/Api/Client/Servers/Schedules/StoreTaskRequest.php +++ b/app/Http/Requests/Api/Client/Servers/Schedules/StoreTaskRequest.php @@ -24,9 +24,9 @@ class StoreTaskRequest extends ViewScheduleRequest public function rules(): array { return [ - 'action' => 'required|in:command,power', - 'payload' => 'required|string', - 'time_offset' => 'required|numeric|min:0|max:900', + 'action' => 'required|in:command,power,backup', + 'payload' => 'required_unless:action,backup|string', + 'time_offset' => 'r=equired|numeric|min:0|max:900', 'sequence_id' => 'sometimes|required|numeric|min:1', ]; } diff --git a/app/Jobs/Schedule/RunTaskJob.php b/app/Jobs/Schedule/RunTaskJob.php index bab5b9f68..4f6bfd22f 100644 --- a/app/Jobs/Schedule/RunTaskJob.php +++ b/app/Jobs/Schedule/RunTaskJob.php @@ -12,10 +12,10 @@ use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\DispatchesJobs; use Pterodactyl\Repositories\Eloquent\TaskRepository; +use Pterodactyl\Services\Backups\InitiateBackupService; use Pterodactyl\Repositories\Wings\DaemonPowerRepository; use Pterodactyl\Repositories\Wings\DaemonCommandRepository; use Pterodactyl\Contracts\Repository\TaskRepositoryInterface; -use Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService; use Pterodactyl\Contracts\Repository\ScheduleRepositoryInterface; class RunTaskJob extends Job implements ShouldQueue @@ -54,16 +54,16 @@ class RunTaskJob extends Job implements ShouldQueue * Run the job and send actions to the daemon running the server. * * @param \Pterodactyl\Repositories\Wings\DaemonCommandRepository $commandRepository - * @param \Pterodactyl\Services\DaemonKeys\DaemonKeyProviderService $keyProviderService + * @param \Pterodactyl\Services\Backups\InitiateBackupService $backupService * @param \Pterodactyl\Repositories\Wings\DaemonPowerRepository $powerRepository * @param \Pterodactyl\Repositories\Eloquent\TaskRepository $taskRepository * * @throws \Pterodactyl\Exceptions\Model\DataValidationException - * @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException + * @throws \Throwable */ public function handle( DaemonCommandRepository $commandRepository, - DaemonKeyProviderService $keyProviderService, + InitiateBackupService $backupService, DaemonPowerRepository $powerRepository, TaskRepository $taskRepository ) { @@ -88,6 +88,9 @@ class RunTaskJob extends Job implements ShouldQueue case 'command': $commandRepository->setServer($server)->send($task->payload); break; + case 'backup': + $backupService->setIgnoredFiles(explode(PHP_EOL, $task->payload))->handle($server, null); + break; default: throw new InvalidArgumentException('Cannot run a task that points to a non-existent action.'); } diff --git a/app/Services/Backups/InitiateBackupService.php b/app/Services/Backups/InitiateBackupService.php index 24a3203cb..d952c46da 100644 --- a/app/Services/Backups/InitiateBackupService.php +++ b/app/Services/Backups/InitiateBackupService.php @@ -2,6 +2,7 @@ namespace Pterodactyl\Services\Backups; +use Carbon\Carbon; use Ramsey\Uuid\Uuid; use Carbon\CarbonImmutable; use Webmozart\Assert\Assert; @@ -10,6 +11,7 @@ use Pterodactyl\Models\Server; use Illuminate\Database\ConnectionInterface; use Pterodactyl\Repositories\Eloquent\BackupRepository; use Pterodactyl\Repositories\Wings\DaemonBackupRepository; +use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException; class InitiateBackupService { @@ -85,6 +87,14 @@ class InitiateBackupService */ public function handle(Server $server, string $name = null): Backup { + $previous = $this->repository->getBackupsGeneratedDuringTimespan($server->id, 10); + if ($previous->count() >= 2) { + throw new TooManyRequestsHttpException( + Carbon::now()->diffInSeconds($previous->last()->created_at->addMinutes(10)), + 'Only two backups may be generated within a 10 minute span of time.' + ); + } + return $this->connection->transaction(function () use ($server, $name) { /** @var \Pterodactyl\Models\Backup $backup */ $backup = $this->repository->create([ diff --git a/resources/scripts/components/server/schedules/TaskDetailsModal.tsx b/resources/scripts/components/server/schedules/TaskDetailsModal.tsx index 53481a144..7c6cdbc7b 100644 --- a/resources/scripts/components/server/schedules/TaskDetailsModal.tsx +++ b/resources/scripts/components/server/schedules/TaskDetailsModal.tsx @@ -36,14 +36,17 @@ const TaskDetailsForm = ({ isEditingTask }: { isEditingTask: boolean }) => { return (
-

Edit Task

+

{isEditingTask ? 'Edit Task' : 'Create Task'}

-
+
- - - - + + + + + + +
{action === 'command' ? @@ -53,17 +56,25 @@ const TaskDetailsForm = ({ isEditingTask }: { isEditingTask: boolean }) => { description={'The command to send to the server when this task executes.'} /> : -
- - - - - - - - - -
+ action === 'power' ? +
+ + + + + + + + + +
+ : +
+ + + + +
}
@@ -120,8 +131,12 @@ export default ({ task, schedule, onDismissed }: Props) => { timeOffset: task?.timeOffset.toString() || '0', }} validationSchema={object().shape({ - action: string().required().oneOf([ 'command', 'power' ]), - payload: string().required('A task payload must be provided.'), + action: string().required().oneOf([ 'command', 'power', 'backup' ]), + payload: string().when('action', { + is: v => v !== 'backup', + then: string().required('A task payload must be provided.'), + otherwise: string(), + }), timeOffset: number().typeError('The time offset must be a valid number between 0 and 900.') .required('A time offset value must be provided.') .min(0, 'The time offset must be at least 0 seconds.')