Merge pull request #3011 from AreYouRlyScared/addcronmonth
Adds months for schedules
This commit is contained in:
commit
aab353d91e
12 changed files with 72 additions and 18 deletions
|
@ -42,13 +42,14 @@ class Utilities
|
||||||
* @param string $minute
|
* @param string $minute
|
||||||
* @param string $hour
|
* @param string $hour
|
||||||
* @param string $dayOfMonth
|
* @param string $dayOfMonth
|
||||||
|
* @param string $month
|
||||||
* @param string $dayOfWeek
|
* @param string $dayOfWeek
|
||||||
* @return \Carbon\Carbon
|
* @return \Carbon\Carbon
|
||||||
*/
|
*/
|
||||||
public static function getScheduleNextRunDate(string $minute, string $hour, string $dayOfMonth, string $dayOfWeek)
|
public static function getScheduleNextRunDate(string $minute, string $hour, string $dayOfMonth, string $month, string $dayOfWeek)
|
||||||
{
|
{
|
||||||
return Carbon::instance(CronExpression::factory(
|
return Carbon::instance(CronExpression::factory(
|
||||||
sprintf('%s %s %s * %s', $minute, $hour, $dayOfMonth, $dayOfWeek)
|
sprintf('%s %s %s %s %s', $minute, $hour, $dayOfMonth, $month, $dayOfWeek)
|
||||||
)->getNextRunDate());
|
)->getNextRunDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@ class ScheduleController extends ClientApiController
|
||||||
'server_id' => $server->id,
|
'server_id' => $server->id,
|
||||||
'name' => $request->input('name'),
|
'name' => $request->input('name'),
|
||||||
'cron_day_of_week' => $request->input('day_of_week'),
|
'cron_day_of_week' => $request->input('day_of_week'),
|
||||||
|
'cron_month' => $request->input('month'),
|
||||||
'cron_day_of_month' => $request->input('day_of_month'),
|
'cron_day_of_month' => $request->input('day_of_month'),
|
||||||
'cron_hour' => $request->input('hour'),
|
'cron_hour' => $request->input('hour'),
|
||||||
'cron_minute' => $request->input('minute'),
|
'cron_minute' => $request->input('minute'),
|
||||||
|
@ -136,6 +137,7 @@ class ScheduleController extends ClientApiController
|
||||||
$data = [
|
$data = [
|
||||||
'name' => $request->input('name'),
|
'name' => $request->input('name'),
|
||||||
'cron_day_of_week' => $request->input('day_of_week'),
|
'cron_day_of_week' => $request->input('day_of_week'),
|
||||||
|
'cron_month' => $request->input('month'),
|
||||||
'cron_day_of_month' => $request->input('day_of_month'),
|
'cron_day_of_month' => $request->input('day_of_month'),
|
||||||
'cron_hour' => $request->input('hour'),
|
'cron_hour' => $request->input('hour'),
|
||||||
'cron_minute' => $request->input('minute'),
|
'cron_minute' => $request->input('minute'),
|
||||||
|
@ -211,6 +213,7 @@ class ScheduleController extends ClientApiController
|
||||||
$request->input('minute'),
|
$request->input('minute'),
|
||||||
$request->input('hour'),
|
$request->input('hour'),
|
||||||
$request->input('day_of_month'),
|
$request->input('day_of_month'),
|
||||||
|
$request->input('month'),
|
||||||
$request->input('day_of_week')
|
$request->input('day_of_week')
|
||||||
);
|
);
|
||||||
} catch (Exception $exception) {
|
} catch (Exception $exception) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ use Pterodactyl\Contracts\Extensions\HashidsInterface;
|
||||||
* @property int $server_id
|
* @property int $server_id
|
||||||
* @property string $name
|
* @property string $name
|
||||||
* @property string $cron_day_of_week
|
* @property string $cron_day_of_week
|
||||||
|
* @property string $cron_month
|
||||||
* @property string $cron_day_of_month
|
* @property string $cron_day_of_month
|
||||||
* @property string $cron_hour
|
* @property string $cron_hour
|
||||||
* @property string $cron_minute
|
* @property string $cron_minute
|
||||||
|
@ -58,6 +59,7 @@ class Schedule extends Model
|
||||||
'server_id',
|
'server_id',
|
||||||
'name',
|
'name',
|
||||||
'cron_day_of_week',
|
'cron_day_of_week',
|
||||||
|
'cron_month',
|
||||||
'cron_day_of_month',
|
'cron_day_of_month',
|
||||||
'cron_hour',
|
'cron_hour',
|
||||||
'cron_minute',
|
'cron_minute',
|
||||||
|
@ -93,6 +95,7 @@ class Schedule extends Model
|
||||||
protected $attributes = [
|
protected $attributes = [
|
||||||
'name' => null,
|
'name' => null,
|
||||||
'cron_day_of_week' => '*',
|
'cron_day_of_week' => '*',
|
||||||
|
'cron_month' => '*',
|
||||||
'cron_day_of_month' => '*',
|
'cron_day_of_month' => '*',
|
||||||
'cron_hour' => '*',
|
'cron_hour' => '*',
|
||||||
'cron_minute' => '*',
|
'cron_minute' => '*',
|
||||||
|
@ -107,6 +110,7 @@ class Schedule extends Model
|
||||||
'server_id' => 'required|exists:servers,id',
|
'server_id' => 'required|exists:servers,id',
|
||||||
'name' => 'required|string|max:191',
|
'name' => 'required|string|max:191',
|
||||||
'cron_day_of_week' => 'required|string',
|
'cron_day_of_week' => 'required|string',
|
||||||
|
'cron_month' => 'required|string',
|
||||||
'cron_day_of_month' => 'required|string',
|
'cron_day_of_month' => 'required|string',
|
||||||
'cron_hour' => 'required|string',
|
'cron_hour' => 'required|string',
|
||||||
'cron_minute' => 'required|string',
|
'cron_minute' => 'required|string',
|
||||||
|
@ -123,7 +127,7 @@ class Schedule extends Model
|
||||||
*/
|
*/
|
||||||
public function getNextRunDate()
|
public function getNextRunDate()
|
||||||
{
|
{
|
||||||
$formatted = sprintf('%s %s %s * %s', $this->cron_minute, $this->cron_hour, $this->cron_day_of_month, $this->cron_day_of_week);
|
$formatted = sprintf('%s %s %s %s %s', $this->cron_minute, $this->cron_hour, $this->cron_day_of_month, $this->cron_month, $this->cron_day_of_week);
|
||||||
|
|
||||||
return CarbonImmutable::createFromTimestamp(
|
return CarbonImmutable::createFromTimestamp(
|
||||||
CronExpression::factory($formatted)->getNextRunDate()->getTimestamp()
|
CronExpression::factory($formatted)->getNextRunDate()->getTimestamp()
|
||||||
|
|
|
@ -40,6 +40,7 @@ class ScheduleTransformer extends BaseClientTransformer
|
||||||
'cron' => [
|
'cron' => [
|
||||||
'day_of_week' => $model->cron_day_of_week,
|
'day_of_week' => $model->cron_day_of_week,
|
||||||
'day_of_month' => $model->cron_day_of_month,
|
'day_of_month' => $model->cron_day_of_month,
|
||||||
|
'month' => $model->cron_month,
|
||||||
'hour' => $model->cron_hour,
|
'hour' => $model->cron_hour,
|
||||||
'minute' => $model->cron_minute,
|
'minute' => $model->cron_minute,
|
||||||
],
|
],
|
||||||
|
|
32
database/migrations/2021_01_13_013420_add_cron_month.php
Normal file
32
database/migrations/2021_01_13_013420_add_cron_month.php
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddCronMonth extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('schedules', function (Blueprint $table) {
|
||||||
|
$table->string('cron_month')->after('cron_day_of_week');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('schedules', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('cron_month');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ export default (uuid: string, schedule: Data): Promise<Schedule> => {
|
||||||
minute: schedule.cron.minute,
|
minute: schedule.cron.minute,
|
||||||
hour: schedule.cron.hour,
|
hour: schedule.cron.hour,
|
||||||
day_of_month: schedule.cron.dayOfMonth,
|
day_of_month: schedule.cron.dayOfMonth,
|
||||||
|
month: schedule.cron.month,
|
||||||
day_of_week: schedule.cron.dayOfWeek,
|
day_of_week: schedule.cron.dayOfWeek,
|
||||||
})
|
})
|
||||||
.then(({ data }) => resolve(rawDataToServerSchedule(data.attributes)))
|
.then(({ data }) => resolve(rawDataToServerSchedule(data.attributes)))
|
||||||
|
|
|
@ -5,6 +5,7 @@ export interface Schedule {
|
||||||
name: string;
|
name: string;
|
||||||
cron: {
|
cron: {
|
||||||
dayOfWeek: string;
|
dayOfWeek: string;
|
||||||
|
month: string;
|
||||||
dayOfMonth: string;
|
dayOfMonth: string;
|
||||||
hour: string;
|
hour: string;
|
||||||
minute: string;
|
minute: string;
|
||||||
|
@ -46,6 +47,7 @@ export const rawDataToServerSchedule = (data: any): Schedule => ({
|
||||||
name: data.name,
|
name: data.name,
|
||||||
cron: {
|
cron: {
|
||||||
dayOfWeek: data.cron.day_of_week,
|
dayOfWeek: data.cron.day_of_week,
|
||||||
|
month: data.cron.month,
|
||||||
dayOfMonth: data.cron.day_of_month,
|
dayOfMonth: data.cron.day_of_month,
|
||||||
hour: data.cron.hour,
|
hour: data.cron.hour,
|
||||||
minute: data.cron.minute,
|
minute: data.cron.minute,
|
||||||
|
|
|
@ -19,6 +19,7 @@ type Props = {
|
||||||
interface Values {
|
interface Values {
|
||||||
name: string;
|
name: string;
|
||||||
dayOfWeek: string;
|
dayOfWeek: string;
|
||||||
|
month: string;
|
||||||
dayOfMonth: string;
|
dayOfMonth: string;
|
||||||
hour: string;
|
hour: string;
|
||||||
minute: string;
|
minute: string;
|
||||||
|
@ -38,7 +39,7 @@ const EditScheduleModal = ({ schedule, ...props }: Omit<Props, 'onScheduleUpdate
|
||||||
label={'Schedule name'}
|
label={'Schedule name'}
|
||||||
description={'A human readable identifer for this schedule.'}
|
description={'A human readable identifer for this schedule.'}
|
||||||
/>
|
/>
|
||||||
<div css={tw`grid grid-cols-2 sm:grid-cols-4 gap-4 mt-6`}>
|
<div css={tw`grid grid-cols-2 sm:grid-cols-5 gap-4 mt-6`}>
|
||||||
<div>
|
<div>
|
||||||
<Field name={'minute'} label={'Minute'}/>
|
<Field name={'minute'} label={'Minute'}/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -48,6 +49,9 @@ const EditScheduleModal = ({ schedule, ...props }: Omit<Props, 'onScheduleUpdate
|
||||||
<div>
|
<div>
|
||||||
<Field name={'dayOfMonth'} label={'Day of month'}/>
|
<Field name={'dayOfMonth'} label={'Day of month'}/>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<Field name={'month'} label={'Month'}/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Field name={'dayOfWeek'} label={'Day of week'}/>
|
<Field name={'dayOfWeek'} label={'Day of week'}/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -94,6 +98,7 @@ export default ({ schedule, visible, ...props }: Props) => {
|
||||||
minute: values.minute,
|
minute: values.minute,
|
||||||
hour: values.hour,
|
hour: values.hour,
|
||||||
dayOfWeek: values.dayOfWeek,
|
dayOfWeek: values.dayOfWeek,
|
||||||
|
month: values.month,
|
||||||
dayOfMonth: values.dayOfMonth,
|
dayOfMonth: values.dayOfMonth,
|
||||||
},
|
},
|
||||||
isActive: values.enabled,
|
isActive: values.enabled,
|
||||||
|
@ -116,10 +121,11 @@ export default ({ schedule, visible, ...props }: Props) => {
|
||||||
onSubmit={submit}
|
onSubmit={submit}
|
||||||
initialValues={{
|
initialValues={{
|
||||||
name: schedule?.name || '',
|
name: schedule?.name || '',
|
||||||
dayOfWeek: schedule?.cron.dayOfWeek || '*',
|
|
||||||
dayOfMonth: schedule?.cron.dayOfMonth || '*',
|
|
||||||
hour: schedule?.cron.hour || '*',
|
|
||||||
minute: schedule?.cron.minute || '*/5',
|
minute: schedule?.cron.minute || '*/5',
|
||||||
|
hour: schedule?.cron.hour || '*',
|
||||||
|
dayOfMonth: schedule?.cron.dayOfMonth || '*',
|
||||||
|
month: schedule?.cron.month || '*',
|
||||||
|
dayOfWeek: schedule?.cron.dayOfWeek || '*',
|
||||||
enabled: schedule ? schedule.isActive : true,
|
enabled: schedule ? schedule.isActive : true,
|
||||||
} as Values}
|
} as Values}
|
||||||
validationSchema={null}
|
validationSchema={null}
|
||||||
|
|
|
@ -22,7 +22,7 @@ const ScheduleCronRow = ({ cron, className }: Props) => (
|
||||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Day (Month)</p>
|
<p css={tw`text-2xs text-neutral-500 uppercase`}>Day (Month)</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
||||||
<p css={tw`font-medium`}>*</p>
|
<p css={tw`font-medium`}>{cron.month}</p>
|
||||||
<p css={tw`text-2xs text-neutral-500 uppercase`}>Month</p>
|
<p css={tw`text-2xs text-neutral-500 uppercase`}>Month</p>
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
<div css={tw`w-1/5 sm:w-auto text-center ml-4`}>
|
||||||
|
|
|
@ -28,9 +28,9 @@ interface State {
|
||||||
}
|
}
|
||||||
|
|
||||||
const CronBox = ({ title, value }: { title: string; value: string }) => (
|
const CronBox = ({ title, value }: { title: string; value: string }) => (
|
||||||
<div css={tw`bg-neutral-700 rounded p-4`}>
|
<div css={tw`bg-neutral-700 rounded p-3`}>
|
||||||
<p css={tw`text-neutral-300 text-sm`}>{title}</p>
|
<p css={tw`text-neutral-300 text-sm`}>{title}</p>
|
||||||
<p css={tw`text-2xl font-medium text-neutral-100`}>{value}</p>
|
<p css={tw`text-xl font-medium text-neutral-100`}>{value}</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -88,13 +88,6 @@ export default () => {
|
||||||
:
|
:
|
||||||
<>
|
<>
|
||||||
<ScheduleCronRow cron={schedule.cron} css={tw`sm:hidden bg-neutral-700 rounded mb-4 p-3`}/>
|
<ScheduleCronRow cron={schedule.cron} css={tw`sm:hidden bg-neutral-700 rounded mb-4 p-3`}/>
|
||||||
<div css={tw`hidden sm:grid grid-cols-5 md:grid-cols-7 gap-4 mb-6`}>
|
|
||||||
<CronBox title={'Minute'} value={schedule.cron.minute}/>
|
|
||||||
<CronBox title={'Hour'} value={schedule.cron.hour}/>
|
|
||||||
<CronBox title={'Day (Month)'} value={schedule.cron.dayOfMonth}/>
|
|
||||||
<CronBox title={'Month'} value={'*'}/>
|
|
||||||
<CronBox title={'Day (Week)'} value={schedule.cron.dayOfWeek}/>
|
|
||||||
</div>
|
|
||||||
<div css={tw`rounded shadow`}>
|
<div css={tw`rounded shadow`}>
|
||||||
<div css={tw`sm:flex items-center bg-neutral-900 p-3 sm:p-6 border-b-4 border-neutral-600 rounded-t`}>
|
<div css={tw`sm:flex items-center bg-neutral-900 p-3 sm:p-6 border-b-4 border-neutral-600 rounded-t`}>
|
||||||
<div css={tw`flex-1`}>
|
<div css={tw`flex-1`}>
|
||||||
|
@ -143,6 +136,13 @@ export default () => {
|
||||||
</Can>
|
</Can>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div css={tw`hidden sm:grid grid-cols-5 md:grid-cols-5 gap-4 mb-4 mt-4`}>
|
||||||
|
<CronBox title={'Minute'} value={schedule.cron.minute}/>
|
||||||
|
<CronBox title={'Hour'} value={schedule.cron.hour}/>
|
||||||
|
<CronBox title={'Day (Month)'} value={schedule.cron.dayOfMonth}/>
|
||||||
|
<CronBox title={'Month'} value={schedule.cron.month}/>
|
||||||
|
<CronBox title={'Day (Week)'} value={schedule.cron.dayOfWeek}/>
|
||||||
|
</div>
|
||||||
<div css={tw`bg-neutral-700 rounded-b`}>
|
<div css={tw`bg-neutral-700 rounded-b`}>
|
||||||
{schedule.tasks.length > 0 ?
|
{schedule.tasks.length > 0 ?
|
||||||
schedule.tasks.map(task => (
|
schedule.tasks.map(task => (
|
||||||
|
|
|
@ -25,6 +25,7 @@ class CreateServerScheduleTest extends ClientApiIntegrationTestCase
|
||||||
'minute' => '0',
|
'minute' => '0',
|
||||||
'hour' => '*/2',
|
'hour' => '*/2',
|
||||||
'day_of_week' => '2',
|
'day_of_week' => '2',
|
||||||
|
'month' => '1',
|
||||||
'day_of_month' => '*',
|
'day_of_month' => '*',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -39,6 +40,7 @@ class CreateServerScheduleTest extends ClientApiIntegrationTestCase
|
||||||
$this->assertSame('0', $schedule->cron_minute);
|
$this->assertSame('0', $schedule->cron_minute);
|
||||||
$this->assertSame('*/2', $schedule->cron_hour);
|
$this->assertSame('*/2', $schedule->cron_hour);
|
||||||
$this->assertSame('2', $schedule->cron_day_of_week);
|
$this->assertSame('2', $schedule->cron_day_of_week);
|
||||||
|
$this->assertSame('1', $schedule->cron_month);
|
||||||
$this->assertSame('*', $schedule->cron_day_of_month);
|
$this->assertSame('*', $schedule->cron_day_of_month);
|
||||||
$this->assertSame('Test Schedule', $schedule->name);
|
$this->assertSame('Test Schedule', $schedule->name);
|
||||||
|
|
||||||
|
@ -69,6 +71,7 @@ class CreateServerScheduleTest extends ClientApiIntegrationTestCase
|
||||||
'minute' => '*',
|
'minute' => '*',
|
||||||
'hour' => '*',
|
'hour' => '*',
|
||||||
'day_of_month' => '*',
|
'day_of_month' => '*',
|
||||||
|
'month' => '*',
|
||||||
'day_of_week' => '*',
|
'day_of_week' => '*',
|
||||||
])
|
])
|
||||||
->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY)
|
->assertStatus(Response::HTTP_UNPROCESSABLE_ENTITY)
|
||||||
|
|
|
@ -19,6 +19,7 @@ class UpdateServerScheduleTest extends ClientApiIntegrationTestCase
|
||||||
'minute' => '5',
|
'minute' => '5',
|
||||||
'hour' => '*',
|
'hour' => '*',
|
||||||
'day_of_week' => '*',
|
'day_of_week' => '*',
|
||||||
|
'month' => '*',
|
||||||
'day_of_month' => '*',
|
'day_of_month' => '*',
|
||||||
'is_active' => false,
|
'is_active' => false,
|
||||||
];
|
];
|
||||||
|
@ -35,7 +36,7 @@ class UpdateServerScheduleTest extends ClientApiIntegrationTestCase
|
||||||
|
|
||||||
/** @var \Pterodactyl\Models\Schedule $schedule */
|
/** @var \Pterodactyl\Models\Schedule $schedule */
|
||||||
$schedule = factory(Schedule::class)->create(['server_id' => $server->id]);
|
$schedule = factory(Schedule::class)->create(['server_id' => $server->id]);
|
||||||
$expected = Utilities::getScheduleNextRunDate('5', '*', '*', '*');
|
$expected = Utilities::getScheduleNextRunDate('5', '*', '*', '*', '*');
|
||||||
|
|
||||||
$response = $this->actingAs($user)
|
$response = $this->actingAs($user)
|
||||||
->postJson("/api/client/servers/{$server->uuid}/schedules/{$schedule->id}", $this->updateData);
|
->postJson("/api/client/servers/{$server->uuid}/schedules/{$schedule->id}", $this->updateData);
|
||||||
|
|
Loading…
Reference in a new issue