506 lines
No EOL
18 KiB
PHP
506 lines
No EOL
18 KiB
PHP
<?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/>.
|
|
/**
|
|
*
|
|
* @package local_treestudyplan
|
|
* @copyright 2023 P.M. Kuipers
|
|
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
*/
|
|
|
|
namespace local_treestudyplan;
|
|
|
|
use local_treestudyplan\local\helpers\webservicehelper;
|
|
|
|
require_once($CFG->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();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} |