From f8fd27528a96f072923719a1e1bf53532b091334 Mon Sep 17 00:00:00 2001 From: PMKuipers Date: Fri, 25 Aug 2023 13:34:31 +0200 Subject: [PATCH] Moodle code style fixes part 10 --- classes/aggregator.php | 16 +- classes/associationservice.php | 949 +++++++++--------- classes/cascadecohortsync.php | 9 +- classes/contextinfo.php | 14 +- classes/corecompletioninfo.php | 47 +- .../local/aggregators/bistate_aggregator.php | 8 +- classes/local/aggregators/core_aggregator.php | 8 +- .../local/aggregators/tristate_aggregator.php | 8 +- classes/studyplan.php | 6 +- invitations.php | 1 - lang/en/local_treestudyplan.php | 2 - lib.php | 1 - 12 files changed, 533 insertions(+), 536 deletions(-) diff --git a/classes/aggregator.php b/classes/aggregator.php index 7d7bb6a..397b56a 100644 --- a/classes/aggregator.php +++ b/classes/aggregator.php @@ -59,7 +59,7 @@ abstract class aggregator { } } - public static function createOrDefault($mod, $configstr) { + public static function createordefault($mod, $configstr) { try { return self::create($mod, $configstr); } catch (\ValueError $x) { @@ -74,17 +74,17 @@ abstract class aggregator { protected function initialize($configstr) { } - abstract public function needSelectGradables(); - abstract public function isDeprecated(); + abstract public function select_gradables(); + abstract public function deprecated(); abstract public function aggregate_course(courseinfo $courseinfo, studyitem $studyitem, $userid); abstract public function aggregate_junction(array $completion, studyitem $studyitem, $userid); abstract public function grade_completion(gradeinfo $gradeinfo, $userid); // Aggregation method makes use of "required grades" in a course/module. - abstract public function useRequiredGrades(); + abstract public function use_required_grades(); // Aggregation method makes use of . - abstract public function useItemConditions(); + abstract public function use_item_conditions(); // Whether the aggregation method uses core_completion, or treestudyplan custom completion. public function usecorecompletioninfo() { @@ -107,8 +107,8 @@ abstract class aggregator { public function basic_model() { return [ - "useRequiredGrades" => $this->useRequiredGrades(), - "useItemConditions" => $this->useItemConditions(), + "useRequiredGrades" => $this->use_required_grades(), + "useItemConditions" => $this->use_item_conditions(), ]; } @@ -130,7 +130,7 @@ abstract class aggregator { $list[] = [ 'id' => $agid, 'name' => get_string("{$agid}_aggregator_title", "local_treestudyplan"), - 'deprecated' => $a->isDeprecated(), + 'deprecated' => $a->deprecated(), 'defaultconfig' => $a->config_string(), ]; } diff --git a/classes/associationservice.php b/classes/associationservice.php index 57d8510..5d75199 100644 --- a/classes/associationservice.php +++ b/classes/associationservice.php @@ -1,475 +1,474 @@ -. -/** - * - * @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; - -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 = '', $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 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($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; - } - - 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, $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 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($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; - } - - 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($studyplanid, $cohortid) { - global $CFG, $DB; - - $studyplan = studyplan::findById($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']; - } - - } - - 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($studyplanid, $cohortid) { - global $CFG, $DB; - - $studyplan = studyplan::findById($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']; - } - - } - - 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($studyplanid, $userid) { - global $CFG, $DB; - - $studyplan = studyplan::findById($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']; - } - } - - 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($studyplanid, $userid) { - global $CFG, $DB; - $studyplan = studyplan::findById($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']; - } - } - - 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($studyplanid) { - global $CFG, $DB; - $studyplan = studyplan::findById($studyplanid); - 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' => $studyplanid]); - - $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($studyplanid) { - global $CFG, $DB; - $studyplan = studyplan::findById($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"; - $sql .= " 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; - } - - 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($studyplanid) { - global $CFG, $DB; - - $studyplan = studyplan::findById($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 = {$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)) { - $sortln_a = $m[1]; - } else { - $sortln_a = $a['lastname']; - } - if (preg_match("/.*?([A-Z].*)/", $b['lastname'], $m)) { - $sortln_b = $m[1]; - } else { - $sortln_b = $b['lastname']; - } - $cmp = $sortln_a <=> $sortln_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($studyplanid) { - $studyplan = studyplan::findById($studyplanid); - 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(); - - } - - -} +. +/** + * + * @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; + +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 = '', $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 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($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; + } + + 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, $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 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($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; + } + + 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($studyplanid, $cohortid) { + global $CFG, $DB; + + $studyplan = studyplan::findById($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']; + } + + } + + 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($studyplanid, $cohortid) { + global $CFG, $DB; + + $studyplan = studyplan::findById($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']; + } + + } + + 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($studyplanid, $userid) { + global $CFG, $DB; + + $studyplan = studyplan::findById($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']; + } + } + + 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($studyplanid, $userid) { + global $CFG, $DB; + $studyplan = studyplan::findById($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']; + } + } + + 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($studyplanid) { + global $CFG, $DB; + $studyplan = studyplan::findById($studyplanid); + 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' => $studyplanid]); + + $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($studyplanid) { + global $CFG, $DB; + $studyplan = studyplan::findById($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"; + $sql .= " 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; + } + + 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($studyplanid) { + global $CFG, $DB; + + $studyplan = studyplan::findById($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 = {$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)) { + $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']; + }); + } + + 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($studyplanid) { + $studyplan = studyplan::findById($studyplanid); + 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(); + + } + +} diff --git a/classes/cascadecohortsync.php b/classes/cascadecohortsync.php index 1a02121..61e6dfd 100644 --- a/classes/cascadecohortsync.php +++ b/classes/cascadecohortsync.php @@ -37,7 +37,7 @@ class cascadecohortsync { $this->studyplanid = $studyplan->id(); } - static private function array_remove_value($array, $value) { + private static function array_remove_value($array, $value) { $a = []; foreach ($array as $v) { if ($v != $value) { @@ -47,7 +47,7 @@ class cascadecohortsync { return $a; } - static function uploadenrolmentmethods_get_group($courseid, $groupname) { + private static function uploadenrolmentmethods_get_group($courseid, $groupname) { // Function shamelessly copied from tool/uploadenrolmentmethods/locallib.php. global $DB, $CFG; @@ -92,7 +92,6 @@ class cascadecohortsync { foreach ($cohortids as $cohortid) { $cohort = $DB->get_record('cohort', ['id' => $cohortid]); - $instanceparams = [ 'courseid' => $courseid, 'customint1' => $cohortid, @@ -152,16 +151,12 @@ class cascadecohortsync { $instance = $DB->get_record('enrol', array('id' => $instanceid)); $enrol->update_instance($instance, (object)["customtext4" => json_encode([(int)($this->studyplanid)])]); - // Successfully added a valid new instance, so now instantiate it. // First synchronise the enrolment. $cohorttrace = new \null_progress_trace(); $result = enrol_cohort_sync($cohorttrace, $cohortid); $cohorttrace->finished(); - } else { - // Instance not added for some reason, so report an error somewhere. - // (or not). } } } diff --git a/classes/contextinfo.php b/classes/contextinfo.php index 2043954..01b6b29 100644 --- a/classes/contextinfo.php +++ b/classes/contextinfo.php @@ -39,17 +39,19 @@ class contextinfo { public function model() { - $ctxPath = array_reverse($this->context->get_parent_context_ids(true)); - if (count($ctxPath) > 1 && $ctxPath[0] == 1) { - array_shift($ctxPath); + $ctxpath = array_reverse($this->context->get_parent_context_ids(true)); + if (count($ctxpath) > 1 && $ctxpath[0] == 1) { + array_shift($ctxpath); } return [ "name" => $this->context->get_context_name(false, false), "shortname" => $this->context->get_context_name(false, true), - "path" => array_map(function($c) { return \context::instance_by_id($c)->get_context_name(false, false);}, $ctxPath), + "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 \context::instance_by_id($c)->get_context_name(false, true); + }, $ctxpath), ]; } diff --git a/classes/corecompletioninfo.php b/classes/corecompletioninfo.php index df70000..f7ec6d1 100644 --- a/classes/corecompletioninfo.php +++ b/classes/corecompletioninfo.php @@ -37,7 +37,8 @@ class corecompletioninfo { private $course; private $completion; private $modinfo; - private static $COMPLETIONHANDLES = null; + private static $completionhandles = null; + private static $completiontypes = null; public function id() { return $this->course->id; @@ -49,28 +50,33 @@ class corecompletioninfo { $this->modinfo = get_fast_modinfo($this->course); } - static public function completiontypes() { - global $COMPLETIONCRITERIA_TYPES; - // Just return the keys of the global array COMPLETION_CRITERIA_TYPES, so we don't have to manually. - // Add any completion types.... - return \array_keys($COMPLETIONCRITERIA_TYPES); + public static function completiontypes() { + global $COMPLETION_CRITERIA_TYPES; + /* Just return the keys of the global array COMPLETION_CRITERIA_TYPES, + so we don't have to manually add any completion types if moodle decides to add a few. + Unfortunately, the global variable breaks the moodle coding standard... + */ + if (!isset(self::$completiontypes)) { + self::$completiontypes = \array_keys($COMPLETION_CRITERIA_TYPES); + } + return self::$completiontypes; } /** * Translate a numeric completion constant to a text string * @param $completion The completion code as defined in completionlib.php to translate to a text handle */ - static public function completion_handle($completion) { - if (empty(self::$COMPLETIONHANDLES)) { + public static function completion_handle($completion) { + if (empty(self::$completionhandles)) { // Cache the translation table, to avoid overhead. - self::$COMPLETIONHANDLES = [ + self::$completionhandles = [ COMPLETION_INCOMPLETE => "incomplete", COMPLETION_COMPLETE => "complete", COMPLETION_COMPLETE_PASS => "complete-pass", COMPLETION_COMPLETE_FAIL => "complete-fail", COMPLETION_COMPLETE_FAIL_HIDDEN => "complete-fail"]; // The front end won't differentiate between hidden or not. } - return self::$COMPLETIONHANDLES[$completion] ?? "undefined"; + return self::$completionhandles[$completion] ?? "undefined"; } public static function completion_item_editor_structure($value = VALUE_REQUIRED) { @@ -156,11 +162,11 @@ class corecompletioninfo { } private static function aggregation_handle($method) { - return ($method ==COMPLETION_AGGREGATION_ALL) ? "all" : "any"; + return ($method == COMPLETION_AGGREGATION_ALL) ? "all" : "any"; } public function editor_model() { - global $DB, $CFG, $COMPLETIONCRITERIA_TYPES; + global $DB, $CFG; $conditions = []; $aggregation = "all"; // Default. @@ -179,7 +185,7 @@ class corecompletioninfo { if (count($criterias) > 0 ) { // Only take it into account if the criteria count is > 0. $cinfo = [ - "type" => $COMPLETIONCRITERIA_TYPES[$type], + "type" => self::completiontypes()[$type], "aggregation" => self::aggregation_handle($this->completion->get_aggregation_method($type)), "title" => reset($criterias)->get_type_title(), "items" => [], @@ -254,7 +260,7 @@ class corecompletioninfo { $details = [ "type" => get_string('periodpostenrolment', 'completion'), "criteria" => get_string('remainingenroledfortime', 'completion'), - "requirement" => get_string('xdays', 'completion', ceil($criteria->enrolperiod / (60*60*24))), + "requirement" => get_string('xdays', 'completion', ceil($criteria->enrolperiod / (60 * 60 * 24))), "status" => "", ]; } else if ($type == COMPLETION_CRITERIA_TYPE_GRADE) { @@ -333,7 +339,7 @@ class corecompletioninfo { } public function user_model($userid) { - global $DB, $COMPLETIONCRITERIA_TYPES; + global $DB; $progress = $this->get_advanced_progress_percentage($userid); $info = [ @@ -357,7 +363,7 @@ class corecompletioninfo { $typeaggregation = $this->completion->get_aggregation_method($type); $completed = $this->aggregate_completions($typeaggregation, $completions); $cinfo = [ - "type" => $COMPLETIONCRITERIA_TYPES[$type], + "type" => self::completiontypes()[$type], "aggregation" => self::aggregation_handle($typeaggregation), "completed" => $completed, "status" => $completed ? "complete" : "incomplete", @@ -428,7 +434,7 @@ class corecompletioninfo { // Count and progress are either 1 or 0, since any of the items. // Complete's the type. $cinfo["count"] = (count($cinfo["items"]) > 0) ? 1 : 0; - $cinfo["progress"] = ($progress>0) ? 1 : 0; + $cinfo["progress"] = ($progress > 0) ? 1 : 0; } $info['conditions'][] = $cinfo; @@ -650,15 +656,14 @@ class corecompletioninfo { // If ANY completion for the types, count only the criteria type with the highest completion percentage -. // Overwrite data if current type is more complete. if ($aggregation == COMPLETION_AGGREGATION_ANY) { - $pct = $cmpl/$ct; + $pct = $cmpl / $ct; if ($pct > $completionpercentage) { $count = $ct; $completed = $cmpl; $completionpercentage = $pct; } - } - // If ALL completion for the types, add the count for this type to that of the others. - else { + } else { + // If ALL completion for the types, add the count for this type to that of the others. $count += $ct; $completed += $cmpl; // Don't really care about recalculating completion percentage every round in this case. diff --git a/classes/local/aggregators/bistate_aggregator.php b/classes/local/aggregators/bistate_aggregator.php index f49fd94..77fa033 100644 --- a/classes/local/aggregators/bistate_aggregator.php +++ b/classes/local/aggregators/bistate_aggregator.php @@ -90,16 +90,16 @@ class bistate_aggregator extends \local_treestudyplan\aggregator { ]); } - public function needSelectGradables() { + public function select_gradables() { return true; } - public function isDeprecated() { + public function deprecated() { return self::DEPRECATED; } - public function useRequiredGrades() { + public function use_required_grades() { return true; } - public function useItemConditions() { + public function use_item_conditions() { return false; } diff --git a/classes/local/aggregators/core_aggregator.php b/classes/local/aggregators/core_aggregator.php index c07a039..652d0b1 100644 --- a/classes/local/aggregators/core_aggregator.php +++ b/classes/local/aggregators/core_aggregator.php @@ -64,16 +64,16 @@ class core_aggregator extends \local_treestudyplan\aggregator { ]); } - public function needSelectGradables() { + public function select_gradables() { return false; } - public function isDeprecated() { + public function deprecated() { return self::DEPRECATED; } - public function useRequiredGrades() { + public function use_required_grades() { return true; } - public function useItemConditions() { + public function use_item_conditions() { return false; } public function usecorecompletioninfo() { diff --git a/classes/local/aggregators/tristate_aggregator.php b/classes/local/aggregators/tristate_aggregator.php index 4bfbf58..93c8522 100644 --- a/classes/local/aggregators/tristate_aggregator.php +++ b/classes/local/aggregators/tristate_aggregator.php @@ -31,16 +31,16 @@ class tristate_aggregator extends \local_treestudyplan\aggregator { public const DEPRECATED = true; private const DEFAULT_CONDITION = "50"; - public function needSelectGradables() { + public function select_gradables() { return true; } - public function isDeprecated() { + public function deprecated() { return self::DEPRECATED; } - public function useRequiredGrades() { + public function use_required_grades() { return false; } - public function useItemConditions() { + public function use_item_conditions() { return true; } diff --git a/classes/studyplan.php b/classes/studyplan.php index bfc0f4d..3177569 100644 --- a/classes/studyplan.php +++ b/classes/studyplan.php @@ -54,7 +54,7 @@ class studyplan { $this->id = $id; $this->r = $DB->get_record(self::TABLE, ['id' => $id]); - $this->aggregator = aggregator::createOrDefault($this->r->aggregation, $this->r->aggregation_config); + $this->aggregator = aggregator::createordefault($this->r->aggregation, $this->r->aggregation_config); } public function id() { @@ -250,7 +250,7 @@ class studyplan { $this->context = null; $this->context(); // Reload aggregator. - $this->aggregator = aggregator::createOrDefault($this->r->aggregation, $this->r->aggregation_config); + $this->aggregator = aggregator::createordefault($this->r->aggregation, $this->r->aggregation_config); // Start temporary skräpp code. // TODO: Until proper page editing is implemented, copy data from studyplan to it's first page. @@ -359,7 +359,7 @@ class studyplan { } - static public function exist_for_user($userid) { + public static function exist_for_user($userid) { global $DB; $count = 0; $sql = "SELECT s.* FROM {local_treestudyplan} s diff --git a/invitations.php b/invitations.php index 336f0b6..58a12e1 100644 --- a/invitations.php +++ b/invitations.php @@ -20,7 +20,6 @@ * @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - require_once("../../config.php"); require_once($CFG->libdir.'/weblib.php'); diff --git a/lang/en/local_treestudyplan.php b/lang/en/local_treestudyplan.php index 77a461f..6a4e4f1 100644 --- a/lang/en/local_treestudyplan.php +++ b/lang/en/local_treestudyplan.php @@ -39,7 +39,6 @@ $string['treestudyplan:viewuserreports'] = "View study plan of others"; $string['treestudyplan:forcescales'] = 'Advanced: Allow studyplan manager to force assignment scales to setting (manual modes only)'; $string['treestudyplan:selectowngradables'] = 'Teachers can select gradables in their own courses in study plan view mode (manual modes only)'; - $string['report'] = 'Progress report'; $string['report_invited'] = 'Progress report for {$a}'; $string['report_index'] = 'View student progress reports'; @@ -242,7 +241,6 @@ $string['bistate_aggregator_desc'] = 'Goals are completed or not (e.g. not start $string['core_aggregator_title'] = 'Moodle course completion'; $string['core_aggregator_desc'] = 'Use Moodle core completion'; - $string['setting_bistate_heading'] = 'Defaults for Completed + Required goalsn'; $string['settingdesc_bistate_heading'] = 'Set the defaults for this aggregation method'; diff --git a/lib.php b/lib.php index 5e66829..4eff302 100644 --- a/lib.php +++ b/lib.php @@ -26,7 +26,6 @@ use local_treestudyplan\local\helpers\webservicehelper; use \local_treestudyplan\studyplan; - function local_treestudyplan_unit_get_editor_options($context) { global $CFG; return ['subdirs' => 1,