Don't allow backups to be made via schedules if limit = 0 (#3323)
This commit is contained in:
parent
5a82dd6a18
commit
76ac1998cf
6 changed files with 42 additions and 21 deletions
|
@ -39,6 +39,7 @@ class ScheduleTaskController extends ClientApiController
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Model\HttpForbiddenException
|
||||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||||
* @throws \Pterodactyl\Exceptions\Service\ServiceLimitExceededException
|
* @throws \Pterodactyl\Exceptions\Service\ServiceLimitExceededException
|
||||||
*/
|
*/
|
||||||
|
@ -49,6 +50,10 @@ class ScheduleTaskController extends ClientApiController
|
||||||
throw new ServiceLimitExceededException("Schedules may not have more than {$limit} tasks associated with them. Creating this task would put this schedule over the limit.");
|
throw new ServiceLimitExceededException("Schedules may not have more than {$limit} tasks associated with them. Creating this task would put this schedule over the limit.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
/** @var \Pterodactyl\Models\Task|null $lastTask */
|
/** @var \Pterodactyl\Models\Task|null $lastTask */
|
||||||
$lastTask = $schedule->tasks()->orderByDesc('sequence_id')->first();
|
$lastTask = $schedule->tasks()->orderByDesc('sequence_id')->first();
|
||||||
|
|
||||||
|
@ -72,6 +77,7 @@ class ScheduleTaskController extends ClientApiController
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*
|
*
|
||||||
|
* @throws \Pterodactyl\Exceptions\Model\HttpForbiddenException
|
||||||
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
* @throws \Pterodactyl\Exceptions\Model\DataValidationException
|
||||||
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
* @throws \Pterodactyl\Exceptions\Repository\RecordNotFoundException
|
||||||
*/
|
*/
|
||||||
|
@ -81,6 +87,10 @@ class ScheduleTaskController extends ClientApiController
|
||||||
throw new NotFoundHttpException();
|
throw new NotFoundHttpException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
$this->repository->update($task->id, [
|
$this->repository->update($task->id, [
|
||||||
'action' => $request->input('action'),
|
'action' => $request->input('action'),
|
||||||
'payload' => $request->input('payload') ?? '',
|
'payload' => $request->input('payload') ?? '',
|
||||||
|
|
|
@ -3,6 +3,7 @@ import tw from 'twin.macro';
|
||||||
import Button from '@/components/elements/Button';
|
import Button from '@/components/elements/Button';
|
||||||
import asModal from '@/hoc/asModal';
|
import asModal from '@/hoc/asModal';
|
||||||
import ModalContext from '@/context/ModalContext';
|
import ModalContext from '@/context/ModalContext';
|
||||||
|
import CopyOnClick from '@/components/elements/CopyOnClick';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
apiKey: string;
|
apiKey: string;
|
||||||
|
@ -19,7 +20,7 @@ const ApiKeyModal = ({ apiKey }: Props) => {
|
||||||
shown again.
|
shown again.
|
||||||
</p>
|
</p>
|
||||||
<pre css={tw`text-sm bg-neutral-900 rounded py-2 px-4 font-mono`}>
|
<pre css={tw`text-sm bg-neutral-900 rounded py-2 px-4 font-mono`}>
|
||||||
<code css={tw`font-mono`}>{apiKey}</code>
|
<CopyOnClick text={apiKey}><code css={tw`font-mono`}>{apiKey}</code></CopyOnClick>
|
||||||
</pre>
|
</pre>
|
||||||
<div css={tw`flex justify-end mt-6`}>
|
<div css={tw`flex justify-end mt-6`}>
|
||||||
<Button type={'button'} onClick={() => dismiss()}>
|
<Button type={'button'} onClick={() => dismiss()}>
|
||||||
|
|
|
@ -53,7 +53,7 @@ export default () => {
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
:
|
:
|
||||||
<p css={tw`text-center text-sm text-neutral-400`}>
|
<p css={tw`text-center text-sm text-neutral-300`}>
|
||||||
{databaseLimit > 0 ?
|
{databaseLimit > 0 ?
|
||||||
'It looks like you have no databases.'
|
'It looks like you have no databases.'
|
||||||
:
|
:
|
||||||
|
|
|
@ -81,7 +81,7 @@ export default () => {
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContentBlock>
|
<PageContentBlock title={'Schedules'}>
|
||||||
<FlashMessageRender byKey={'schedules'} css={tw`mb-4`}/>
|
<FlashMessageRender byKey={'schedules'} css={tw`mb-4`}/>
|
||||||
{!schedule || isLoading ?
|
{!schedule || isLoading ?
|
||||||
<Spinner size={'large'} centered/>
|
<Spinner size={'large'} centered/>
|
||||||
|
|
|
@ -69,6 +69,7 @@ const TaskDetailsModal = ({ schedule, task }: Props) => {
|
||||||
|
|
||||||
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
|
const uuid = ServerContext.useStoreState(state => state.server.data!.uuid);
|
||||||
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);
|
const appendSchedule = ServerContext.useStoreActions(actions => actions.schedules.appendSchedule);
|
||||||
|
const backupLimit = ServerContext.useStoreState(state => state.server.data!.featureLimits.backups);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
|
@ -78,21 +79,26 @@ const TaskDetailsModal = ({ schedule, task }: Props) => {
|
||||||
|
|
||||||
const submit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
|
const submit = (values: Values, { setSubmitting }: FormikHelpers<Values>) => {
|
||||||
clearFlashes('schedule:task');
|
clearFlashes('schedule:task');
|
||||||
createOrUpdateScheduleTask(uuid, schedule.id, task?.id, values)
|
if (backupLimit === 0 && values.action === 'backup') {
|
||||||
.then(task => {
|
setSubmitting(false);
|
||||||
let tasks = schedule.tasks.map(t => t.id === task.id ? task : t);
|
addError({ message: 'A backup task cannot be created when the server\'s backup limit is set to 0.', key: 'schedule:task' });
|
||||||
if (!schedule.tasks.find(t => t.id === task.id)) {
|
} else {
|
||||||
tasks = [ ...tasks, task ];
|
createOrUpdateScheduleTask(uuid, schedule.id, task?.id, values)
|
||||||
}
|
.then(task => {
|
||||||
|
let tasks = schedule.tasks.map(t => t.id === task.id ? task : t);
|
||||||
|
if (!schedule.tasks.find(t => t.id === task.id)) {
|
||||||
|
tasks = [ ...tasks, task ];
|
||||||
|
}
|
||||||
|
|
||||||
appendSchedule({ ...schedule, tasks });
|
appendSchedule({ ...schedule, tasks });
|
||||||
dismiss();
|
dismiss();
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
addError({ message: httpErrorToHuman(error), key: 'schedule:task' });
|
addError({ message: httpErrorToHuman(error), key: 'schedule:task' });
|
||||||
});
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -89,9 +89,9 @@ class CreateServerScheduleTaskTest extends ClientApiIntegrationTestCase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that backups can be tasked out correctly since they do not require a payload.
|
* Test that backups can not be tasked when the backup limit is 0
|
||||||
*/
|
*/
|
||||||
public function testBackupsCanBeTaskedCorrectly()
|
public function testBackupsCanNotBeTaskedIfLimit0()
|
||||||
{
|
{
|
||||||
[$user, $server] = $this->generateTestAccount();
|
[$user, $server] = $this->generateTestAccount();
|
||||||
|
|
||||||
|
@ -101,13 +101,17 @@ class CreateServerScheduleTaskTest extends ClientApiIntegrationTestCase
|
||||||
$this->actingAs($user)->postJson($this->link($schedule, '/tasks'), [
|
$this->actingAs($user)->postJson($this->link($schedule, '/tasks'), [
|
||||||
'action' => 'backup',
|
'action' => 'backup',
|
||||||
'time_offset' => 0,
|
'time_offset' => 0,
|
||||||
])->assertOk();
|
])
|
||||||
|
->assertStatus(Response::HTTP_FORBIDDEN)
|
||||||
|
->assertJsonPath('errors.0.detail', 'A backup task cannot be created when the server\'s backup limit is set to 0.');
|
||||||
|
|
||||||
$this->actingAs($user)->postJson($this->link($schedule, '/tasks'), [
|
$this->actingAs($user)->postJson($this->link($schedule, '/tasks'), [
|
||||||
'action' => 'backup',
|
'action' => 'backup',
|
||||||
'payload' => "file.txt\nfile2.log",
|
'payload' => "file.txt\nfile2.log",
|
||||||
'time_offset' => 0,
|
'time_offset' => 0,
|
||||||
])->assertOk();
|
])
|
||||||
|
->assertStatus(Response::HTTP_FORBIDDEN)
|
||||||
|
->assertJsonPath('errors.0.detail', 'A backup task cannot be created when the server\'s backup limit is set to 0.');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue