From 40fbfeb698b220f8d15675a0e05ba850aab78599 Mon Sep 17 00:00:00 2001 From: PMKuipers Date: Mon, 19 Jun 2023 22:48:33 +0200 Subject: [PATCH] Untested code for cascading a cohort sync to the courses in a studyplan --- classes/enrolcohortsync.php | 148 ++++++++++++++++++++++++++++---- classes/studyplan.php | 19 +++- lang/en/local_treestudyplan.php | 14 ++- lang/nl/local_treestudyplan.php | 15 +++- settings.php | 71 ++++++++++++++- 5 files changed, 244 insertions(+), 23 deletions(-) diff --git a/classes/enrolcohortsync.php b/classes/enrolcohortsync.php index b31b8f5..34f0ba4 100644 --- a/classes/enrolcohortsync.php +++ b/classes/enrolcohortsync.php @@ -5,32 +5,150 @@ require_once($CFG->libdir.'/externallib.php'); use \local_treestudyplan\studyplan; class enrolcohortsync { - + private const METHOD = "cohort"; private $studyplan; function __construct($studyplan){ $this->studyplan = $studyplan; + $this->studyplanid = $studyplan->id(); + } + + static private function array_remove_value(&$array,$value){ + while (($key = array_search($value, $array)) !== false) { + unset($array[$key]); + } } function sync(){ - // Find the courses that need to be synced to the associated cohorts - $courses = $this->studyplan->get_linked_course_ids(); + global $DB; + // TODO: Determine if it would be better to add a database table of our own to store references between studyplan and cohort sync enrolment + // instead of using customtext4 for this - // And find the cohorts that are linked to this studyplan. - // Next, for each course that is linked: - // 1: check if a link exists - // If not, make it (maybe use some of the custom text to list the studyplans involved) + if(get_config("local_treestudyplan","csync_enable")){ + $enrol = enrol_get_plugin(self::METHOD); + // Find the courses that need to be synced to the associated cohorts + $courseids = $this->studyplan->get_linked_course_ids(); - // 2: Check if there are cohort links for this studyplan that should be removed - // A: Check if there are cohort links that are no longer related to this studyplan - // B: Check if these links are valid through another studyplan... - // If no one uses the link anymore, deactivate it... + // And find the cohorts that are linked to this studyplan. + $cohortids = $this->studyplan->get_linked_cohort_ids(); - + // Next, for each course that is linked: + foreach($courseids as $courseid){ + $course = get_course($courseid); + // first create any nonexistent links + foreach($cohortids as $cohortid){ + $cohort = $DB->get_record('cohort',['id'=>$cohortid]); + + $instanceparams = [ + 'courseid' => $courseid, + 'customint1' => $cohortid, + 'enrol' => self::METHOD, + 'roleid' => get_config("local_treestudyplan","csync_roleid"), + ]; + + $instancenewparams = [ + 'customint1' => $cohortid, + 'enrol' => self::METHOD, + 'roleid' => get_config("local_treestudyplan","csync_roleid"), + ]; + + + // Create group: + + // 1: check if a link exists + // If not, make it (maybe use some of the custom text to list the studyplans involved) + if ($instance = $DB->get_record('enrol', $instanceparams)) { + // it already exists + // check if this studyplan is already referenced in customtext4 in json format + if(empty($instance->customtext4)){ + // Cohort sync was already done, but without studyplan info + // make sure we add a "manual" link to the plan list + $plans = ["manual"]; + } + else{ + $plans = json_decode($instance->customtext4); + } + if(!$in_array($this->studyplanid ,$plans)){ + // if not, add it to the reference + $plans[] = $this->studyplanid; + $enrol->update_instance($instance,["customtext4"=>json_encode($plans)]); + } + + } else { + // If method members should be added to a group, create it or get its ID. + + if (get_config("local_treestudyplan","csync_creategroup")) { + // Make or get new new cohort group - but only on creating of instances + $groupname = $cohort->name." ".strtolower(get_string('defaultgroupname', 'core')); + // and make sure the + $instancenewparams['customint2'] = uploadenrolmentmethods_get_group($courseid, $groupname); + } + + if ($instanceid = $enrol->add_instance($course, $instancenewparams)) { + // also record the (as of yet only) studyplans id requiring this association + // in the customtext4 field in json format + $enrol->update_instance($instance,["customtext4"=>json_encode([$this->studyplanid])]); + + // Successfully added a valid new instance, so now instantiate it. + // First synchronise the enrolment. + $cohorttrace = new null_progress_trace(); + enrol_cohort_sync($cohorttrace, $cohortid); + $cohorttrace->finished(); + + } else { + // Instance not added for some reason, so report an error somewhere + // (or not) + } + } + } + + // 2: Check if there are cohort links for this studyplan in this course that should be removed + // A: Check if there are cohort links that are no longer related to this studyplan + // B: Check if these links are valid through another studyplan... + // If no one uses the link anymore, deactivate it... + // INFO: This does not remove the sync from courses that are unlinked from a studplan. But maybe we do not want that anyway + // since it is generally a good idea to keep student access to courses available + + if(get_config("local_treestudyplan","csync_autoremove")){ + // Only try the autoremove if the option is enabled + + // find all cohort syncs for this course + $searchparams = [ + 'courseid' => $courseid, + 'enrol' => self::METHOD, + 'roleid' => get_config("local_treestudyplan","csync_roleid"), + ]; + + $records = $DB->get_records("enrol",$searchparams); + foreach($records as $instance){ + if(!empty($instance->customtext4)){ // only check the records that have studyplan information in the customtext4 field + // first check if the cohort is not one of the cohort id's we have associated + if(!in_array($instance->customint1,$cohortids)){ + // So it may or may not need to be removed + $plans = json_decode($instance->customtext4); + if($plans !== null && is_array($plans)){ + //if a valid array is not returned, better leave it be, we don't want to mess with it + // otherwise, check if we should remove it + if(in_array($this->studyplanid,$plans)){ + //if this plan was referenced before + // first remove the link + self::array_remove_value($plans,$this->studyplanid); + if(count($plans) == 0){ + // delete the sync if there are no studyplan references left + $enrol->delete_instance($instance); + } else { + // otherwise just update the references so this studyplan is no longer linked + $enrol->update_instance($instance,["customtext4"=>json_encode($plans)]); + } + } + } + } + } + } + } + } + } } - - - } \ No newline at end of file diff --git a/classes/studyplan.php b/classes/studyplan.php index 4b57119..1c0c2fa 100644 --- a/classes/studyplan.php +++ b/classes/studyplan.php @@ -750,15 +750,28 @@ class studyplan { global $DB; $sql = "SELECT i.course_id - FROM {local_treestudyplan} + FROM {local_treestudyplan} p INNER JOIN {local_treestudyplan_line} l ON p.id = l.studyplan_id INNER JOIN {local_treestudyplan_item} i ON l.id = i.line_id - WHERE p.id = :planid "; - $fields = $DB->get_fieldset_sql($sql,["planid" => $this->id]); + WHERE p.id = :studyplan_id AND i.type = :itemtype"; + $fields = $DB->get_fieldset_sql($sql,["studyplan_id" => $this->id,"itemtype" => studyitem::COURSE]); return $fields; } + /** + * List the cohort id's associated with this studyplan + */ + public function get_linked_cohort_ids(){ + global $CFG, $DB; + + $sql = "SELECT DISTINCT j.cohort_id FROM {local_treestudyplan_cohort} j + WHERE j.studyplan_id = :studyplan_id"; + $fields = $DB->get_field_sql($sql, ['studyplan_id' => $this->id]); + return $fields; + } + + /** * See if the specified course id is linked in this studyplan */ diff --git a/lang/en/local_treestudyplan.php b/lang/en/local_treestudyplan.php index a7ecbaa..3cf32dd 100644 --- a/lang/en/local_treestudyplan.php +++ b/lang/en/local_treestudyplan.php @@ -43,7 +43,7 @@ $string['invite_mail_text'] = ' $string['view_plan'] = 'View studyplans'; $string['edit_plan'] = 'Edit studyplan'; -$string['settingspage'] = 'Tree studyplan settings'; +$string['settingspage'] = 'Studyplan settings'; $string['setting_taxonomy_category'] = 'Competency taxonomy for categories'; $string['settingdesc_taxonomy_category'] = 'Indicate the taxonomy used to indicate a competency as a category'; $string['setting_taxonomy_module'] = 'Competency taxonomy for modules'; @@ -56,6 +56,18 @@ $string['settingdesc_display_heading'] = 'Study plan display settings'; $string['setting_display_field'] = 'Course display name'; $string['settingdesc_display_field'] = 'Select the field to use for the display name of a course in the studyplan'; +$string['settingspage_csync'] = 'Studyplan cohort sync'; +$string['setting_csync_heading'] = 'Automatically create a cohort sync in all courses linked to a studyplan for all cohorts linked to a studyplan'; +$string['settingdesc_csync_heading'] = ''; +$string['setting_csync_enable_field'] = 'Enable'; +$string['settingdesc_csync_enable_field'] = 'Enable automatic cohort sync'; +$string['setting_csync_autoremove_field'] = 'Automatisch deletion'; +$string['settingdesc_csync_autoremove_field'] = 'Delete syncronization from courses once a cohort is removed from the studyplan'; +$string['setting_csync_creategroup_field'] = 'Create groups'; +$string['settingdesc_csync_creategroup_field'] = 'Create a group in the course for each cohort sync'; +$string['setting_csync_role_field'] = 'Role'; +$string['settingdesc_csync_role_field'] = 'The role to use for automatic cohort sync enrolment created in courses'; + $string['studyplan_add'] = 'Add study plan'; $string['studyplan_edit'] = 'Edit study plan'; $string['studyplan_remove'] = 'Remove study plan'; diff --git a/lang/nl/local_treestudyplan.php b/lang/nl/local_treestudyplan.php index 4fc73f3..3e97fc0 100644 --- a/lang/nl/local_treestudyplan.php +++ b/lang/nl/local_treestudyplan.php @@ -45,7 +45,7 @@ $string['invite_mail_text'] = ' $string['view_plan'] = 'Studieplannen bekijken'; $string['edit_plan'] = 'Studieplan bewerken'; -$string['settingspage'] = 'Tree studieplan instellingen'; +$string['settingspage'] = 'Studieplan instellingen'; $string['setting_taxonomy_category'] = 'Competentietaxonomie voor categorieën'; $string['settingdesc_taxonomy_category'] = 'Geef aan bij welke taxonomie een competentie categorie module moet worden gezien'; $string['setting_taxonomy_module'] = 'Competentietaxonomie voor modules'; @@ -58,6 +58,19 @@ $string['settingdesc_display_heading'] = 'Configuratie voor de weergave van de s $string['setting_display_field'] = 'Weergavenaam cursus'; $string['settingdesc_display_field'] = 'Kies welk veld gebruikt moet worden als weergavenaam van een cursus'; +$string['settingspage_csync'] = 'Studieplan site-groep synchronisatie'; +$string['setting_csync_heading'] = 'Site-groepen die aan een studieplan gekoppeld zijn automatisch als site-groep synchronisatie koppelen aan alle cursussen in het studieplan.'; +$string['settingdesc_csync_heading'] = ''; +$string['setting_csync_enable_field'] = 'Inschakelen'; +$string['settingdesc_csync_enable_field'] = 'Automatische koppelen van site-groep synchronisatie inschakelen'; +$string['setting_csync_autoremove_field'] = 'Automatisch verwijderen'; +$string['settingdesc_csync_autoremove_field'] = 'Verwijder sychronisaties in cursussen als deze uit het studieplan worden verwijderd'; +$string['setting_csync_creategroup_field'] = 'Groepen aanmaken'; +$string['settingdesc_csync_creategroup_field'] = 'Maak voor elke site-groep synchronisatie een groep aan'; +$string['setting_csync_role_field'] = 'Synchronisatierol'; +$string['settingdesc_csync_role_field'] = 'Welke rol te gebruiken voor automatische site-groep sync koppelingen'; + + $string['studyplan_add'] = 'Nieuw studieplan'; $string['studyplan_edit'] = 'Studieplan bewerken'; $string['studyplan_remove'] = 'Studieplan verwijderen'; diff --git a/settings.php b/settings.php index 4b13bf3..e50e78a 100644 --- a/settings.php +++ b/settings.php @@ -28,7 +28,11 @@ use local_treestudyplan\aggregator; if ($hassiteconfig) { - $taxonomies = core_competency\competency_framework::get_taxonomies_list(); + /************************************** + * + * Main studyplan settings + * + *************************************/ // Create admin settings category. $ADMIN->add('courses', new admin_category('local_treestudyplan', @@ -131,12 +135,73 @@ if ($hassiteconfig) { // Add settings page to the admin settings category. $ADMIN->add('local_treestudyplan', $page); - // Cohort config page + + /************************************** + * + * Manage plans link (systemwide) + * + *************************************/ + $ADMIN->add('local_treestudyplan', new admin_externalpage( 'local_treestudyplan_editplans', get_string('cfg_plans', 'local_treestudyplan', null, true), $CFG->wwwroot . '/local/treestudyplan/edit-plan.php')); - // Cohort config page + + + /************************************** + * + * Settings page: Cohort sync + * + *************************************/ + + $page_csync = new admin_settingpage('local_treestudyplan_settings_cohortsync', + get_string('settingspage_csync', 'local_treestudyplan', null, true)); + + + // Description heading + $page_csync->add(new admin_setting_heading('local_treestudyplan/csync_heading', + get_string('setting_csync_heading', 'local_treestudyplan'), + get_string('settingdesc_csync_heading', 'local_treestudyplan') + )); + + // Enable/disable cohort sync + $page_csync->add(new admin_setting_configcheckbox('local_treestudyplan/csync_enable', + get_string('setting_csync_enable_field', 'local_treestudyplan'), + get_string('settingdesc_csync_enable_field', 'local_treestudyplan'), + false + )); + + // Enable/disable autoremove + $page_csync->add(new admin_setting_configcheckbox('local_treestudyplan/csync_autoremove', + get_string('setting_csync_autoremove_field', 'local_treestudyplan'), + get_string('settingdesc_csync_autoremove_field', 'local_treestudyplan'), + true + )); + + // Enable/disable group creation + $page_csync->add(new admin_setting_configcheckbox('local_treestudyplan/csync_creategroup', + get_string('setting_csync_creategroup_field', 'local_treestudyplan'), + get_string('settingdesc_csync_creategroup_field', 'local_treestudyplan'), + true + )); + + // Select csync enrol role + if (!during_initial_install()) { + $options = get_default_enrol_roles(context_system::instance()); + $student = get_archetype_roles('student'); + $student = reset($student); + $page_csync->add(new admin_setting_configselect('local_treestudyplan/csync_roleid', + get_string('defaultrole', 'role'), '', $student->id ?? null, $options)); + } + + // Add settings page2 to the admin settings category. + $ADMIN->add('local_treestudyplan', $page_csync); + + /************************************** + * + * Grade and scale interpretation + * + *************************************/ $ADMIN->add('local_treestudyplan', new admin_externalpage( 'local_treestudyplan_gradeconfig', get_string('cfg_grades', 'local_treestudyplan', null, true),