diff --git a/admin/tool/lp/amd/build/grade_user_competency_inline.min.js b/admin/tool/lp/amd/build/grade_user_competency_inline.min.js new file mode 100644 index 00000000000..e8e09f0d4c9 --- /dev/null +++ b/admin/tool/lp/amd/build/grade_user_competency_inline.min.js @@ -0,0 +1 @@ +define(["jquery","core/notification","core/ajax","core/log"],function(a,b,c,d){var e=function(a,b,c,d,e){this._formId=a,this._scaleConfig=b,this._competencyId=c,this._userId=d,this._planId=e,this._buildSelect(),this._addListeners()};return e.prototype._buildSelect=function(){var b=1;for(b=1;b");d.text(c.name),d.attr("value",c.id),c.scaledefault&&d.attr("selected","selected"),a(document.getElementById(this._formId)).find("select").append(d)}},e.prototype._handleGrade=function(d){var e=this,f=a(document.getElementById(this._formId)).find("select").val();if(d.preventDefault(),this._planId>0){var g={userid:this._userId,competencyid:this._competencyId,planid:this._planId,grade:f,override:!0};c.call([{methodname:"tool_lp_grade_competency_in_plan",args:g,done:function(a){e._trigger("competencyupdated",{args:g,evidence:a})},fail:b.exception}])}},e.prototype._handleSuggest=function(d){var e=this,f=a(document.getElementById(this._formId)).find("select").val();if(d.preventDefault(),this._planId>0){var g={userid:this._userId,competencyid:this._competencyId,planid:this._planId,grade:f,override:!1};c.call([{methodname:"tool_lp_grade_competency_in_plan",args:g,done:function(a){e._trigger("competencyupdated",{args:g,evidence:a})},fail:b.exception}])}},e.prototype._addListeners=function(){var b=this,c=a(document.getElementById(this._formId)),e=c.find('[data-action="grade"]');e.on("click",function(a){b._handleGrade.call(b,a)});var f=c.find('[data-action="suggest"]');f.on("click",function(a){b._handleSuggest.call(b,a)}),this.on("competencyupdated",function(a,b){d.debug("Competency updated"),d.debug(b)})},e.prototype._trigger=function(c,d){return"competencyupdated"!=c&&b.exception("Invalid event name:"+c),a(document.getElementById(this._formId)).trigger(c,d),this},e.prototype.on=function(c,d){return"competencyupdated"!=c&&b.exception("Invalid event name:"+c),a(document.getElementById(this._formId)).on(c,d),this},e.prototype._formId=null,e.prototype._scaleConfig=null,e.prototype._competencyId=null,e.prototype._userId=null,e.prototype._planId=null,e}); \ No newline at end of file diff --git a/admin/tool/lp/amd/build/user_competency_info.min.js b/admin/tool/lp/amd/build/user_competency_info.min.js new file mode 100644 index 00000000000..a3877a7e6ad --- /dev/null +++ b/admin/tool/lp/amd/build/user_competency_info.min.js @@ -0,0 +1 @@ +define(["jquery","core/notification","core/ajax","core/templates"],function(a,b,c,d){var e=function(a,b,c,d){this._rootElement=a,this._competencyId=b,this._userId=c,this._planId=d};return e.prototype.reload=function(){var a=this,e=[];e=c.call([{methodname:"tool_lp_read_user_competency_summary",args:{userid:this._userId,competencyid:this._competencyId,planid:this._planId}}]),e[0].done(function(c){d.render("tool_lp/user_competency_info",c).done(function(b,c){d.replaceNode(a._rootElement,b,c)}).fail(b.exception)}).fail(b.exception)},e.prototype._rootElement=null,e.prototype._planId=null,e.prototype._competencyId=null,e.prototype._userId=null,e}); \ No newline at end of file diff --git a/admin/tool/lp/amd/src/grade_user_competency_inline.js b/admin/tool/lp/amd/src/grade_user_competency_inline.js new file mode 100644 index 00000000000..7be6b1072ef --- /dev/null +++ b/admin/tool/lp/amd/src/grade_user_competency_inline.js @@ -0,0 +1,194 @@ +// This file is part of Moodle - http://moodle.org/ +// +// 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 . + +/** + * Module to enable inline editing of a comptency grade. + * + * @package tool_lp + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define(['jquery', 'core/notification', 'core/ajax', 'core/log'], function($, notification, ajax, log) { + + /** + * InlineEditor + * + * @param {String} The id of the form element. + * @param {Object} The scale config for this competency. + * @param {Number} The id of the competency. + * @param {Number} The id of the user. + * @param {Number} The id of the plan. + */ + var InlineEditor = function(formId, scaleConfig, competencyId, userId, planId) { + this._formId = formId; + this._scaleConfig = scaleConfig; + this._competencyId = competencyId; + this._userId = userId; + this._planId = planId; + this._buildSelect(); + this._addListeners(); + }; + + /** + * Add all the options to the select. + * + * @method _buildSelect + */ + InlineEditor.prototype._buildSelect = function() { + var i = 1; + + // The first item is the scaleid - we don't care about that. + for (i = 1; i < this._scaleConfig.length; i++) { + var optionConfig = this._scaleConfig[i]; + var optionEle = $(''); + optionEle.text(optionConfig.name); + optionEle.attr('value', optionConfig.id); + if (optionConfig.scaledefault) { + optionEle.attr('selected', 'selected'); + } + + $(document.getElementById(this._formId)).find('select').append(optionEle); + } + }; + + /** + * Handle grade button click + * + * @param {Event} event + * @method _handleGrade + */ + InlineEditor.prototype._handleGrade = function(event) { + var currentthis = this; + var grade = $(document.getElementById(this._formId)).find('select').val(); + event.preventDefault(); + if (this._planId > 0) { + var args = { + userid: this._userId, + competencyid: this._competencyId, + planid: this._planId, + grade: grade, + override: true + }; + ajax.call([{ + methodname: 'tool_lp_grade_competency_in_plan', + args: args, + done: function(evidence) { + currentthis._trigger('competencyupdated', { args: args, evidence: evidence}); + }, + fail: notification.exception + }]); + } + }; + + /** + * Handle suggest button click + * + * @param {Event} event + * @method _handleSuggest + */ + InlineEditor.prototype._handleSuggest = function(event) { + var currentthis = this; + var grade = $(document.getElementById(this._formId)).find('select').val(); + event.preventDefault(); + if (this._planId > 0) { + var args = { + userid: this._userId, + competencyid: this._competencyId, + planid: this._planId, + grade: grade, + override: false + }; + ajax.call([{ + methodname: 'tool_lp_grade_competency_in_plan', + args: args, + done: function(evidence) { + currentthis._trigger('competencyupdated', { args: args, evidence: evidence}); + }, + fail: notification.exception + }]); + } + }; + + /** + * Setup event listeners. + * + * @method _addListeners + */ + InlineEditor.prototype._addListeners = function() { + var currentthis = this; + var form = $(document.getElementById(this._formId)); + var gradebutton = form.find('[data-action="grade"]'); + gradebutton.on('click', function(event) { + currentthis._handleGrade.call(currentthis, event); + }); + var suggestbutton = form.find('[data-action="suggest"]'); + suggestbutton.on('click', function(event) { + currentthis._handleSuggest.call(currentthis, event); + }); + + this.on('competencyupdated', function(event, args) { + log.debug('Competency updated'); + log.debug(args); + }); + }; + + /** + * Trigger an event from this module. + * + * @param {String} eventname - Only 'competencyupdated' is supported + * @param {Object} arguments - Additional arguments for the event. + * @return InlineEditor for chaining + * @method _trigger + */ + InlineEditor.prototype._trigger = function(eventname, data) { + if (eventname != 'competencyupdated') { + notification.exception('Invalid event name:' + eventname); + } + $(document.getElementById(this._formId)).trigger(eventname, data); + return this; + }; + + /** + * Attach a listener for events triggered from this module. + * + * @param {String} eventname - Only 'competencyupdated' is supported + * @param {Function} handler - Event handler to call when this event is triggered. + * @return InlineEditor for chaining + * @method on + */ + InlineEditor.prototype.on = function(eventname, handler) { + if (eventname != 'competencyupdated') { + notification.exception('Invalid event name:' + eventname); + } + $(document.getElementById(this._formId)).on(eventname, handler); + return this; + }; + + + /** @type {String} The id of the select element. */ + InlineEditor.prototype._formId = null; + /** @type {Object} The scale config for this competency. */ + InlineEditor.prototype._scaleConfig = null; + /** @type {Number} The id of the competency. */ + InlineEditor.prototype._competencyId = null; + /** @type {Number} The id of the user. */ + InlineEditor.prototype._userId = null; + /** @type {Number} The id of the plan. */ + InlineEditor.prototype._planId = null; + + return /** @alias module:tool_lp/grade_user_competency_inline */ InlineEditor; + +}); diff --git a/admin/tool/lp/amd/src/user_competency_info.js b/admin/tool/lp/amd/src/user_competency_info.js new file mode 100644 index 00000000000..ecd698d8f79 --- /dev/null +++ b/admin/tool/lp/amd/src/user_competency_info.js @@ -0,0 +1,73 @@ +// This file is part of Moodle - http://moodle.org/ +// +// 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 . + +/** + * Module to refresh a user competency summary in a page. + * + * @package tool_lp + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +define(['jquery', 'core/notification', 'core/ajax', 'core/templates'], function($, notification, ajax, templates) { + + /** + * Info + * + * @param {JQuery} Selector to replace when the information needs updating. + * @param {Number} The id of the competency. + * @param {Number} The id of the user. + * @param {Number} The id of the plan. + */ + var Info = function(rootElement, competencyId, userId, planId) { + this._rootElement = rootElement; + this._competencyId = competencyId; + this._userId = userId; + this._planId = planId; + }; + + /** + * Reload the info for this user competency. + * + * @method reload + */ + Info.prototype.reload = function() { + var self = this, + promises = []; + + promises = ajax.call([{ + methodname: 'tool_lp_read_user_competency_summary', + args: { userid: this._userId, competencyid: this._competencyId, planid: this._planId } + }]); + + promises[0].done(function(context) { + templates.render('tool_lp/user_competency_info', context).done(function(html, js) { + templates.replaceNode(self._rootElement, html, js); + }).fail(notification.exception); + }).fail(notification.exception); + }; + + /** @type {JQuery} The root element to replace in the DOM. */ + Info.prototype._rootElement = null; + /** @type {Number} The id of the plan. */ + Info.prototype._planId = null; + /** @type {Number} The id of the competency. */ + Info.prototype._competencyId = null; + /** @type {Number} The id of the user. */ + Info.prototype._userId = null; + + return /** @alias module:tool_lp/grade_user_competency_inline */ Info; + +}); diff --git a/admin/tool/lp/classes/api.php b/admin/tool/lp/classes/api.php index d9dca79e179..e0f6ff8716d 100644 --- a/admin/tool/lp/classes/api.php +++ b/admin/tool/lp/classes/api.php @@ -2387,6 +2387,40 @@ class api { } } + /** + * List all the evidence for a user competency + * + * @param int $usercompetencyid The user competency id - if 0, then userid and competencyid are used. + * @param int $userid The user id - only used if usercompetencyid is 0. + * @param int $competencyid The competency id - only used it usercompetencyid is 0. + * @return array of \tool_lp\evidence + */ + public static function list_evidence($usercompetencyid = 0, + $userid = 0, + $competencyid = 0, + $sort = 'timecreated', + $order = 'DESC', + $skip = 0, + $limit = 0) { + + if ($usercompetencyid > 0) { + $usercompetency = new user_competency($usercompetencyid); + + $context = context_user::instance($usercompetency->get_userid()); + require_capability('tool/lp:planview', $context); + } else { + $context = context_user::instance($userid); + require_capability('tool/lp:planview', $context); + + $usercompetency = user_competency::get_record(array('userid' => $userid, 'competencyid' => $competencyid)); + if (!$usercompetency) { + return array(); + } + } + + return evidence::get_records(array('usercompetencyid' => $usercompetency->get_id()), $sort, $order, $skip, $limit); + } + /** * Create an evidence from a list of parameters. * @@ -2683,4 +2717,76 @@ class api { ); } } + + /** + * Returns a user competency data. + * + * @param int $userid + * @param array of int $competencyids + * @return array of \tool_lp\user_competency + */ + public static function read_user_competencies($userid, $competencyids) { + $context = context_user::instance($userid); + require_capability('tool/lp:planview', $context); + + return user_competency::get_multiple($userid, $competencyids); + } + + /** + * Manually grade a user competency from the plans page. + * + * @param int $userid + * @param int $competencyid + * @param int $planid + * @param int $grade + * @param boolean $override + * @return array of \tool_lp\user_competency + */ + public static function grade_competency_in_plan($userid, $competencyid, $planid, $grade, $override) { + global $USER; + $context = context_user::instance($userid); + if ($override) { + require_capability('tool/lp:competencygrade', $context); + } else { + require_capability('tool/lp:competencysuggestgrade', $context); + } + + // Verify the data. + + $plan = new plan($planid); + if ($plan->get_userid() != $userid) { + throw new coding_exception('The plan does not belong to this user: ' . $planid . ', ' . $userid); + } + + $userplancompetencies = self::list_plan_competencies($plan); + $competency = null; + + foreach ($userplancompetencies as $userplancompetency) { + if ($userplancompetency->competency->get_id() == $competencyid) { + $competency = $userplancompetency->competency; + } + } + if (!$competency) { + throw new coding_exception('The competency does not belong to this plan: ' . $competencyid . ', ' . $planid); + } + + $action = evidence::ACTION_OVERRIDE; + $desckey = 'evidence_manualoverrideinplan'; + if (!$override) { + $action = evidence::ACTION_SUGGEST; + $desckey = 'evidence_manualsuggestinplan'; + } + + return self::add_evidence($userid, + $competency, + $context->id, + $action, + $desckey, + 'tool_lp', + $plan->get_name(), + false, + null, + $grade, + $USER->id); + } } diff --git a/admin/tool/lp/classes/external.php b/admin/tool/lp/classes/external.php index e926ffd3274..4829b97c0dc 100644 --- a/admin/tool/lp/classes/external.php +++ b/admin/tool/lp/classes/external.php @@ -47,6 +47,7 @@ use tool_lp\external\cohort_summary_exporter; use tool_lp\external\user_summary_exporter; use tool_lp\external\user_competency_exporter; use tool_lp\external\user_competency_plan_exporter; +use tool_lp\external\user_competency_summary_exporter; use tool_lp\external\user_evidence_exporter; use tool_lp\external\user_evidence_competency_exporter; use tool_lp\external\competency_exporter; @@ -54,6 +55,7 @@ use tool_lp\external\course_competency_exporter; use tool_lp\external\course_summary_exporter; use tool_lp\external\plan_exporter; use tool_lp\external\template_exporter; +use tool_lp\external\evidence_exporter; /** * This is the external API for this tool. @@ -3546,8 +3548,7 @@ class external extends external_api { // The following section is not learning plan specific and so has not been moved to the api. // Retrieve the scale value from the database. $scale = grade_scale::fetch(array('id' => $scaleid)); - // Reverse the array so that high levels are at the top. - $scalevalues = array_reverse($scale->load_items()); + $scalevalues = $scale->load_items(); foreach ($scalevalues as $key => $value) { // Add a key (make the first value 1). $scalevalues[$key] = array( @@ -4115,4 +4116,187 @@ class external extends external_api { return new external_value(PARAM_BOOL, 'True if the update was successful'); } + /** + * Returns description of grade_competency_in_plan() parameters. + * + * @return \external_function_parameters + */ + public static function grade_competency_in_plan_parameters() { + $userid = new external_value( + PARAM_INT, + 'User id', + VALUE_REQUIRED + ); + $competencyid = new external_value( + PARAM_INT, + 'Competency id', + VALUE_REQUIRED + ); + $planid = new external_value( + PARAM_INT, + 'Plan id', + VALUE_REQUIRED + ); + $grade = new external_value( + PARAM_INT, + 'New grade', + VALUE_REQUIRED + ); + $override = new external_value( + PARAM_BOOL, + 'Override the grade, or just suggest it', + VALUE_REQUIRED + ); + + $params = array( + 'userid' => $userid, + 'competencyid' => $competencyid, + 'planid' => $planid, + 'grade' => $grade, + 'override' => $override + ); + return new external_function_parameters($params); + } + + /** + * Grade a competency in a plan. + * + * @param int $userid The user id + * @param int $competencyid The competency id + * @param int $planid The plan id + * @param int $grade The new grade value + * @param bool $override Override the grade or only suggest it + * @return bool + */ + public static function grade_competency_in_plan($userid, $competencyid, $planid, $grade, $override) { + global $USER, $PAGE; + + $params = self::validate_parameters(self::grade_competency_in_plan_parameters(), + array( + 'userid' => $userid, + 'competencyid' => $competencyid, + 'planid' => $planid, + 'grade' => $grade, + 'override' => $override + )); + + self::validate_context(context_user::instance($params['userid'])); + $output = $PAGE->get_renderer('tool_lp'); + + $evidence = api::grade_competency_in_plan($params['userid'], $params['competencyid'], $params['planid'], $params['grade'], $params['override']); + $competency = api::read_competency($params['competencyid']); + $scale = $competency->get_scale(); + $exporter = new evidence_exporter($evidence, array('actionuser' => $USER, 'scale' => $scale)); + return $exporter->export($output); + } + + /** + * Returns description of grade_competency_in_plan() result value. + * + * @return \external_value + */ + public static function grade_competency_in_plan_returns() { + return evidence_exporter::get_read_structure(); + } + + /** + * Returns description of read_user_competency_summary() parameters. + * + * @return \external_function_parameters + */ + public static function read_user_competency_summary_parameters() { + $userid = new external_value( + PARAM_INT, + 'Data base record id for the user', + VALUE_REQUIRED + ); + $competencyid = new external_value( + PARAM_INT, + 'Data base record id for the competency', + VALUE_REQUIRED + ); + $planid = new external_value( + PARAM_INT, + 'Data base record id for the plan', + VALUE_DEFAULT, + 0 + ); + + $params = array( + 'userid' => $userid, + 'competencyid' => $competencyid, + 'planid' => $planid, + ); + return new external_function_parameters($params); + } + + /** + * Read a user competency summary. + * + * @param int $userid The user id + * @param int $competencyid The competency id + * @param int $planid The plan id + * @return \stdClass + */ + public static function read_user_competency_summary($userid, $competencyid, $planid) { + global $PAGE, $DB, $CFG; + require_once($CFG->dirroot . '/user/lib.php'); + + $params = self::validate_parameters(self::read_user_competency_summary_parameters(), + array( + 'userid' => $userid, + 'competencyid' => $competencyid, + 'planid' => $planid + )); + $context = context_user::instance($params['userid']); + self::validate_context($context); + $output = $PAGE->get_renderer('tool_lp'); + require_capability('tool/lp:planview', $context); + + $list = api::read_user_competencies($params['userid'], array($params['competencyid'])); + if ($list) { + $usercompetency = array_pop($list); + } else { + $record = (object)array('userid' => $params['userid'], 'competencyid' => $params['competencyid']); + $usercompetency = new user_competency(0, $record); + } + + $competency = $usercompetency->get_competency(); + $relatedcompetencies = api::list_related_competencies($competency->get_id()); + $userid = $usercompetency->get_userid(); + $user = (object) array('id' => $userid); + if (can_view_user_details_cap($user)) { + $user = $DB->get_record('user', array('id' => $userid)); + } else { + $user = null; + } + $plan = null; + if ($params['planid']) { + $plan = \tool_lp\api::read_plan($planid); + } + $evidence = api::list_evidence(0, $params['userid'], $params['competencyid']); + + $params = array( + 'competency' => $competency, + 'usercompetency' => $usercompetency, + 'evidence' => $evidence, + 'user' => $user, + 'plan' => $plan, + 'relatedcompetencies' => $relatedcompetencies + ); + $exporter = new user_competency_summary_exporter(null, $params); + $data = $exporter->export($output); + + return $data; + } + + /** + * Returns description of read_user_competency_summary() result value. + * + * @return \external_description + */ + public static function read_user_competency_summary_returns() { + return user_competency_summary_exporter::get_read_structure(); + } + } diff --git a/admin/tool/lp/classes/external/evidence_exporter.php b/admin/tool/lp/classes/external/evidence_exporter.php new file mode 100644 index 00000000000..54d11f813b0 --- /dev/null +++ b/admin/tool/lp/classes/external/evidence_exporter.php @@ -0,0 +1,83 @@ +. + +/** + * Class for exporting evidence data. + * + * @package tool_lp + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace tool_lp\external; + +use renderer_base; + +/** + * Class for exporting evidence data. + * + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class evidence_exporter extends persistent_exporter { + + protected static function define_related() { + return array('actionuser' => '\\stdClass?', + 'scale' => 'grade_scale'); + } + + protected static function define_class() { + return 'tool_lp\\evidence'; + } + + protected function get_other_values(renderer_base $output) { + $other = array(); + if ($this->related['actionuser']) { + $exporter = new user_summary_exporter($this->related['actionuser']); + $actionuser = $exporter->export($output); + $other['actionuser'] = $actionuser; + } + $other['description'] = $this->persistent->get_description(); + + $other['userdate'] = userdate($this->persistent->get_timecreated()); + + if ($this->persistent->get_grade() === null) { + $gradename = '-'; + } else { + $gradename = $this->related['scale']->scale_items[$this->persistent->get_grade() - 1]; + } + $other['gradename'] = $gradename; + + return $other; + } + + public static function define_other_properties() { + return array( + 'actionuser' => array( + 'type' => user_summary_exporter::read_properties_definition(), + 'optional' => true + ), + 'description' => array( + 'type' => PARAM_TEXT, + ), + 'gradename' => array( + 'type' => PARAM_TEXT, + ), + 'userdate' => array( + 'type' => PARAM_TEXT + ) + ); + } +} diff --git a/admin/tool/lp/classes/external/user_competency_exporter.php b/admin/tool/lp/classes/external/user_competency_exporter.php index 132a914c6b4..64836124d14 100644 --- a/admin/tool/lp/classes/external/user_competency_exporter.php +++ b/admin/tool/lp/classes/external/user_competency_exporter.php @@ -56,7 +56,7 @@ class user_competency_exporter extends persistent_exporter { $result->gradename = $gradename; if ($this->persistent->get_proficiency() === null) { - $proficiencyname = '-'; + $proficiencyname = get_string('no'); } else { $proficiencyname = get_string($this->persistent->get_proficiency() ? 'yes' : 'no'); } diff --git a/admin/tool/lp/classes/external/user_competency_plan_exporter.php b/admin/tool/lp/classes/external/user_competency_plan_exporter.php index ae413aff6ed..ecae6072143 100644 --- a/admin/tool/lp/classes/external/user_competency_plan_exporter.php +++ b/admin/tool/lp/classes/external/user_competency_plan_exporter.php @@ -55,7 +55,7 @@ class user_competency_plan_exporter extends persistent_exporter { $result->gradename = $gradename; if ($this->persistent->get_proficiency() === null) { - $proficiencyname = '-'; + $proficiencyname = get_string('no'); } else { $proficiencyname = get_string($this->persistent->get_proficiency() ? 'yes' : 'no'); } diff --git a/admin/tool/lp/classes/external/user_competency_summary_exporter.php b/admin/tool/lp/classes/external/user_competency_summary_exporter.php new file mode 100644 index 00000000000..dea6c1269b8 --- /dev/null +++ b/admin/tool/lp/classes/external/user_competency_summary_exporter.php @@ -0,0 +1,153 @@ +. + +/** + * Class for exporting user competency data with all the evidence + * + * @package tool_lp + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace tool_lp\external; + +use context_user; +use renderer_base; +use stdClass; + +/** + * Class for exporting user competency data with additional related data. + * + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_competency_summary_exporter extends exporter { + + protected static function define_related() { + // We cache the context so it does not need to be retrieved from the framework every time. + return array('competency' => '\\tool_lp\\competency', + 'relatedcompetencies' => '\\tool_lp\\competency[]', + 'user' => '\\stdClass?', + 'plan' => '\\tool_lp\\plan?', + 'usercompetency' => '\\tool_lp\\user_competency', + 'evidence' => '\\tool_lp\\evidence[]'); + } + + protected static function define_other_properties() { + return array( + 'showrelatedcompetencies' => array( + 'type' => PARAM_BOOL + ), + 'cangrade' => array( + 'type' => PARAM_BOOL + ), + 'cansuggest' => array( + 'type' => PARAM_BOOL + ), + 'cangradeorsuggest' => array( + 'type' => PARAM_BOOL + ), + 'competency' => array( + 'type' => competency_summary_exporter::read_properties_definition() + ), + 'user' => array( + 'type' => user_summary_exporter::read_properties_definition(), + 'optional' => true + ), + 'plan' => array( + 'type' => plan_exporter::read_properties_definition(), + 'optional' => true + ), + 'usercompetency' => array( + 'type' => user_competency_exporter::read_properties_definition() + ), + 'evidence' => array( + 'type' => evidence_exporter::read_properties_definition(), + 'multiple' => true + ) + ); + } + + protected function get_other_values(renderer_base $output) { + global $DB; + $result = new stdClass(); + $result->showrelatedcompetencies = true; + + $competency = $this->related['competency']; + $exporter = new competency_summary_exporter(null, array( + 'competency' => $competency, + 'context' => $competency->get_context(), + 'framework' => $competency->get_framework(), + 'linkedcourses' => array(), + 'relatedcompetencies' => $this->related['relatedcompetencies'] + )); + $result->competency = $exporter->export($output); + $context = context_user::instance($this->related['usercompetency']->get_userid()); + $result->cangrade = has_capability('tool/lp:competencygrade', $context); + $result->cansuggest = has_capability('tool/lp:competencysuggestgrade', $context); + $result->cangradeorsuggest = $result->cangrade || $result->cansuggest; + if ($this->related['user']) { + $exporter = new user_summary_exporter($this->related['user']); + $result->user = $exporter->export($output); + } + $exporter = new user_competency_exporter($this->related['usercompetency'], array('scale' => $competency->get_scale())); + $result->usercompetency = $exporter->export($output); + + if ($this->related['plan']) { + $exporter = new plan_exporter($this->related['plan'], array('template' => $this->related['plan']->get_template())); + $result->plan = $exporter->export($output); + } + + $allevidence = array(); + $usercache = array(); + $scale = $competency->get_scale(); + + $result->evidence = array(); + if (count($this->related['evidence'])) { + foreach ($this->related['evidence'] as $evidence) { + if (!empty($evidence->get_actionuserid())) { + $usercache[$evidence->get_actionuserid()] = true; + } + } + $users = array(); + if (!empty($usercache)) { + list($sql, $params) = $DB->get_in_or_equal(array_keys($usercache)); + $users = $DB->get_records_select('user', 'id ' . $sql, $params); + } + + foreach ($users as $user) { + if (can_view_user_details_cap($user)) { + $usercache[$user->id] = $user; + } else { + unset($usercache[$user->id]); + } + } + + foreach ($this->related['evidence'] as $evidence) { + $related = array('scale' => $scale); + if (!empty($usercache[$evidence->get_actionuserid()])) { + $related['actionuser'] = $usercache[$evidence->get_actionuserid()]; + } else { + $related['actionuser'] = null; + } + $exporter = new evidence_exporter($evidence, $related); + $allevidence[] = $exporter->export($output); + } + $result->evidence = $allevidence; + } + + return (array) $result; + } +} diff --git a/admin/tool/lp/classes/external/user_summary_exporter.php b/admin/tool/lp/classes/external/user_summary_exporter.php index a784e4c34f5..cafae7a2320 100644 --- a/admin/tool/lp/classes/external/user_summary_exporter.php +++ b/admin/tool/lp/classes/external/user_summary_exporter.php @@ -36,7 +36,7 @@ use moodle_url; class user_summary_exporter extends exporter { protected function get_other_values(renderer_base $output) { - global $PAGE; + global $PAGE, $CFG; // Add user picture. $userpicture = new \user_picture($this->data); @@ -45,10 +45,22 @@ class user_summary_exporter extends exporter { $userpicture->size = 0; // Size f2. $profileimageurlsmall = $userpicture->get_url($PAGE)->out(false); + $identityfields = array_flip(explode(',', $CFG->showuseridentity)); + $identity = ''; + $data = $this->data; + foreach ($identityfields as $field => $index) { + if (!empty($data->$field)) { + $identityfields[$field] = $data->$field; + } else { + unset($identityfields[$field]); + } + } + $identity = implode(', ', $identityfields); return array( 'fullname' => fullname($this->data), 'profileimageurl' => $profileimageurl, - 'profileimageurlsmall' => $profileimageurlsmall + 'profileimageurlsmall' => $profileimageurlsmall, + 'identity' => $identity ); } @@ -89,6 +101,9 @@ class user_summary_exporter extends exporter { 'fullname' => array( 'type' => PARAM_TEXT ), + 'identity' => array( + 'type' => PARAM_TEXT + ), 'profileimageurl' => array( 'type' => PARAM_URL ), diff --git a/admin/tool/lp/classes/output/plan_page.php b/admin/tool/lp/classes/output/plan_page.php index ab805038f13..1359ceeeaca 100644 --- a/admin/tool/lp/classes/output/plan_page.php +++ b/admin/tool/lp/classes/output/plan_page.php @@ -24,10 +24,10 @@ namespace tool_lp\output; defined('MOODLE_INTERNAL') || die(); -use moodle_url; use renderable; use templatable; use stdClass; +use moodle_url; use tool_lp\api; use tool_lp\plan; use tool_lp\external\competency_exporter; diff --git a/admin/tool/lp/classes/output/renderer.php b/admin/tool/lp/classes/output/renderer.php index 12cce40c1d0..def397808a7 100644 --- a/admin/tool/lp/classes/output/renderer.php +++ b/admin/tool/lp/classes/output/renderer.php @@ -131,6 +131,17 @@ class renderer extends plugin_renderer_base { return parent::render_from_template('tool_lp/related_competencies', $data); } + /** + * Defer to template. + * + * @param renderable $page + * @return string + */ + public function render_user_competency_plan_page(user_competency_plan_page $page) { + $data = $page->export_for_template($this); + return parent::render_from_template('tool_lp/user_competency_info', $data); + } + /** * Render the template plans page. * diff --git a/admin/tool/lp/classes/output/user_competency_plan_page.php b/admin/tool/lp/classes/output/user_competency_plan_page.php new file mode 100644 index 00000000000..b35bac88e3b --- /dev/null +++ b/admin/tool/lp/classes/output/user_competency_plan_page.php @@ -0,0 +1,74 @@ +. + +/** + * User competency page class. + * + * @package tool_lp + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +namespace tool_lp\output; + +use renderable; +use context_user; +use templatable; +use stdClass; +use tool_lp\api; +use tool_lp\external\user_competency_summary_exporter; +use tool_lp\external\plan_exporter; + +/** + * User competency page class. + * + * @package tool_lp + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class user_competency_plan_page implements renderable, templatable { + + /** @var userid */ + protected $userid; + + /** @var competencyid */ + protected $competencyid; + + /** @var planid */ + protected $planid; + + /** + * Construct. + * + * @param $userid + * @param $competencyid + * @param $planid + */ + public function __construct($userid, $competencyid, $planid) { + $this->userid = $userid; + $this->competencyid = $competencyid; + $this->planid = $planid; + } + + /** + * Export the data. + * + * @param renderer_base $output + * @return stdClass + */ + public function export_for_template(\renderer_base $output) { + return \tool_lp\external::read_user_competency_summary($this->userid, $this->competencyid, $this->planid); + } +} diff --git a/admin/tool/lp/db/access.php b/admin/tool/lp/db/access.php index 44c6b05770d..ae61d6cbaaa 100644 --- a/admin/tool/lp/db/access.php +++ b/admin/tool/lp/db/access.php @@ -155,4 +155,19 @@ $capabilities = array( ), 'clonepermissionsfrom' => 'moodle/site:config' ), + 'tool/lp:competencysuggestgrade' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, // And CONTEXT_USER. + 'archetypes' => array( + 'teacher' => CAP_ALLOW + ), + ), + 'tool/lp:competencygrade' => array( + 'captype' => 'write', + 'contextlevel' => CONTEXT_COURSE, // And CONTEXT_USER. + 'archetypes' => array( + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ), + ), ); diff --git a/admin/tool/lp/db/services.php b/admin/tool/lp/db/services.php index 15183426922..f62df78681e 100644 --- a/admin/tool/lp/db/services.php +++ b/admin/tool/lp/db/services.php @@ -662,5 +662,24 @@ $functions = array( 'capabilities' => 'tool/lp:userevidencemanageown', 'ajax' => true, ), + + 'tool_lp_grade_competency_in_plan' => array( + 'classname' => 'tool_lp\external', + 'methodname' => 'grade_competency_in_plan', + 'classpath' => '', + 'description' => 'Grade a competency from the user plan page.', + 'type' => 'write', + 'capabilities' => 'tool/lp:competencygrade', + 'ajax' => true, + ), + 'tool_lp_read_user_competency_summary' => array( + 'classname' => 'tool_lp\external', + 'methodname' => 'read_user_competency_summary', + 'classpath' => '', + 'description' => 'Load a summary of a user competency.', + 'type' => 'read', + 'capabilities' => 'tool/lp:planview', + 'ajax' => true, + ), ); diff --git a/admin/tool/lp/lang/en/tool_lp.php b/admin/tool/lp/lang/en/tool_lp.php index f307e62e208..b1363189d21 100644 --- a/admin/tool/lp/lang/en/tool_lp.php +++ b/admin/tool/lp/lang/en/tool_lp.php @@ -89,6 +89,8 @@ $string['evidence_competencyrule'] = 'The rule of the competency was met.'; $string['evidence_coursecompleted'] = 'The course \'{$a}\' was completed.'; $string['evidence_evidenceofpriorlearninglinked'] = 'The evidence of prior learning \'{$a}\' was linked.'; $string['evidence_evidenceofpriorlearningunlinked'] = 'The evidence of prior learning \'{$a}\' was unlinked.'; +$string['evidence_manualoverrideinplan'] = 'The competency grade was manually set in the plan \'{$a}\'.'; +$string['evidence_manualsuggestinplan'] = 'The competency grade was manually suggested in the plan \'{$a}\'.'; $string['errorcannotsetduedateinthepast'] = 'The due date cannot be set in the past.'; $string['errorcannotchangeapastduedate'] = 'The due date has passed, it cannot be changed.'; $string['errornocompetency'] = '{$a} competency can not be found'; @@ -122,6 +124,8 @@ $string['listtemplatescaption'] = 'List of learning plan templates'; $string['loading'] = 'Loading...'; $string['locatecompetency'] = 'Locate competency'; $string['lp:competencymanage'] = 'Manage competency frameworks'; +$string['lp:competencysuggestgrade'] = 'Suggest competency grade'; +$string['lp:competencygrade'] = 'Set competency grade'; $string['lp:competencyread'] = 'View competency frameworks'; $string['lp:coursecompetencymanage'] = 'Manage course competencies'; $string['lp:coursecompetencyread'] = 'View course competencies'; @@ -275,3 +279,7 @@ $string['userplans'] = 'User plans'; $string['visible'] = 'Visible'; $string['visible_help'] = 'A competency framework can be hidden from teachers. This could be useful if a framework is still in the process of being developed.'; $string['when'] = 'When'; +$string['noevidence'] = 'No evidence'; +$string['evidence'] = 'Evidence'; +$string['grade'] = 'Grade'; +$string['suggest'] = 'Suggest'; diff --git a/admin/tool/lp/templates/evidence_summary.mustache b/admin/tool/lp/templates/evidence_summary.mustache new file mode 100644 index 00000000000..d017a6590fc --- /dev/null +++ b/admin/tool/lp/templates/evidence_summary.mustache @@ -0,0 +1,15 @@ +
+{{#actionuser}} +
+{{> tool_lp/form-user-selector-suggestion }} +
+{{/actionuser}} + +{{#grade}} +

{{gradename}}

+{{/grade}} +

{{description}}

+{{#url}} +

{{url}}

+{{/url}} +
diff --git a/admin/tool/lp/templates/grade_user_competency_form.mustache b/admin/tool/lp/templates/grade_user_competency_form.mustache new file mode 100644 index 00000000000..82cce24f140 --- /dev/null +++ b/admin/tool/lp/templates/grade_user_competency_form.mustache @@ -0,0 +1,31 @@ +
+{{#cangrade}} +
+ +{{/cangrade}} +{{#cansuggest}} + +{{/cansuggest}} +
+ + +
+{{#js}} +require(['jquery', 'tool_lp/grade_user_competency_inline', 'tool_lp/user_competency_info'], function($, mod, info) { + var competencyScaleConfig = '{{{competency.competency.scaleconfiguration}}}'; + var frameworkScaleConfig = '{{{competency.framework.scaleconfiguration}}}'; + var scaleConfig = frameworkScaleConfig; + {{#competency.competency.scaleid}} + scaleConfig = competencyScaleConfig; + {{/competency.competency.scaleid}} + scaleConfig = JSON.parse(scaleConfig); + + var inlineGrader = new mod('grade-competency-form-{{uniqid}}', scaleConfig, '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}'); + var competencyElement = $(document.getElementById('grade-competency-form-{{uniqid}}')).closest('[data-region=user-competency-full-info]'); + var infoReloader = new info(competencyElement, '{{competency.competency.id}}', '{{user.id}}', '{{plan.id}}'); + + inlineGrader.on('competencyupdated', infoReloader.reload.bind(infoReloader)); +}); + +{{/js}} diff --git a/admin/tool/lp/templates/plan_page.mustache b/admin/tool/lp/templates/plan_page.mustache index b686c857819..7581fcfd028 100644 --- a/admin/tool/lp/templates/plan_page.mustache +++ b/admin/tool/lp/templates/plan_page.mustache @@ -79,7 +79,7 @@ {{#plan.canbeedited}} {{/plan.canbeedited}} - {{competency.shortname}} + {{competency.shortname}} {{competency.idnumber}} {{#plan.iscompleted}} diff --git a/admin/tool/lp/templates/user_competency_info.mustache b/admin/tool/lp/templates/user_competency_info.mustache new file mode 100644 index 00000000000..543fbd7fc7c --- /dev/null +++ b/admin/tool/lp/templates/user_competency_info.mustache @@ -0,0 +1,31 @@ +
+
+{{#competency}} +{{> tool_lp/competency_summary }} +{{/competency}} +
+
{{#str}}grade, tool_lp{{/str}}
+
{{usercompetency.gradename}}
+{{#cangradeorsuggest}} +
{{#str}}editgrade, grades{{/str}}
+
{{> tool_lp/grade_user_competency_form }}
+{{/cangradeorsuggest}} +
{{#str}}proficient, tool_lp{{/str}}
+
+ +{{usercompetency.proficiencyname}} + +
+
+
+
{{#str}}evidence, tool_lp{{/str}}
+
+{{#evidence}} +{{> tool_lp/evidence_summary }} +{{/evidence}} +{{^evidence}} +

{{#str}}noevidence, tool_lp{{/str}}

+{{/evidence}} +
+
+
diff --git a/admin/tool/lp/tests/api_test.php b/admin/tool/lp/tests/api_test.php index c2ee6c64c91..d250df616ad 100644 --- a/admin/tool/lp/tests/api_test.php +++ b/admin/tool/lp/tests/api_test.php @@ -1721,7 +1721,6 @@ class tool_lp_api_testcase extends advanced_testcase { $usercompetency->create(); $this->assertTrue(true); } catch (\tool_lp\invalid_persistent_exception $e) { - var_dump($e); $this->fail('Valide grade rejected in competency scale'); } } diff --git a/admin/tool/lp/tests/externallib_test.php b/admin/tool/lp/tests/externallib_test.php index ed181535f6a..5e2373e0b37 100644 --- a/admin/tool/lp/tests/externallib_test.php +++ b/admin/tool/lp/tests/externallib_test.php @@ -100,12 +100,17 @@ class tool_lp_external_testcase extends externallib_advanced_testcase { $authrole = array_pop($userroles); // Reset all default authenticated users permissions. + unassign_capability('tool/lp:competencygrade', $authrole->id); + unassign_capability('tool/lp:competencysuggestgrade', $authrole->id); unassign_capability('tool/lp:competencymanage', $authrole->id); unassign_capability('tool/lp:competencyread', $authrole->id); unassign_capability('tool/lp:planmanage', $authrole->id); unassign_capability('tool/lp:planmanagedraft', $authrole->id); unassign_capability('tool/lp:planmanageown', $authrole->id); unassign_capability('tool/lp:planview', $authrole->id); + unassign_capability('tool/lp:planviewdraft', $authrole->id); + unassign_capability('tool/lp:planviewown', $authrole->id); + unassign_capability('tool/lp:planviewowndraft', $authrole->id); unassign_capability('tool/lp:templatemanage', $authrole->id); unassign_capability('tool/lp:templateread', $authrole->id); @@ -119,8 +124,14 @@ class tool_lp_external_testcase extends externallib_advanced_testcase { assign_capability('tool/lp:planmanagedraft', CAP_ALLOW, $this->creatorrole, $syscontext->id); assign_capability('tool/lp:planmanageown', CAP_ALLOW, $this->creatorrole, $syscontext->id); assign_capability('tool/lp:planview', CAP_ALLOW, $this->creatorrole, $syscontext->id); + assign_capability('tool/lp:planviewdraft', CAP_ALLOW, $this->creatorrole, $syscontext->id); assign_capability('tool/lp:templatemanage', CAP_ALLOW, $this->creatorrole, $syscontext->id); + assign_capability('tool/lp:competencygrade', CAP_ALLOW, $this->creatorrole, $syscontext->id); + assign_capability('tool/lp:competencysuggestgrade', CAP_ALLOW, $this->creatorrole, $syscontext->id); assign_capability('tool/lp:templateread', CAP_ALLOW, $this->userrole, $syscontext->id); + assign_capability('tool/lp:competencysuggestgrade', CAP_ALLOW, $this->userrole, $syscontext->id); + assign_capability('tool/lp:planviewown', CAP_ALLOW, $this->userrole, $syscontext->id); + assign_capability('tool/lp:planviewowndraft', CAP_ALLOW, $this->userrole, $syscontext->id); role_assign($this->creatorrole, $creator->id, $syscontext->id); role_assign($this->creatorrole, $catcreator->id, $catcontext->id); @@ -1606,19 +1617,19 @@ class tool_lp_external_testcase extends externallib_advanced_testcase { // Expected return value. $expected = array(array( 'id' => 1, - 'name' => 'Excellent' + 'name' => 'Poor' ), array( 'id' => 2, - 'name' => 'Fine' + 'name' => 'Not good' ), array( 'id' => 3, 'name' => 'Okay' ), array( 'id' => 4, - 'name' => 'Not good' + 'name' => 'Fine' ), array( 'id' => 5, - 'name' => 'Poor' + 'name' => 'Excellent' ) ); // Call the webservice. @@ -2608,4 +2619,72 @@ class tool_lp_external_testcase extends externallib_advanced_testcase { $this->assertEmpty($result['users'][0]['institution']); } + public function test_grade_competency_in_plan() { + global $CFG; + + $this->setUser($this->creator); + + $dg = $this->getDataGenerator(); + $lpg = $dg->get_plugin_generator('tool_lp'); + + $f1 = $lpg->create_framework(); + + $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id())); + + $tpl = $lpg->create_template(); + $lpg->create_template_competency(array('templateid' => $tpl->get_id(), 'competencyid' => $c1->get_id())); + + $plan = $lpg->create_plan(array('userid' => $this->user->id, 'templateid' => $tpl->get_id(), 'name' => 'Evil')); + + $uc = $lpg->create_user_competency(array('userid' => $this->user->id, 'competencyid' => $c1->get_id())); + + $evidence = external::grade_competency_in_plan($this->user->id, $c1->get_id(), $plan->get_id(), 1, false); + + $this->assertEquals('The competency grade was manually suggested in the plan \'Evil\'.', $evidence->description); + $this->assertEquals('A', $evidence->gradename); + $evidence = external::grade_competency_in_plan($this->user->id, $c1->get_id(), $plan->get_id(), 1, true); + + $this->assertEquals('The competency grade was manually set in the plan \'Evil\'.', $evidence->description); + $this->assertEquals('A', $evidence->gradename); + + $this->setUser($this->user); + $evidence = external::grade_competency_in_plan($this->user->id, $c1->get_id(), $plan->get_id(), 1, false); + $this->assertEquals('The competency grade was manually suggested in the plan \'Evil\'.', $evidence->description); + $this->assertEquals('A', $evidence->gradename); + + $this->setExpectedException('required_capability_exception'); + $evidence = external::grade_competency_in_plan($this->user->id, $c1->get_id(), $plan->get_id(), 1, true); + } + + public function test_read_user_competency_summary() { + global $CFG; + + $this->setUser($this->creator); + + $dg = $this->getDataGenerator(); + $lpg = $dg->get_plugin_generator('tool_lp'); + + $f1 = $lpg->create_framework(); + + $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id())); + + $tpl = $lpg->create_template(); + $lpg->create_template_competency(array('templateid' => $tpl->get_id(), 'competencyid' => $c1->get_id())); + + $plan = $lpg->create_plan(array('userid' => $this->user->id, 'templateid' => $tpl->get_id(), 'name' => 'Evil')); + + $uc = $lpg->create_user_competency(array('userid' => $this->user->id, 'competencyid' => $c1->get_id())); + + $evidence = external::grade_competency_in_plan($this->user->id, $c1->get_id(), $plan->get_id(), 1, false); + $evidence = external::grade_competency_in_plan($this->user->id, $c1->get_id(), $plan->get_id(), 2, true); + + $summary = external::read_user_competency_summary($this->user->id, $c1->get_id(), $plan->get_id()); + $this->assertTrue($summary->cangrade); + $this->assertTrue($summary->cansuggest); + $this->assertEquals('Evil', $summary->plan->name); + $this->assertEquals('B', $summary->usercompetency->gradename); + $this->assertEquals('B', $summary->evidence[0]->gradename); + $this->assertEquals('A', $summary->evidence[1]->gradename); + } + } diff --git a/admin/tool/lp/usercompetencyplan.php b/admin/tool/lp/usercompetencyplan.php new file mode 100644 index 00000000000..62f2d77b393 --- /dev/null +++ b/admin/tool/lp/usercompetencyplan.php @@ -0,0 +1,59 @@ +. + +/** + * User competency page. Lists everything known about a user competency. + * + * @package tool_lp + * @copyright 2015 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require(__DIR__ . '/../../../config.php'); + +$userid = required_param('userid', PARAM_INT); +$competencyid = required_param('competencyid', PARAM_INT); +$planid = required_param('planid', PARAM_INT); + +require_login(null, false); +if (isguestuser()) { + throw new require_login_exception('Guests are not allowed here.'); +} + +$params = array('userid' => $userid, 'competencyid' => $competencyid); +$params['planid'] = $planid; +$plan = \tool_lp\api::read_plan($planid); +$url = new moodle_url('/admin/tool/lp/usercompetencyplan.php', $params); +$competency = new \tool_lp\competency($competencyid); +$framework = $competency->get_framework(); +$subtitle = get_string('taxonomy_' . $framework->get_taxonomy($competency->get_level()), 'tool_lp'); + +list($title, $subtitle) = \tool_lp\page_helper::setup_for_plan($userid, $url, $plan, + $subtitle); + +$output = $PAGE->get_renderer('tool_lp'); +echo $output->header(); +if ($userid != $USER->id) { + echo $output->context_header($userid); +} else { + echo $output->heading($title); + echo $output->heading($subtitle, 3); +} + +$page = new \tool_lp\output\user_competency_plan_page($userid, $competencyid, $planid); +echo $output->render($page); + +echo $output->footer(); diff --git a/user/lib.php b/user/lib.php index a063ea363a7..e15adda99de 100644 --- a/user/lib.php +++ b/user/lib.php @@ -22,6 +22,8 @@ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ +require_once($CFG->libdir . "/externallib.php"); + /** * Creates a user