2020-03-19 04:08:32 +00:00
< ? php
namespace Pterodactyl\Http\Controllers\Api\Client\Servers ;
use Pterodactyl\Models\Task ;
use Illuminate\Http\Response ;
use Pterodactyl\Models\Server ;
use Pterodactyl\Models\Schedule ;
use Illuminate\Http\JsonResponse ;
2022-05-29 23:26:28 +00:00
use Pterodactyl\Facades\Activity ;
2020-03-19 04:08:32 +00:00
use Pterodactyl\Models\Permission ;
2023-01-24 22:57:24 +00:00
use Illuminate\Database\ConnectionInterface ;
2020-03-19 04:08:32 +00:00
use Pterodactyl\Repositories\Eloquent\TaskRepository ;
use Pterodactyl\Exceptions\Http\HttpForbiddenException ;
2020-03-19 05:28:32 +00:00
use Pterodactyl\Transformers\Api\Client\TaskTransformer ;
2020-03-19 04:08:32 +00:00
use Pterodactyl\Http\Requests\Api\Client\ClientApiRequest ;
use Pterodactyl\Http\Controllers\Api\Client\ClientApiController ;
2020-06-28 21:41:22 +00:00
use Pterodactyl\Exceptions\Service\ServiceLimitExceededException ;
2020-03-19 04:08:32 +00:00
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException ;
2020-03-19 05:28:32 +00:00
use Pterodactyl\Http\Requests\Api\Client\Servers\Schedules\StoreTaskRequest ;
2020-03-19 04:08:32 +00:00
class ScheduleTaskController extends ClientApiController
{
/**
* ScheduleTaskController constructor .
*/
2023-01-24 22:57:24 +00:00
public function __construct (
private ConnectionInterface $connection ,
private TaskRepository $repository
) {
2020-03-19 04:08:32 +00:00
parent :: __construct ();
}
2020-03-19 05:28:32 +00:00
/**
* Create a new task for a given schedule and store it in the database .
*
* @ throws \Pterodactyl\Exceptions\Model\DataValidationException
2020-06-28 21:41:22 +00:00
* @ throws \Pterodactyl\Exceptions\Service\ServiceLimitExceededException
2020-03-19 05:28:32 +00:00
*/
2022-10-14 16:59:20 +00:00
public function store ( StoreTaskRequest $request , Server $server , Schedule $schedule ) : array
2020-03-19 05:28:32 +00:00
{
2020-06-28 21:41:22 +00:00
$limit = config ( 'pterodactyl.client_features.schedules.per_schedule_task_limit' , 10 );
if ( $schedule -> tasks () -> count () >= $limit ) {
2022-10-14 16:59:20 +00:00
throw new ServiceLimitExceededException ( " Schedules may not have more than $limit tasks associated with them. Creating this task would put this schedule over the limit. " );
2020-03-19 05:28:32 +00:00
}
2021-05-16 16:47:36 +00:00
if ( $server -> backup_limit === 0 && $request -> action === 'backup' ) {
throw new HttpForbiddenException ( " A backup task cannot be created when the server's backup limit is set to 0. " );
}
2020-10-23 03:54:58 +00:00
/** @var \Pterodactyl\Models\Task|null $lastTask */
$lastTask = $schedule -> tasks () -> orderByDesc ( 'sequence_id' ) -> first ();
2020-03-19 05:28:32 +00:00
/** @var \Pterodactyl\Models\Task $task */
2023-01-24 22:57:24 +00:00
$task = $this -> connection -> transaction ( function () use ( $request , $schedule , $lastTask ) {
$sequenceId = ( $lastTask -> sequence_id ? ? 0 ) + 1 ;
$requestSequenceId = $request -> integer ( 'sequence_id' , $sequenceId );
2023-01-24 23:18:38 +00:00
// Ensure that the sequence id is at least 1.
if ( $requestSequenceId < 1 ) {
$requestSequenceId = 1 ;
}
2023-01-24 22:57:24 +00:00
// If the sequence id from the request is greater than or equal to the next available
// sequence id, we don't need to do anything special. Otherwise, we need to update
// the sequence id of all tasks that are greater than or equal to the request sequence
// id to be one greater than the current value.
if ( $requestSequenceId < $sequenceId ) {
$schedule -> tasks ()
-> where ( 'sequence_id' , '>=' , $requestSequenceId )
-> increment ( 'sequence_id' );
$sequenceId = $requestSequenceId ;
}
return $this -> repository -> create ([
'schedule_id' => $schedule -> id ,
'sequence_id' => $sequenceId ,
'action' => $request -> input ( 'action' ),
'payload' => $request -> input ( 'payload' ) ? ? '' ,
'time_offset' => $request -> input ( 'time_offset' ),
'continue_on_failure' => $request -> boolean ( 'continue_on_failure' ),
]);
});
2020-03-19 05:28:32 +00:00
2022-05-29 23:26:28 +00:00
Activity :: event ( 'server:task.create' )
-> subject ( $schedule , $task )
-> property ([ 'name' => $schedule -> name , 'action' => $task -> action , 'payload' => $task -> payload ])
-> log ();
2020-03-19 05:28:32 +00:00
return $this -> fractal -> item ( $task )
-> transformWith ( $this -> getTransformer ( TaskTransformer :: class ))
-> toArray ();
}
/**
* Updates a given task for a server .
*
* @ throws \Pterodactyl\Exceptions\Model\DataValidationException
* @ throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
*/
2022-10-14 16:59:20 +00:00
public function update ( StoreTaskRequest $request , Server $server , Schedule $schedule , Task $task ) : array
2020-03-19 05:28:32 +00:00
{
if ( $schedule -> id !== $task -> schedule_id || $server -> id !== $schedule -> server_id ) {
2021-01-23 20:33:34 +00:00
throw new NotFoundHttpException ();
2020-03-19 05:28:32 +00:00
}
2021-05-16 16:47:36 +00:00
if ( $server -> backup_limit === 0 && $request -> action === 'backup' ) {
throw new HttpForbiddenException ( " A backup task cannot be created when the server's backup limit is set to 0. " );
}
2023-01-24 22:57:24 +00:00
$this -> connection -> transaction ( function () use ( $request , $schedule , $task ) {
$sequenceId = $request -> integer ( 'sequence_id' , $task -> sequence_id );
2023-01-24 23:18:38 +00:00
// Ensure that the sequence id is at least 1.
if ( $sequenceId < 1 ) {
$sequenceId = 1 ;
}
2023-01-24 22:57:24 +00:00
// Shift all other tasks in the schedule up or down to make room for the new task.
if ( $sequenceId < $task -> sequence_id ) {
$schedule -> tasks ()
-> where ( 'sequence_id' , '>=' , $sequenceId )
-> where ( 'sequence_id' , '<' , $task -> sequence_id )
-> increment ( 'sequence_id' );
} elseif ( $sequenceId > $task -> sequence_id ) {
$schedule -> tasks ()
-> where ( 'sequence_id' , '>' , $task -> sequence_id )
-> where ( 'sequence_id' , '<=' , $sequenceId )
-> decrement ( 'sequence_id' );
}
$this -> repository -> update ( $task -> id , [
'sequence_id' => $sequenceId ,
'action' => $request -> input ( 'action' ),
'payload' => $request -> input ( 'payload' ) ? ? '' ,
'time_offset' => $request -> input ( 'time_offset' ),
'continue_on_failure' => $request -> boolean ( 'continue_on_failure' ),
]);
});
2020-03-19 05:28:32 +00:00
2022-05-29 23:26:28 +00:00
Activity :: event ( 'server:task.update' )
-> subject ( $schedule , $task )
-> property ([ 'name' => $schedule -> name , 'action' => $task -> action , 'payload' => $task -> payload ])
-> log ();
2020-03-19 05:28:32 +00:00
return $this -> fractal -> item ( $task -> refresh ())
-> transformWith ( $this -> getTransformer ( TaskTransformer :: class ))
-> toArray ();
}
2020-03-19 04:08:32 +00:00
/**
2020-10-23 03:54:58 +00:00
* Delete a given task for a schedule . If there are subsequent tasks stored in the database
* for this schedule their sequence IDs are decremented properly .
2020-03-19 04:08:32 +00:00
*
2020-10-23 03:54:58 +00:00
* @ throws \Exception
2020-03-19 04:08:32 +00:00
*/
2022-10-14 16:59:20 +00:00
public function delete ( ClientApiRequest $request , Server $server , Schedule $schedule , Task $task ) : JsonResponse
2020-03-19 04:08:32 +00:00
{
if ( $task -> schedule_id !== $schedule -> id || $schedule -> server_id !== $server -> id ) {
2021-01-23 20:33:34 +00:00
throw new NotFoundHttpException ();
2020-03-19 04:08:32 +00:00
}
2021-01-23 20:33:34 +00:00
if ( ! $request -> user () -> can ( Permission :: ACTION_SCHEDULE_UPDATE , $server )) {
2020-03-19 04:08:32 +00:00
throw new HttpForbiddenException ( 'You do not have permission to perform this action.' );
}
2023-01-24 22:57:24 +00:00
$schedule -> tasks ()
-> where ( 'sequence_id' , '>' , $task -> sequence_id )
-> decrement ( 'sequence_id' );
2020-10-23 03:54:58 +00:00
$task -> delete ();
2020-03-19 04:08:32 +00:00
2022-05-29 23:26:28 +00:00
Activity :: event ( 'server:task.delete' ) -> subject ( $schedule , $task ) -> property ( 'name' , $schedule -> name ) -> log ();
2020-10-23 03:54:58 +00:00
return new JsonResponse ( null , Response :: HTTP_NO_CONTENT );
2020-03-19 04:08:32 +00:00
}
}