Пример #1
0
 /**
  * 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;
 }
Пример #2
0
 /**
  * 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;
 }
Пример #3
0
 /**
  * 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();
 }
Пример #4
0
/**
 * 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;
}
Пример #5
0
 /**
  * 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'));
 }
Пример #6
0
 /**
  * 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;
 }
Пример #7
0
 /**
  * Returns true when the template has user learning plans.
  *
  * @return boolean
  */
 public function has_plans()
 {
     return plan::has_records_for_template($this->get_id());
 }
Пример #8
0
 /**
  * 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;
 }
Пример #9
0
 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());
 }
Пример #10
0
 /**
  * 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);
 }
Пример #11
0
 /**
  * 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;
 }
Пример #12
0
    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()) {
Пример #13
0
 /**
  * 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;
 }
Пример #14
0
 /**
  * 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);
 }
Пример #15
0
/**
 * 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;
}
Пример #16
0
 /**
  * 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()));
 }
Пример #17
0
 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.
 }
Пример #18
0
 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);
 }
Пример #19
0
 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));
 }
Пример #20
0
 /**
  * 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);
 }
Пример #21
0
 /**
  * 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);
 }
Пример #22
0
 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);
 }