Skip to content

Commit 2b14e46

Browse files
committed
api: fix sequence_id being ignored in server task API
Closes pterodactyl#4434
1 parent 20f23a0 commit 2b14e46

File tree

2 files changed

+57
-20
lines changed

2 files changed

+57
-20
lines changed

app/Http/Controllers/Api/Client/Servers/ScheduleTaskController.php

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Illuminate\Http\JsonResponse;
1010
use Pterodactyl\Facades\Activity;
1111
use Pterodactyl\Models\Permission;
12+
use Illuminate\Database\ConnectionInterface;
1213
use Pterodactyl\Repositories\Eloquent\TaskRepository;
1314
use Pterodactyl\Exceptions\Http\HttpForbiddenException;
1415
use Pterodactyl\Transformers\Api\Client\TaskTransformer;
@@ -23,8 +24,10 @@ class ScheduleTaskController extends ClientApiController
2324
/**
2425
* ScheduleTaskController constructor.
2526
*/
26-
public function __construct(private TaskRepository $repository)
27-
{
27+
public function __construct(
28+
private ConnectionInterface $connection,
29+
private TaskRepository $repository
30+
) {
2831
parent::__construct();
2932
}
3033

@@ -49,14 +52,30 @@ public function store(StoreTaskRequest $request, Server $server, Schedule $sched
4952
$lastTask = $schedule->tasks()->orderByDesc('sequence_id')->first();
5053

5154
/** @var \Pterodactyl\Models\Task $task */
52-
$task = $this->repository->create([
53-
'schedule_id' => $schedule->id,
54-
'sequence_id' => ($lastTask->sequence_id ?? 0) + 1,
55-
'action' => $request->input('action'),
56-
'payload' => $request->input('payload') ?? '',
57-
'time_offset' => $request->input('time_offset'),
58-
'continue_on_failure' => (bool) $request->input('continue_on_failure'),
59-
]);
55+
$task = $this->connection->transaction(function () use ($request, $schedule, $lastTask) {
56+
$sequenceId = ($lastTask->sequence_id ?? 0) + 1;
57+
$requestSequenceId = $request->integer('sequence_id', $sequenceId);
58+
59+
// If the sequence id from the request is greater than or equal to the next available
60+
// sequence id, we don't need to do anything special. Otherwise, we need to update
61+
// the sequence id of all tasks that are greater than or equal to the request sequence
62+
// id to be one greater than the current value.
63+
if ($requestSequenceId < $sequenceId) {
64+
$schedule->tasks()
65+
->where('sequence_id', '>=', $requestSequenceId)
66+
->increment('sequence_id');
67+
$sequenceId = $requestSequenceId;
68+
}
69+
70+
return $this->repository->create([
71+
'schedule_id' => $schedule->id,
72+
'sequence_id' => $sequenceId,
73+
'action' => $request->input('action'),
74+
'payload' => $request->input('payload') ?? '',
75+
'time_offset' => $request->input('time_offset'),
76+
'continue_on_failure' => $request->boolean('continue_on_failure'),
77+
]);
78+
});
6079

6180
Activity::event('server:task.create')
6281
->subject($schedule, $task)
@@ -84,12 +103,30 @@ public function update(StoreTaskRequest $request, Server $server, Schedule $sche
84103
throw new HttpForbiddenException("A backup task cannot be created when the server's backup limit is set to 0.");
85104
}
86105

87-
$this->repository->update($task->id, [
88-
'action' => $request->input('action'),
89-
'payload' => $request->input('payload') ?? '',
90-
'time_offset' => $request->input('time_offset'),
91-
'continue_on_failure' => (bool) $request->input('continue_on_failure'),
92-
]);
106+
$this->connection->transaction(function () use ($request, $schedule, $task) {
107+
$sequenceId = $request->integer('sequence_id', $task->sequence_id);
108+
109+
// Shift all other tasks in the schedule up or down to make room for the new task.
110+
if ($sequenceId < $task->sequence_id) {
111+
$schedule->tasks()
112+
->where('sequence_id', '>=', $sequenceId)
113+
->where('sequence_id', '<', $task->sequence_id)
114+
->increment('sequence_id');
115+
} elseif ($sequenceId > $task->sequence_id) {
116+
$schedule->tasks()
117+
->where('sequence_id', '>', $task->sequence_id)
118+
->where('sequence_id', '<=', $sequenceId)
119+
->decrement('sequence_id');
120+
}
121+
122+
$this->repository->update($task->id, [
123+
'sequence_id' => $sequenceId,
124+
'action' => $request->input('action'),
125+
'payload' => $request->input('payload') ?? '',
126+
'time_offset' => $request->input('time_offset'),
127+
'continue_on_failure' => $request->boolean('continue_on_failure'),
128+
]);
129+
});
93130

94131
Activity::event('server:task.update')
95132
->subject($schedule, $task)
@@ -117,10 +154,9 @@ public function delete(ClientApiRequest $request, Server $server, Schedule $sche
117154
throw new HttpForbiddenException('You do not have permission to perform this action.');
118155
}
119156

120-
$schedule->tasks()->where('sequence_id', '>', $task->sequence_id)->update([
121-
'sequence_id' => $schedule->tasks()->getConnection()->raw('(sequence_id - 1)'),
122-
]);
123-
157+
$schedule->tasks()
158+
->where('sequence_id', '>', $task->sequence_id)
159+
->decrement('sequence_id');
124160
$task->delete();
125161

126162
Activity::event('server:task.delete')->subject($schedule, $task)->property('name', $schedule->name)->log();

app/Http/Requests/Api/Client/Servers/Schedules/StoreTaskRequest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function rules(): array
2323
'payload' => 'required_unless:action,backup|string|nullable',
2424
'time_offset' => 'required|numeric|min:0|max:900',
2525
'sequence_id' => 'sometimes|required|numeric|min:1',
26+
'continue_on_failure' => 'sometimes|required|boolean',
2627
];
2728
}
2829
}

0 commit comments

Comments
 (0)