diff --git a/admin/cli/scheduled_task.php b/admin/cli/scheduled_task.php index cf6e3accd80..6c8144b45fb 100644 --- a/admin/cli/scheduled_task.php +++ b/admin/cli/scheduled_task.php @@ -36,6 +36,8 @@ list($options, $unrecognized) = cli_get_params( 'showsql' => false, 'showdebugging' => false, 'force' => false, + 'disable' => false, + 'enable' => false, ], [ 'h' => 'help', 'f' => 'force', @@ -47,11 +49,15 @@ if ($unrecognized) { cli_error(get_string('cliunknowoption', 'admin', $unrecognized)); } -if ($options['help'] or (!$options['list'] and !$options['execute'])) { +$commands = ['list', 'execute', 'disable', 'enable']; +$hascommand = count(array_filter($commands, fn($command) => $options[$command])) > 0; +if ($options['help'] || !$hascommand) { $help = "Scheduled cron tasks. Options: + --disable=\\some\\task Disable scheduled task + --enable=\\some\\task Enable scheduled task --execute=\\some\\task Execute scheduled task manually --list List all scheduled tasks --showsql Show sql queries before they are executed @@ -119,14 +125,40 @@ if ($options['list']) { exit(0); } -if ($execute = $options['execute']) { - if (!$task = \core\task\manager::get_scheduled_task($execute)) { - mtrace("Task '$execute' not found"); +if (moodle_needs_upgrading()) { + mtrace("Moodle upgrade pending, cannot manage tasks."); + exit(1); +} + +if ($disable = $options['disable']) { + if (!$task = \core\task\manager::get_scheduled_task($disable)) { + mtrace("Task '$disable' not found"); exit(1); } - if (moodle_needs_upgrading()) { - mtrace("Moodle upgrade pending, cannot execute tasks."); + try { + $task->disable(); + mtrace("Disabled '$disable'"); + } catch (Exception $e) { + mtrace("$e->getMessage()"); + exit(1); + } +} else if ($enable = $options['enable']) { + if (!$task = \core\task\manager::get_scheduled_task($enable)) { + mtrace("Task '$enable' not found"); + exit(1); + } + + try { + $task->enable(); + mtrace("Enabled '$enable'"); + } catch (Exception $e) { + mtrace("$e->getMessage()"); + exit(1); + } +} else if ($execute = $options['execute']) { + if (!$task = \core\task\manager::get_scheduled_task($execute)) { + mtrace("Task '$execute' not found"); exit(1); } diff --git a/lib/classes/task/scheduled_task.php b/lib/classes/task/scheduled_task.php index 0eadddb6a71..f8f4943f055 100644 --- a/lib/classes/task/scheduled_task.php +++ b/lib/classes/task/scheduled_task.php @@ -132,7 +132,7 @@ abstract class scheduled_task extends task_base { } /** - * Has this task been changed from it's default config? + * Set customised for this scheduled task. * * @param bool */ @@ -140,6 +140,53 @@ abstract class scheduled_task extends task_base { $this->customised = $customised; } + /** + * Determine if this task is using its default configuration changed from the default. Returns true + * if it is and false otherwise. Does not rely on the customised field. + * + * @return bool + */ + public function has_default_configuration(): bool { + $defaulttask = \core\task\manager::get_default_scheduled_task($this::class); + if ($defaulttask->get_minute() !== $this->get_minute()) { + return false; + } + if ($defaulttask->get_hour() != $this->get_hour()) { + return false; + } + if ($defaulttask->get_month() != $this->get_month()) { + return false; + } + if ($defaulttask->get_day_of_week() != $this->get_day_of_week()) { + return false; + } + if ($defaulttask->get_day() != $this->get_day()) { + return false; + } + if ($defaulttask->get_disabled() != $this->get_disabled()) { + return false; + } + return true; + } + + /** + * Disable the task. + */ + public function disable(): void { + $this->set_disabled(true); + $this->set_customised(!$this->has_default_configuration()); + \core\task\manager::configure_scheduled_task($this); + } + + /** + * Enable the task. + */ + public function enable(): void { + $this->set_disabled(false); + $this->set_customised(!$this->has_default_configuration()); + \core\task\manager::configure_scheduled_task($this); + } + /** * Has this task been changed from it's default config? * diff --git a/lib/tests/task/scheduled_task_test.php b/lib/tests/task/scheduled_task_test.php index ee564bb838a..b1de1b95c11 100644 --- a/lib/tests/task/scheduled_task_test.php +++ b/lib/tests/task/scheduled_task_test.php @@ -26,6 +26,7 @@ require_once(__DIR__ . '/../fixtures/task_fixtures.php'); * @category test * @copyright 2013 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @coversDefaultClass \core\task\scheduled_task */ class scheduled_task_test extends \advanced_testcase { @@ -807,4 +808,55 @@ class scheduled_task_test extends \advanced_testcase { $task = new scheduled_test_task(); $this->assertTrue($task->is_component_enabled()); } + + /** + * Test disabling and enabling individual tasks. + * + * @covers ::disable + * @covers ::enable + * @covers ::has_default_configuration + */ + public function test_disable_and_enable_task(): void { + $this->resetAfterTest(); + + // We use a real task because the manager doesn't know about the test tasks. + $taskname = '\core\task\send_new_user_passwords_task'; + + $task = manager::get_scheduled_task($taskname); + $defaulttask = manager::get_default_scheduled_task($taskname); + $this->assertTaskEquals($task, $defaulttask); + + // Disable task and verify drift. + $task->disable(); + $this->assertTaskNotEquals($task, $defaulttask); + $this->assertEquals(1, $task->get_disabled()); + $this->assertEquals(false, $task->has_default_configuration()); + + // Enable task and verify not drifted. + $task->enable(); + $this->assertTaskEquals($task, $defaulttask); + $this->assertEquals(0, $task->get_disabled()); + $this->assertEquals(true, $task->has_default_configuration()); + + // Modify task and verify drift. + $task->set_hour(1); + \core\task\manager::configure_scheduled_task($task); + $this->assertTaskNotEquals($task, $defaulttask); + $this->assertEquals(1, $task->get_hour()); + $this->assertEquals(false, $task->has_default_configuration()); + + // Disable task and verify drift. + $task->disable(); + $this->assertTaskNotEquals($task, $defaulttask); + $this->assertEquals(1, $task->get_disabled()); + $this->assertEquals(1, $task->get_hour()); + $this->assertEquals(false, $task->has_default_configuration()); + + // Enable task and verify drift. + $task->enable(); + $this->assertTaskNotEquals($task, $defaulttask); + $this->assertEquals(0, $task->get_disabled()); + $this->assertEquals(1, $task->get_hour()); + $this->assertEquals(false, $task->has_default_configuration()); + } }