diff --git a/trigger/enddate/README.md b/trigger/enddate/README.md new file mode 100644 index 00000000..9713da42 --- /dev/null +++ b/trigger/enddate/README.md @@ -0,0 +1,3 @@ +# moodle-lifecycletrigger_enddate + +This subplugin adds a trigger for the tool lifecycle that depends on the course enddate. diff --git a/trigger/enddate/classes/privacy/provider.php b/trigger/enddate/classes/privacy/provider.php new file mode 100644 index 00000000..a0209e9a --- /dev/null +++ b/trigger/enddate/classes/privacy/provider.php @@ -0,0 +1,40 @@ +. + +namespace lifecycletrigger_enddate\privacy; + +use core_privacy\local\metadata\null_provider; + +/** + * Privacy subsystem implementation for lifecycletrigger_enddate. + * + * @package lifecycletrigger_enddate + * @copyright 2022 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class provider implements null_provider { + + /** + * Get the language string identifier with the component's language + * file to explain why this plugin stores no data. + * + * @return string the reason + */ + public static function get_reason(): string { + return 'privacy:metadata'; + } +} diff --git a/trigger/enddate/lang/de/lifecycletrigger_enddate.php b/trigger/enddate/lang/de/lifecycletrigger_enddate.php new file mode 100644 index 00000000..d498b81f --- /dev/null +++ b/trigger/enddate/lang/de/lifecycletrigger_enddate.php @@ -0,0 +1,31 @@ +. + +/** + * Lang strings for start date delay trigger + * + * @package lifecycletrigger_enddate + * @copyright 2025 Ostfalia + * @copyright 2017 Tobias Reischmann WWU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['delay'] = 'Zeit seit Kursendedatum, bis ein Prozess gestartet wird'; +$string['delay_help'] = 'Dieser Trigger wird ausgeführt, sobald die Zeit, die seit dem Ende des Kurses vergangen ist, größer ist als der angegebene Zeitraum.'; +$string['plugindescription'] = 'Trigger des Lifecycle-Tools, der bestimmt, wieviel Zeit nach dem Endedatum des Kurses verstreichen muss, ehe dieser Workflow startet.'; +$string['pluginname'] = 'Endedatumsabstand - Trigger'; +$string['privacy:metadata'] = 'Dieses Subplugin speichert keine persönlichen Daten.'; + diff --git a/trigger/enddate/lang/en/lifecycletrigger_enddate.php b/trigger/enddate/lang/en/lifecycletrigger_enddate.php new file mode 100644 index 00000000..248ea27e --- /dev/null +++ b/trigger/enddate/lang/en/lifecycletrigger_enddate.php @@ -0,0 +1,31 @@ +. + +/** + * Lang strings for start date delay trigger + * + * @package lifecycletrigger_enddate + * @copyright 2025 Ostfalia + * @copyright 2017 Tobias Reischmann WWU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +$string['delay'] = 'Delay from end of course until starting a process'; +$string['delay_help'] = 'The trigger will be invoked if the time passed since the course has ended is longer than this delay.'; +$string['plugindescription'] = 'Defines the time that has to pass after the course end date has been reached before this workflow starts.'; +$string['pluginname'] = 'End date trigger'; +$string['privacy:metadata'] = 'This subplugin does not store any personal data.'; + diff --git a/trigger/enddate/lib.php b/trigger/enddate/lib.php new file mode 100644 index 00000000..44328edb --- /dev/null +++ b/trigger/enddate/lib.php @@ -0,0 +1,112 @@ +. + +/** + * Subplugin for the start date delay. + * + * @package lifecycletrigger_enddate + * @copyright 2025 Ostfalia + * @copyright 2017 Tobias Reischmann WWU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace tool_lifecycle\trigger; + +use tool_lifecycle\local\manager\settings_manager; +use tool_lifecycle\local\response\trigger_response; +use tool_lifecycle\settings_type; + +defined('MOODLE_INTERNAL') || die(); +require_once(__DIR__ . '/../lib.php'); +require_once(__DIR__ . '/../../lib.php'); + +/** + * Class which implements the basic methods necessary for a cleanyp courses trigger subplugin + * + * @package lifecycletrigger_enddate + * @copyright 2025 Ostfalia + * @copyright 2017 Tobias Reischmann WWU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class enddate extends base_automatic { + + /** + * If check_course_code() returns true, code to check the given course is placed here + * @param object $course + * @param int $triggerid + * @return trigger_response + */ + public function check_course($course, $triggerid) { + return trigger_response::trigger(); + } + + /** + * Add sql comparing the current date to the start date of a course in combination with the specified delay. + * @param int $triggerid Id of the trigger. + * @return array A list containing the constructed sql fragment and an array of parameters. + * @throws \coding_exception + * @throws \dml_exception + */ + public function get_course_recordset_where($triggerid) { + $delay = settings_manager::get_settings($triggerid, settings_type::TRIGGER)['delay']; + $where = "c.enddate > 0 AND c.enddate < :enddatedelay"; + $params = [ + "enddatedelay" => time() - $delay, + ]; + return [$where, $params]; + } + + /** + * The return value should be equivalent with the name of the subplugin folder. + * @return string technical name of the subplugin + */ + public function get_subpluginname() { + return 'enddate'; + } + + /** + * Defines which settings each instance of the subplugin offers for the user to define. + * @return instance_setting[] containing settings keys and PARAM_TYPES + */ + public function instance_settings() { + return [ + new instance_setting('delay', PARAM_INT, true), + ]; + } + + /** + * At the delay since the start date of a course. + * @param \MoodleQuickForm $mform + * @throws \coding_exception + */ + public function extend_add_instance_form_definition($mform) { + $mform->addElement('duration', 'delay', get_string('delay', 'lifecycletrigger_enddate')); + $mform->addHelpButton('delay', 'delay', 'lifecycletrigger_enddate'); + } + + /** + * Reset the delay at the add instance form initializiation. + * @param \MoodleQuickForm $mform + * @param array $settings array containing the settings from the db. + */ + public function extend_add_instance_form_definition_after_data($mform, $settings) { + if (is_array($settings) && array_key_exists('delay', $settings)) { + $default = $settings['delay']; + } else { + $default = 24 * 60 * 60; // One day. + } + $mform->setDefault('delay', $default); + } +} diff --git a/trigger/enddate/tests/generator/lib.php b/trigger/enddate/tests/generator/lib.php new file mode 100644 index 00000000..dfd4b692 --- /dev/null +++ b/trigger/enddate/tests/generator/lib.php @@ -0,0 +1,71 @@ +. + +/** + * lifecycletrigger_enddate generator tests + * + * @package lifecycletrigger_enddate + * @category test + * @copyright 2025 Ostfalia + * @copyright 2018 Tobias Reischmann WWU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +use tool_lifecycle\local\entity\trigger_subplugin; +use tool_lifecycle\local\entity\workflow; +use tool_lifecycle\local\manager\settings_manager; +use tool_lifecycle\local\manager\trigger_manager; +use tool_lifecycle\local\manager\workflow_manager; +use tool_lifecycle\settings_type; + +/** + * lifecycletrigger_enddate generator tests + * + * @package lifecycletrigger_enddate + * @category test + * @copyright 2025 Ostfalia + * @copyright 2018 Tobias Reischmann WWU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class tool_lifecycle_trigger_enddate_generator extends testing_module_generator { + + /** + * Creates a trigger enddatedelay for an artificial workflow without steps. + * @return trigger_subplugin the created enddatedelay trigger. + * @throws moodle_exception + */ + public static function create_trigger_with_workflow() { + // Create Workflow. + $record = new stdClass(); + $record->id = null; + $record->title = 'myworkflow'; + $workflow = workflow::from_record($record); + workflow_manager::insert_or_update($workflow); + // Create trigger. + $record = new stdClass(); + $record->subpluginname = 'enddate'; + $record->instancename = 'enddate'; + $record->workflowid = $workflow->id; + $trigger = trigger_subplugin::from_record($record); + trigger_manager::insert_or_update($trigger); + // Set delay setting. + $settings = new stdClass(); + $settings->delay = 10 * DAYSECS; // Trigger when 10 days have passed. + settings_manager::save_settings($trigger->id, settings_type::TRIGGER, $trigger->subpluginname, $settings); + + return $trigger; + } +} diff --git a/trigger/enddate/tests/trigger_test.php b/trigger/enddate/tests/trigger_test.php new file mode 100644 index 00000000..866f371d --- /dev/null +++ b/trigger/enddate/tests/trigger_test.php @@ -0,0 +1,121 @@ +. + +/** + * Trigger test for start date delay trigger. + * + * @package lifecycletrigger_enddate + * @group lifecycletrigger + * @copyright 2025 Ostfalia + * @copyright 2017 Tobias Reischmann WWU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace lifecycletrigger_enddate; + +use tool_lifecycle\local\entity\trigger_subplugin; +use tool_lifecycle\processor; + +defined('MOODLE_INTERNAL') || die(); + +require_once(__DIR__ . '/../lib.php'); +require_once(__DIR__ . '/generator/lib.php'); + +/** + * Trigger test for end date trigger. + * + * @package lifecycletrigger_enddate + * @group lifecycletrigger + * @copyright 2025 Ostfalia + * @copyright 2017 Tobias Reischmann WWU + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +final class trigger_test extends \advanced_testcase { + + /** @var $triggerinstance trigger_subplugin Instance of the trigger. */ + private $triggerinstance; + + /** @var $processor processor Instance of the lifecycle processor. */ + private $processor; + + public function setUp(): void { + parent::setUp(); + $this->resetAfterTest(true); + $this->setAdminUser(); + + $this->processor = new processor(); + $this->triggerinstance = \tool_lifecycle_trigger_enddate_generator::create_trigger_with_workflow(); + } + + /** + * Tests if courses, which are has ended 10 days before are not triggered by this plugin. + * @covers \tool_lifecycle\processor \tool_lifecycle\trigger\startdatedelay + */ + public function test_young_course(): void { + + $course = $this->getDataGenerator()->create_course( + ['startdate' => time() - 200 * DAYSECS, 'enddate' => time() - 10 * DAYSECS + 10]); + + $recordset = $this->processor->get_course_recordset([$this->triggerinstance]); + $found = false; + foreach ($recordset as $element) { + if ($course->id === $element->id) { + $found = true; + break; + } + } + $this->assertFalse($found, 'The course should not have been triggered'); + } + + /** + * Tests if courses without and enddate are not triggered by this plugin. + * @covers \tool_lifecycle\processor \tool_lifecycle\trigger\startdatedelay + */ + public function test_never_ending_course(): void { + + $course = $this->getDataGenerator()->create_course( + ['startdate' => time() - 200 * DAYSECS]); + + $recordset = $this->processor->get_course_recordset([$this->triggerinstance]); + $found = false; + foreach ($recordset as $element) { + if ($course->id === $element->id) { + $found = true; + break; + } + } + $this->assertFalse($found, 'The course should not have been triggered'); + } + + /** + * Tests if courses, which have ended before 10 days and a few seconds are triggered by this plugin. + * @covers \tool_lifecycle\processor \tool_lifecycle\trigger\startdatedelay + */ + public function test_old_course(): void { + + $course = $this->getDataGenerator()->create_course(['startdate' => time() - 300 * DAYSECS, + 'enddate' => time() - 10 * DAYSECS - 10]); + + $recordset = $this->processor->get_course_recordset([$this->triggerinstance]); + $found = false; + foreach ($recordset as $element) { + if ($course->id === $element->id) { + $found = true; + break; + } + } + $this->assertTrue($found, 'The course should have been triggered'); + } +} diff --git a/trigger/enddate/version.php b/trigger/enddate/version.php new file mode 100644 index 00000000..82fb4bd0 --- /dev/null +++ b/trigger/enddate/version.php @@ -0,0 +1,33 @@ +. + +/** + * Life Cycle Enddate Trigger + * + * @package lifecycletrigger_enddate + * @copyright 2025 Ostfalia + * @copyright 2025 Thomas Niedermaier Universität Münster + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die; + +$plugin->version = 2025111100; +$plugin->requires = 2022112800; // Requires Moodle 4.1+. +$plugin->supported = [405, 500]; +$plugin->component = 'lifecycletrigger_enddate'; +$plugin->release = 'v5.0-r1'; +$plugin->maturity = MATURITY_STABLE;