Adds months for schedules

Adds month variable for schedules
This commit is contained in:
Charles Morgan 2021-01-16 22:07:39 -05:00
parent 9684456480
commit ffeedf17e4
12 changed files with 65 additions and 11 deletions

View file

@ -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());
} }

View file

@ -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) {

View file

@ -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()

View file

@ -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,
], ],

View 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');
});
}
}

View file

@ -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)))

View file

@ -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,

View file

@ -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}

View file

@ -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`}>

View file

@ -88,11 +88,11 @@ 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`}> <div css={tw`hidden sm:grid grid-cols-6 md:grid-cols-7 gap-4 mb-6`}>
<CronBox title={'Minute'} value={schedule.cron.minute}/> <CronBox title={'Minute'} value={schedule.cron.minute}/>
<CronBox title={'Hour'} value={schedule.cron.hour}/> <CronBox title={'Hour'} value={schedule.cron.hour}/>
<CronBox title={'Day (Month)'} value={schedule.cron.dayOfMonth}/> <CronBox title={'Day (Month)'} value={schedule.cron.dayOfMonth}/>
<CronBox title={'Month'} value={'*'}/> <CronBox title={'Month'} value={schedule.cron.month}/>
<CronBox title={'Day (Week)'} value={schedule.cron.dayOfWeek}/> <CronBox title={'Day (Week)'} value={schedule.cron.dayOfWeek}/>
</div> </div>
<div css={tw`rounded shadow`}> <div css={tw`rounded shadow`}>

View file

@ -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)

View file

@ -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);