. /** * Webservice class for handling associations of cohorts and users to a studyplan * @package local_treestudyplan * @copyright 2023 P.M. Kuipers * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace local_treestudyplan; defined('MOODLE_INTERNAL') || die(); use local_treestudyplan\local\helpers\webservicehelper; use local_treestudyplan\task\autocohortsync; require_once($CFG->libdir.'/externallib.php'); /** * Webservice class for handling associations of cohorts and users to a studyplan */ class associationservice extends \external_api { /** * Capability required to edit study plans * @var string */ const CAP_EDIT = "local/treestudyplan:editstudyplan"; /** * Capability required to view studyplans (for other users) * @var string */ const CAP_VIEW = "local/treestudyplan:viewuserreports"; /** * Capability required to be linked as coach to a studyplan * @var string */ const CAP_COACH = "local/treestudyplan:coach"; /** * Webservice structure to use in describing a user */ public static function user_structure(): \external_description { 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'), "lastaccess" => new \external_value(PARAM_INT, 'id of last access this user had to any course in the studyplan', VALUE_OPTIONAL), ]); } /** * Make a webservice user model for a given user * @param stdClass $r User DB record */ 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, ]; } /** * Webservice structure to use in describing a cohort */ public static function cohort_structure(): \external_description { 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), ]); } /** * Make a webservice cohort model for a given cohort * @param stdClass $r Cohort DB record */ 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 user_lastaccess($userid, $studyplanid=null) { global $DB; if (!empty($studyplanid)) { $lasql = "SELECT MAX(a.timeaccess) FROM {user_lastaccess} a INNER JOIN {local_treestudyplan_item} i ON i.course_id = a.courseid INNER JOIN {local_treestudyplan_line} l ON l.id = i.line_id INNER JOIN {local_treestudyplan_page} p ON l.page_id = p.id WHERE a.userid = :userid AND p.studyplan_id = :studyplanid"; $lastaccess = $DB->get_field_sql($lasql, ["userid" => $userid, "studyplanid" => $studyplanid]); } else { $lasql = "SELECT MAX(a.timeaccess) FROM {user_lastaccess} a WHERE a.userid = :userid"; $lastaccess = $DB->get_field_sql($lasql, ["userid" => $userid]); } return $lastaccess; } /** * Parameter description for webservice function list_cohort */ public static function list_cohort_parameters(): \external_function_parameters { return new \external_function_parameters( [ 'like' => new \external_value(PARAM_TEXT, 'search text'), 'studyplan_id' => new \external_value(PARAM_INT, 'id of studyplan to list for'), ] ); } /** * Return value description for webservice function list_cohort */ public static function list_cohort_returns(): \external_description { return new \external_multiple_structure(self::cohort_structure()); } /** * Search cohorts for matching string * @param string $like String to match cohorts with * @param int $studyplanid Do not include these cohorts * @return array */ public static function list_cohort($like, $studyplanid) { global $CFG, $DB; // Only allow this if the user has the right to edit in this context. $studyplan = studyplan::find_by_id($studyplanid); $context = $studyplan->context(); webservicehelper::require_capabilities(self::CAP_EDIT, $context); $pattern = "%{$like}%"; $params = ["pattern_nm" => $pattern, "pattern_id" => $pattern ]; $sql = "SELECT DISTINCT c.* from {cohort} c LEFT JOIN {local_treestudyplan_cohort} j ON c.id = j.cohort_id WHERE c.visible = 1 AND(name LIKE :pattern_nm OR idnumber LIKE :pattern_id) AND (j.studyplan_id IS NULL OR j.studyplan_id != :exclude_id)"; $params['exclude_id'] = $studyplanid; $cohorts = []; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $r) { $cohorts[] = static::make_cohort_model($r); } $rs->close(); return $cohorts; } /** * Parameter description for webservice function find_user */ public static function find_user_parameters(): \external_function_parameters { return new \external_function_parameters( [ 'like' => new \external_value(PARAM_TEXT, 'search text'), 'studyplan_id' => new \external_value(PARAM_INT, 'id of studyplan to list for'), ] ); } /** * Return value description for webservice function find_user */ public static function find_user_returns(): \external_description { return new \external_multiple_structure(self::user_structure()); } /** * Search users for match * @param string $like String to match user firstname/lastname with * @param null $excludeid Do not include these users * @param int $contextid Context to search (default system) * @return array */ public static function find_user($like, $studyplanid) { global $CFG, $DB; // Only allow this if the user has the right to edit in this context. $studyplan = studyplan::find_by_id($studyplanid); $context = $studyplan->context(); webservicehelper::require_capabilities(self::CAP_EDIT, $context); $pattern = "%{$like}%"; $params = ["pattern_fn" => $pattern, "pattern_ln" => $pattern, "pattern_un" => $pattern, ]; $sql = "SELECT DISTINCT u.* from {user} u LEFT JOIN {local_treestudyplan_user} j ON u.id = j.user_id WHERE u.deleted != 1 AND (firstname LIKE :pattern_fn OR lastname LIKE :pattern_ln OR username LIKE :pattern_un) AND (j.studyplan_id IS NULL OR j.studyplan_id != :exclude_id)"; $params['exclude_id'] = $studyplanid; $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; } /** * Parameter description for webservice function connect_cohort */ public static function connect_cohort_parameters(): \external_function_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), ] ); } /** * Return value description for webservice function connect_cohort */ public static function connect_cohort_returns(): \external_description { return new \external_single_structure([ "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "msg" => new \external_value(PARAM_TEXT, 'message'), ]); } /** * Connect a cohort to a studyplan * @param mixed $studyplanid Id of studyplan * @param mixed $cohortid Id of cohort * @return array Success/fail model */ public static function connect_cohort($studyplanid, $cohortid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context()); if (!$DB->record_exists('local_treestudyplan_cohort', ['studyplan_id' => $studyplanid, 'cohort_id' => $cohortid])) { $id = $DB->insert_record('local_treestudyplan_cohort', [ 'studyplan_id' => $studyplanid, 'cohort_id' => $cohortid, ]); $studyplan->mark_csync_changed(); return ['success' => true, 'msg' => 'Cohort connected']; } else { return ['success' => true, 'msg' => 'Cohort already connected']; } } /** * Parameter description for webservice function disconnect_cohort */ public static function disconnect_cohort_parameters(): \external_function_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), ] ); } /** * Return value description for webservice function disconnect_cohort */ public static function disconnect_cohort_returns(): \external_description { return new \external_single_structure([ "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "msg" => new \external_value(PARAM_TEXT, 'message'), ]); } /** * Disconnect a cohort from a studyplan * @param mixed $studyplanid Id of studyplan * @param mixed $cohortid Id of cohort * @return array Success/fail model */ public static function disconnect_cohort($studyplanid, $cohortid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context()); if ($DB->record_exists('local_treestudyplan_cohort', ['studyplan_id' => $studyplanid, 'cohort_id' => $cohortid])) { $DB->delete_records('local_treestudyplan_cohort', [ 'studyplan_id' => $studyplanid, 'cohort_id' => $cohortid, ]); $studyplan->mark_csync_changed(); return ['success' => true, 'msg' => 'Cohort Disconnected']; } else { return ['success' => true, 'msg' => 'Connection does not exist']; } } /** * Parameter description for webservice function connect_user */ public static function connect_user_parameters(): \external_function_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), ] ); } /** * Return value description for webservice function connect_user */ public static function connect_user_returns(): \external_description { return new \external_single_structure([ "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "msg" => new \external_value(PARAM_TEXT, 'message'), ]); } /** * Connect a user to a studyplan * @param mixed $studyplanid Id of studyplan * @param mixed $userid Id of user * @return array Success/fail model */ public static function connect_user($studyplanid, $userid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context()); if (!$DB->record_exists('local_treestudyplan_user', ['studyplan_id' => $studyplanid, 'user_id' => $userid])) { $id = $DB->insert_record('local_treestudyplan_user', [ 'studyplan_id' => $studyplanid, 'user_id' => $userid, ]); $studyplan->mark_csync_changed(); return ['success' => true, 'msg' => 'Cohort connected']; } else { return ['success' => true, 'msg' => 'Cohort already connected']; } } /** * Parameter description for webservice function disconnect_user */ public static function disconnect_user_parameters(): \external_function_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), ] ); } /** * Return value description for webservice function disconnect_user */ public static function disconnect_user_returns(): \external_description { return new \external_single_structure([ "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "msg" => new \external_value(PARAM_TEXT, 'message'), ]); } /** * Disconnect a user from a studyplan * @param mixed $studyplanid Id of studyplan * @param mixed $userid Id of user * @return array Success/fail model */ public static function disconnect_user($studyplanid, $userid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context()); if ($DB->record_exists('local_treestudyplan_user', ['studyplan_id' => $studyplanid, 'user_id' => $userid])) { $DB->delete_records('local_treestudyplan_user', [ 'studyplan_id' => $studyplanid, 'user_id' => $userid, ]); $studyplan->mark_csync_changed(); return ['success' => true, 'msg' => 'User Disconnected']; } else { return ['success' => true, 'msg' => 'Connection does not exist']; } } /** * Parameter description for webservice function associated_users */ public static function associated_users_parameters(): \external_function_parameters { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), ] ); } /** * Return value description for webservice function associated_users */ public static function associated_users_returns(): \external_description { return new \external_multiple_structure(self::user_structure()); } /** * List all users associated to a studyplan * @param mixed $studyplanid Id of studyplan * @return array */ public static function associated_users($studyplanid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); if ($studyplan->is_coach()) { \external_api::validate_context($studyplan->context()); } else { 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 WHERE j.studyplan_id = :studyplan_id AND u.deleted != 1 ORDER BY u.lastname, u.firstname"; $rs = $DB->get_recordset_sql($sql, ['studyplan_id' => $studyplanid]); /* ID: 30 page: 33 plan: 28 */ $users = []; foreach ($rs as $u) { $user = self::make_user_model($u); $user["lastaccess"] = self::user_lastaccess($u->id, $studyplanid); $users[] = $user; } $rs->close(); self::sortusermodels($users); return $users; } /** * Parameter description for webservice function associated_cohorts */ public static function associated_cohorts_parameters(): \external_function_parameters { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), ] ); } /** * Return value description for webservice function associated_cohorts */ public static function associated_cohorts_returns(): \external_description { return new \external_multiple_structure(self::cohort_structure()); } /** * List all cohorts associated to a studyplan * @param mixed $studyplanid Id of studyplan * @return array */ public static function associated_cohorts($studyplanid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); 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 WHERE j.studyplan_id = :studyplan_id"; $rs = $DB->get_recordset_sql($sql, ['studyplan_id' => $studyplanid]); $cohorts = []; foreach ($rs as $c) { $cohorts[] = self::make_cohort_model($c); } $rs->close(); return $cohorts; } /** * Parameter description for webservice function all_associated */ public static function all_associated_parameters(): \external_function_parameters { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), ] ); } /** * Return value description for webservice function all_associated */ public static function all_associated_returns(): \external_description { return new \external_multiple_structure(self::user_structure()); } /** * List all users associated to a studyplan through either a cohort or directly * @param mixed $studyplanid Id of studyplan * @return array */ public static function all_associated($studyplanid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); 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 = :studyplanid OR tu.studyplan_id = :studyplanidtoo ) AND u.deleted != 1 ORDER BY u.lastname, u.firstname"; $rs = $DB->get_recordset_sql($sql, ["studyplanid" => $studyplan->id(), "studyplanidtoo" => $studyplan->id()]); foreach ($rs as $u) { $users[] = self::make_user_model($u); } $rs->close(); self::sortusermodels($users); return $users; } /** * Parameter description for webservice function all_associated */ public static function all_associated_grouped_parameters(): \external_function_parameters { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), ] ); } /** * Return value description for webservice function all_associated */ public static function all_associated_grouped_returns(): \external_description { return new \external_multiple_structure(new \external_single_structure([ 'id' => new \external_value(PARAM_INT, 'id of group'), 'label' => new \external_value(PARAM_TEXT, 'group label'), 'users' => new \external_multiple_structure(self::user_structure()), ])); } /** * List all users associated to a studyplan through either a cohort or directly * @param mixed $studyplanid Id of studyplan * @return array */ public static function all_associated_grouped($studyplanid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); if ($studyplan->is_coach()) { \external_api::validate_context($studyplan->context()); } else { webservicehelper::require_capabilities(self::CAP_VIEW, $studyplan->context()); } $userlist = [ [ 'id' => 0, 'label' => get_string("individuals", 'local_treestudyplan'), 'users' => self::associated_users($studyplanid), ], ]; $sql = "SELECT DISTINCT c.* FROM {cohort} c INNER JOIN {local_treestudyplan_cohort} j ON j.cohort_id = c.id WHERE j.studyplan_id = :studyplan_id"; $crs = $DB->get_recordset_sql($sql, ['studyplan_id' => $studyplanid]); foreach ($crs as $c) { $users = []; $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 WHERE cm.cohortid = :cohortid AND u.deleted != 1 ORDER BY u.lastname, u.firstname"; $rs = $DB->get_recordset_sql($sql, ["cohortid" => $c->id]); foreach ($rs as $u) { $user = self::make_user_model($u); $user["lastaccess"] = self::user_lastaccess($u->id, $studyplanid); $users[] = $user; } $rs->close(); $userlist[] = [ 'id' => $c->id, 'label' => $c->name, 'users' => $users, ]; } $crs->close(); return $userlist; } /** * Sort a list of user models by firstname->lastname * @param array $list Reference to list of user models */ public static function sortusermodels(&$list) { return usort($list, function($a, $b) { $m = []; if (preg_match("/.*?([A-Z].*)/", $a['lastname'], $m)) { $sortlna = $m[1]; } else { $sortlna = $a['lastname']; } if (preg_match("/.*?([A-Z].*)/", $b['lastname'], $m)) { $sortlnb = $m[1]; } else { $sortlnb = $b['lastname']; } $cmp = $sortlna <=> $sortlnb; return ($cmp != 0) ? $cmp : $a['firstname'] <=> $b['firstname']; }); } /** * Parameter description for webservice function cascade_cohortsync */ public static function cascade_cohortsync_parameters(): \external_function_parameters { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), ] ); } /** * Return value description for webservice function cascade_cohortsync */ public static function cascade_cohortsync_returns(): \external_description { return success::structure(); } /** * Perform cascading cohort sync for a given studyplan * This adds a cohort sync enrolment to all linked cohorts for each course listed in the studyplan * @param mixed $studyplanid Id of studyplan * @return array Success/fail model */ public static function cascade_cohortsync($studyplanid) { $studyplan = studyplan::find_by_id($studyplanid); webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context()); autocohortsync::syncplan($studyplan); return success::success()->model(); } /** * Parameter description for webservice function connect_user */ public static function connect_coach_parameters(): \external_function_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), ] ); } /** * Return value description for webservice function connect_user */ public static function connect_coach_returns(): \external_description { return new \external_single_structure([ "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "msg" => new \external_value(PARAM_TEXT, 'message'), ]); } /** * Connect a user to a studyplan * @param mixed $studyplanid Id of studyplan * @param mixed $userid Id of user * @return array Success/fail model */ public static function connect_coach($studyplanid, $userid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context()); $user = $DB->get_record("user", ["id" => $userid]); if ( has_capability(self::CAP_COACH, $studyplan->context(), $user)) { if (!$DB->record_exists('local_treestudyplan_coach', ['studyplan_id' => $studyplanid, 'user_id' => $userid])) { $id = $DB->insert_record('local_treestudyplan_coach', [ 'studyplan_id' => $studyplanid, 'user_id' => $userid, ]); return ['success' => true, 'msg' => 'User connected as coach']; } else { return ['success' => true, 'msg' => 'User already connected as coach']; } } else { return ['success' => false, 'msg' => 'User does not have coach capability in this studyplan\'s context']; } } /** * Parameter description for webservice function disconnect_user */ public static function disconnect_coach_parameters(): \external_function_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), ] ); } /** * Return value description for webservice function disconnect_user */ public static function disconnect_coach_returns(): \external_description { return new \external_single_structure([ "success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'), "msg" => new \external_value(PARAM_TEXT, 'message'), ]); } /** * Disconnect a user from a studyplan * @param mixed $studyplanid Id of studyplan * @param mixed $userid Id of user * @return array Success/fail model */ public static function disconnect_coach($studyplanid, $userid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context()); if ($DB->record_exists('local_treestudyplan_coach', ['studyplan_id' => $studyplanid, 'user_id' => $userid])) { $DB->delete_records('local_treestudyplan_coach', [ 'studyplan_id' => $studyplanid, 'user_id' => $userid, ]); return ['success' => true, 'msg' => 'User Disconnected as coach']; } else { return ['success' => true, 'msg' => 'Connection does not exist']; } } /** * Parameter description for webservice function find_user */ public static function find_coach_parameters(): \external_function_parameters { return new \external_function_parameters( [ 'like' => new \external_value(PARAM_TEXT, 'search text'), 'studyplan_id' => new \external_value(PARAM_INT, 'studyplan id to associate for', VALUE_OPTIONAL), ] ); } /** * Return value description for webservice function find_user */ public static function find_coach_returns(): \external_description { return new \external_multiple_structure(self::user_structure()); } /** * Search users for match * @param string $like String to match user firstname/lastname with * @param null $excludeid Do not include coaches connected to this studyplan id * @param int $contextid Context to search (default system) * @return array */ public static function find_coach($like, $studyplanid) { global $CFG, $DB; // Only allow this if the user has the right to edit in this context. $studyplan = studyplan::find_by_id($studyplanid); $context = $studyplan->context(); webservicehelper::require_capabilities(self::CAP_EDIT, $context); $pattern = "%{$like}%"; $params = ["pattern_fn" => $pattern, "pattern_ln" => $pattern, "pattern_un" => $pattern, ]; $sql = "SELECT DISTINCT u.* FROM {user} u LEFT JOIN {local_treestudyplan_coach} j ON u.id = j.user_id WHERE u.deleted != 1 AND (firstname LIKE :pattern_fn OR lastname LIKE :pattern_ln OR username LIKE :pattern_un)"; if (isset($excludeid) && is_numeric($excludeid)) { $sql .= " AND (j.studyplan_id IS NULL OR j.studyplan_id != :exclude_id)"; $params['exclude_id'] = $studyplan; } $users = []; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $r) { if (has_capability(self::CAP_COACH, $context, $r)) { $users[] = static::make_user_model($r); } } $rs->close(); self::sortusermodels($users); return $users; } /** * Parameter description for webservice function associated_users */ public static function associated_coaches_parameters(): \external_function_parameters { return new \external_function_parameters( [ "studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL), ] ); } /** * Return value description for webservice function associated_users */ public static function associated_coaches_returns(): \external_description { return new \external_multiple_structure(self::user_structure()); } /** * List all users associated to a studyplan * @param mixed $studyplanid Id of studyplan * @return array */ public static function associated_coaches($studyplanid) { global $CFG, $DB; $studyplan = studyplan::find_by_id($studyplanid); webservicehelper::require_capabilities(self::CAP_VIEW, $studyplan->context()); $sql = "SELECT DISTINCT u.* FROM {user} u INNER JOIN {local_treestudyplan_coach} j ON j.user_id = u.id WHERE j.studyplan_id = :studyplan_id AND u.deleted != 1 ORDER BY u.lastname, u.firstname"; $rs = $DB->get_recordset_sql($sql, ['studyplan_id' => $studyplanid]); $users = []; foreach ($rs as $u) { $user = self::make_user_model($u); $users[] = $user; } $rs->close(); self::sortusermodels($users); return $users; } }