libdir.'/externallib.php'); class associationservice extends \external_api { const CAP_EDIT = "local/treestudyplan:editstudyplan"; const CAP_VIEW = "local/treestudyplan:viewuserreports"; public static function user_structure(){ return new \external_single_structure([ "id" => new \external_value(PARAM_INT, 'user id'), "username" => new \external_value(PARAM_TEXT, 'username'), "firstname" => new \external_value(PARAM_TEXT, 'first name'), "lastname" => new \external_value(PARAM_TEXT, 'last name'), "idnumber" => new \external_value(PARAM_TEXT, 'id number'), "email" => new \external_value(PARAM_TEXT, 'email address'), ]); } public static function make_user_model($r){ return [ "id" => $r->id, "username" => $r->username, "firstname" => $r->firstname, "lastname" => $r->lastname, "idnumber" => $r->idnumber, "email" => $r->email, ]; } public static function cohort_structure(){ return new \external_single_structure([ "id" => new \external_value(PARAM_INT, 'cohort id'), "name" => new \external_value(PARAM_TEXT, 'name'), "idnumber" => new \external_value(PARAM_TEXT, 'id number'), "description" => new \external_value(PARAM_TEXT, 'description'), "visible" => new \external_value(PARAM_BOOL, 'is visible'), "context" => new \external_single_structure([ "name" => new \external_value(PARAM_TEXT, 'context name'), "shortname" => new \external_value(PARAM_TEXT, 'context short name'), "path" => new \external_multiple_structure( new \external_value(PARAM_TEXT)), "shortpath" => new \external_multiple_structure( new \external_value(PARAM_TEXT)), ], 'context information', VALUE_OPTIONAL), ]); } public static function make_cohort_model($r){ global $DB; $ctx = \context::instance_by_id($r->contextid); $ctxPath = array_reverse($ctx->get_parent_context_ids(true)); if(count($ctxPath) > 1 && $ctxPath[0] == 1) { array_shift($ctxPath); } $result = [ "id" => $r->id, "name" => $r->name, "idnumber" => $r->idnumber, "description" => $r->description, "visible" => $r->visible, "context" => [ "name" => $ctx->get_context_name(false,false), "shortname" => $ctx->get_context_name(false,true), "path" => array_map(function($c){ return \context::instance_by_id($c)->get_context_name(false,false);},$ctxPath), "shortpath" => array_map(function($c){ return \context::instance_by_id($c)->get_context_name(false,true);},$ctxPath), ] ]; return $result; } public static function list_cohort_parameters() { return new \external_function_parameters( [ 'like' => new \external_value(PARAM_TEXT, 'search text', VALUE_OPTIONAL), 'exclude_id' => new \external_value(PARAM_INT, 'exclude members of this studyplan', VALUE_OPTIONAL), 'context_ic' => new \external_value(PARAM_INT, 'context for this request', VALUE_OPTIONAL), ] ); } public static function list_cohort_returns() { return new \external_multiple_structure(self::cohort_structure()); } // Actual functions public static function list_cohort($like='',$exclude_id=null,$context_id=1) { global $CFG, $DB; // Only allow this if the user has the right to edit in this context $context = webservicehelper::find_context($context_id); webservicehelper::require_capabilities(self::CAP_EDIT, $context); $pattern = "%{$like}%"; $params = ["pattern_nm" => $pattern,"pattern_id" => $pattern,]; $sql = "SELECT c.* from {cohort} c LEFT JOIN {local_treestudyplan_cohort} j ON c.id = j.cohort_id"; $sql .= " WHERE c.visible = 1 AND(name LIKE :pattern_nm OR idnumber LIKE :pattern_id)"; if(isset($exclude_id) && is_numeric($exclude_id)){ $sql .= " AND (j.studyplan_id IS NULL OR j.studyplan_id != :exclude_id)"; $params['exclude_id'] = $exclude_id; } if($context_id > 1){ // system context returns all cohorts, including system cohorts // otherwise, $sql .= " AND contextid = :context_id"; $params['context_id'] = $context_id; } $cohorts = []; $rs = $DB->get_recordset_sql($sql,$params); foreach ($rs as $r) { $cohorts[] = static::make_cohort_model($r); } $rs->close(); return $cohorts; } public static function find_user_parameters() { return new \external_function_parameters( [ 'like' => new \external_value(PARAM_TEXT, 'search text'), 'exclude_id' => new \external_value(PARAM_INT, 'exclude members of this studyplan', VALUE_OPTIONAL), 'context_id' => new \external_value(PARAM_INT, 'context for this request', VALUE_OPTIONAL), ] ); } public static function find_user_returns() { return new \external_multiple_structure(self::user_structure()); } // Actual functions public static function find_user($like,$exclude_id=null,$context_id=1) { global $CFG, $DB; // Only allow this if the user has the right to edit in this context (using system rights would make things more confusing) $context = webservicehelper::find_context($context_id); webservicehelper::require_capabilities(self::CAP_EDIT,$context); $pattern = "%{$like}%"; $params = ["pattern_fn" => $pattern, "pattern_ln" => $pattern, "pattern_un" => $pattern, ]; $sql = "SELECT u.* from {user} u LEFT JOIN {local_treestudyplan_user} j ON u.id = j.user_id"; $sql .= " WHERE u.deleted != 1 AND (firstname LIKE :pattern_fn OR lastname LIKE :pattern_ln OR username LIKE :pattern_un)"; if(isset($exclude_id) && is_numeric($exclude_id)){ $sql .= " AND (j.studyplan_id IS NULL OR j.studyplan_id != :exclude_id)"; $params['exclude_id'] = $exclude_id; } $users = []; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $r) { $users[] = static::make_user_model($r); } $rs->close(); self::sortusermodels($users); return $users; } public static function connect_cohort_parameters() { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), "cohort_id" => new \external_value(PARAM_INT, 'id of cohort to link', VALUE_OPTIONAL), ] ); } public static function connect_cohort_returns() { return new \external_single_structure([ "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "msg" => new \external_value(PARAM_TEXT, 'message'), ]); } // Actual functions public static function connect_cohort($studyplan_id,$cohort_id) { global $CFG, $DB; $studyplan = studyplan::findById($studyplan_id); webservicehelper::require_capabilities(self::CAP_EDIT,$studyplan->context()); if(!$DB->record_exists('local_treestudyplan_cohort', ['studyplan_id' => $studyplan_id, 'cohort_id' => $cohort_id])) { $id = $DB->insert_record('local_treestudyplan_cohort', [ 'studyplan_id' => $studyplan_id, 'cohort_id' => $cohort_id, ]); $studyplan->mark_csync_changed(); return ['success' => true, 'msg'=>'Cohort connected']; } else { return ['success' => true, 'msg'=>'Cohort already connected']; } } public static function disconnect_cohort_parameters() { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), "cohort_id" => new \external_value(PARAM_INT, 'id of cohort to link', VALUE_OPTIONAL), ] ); } public static function disconnect_cohort_returns() { return new \external_single_structure([ "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "msg" => new \external_value(PARAM_TEXT, 'message'), ]); } // Actual functions public static function disconnect_cohort($studyplan_id,$cohort_id) { global $CFG, $DB; $studyplan = studyplan::findById($studyplan_id); webservicehelper::require_capabilities(self::CAP_EDIT,$studyplan->context()); if($DB->record_exists('local_treestudyplan_cohort', ['studyplan_id' => $studyplan_id, 'cohort_id' => $cohort_id])) { $DB->delete_records('local_treestudyplan_cohort', [ 'studyplan_id' => $studyplan_id, 'cohort_id' => $cohort_id, ]); $studyplan->mark_csync_changed(); return ['success' => true, 'msg'=>'Cohort Disconnected']; } else { return ['success' => true, 'msg'=>'Connection does not exist']; } } public static function connect_user_parameters() { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), "user_id" => new \external_value(PARAM_INT, 'id of user to link', VALUE_OPTIONAL), ] ); } public static function connect_user_returns() { return new \external_single_structure([ "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "msg" => new \external_value(PARAM_TEXT, 'message'), ]); } // Actual functions public static function connect_user($studyplan_id,$user_id) { global $CFG, $DB; $studyplan = studyplan::findById($studyplan_id); webservicehelper::require_capabilities(self::CAP_EDIT,$studyplan->context()); if(!$DB->record_exists('local_treestudyplan_user', ['studyplan_id' => $studyplan_id, 'user_id' => $user_id])) { $id = $DB->insert_record('local_treestudyplan_user', [ 'studyplan_id' => $studyplan_id, 'user_id' => $user_id, ]); $studyplan->mark_csync_changed(); return ['success' => true, 'msg'=>'Cohort connected']; } else { return ['success' => true, 'msg'=>'Cohort already connected']; } } public static function disconnect_user_parameters() { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), "user_id" => new \external_value(PARAM_INT, 'id of user to link', VALUE_OPTIONAL), ] ); } public static function disconnect_user_returns() { return new \external_single_structure([ "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "msg" => new \external_value(PARAM_TEXT, 'message'), ]); } // Actual functions public static function disconnect_user($studyplan_id,$user_id) { global $CFG, $DB; $studyplan = studyplan::findById($studyplan_id); webservicehelper::require_capabilities(self::CAP_EDIT,$studyplan->context()); if($DB->record_exists('local_treestudyplan_user', ['studyplan_id' => $studyplan_id, 'user_id' => $user_id])) { $DB->delete_records('local_treestudyplan_user', [ 'studyplan_id' => $studyplan_id, 'user_id' => $user_id, ]); $studyplan->mark_csync_changed(); return ['success' => true, 'msg'=>'User Disconnected']; } else { return ['success' => true, 'msg'=>'Connection does not exist']; } } public static function associated_users_parameters() { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), ] ); } public static function associated_users_returns() { return new \external_multiple_structure(self::user_structure()); } // Actual functions public static function associated_users($studyplan_id) { global $CFG, $DB; $studyplan = studyplan::findById($studyplan_id); webservicehelper::require_capabilities(self::CAP_VIEW,$studyplan->context()); $sql = "SELECT DISTINCT u.* FROM {user} u INNER JOIN {local_treestudyplan_user} j ON j.user_id = u.id"; $sql .= " WHERE j.studyplan_id = :studyplan_id"; $rs = $DB->get_recordset_sql($sql, ['studyplan_id' => $studyplan_id]); $users = []; foreach($rs as $u) { $users[] = self::make_user_model($u); } $rs->close(); self::sortusermodels($users); return $users; } public static function associated_cohorts_parameters() { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), ] ); } public static function associated_cohorts_returns() { return new \external_multiple_structure(self::cohort_structure()); } // Actual functions public static function associated_cohorts($studyplan_id) { global $CFG, $DB; $studyplan = studyplan::findById($studyplan_id); webservicehelper::require_capabilities(self::CAP_VIEW,$studyplan->context()); $sql = "SELECT DISTINCT c.* FROM {cohort} c INNER JOIN {local_treestudyplan_cohort} j ON j.cohort_id = c.id"; $sql .= " WHERE j.studyplan_id = :studyplan_id"; $rs = $DB->get_recordset_sql($sql, ['studyplan_id' => $studyplan_id]); $cohorts = []; foreach($rs as $c) { $cohorts[] = self::make_cohort_model($c); } $rs->close(); return $cohorts; } public static function all_associated_parameters() { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), ] ); } public static function all_associated_returns() { return new \external_multiple_structure(self::user_structure()); } // Actual functions public static function all_associated($studyplan_id) { global $CFG, $DB; $studyplan = studyplan::findById($studyplan_id); webservicehelper::require_capabilities(self::CAP_VIEW,$studyplan->context()); $users = []; // SQL JOIN script selecting all users that have a cohort linked to this studyplan // or are directly linked $sql = "SELECT DISTINCT u.id, u.username, u.firstname, u.lastname, u.idnumber, u.email FROM {user} u LEFT JOIN {cohort_members} cm ON u.id = cm.userid LEFT JOIN {local_treestudyplan_cohort} tc ON cm.cohortid = tc.cohort_id LEFT JOIN {local_treestudyplan_user} tu ON u.id = tu.user_id WHERE tc.studyplan_id = {$studyplan_id} OR tu.studyplan_id = {$studyplan_id} ORDER BY u.lastname, u.firstname"; $rs = $DB->get_recordset_sql($sql); foreach($rs as $u) { $users[] = self::make_user_model($u); } $rs->close(); self::sortusermodels($users); return $users; } public static function sortusermodels(&$list){ return usort($list,function($a,$b){ $m= []; if(preg_match("/.*?([A-Z].*)/",$a['lastname'],$m)){ $sort_ln_a = $m[1]; } else { $sort_ln_a = $a['lastname']; } if(preg_match("/.*?([A-Z].*)/",$b['lastname'],$m)){ $sort_ln_b = $m[1]; } else { $sort_ln_b = $b['lastname']; } $cmp= $sort_ln_a <=> $sort_ln_b; return ($cmp != 0)?$cmp:$a['firstname'] <=> $b['firstname']; }); } public static function cascade_cohortsync_parameters() { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), ] ); } public static function cascade_cohortsync_returns() { return success::structure(); } // Actual functions public static function cascade_cohortsync($studyplan_id) { $studyplan = studyplan::findById($studyplan_id); webservicehelper::require_capabilities(self::CAP_EDIT,$studyplan->context()); $enroller = new cascadecohortsync($studyplan); $enroller->sync(); if(get_config("local_treestudyplan","csync_users")){ $userenroller = new cascadeusersync($studyplan); $userenroller->sync(); } $studyplan->clear_csync_changed(); // Clear the csync required flag return success::success()->model(); } }