Path: blob/1.0-develop/app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php
14055 views
<?php12namespace Pterodactyl\Http\Controllers\Api\Client\Servers;34use Pterodactyl\Models\Task;5use Illuminate\Http\Response;6use Pterodactyl\Models\Server;7use Pterodactyl\Models\Schedule;8use Illuminate\Http\JsonResponse;9use Pterodactyl\Facades\Activity;10use Pterodactyl\Models\Permission;11use Illuminate\Database\ConnectionInterface;12use Pterodactyl\Repositories\Eloquent\TaskRepository;13use Pterodactyl\Exceptions\Http\HttpForbiddenException;14use Pterodactyl\Transformers\Api\Client\TaskTransformer;15use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest;16use Pterodactyl\Http\Controllers\Api\Client\ClientApiController;17use Pterodactyl\Exceptions\Service\ServiceLimitExceededException;18use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;19use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\StoreTaskRequest;2021class ScheduleTaskController extends ClientApiController22{23/**24* ScheduleTaskController constructor.25*/26public function __construct(27private ConnectionInterface $connection,28private TaskRepository $repository,29) {30parent::__construct();31}3233/**34* Create a new task for a given schedule and store it in the database.35*36* @throws \Pterodactyl\Exceptions\Model\DataValidationException37* @throws ServiceLimitExceededException38*/39public function store(StoreTaskRequest $request, Server $server, Schedule $schedule): array40{41$limit = config('pterodactyl.client_features.schedules.per_schedule_task_limit', 10);42if ($schedule->tasks()->count() >= $limit) {43throw new ServiceLimitExceededException("Schedules may not have more than $limit tasks associated with them. Creating this task would put this schedule over the limit.");44}4546if ($server->backup_limit === 0 && $request->action === 'backup') {47throw new HttpForbiddenException("A backup task cannot be created when the server's backup limit is set to 0.");48}4950/** @var Task|null $lastTask */51$lastTask = $schedule->tasks()->orderByDesc('sequence_id')->first();5253/** @var Task $task */54$task = $this->connection->transaction(function () use ($request, $schedule, $lastTask) {55$sequenceId = ($lastTask->sequence_id ?? 0) + 1;56$requestSequenceId = $request->integer('sequence_id', $sequenceId);5758// Ensure that the sequence id is at least 1.59if ($requestSequenceId < 1) {60$requestSequenceId = 1;61}6263// If the sequence id from the request is greater than or equal to the next available64// sequence id, we don't need to do anything special. Otherwise, we need to update65// the sequence id of all tasks that are greater than or equal to the request sequence66// id to be one greater than the current value.67if ($requestSequenceId < $sequenceId) {68$schedule->tasks()69->where('sequence_id', '>=', $requestSequenceId)70->increment('sequence_id');71$sequenceId = $requestSequenceId;72}7374return $this->repository->create([75'schedule_id' => $schedule->id,76'sequence_id' => $sequenceId,77'action' => $request->input('action'),78'payload' => $request->input('payload') ?? '',79'time_offset' => $request->input('time_offset'),80'continue_on_failure' => $request->boolean('continue_on_failure'),81]);82});8384Activity::event('server:task.create')85->subject($schedule, $task)86->property(['name' => $schedule->name, 'action' => $task->action, 'payload' => $task->payload])87->log();8889return $this->fractal->item($task)90->transformWith($this->getTransformer(TaskTransformer::class))91->toArray();92}9394/**95* Updates a given task for a server.96*97* @throws \Pterodactyl\Exceptions\Model\DataValidationException98* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException99*/100public function update(StoreTaskRequest $request, Server $server, Schedule $schedule, Task $task): array101{102if ($schedule->id !== $task->schedule_id || $server->id !== $schedule->server_id) {103throw new NotFoundHttpException();104}105106if ($server->backup_limit === 0 && $request->action === 'backup') {107throw new HttpForbiddenException("A backup task cannot be created when the server's backup limit is set to 0.");108}109110$this->connection->transaction(function () use ($request, $schedule, $task) {111$sequenceId = $request->integer('sequence_id', $task->sequence_id);112// Ensure that the sequence id is at least 1.113if ($sequenceId < 1) {114$sequenceId = 1;115}116117// Shift all other tasks in the schedule up or down to make room for the new task.118if ($sequenceId < $task->sequence_id) {119$schedule->tasks()120->where('sequence_id', '>=', $sequenceId)121->where('sequence_id', '<', $task->sequence_id)122->increment('sequence_id');123} elseif ($sequenceId > $task->sequence_id) {124$schedule->tasks()125->where('sequence_id', '>', $task->sequence_id)126->where('sequence_id', '<=', $sequenceId)127->decrement('sequence_id');128}129130$this->repository->update($task->id, [131'sequence_id' => $sequenceId,132'action' => $request->input('action'),133'payload' => $request->input('payload') ?? '',134'time_offset' => $request->input('time_offset'),135'continue_on_failure' => $request->boolean('continue_on_failure'),136]);137});138139Activity::event('server:task.update')140->subject($schedule, $task)141->property(['name' => $schedule->name, 'action' => $task->action, 'payload' => $task->payload])142->log();143144return $this->fractal->item($task->refresh())145->transformWith($this->getTransformer(TaskTransformer::class))146->toArray();147}148149/**150* Delete a given task for a schedule. If there are subsequent tasks stored in the database151* for this schedule their sequence IDs are decremented properly.152*153* @throws \Exception154*/155public function delete(ClientApiRequest $request, Server $server, Schedule $schedule, Task $task): JsonResponse156{157if ($task->schedule_id !== $schedule->id || $schedule->server_id !== $server->id) {158throw new NotFoundHttpException();159}160161if (!$request->user()->can(Permission::ACTION_SCHEDULE_UPDATE, $server)) {162throw new HttpForbiddenException('You do not have permission to perform this action.');163}164165$schedule->tasks()166->where('sequence_id', '>', $task->sequence_id)167->decrement('sequence_id');168$task->delete();169170Activity::event('server:task.delete')->subject($schedule, $task)->property('name', $schedule->name)->log();171172return new JsonResponse(null, Response::HTTP_NO_CONTENT);173}174}175176177