From f0da26a4943067644352fb459b9d7f3b371be0cf Mon Sep 17 00:00:00 2001 From: Frederic Massart Date: Thu, 17 Sep 2015 20:40:02 +0800 Subject: [PATCH] MDL-51031 tool_lp: Templates can be created on a category level --- admin/tool/lp/amd/build/competencies.min.js | 2 +- admin/tool/lp/amd/build/templatedelete.min.js | 2 +- admin/tool/lp/amd/src/competencies.js | 4 +- admin/tool/lp/amd/src/templatedelete.js | 19 ++- admin/tool/lp/classes/api.php | 112 +++++++++----- admin/tool/lp/classes/external.php | 146 ++++++++++++------ admin/tool/lp/classes/form/template.php | 6 +- .../classes/output/manage_templates_page.php | 25 +-- .../output/template_competencies_page.php | 18 ++- admin/tool/lp/classes/template.php | 27 +++- admin/tool/lp/db/access.php | 4 +- admin/tool/lp/db/install.xml | 3 +- admin/tool/lp/db/upgrade.php | 19 ++- admin/tool/lp/edittemplate.php | 34 +++- admin/tool/lp/learningplans.php | 14 +- admin/tool/lp/settings.php | 4 +- admin/tool/lp/templatecompetencies.php | 20 ++- .../templates/manage_templates_page.mustache | 9 +- .../template_competencies_page.mustache | 2 +- admin/tool/lp/tests/api_test.php | 76 ++++++++- admin/tool/lp/tests/externallib_test.php | 9 +- admin/tool/lp/version.php | 2 +- 22 files changed, 412 insertions(+), 145 deletions(-) diff --git a/admin/tool/lp/amd/build/competencies.min.js b/admin/tool/lp/amd/build/competencies.min.js index 1ad14cc4273..2044d43abe3 100644 --- a/admin/tool/lp/amd/build/competencies.min.js +++ b/admin/tool/lp/amd/build/competencies.min.js @@ -1 +1 @@ -define(["jquery","core/notification","core/ajax","core/templates","tool_lp/dialogue","core/str","tool_lp/tree","tool_lp/dragdrop-reorder"],function(a,b,c,d,e,f,g,h){var i=function(e,f,g){this.itemid=e,this.itemtype=f,this.pageContextId=g,this.selectedCompetency=0;var h=this,i=c.call([{methodname:"tool_lp_list_competency_frameworks",args:{sort:"shortname",context:{contextid:this.pageContextId},includes:"parents"}}]);i[0].done(function(c){return h.frameworks=c,0===c.length?void d.render("tool_lp/no_frameworks_warning",{}).done(function(b){a('[data-region="actions"]').append(b),a('[data-region="actions"] button').hide()}).fail(b.exception):(a('[data-region="actions"] button').show(),h.registerEvents(),void h.registerDragDrop())}).fail(b.exception)};return i.prototype.registerDragDrop=function(){var a=this;f.get_string("movecompetency","tool_lp").done(function(b){h.dragdrop("movecompetency",b,{identifier:"movecompetency",component:"tool_lp"},{identifier:"movecompetencyafter",component:"tool_lp"},"drag-samenode","drag-parentnode","drag-handlecontainer",function(b,c){a.handleDrop.call(a,b,c)})}).fail(b.exception)},i.prototype.handleDrop=function(d,e){var f=a(d).data("id"),g=a(e).data("id"),h=this,i=[];if("course"==h.itemtype)i=c.call([{methodname:"tool_lp_reorder_course_competency",args:{courseid:h.itemid,competencyidfrom:f,competencyidto:g}}]);else{if("template"!=h.itemtype)return null;i=c.call([{methodname:"tool_lp_reorder_template_competency",args:{templateid:h.itemid,competencyidfrom:f,competencyidto:g}}])}i[0].fail(b.exception)},i.prototype.applyFilter=function(c){c.preventDefault();var e=this,f=a('[data-region="filtercompetencies"] input'),g=f.val(),h=a('[data-action="chooseframework"]'),i=h.val();this.searchCompetencies().done(function(c){var f=0,h=e.frameworks[0];for(f=0;fget_context()); // OK - all set. - $template = new template(0, $record); $id = $template->create(); return $template; } @@ -763,35 +766,39 @@ class api { /** * Delete a learning plan template by id. * - * Requires tool/lp:templatemanage capability at the system context. + * Requires tool/lp:templatemanage capability. * * @param int $id The record to delete. * @return boolean */ public static function delete_template($id) { + $template = new template($id); + // First we do a permissions check. - require_capability('tool/lp:templatemanage', context_system::instance()); + require_capability('tool/lp:templatemanage', $template->get_context()); // OK - all set. - $template = new template(); - $template->set_id($id); return $template->delete(); } /** * Update the details for a learning plan template. * - * Requires tool/lp:templatemanage capability at the system context. + * Requires tool/lp:templatemanage capability. * * @param stdClass $record The new details for the template. Note - must contain an id that points to the template to update. * @return boolean */ public static function update_template($record) { - // First we do a permissions check. - require_capability('tool/lp:templatemanage', context_system::instance()); + $template = new template($record->id); - // OK - all set. - $template = new template(0, $record); + // First we do a permissions check. + require_capability('tool/lp:templatemanage', $template->get_context()); + if (isset($record->contextid) && $record->contextid != $template->get_contextid()) { + throw new coding_exception('Changing the context of an existing tempalte is forbidden.'); + } + + $template->from_record($record); return $template->update(); } @@ -804,15 +811,17 @@ class api { * @return template */ public static function read_template($id) { + $template = new template($id); + $context = $template->get_context(); + // First we do a permissions check. - $context = context_system::instance(); $caps = array('tool/lp:templateread', 'tool/lp:templatemanage'); if (!has_any_capability($caps, $context)) { throw new required_capability_exception($context, 'tool/lp:templateread', 'nopermissions', ''); } // OK - all set. - return new template($id); + return $template; } /** @@ -857,24 +866,40 @@ class api { * * Requires tool/lp:templateread capability at the system context. * - * @param array $filters A list of filters to apply to the list. * @param string $sort The column to sort on * @param string $order ('ASC' or 'DESC') * @param int $skip Number of records to skip (pagination) * @param int $limit Max of records to return (pagination) + * @param context $context The parent context of the frameworks. + * @param string $includes Defines what other contexts to fetch frameworks from. + * Accepted values are: + * - children: All descendants + * - parents: All parents, grand parents, etc... + * - self: Context passed only. * @return array of competency_framework */ - public static function list_templates($filters = array(), $sort = '', $order = 'ASC', $skip = 0, $limit = 0) { + public static function list_templates($sort, $order, $skip, $limit, $context, $includes = 'children') { + global $DB; + + // Get all the relevant contexts. + $contexts = self::get_related_contexts($context, $includes, + array('tool/lp:templateread', 'tool/lp:templatemanage')); + // First we do a permissions check. - $context = context_system::instance(); - $caps = array('tool/lp:templateread', 'tool/lp:templatemanage'); - if (!has_any_capability($caps, $context)) { + if (empty($contexts)) { throw new required_capability_exception($context, 'tool/lp:templateread', 'nopermissions', ''); } + // Make the order by. + $orderby = ''; + if (!empty($sort)) { + $orderby = $sort . ' ' . $order; + } + // OK - all set. $template = new template(); - return $template->get_records($filters, $sort, $order, $skip, $limit); + list($insql, $inparams) = $DB->get_in_or_equal(array_keys($contexts), SQL_PARAMS_NAMED); + return $template->get_records_select("contextid $insql", $inparams, $orderby, '*', $skip, $limit); } /** @@ -882,20 +907,29 @@ class api { * * Requires tool/lp:templateread capability at the system context. * - * @param array $filters A list of filters to apply to the list. + * @param context $context The parent context of the frameworks. + * @param string $includes Defines what other contexts to fetch frameworks from. + * Accepted values are: + * - children: All descendants + * - parents: All parents, grand parents, etc... + * - self: Context passed only. * @return int */ - public static function count_templates($filters) { + public static function count_templates($context, $includes) { + global $DB; + // First we do a permissions check. - $context = context_system::instance(); - $caps = array('tool/lp:templateread', 'tool/lp:templatemanage'); - if (!has_any_capability($caps, $context)) { + $contexts = self::get_related_contexts($context, $includes, + array('tool/lp:templateread', 'tool/lp:templatemanage')); + + if (empty($contexts)) { throw new required_capability_exception($context, 'tool/lp:templateread', 'nopermissions', ''); } // OK - all set. $template = new template(); - return $template->count_records($filters); + list($insql, $inparams) = $DB->get_in_or_equal(array_keys($contexts), SQL_PARAMS_NAMED); + return $template->count_records_select("contextid $insql", $inparams); } /** @@ -957,7 +991,8 @@ class api { */ public static function count_competencies_in_template($templateid) { // First we do a permissions check. - $context = context_system::instance(); + $template = new template($templateid); + $context = $template->get_context(); $onlyvisible = 1; $capabilities = array('tool/lp:templateread', 'tool/lp:templatemanage'); @@ -982,7 +1017,8 @@ class api { */ public static function list_competencies_in_template($templateid) { // First we do a permissions check. - $context = context_system::instance(); + $template = new template($templateid); + $context = $template->get_context(); $onlyvisible = 1; $capabilities = array('tool/lp:templateread', 'tool/lp:templatemanage'); @@ -1008,9 +1044,8 @@ class api { */ public static function add_competency_to_template($templateid, $competencyid) { // First we do a permissions check. - $context = context_system::instance(); - - require_capability('tool/lp:templatemanage', $context); + $template = new template($templateid); + require_capability('tool/lp:templatemanage', $template->get_context()); $record = new stdClass(); $record->templateid = $templateid; @@ -1042,15 +1077,14 @@ class api { */ public static function remove_competency_from_template($templateid, $competencyid) { // First we do a permissions check. - $context = context_system::instance(); - - require_capability('tool/lp:templatemanage', $context); + $template = new template($templateid); + require_capability('tool/lp:templatemanage', $template->get_context()); $record = new stdClass(); $record->templateid = $templateid; $record->competencyid = $competencyid; - $competency = new competency(); + $competency = new competency($competencyid); $competency->set_id($competencyid); if (!$competency->read()) { throw new coding_exception('The competency does not exist'); diff --git a/admin/tool/lp/classes/external.php b/admin/tool/lp/classes/external.php index 5afc2708fcc..b87e088aa88 100644 --- a/admin/tool/lp/classes/external.php +++ b/admin/tool/lp/classes/external.php @@ -2145,6 +2145,10 @@ class external extends external_api { PARAM_INT, 'User who modified this record last' ); + $contextid = new external_value( + PARAM_INT, + 'The context ID the template belongs to' + ); $returns = array( 'id' => $id, @@ -2158,6 +2162,7 @@ class external extends external_api { 'timecreated' => $timecreated, 'timemodified' => $timemodified, 'usermodified' => $usermodified, + 'contextid' => $contextid, ); return new external_single_structure($returns); } @@ -2210,6 +2215,7 @@ class external extends external_api { 'description' => $description, 'descriptionformat' => $descriptionformat, 'visible' => $visible, + 'context' => self::get_context_parameters() ); return new external_function_parameters($params); } @@ -2231,9 +2237,10 @@ class external extends external_api { * @param string $description The description of the template. * @param int $descriptionformat The format of the description * @param bool $visible Is this template visible. + * @param array $context The context info. * @return \stdClass Record of new template. */ - public static function create_template($shortname, $idnumber, $duedate, $description, $descriptionformat, $visible) { + public static function create_template($shortname, $idnumber, $duedate, $description, $descriptionformat, $visible, $context) { $params = self::validate_parameters(self::create_template_parameters(), array( 'shortname' => $shortname, @@ -2242,9 +2249,14 @@ class external extends external_api { 'description' => $description, 'descriptionformat' => $descriptionformat, 'visible' => $visible, + 'context' => $context )); + $context = self::get_context_from_params($params['context']); + self::validate_context($context); + unset($params['context']); $params = (object) $params; + $params->contextid = $context->id; $result = api::create_template($params); return $result->to_record(); @@ -2471,7 +2483,46 @@ class external extends external_api { * @return \external_function_parameters */ public static function list_templates_parameters() { - return self::list_parameters_structure(); + $sort = new external_value( + PARAM_ALPHANUMEXT, + 'Column to sort by.', + VALUE_DEFAULT, + '' + ); + $order = new external_value( + PARAM_ALPHA, + 'Sort direction. Should be either ASC or DESC', + VALUE_DEFAULT, + '' + ); + $skip = new external_value( + PARAM_INT, + 'Skip this number of records before returning results', + VALUE_DEFAULT, + 0 + ); + $limit = new external_value( + PARAM_INT, + 'Return this number of records at most.', + VALUE_DEFAULT, + 0 + ); + $includes = new external_value( + PARAM_ALPHA, + 'What other contexts to fetch the templates from. (children, parents, self)', + VALUE_DEFAULT, + 'children' + ); + + $params = array( + 'sort' => $sort, + 'order' => $order, + 'skip' => $skip, + 'limit' => $limit, + 'context' => self::get_context_parameters(), + 'includes' => $includes + ); + return new external_function_parameters($params); } /** @@ -2485,42 +2536,39 @@ class external extends external_api { /** * List the existing learning plan templates * - * @param array $filters Filters to apply. * @param string $sort Field to sort by. * @param string $order Sort order. * @param int $skip Limitstart. * @param int $limit Number of rows to return. + * @param array $context + * @param bool $includes * * @return array */ - public static function list_templates($filters, $sort, $order, $skip, $limit) { + public static function list_templates($sort, $order, $skip, $limit, $context, $includes) { $params = self::validate_parameters(self::list_templates_parameters(), array( - 'filters' => $filters, 'sort' => $sort, 'order' => $order, 'skip' => $skip, - 'limit' => $limit + 'limit' => $limit, + 'context' => $context, + 'includes' => $includes )); + $context = self::get_context_from_params($params['context']); + self::validate_context($context); + if ($params['order'] !== '' && $params['order'] !== 'ASC' && $params['order'] !== 'DESC') { throw new invalid_parameter_exception('Invalid order param. Must be ASC, DESC or empty.'); } - $safefilters = array(); - $validcolumns = array('id', 'shortname', 'description', 'sortorder', 'idnumber', 'visible'); - foreach ($params['filters'] as $filter) { - if (!in_array($filter->column, $validcolumns)) { - throw new invalid_parameter_exception('Filter column was invalid'); - } - $safefilters[$filter->column] = $filter->value; - } - - $results = api::list_templates($safefilters, - $params['sort'], - $params['order'], - $params['skip'], - $params['limit']); + $results = api::list_templates($params['sort'], + $params['order'], + $params['skip'], + $params['limit'], + $context, + $params['includes']); $records = array(); foreach ($results as $result) { $record = $result->to_record(); @@ -2544,15 +2592,16 @@ class external extends external_api { * @return \external_function_parameters */ public static function count_templates_parameters() { - $filters = new external_multiple_structure(new external_single_structure( - array( - 'column' => new external_value(PARAM_ALPHANUMEXT, 'Column name to filter by'), - 'value' => new external_value(PARAM_TEXT, 'Value to filter by. Must be exact match') - ) - )); + $includes = new external_value( + PARAM_ALPHA, + 'What other contextes to fetch the frameworks from. (children, parents, self)', + VALUE_DEFAULT, + 'children' + ); $params = array( - 'filters' => $filters, + 'context' => self::get_context_parameters(), + 'includes' => $includes ); return new external_function_parameters($params); } @@ -2571,22 +2620,16 @@ class external extends external_api { * @param array $filters Filters to allow. * @return boolean */ - public static function count_templates($filters) { + public static function count_templates($context, $includes) { $params = self::validate_parameters(self::count_templates_parameters(), array( - 'filters' => $filters + 'context' => $context, + 'includes' => $includes )); + $context = self::get_context_from_params($params['context']); + self::validate_context($context); - $safefilters = array(); - $validcolumns = array('id', 'shortname', 'description', 'sortorder', 'idnumber', 'visible'); - foreach ($params['filters'] as $filter) { - if (!in_array($filter->column, $validcolumns)) { - throw new invalid_parameter_exception('Filter column was invalid'); - } - $safefilters[$filter->column] = $filter->value; - } - - return api::count_templates($safefilters); + return api::count_templates($context, $includes); } /** @@ -2660,8 +2703,7 @@ class external extends external_api { * @return \external_function_parameters */ public static function data_for_templates_manage_page_parameters() { - // No params required. - $params = array(); + $params = array('pagecontext' => self::get_context_parameters()); return new external_function_parameters($params); } @@ -2676,12 +2718,19 @@ class external extends external_api { /** * Loads the data required to render the templates_manage_page template. * + * @param array $pagecontext The page context info. * @return boolean */ - public static function data_for_templates_manage_page() { + public static function data_for_templates_manage_page($pagecontext) { global $PAGE; - $renderable = new output\manage_templates_page(); + $params = self::validate_parameters(self::data_for_templates_manage_page_parameters(), array( + 'pagecontext' => $pagecontext + )); + $context = self::get_context_from_params($params['pagecontext']); + self::validate_context($context); + + $renderable = new output\manage_templates_page($context); $renderer = $PAGE->get_renderer('tool_lp'); $data = $renderable->export_for_template($renderer); @@ -3039,7 +3088,7 @@ class external extends external_api { 'The template id', VALUE_REQUIRED ); - $params = array('templateid' => $templateid); + $params = array('templateid' => $templateid, 'pagecontext' => self::get_context_parameters()); return new external_function_parameters($params); } @@ -3055,16 +3104,21 @@ class external extends external_api { * Loads the data required to render the template_competencies_page template. * * @param int $templateid Template id. + * @param array $pagecontext The page context info. * @return boolean */ - public static function data_for_template_competencies_page($templateid) { + public static function data_for_template_competencies_page($templateid, $pagecontext) { global $PAGE; $params = self::validate_parameters(self::data_for_template_competencies_page_parameters(), array( 'templateid' => $templateid, + 'pagecontext' => $pagecontext )); - $renderable = new output\template_competencies_page($params['templateid']); + $context = self::get_context_from_params($params['pagecontext']); + self::validate_context($context); + + $renderable = new output\template_competencies_page($params['templateid'], $context); $renderer = $PAGE->get_renderer('tool_lp'); $data = $renderable->export_for_template($renderer); diff --git a/admin/tool/lp/classes/form/template.php b/admin/tool/lp/classes/form/template.php index 490e0849378..ce292d20809 100644 --- a/admin/tool/lp/classes/form/template.php +++ b/admin/tool/lp/classes/form/template.php @@ -45,7 +45,8 @@ class template extends moodleform { */ public function definition() { $mform = $this->_form; - $id = $this->_customdata; + $id = $this->_customdata['id']; + $context = $this->_customdata['context']; $mform->addElement('hidden', 'id'); $mform->setType('id', PARAM_INT); @@ -72,6 +73,9 @@ class template extends moodleform { $mform->setDefault('visible', true); $mform->addHelpButton('visible', 'visible', 'tool_lp'); + $mform->addElement('static', 'context', get_string('context', 'core_role')); + $mform->setDefault('context', $context->get_context_name()); + $this->add_action_buttons(true, get_string('savechanges', 'tool_lp')); if (!empty($id)) { diff --git a/admin/tool/lp/classes/output/manage_templates_page.php b/admin/tool/lp/classes/output/manage_templates_page.php index 83e3eaaa05e..d830ed22017 100644 --- a/admin/tool/lp/classes/output/manage_templates_page.php +++ b/admin/tool/lp/classes/output/manage_templates_page.php @@ -23,6 +23,7 @@ */ namespace tool_lp\output; +use context; use renderable; use templatable; use renderer_base; @@ -40,29 +41,29 @@ use tool_lp\api; */ class manage_templates_page implements renderable, templatable { + /** @var context The context in which everything is happening. */ + protected $pagecontext; + /** @var array $navigation List of links to display on the page. Each link contains a url and a title. */ protected $navigation = array(); /** @var array $templates List of learning plan templates. */ protected $templates = array(); - /** @var bool $canmanage Result of permissions checks. */ - protected $canmanage = false; - /** * Construct this renderable. */ - public function __construct() { + public function __construct(context $pagecontext) { + $this->pagecontext = $pagecontext; + $addpage = new single_button( - new moodle_url('/admin/tool/lp/edittemplate.php'), - get_string('addnewtemplate', 'tool_lp') + new moodle_url('/admin/tool/lp/edittemplate.php', array('pagecontextid' => $this->pagecontext->id)), + get_string('addnewtemplate', 'tool_lp'), + 'get' ); $this->navigation[] = $addpage; - $this->templates = api::list_templates(array(), 'sortorder', 'ASC', 0, 0); - - $context = context_system::instance(); - $this->canmanage = has_capability('tool/lp:planmanageall', $context); + $this->templates = api::list_templates('sortorder', 'ASC', 0, 0, $this->pagecontext); } /** @@ -73,10 +74,12 @@ class manage_templates_page implements renderable, templatable { */ public function export_for_template(renderer_base $output) { $data = new stdClass(); - $data->canmanage = $this->canmanage; + $data->pagecontextid = $this->pagecontext->id; $data->templates = array(); foreach ($this->templates as $template) { $record = $template->to_record(); + $record->canmanage = has_capability('tool/lp:templatemanage', $template->get_context()); + $record->contextname = $template->get_context()->get_context_name(); $data->templates[] = $record; } $data->pluginbaseurl = (new moodle_url('/admin/tool/lp'))->out(true); diff --git a/admin/tool/lp/classes/output/template_competencies_page.php b/admin/tool/lp/classes/output/template_competencies_page.php index e195a8fac89..050ca85abdd 100644 --- a/admin/tool/lp/classes/output/template_competencies_page.php +++ b/admin/tool/lp/classes/output/template_competencies_page.php @@ -28,7 +28,7 @@ use templatable; use renderer_base; use stdClass; use moodle_url; -use context_system; +use context; use tool_lp\api; /** @@ -54,19 +54,22 @@ class template_competencies_page implements renderable, templatable { /** @var string $manageurl manage url. */ protected $manageurl = null; + /** @var context $pagecontext The page context. */ + protected $pagecontext = null; + /** * Construct this renderable. * * @param int $templateid The learning plan template id for this page. */ - public function __construct($templateid) { - $context = context_system::instance(); - + public function __construct($templateid, context $pagecontext) { + $this->pagecontext = $pagecontext; $this->templateid = $templateid; $this->competencies = api::list_competencies_in_template($templateid); - $this->canmanagecompetencyframeworks = has_capability('tool/lp:competencymanage', $context); - $this->canmanagetemplatecompetencies = has_capability('tool/lp:templatemanage', $context); - $this->manageurl = new moodle_url('/admin/tool/lp/competencyframeworks.php'); + $this->canmanagecompetencyframeworks = has_capability('tool/lp:competencymanage', $this->pagecontext); + $this->canmanagetemplatecompetencies = has_capability('tool/lp:templatemanage', $this->pagecontext); + $this->manageurl = new moodle_url('/admin/tool/lp/competencyframeworks.php', + array('pagecontextid' => $this->pagecontext->id)); } /** @@ -77,6 +80,7 @@ class template_competencies_page implements renderable, templatable { */ public function export_for_template(renderer_base $output) { $data = new stdClass(); + $data->pagecontextid = $this->pagecontext->id; $data->templateid = $this->templateid; $data->competencies = array(); foreach ($this->competencies as $competency) { diff --git a/admin/tool/lp/classes/template.php b/admin/tool/lp/classes/template.php index 0046a964b22..30e2924399b 100644 --- a/admin/tool/lp/classes/template.php +++ b/admin/tool/lp/classes/template.php @@ -23,6 +23,7 @@ */ namespace tool_lp; +use context; use stdClass; /** @@ -36,7 +37,7 @@ class template extends persistent { /** @var string $shortname Short name for this template */ private $shortname = ''; - /** @var string $description Description for this framework */ + /** @var string $description Description for this template */ private $description = ''; /** @var int $descriptionformat Format for the description */ @@ -54,6 +55,8 @@ class template extends persistent { /** @var bool $visible Used to show/hide this template */ private $visible = true; + /** @var int $contextid The context ID in which the template is set. */ + private $contextid = null; /** * Method that provides the table name matching this class. * @@ -81,6 +84,24 @@ class template extends persistent { $this->shortname = $shortname; } + /** + * Get the context. + * + * @return context The context + */ + public function get_context() { + return context::instance_by_id($this->contextid); + } + + /** + * Get the contextid. + * + * @return string The contextid + */ + public function get_contextid() { + return $this->contextid; + } + /** * Get the description format. * @@ -229,6 +250,9 @@ class template extends persistent { if (isset($record->usermodified)) { $this->set_usermodified($record->usermodified); } + if (isset($record->contextid)) { + $this->contextid = $record->contextid; + } return $this; } @@ -255,6 +279,7 @@ class template extends persistent { $record->timecreated = $this->get_timecreated(); $record->timemodified = $this->get_timemodified(); $record->usermodified = $this->get_usermodified(); + $record->contextid = $this->get_contextid(); return $record; } diff --git a/admin/tool/lp/db/access.php b/admin/tool/lp/db/access.php index cf8f30c71f1..0f51706ec1c 100644 --- a/admin/tool/lp/db/access.php +++ b/admin/tool/lp/db/access.php @@ -98,14 +98,14 @@ $capabilities = array( ), 'tool/lp:templatemanage' => array( 'captype' => 'write', - 'contextlevel' => CONTEXT_SYSTEM, + 'contextlevel' => CONTEXT_COURSECAT, 'archetypes' => array( ), 'clonepermissionsfrom' => 'moodle/site:config' ), 'tool/lp:templateread' => array( 'captype' => 'read', - 'contextlevel' => CONTEXT_SYSTEM, + 'contextlevel' => CONTEXT_COURSECAT, 'archetypes' => array( 'user' => CAP_ALLOW ), diff --git a/admin/tool/lp/db/install.xml b/admin/tool/lp/db/install.xml index 104f9e0531b..d6c6a174a2c 100755 --- a/admin/tool/lp/db/install.xml +++ b/admin/tool/lp/db/install.xml @@ -1,5 +1,5 @@ - @@ -92,6 +92,7 @@ + diff --git a/admin/tool/lp/db/upgrade.php b/admin/tool/lp/db/upgrade.php index 414103bc223..1d7bd925cd1 100644 --- a/admin/tool/lp/db/upgrade.php +++ b/admin/tool/lp/db/upgrade.php @@ -70,7 +70,7 @@ function xmldb_tool_lp_upgrade($oldversion) { // Define field contextid to be added to tool_lp_competency_framework. $table = new xmldb_table('tool_lp_competency_framework'); $field = new xmldb_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, - context_system::instance()->id, 'id'); + context_system::instance()->id, 'shortname'); // Conditionally launch add field contextid. if (!$dbman->field_exists($table, $field)) { @@ -96,6 +96,23 @@ function xmldb_tool_lp_upgrade($oldversion) { upgrade_plugin_savepoint(true, 2015052406, 'tool', 'lp'); } + if ($oldversion < 2015052407) { + + // Define field contextid to be added to tool_lp_template. + $table = new xmldb_table('tool_lp_template'); + $field = new xmldb_field('contextid', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, + context_system::instance()->id, 'shortname'); + + // Conditionally launch add field contextid. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Lp savepoint reached. + upgrade_plugin_savepoint(true, 2015052407, 'tool', 'lp'); + } + + return true; } diff --git a/admin/tool/lp/edittemplate.php b/admin/tool/lp/edittemplate.php index 6c2930f2ff8..9dcc0fb581d 100644 --- a/admin/tool/lp/edittemplate.php +++ b/admin/tool/lp/edittemplate.php @@ -25,26 +25,45 @@ require_once(__DIR__ . '/../../../config.php'); require_once($CFG->libdir.'/adminlib.php'); -admin_externalpage_setup('toollplearningplans'); +$id = optional_param('id', 0, PARAM_INT); +$pagecontextid = required_param('pagecontextid', PARAM_INT); // Reference to where we can from. + +if (!empty($id)) { + // Always use the context from the framework when it exists. + $template = new \tool_lp\template($id); + $context = $template->get_context(); +} else { + $context = context::instance_by_id($pagecontextid); +} + +// We check that we have the permission to edit this framework, in its own context. +require_login(); +require_capability('tool/lp:templatemanage', $context); + +// We keep the original context in the URLs, so that we remain in the same context. +$url = new moodle_url("/admin/tool/lp/edittemplate.php", array('id' => $id, 'pagecontextid' => $pagecontextid)); +$templatesurl = new moodle_url('/admin/tool/lp/learningplans.php', array('pagecontextid' => $pagecontextid)); +$formurl = new moodle_url("/admin/tool/lp/edittemplate.php", array('pagecontextid' => $pagecontextid)); $title = get_string('templates', 'tool_lp'); -$id = optional_param('id', 0, PARAM_INT); if (empty($id)) { $pagetitle = get_string('addnewtemplate', 'tool_lp'); } else { $pagetitle = get_string('edittemplate', 'tool_lp'); } // Set up the page. -$url = new moodle_url("/admin/tool/lp/edittemplate.php", array('id' => $id)); +$PAGE->navigation->override_active_url($templatesurl); +$PAGE->set_context(context::instance_by_id($pagecontextid)); +$PAGE->set_pagelayout('admin'); $PAGE->set_url($url); $PAGE->set_title($title); $PAGE->set_heading($title); $output = $PAGE->get_renderer('tool_lp'); -$form = new \tool_lp\form\template(null, $id); +$form = new \tool_lp\form\template($formurl->out(false), array('id' => $id, 'context' => $context)); if ($form->is_cancelled()) { - redirect(new moodle_url('/admin/tool/lp/learningplans.php')); + redirect($templatesurl); } echo $output->header(); @@ -59,14 +78,15 @@ if ($data) { if (empty($data->id)) { // Create new template. require_sesskey(); + $data->contextid = $context->id; \tool_lp\api::create_template($data); echo $output->notification(get_string('templatecreated', 'tool_lp'), 'notifysuccess'); - echo $output->continue_button('/admin/tool/lp/learningplans.php'); + echo $output->continue_button($templatesurl); } else { require_sesskey(); \tool_lp\api::update_template($data); echo $output->notification(get_string('templateupdated', 'tool_lp'), 'notifysuccess'); - echo $output->continue_button('/admin/tool/lp/learningplans.php'); + echo $output->continue_button($templatesurl); } } else { $form->display(); diff --git a/admin/tool/lp/learningplans.php b/admin/tool/lp/learningplans.php index bdb782cccfb..51bb859532f 100644 --- a/admin/tool/lp/learningplans.php +++ b/admin/tool/lp/learningplans.php @@ -25,12 +25,20 @@ require_once(__DIR__ . '/../../../config.php'); require_once($CFG->libdir.'/adminlib.php'); -admin_externalpage_setup('toollplearningplans'); +$pagecontextid = required_param('pagecontextid', PARAM_INT); +$context = context::instance_by_id($pagecontextid); + +$url = new moodle_url('/admin/tool/lp/learningplans.php', array('pagecontextid' => $pagecontextid)); + +require_login(); +require_capability('tool/lp:templatemanage', $context); $title = get_string('learningplans', 'tool_lp'); $pagetitle = get_string('templates', 'tool_lp'); + // Set up the page. -$url = new moodle_url("/admin/tool/lp/learningplans.php"); +$PAGE->set_context($context); +$PAGE->set_pagelayout('admin'); $PAGE->set_url($url); $PAGE->set_title($title); $PAGE->set_heading($title); @@ -38,7 +46,7 @@ $output = $PAGE->get_renderer('tool_lp'); echo $output->header(); echo $output->heading($pagetitle); -$page = new \tool_lp\output\manage_templates_page(); +$page = new \tool_lp\output\manage_templates_page($context); echo $output->render($page); echo $output->footer(); diff --git a/admin/tool/lp/settings.php b/admin/tool/lp/settings.php index d4db0b08953..bb5f22005f2 100644 --- a/admin/tool/lp/settings.php +++ b/admin/tool/lp/settings.php @@ -37,8 +37,8 @@ $ADMIN->add('root', $temp, 'badges'); $temp = new admin_externalpage( 'toollplearningplans', get_string('learningplans', 'tool_lp'), - new moodle_url('/admin/tool/lp/learningplans.php'), - 'tool/lp:planmanageall' + new moodle_url('/admin/tool/lp/learningplans.php', array('pagecontextid' => context_system::instance()->id)), + 'tool/lp:templatemanage' ); $ADMIN->add('root', $temp, 'toollpcompetencies'); diff --git a/admin/tool/lp/templatecompetencies.php b/admin/tool/lp/templatecompetencies.php index de0320a7dd2..679439893d5 100644 --- a/admin/tool/lp/templatecompetencies.php +++ b/admin/tool/lp/templatecompetencies.php @@ -26,15 +26,27 @@ require_once(__DIR__ . '/../../../config.php'); require_once($CFG->libdir.'/adminlib.php'); $templateid = required_param('templateid', PARAM_INT); +$pagecontextid = required_param('pagecontextid', PARAM_INT); // Reference to the context we came from. +require_login(); + +$pagecontext = context::instance_by_id($pagecontextid); $template = \tool_lp\api::read_template($templateid); - -admin_externalpage_setup('toollplearningplans'); +$context = $template->get_context(); +require_capability('tool/lp:templatemanage', $context); // Set up the page. -$url = new moodle_url('/admin/tool/lp/templatecompetencies.php', array('templateid' => $template->get_id())); +$url = new moodle_url('/admin/tool/lp/templatecompetencies.php', array('templateid' => $template->get_id(), + 'pagecontextid' => $pagecontextid)); +$templatesurl = new moodle_url('/admin/tool/lp/learningplans.php', array('pagecontextid' => $pagecontextid)); + +$PAGE->navigation->override_active_url($templatesurl); +$PAGE->set_context($pagecontext); + $title = get_string('templatecompetencies', 'tool_lp'); $templatename = format_text($template->get_shortname()); + +$PAGE->set_pagelayout('admin'); $PAGE->set_url($url); $PAGE->set_title($title); $PAGE->set_heading($templatename); @@ -44,6 +56,6 @@ $PAGE->navbar->add($templatename, $url); $output = $PAGE->get_renderer('tool_lp'); echo $output->header(); echo $output->heading($title); -$page = new \tool_lp\output\template_competencies_page($template->get_id()); +$page = new \tool_lp\output\template_competencies_page($template->get_id(), $pagecontext); echo $output->render($page); echo $output->footer(); diff --git a/admin/tool/lp/templates/manage_templates_page.mustache b/admin/tool/lp/templates/manage_templates_page.mustache index c3a61b31da3..64b3df3989b 100644 --- a/admin/tool/lp/templates/manage_templates_page.mustache +++ b/admin/tool/lp/templates/manage_templates_page.mustache @@ -30,7 +30,6 @@ Context variables required for this template: * templates - array of objects containing id, shortname, idnumber, sortorder, visible - * canmanage - true if this user has permission to manage the templates * navigation - array of strings containing buttons for navigation }}
@@ -39,13 +38,15 @@ {{#str}}templatename, tool_lp{{/str}} + {{#str}}context, core_role{{/str}} {{#str}}actions, tool_lp{{/str}} {{#templates}} - {{shortname}} {{idnumber}} {{^visible}}{{#str}}hiddenhint, tool_lp{{/str}}{{/visible}} + {{shortname}} {{idnumber}} {{^visible}}{{#str}}hiddenhint, tool_lp{{/str}}{{/visible}} + {{contextname}} {{#canmanage}}
    @@ -53,7 +54,7 @@ {{#str}}edit{{/str}}
{{#js}} require(['tool_lp/competencies'], function(mod) { - (new mod({{templateid}}, 'template')); + (new mod({{templateid}}, 'template', {{pagecontextid}})); }); {{/js}} diff --git a/admin/tool/lp/tests/api_test.php b/admin/tool/lp/tests/api_test.php index bd60e82375b..7ae9c6f9950 100644 --- a/admin/tool/lp/tests/api_test.php +++ b/admin/tool/lp/tests/api_test.php @@ -42,6 +42,7 @@ class tool_lp_api_testcase extends advanced_testcase { $cat1 = $dg->create_category(); $cat2 = $dg->create_category(array('parent' => $cat1->id)); $cat3 = $dg->create_category(array('parent' => $cat2->id)); + $c1 = $dg->create_course(array('category' => $cat2->id)); // This context should not be returned. $cat1ctx = context_coursecat::instance($cat1->id); $cat2ctx = context_coursecat::instance($cat2->id); @@ -49,13 +50,13 @@ class tool_lp_api_testcase extends advanced_testcase { $sysctx = context_system::instance(); $expected = array($cat1ctx->id => $cat1ctx); - $this->assertEquals($expected, api::get_framework_related_contexts($cat1ctx, 'self')); + $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'self')); $expected = array($cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx, $cat3ctx->id => $cat3ctx); - $this->assertEquals($expected, api::get_framework_related_contexts($cat1ctx, 'children')); + $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children')); $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx); - $this->assertEquals($expected, api::get_framework_related_contexts($cat2ctx, 'parents')); + $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents')); } public function test_get_framework_related_contexts_with_capabilities() { @@ -65,6 +66,7 @@ class tool_lp_api_testcase extends advanced_testcase { $cat1 = $dg->create_category(); $cat2 = $dg->create_category(array('parent' => $cat1->id)); $cat3 = $dg->create_category(array('parent' => $cat2->id)); + $c1 = $dg->create_course(array('category' => $cat2->id)); // This context should not be returned. $cat1ctx = context_coursecat::instance($cat1->id); $cat2ctx = context_coursecat::instance($cat2->id); @@ -86,12 +88,74 @@ class tool_lp_api_testcase extends advanced_testcase { $requiredcap = array('tool/lp:competencyread'); $expected = array(); - $this->assertEquals($expected, api::get_framework_related_contexts($cat2ctx, 'self', $requiredcap)); + $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'self', $requiredcap)); $expected = array($cat1ctx->id => $cat1ctx); - $this->assertEquals($expected, api::get_framework_related_contexts($cat1ctx, 'children', $requiredcap)); + $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children', $requiredcap)); $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx); - $this->assertEquals($expected, api::get_framework_related_contexts($cat2ctx, 'parents', $requiredcap)); + $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents', $requiredcap)); } + + public function test_get_template_related_contexts() { + $this->resetAfterTest(true); + $dg = $this->getDataGenerator(); + $cat1 = $dg->create_category(); + $cat2 = $dg->create_category(array('parent' => $cat1->id)); + $cat3 = $dg->create_category(array('parent' => $cat2->id)); + $c1 = $dg->create_course(array('category' => $cat2->id)); // This context should not be returned. + + $cat1ctx = context_coursecat::instance($cat1->id); + $cat2ctx = context_coursecat::instance($cat2->id); + $cat3ctx = context_coursecat::instance($cat3->id); + $sysctx = context_system::instance(); + + $expected = array($cat1ctx->id => $cat1ctx); + $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'self')); + + $expected = array($cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx, $cat3ctx->id => $cat3ctx); + $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children')); + + $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx, $cat2ctx->id => $cat2ctx); + $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents')); + } + + public function test_get_template_related_contexts_with_capabilities() { + $this->resetAfterTest(true); + $dg = $this->getDataGenerator(); + $user = $dg->create_user(); + $cat1 = $dg->create_category(); + $cat2 = $dg->create_category(array('parent' => $cat1->id)); + $cat3 = $dg->create_category(array('parent' => $cat2->id)); + $c1 = $dg->create_course(array('category' => $cat2->id)); // This context should not be returned. + + $cat1ctx = context_coursecat::instance($cat1->id); + $cat2ctx = context_coursecat::instance($cat2->id); + $cat3ctx = context_coursecat::instance($cat3->id); + $sysctx = context_system::instance(); + + $roleallow = create_role('Allow', 'allow', 'Allow read'); + assign_capability('tool/lp:templateread', CAP_ALLOW, $roleallow, $sysctx->id); + role_assign($roleallow, $user->id, $sysctx->id); + + $roleprevent = create_role('Prevent', 'prevent', 'Prevent read'); + assign_capability('tool/lp:templateread', CAP_PROHIBIT, $roleprevent, $sysctx->id); + role_assign($roleprevent, $user->id, $cat2ctx->id); + + accesslib_clear_all_caches_for_unit_testing(); + $this->setUser($user); + $this->assertFalse(has_capability('tool/lp:templateread', $cat2ctx)); + + $requiredcap = array('tool/lp:templateread'); + + $expected = array(); + $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'self', $requiredcap)); + + $expected = array($cat1ctx->id => $cat1ctx); + $this->assertEquals($expected, api::get_related_contexts($cat1ctx, 'children', $requiredcap)); + + $expected = array($sysctx->id => $sysctx, $cat1ctx->id => $cat1ctx); + $this->assertEquals($expected, api::get_related_contexts($cat2ctx, 'parents', $requiredcap)); + } + } diff --git a/admin/tool/lp/tests/externallib_test.php b/admin/tool/lp/tests/externallib_test.php index 8d75a62ed03..08ffa25439e 100644 --- a/admin/tool/lp/tests/externallib_test.php +++ b/admin/tool/lp/tests/externallib_test.php @@ -1141,7 +1141,8 @@ class tool_lp_external_testcase extends externallib_advanced_testcase { $syscontext = context_system::instance(); // Create a template. - $template = external::create_template('shortname', 'idnumber', time(), 'description', FORMAT_HTML, true); + $template = external::create_template('shortname', 'idnumber', time(), 'description', FORMAT_HTML, true, + array('contextid' => $syscontext->id)); $template = (object) external_api::clean_returnvalue(external::create_template_returns(), $template); // Create a competency. @@ -1176,7 +1177,8 @@ class tool_lp_external_testcase extends externallib_advanced_testcase { $syscontext = context_system::instance(); // Create a template. - $template = external::create_template('shortname', 'idnumber', time(), 'description', FORMAT_HTML, true); + $template = external::create_template('shortname', 'idnumber', time(), 'description', FORMAT_HTML, true, + array('contextid' => $syscontext->id)); $template = (object) external_api::clean_returnvalue(external::create_template_returns(), $template); // Create a competency. @@ -1220,7 +1222,8 @@ class tool_lp_external_testcase extends externallib_advanced_testcase { $syscontext = context_system::instance(); // Create a template. - $template = external::create_template('shortname', 'idnumber', time(), 'description', FORMAT_HTML, true); + $template = external::create_template('shortname', 'idnumber', time(), 'description', FORMAT_HTML, true, + array('contextid' => $syscontext->id)); $template = (object) external_api::clean_returnvalue(external::create_template_returns(), $template); // Create a competency framework. diff --git a/admin/tool/lp/version.php b/admin/tool/lp/version.php index f2f85150a98..40720592372 100644 --- a/admin/tool/lp/version.php +++ b/admin/tool/lp/version.php @@ -24,7 +24,7 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2015052406; // The current plugin version (Date: YYYYMMDDXX). +$plugin->version = 2015052407; // The current plugin version (Date: YYYYMMDDXX). $plugin->requires = 2014110400; // Requires this Moodle version. $plugin->component = 'tool_lp'; // Full name of the plugin (used for diagnostics).