diff --git a/classes/local/backup/restore_lifecycle_workflow.php b/classes/local/backup/restore_lifecycle_workflow.php index 5e9b1fe9..cd05dba4 100644 --- a/classes/local/backup/restore_lifecycle_workflow.php +++ b/classes/local/backup/restore_lifecycle_workflow.php @@ -87,7 +87,7 @@ public function execute(bool $force = false) { $this->check_subplugin_validity(); if (empty($this->errors) || $force) { // If all loaded data is valid, the new workflow and the steps can be stored in the database. - // If we force the import, we empty the errors; + // If we force the import, we empty the errors. $this->errors = []; $this->persist(); } diff --git a/classes/local/manager/interaction_manager.php b/classes/local/manager/interaction_manager.php index 87ecfff8..f263fb8a 100644 --- a/classes/local/manager/interaction_manager.php +++ b/classes/local/manager/interaction_manager.php @@ -170,7 +170,7 @@ public static function get_process_status_message($processid) { } if ($process->stepindex == 0) { - // TODO: Rethink behaviour for multiple triggers. + // Software enhancement: Rethink behaviour for multiple triggers. $trigger = trigger_manager::get_triggers_for_workflow($process->workflowid)[0]; $triggerlib = lib_manager::get_trigger_lib($trigger->subpluginname); return $triggerlib->get_status_message(); diff --git a/classes/local/manager/workflow_manager.php b/classes/local/manager/workflow_manager.php index 4d395090..b30d54e7 100644 --- a/classes/local/manager/workflow_manager.php +++ b/classes/local/manager/workflow_manager.php @@ -257,7 +257,7 @@ public static function activate_workflow($workflowid) { $transaction = $DB->start_delegated_transaction(); $workflow = self::get_workflow($workflowid); if (!self::is_active($workflow->id)) { - // TODO: Rethink behaviour for multiple triggers. + // Software enhancement: Rethink behaviour for multiple triggers. $trigger = trigger_manager::get_triggers_for_workflow($workflowid)[0]; $lib = lib_manager::get_trigger_lib($trigger->subpluginname); $workflow->manual = $lib->is_manual_trigger(); diff --git a/classes/local/table/interaction_attention_table.php b/classes/local/table/interaction_attention_table.php index 2624831d..e67b7a86 100644 --- a/classes/local/table/interaction_attention_table.php +++ b/classes/local/table/interaction_attention_table.php @@ -51,15 +51,14 @@ public function __construct($uniqueid, $courseids, $filterdata = null) { global $PAGE, $DB; $fields = "p.id as processid, c.id as courseid, c.fullname as coursefullname, c.shortname as courseshortname, " . - "c.startdate, cc.name as category , s.id as stepinstanceid, s.instancename as stepinstancename, ". - "s.subpluginname as subpluginname"; + "c.startdate, cc.name as category, cc.path as categorypath, s.id as stepinstanceid, " . + "s.instancename as stepinstancename, s.subpluginname as subpluginname"; $from = '{tool_lifecycle_process} p join ' . '{course} c on p.courseid = c.id join ' . '{tool_lifecycle_step} s ' . 'on p.workflowid = s.workflowid AND p.stepindex = s.sortindex ' . 'left join {course_categories} cc on c.category = cc.id'; $ids = implode(',', $courseids); - $where = ['FALSE']; if ($ids) { $where = ['p.courseid IN (' . $ids . ')']; diff --git a/classes/local/table/interaction_remaining_table.php b/classes/local/table/interaction_remaining_table.php index 710ffa68..adcf34c8 100644 --- a/classes/local/table/interaction_remaining_table.php +++ b/classes/local/table/interaction_remaining_table.php @@ -58,7 +58,7 @@ public function __construct($uniqueid, $courseids) { // We need to do this, so that courses without any action have a smaller timestamp than courses with an recorded action. // Otherwise, it would mess up the sorting. $fields = "c.id as courseid, p.id AS processid, c.fullname AS coursefullname, c.shortname AS courseshortname, " . - "c.startdate, cc.name AS category, COALESCE(l.time, 0) AS lastmodified, l.userid, " . + "c.startdate, cc.name AS category, cc.path as categorypath, COALESCE(l.time, 0) AS lastmodified, l.userid, " . "l.action, s.subpluginname, "; if ($CFG->branch >= 311) { $fields .= \core_user\fields::for_name()->get_sql('u', false, '', '', false)->selects; diff --git a/classes/local/table/interaction_table.php b/classes/local/table/interaction_table.php index 60d54c9f..c5966ac0 100644 --- a/classes/local/table/interaction_table.php +++ b/classes/local/table/interaction_table.php @@ -42,12 +42,26 @@ */ abstract class interaction_table extends \table_sql { + /** + * In case a specific course category should be shown, all course categories are fetched once ... + * ... to find the suitable category later. + * @var \stdClass + */ + private $coursecategories; + /** * Constructor for interaction_table. * @param int $uniqueid Unique id of this table. */ public function __construct($uniqueid) { + global $DB; parent::__construct($uniqueid); + + if (get_config('tool_lifecycle', 'enablecategoryhierachy')) { + // We have to get the complete category tree. + $this->coursecategories = $DB->get_records_sql('SELECT id, name, depth, path, parent FROM {course_categories} '); + } + $this->set_attribute('class', $this->attributes['class'] . ' ' . $uniqueid); } @@ -107,6 +121,31 @@ public function col_status($row) { return ''; } + /** + * Dependent on the setting either returns the closest category or the category that is on the specified depth, + * if the category depth is not reached the last category is returned. + * @param object $row Row data. + * @return string category name + * @throws \dml_exception + */ + public function col_category($row): String { + $categorydepth = get_config('tool_lifecycle', 'enablecategoryhierachy'); + if ($categorydepth == false) { + return $row->category; + } else { + $categorydepth = (int) get_config('tool_lifecycle', 'coursecategorydepth'); + $categoryhierachy = explode('/', substr($row->categorypath, 1)); + $categoryhierachy = array_map('intval', $categoryhierachy); + if (isset($categoryhierachy[$categorydepth])) { + $category = $this->coursecategories[$categoryhierachy[$categorydepth]]; + return $category->name; + } else { + $category = $this->coursecategories[end($categoryhierachy)]; + return $category->name; + } + } + } + /** * This function is not part of the public api. */ diff --git a/classes/view_controller.php b/classes/view_controller.php index b0696515..9f964e90 100644 --- a/classes/view_controller.php +++ b/classes/view_controller.php @@ -57,7 +57,7 @@ public function handle_view($renderer, $filterdata) { $courses = get_user_capability_course('tool/lifecycle:managecourses', null, false); if (!$courses) { echo 'no courses'; - // TODO show error. + // Software enhancement show error. return; } @@ -142,7 +142,7 @@ public function handle_interaction($action, $processid, $stepid) { */ public function handle_trigger($triggerid, $courseid) { global $PAGE; - // TODO check if trigger to triggerid exists. + // Software enhancement check if trigger to triggerid exists. // Check if trigger is manual. $trigger = trigger_manager::get_instance($triggerid); $lib = lib_manager::get_trigger_lib($trigger->subpluginname); diff --git a/lang/de/tool_lifecycle.php b/lang/de/tool_lifecycle.php index a92d11a1..375c8fe8 100644 --- a/lang/de/tool_lifecycle.php +++ b/lang/de/tool_lifecycle.php @@ -45,10 +45,14 @@ $string['backupcreated'] = 'Erstellt am'; $string['backupworkflow'] = 'Workflow sichern'; $string['cannot_trigger_workflow_manually'] = 'Der Workflow konnte nicht manuell ausgelöst werden.'; +$string['config_coursecategorydepth'] = 'Tiefe der Kurskategorien, die in der Interaktionstabelle angezeigt werden sollen'; +$string['config_coursecategorydepth_desc'] = 'Standardmäßig wird die erste Kategorie angezeigt, wenn Lehrkräfte den Status ihrer Kurse in der view.php verwalten. Die Einstellung ermöglicht es, nicht die erste Ebene der Kategorien, sondern Unterkategorien anzuzeigen.'; $string['config_delay_duration'] = 'Standardlänge eines Kursausschlusses'; $string['config_delay_duration_desc'] = 'Diese Einstellung definiert den Standardlänge einer Kursausschlusses in einem Workflow falls ein Prozess des Workflows zurückgesetzt oder beendigt wird. Die Länge des Kursausschlusses besagt, wie lange es dauert, bis der Kurs wieder vom Workflow bearbeitet wird.'; +$string['config_enablecategoryhierachy'] = 'Kurskategorienhierarchie in der Interaktionstabelle spezifizieren'; +$string['config_enablecategoryhierachy_desc'] = 'Standardmäßig wird die direkt zugewiesene Kurskategorie angezeigt, wenn Lehrkräfte den Status ihrer Kurse in der view.php verwalten. Die Einstellung ermöglicht es, eine bestimmte Ebene des Kurskategorienbaums anzuzeigen.'; $string['config_showcoursecounts'] = 'Zeige Anzahl der Kurse, die getriggert werden'; $string['config_showcoursecounts_desc'] = 'Die Workflow-Konfigurationsseite zeigt normalerweise die Anzahl an Kursen, die durch die konfigurierten Trigger getriggert werden, was Performance-Probleme verursachen kann. Bei Performance-Problemen kann dies hiermit diff --git a/lang/en/tool_lifecycle.php b/lang/en/tool_lifecycle.php index 1d96728d..af1b212e 100644 --- a/lang/en/tool_lifecycle.php +++ b/lang/en/tool_lifecycle.php @@ -52,10 +52,14 @@ $string['config_backup_path'] = 'Path of the lifecycle backup folder'; $string['config_backup_path_desc'] = 'This settings defines the storage location of the backups created by the backup step. The path has to be specified as an absolute path on your server.'; +$string['config_coursecategorydepth'] = 'Depth of categories to be shown in the interaction table'; +$string['config_coursecategorydepth_desc'] = 'By default the first category is shown when teachers manage the status of their courses on the view.php. The setting enables to show not the first level of categories but subcategories.'; $string['config_delay_duration'] = 'Default duration of a course delay'; $string['config_delay_duration_desc'] = 'This setting defines the default delay duration of a workflow in case one of its processes is rolled back or finishes. The delay duration determines how long a course will be excepted from being processed again in either of the cases.'; +$string['config_enablecategoryhierachy'] = 'Show a specified level of the course category hierarchy in the interaction table'; +$string['config_enablecategoryhierachy_desc'] = 'By default the directly assigned course category is shown when teachers manage the status of their courses on the view.php. The setting enables to show a specified level of the course category tree.'; $string['config_showcoursecounts'] = 'Show amount of courses which will be triggered'; $string['config_showcoursecounts_desc'] = 'The workflow overview page by default shows the amount of courses which will be triggered by the configured triggers which can be load heavy. Disable this option if you experience issues loading the workflow diff --git a/settings.php b/settings.php index 3f37c086..22e6f8f0 100644 --- a/settings.php +++ b/settings.php @@ -46,6 +46,18 @@ get_string('config_showcoursecounts', 'tool_lifecycle'), get_string('config_showcoursecounts_desc', 'tool_lifecycle'), 1)); + $settingenablehierachy = new admin_setting_configcheckbox('tool_lifecycle/enablecategoryhierachy', + get_string('config_enablecategoryhierachy', 'tool_lifecycle'), + get_string('config_enablecategoryhierachy_desc', 'tool_lifecycle'), + false); + $settings->add($settingenablehierachy); + $coursehierachysetting = new admin_setting_configtext('tool_lifecycle/coursecategorydepth', + get_string('config_coursecategorydepth', 'tool_lifecycle'), + get_string('config_coursecategorydepth_desc', 'tool_lifecycle'), + 0, PARAM_INT); + $coursehierachysetting->add_dependent_on('tool_lifecycle/enablecategoryhierachy'); + $settings->add($coursehierachysetting); + $settings->hide_if('tool_lifecycle/coursecategorydepth', 'tool_lifecycle/enablecategoryhierachy', 'notchecked'); $ADMIN->add('lifecycle_category', new admin_externalpage('tool_lifecycle_workflow_drafts', get_string('workflow_drafts_header', 'tool_lifecycle'), diff --git a/step/email/interactionlib.php b/step/email/interactionlib.php index 8d71b69b..65054d19 100644 --- a/step/email/interactionlib.php +++ b/step/email/interactionlib.php @@ -126,7 +126,7 @@ public function get_due_date($processid, $stepid) { $date += $settings['responsetimeout']; } } - // TODO default format -- seconds -> not in this class ! + // Software enhancement default format -- seconds -> not in this class ! return date('d.m.Y', $date); } diff --git a/step/email/lib.php b/step/email/lib.php index 4635aed8..fb19c2c7 100644 --- a/step/email/lib.php +++ b/step/email/lib.php @@ -119,19 +119,17 @@ public function post_processing_bulk_operation() { ['instanceid' => $step->id, 'touser' => $user->id, ]); - $parsedsettings = $this->replace_placeholders($settings, $user, $step->id, $mailentries); - + $parsedsettings = $this->replace_placeholders($settings, $user, $step->id, $mailentries); $subject = $parsedsettings['subject']; $content = $parsedsettings['content']; $contenthtml = $parsedsettings['contenthtml']; - // TODO: use course info to parse content template! + // Software enhancement: use course info to parse content template! $success = email_to_user($user, \core_user::get_noreply_user(), $subject, $content, $contenthtml); if (!$success) { mtrace("E-mail to user {$user->id} failed."); } $DB->delete_records('lifecyclestep_email', - ['instanceid' => $step->id, - 'touser' => $user->id, ]); + ['instanceid' => $step->id, 'touser' => $user->id]); $transaction->allow_commit(); } } diff --git a/tests/behat/interaction.feature b/tests/behat/interaction.feature index 6b4885ac..215f0c0e 100644 --- a/tests/behat/interaction.feature +++ b/tests/behat/interaction.feature @@ -5,11 +5,19 @@ Feature: Add a workflow with an email step and test the interaction as a teacher Given the following "users" exist: | username | firstname | lastname | email | | teacher1 | Teacher | 1 | teacher1@example.com | + And the following "categories" exist: + | name | category | idnumber | + | Cat1 | 0 | 1 | + | Cat2 | 0 | 2 | + | Cat02 | 2 | 02 | + | Cat01 | 1 | 01 | + | Cat001 | 01 | 001 | + | Cat002 | 01 | 002 | And the following "courses" exist: | fullname | shortname | category | startdate | - | Course 1 | C1 | 0 | ##2 days ago## | - | Course 2 | C2 | 0 | ##4 days ago## | - | Course 3 | C3 | 0 | ##4 days ago## | + | Course 1 | C1 | 0 | ##2 days ago## | + | Course 2 | C2 | 001 | ##4 days ago## | + | Course 3 | C3 | 02 | ##4 days ago## | And the following "course enrolments" exist: | user | course | role | | teacher1 | C1 | editingteacher | @@ -44,8 +52,12 @@ Feature: Add a workflow with an email step and test the interaction as a teacher And I press "Activate" And I log out - Scenario: Test interaction of email step - Given I log in as "teacher1" + Scenario Outline: Test interaction of email step + Given the following config values are set as admin: + | config | value | plugin | + | enablecategoryhierachy | | tool_lifecycle | + | coursecategorydepth | | tool_lifecycle | + And I log in as "teacher1" When I am on lifecycle view Then I should see "Course 1" in the "tool_lifecycle_remaining" "table" And I should see "Course 2" in the "tool_lifecycle_remaining" "table" @@ -57,6 +69,8 @@ Feature: Add a workflow with an email step and test the interaction as a teacher And I should see "Course 3" in the "tool_lifecycle_interaction" "table" And I should see the tool "Keep course" in the "Course 2" row of the "tool_lifecycle_interaction" table And I should see the tool "Keep course" in the "Course 3" row of the "tool_lifecycle_interaction" table + And I should see "" in the "tool_lifecycle_interaction" "table" + And I should see "" in the "tool_lifecycle_interaction" "table" When I click on the tool "Keep course" in the "Course 2" row of the "tool_lifecycle_interaction" table Then I should see "Course 1" in the "tool_lifecycle_remaining" "table" And I should see "Course 2" in the "tool_lifecycle_remaining" "table" @@ -66,4 +80,10 @@ Feature: Add a workflow with an email step and test the interaction as a teacher And I am on lifecycle view Then I should see "Course 1" in the "tool_lifecycle_remaining" "table" And I should see "Course 2" in the "tool_lifecycle_remaining" "table" + And I should see "" in the "tool_lifecycle_remaining" "table" And I should not see "Course 3" + Examples: + | config | config1 | category1 | category2 | + | 0 | 0 | Cat001 | Cat02 | + | 1 | 0 | Cat1 | Cat2 | + | 1 | 2 | Cat001 | Cat02 | diff --git a/version.php b/version.php index e8f6b54a..790a03d1 100644 --- a/version.php +++ b/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die; $plugin->maturity = MATURITY_BETA; -$plugin->version = 2024042300; +$plugin->version = 2024042302; $plugin->component = 'tool_lifecycle'; $plugin->requires = 2022112800; // Requires Moodle 4.1+. $plugin->release = 'v4.4-r1';