/** * Export the data. * * @param renderer_base $output * @return stdClass */ public function export_for_template(\renderer_base $output) { $frameworks = array(); $scales = array(); $planexporter = new plan_exporter($this->plan, array('template' => $this->plan->get_template())); $data = new stdClass(); $data->plan = $planexporter->export($output); $data->competencies = array(); $data->pluginbaseurl = (new moodle_url('/admin/tool/lp'))->out(false); $data->contextid = $this->plan->get_context()->id; if ($data->plan->iscompleted) { $ucproperty = 'usercompetencyplan'; $ucexporter = 'core_competency\\external\\user_competency_plan_exporter'; } else { $ucproperty = 'usercompetency'; $ucexporter = 'core_competency\\external\\user_competency_exporter'; } $pclist = api::list_plan_competencies($this->plan); $proficientcount = 0; foreach ($pclist as $pc) { $comp = $pc->competency; $usercomp = $pc->{$ucproperty}; // Get the framework. if (!isset($frameworks[$comp->get_competencyframeworkid()])) { $frameworks[$comp->get_competencyframeworkid()] = $comp->get_framework(); } $framework = $frameworks[$comp->get_competencyframeworkid()]; // Get the scale. $scaleid = $comp->get_scaleid(); if ($scaleid === null) { $scaleid = $framework->get_scaleid(); } if (!isset($scales[$framework->get_scaleid()])) { $scales[$framework->get_scaleid()] = $framework->get_scale(); } $scale = $scales[$framework->get_scaleid()]; // Prepare the data. $record = new stdClass(); $exporter = new competency_exporter($comp, array('context' => $framework->get_context())); $record->competency = $exporter->export($output); // Competency path. $exporter = new competency_path_exporter(['ancestors' => $comp->get_ancestors(), 'framework' => $framework, 'context' => $framework->get_context()]); $record->comppath = $exporter->export($output); $exporter = new $ucexporter($usercomp, array('scale' => $scale)); $record->{$ucproperty} = $exporter->export($output); $data->competencies[] = $record; if ($usercomp->get_proficiency()) { $proficientcount++; } } $data->competencycount = count($data->competencies); $data->proficientcompetencycount = $proficientcount; if ($data->competencycount) { $data->proficientcompetencypercentage = (double) $proficientcount / (double) $data->competencycount * 100.0; } else { $data->proficientcompetencypercentage = 0.0; } $data->proficientcompetencypercentageformatted = format_float($data->proficientcompetencypercentage); return $data; }
/** * Convenience method to instantiate the event. * * @param plan $plan The plan. * @return self */ public static function create_from_plan(plan $plan) { if (!$plan->get_id()) { throw new \coding_exception('The plan ID must be set.'); } $event = static::create(array('contextid' => $plan->get_context()->id, 'objectid' => $plan->get_id())); $event->add_record_snapshot(plan::TABLE, $plan->to_record()); return $event; }
/** * Do the job. */ public function execute() { if (!api::is_enabled()) { return; } $records = plan::get_recordset_for_due_and_incomplete(); foreach ($records as $record) { $plan = new plan(0, $record); api::complete_plan($plan); } $records->close(); }
/** * Add nodes to myprofile page. * * @param \core_user\output\myprofile\tree $tree Tree object * @param stdClass $user user object * @param bool $iscurrentuser * @param stdClass $course Course object * * @return bool */ function tool_lp_myprofile_navigation(core_user\output\myprofile\tree $tree, $user, $iscurrentuser, $course) { if (!get_config('core_competency', 'enabled')) { return false; } else { if (!\core_competency\plan::can_read_user($user->id)) { return false; } } $url = new moodle_url('/admin/tool/lp/plans.php', array('userid' => $user->id)); $node = new core_user\output\myprofile\node('miscellaneous', 'learningplans', get_string('learningplans', 'tool_lp'), null, $url); $tree->add_node($node); return true; }
/** * Define the form - called by parent constructor */ public function definition() { $mform = $this->_form; $context = $this->_customdata['context']; $mform->addElement('hidden', 'userid'); $mform->setType('userid', PARAM_INT); $mform->setConstant('userid', $this->_customdata['userid']); $mform->addElement('header', 'generalhdr', get_string('general')); // Name. $mform->addElement('text', 'name', get_string('planname', 'tool_lp'), 'maxlength="100"'); $mform->setType('name', PARAM_TEXT); $mform->addRule('name', null, 'required', null, 'client'); $mform->addRule('name', get_string('maximumchars', '', 100), 'maxlength', 100, 'client'); // Description. $mform->addElement('editor', 'description', get_string('plandescription', 'tool_lp'), array('rows' => 4)); $mform->setType('description', PARAM_RAW); $mform->addElement('date_time_selector', 'duedate', get_string('duedate', 'tool_lp'), array('optional' => true)); $mform->addHelpButton('duedate', 'duedate', 'tool_lp'); // Display status selector in form. // When the plan was already saved then the status can not be changed via this form. $status = planpersistent::get_status_list($this->_customdata['userid']); $plan = $this->get_persistent(); if ($plan->get_id()) { // The current status is not selectable (workflow status probably), we just display it. $mform->addElement('static', 'staticstatus', get_string('status', 'tool_lp'), $plan->get_statusname()); } else { if (!empty($status) && count($status) > 1) { // There is more than one status to select from. $mform->addElement('select', 'status', get_string('status', 'tool_lp'), $status); } else { if (count($status) === 1) { // There is only one status to select from. $mform->addElement('static', 'staticstatus', get_string('status', 'tool_lp'), current($status)); } else { throw new required_capability_exception($context, 'moodle/competency:planmanage', 'nopermissions', ''); } } } // Disable short forms. $mform->setDisableShortforms(); $this->add_action_buttons(true, get_string('savechanges', 'tool_lp')); }
/** * Export this data so it can be used as the context for a mustache template. * * @param renderer_base $output * @return stdClass */ public function export_for_template(renderer_base $output) { $data = new stdClass(); $data->userid = $this->userid; $data->pluginbaseurl = (new moodle_url('/admin/tool/lp'))->out(true); $data->canreaduserevidence = user_evidence::can_read_user($this->userid); $data->canmanageuserplans = plan::can_manage_user($this->userid); // Attach standard objects as mustache can not parse \core_competency\plan objects. $data->plans = array(); if ($this->plans) { foreach ($this->plans as $plan) { $exporter = new plan_exporter($plan, array('template' => $plan->get_template())); $record = $exporter->export($output); $data->plans[] = $record; } } $data->navigation = array(); foreach ($this->navigation as $button) { $data->navigation[] = $output->render($button); } return $data; }
/** * Returns true when the template has user learning plans. * * @return boolean */ public function has_plans() { return plan::has_records_for_template($this->get_id()); }
/** * Validate the plan ID. * * @param int $value The value. * @return true|lang_string */ protected function validate_planid($value) { if (!plan::record_exists($value)) { return new lang_string('invalidplan', 'core_competency'); } return true; }
public function test_delete_template_unlink_plans() { $this->resetAfterTest(true); $this->setAdminUser(); $dg = $this->getDataGenerator(); $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency'); $u1 = $dg->create_user(); $f = $lpg->create_framework(); $c1 = $lpg->create_competency(array('competencyframeworkid' => $f->get_id())); $c2 = $lpg->create_competency(array('competencyframeworkid' => $f->get_id())); $tpl = $lpg->create_template(); $tplc1 = $lpg->create_template_competency(array('templateid' => $tpl->get_id(), 'competencyid' => $c1->get_id(), 'sortorder' => 1)); $tplc2 = $lpg->create_template_competency(array('templateid' => $tpl->get_id(), 'competencyid' => $c2->get_id(), 'sortorder' => 2)); $p1 = $lpg->create_plan(array('templateid' => $tpl->get_id(), 'userid' => $u1->id)); // Check pre-test. $this->assertTrue(\core_competency\template::record_exists($tpl->get_id())); $this->assertEquals(2, \core_competency\template_competency::count_competencies($tpl->get_id())); $this->assertEquals(1, count(\core_competency\plan::get_records(array('templateid' => $tpl->get_id())))); $result = api::delete_template($tpl->get_id(), false); $this->assertTrue($result); // Check that the template does not exist anymore. $this->assertFalse(\core_competency\template::record_exists($tpl->get_id())); // Check that associated competencies are also deleted. $this->assertEquals(0, \core_competency\template_competency::count_competencies($tpl->get_id())); // Check that associated plan still exist but unlink from template. $plans = \core_competency\plan::get_records(array('id' => $p1->get_id())); $this->assertEquals(1, count($plans)); $this->assertEquals($plans[0]->get_origtemplateid(), $tpl->get_id()); $this->assertNull($plans[0]->get_templateid()); }
/** * List the plans in the template, filtered by status. * * Requires moodle/competency:templateview capability at the system context. * * @param mixed $templateorid The id or the template. * @param int $status One of the plan status constants (or 0 for all plans). * @param int $skip The number of records to skip * @param int $limit The max number of records to return * @return plan[] */ public static function list_plans_for_template($templateorid, $status = 0, $skip = 0, $limit = 100) { $template = $templateorid; if (!is_object($template)) { $template = new template($template); } // First we do a permissions check. if (!$template->can_read()) { throw new required_capability_exception($template->get_context(), 'moodle/competency:templateview', 'nopermissions', ''); } return plan::get_records_for_template($template->get_id(), $status, $skip, $limit); }
/** * Create a new plan. * * @param array|stdClass $record * @return plan */ public function create_plan($record = null) { $this->plancount++; $i = $this->plancount; $record = (object) $record; if (!isset($record->name)) { $record->name = "Plan shortname {$i}"; } if (!isset($record->description)) { $record->description = "Plan {$i} description"; } if (!isset($record->descriptionformat)) { $record->descriptionformat = FORMAT_HTML; } if (!isset($record->userid)) { throw new coding_exception('The userid value is required.'); } $plan = new plan(0, $record); $plan->create(); return $plan; }
list($title, $subtitle, $returnurl) = \tool_lp\page_helper::setup_for_plan($userid, $url, null, $pagetitle, $returntype); } else { $plan = \core_competency\api::read_plan($id); // The userid parameter must be the same as the owner of the plan. if ($userid != $plan->get_userid()) { throw new coding_exception('Inconsistency between the userid parameter and the userid of the plan'); } $pagetitle = get_string('editplan', 'tool_lp'); list($title, $subtitle, $returnurl) = \tool_lp\page_helper::setup_for_plan($userid, $url, $plan, $pagetitle, $returntype); } $output = $PAGE->get_renderer('tool_lp'); // Custom data to pass to the form. $customdata = array('userid' => $userid, 'context' => $PAGE->context, 'persistent' => $plan); // User can create plan if he can_manage_user with active/complete status // or if he can_manage_user_draft with draft status. $cancreate = \core_competency\plan::can_manage_user_draft($userid) || \core_competency\plan::can_manage_user($userid); // If editing plan, check if user has permissions to edit it. if ($plan != null) { if (!$plan->can_manage()) { throw new required_capability_exception($PAGE->context, 'moodle/competency:planmanage', 'nopermissions', ''); } if (!$plan->can_be_edited()) { throw new coding_exception('Completed plan can not be edited'); } } else { if (!$cancreate) { throw new required_capability_exception($PAGE->context, 'moodle/competency:planmanage', 'nopermissions', ''); } } $form = new \tool_lp\form\plan($url->out(false), $customdata); if ($form->is_cancelled()) {
/** * Validate planid. * * @param int $value ID. * @return true|lang_string */ protected function validate_planid($value) { if (!plan::record_exists($value)) { return new lang_string('invaliddata', 'error'); } return true; }
/** * Unlink the plan from the template. * * @param int $planid The plan id * @return bool */ public static function unlink_plan_from_template($planid) { $params = self::validate_parameters(self::unlink_plan_from_template_parameters(), array('planid' => $planid)); $plan = new plan($params['planid']); self::validate_context($plan->get_context()); return api::unlink_plan_from_template($plan); }
/** * Validates comments. * * @param stdClass $params The parameters. * @return bool */ function core_competency_comment_validate($params) { if (!get_config('core_competency', 'enabled')) { return false; } if ($params->commentarea == 'user_competency') { if (!user_competency::record_exists($params->itemid)) { return false; } return true; } else { if ($params->commentarea == 'plan') { if (!plan::record_exists($params->itemid)) { return false; } return true; } } return false; }
/** * Return true if the user of the evidence has plan. * * @return bool */ public function user_has_plan() { return plan::record_exists_select('userid = ?', array($this->get_userid())); }
public function test_sync_plans_from_cohorts_with_passed_duedate() { global $DB; $this->resetAfterTest(true); $this->setAdminUser(); $dg = $this->getDataGenerator(); $lpg = $dg->get_plugin_generator('core_competency'); $user1 = $dg->create_user(); $user2 = $dg->create_user(); $cohort = $dg->create_cohort(); $tpl = $lpg->create_template(array('duedate' => time() + 1000)); $templatecohort = api::create_template_cohort($tpl->get_id(), $cohort->id); $task = \core\task\manager::get_scheduled_task('\\core\\task\\sync_plans_from_template_cohorts_task'); // Add 1 user to the cohort. cohort_add_member($cohort->id, $user1->id); // Creating plans from template cohort. $task->execute(); $this->assertEquals(1, \core_competency\plan::count_records()); // Now add another user, but this time the template will be expired. cohort_add_member($cohort->id, $user2->id); $record = $tpl->to_record(); $record->duedate = time() - 10000; $DB->update_record(\core_competency\template::TABLE, $record); $tpl->read(); $task->execute(); $this->assertEquals(1, \core_competency\plan::count_records()); // Still only one plan. // Pretend it wasn't expired. $tpl->set_duedate(time() + 100); $tpl->update(); $task->execute(); $this->assertEquals(2, \core_competency\plan::count_records()); // Now there is two. }
public function test_get_by_user_and_competency() { $this->resetAfterTest(); $this->setAdminUser(); $dg = $this->getDataGenerator(); $lpg = $dg->get_plugin_generator('core_competency'); $u1 = $dg->create_user(); $u2 = $dg->create_user(); $u3 = $dg->create_user(); $u4 = $dg->create_user(); $f1 = $lpg->create_framework(); $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id())); $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get_id())); $tpl1 = $lpg->create_template(); $lpg->create_template_competency(array('competencyid' => $c1->get_id(), 'templateid' => $tpl1->get_id())); $p1 = $lpg->create_plan(array('userid' => $u1->id)); $lpg->create_plan_competency(array('planid' => $p1->get_id(), 'competencyid' => $c1->get_id())); $p2 = $lpg->create_plan(array('userid' => $u2->id)); $lpg->create_plan_competency(array('planid' => $p2->get_id(), 'competencyid' => $c1->get_id())); $p3 = $lpg->create_plan(array('userid' => $u3->id, 'templateid' => $tpl1->get_id())); $p4 = $lpg->create_plan(array('userid' => $u4->id, 'templateid' => $tpl1->get_id())); api::complete_plan($p2); api::complete_plan($p4); // Finding a plan, not completed. $plans = plan::get_by_user_and_competency($u1->id, $c1->get_id()); $this->assertCount(1, $plans); $plan = array_shift($plans); $this->assertEquals($p1->get_id(), $plan->get_id()); $this->assertNotEquals(plan::STATUS_COMPLETE, $plan->get_status()); // Finding a completed plan. $plans = plan::get_by_user_and_competency($u2->id, $c1->get_id()); $this->assertCount(1, $plans); $plan = array_shift($plans); $this->assertEquals($p2->get_id(), $plan->get_id()); $this->assertEquals(plan::STATUS_COMPLETE, $plan->get_status()); // Finding a plan based on a template, not completed. $plans = plan::get_by_user_and_competency($u3->id, $c1->get_id()); $this->assertCount(1, $plans); $plan = array_shift($plans); $this->assertEquals($p3->get_id(), $plan->get_id()); $this->assertTrue($plan->is_based_on_template()); $this->assertNotEquals(plan::STATUS_COMPLETE, $plan->get_status()); // Finding a plan based on a template. $plans = plan::get_by_user_and_competency($u4->id, $c1->get_id()); $this->assertCount(1, $plans); $plan = array_shift($plans); $this->assertEquals($p4->get_id(), $plan->get_id()); $this->assertTrue($plan->is_based_on_template()); $this->assertEquals(plan::STATUS_COMPLETE, $plan->get_status()); // Finding more than one plan, no template. $p5 = $lpg->create_plan(array('userid' => $u1->id)); $lpg->create_plan_competency(array('planid' => $p5->get_id(), 'competencyid' => $c1->get_id())); $plans = plan::get_by_user_and_competency($u1->id, $c1->get_id()); $this->assertCount(2, $plans); $plan = array_shift($plans); $this->assertEquals($p1->get_id(), $plan->get_id()); $plan = array_shift($plans); $this->assertEquals($p5->get_id(), $plan->get_id()); // Finding more than one plan, with template. $p6 = $lpg->create_plan(array('userid' => $u1->id, 'templateid' => $tpl1->get_id())); $plans = plan::get_by_user_and_competency($u1->id, $c1->get_id()); $this->assertCount(3, $plans); $plan = array_shift($plans); $this->assertEquals($p1->get_id(), $plan->get_id()); $plan = array_shift($plans); $this->assertEquals($p5->get_id(), $plan->get_id()); $plan = array_shift($plans); $this->assertEquals($p6->get_id(), $plan->get_id()); // Finding no plans. $plans = plan::get_by_user_and_competency($u1->id, $c2->get_id()); $this->assertCount(0, $plans); }
protected function get_other_values(renderer_base $output) { $context = $this->persistent->get_context(); return array('duedateformatted' => userdate($this->persistent->get_duedate()), 'cohortscount' => template_cohort::count_records(array('templateid' => $this->persistent->get_id())), 'planscount' => plan::count_records(array('templateid' => $this->persistent->get_id())), 'canmanage' => $this->persistent->can_manage(), 'canread' => $this->persistent->can_read(), 'contextname' => $context->get_context_name(), 'contextnamenoprefix' => $context->get_context_name(false)); }
/** * Set-up a plan page. * * Example: * list($title, $subtitle) = page_helper::setup_for_plan($url, $template, $pagetitle); * echo $OUTPUT->heading($title); * echo $OUTPUT->heading($subtitle, 3); * * @param int $userid The user ID. * @param moodle_url $url The current page. * @param \core_competency\plan $plan The plan, if any. * @param string $subtitle The title of the subpage, if any. * @param string $returntype The desired return page. * @return array With the following: * - Page title * - Page sub title * - Return URL (main plan page) */ public static function setup_for_plan($userid, moodle_url $url, $plan = null, $subtitle = '', $returntype = null) { global $PAGE, $USER; // Check that the user is a valid user. $user = core_user::get_user($userid); if (!$user || !core_user::is_real_user($userid)) { throw new \moodle_exception('invaliduser', 'error'); } $context = context_user::instance($user->id); $plansurl = new moodle_url('/admin/tool/lp/plans.php', array('userid' => $userid)); $planurl = null; if ($plan) { $planurl = new moodle_url('/admin/tool/lp/plan.php', array('id' => $plan->get_id())); } $returnurl = $plansurl; if ($returntype != 'plans' && $planurl) { $returnurl = $planurl; } $PAGE->navigation->override_active_url($plansurl); $PAGE->set_context($context); // If not his own plan, we want to extend the navigation for the user. $iscurrentuser = $USER->id == $user->id; if (!$iscurrentuser) { $PAGE->navigation->extend_for_user($user); $PAGE->navigation->set_userid_for_parent_checks($user->id); } if (!empty($plan)) { $title = format_string($plan->get_name(), true, array('context' => $context)); } else { $title = get_string('learningplans', 'tool_lp'); } $PAGE->set_pagelayout('standard'); $PAGE->set_url($url); $PAGE->set_title($title); $PAGE->set_heading($title); if (!empty($plan)) { $PAGE->navbar->add($title, $planurl); if (!empty($subtitle)) { $PAGE->navbar->add($subtitle, $url); } } else { if (!empty($subtitle)) { // We're in a sub page without a specific plan. $PAGE->navbar->add($subtitle, $url); } } return array($title, $subtitle, $returnurl); }
/** * Can the current user read a user's competency? * * @param int $userid The user ID the competency belongs to. * @return bool */ public static function can_read_user($userid) { $capability = 'moodle/competency:usercompetencyview'; return has_capability($capability, context_user::instance($userid)) || plan::can_read_user($userid); }
public function test_create_plan() { $this->resetAfterTest(true); $user = $this->getDataGenerator()->create_user(); $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency'); $this->assertEquals(0, plan::count_records()); $plan = $lpg->create_plan(array('userid' => $user->id)); $this->assertEquals(1, plan::count_records()); $this->assertInstanceOf('\\core_competency\\plan', $plan); }