moodle_local_treestudyplan/classes/associationservice.php

914 lines
34 KiB
PHP
Raw Normal View History

2023-08-25 13:34:31 +02:00
<?php
// This file is part of the Studyplan plugin for Moodle
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <https://www.gnu.org/licenses/>.
/**
2023-08-28 11:26:14 +02:00
* Webservice class for handling associations of cohorts and users to a studyplan
2023-08-25 13:34:31 +02:00
* @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;
2023-08-25 13:34:31 +02:00
require_once($CFG->libdir.'/externallib.php');
2023-08-28 11:26:14 +02:00
/**
* Webservice class for handling associations of cohorts and users to a studyplan
*/
2023-08-25 13:34:31 +02:00
class associationservice extends \external_api {
2023-08-28 11:26:14 +02:00
/**
* Capability required to edit study plans
* @var string
*/
2023-08-25 13:34:31 +02:00
const CAP_EDIT = "local/treestudyplan:editstudyplan";
2023-08-28 11:26:14 +02:00
/**
* Capability required to view studyplans (for other users)
* @var string
*/
2023-08-25 13:34:31 +02:00
const CAP_VIEW = "local/treestudyplan:viewuserreports";
2024-03-08 17:05:07 +01:00
/**
* Capability required to be linked as coach to a studyplan
* @var string
*/
const CAP_COACH = "local/treestudyplan:coach";
2023-08-28 11:26:14 +02:00
/**
* Webservice structure to use in describing a user
*/
public static function user_structure() : \external_description {
2023-08-25 13:34:31 +02:00
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),
2023-08-25 13:34:31 +02:00
]);
}
2023-08-28 11:26:14 +02:00
/**
* Make a webservice user model for a given user
* @param stdClass $r User DB record
*/
2023-08-25 13:34:31 +02:00
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,
];
}
2023-08-28 11:26:14 +02:00
/**
* Webservice structure to use in describing a cohort
*/
public static function cohort_structure() : \external_description {
2023-08-25 13:34:31 +02:00
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),
]);
}
2023-08-28 11:26:14 +02:00
/**
* Make a webservice cohort model for a given cohort
* @param stdClass $r Cohort DB record
*/
2023-08-25 13:34:31 +02:00
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;
}
2023-08-27 21:57:21 +02:00
/**
* Parameter description for webservice function list_cohort
*/
2023-08-28 08:51:52 +02:00
public static function list_cohort_parameters() : \external_function_parameters {
2023-08-25 13:34:31 +02:00
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),
] );
}
2023-08-27 21:57:21 +02:00
/**
* Return value description for webservice function list_cohort
*/
2023-08-28 11:26:14 +02:00
public static function list_cohort_returns() : \external_description {
2023-08-25 13:34:31 +02:00
return new \external_multiple_structure(self::cohort_structure());
}
2023-08-28 11:26:14 +02:00
/**
* Search cohorts for matching string
* @param string $like String to match cohorts with
* @param null $excludeid Do not include these cohorts
* @param int $contextid Context to search (default system)
* @return array
*/
2023-08-25 13:34:31 +02:00
public static function list_cohort($like = '', $excludeid = null, $contextid = 1) {
global $CFG, $DB;
// Only allow this if the user has the right to edit in this context.
$context = webservicehelper::find_context($contextid);
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
2023-08-25 17:33:20 +02:00
WHERE c.visible = 1 AND(name LIKE :pattern_nm OR idnumber LIKE :pattern_id)";
2023-08-25 13:34:31 +02:00
if (isset($excludeid) && is_numeric($excludeid)) {
$sql .= " AND (j.studyplan_id IS NULL OR j.studyplan_id != :exclude_id)";
$params['exclude_id'] = $excludeid;
}
if ($contextid > 1) {
// System context returns all cohorts, including system cohorts.
// Otherwise, .
$sql .= " AND contextid = :context_id";
$params['context_id'] = $contextid;
}
$cohorts = [];
$rs = $DB->get_recordset_sql($sql, $params);
foreach ($rs as $r) {
$cohorts[] = static::make_cohort_model($r);
}
$rs->close();
return $cohorts;
}
2023-08-27 21:57:21 +02:00
/**
* Parameter description for webservice function find_user
*/
2023-08-28 08:51:52 +02:00
public static function find_user_parameters() : \external_function_parameters {
2023-08-25 13:34:31 +02:00
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),
] );
}
2023-08-27 21:57:21 +02:00
/**
* Return value description for webservice function find_user
*/
2023-08-28 11:26:14 +02:00
public static function find_user_returns() : \external_description {
2023-08-25 13:34:31 +02:00
return new \external_multiple_structure(self::user_structure());
}
2023-08-28 11:26:14 +02:00
/**
* 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
*/
2023-08-25 13:34:31 +02:00
public static function find_user($like, $excludeid = null, $contextid = 1) {
global $CFG, $DB;
// Only allow this if the user has the right to edit in this context.
$context = webservicehelper::find_context($contextid);
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
2023-08-25 17:33:20 +02:00
WHERE u.deleted != 1 AND (firstname LIKE :pattern_fn OR lastname LIKE :pattern_ln OR username LIKE :pattern_un)";
2023-08-25 13:34:31 +02:00
if (isset($excludeid) && is_numeric($excludeid)) {
$sql .= " AND (j.studyplan_id IS NULL OR j.studyplan_id != :exclude_id)";
$params['exclude_id'] = $excludeid;
}
$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;
}
2023-08-27 21:57:21 +02:00
/**
* Parameter description for webservice function connect_cohort
*/
2023-08-28 08:51:52 +02:00
public static function connect_cohort_parameters() : \external_function_parameters {
2023-08-25 13:34:31 +02:00
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),
] );
}
2023-08-27 21:57:21 +02:00
/**
* Return value description for webservice function connect_cohort
*/
2023-08-28 11:26:14 +02:00
public static function connect_cohort_returns() : \external_description {
2023-08-25 13:34:31 +02:00
return new \external_single_structure([
"success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'),
"msg" => new \external_value(PARAM_TEXT, 'message'),
]);
}
2023-08-28 11:26:14 +02:00
/**
* Connect a cohort to a studyplan
* @param mixed $studyplanid Id of studyplan
* @param mixed $cohortid Id of cohort
* @return array Success/fail model
*/
2023-08-25 13:34:31 +02:00
public static function connect_cohort($studyplanid, $cohortid) {
global $CFG, $DB;
2023-08-25 17:33:20 +02:00
$studyplan = studyplan::find_by_id($studyplanid);
2023-08-25 13:34:31 +02:00
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'];
}
}
2023-08-27 21:57:21 +02:00
/**
* Parameter description for webservice function disconnect_cohort
*/
2023-08-28 08:51:52 +02:00
public static function disconnect_cohort_parameters() : \external_function_parameters {
2023-08-25 13:34:31 +02:00
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),
] );
}
2023-08-27 21:57:21 +02:00
/**
* Return value description for webservice function disconnect_cohort
*/
2023-08-28 11:26:14 +02:00
public static function disconnect_cohort_returns() : \external_description {
2023-08-25 13:34:31 +02:00
return new \external_single_structure([
"success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'),
"msg" => new \external_value(PARAM_TEXT, 'message'),
]);
}
2023-08-28 11:26:14 +02:00
/**
* Disconnect a cohort from a studyplan
* @param mixed $studyplanid Id of studyplan
* @param mixed $cohortid Id of cohort
* @return array Success/fail model
*/
2023-08-25 13:34:31 +02:00
public static function disconnect_cohort($studyplanid, $cohortid) {
global $CFG, $DB;
2023-08-25 17:33:20 +02:00
$studyplan = studyplan::find_by_id($studyplanid);
2023-08-25 13:34:31 +02:00
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'];
}
}
2023-08-27 21:57:21 +02:00
/**
* Parameter description for webservice function connect_user
*/
2023-08-28 08:51:52 +02:00
public static function connect_user_parameters() : \external_function_parameters {
2023-08-25 13:34:31 +02:00
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),
] );
}
2023-08-27 21:57:21 +02:00
/**
* Return value description for webservice function connect_user
*/
2023-08-28 11:26:14 +02:00
public static function connect_user_returns() : \external_description {
2023-08-25 13:34:31 +02:00
return new \external_single_structure([
"success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'),
"msg" => new \external_value(PARAM_TEXT, 'message'),
]);
}
2023-08-28 11:26:14 +02:00
/**
* Connect a user to a studyplan
* @param mixed $studyplanid Id of studyplan
* @param mixed $userid Id of user
* @return array Success/fail model
*/
2023-08-25 13:34:31 +02:00
public static function connect_user($studyplanid, $userid) {
global $CFG, $DB;
2023-08-25 17:33:20 +02:00
$studyplan = studyplan::find_by_id($studyplanid);
2023-08-25 13:34:31 +02:00
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'];
}
}
2023-08-27 21:57:21 +02:00
/**
* Parameter description for webservice function disconnect_user
*/
2023-08-28 08:51:52 +02:00
public static function disconnect_user_parameters() : \external_function_parameters {
2023-08-25 13:34:31 +02:00
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),
] );
}
2023-08-27 21:57:21 +02:00
/**
* Return value description for webservice function disconnect_user
*/
2023-08-28 11:26:14 +02:00
public static function disconnect_user_returns() : \external_description {
2023-08-25 13:34:31 +02:00
return new \external_single_structure([
"success" => new \external_value(PARAM_BOOL, 'operation completed succesfully'),
"msg" => new \external_value(PARAM_TEXT, 'message'),
]);
}
2023-08-28 11:26:14 +02:00
/**
* Disconnect a user from a studyplan
* @param mixed $studyplanid Id of studyplan
* @param mixed $userid Id of user
* @return array Success/fail model
*/
2023-08-25 13:34:31 +02:00
public static function disconnect_user($studyplanid, $userid) {
global $CFG, $DB;
2023-08-25 17:33:20 +02:00
$studyplan = studyplan::find_by_id($studyplanid);
2023-08-25 13:34:31 +02:00
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'];
}
}
2023-08-27 21:57:21 +02:00
/**
* Parameter description for webservice function associated_users
*/
2023-08-28 08:51:52 +02:00
public static function associated_users_parameters() : \external_function_parameters {
2023-08-25 13:34:31 +02:00
return new \external_function_parameters( [
"studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL),
] );
}
2023-08-27 21:57:21 +02:00
/**
* Return value description for webservice function associated_users
*/
2023-08-28 11:26:14 +02:00
public static function associated_users_returns() : \external_description {
2023-08-25 13:34:31 +02:00
return new \external_multiple_structure(self::user_structure());
}
2023-08-28 11:26:14 +02:00
/**
* List all users associated to a studyplan
* @param mixed $studyplanid Id of studyplan
* @return array
*/
2023-08-25 13:34:31 +02:00
public static function associated_users($studyplanid) {
global $CFG, $DB;
2023-08-25 17:33:20 +02:00
$studyplan = studyplan::find_by_id($studyplanid);
2024-03-09 22:51:34 +01:00
if ($studyplan->is_coach()) {
\external_api::validate_context($studyplan->context());
} else {
webservicehelper::require_capabilities(self::CAP_VIEW, $studyplan->context());
}
2023-08-25 13:34:31 +02:00
2023-08-25 17:33:20 +02:00
$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";
2023-08-25 13:34:31 +02:00
$rs = $DB->get_recordset_sql($sql, ['studyplan_id' => $studyplanid]);
/*
ID: 30
page: 33
plan: 28
*/
2023-08-25 13:34:31 +02:00
$users = [];
foreach ($rs as $u) {
$user = self::make_user_model($u);
$user["lastaccess"] = self::user_lastaccess($u->id,$studyplanid);
$users[] = $user;
2023-08-25 13:34:31 +02:00
}
$rs->close();
self::sortusermodels($users);
return $users;
}
2023-08-27 21:57:21 +02:00
/**
* Parameter description for webservice function associated_cohorts
*/
2023-08-28 08:51:52 +02:00
public static function associated_cohorts_parameters() : \external_function_parameters {
2023-08-25 13:34:31 +02:00
return new \external_function_parameters( [
"studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL),
] );
}
2023-08-27 21:57:21 +02:00
/**
* Return value description for webservice function associated_cohorts
*/
2023-08-28 11:26:14 +02:00
public static function associated_cohorts_returns() : \external_description {
2023-08-25 13:34:31 +02:00
return new \external_multiple_structure(self::cohort_structure());
}
2023-08-28 11:26:14 +02:00
/**
* List all cohorts associated to a studyplan
* @param mixed $studyplanid Id of studyplan
* @return array
*/
2023-08-25 13:34:31 +02:00
public static function associated_cohorts($studyplanid) {
global $CFG, $DB;
2023-08-25 17:33:20 +02:00
$studyplan = studyplan::find_by_id($studyplanid);
2023-08-25 13:34:31 +02:00
webservicehelper::require_capabilities(self::CAP_VIEW, $studyplan->context());
2023-08-25 17:33:20 +02:00
$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";
2023-08-25 13:34:31 +02:00
$rs = $DB->get_recordset_sql($sql, ['studyplan_id' => $studyplanid]);
$cohorts = [];
foreach ($rs as $c) {
$cohorts[] = self::make_cohort_model($c);
}
$rs->close();
return $cohorts;
}
2023-08-27 21:57:21 +02:00
/**
* Parameter description for webservice function all_associated
*/
2023-08-28 08:51:52 +02:00
public static function all_associated_parameters() : \external_function_parameters {
2023-08-25 13:34:31 +02:00
return new \external_function_parameters( [
"studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL),
] );
}
2023-08-27 21:57:21 +02:00
/**
* Return value description for webservice function all_associated
*/
2023-08-28 11:26:14 +02:00
public static function all_associated_returns() : \external_description {
2023-08-25 13:34:31 +02:00
return new \external_multiple_structure(self::user_structure());
}
2023-08-28 11:26:14 +02:00
/**
* List all users associated to a studyplan through either a cohort or directly
* @param mixed $studyplanid Id of studyplan
* @return array
*/
2023-08-25 13:34:31 +02:00
public static function all_associated($studyplanid) {
global $CFG, $DB;
2023-08-25 17:33:20 +02:00
$studyplan = studyplan::find_by_id($studyplanid);
2023-08-25 13:34:31 +02:00
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.
2023-08-25 17:33:20 +02:00
$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
2023-08-25 17:33:20 +02:00
ORDER BY u.lastname, u.firstname";
2023-08-26 16:51:35 +02:00
$rs = $DB->get_recordset_sql($sql, ["studyplanid" => $studyplan->id(), "studyplanidtoo" => $studyplan->id()]);
2023-08-25 13:34:31 +02:00
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);
2024-03-09 22:51:34 +01:00
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;
}
2023-08-28 11:26:14 +02:00
/**
* Sort a list of user models by firstname->lastname
* @param array $list Reference to list of user models
*/
2023-08-25 13:34:31 +02:00
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'];
});
}
2023-08-27 21:57:21 +02:00
/**
* Parameter description for webservice function cascade_cohortsync
*/
2023-08-28 08:51:52 +02:00
public static function cascade_cohortsync_parameters() : \external_function_parameters {
2023-08-25 13:34:31 +02:00
return new \external_function_parameters( [
"studyplan_id" => new \external_value(PARAM_INT, 'id of studyplan', VALUE_OPTIONAL),
] );
}
2023-08-27 21:57:21 +02:00
/**
* Return value description for webservice function cascade_cohortsync
*/
2023-08-28 11:26:14 +02:00
public static function cascade_cohortsync_returns() : \external_description {
2023-08-25 13:34:31 +02:00
return success::structure();
}
2023-08-28 11:26:14 +02:00
/**
* 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
*/
2023-08-25 13:34:31 +02:00
public static function cascade_cohortsync($studyplanid) {
2023-08-25 17:33:20 +02:00
$studyplan = studyplan::find_by_id($studyplanid);
2023-08-25 13:34:31 +02:00
webservicehelper::require_capabilities(self::CAP_EDIT, $studyplan->context());
autocohortsync::syncplan($studyplan);
2023-08-25 13:34:31 +02:00
return success::success()->model();
}
2024-03-08 17:05:07 +01:00
/**
* 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'),
2024-04-19 16:46:30 +02:00
'studyplan_id' => new \external_value(PARAM_INT, 'studyplan id to associate for', VALUE_OPTIONAL),
2024-03-08 17:05:07 +01:00
] );
}
/**
* 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
*/
2024-04-19 16:46:30 +02:00
public static function find_coach($like, $studyplan_id) {
2024-03-08 17:05:07 +01:00
global $CFG, $DB;
// Only allow this if the user has the right to edit in this context.
2024-04-19 16:46:30 +02:00
$studyplan = studyplan::find_by_id($studyplan_id);
$context = $studyplan->context();
2024-03-08 17:05:07 +01:00
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)";
2024-04-19 16:46:30 +02:00
$params['exclude_id'] = $studyplan;
2024-03-08 17:05:07 +01:00
}
$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
2024-03-08 17:05:07 +01:00
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;
}
2023-08-25 13:34:31 +02:00
}