Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 and 402] [Versions 311 and 403]

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * External tests.
  19   *
  20   * @package    core_competency
  21   * @copyright  2016 Frédéric Massart - FMCorz.net
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core_competency\external;
  26  
  27  use core_competency\api;
  28  use core_competency\course_competency_settings;
  29  use core_competency\external;
  30  use core_competency\invalid_persistent_exception;
  31  use core_competency\plan;
  32  use core_competency\plan_competency;
  33  use core_competency\related_competency;
  34  use core_competency\template;
  35  use core_competency\template_competency;
  36  use core_competency\user_competency;
  37  use core_competency\user_competency_plan;
  38  use externallib_advanced_testcase;
  39  
  40  defined('MOODLE_INTERNAL') || die();
  41  global $CFG;
  42  
  43  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  44  
  45  /**
  46   * External testcase.
  47   *
  48   * @package    core_competency
  49   * @copyright  2016 Frédéric Massart - FMCorz.net
  50   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  51   */
  52  class external_test extends externallib_advanced_testcase {
  53  
  54      /** @var \stdClass $creator User with enough permissions to create insystem context. */
  55      protected $creator = null;
  56  
  57      /** @var \stdClass $learningplancreator User with enough permissions to create incategory context. */
  58      protected $catcreator = null;
  59  
  60      /** @var \stdClass $category Category */
  61      protected $category = null;
  62  
  63      /** @var \stdClass $user User with enough permissions to view insystem context */
  64      protected $user = null;
  65  
  66      /** @var \stdClass $catuser User with enough permissions to view incategory context */
  67      protected $catuser = null;
  68  
  69      /** @var int Creator role id */
  70      protected $creatorrole = null;
  71  
  72      /** @var int User role id */
  73      protected $userrole = null;
  74  
  75      /** @var \stdClass $scale1 Scale */
  76      protected $scale1 = null;
  77  
  78      /** @var \stdClass $scale2 Scale */
  79      protected $scale2 = null;
  80  
  81      /** @var \stdClass $scale3 Scale */
  82      protected $scale3 = null;
  83  
  84      /** @var \stdClass $scale4 Scale */
  85      protected $scale4 = null;
  86  
  87      /** @var string scaleconfiguration */
  88      protected $scaleconfiguration1 = null;
  89  
  90      /** @var string scaleconfiguration */
  91      protected $scaleconfiguration2 = null;
  92  
  93      /** @var string catscaleconfiguration */
  94      protected $scaleconfiguration3 = null;
  95  
  96      /** @var string catscaleconfiguration */
  97      protected $catscaleconfiguration4 = null;
  98  
  99      /**
 100       * Setup function- we will create a course and add an assign instance to it.
 101       */
 102      protected function setUp(): void {
 103          global $DB, $CFG;
 104  
 105          $this->resetAfterTest(true);
 106  
 107          // Create some users.
 108          $creator = $this->getDataGenerator()->create_user();
 109          $user = $this->getDataGenerator()->create_user();
 110          $catuser = $this->getDataGenerator()->create_user();
 111          $category = $this->getDataGenerator()->create_category();
 112          $othercategory = $this->getDataGenerator()->create_category();
 113          $catcreator = $this->getDataGenerator()->create_user();
 114  
 115          $syscontext = \context_system::instance();
 116          $catcontext = \context_coursecat::instance($category->id);
 117          $othercatcontext = \context_coursecat::instance($othercategory->id);
 118  
 119          // Fetching default authenticated user role.
 120          $authrole = $DB->get_record('role', array('id' => $CFG->defaultuserroleid));
 121  
 122          // Reset all default authenticated users permissions.
 123          unassign_capability('moodle/competency:competencygrade', $authrole->id);
 124          unassign_capability('moodle/competency:competencymanage', $authrole->id);
 125          unassign_capability('moodle/competency:competencyview', $authrole->id);
 126          unassign_capability('moodle/competency:planmanage', $authrole->id);
 127          unassign_capability('moodle/competency:planmanagedraft', $authrole->id);
 128          unassign_capability('moodle/competency:planmanageown', $authrole->id);
 129          unassign_capability('moodle/competency:planview', $authrole->id);
 130          unassign_capability('moodle/competency:planviewdraft', $authrole->id);
 131          unassign_capability('moodle/competency:planviewown', $authrole->id);
 132          unassign_capability('moodle/competency:planviewowndraft', $authrole->id);
 133          unassign_capability('moodle/competency:templatemanage', $authrole->id);
 134          unassign_capability('moodle/competency:templateview', $authrole->id);
 135          unassign_capability('moodle/cohort:manage', $authrole->id);
 136          unassign_capability('moodle/competency:coursecompetencyconfigure', $authrole->id);
 137  
 138          // Creating specific roles.
 139          $this->creatorrole = create_role('Creator role', 'creatorrole', 'learning plan creator role description');
 140          $this->userrole = create_role('User role', 'userrole', 'learning plan user role description');
 141  
 142          assign_capability('moodle/competency:competencymanage', CAP_ALLOW, $this->creatorrole, $syscontext->id);
 143          assign_capability('moodle/competency:coursecompetencyconfigure', CAP_ALLOW, $this->creatorrole, $syscontext->id);
 144          assign_capability('moodle/competency:competencyview', CAP_ALLOW, $this->userrole, $syscontext->id);
 145          assign_capability('moodle/competency:planmanage', CAP_ALLOW, $this->creatorrole, $syscontext->id);
 146          assign_capability('moodle/competency:planmanagedraft', CAP_ALLOW, $this->creatorrole, $syscontext->id);
 147          assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $this->creatorrole, $syscontext->id);
 148          assign_capability('moodle/competency:planview', CAP_ALLOW, $this->creatorrole, $syscontext->id);
 149          assign_capability('moodle/competency:planviewdraft', CAP_ALLOW, $this->creatorrole, $syscontext->id);
 150          assign_capability('moodle/competency:templatemanage', CAP_ALLOW, $this->creatorrole, $syscontext->id);
 151          assign_capability('moodle/competency:competencygrade', CAP_ALLOW, $this->creatorrole, $syscontext->id);
 152          assign_capability('moodle/cohort:manage', CAP_ALLOW, $this->creatorrole, $syscontext->id);
 153          assign_capability('moodle/competency:templateview', CAP_ALLOW, $this->userrole, $syscontext->id);
 154          assign_capability('moodle/competency:planviewown', CAP_ALLOW, $this->userrole, $syscontext->id);
 155          assign_capability('moodle/competency:planviewowndraft', CAP_ALLOW, $this->userrole, $syscontext->id);
 156  
 157          role_assign($this->creatorrole, $creator->id, $syscontext->id);
 158          role_assign($this->creatorrole, $catcreator->id, $catcontext->id);
 159          role_assign($this->userrole, $user->id, $syscontext->id);
 160          role_assign($this->userrole, $catuser->id, $catcontext->id);
 161  
 162          $this->creator = $creator;
 163          $this->catcreator = $catcreator;
 164          $this->user = $user;
 165          $this->catuser = $catuser;
 166          $this->category = $category;
 167          $this->othercategory = $othercategory;
 168  
 169          $this->scale1 = $this->getDataGenerator()->create_scale(array("scale" => "value1, value2"));
 170          $this->scale2 = $this->getDataGenerator()->create_scale(array("scale" => "value3, value4"));
 171          $this->scale3 = $this->getDataGenerator()->create_scale(array("scale" => "value5, value6"));
 172          $this->scale4 = $this->getDataGenerator()->create_scale(array("scale" => "value7, value8"));
 173  
 174          $this->scaleconfiguration1 = '[{"scaleid":"'.$this->scale1->id.'"},' .
 175                  '{"name":"value1","id":1,"scaledefault":1,"proficient":0},' .
 176                  '{"name":"value2","id":2,"scaledefault":0,"proficient":1}]';
 177          $this->scaleconfiguration2 = '[{"scaleid":"'.$this->scale2->id.'"},' .
 178                  '{"name":"value3","id":1,"scaledefault":1,"proficient":0},' .
 179                  '{"name":"value4","id":2,"scaledefault":0,"proficient":1}]';
 180          $this->scaleconfiguration3 = '[{"scaleid":"'.$this->scale3->id.'"},' .
 181                  '{"name":"value5","id":1,"scaledefault":1,"proficient":0},' .
 182                  '{"name":"value6","id":2,"scaledefault":0,"proficient":1}]';
 183          $this->scaleconfiguration4 = '[{"scaleid":"'.$this->scale4->id.'"},'.
 184                  '{"name":"value8","id":1,"scaledefault":1,"proficient":0},' .
 185                  '{"name":"value8","id":2,"scaledefault":0,"proficient":1}]';
 186          accesslib_clear_all_caches_for_unit_testing();
 187      }
 188  
 189  
 190      protected function create_competency_framework($number = 1, $system = true) {
 191          $scalename = 'scale' . $number;
 192          $scalepropname = 'scaleconfiguration' . $number;
 193          $framework = array(
 194              'shortname' => 'shortname' . $number,
 195              'idnumber' => 'idnumber' . $number,
 196              'description' => 'description' . $number,
 197              'descriptionformat' => FORMAT_HTML,
 198              'scaleid' => $this->$scalename->id,
 199              'scaleconfiguration' => $this->$scalepropname,
 200              'visible' => true,
 201              'contextid' => $system ? \context_system::instance()->id : \context_coursecat::instance($this->category->id)->id
 202          );
 203          $result = external::create_competency_framework($framework);
 204          return (object) \external_api::clean_returnvalue(external::create_competency_framework_returns(), $result);
 205      }
 206  
 207      protected function create_plan($number, $userid, $templateid, $status, $duedate) {
 208          $plan = array(
 209              'name' => 'name' . $number,
 210              'description' => 'description' . $number,
 211              'descriptionformat' => FORMAT_HTML,
 212              'userid' => $userid,
 213              'templateid' => empty($templateid) ? null : $templateid,
 214              'status' => $status,
 215              'duedate' => $duedate
 216          );
 217          $result = external::create_plan($plan);
 218          return (object) \external_api::clean_returnvalue(external::create_plan_returns(), $result);
 219      }
 220  
 221      protected function create_template($number, $system) {
 222          $template = array(
 223              'shortname' => 'shortname' . $number,
 224              'description' => 'description' . $number,
 225              'descriptionformat' => FORMAT_HTML,
 226              'duedate' => 0,
 227              'visible' => true,
 228              'contextid' => $system ? \context_system::instance()->id : \context_coursecat::instance($this->category->id)->id
 229          );
 230          $result = external::create_template($template);
 231          return (object) \external_api::clean_returnvalue(external::create_template_returns(), $result);
 232      }
 233  
 234      protected function update_template($templateid, $number) {
 235          $template = array(
 236              'id' => $templateid,
 237              'shortname' => 'shortname' . $number,
 238              'description' => 'description' . $number,
 239              'descriptionformat' => FORMAT_HTML,
 240              'visible' => true
 241          );
 242          $result = external::update_template($template);
 243          return \external_api::clean_returnvalue(external::update_template_returns(), $result);
 244      }
 245  
 246      protected function update_plan($planid, $number, $userid, $templateid, $status, $duedate) {
 247          $plan = array(
 248              'id' => $planid,
 249              'name' => 'name' . $number,
 250              'description' => 'description' . $number,
 251              'descriptionformat' => FORMAT_HTML,
 252              'userid' => $userid,
 253              'templateid' => $templateid,
 254              'status' => $status,
 255              'duedate' => $duedate
 256          );
 257          $result = external::update_plan($plan);
 258          return \external_api::clean_returnvalue(external::update_plan_returns(), $result);
 259      }
 260  
 261      protected function update_competency_framework($id, $number = 1, $system = true) {
 262          $scalename = 'scale' . $number;
 263          $scalepropname = 'scaleconfiguration' . $number;
 264          $framework = array(
 265              'id' => $id,
 266              'shortname' => 'shortname' . $number,
 267              'idnumber' => 'idnumber' . $number,
 268              'description' => 'description' . $number,
 269              'descriptionformat' => FORMAT_HTML,
 270              'scaleid' => $this->$scalename->id,
 271              'scaleconfiguration' => $this->$scalepropname,
 272              'visible' => true,
 273              'contextid' => $system ? \context_system::instance()->id : \context_coursecat::instance($this->category->id)->id
 274          );
 275          $result = external::update_competency_framework($framework);
 276          return \external_api::clean_returnvalue(external::update_competency_framework_returns(), $result);
 277      }
 278  
 279      protected function create_competency($number, $frameworkid) {
 280          $competency = array(
 281              'shortname' => 'shortname' . $number,
 282              'idnumber' => 'idnumber' . $number,
 283              'description' => 'description' . $number,
 284              'descriptionformat' => FORMAT_HTML,
 285              'competencyframeworkid' => $frameworkid
 286          );
 287          $result = external::create_competency($competency);
 288          return (object) \external_api::clean_returnvalue(external::create_competency_returns(), $result);
 289      }
 290  
 291      protected function update_competency($id, $number) {
 292          $competency = array(
 293              'id' => $id,
 294              'shortname' => 'shortname' . $number,
 295              'idnumber' => 'idnumber' . $number,
 296              'description' => 'description' . $number,
 297              'descriptionformat' => FORMAT_HTML
 298          );
 299          $result = external::update_competency($competency);
 300          return \external_api::clean_returnvalue(external::update_competency_returns(), $result);
 301      }
 302  
 303      /**
 304       * Test we can't create a competency framework with only read permissions.
 305       */
 306      public function test_create_competency_frameworks_with_read_permissions() {
 307          $this->setUser($this->user);
 308  
 309          $this->expectException(\required_capability_exception::class);
 310          $result = $this->create_competency_framework(1, true);
 311      }
 312  
 313      /**
 314       * Test we can't create a competency framework with only read permissions.
 315       */
 316      public function test_create_competency_frameworks_with_read_permissions_in_category() {
 317          $this->setUser($this->catuser);
 318          $this->expectException(\required_capability_exception::class);
 319          $result = $this->create_competency_framework(1, false);
 320      }
 321  
 322      /**
 323       * Test we can create a competency framework with manage permissions.
 324       */
 325      public function test_create_competency_frameworks_with_manage_permissions() {
 326          $this->setUser($this->creator);
 327          $result = $this->create_competency_framework(1, true);
 328  
 329          $this->assertGreaterThan(0, $result->timecreated);
 330          $this->assertGreaterThan(0, $result->timemodified);
 331          $this->assertEquals($this->creator->id, $result->usermodified);
 332          $this->assertEquals('shortname1', $result->shortname);
 333          $this->assertEquals('idnumber1', $result->idnumber);
 334          $this->assertEquals('description1', $result->description);
 335          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 336          $this->assertEquals($this->scale1->id, $result->scaleid);
 337          $this->assertEquals($this->scaleconfiguration1, $result->scaleconfiguration);
 338          $this->assertEquals(true, $result->visible);
 339      }
 340  
 341      /**
 342       * Test we can create a competency framework with manage permissions.
 343       */
 344      public function test_create_competency_frameworks_with_manage_permissions_in_category() {
 345          $this->setUser($this->catcreator);
 346          $result = $this->create_competency_framework(1, false);
 347  
 348          $this->assertGreaterThan(0, $result->timecreated);
 349          $this->assertGreaterThan(0, $result->timemodified);
 350          $this->assertEquals($this->catcreator->id, $result->usermodified);
 351          $this->assertEquals('shortname1', $result->shortname);
 352          $this->assertEquals('idnumber1', $result->idnumber);
 353          $this->assertEquals('description1', $result->description);
 354          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 355          $this->assertEquals($this->scale1->id, $result->scaleid);
 356          $this->assertEquals($this->scaleconfiguration1, $result->scaleconfiguration);
 357          $this->assertEquals(true, $result->visible);
 358  
 359          try {
 360              $result = $this->create_competency_framework(1, true);
 361              $this->fail('User cannot create a framework at system level.');
 362          } catch (\required_capability_exception $e) {
 363              // All good.
 364          }
 365      }
 366  
 367      /**
 368       * Test we cannot create a competency framework with nasty data.
 369       */
 370      public function test_create_competency_frameworks_with_nasty_data() {
 371          $this->setUser($this->creator);
 372          $framework = array(
 373              'shortname' => 'short<a href="">',
 374              'idnumber' => 'id;"number',
 375              'description' => 'de<>\\..scription',
 376              'descriptionformat' => FORMAT_HTML,
 377              'scaleid' => $this->scale1->id,
 378              'scaleconfiguration' => $this->scaleconfiguration1,
 379              'visible' => true,
 380              'contextid' => \context_system::instance()->id
 381          );
 382          $this->expectException(\invalid_parameter_exception::class);
 383          $result = external::create_competency_framework($framework);
 384      }
 385  
 386      /**
 387       * Test we can read a competency framework with manage permissions.
 388       */
 389      public function test_read_competency_frameworks_with_manage_permissions() {
 390          $this->setUser($this->creator);
 391          $result = $this->create_competency_framework(1, true);
 392  
 393          $id = $result->id;
 394          $result = external::read_competency_framework($id);
 395          $result = (object) \external_api::clean_returnvalue(external::read_competency_framework_returns(), $result);
 396  
 397          $this->assertGreaterThan(0, $result->timecreated);
 398          $this->assertGreaterThan(0, $result->timemodified);
 399          $this->assertEquals($this->creator->id, $result->usermodified);
 400          $this->assertEquals('shortname1', $result->shortname);
 401          $this->assertEquals('idnumber1', $result->idnumber);
 402          $this->assertEquals('description1', $result->description);
 403          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 404          $this->assertEquals($this->scale1->id, $result->scaleid);
 405          $this->assertEquals($this->scaleconfiguration1, $result->scaleconfiguration);
 406          $this->assertEquals(true, $result->visible);
 407      }
 408  
 409      /**
 410       * Test we can read a competency framework with manage permissions.
 411       */
 412      public function test_read_competency_frameworks_with_manage_permissions_in_category() {
 413          $this->setUser($this->creator);
 414  
 415          $insystem = $this->create_competency_framework(1, true);
 416          $incat = $this->create_competency_framework(2, false);
 417  
 418          $this->setUser($this->catcreator);
 419          $id = $incat->id;
 420          $result = external::read_competency_framework($id);
 421          $result = (object) \external_api::clean_returnvalue(external::read_competency_framework_returns(), $result);
 422  
 423          $this->assertGreaterThan(0, $result->timecreated);
 424          $this->assertGreaterThan(0, $result->timemodified);
 425          $this->assertEquals($this->creator->id, $result->usermodified);
 426          $this->assertEquals('shortname2', $result->shortname);
 427          $this->assertEquals('idnumber2', $result->idnumber);
 428          $this->assertEquals('description2', $result->description);
 429          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 430          $this->assertEquals($this->scale2->id, $result->scaleid);
 431          $this->assertEquals($this->scaleconfiguration2, $result->scaleconfiguration);
 432          $this->assertEquals(true, $result->visible);
 433  
 434          try {
 435              $id = $insystem->id;
 436              $result = external::read_competency_framework($id);
 437              $result = (object) \external_api::clean_returnvalue(external::read_competency_framework_returns(), $result);
 438              $this->fail('User cannot read a framework at system level.');
 439          } catch (\required_capability_exception $e) {
 440              // All good.
 441          }
 442      }
 443  
 444      /**
 445       * Test we can read a competency framework with read permissions.
 446       */
 447      public function test_read_competency_frameworks_with_read_permissions() {
 448          $this->setUser($this->creator);
 449          $result = $this->create_competency_framework(1, true);
 450  
 451          // Switch users to someone with less permissions.
 452          $this->setUser($this->user);
 453          $id = $result->id;
 454          $result = external::read_competency_framework($id);
 455          $result = (object) \external_api::clean_returnvalue(external::read_competency_framework_returns(), $result);
 456  
 457          $this->assertGreaterThan(0, $result->timecreated);
 458          $this->assertGreaterThan(0, $result->timemodified);
 459          $this->assertEquals($this->creator->id, $result->usermodified);
 460          $this->assertEquals('shortname1', $result->shortname);
 461          $this->assertEquals('idnumber1', $result->idnumber);
 462          $this->assertEquals('description1', $result->description);
 463          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 464          $this->assertEquals($this->scale1->id, $result->scaleid);
 465          $this->assertEquals($this->scaleconfiguration1, $result->scaleconfiguration);
 466          $this->assertEquals(true, $result->visible);
 467      }
 468      /**
 469       * Test we can read a competency framework with read permissions.
 470       */
 471      public function test_read_competency_frameworks_with_read_permissions_in_category() {
 472          $this->setUser($this->creator);
 473  
 474          $insystem = $this->create_competency_framework(1, true);
 475          $incat = $this->create_competency_framework(2, false);
 476  
 477          // Switch users to someone with less permissions.
 478          $this->setUser($this->catuser);
 479          $id = $incat->id;
 480          $result = external::read_competency_framework($id);
 481          $result = (object) \external_api::clean_returnvalue(external::read_competency_framework_returns(), $result);
 482  
 483          $this->assertGreaterThan(0, $result->timecreated);
 484          $this->assertGreaterThan(0, $result->timemodified);
 485          $this->assertEquals($this->creator->id, $result->usermodified);
 486          $this->assertEquals('shortname2', $result->shortname);
 487          $this->assertEquals('idnumber2', $result->idnumber);
 488          $this->assertEquals('description2', $result->description);
 489          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 490          $this->assertEquals($this->scale2->id, $result->scaleid);
 491          $this->assertEquals($this->scaleconfiguration2, $result->scaleconfiguration);
 492          $this->assertEquals(true, $result->visible);
 493  
 494          // Switching to user with no permissions.
 495          try {
 496              $result = external::read_competency_framework($insystem->id);
 497              $this->fail('Current user cannot should not be able to read the framework.');
 498          } catch (\required_capability_exception $e) {
 499              // All good.
 500          }
 501      }
 502  
 503      /**
 504       * Test we can delete a competency framework with manage permissions.
 505       */
 506      public function test_delete_competency_frameworks_with_manage_permissions() {
 507          $this->setUser($this->creator);
 508          $result = $this->create_competency_framework(1, true);
 509  
 510          $id = $result->id;
 511          $result = external::delete_competency_framework($id);
 512          $result = \external_api::clean_returnvalue(external::delete_competency_framework_returns(), $result);
 513  
 514          $this->assertTrue($result);
 515      }
 516  
 517      /**
 518       * Test we can delete a competency framework with manage permissions.
 519       */
 520      public function test_delete_competency_frameworks_with_manage_permissions_in_category() {
 521          $this->setUser($this->creator);
 522  
 523          $insystem = $this->create_competency_framework(1, true);
 524          $incat = $this->create_competency_framework(2, false);
 525  
 526          $this->setUser($this->catcreator);
 527          $id = $incat->id;
 528          $result = external::delete_competency_framework($id);
 529          $result = \external_api::clean_returnvalue(external::delete_competency_framework_returns(), $result);
 530  
 531          $this->assertTrue($result);
 532  
 533          try {
 534              $id = $insystem->id;
 535              $result = external::delete_competency_framework($id);
 536              $result = \external_api::clean_returnvalue(external::delete_competency_framework_returns(), $result);
 537              $this->fail('Current user cannot should not be able to delete the framework.');
 538          } catch (\required_capability_exception $e) {
 539              // All good.
 540          }
 541      }
 542  
 543      /**
 544       * Test we can delete a competency framework with read permissions.
 545       */
 546      public function test_delete_competency_frameworks_with_read_permissions() {
 547          $this->setUser($this->creator);
 548          $result = $this->create_competency_framework(1, true);
 549  
 550          $id = $result->id;
 551          // Switch users to someone with less permissions.
 552          $this->setUser($this->user);
 553          $this->expectException(\required_capability_exception::class);
 554          $result = external::delete_competency_framework($id);
 555      }
 556  
 557      /**
 558       * Test we can update a competency framework with manage permissions.
 559       */
 560      public function test_update_competency_frameworks_with_manage_permissions() {
 561          $this->setUser($this->creator);
 562          $result = $this->create_competency_framework(1, true);
 563  
 564          $result = $this->update_competency_framework($result->id, 2, true);
 565  
 566          $this->assertTrue($result);
 567      }
 568  
 569      /**
 570       * Test we can update a competency framework with manage permissions.
 571       */
 572      public function test_update_competency_frameworks_with_manage_permissions_in_category() {
 573          $this->setUser($this->creator);
 574  
 575          $insystem = $this->create_competency_framework(1, true);
 576          $incat = $this->create_competency_framework(2, false);
 577  
 578          $this->setUser($this->catcreator);
 579          $id = $incat->id;
 580  
 581          $result = $this->update_competency_framework($incat->id, 3, false);
 582  
 583          $this->assertTrue($result);
 584  
 585          try {
 586              $result = $this->update_competency_framework($insystem->id, 4, true);
 587              $this->fail('Current user should not be able to update the framework.');
 588          } catch (\required_capability_exception $e) {
 589              // All good.
 590          }
 591      }
 592  
 593      public function test_update_framework_scale() {
 594          $this->setUser($this->creator);
 595          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
 596  
 597          $s1 = $this->getDataGenerator()->create_scale();
 598  
 599          $f1 = $lpg->create_framework(array('scaleid' => $s1->id));
 600          $f2 = $lpg->create_framework(array('scaleid' => $s1->id));
 601          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
 602          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f2->get('id')));
 603  
 604          $this->assertEquals($s1->id, $f1->get('scaleid'));
 605  
 606          // Make the scale of f2 being used.
 607          $lpg->create_user_competency(array('userid' => $this->user->id, 'competencyid' => $c2->get('id')));
 608  
 609          // Changing the framework where the scale is not used.
 610          $result = $this->update_competency_framework($f1->get('id'), 3, true);
 611  
 612          $f1 = new \core_competency\competency_framework($f1->get('id'));
 613          $this->assertEquals($this->scale3->id, $f1->get('scaleid'));
 614  
 615          // Changing the framework where the scale is used.
 616          try {
 617              $result = $this->update_competency_framework($f2->get('id'), 4, true);
 618              $this->fail('The scale cannot be changed once used.');
 619          } catch (\core\invalid_persistent_exception $e) {
 620              $this->assertMatchesRegularExpression('/scaleid/', $e->getMessage());
 621          }
 622      }
 623  
 624      /**
 625       * Test we can update a competency framework with read permissions.
 626       */
 627      public function test_update_competency_frameworks_with_read_permissions() {
 628          $this->setUser($this->creator);
 629          $result = $this->create_competency_framework(1, true);
 630  
 631          $this->setUser($this->user);
 632          $this->expectException(\required_capability_exception::class);
 633          $result = $this->update_competency_framework($result->id, 2, true);
 634      }
 635  
 636      /**
 637       * Test we can list and count competency frameworks with manage permissions.
 638       */
 639      public function test_list_and_count_competency_frameworks_with_manage_permissions() {
 640          $this->setUser($this->creator);
 641          $result = $this->create_competency_framework(1, true);
 642          $result = $this->create_competency_framework(2, true);
 643          $result = $this->create_competency_framework(3, true);
 644          $result = $this->create_competency_framework(4, false);
 645  
 646          $result = external::count_competency_frameworks(array('contextid' => \context_system::instance()->id), 'self');
 647          $result = \external_api::clean_returnvalue(external::count_competency_frameworks_returns(), $result);
 648  
 649          $this->assertEquals($result, 3);
 650  
 651          $result = external::list_competency_frameworks('shortname', 'ASC', 0, 10,
 652              array('contextid' => \context_system::instance()->id), 'self', false);
 653          $result = \external_api::clean_returnvalue(external::list_competency_frameworks_returns(), $result);
 654  
 655          $this->assertEquals(count($result), 3);
 656          $result = (object) $result[0];
 657  
 658          $this->assertGreaterThan(0, $result->timecreated);
 659          $this->assertGreaterThan(0, $result->timemodified);
 660          $this->assertEquals($this->creator->id, $result->usermodified);
 661          $this->assertEquals('shortname1', $result->shortname);
 662          $this->assertEquals('idnumber1', $result->idnumber);
 663          $this->assertEquals('description1', $result->description);
 664          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 665          $this->assertEquals($this->scale1->id, $result->scaleid);
 666          $this->assertEquals($this->scaleconfiguration1, $result->scaleconfiguration);
 667          $this->assertEquals(true, $result->visible);
 668      }
 669  
 670      public function test_list_competency_frameworks_with_query() {
 671          $this->setUser($this->creator);
 672          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
 673          $framework1 = $lpg->create_framework(array(
 674              'shortname' => 'shortname_beetroot',
 675              'idnumber' => 'idnumber_cinnamon',
 676              'description' => 'description',
 677              'descriptionformat' => FORMAT_HTML,
 678              'visible' => true,
 679              'contextid' => \context_system::instance()->id
 680          ));
 681          $framework2 = $lpg->create_framework(array(
 682              'shortname' => 'shortname_citrus',
 683              'idnumber' => 'idnumber_beer',
 684              'description' => 'description',
 685              'descriptionformat' => FORMAT_HTML,
 686              'visible' => true,
 687              'contextid' => \context_system::instance()->id
 688          ));
 689  
 690          // Search on both ID number and shortname.
 691          $result = external::list_competency_frameworks('shortname', 'ASC', 0, 10,
 692              array('contextid' => \context_system::instance()->id), 'self', false, 'bee');
 693          $result = \external_api::clean_returnvalue(external::list_competency_frameworks_returns(), $result);
 694          $this->assertCount(2, $result);
 695          $f = (object) array_shift($result);
 696          $this->assertEquals($framework1->get('id'), $f->id);
 697          $f = (object) array_shift($result);
 698          $this->assertEquals($framework2->get('id'), $f->id);
 699  
 700          // Search on ID number.
 701          $result = external::list_competency_frameworks('shortname', 'ASC', 0, 10,
 702              array('contextid' => \context_system::instance()->id), 'self', false, 'beer');
 703          $result = \external_api::clean_returnvalue(external::list_competency_frameworks_returns(), $result);
 704          $this->assertCount(1, $result);
 705          $f = (object) array_shift($result);
 706          $this->assertEquals($framework2->get('id'), $f->id);
 707  
 708          // Search on shortname.
 709          $result = external::list_competency_frameworks('shortname', 'ASC', 0, 10,
 710              array('contextid' => \context_system::instance()->id), 'self', false, 'cinnamon');
 711          $result = \external_api::clean_returnvalue(external::list_competency_frameworks_returns(), $result);
 712          $this->assertCount(1, $result);
 713          $f = (object) array_shift($result);
 714          $this->assertEquals($framework1->get('id'), $f->id);
 715  
 716          // No match.
 717          $result = external::list_competency_frameworks('shortname', 'ASC', 0, 10,
 718              array('contextid' => \context_system::instance()->id), 'self', false, 'pwnd!');
 719          $result = \external_api::clean_returnvalue(external::list_competency_frameworks_returns(), $result);
 720          $this->assertCount(0, $result);
 721      }
 722  
 723      /**
 724       * Test we can list and count competency frameworks with read permissions.
 725       */
 726      public function test_list_and_count_competency_frameworks_with_read_permissions() {
 727          $this->setUser($this->creator);
 728          $result = $this->create_competency_framework(1, true);
 729          $result = $this->create_competency_framework(2, true);
 730          $result = $this->create_competency_framework(3, true);
 731          $result = $this->create_competency_framework(4, false);
 732  
 733          $this->setUser($this->user);
 734          $result = external::count_competency_frameworks(array('contextid' => \context_system::instance()->id), 'self');
 735          $result = \external_api::clean_returnvalue(external::count_competency_frameworks_returns(), $result);
 736          $this->assertEquals($result, 3);
 737  
 738          $result = external::list_competency_frameworks('shortname', 'ASC', 0, 10,
 739              array('contextid' => \context_system::instance()->id), 'self', false);
 740          $result = \external_api::clean_returnvalue(external::list_competency_frameworks_returns(), $result);
 741  
 742          $this->assertEquals(count($result), 3);
 743          $result = (object) $result[0];
 744  
 745          $this->assertGreaterThan(0, $result->timecreated);
 746          $this->assertGreaterThan(0, $result->timemodified);
 747          $this->assertEquals($this->creator->id, $result->usermodified);
 748          $this->assertEquals('shortname1', $result->shortname);
 749          $this->assertEquals('idnumber1', $result->idnumber);
 750          $this->assertEquals('description1', $result->description);
 751          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 752          $this->assertEquals($this->scale1->id, $result->scaleid);
 753          $this->assertEquals($this->scaleconfiguration1, $result->scaleconfiguration);
 754          $this->assertEquals(true, $result->visible);
 755      }
 756  
 757      /**
 758       * Test we can't create a competency with only read permissions.
 759       */
 760      public function test_create_competency_with_read_permissions() {
 761          $framework = $this->getDataGenerator()->get_plugin_generator('core_competency')->create_framework();
 762          $this->setUser($this->user);
 763          $this->expectException(\required_capability_exception::class);
 764          $competency = $this->create_competency(1, $framework->get('id'));
 765      }
 766  
 767      /**
 768       * Test we can create a competency with manage permissions.
 769       */
 770      public function test_create_competency_with_manage_permissions() {
 771          $this->setUser($this->creator);
 772          $framework = $this->create_competency_framework(1, true);
 773          $competency = $this->create_competency(1, $framework->id);
 774  
 775          $this->assertGreaterThan(0, $competency->timecreated);
 776          $this->assertGreaterThan(0, $competency->timemodified);
 777          $this->assertEquals($this->creator->id, $competency->usermodified);
 778          $this->assertEquals('shortname1', $competency->shortname);
 779          $this->assertEquals('idnumber1', $competency->idnumber);
 780          $this->assertEquals('description1', $competency->description);
 781          $this->assertEquals(FORMAT_HTML, $competency->descriptionformat);
 782          $this->assertEquals(0, $competency->parentid);
 783          $this->assertEquals($framework->id, $competency->competencyframeworkid);
 784      }
 785  
 786  
 787      /**
 788       * Test we can create a competency with manage permissions.
 789       */
 790      public function test_create_competency_with_manage_permissions_in_category() {
 791          $this->setUser($this->creator);
 792  
 793          $insystem = $this->create_competency_framework(1, true);
 794          $incat = $this->create_competency_framework(2, false);
 795  
 796          $this->setUser($this->catcreator);
 797  
 798          $competency = $this->create_competency(1, $incat->id);
 799  
 800          $this->assertGreaterThan(0, $competency->timecreated);
 801          $this->assertGreaterThan(0, $competency->timemodified);
 802          $this->assertEquals($this->catcreator->id, $competency->usermodified);
 803          $this->assertEquals('shortname1', $competency->shortname);
 804          $this->assertEquals('idnumber1', $competency->idnumber);
 805          $this->assertEquals('description1', $competency->description);
 806          $this->assertEquals(FORMAT_HTML, $competency->descriptionformat);
 807          $this->assertEquals(0, $competency->parentid);
 808          $this->assertEquals($incat->id, $competency->competencyframeworkid);
 809  
 810          try {
 811              $competency = $this->create_competency(2, $insystem->id);
 812              $this->fail('User should not be able to create a competency in system context.');
 813          } catch (\required_capability_exception $e) {
 814              // All good.
 815          }
 816      }
 817  
 818      /**
 819       * Test we cannot create a competency with nasty data.
 820       */
 821      public function test_create_competency_with_nasty_data() {
 822          $this->setUser($this->creator);
 823          $framework = $this->create_competency_framework(1, true);
 824          $competency = array(
 825              'shortname' => 'shortname<a href="">',
 826              'idnumber' => 'id;"number',
 827              'description' => 'de<>\\..scription',
 828              'descriptionformat' => FORMAT_HTML,
 829              'competencyframeworkid' => $framework->id,
 830              'sortorder' => 0
 831          );
 832  
 833          $this->expectException(\invalid_parameter_exception::class);
 834          $this->expectExceptionMessage('Invalid external api parameter');
 835          $result = external::create_competency($competency);
 836      }
 837  
 838      /**
 839       * Test we can read a competency with manage permissions.
 840       */
 841      public function test_read_competencies_with_manage_permissions() {
 842          $this->setUser($this->creator);
 843          $framework = $this->create_competency_framework(1, true);
 844          $competency = $this->create_competency(1, $framework->id);
 845  
 846          $id = $competency->id;
 847          $result = external::read_competency($id);
 848          $result = (object) \external_api::clean_returnvalue(external::read_competency_returns(), $result);
 849  
 850          $this->assertGreaterThan(0, $result->timecreated);
 851          $this->assertGreaterThan(0, $result->timemodified);
 852          $this->assertEquals($this->creator->id, $result->usermodified);
 853          $this->assertEquals('shortname1', $result->shortname);
 854          $this->assertEquals('idnumber1', $result->idnumber);
 855          $this->assertEquals('description1', $result->description);
 856          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 857          $this->assertEquals(0, $result->parentid);
 858          $this->assertEquals($framework->id, $result->competencyframeworkid);
 859      }
 860  
 861      /**
 862       * Test we can read a competency with manage permissions.
 863       */
 864      public function test_read_competencies_with_manage_permissions_in_category() {
 865          $this->setUser($this->creator);
 866  
 867          $sysframework = $this->create_competency_framework(1, true);
 868          $insystem = $this->create_competency(1, $sysframework->id);
 869  
 870          $catframework = $this->create_competency_framework(2, false);
 871          $incat = $this->create_competency(2, $catframework->id);
 872  
 873          $this->setUser($this->catcreator);
 874          $id = $incat->id;
 875          $result = external::read_competency($id);
 876          $result = (object) \external_api::clean_returnvalue(external::read_competency_returns(), $result);
 877  
 878          $this->assertGreaterThan(0, $result->timecreated);
 879          $this->assertGreaterThan(0, $result->timemodified);
 880          $this->assertEquals($this->creator->id, $result->usermodified);
 881          $this->assertEquals('shortname2', $result->shortname);
 882          $this->assertEquals('idnumber2', $result->idnumber);
 883          $this->assertEquals('description2', $result->description);
 884          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 885          $this->assertEquals(0, $result->parentid);
 886          $this->assertEquals($catframework->id, $result->competencyframeworkid);
 887  
 888          try {
 889              external::read_competency($insystem->id);
 890              $this->fail('User should not be able to read a competency in system context.');
 891          } catch (\required_capability_exception $e) {
 892              // All good.
 893          }
 894      }
 895  
 896      /**
 897       * Test we can read a competency with read permissions.
 898       */
 899      public function test_read_competencies_with_read_permissions() {
 900          $this->setUser($this->creator);
 901          $framework = $this->create_competency_framework(1, true);
 902          $competency = $this->create_competency(1, $framework->id);
 903  
 904          // Switch users to someone with less permissions.
 905          $this->setUser($this->user);
 906          $id = $competency->id;
 907          $result = external::read_competency($id);
 908          $result = (object) \external_api::clean_returnvalue(external::read_competency_returns(), $result);
 909  
 910          $this->assertGreaterThan(0, $result->timecreated);
 911          $this->assertGreaterThan(0, $result->timemodified);
 912          $this->assertEquals($this->creator->id, $result->usermodified);
 913          $this->assertEquals('shortname1', $result->shortname);
 914          $this->assertEquals('idnumber1', $result->idnumber);
 915          $this->assertEquals('description1', $result->description);
 916          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 917          $this->assertEquals(0, $result->parentid);
 918          $this->assertEquals($framework->id, $result->competencyframeworkid);
 919      }
 920  
 921      /**
 922       * Test we can read a competency with read permissions.
 923       */
 924      public function test_read_competencies_with_read_permissions_in_category() {
 925          $this->setUser($this->creator);
 926          $sysframework = $this->create_competency_framework(1, true);
 927          $insystem = $this->create_competency(1, $sysframework->id);
 928          $catframework = $this->create_competency_framework(2, false);
 929          $incat = $this->create_competency(2, $catframework->id);
 930  
 931          // Switch users to someone with less permissions.
 932          $this->setUser($this->catuser);
 933          $id = $incat->id;
 934          $result = external::read_competency($id);
 935          $result = (object) \external_api::clean_returnvalue(external::read_competency_returns(), $result);
 936  
 937          $this->assertGreaterThan(0, $result->timecreated);
 938          $this->assertGreaterThan(0, $result->timemodified);
 939          $this->assertEquals($this->creator->id, $result->usermodified);
 940          $this->assertEquals('shortname2', $result->shortname);
 941          $this->assertEquals('idnumber2', $result->idnumber);
 942          $this->assertEquals('description2', $result->description);
 943          $this->assertEquals(FORMAT_HTML, $result->descriptionformat);
 944          $this->assertEquals(0, $result->parentid);
 945          $this->assertEquals($catframework->id, $result->competencyframeworkid);
 946  
 947          try {
 948              external::read_competency($insystem->id);
 949              $this->fail('User should not be able to read a competency in system context.');
 950          } catch (\required_capability_exception $e) {
 951              // All good.
 952          }
 953      }
 954  
 955      /**
 956       * Test we can delete a competency with manage permissions.
 957       */
 958      public function test_delete_competency_with_manage_permissions() {
 959          $this->setUser($this->creator);
 960          $framework = $this->create_competency_framework(1, true);
 961          $result = $this->create_competency(1, $framework->id);
 962  
 963          $id = $result->id;
 964          $result = external::delete_competency($id);
 965          $result = \external_api::clean_returnvalue(external::delete_competency_returns(), $result);
 966  
 967          $this->assertTrue($result);
 968      }
 969  
 970      /**
 971       * Test we can delete a competency with manage permissions.
 972       */
 973      public function test_delete_competency_with_manage_permissions_in_category() {
 974          $this->setUser($this->creator);
 975  
 976          $sysframework = $this->create_competency_framework(1, true);
 977          $insystem = $this->create_competency(1, $sysframework->id);
 978          $catframework = $this->create_competency_framework(2, false);
 979          $incat = $this->create_competency(2, $catframework->id);
 980  
 981          $this->setUser($this->catcreator);
 982          $id = $incat->id;
 983          $result = external::delete_competency($id);
 984          $result = \external_api::clean_returnvalue(external::delete_competency_returns(), $result);
 985  
 986          $this->assertTrue($result);
 987  
 988          try {
 989              $result = external::delete_competency($insystem->id);
 990              $this->fail('User should not be able to delete a competency in system context.');
 991          } catch (\required_capability_exception $e) {
 992              // All good.
 993          }
 994      }
 995  
 996      /**
 997       * Test we can delete a competency with read permissions.
 998       */
 999      public function test_delete_competency_with_read_permissions() {
1000          $this->setUser($this->creator);
1001          $framework = $this->create_competency_framework(1, true);
1002          $result = $this->create_competency(1, $framework->id);
1003  
1004          $id = $result->id;
1005          // Switch users to someone with less permissions.
1006          $this->setUser($this->user);
1007          $this->expectException(\required_capability_exception::class);
1008          $result = external::delete_competency($id);
1009      }
1010  
1011      /**
1012       * Test we can update a competency with manage permissions.
1013       */
1014      public function test_update_competency_with_manage_permissions() {
1015          $this->setUser($this->creator);
1016          $framework = $this->create_competency_framework(1, true);
1017          $result = $this->create_competency(1, $framework->id);
1018  
1019          $result = $this->update_competency($result->id, 2);
1020  
1021          $this->assertTrue($result);
1022      }
1023  
1024      /**
1025       * Test we can update a competency with manage permissions.
1026       */
1027      public function test_update_competency_with_manage_permissions_in_category() {
1028          $this->setUser($this->creator);
1029  
1030          $sysframework = $this->create_competency_framework(1, true);
1031          $insystem = $this->create_competency(1, $sysframework->id);
1032          $catframework = $this->create_competency_framework(2, false);
1033          $incat = $this->create_competency(2, $catframework->id);
1034  
1035          $this->setUser($this->catcreator);
1036  
1037          $result = $this->update_competency($incat->id, 2);
1038  
1039          $this->assertTrue($result);
1040  
1041          try {
1042              $result = $this->update_competency($insystem->id, 3);
1043              $this->fail('User should not be able to update a competency in system context.');
1044          } catch (\required_capability_exception $e) {
1045              // All good.
1046          }
1047      }
1048  
1049      /**
1050       * Test we can update a competency with read permissions.
1051       */
1052      public function test_update_competency_with_read_permissions() {
1053          $this->setUser($this->creator);
1054          $framework = $this->create_competency_framework(1, true);
1055          $result = $this->create_competency(1, $framework->id);
1056  
1057          $this->setUser($this->user);
1058          $this->expectException(\required_capability_exception::class);
1059          $result = $this->update_competency($result->id, 2);
1060      }
1061  
1062      /**
1063       * Test count competencies with filters.
1064       */
1065      public function test_count_competencies_with_filters() {
1066          $this->setUser($this->creator);
1067  
1068          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1069          $f1 = $lpg->create_framework();
1070          $f2 = $lpg->create_framework();
1071          $c1 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
1072          $c2 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id'), 'shortname' => 'A'));
1073          $c3 = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
1074          $c4 = $lpg->create_competency(array('competencyframeworkid' => $f2->get('id')));
1075          $c5 = $lpg->create_competency(array('competencyframeworkid' => $f2->get('id')));
1076  
1077          $result = external::count_competencies(array(array('column' => 'competencyframeworkid', 'value' => $f2->get('id'))));
1078          $result = \external_api::clean_returnvalue(external::count_competencies_returns(), $result);
1079          $this->assertEquals(2, $result);
1080  
1081          $result = external::count_competencies(array(array('column' => 'competencyframeworkid', 'value' => $f1->get('id'))));
1082          $result = \external_api::clean_returnvalue(external::count_competencies_returns(), $result);
1083          $this->assertEquals(3, $result);
1084  
1085          $result = external::count_competencies(array(array('column' => 'shortname', 'value' => 'A')));
1086          $result = \external_api::clean_returnvalue(external::count_competencies_returns(), $result);
1087          $this->assertEquals(1, $result);
1088      }
1089  
1090      /**
1091       * Test we can list and count competencies with manage permissions.
1092       */
1093      public function test_list_and_count_competencies_with_manage_permissions() {
1094          $this->setUser($this->creator);
1095          $framework = $this->create_competency_framework(1, true);
1096          $result = $this->create_competency(1, $framework->id);
1097          $result = $this->create_competency(2, $framework->id);
1098          $result = $this->create_competency(3, $framework->id);
1099  
1100          $result = external::count_competencies(array());
1101          $result = \external_api::clean_returnvalue(external::count_competencies_returns(), $result);
1102  
1103          $this->assertEquals($result, 3);
1104  
1105          array('id' => $result = external::list_competencies(array(), 'shortname', 'ASC', 0, 10, \context_system::instance()->id));
1106          $result = \external_api::clean_returnvalue(external::list_competencies_returns(), $result);
1107  
1108          $this->assertEquals(count($result), 3);
1109          $result = (object) $result[0];
1110  
1111          $this->assertGreaterThan(0, $result->timecreated);
1112          $this->assertGreaterThan(0, $result->timemodified);
1113          $this->assertEquals($this->creator->id, $result->usermodified);
1114          $this->assertEquals('shortname1', $result->shortname);
1115          $this->assertEquals('idnumber1', $result->idnumber);
1116          $this->assertEquals('description1', $result->description);
1117      }
1118  
1119      /**
1120       * Test we can list and count competencies with read permissions.
1121       */
1122      public function test_list_and_count_competencies_with_read_permissions() {
1123          $this->setUser($this->creator);
1124          $framework = $this->create_competency_framework(1, true);
1125          $result = $this->create_competency(1, $framework->id);
1126          $result = $this->create_competency(2, $framework->id);
1127          $result = $this->create_competency(3, $framework->id);
1128  
1129          $this->setUser($this->user);
1130  
1131          $result = external::count_competencies(array());
1132          $result = \external_api::clean_returnvalue(external::count_competencies_returns(), $result);
1133  
1134          $this->assertEquals($result, 3);
1135  
1136          array('id' => $result = external::list_competencies(array(), 'shortname', 'ASC', 0, 10, \context_system::instance()->id));
1137          $result = \external_api::clean_returnvalue(external::list_competencies_returns(), $result);
1138  
1139          $this->assertEquals(count($result), 3);
1140          $result = (object) $result[0];
1141  
1142          $this->assertGreaterThan(0, $result->timecreated);
1143          $this->assertGreaterThan(0, $result->timemodified);
1144          $this->assertEquals($this->creator->id, $result->usermodified);
1145          $this->assertEquals('shortname1', $result->shortname);
1146          $this->assertEquals('idnumber1', $result->idnumber);
1147          $this->assertEquals('description1', $result->description);
1148      }
1149  
1150      /**
1151       * Test we can search for competencies.
1152       */
1153      public function test_search_competencies_with_read_permissions() {
1154          $this->setUser($this->creator);
1155          $framework = $this->create_competency_framework(1, true);
1156          $result = $this->create_competency(1, $framework->id);
1157          $result = $this->create_competency(2, $framework->id);
1158          $result = $this->create_competency(3, $framework->id);
1159  
1160          $this->setUser($this->user);
1161  
1162          $result = external::search_competencies('short', $framework->id);
1163          $result = \external_api::clean_returnvalue(external::search_competencies_returns(), $result);
1164  
1165          $this->assertEquals(count($result), 3);
1166          $result = (object) $result[0];
1167  
1168          $this->assertGreaterThan(0, $result->timecreated);
1169          $this->assertGreaterThan(0, $result->timemodified);
1170          $this->assertEquals($this->creator->id, $result->usermodified);
1171          $this->assertEquals('shortname1', $result->shortname);
1172          $this->assertEquals('idnumber1', $result->idnumber);
1173          $this->assertEquals('description1', $result->description);
1174      }
1175  
1176      /**
1177       * Test plans creation and updates.
1178       */
1179      public function test_create_and_update_plans() {
1180          $syscontext = \context_system::instance();
1181  
1182          $this->setUser($this->creator);
1183          $plan0 = $this->create_plan(1, $this->creator->id, 0, plan::STATUS_ACTIVE, 0);
1184  
1185          $this->setUser($this->user);
1186  
1187          try {
1188              $plan1 = $this->create_plan(2, $this->user->id, 0, plan::STATUS_DRAFT, 0);
1189              $this->fail('Exception expected due to not permissions to create draft plans');
1190          } catch (\moodle_exception $e) {
1191              $this->assertEquals('nopermissions', $e->errorcode);
1192          }
1193  
1194          assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $this->userrole, $syscontext->id);
1195          accesslib_clear_all_caches_for_unit_testing();
1196  
1197          $this->setUser($this->user);
1198  
1199          $plan2 = $this->create_plan(3, $this->user->id, 0, plan::STATUS_DRAFT, 0);
1200  
1201          // Basic update on the plan.
1202          $this->assertNotEquals('Updated plan 2 name', $plan2->name);
1203          $plan2 = external::update_plan(['id' => $plan2->id, 'name' => 'Updated plan 2 name']);
1204          $this->assertEquals('Updated plan 2 name', $plan2->name);
1205  
1206          try {
1207              $plan3 = $this->create_plan(4, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1208              $this->fail('Exception expected due to not permissions to create active plans');
1209          } catch (\moodle_exception $e) {
1210              $this->assertEquals('nopermissions', $e->errorcode);
1211          }
1212          try {
1213              $plan3 = $this->update_plan($plan2->id, 4, $this->user->id, 0, plan::STATUS_COMPLETE, 0);
1214              $this->fail('We cannot complete a plan using api::update_plan().');
1215          } catch (\coding_exception $e) {
1216              $this->assertTrue(true);
1217          }
1218  
1219          assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $this->userrole, $syscontext->id);
1220          accesslib_clear_all_caches_for_unit_testing();
1221  
1222          $plan3 = $this->create_plan(4, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1223          try {
1224              $plan4 = $this->create_plan(6, $this->creator->id, 0, plan::STATUS_COMPLETE, 0);
1225              $this->fail('Plans cannot be created as complete.');
1226          } catch (\coding_exception $e) {
1227              $this->assertMatchesRegularExpression('/A plan cannot be created as complete./', $e->getMessage());
1228          }
1229  
1230          try {
1231              $plan0 = $this->update_plan($plan0->id, 1, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1232          } catch (\moodle_exception $e) {
1233              $this->assertEquals('nopermissions', $e->errorcode);
1234          }
1235  
1236          unassign_capability('moodle/competency:planmanageown', $this->userrole, $syscontext->id);
1237          unassign_capability('moodle/competency:planmanageowndraft', $this->userrole, $syscontext->id);
1238          accesslib_clear_all_caches_for_unit_testing();
1239  
1240          try {
1241              // Cannot be updated even if they created it.
1242              $this->update_plan($plan2->id, 1, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1243              $this->fail('The user can not update their own plan without permissions.');
1244          } catch (\required_capability_exception $e) {
1245              $this->assertMatchesRegularExpression('/Manage learning plans./', $e->getMessage());
1246          }
1247      }
1248  
1249      /**
1250       * Test complete plan.
1251       */
1252      public function test_complete_plan() {
1253          $syscontext = \context_system::instance();
1254  
1255          $this->setUser($this->creator);
1256  
1257          $this->setUser($this->user);
1258  
1259          assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $this->userrole, $syscontext->id);
1260          assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $this->userrole, $syscontext->id);
1261          accesslib_clear_all_caches_for_unit_testing();
1262  
1263          $this->setUser($this->user);
1264  
1265          $plan = $this->create_plan(1, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1266  
1267          $result = external::complete_plan($plan->id);
1268          $this->assertTrue($result);
1269      }
1270  
1271      /**
1272       * Test reopen plan.
1273       */
1274      public function test_reopen_plan() {
1275          $syscontext = \context_system::instance();
1276  
1277          $this->setUser($this->creator);
1278  
1279          $this->setUser($this->user);
1280  
1281          assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $this->userrole, $syscontext->id);
1282          assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $this->userrole, $syscontext->id);
1283          accesslib_clear_all_caches_for_unit_testing();
1284  
1285          $this->setUser($this->user);
1286  
1287          $plan = $this->create_plan(1, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1288          external::complete_plan($plan->id);
1289  
1290          $result = external::reopen_plan($plan->id);
1291          $this->assertTrue($result);
1292      }
1293  
1294      /**
1295       * Test that we can read plans.
1296       */
1297      public function test_read_plans() {
1298          global $OUTPUT;
1299          $this->setUser($this->creator);
1300  
1301          $syscontext = \context_system::instance();
1302  
1303          $plan1 = $this->create_plan(1, $this->user->id, 0, plan::STATUS_DRAFT, 0);
1304          $plan2 = $this->create_plan(2, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1305          $plan3 = $this->create_plan(3, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1306          external::complete_plan($plan3->id);
1307          $plan3 = (object) external::read_plan($plan3->id);
1308  
1309          $data = external::read_plan($plan1->id);
1310          $this->assertEquals((array)$plan1, external::read_plan($plan1->id));
1311          $data = external::read_plan($plan2->id);
1312          $this->assertEquals((array)$plan2, external::read_plan($plan2->id));
1313          $data = external::read_plan($plan3->id);
1314          $this->assertEquals((array)$plan3, external::read_plan($plan3->id));
1315  
1316          $this->setUser($this->user);
1317  
1318          // The normal user can not edit these plans.
1319          $plan1->canmanage = false;
1320          $plan2->canmanage = false;
1321          $plan3->canmanage = false;
1322          $plan1->canbeedited = false;
1323          $plan2->canbeedited = false;
1324          $plan3->canbeedited = false;
1325          $plan1->canrequestreview = true;
1326          $plan2->canrequestreview = true;
1327          $plan3->canrequestreview = true;
1328          $plan1->canreview = false;
1329          $plan2->canreview = false;
1330          $plan3->canreview = false;
1331          $plan1->iscompleteallowed = false;
1332          $plan2->iscompleteallowed = false;
1333          $plan3->iscompleteallowed = false;
1334          $plan1->isrequestreviewallowed = true;
1335          $plan2->isrequestreviewallowed = true;
1336          $plan3->isrequestreviewallowed = true;
1337          $plan1->isapproveallowed = false;
1338          $plan2->isapproveallowed = false;
1339          $plan3->isapproveallowed = false;
1340          $plan1->isunapproveallowed = false;
1341          $plan2->isunapproveallowed = false;
1342          $plan3->isunapproveallowed = false;
1343          $plan3->isreopenallowed = false;
1344          $plan1->commentarea['canpost'] = false;
1345          $plan1->commentarea['canview'] = true;
1346  
1347          // Prevent the user from seeing their own non-draft plans.
1348          assign_capability('moodle/competency:plancommentown', CAP_PROHIBIT, $this->userrole, $syscontext->id, true);
1349          assign_capability('moodle/competency:planviewown', CAP_PROHIBIT, $this->userrole, $syscontext->id, true);
1350          assign_capability('moodle/competency:planviewowndraft', CAP_ALLOW, $this->userrole, $syscontext->id, true);
1351          accesslib_clear_all_caches_for_unit_testing();
1352  
1353          $this->assertEquals((array)$plan1, external::read_plan($plan1->id));
1354  
1355          try {
1356              external::read_plan($plan2->id);
1357              $this->fail('Exception expected due to not permissions to read plan');
1358          } catch (\moodle_exception $e) {
1359              $this->assertEquals('nopermissions', $e->errorcode);
1360          }
1361          try {
1362              external::read_plan($plan3->id);
1363              $this->fail('Exception expected due to not permissions to read plan');
1364          } catch (\moodle_exception $e) {
1365              $this->assertEquals('nopermissions', $e->errorcode);
1366          }
1367  
1368          // Allow user to see their plan.
1369          assign_capability('moodle/competency:plancommentown', CAP_ALLOW, $this->userrole, $syscontext->id, true);
1370          assign_capability('moodle/competency:planviewown', CAP_ALLOW, $this->userrole, $syscontext->id, true);
1371          assign_capability('moodle/competency:planmanageowndraft', CAP_PROHIBIT, $this->userrole, $syscontext->id, true);
1372          accesslib_clear_all_caches_for_unit_testing();
1373  
1374          $plan1->commentarea['canpost'] = true;
1375          $plan1->commentarea['canview'] = true;
1376          $plan2->commentarea['canpost'] = true;
1377          $plan2->isrequestreviewallowed = false;
1378          $plan3->commentarea['canpost'] = true;
1379          $plan3->isrequestreviewallowed = false;
1380          $plan1->commentarea['canpostorhascomments'] = true;
1381          $plan2->commentarea['canpostorhascomments'] = true;
1382          $plan3->commentarea['canpostorhascomments'] = true;
1383  
1384          $this->assertEquals((array)$plan1, external::read_plan($plan1->id));
1385          $this->assertEquals((array)$plan2, external::read_plan($plan2->id));
1386          $this->assertEquals((array)$plan3, external::read_plan($plan3->id));
1387  
1388          // Allow use to manage their own draft plan.
1389          assign_capability('moodle/competency:planviewown', CAP_PROHIBIT, $this->userrole, $syscontext->id, true);
1390          assign_capability('moodle/competency:planmanageown', CAP_PROHIBIT, $this->userrole, $syscontext->id, true);
1391          assign_capability('moodle/competency:planmanageowndraft', CAP_ALLOW, $this->userrole, $syscontext->id, true);
1392          accesslib_clear_all_caches_for_unit_testing();
1393  
1394          $plan1->canmanage = true;
1395          $plan1->canbeedited = true;
1396          $plan1->canrequestreview = true;
1397          $plan1->isrequestreviewallowed = true;
1398          $this->assertEquals((array)$plan1, external::read_plan($plan1->id));
1399          try {
1400              external::read_plan($plan2->id);
1401              $this->fail('Exception expected due to not permissions to read plan');
1402          } catch (\moodle_exception $e) {
1403              $this->assertEquals('nopermissions', $e->errorcode);
1404          }
1405          try {
1406              external::read_plan($plan3->id);
1407              $this->fail('Exception expected due to not permissions to read plan');
1408          } catch (\moodle_exception $e) {
1409              $this->assertEquals('nopermissions', $e->errorcode);
1410          }
1411  
1412          // Allow use to manage their plan.
1413          assign_capability('moodle/competency:planviewown', CAP_PROHIBIT, $this->userrole, $syscontext->id, true);
1414          assign_capability('moodle/competency:planmanageowndraft', CAP_PROHIBIT, $this->userrole, $syscontext->id, true);
1415          assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $this->userrole, $syscontext->id, true);
1416          accesslib_clear_all_caches_for_unit_testing();
1417  
1418          $plan1->canmanage = false;
1419          $plan1->canbeedited = false;
1420          $plan1->canrequestreview = true;
1421          $plan1->canreview = true;
1422          $plan1->isrequestreviewallowed = true;
1423          $plan1->isapproveallowed = true;
1424          $plan1->iscompleteallowed = false;
1425  
1426          $plan2->canmanage = true;
1427          $plan2->canbeedited = true;
1428          $plan2->canreview = true;
1429          $plan2->iscompleteallowed = true;
1430          $plan2->isunapproveallowed = true;
1431  
1432          $plan3->canmanage = true;
1433          $plan3->canreview = true;
1434          $plan3->isreopenallowed = true;
1435  
1436          $this->assertEquals((array)$plan1, external::read_plan($plan1->id));
1437          $this->assertEquals((array)$plan2, external::read_plan($plan2->id));
1438          $this->assertEquals((array)$plan3, external::read_plan($plan3->id));
1439      }
1440  
1441      public function test_delete_plans() {
1442          $this->setUser($this->creator);
1443  
1444          $syscontext = \context_system::instance();
1445  
1446          $plan1 = $this->create_plan(1, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1447          $plan2 = $this->create_plan(2, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1448          $plan3 = $this->create_plan(3, $this->creator->id, 0, plan::STATUS_ACTIVE, 0);
1449  
1450          $this->assertTrue(external::delete_plan($plan1->id));
1451  
1452          unassign_capability('moodle/competency:planmanage', $this->creatorrole, $syscontext->id);
1453          accesslib_clear_all_caches_for_unit_testing();
1454  
1455          try {
1456              external::delete_plan($plan2->id);
1457              $this->fail('Exception expected due to not permissions to manage plans');
1458          } catch (\moodle_exception $e) {
1459              $this->assertEquals('nopermissions', $e->errorcode);
1460          }
1461  
1462          $this->setUser($this->user);
1463  
1464          // Can not delete plans created by other users.
1465          try {
1466              external::delete_plan($plan2->id);
1467              $this->fail('Exception expected due to not permissions to manage plans');
1468          } catch (\moodle_exception $e) {
1469              $this->assertEquals('nopermissions', $e->errorcode);
1470          }
1471  
1472          assign_capability('moodle/competency:planmanageown', CAP_ALLOW, $this->userrole, $syscontext->id);
1473          accesslib_clear_all_caches_for_unit_testing();
1474  
1475          $this->assertTrue(external::delete_plan($plan2->id));
1476  
1477          // Can not delete plans created for other users.
1478          try {
1479              external::delete_plan($plan3->id);
1480              $this->fail('Exception expected due to not permissions to manage plans');
1481          } catch (\moodle_exception $e) {
1482              $this->assertEquals('nopermissions', $e->errorcode);
1483          }
1484  
1485          $plan4 = $this->create_plan(4, $this->user->id, 0, plan::STATUS_ACTIVE, 0);
1486          $this->assertTrue(external::delete_plan($plan4->id));
1487      }
1488  
1489      public function test_delete_plan_removes_relations() {
1490          $this->setAdminUser();
1491          $dg = $this->getDataGenerator();
1492          $lpg = $dg->get_plugin_generator('core_competency');
1493  
1494          $user = $dg->create_user();
1495          $plan = $lpg->create_plan(array('userid' => $user->id));
1496          $framework = $lpg->create_framework();
1497          $comp1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1498          $comp2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1499          $comp3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1500          $pc1 = $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $comp1->get('id')));
1501          $pc2 = $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $comp2->get('id')));
1502          $pc3 = $lpg->create_plan_competency(array('planid' => $plan->get('id'), 'competencyid' => $comp3->get('id')));
1503  
1504          // Complete the plan to generate user_competency_plan entries.
1505          api::complete_plan($plan);
1506  
1507          // Confirm the data we have.
1508          $this->assertEquals(3, plan_competency::count_records(array('planid' => $plan->get('id'))));
1509          $this->assertEquals(3, user_competency_plan::count_records(array('planid' => $plan->get('id'), 'userid' => $user->id)));
1510  
1511          // Delete the plan now.
1512          api::delete_plan($plan->get('id'));
1513          $this->assertEquals(0, plan_competency::count_records(array('planid' => $plan->get('id'))));
1514          $this->assertEquals(0, user_competency_plan::count_records(array('planid' => $plan->get('id'), 'userid' => $user->id)));
1515      }
1516  
1517      public function test_list_plan_competencies() {
1518          $this->setUser($this->creator);
1519  
1520          $dg = $this->getDataGenerator();
1521          $lpg = $dg->get_plugin_generator('core_competency');
1522  
1523          $f1 = $lpg->create_framework();
1524          $f2 = $lpg->create_framework();
1525  
1526          $c1a = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
1527          $c1b = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
1528          $c1c = $lpg->create_competency(array('competencyframeworkid' => $f1->get('id')));
1529          $c2a = $lpg->create_competency(array('competencyframeworkid' => $f2->get('id')));
1530          $c2b = $lpg->create_competency(array('competencyframeworkid' => $f2->get('id')));
1531  
1532          $tpl = $lpg->create_template();
1533          $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c1a->get('id')));
1534          $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c1c->get('id')));
1535          $lpg->create_template_competency(array('templateid' => $tpl->get('id'), 'competencyid' => $c2b->get('id')));
1536  
1537          $plan = $lpg->create_plan(array('userid' => $this->user->id, 'templateid' => $tpl->get('id')));
1538  
1539          $uc1a = $lpg->create_user_competency(array('userid' => $this->user->id, 'competencyid' => $c1a->get('id'),
1540              'status' => user_competency::STATUS_IN_REVIEW, 'reviewerid' => $this->creator->id));
1541          $uc1b = $lpg->create_user_competency(array('userid' => $this->user->id, 'competencyid' => $c1b->get('id')));
1542          $uc2b = $lpg->create_user_competency(array('userid' => $this->user->id, 'competencyid' => $c2b->get('id'),
1543              'grade' => 2, 'proficiency' => 1));
1544          $ux1a = $lpg->create_user_competency(array('userid' => $this->creator->id, 'competencyid' => $c1a->get('id')));
1545  
1546          $result = external::list_plan_competencies($plan->get('id'));
1547          $result = external::clean_returnvalue(external::list_plan_competencies_returns(), $result);
1548  
1549          $this->assertCount(3, $result);
1550          $this->assertEquals($c1a->get('id'), $result[0]['competency']['id']);
1551          $this->assertEquals($this->user->id, $result[0]['usercompetency']['userid']);
1552          $this->assertArrayNotHasKey('usercompetencyplan', $result[0]);
1553          $this->assertEquals($c1c->get('id'), $result[1]['competency']['id']);
1554          $this->assertEquals($this->user->id, $result[1]['usercompetency']['userid']);
1555          $this->assertArrayNotHasKey('usercompetencyplan', $result[1]);
1556          $this->assertEquals($c2b->get('id'), $result[2]['competency']['id']);
1557          $this->assertEquals($this->user->id, $result[2]['usercompetency']['userid']);
1558          $this->assertArrayNotHasKey('usercompetencyplan', $result[2]);
1559          $this->assertEquals(user_competency::STATUS_IN_REVIEW, $result[0]['usercompetency']['status']);
1560          $this->assertEquals(null, $result[1]['usercompetency']['grade']);
1561          $this->assertEquals(2, $result[2]['usercompetency']['grade']);
1562          $this->assertEquals(1, $result[2]['usercompetency']['proficiency']);
1563  
1564          // Check the return values when the plan status is complete.
1565          $completedplan = $lpg->create_plan(array('userid' => $this->user->id, 'templateid' => $tpl->get('id'),
1566                  'status' => plan::STATUS_COMPLETE));
1567  
1568          $uc1a = $lpg->create_user_competency_plan(array('userid' => $this->user->id, 'competencyid' => $c1a->get('id'),
1569                  'planid' => $completedplan->get('id')));
1570          $uc1b = $lpg->create_user_competency_plan(array('userid' => $this->user->id, 'competencyid' => $c1c->get('id'),
1571                  'planid' => $completedplan->get('id')));
1572          $uc2b = $lpg->create_user_competency_plan(array('userid' => $this->user->id, 'competencyid' => $c2b->get('id'),
1573                  'planid' => $completedplan->get('id'), 'grade' => 2, 'proficiency' => 1));
1574          $ux1a = $lpg->create_user_competency_plan(array('userid' => $this->creator->id, 'competencyid' => $c1a->get('id'),
1575                  'planid' => $completedplan->get('id')));
1576  
1577          $result = external::list_plan_competencies($completedplan->get('id'));
1578          $result = external::clean_returnvalue(external::list_plan_competencies_returns(), $result);
1579  
1580          $this->assertCount(3, $result);
1581          $this->assertEquals($c1a->get('id'), $result[0]['competency']['id']);
1582          $this->assertEquals($this->user->id, $result[0]['usercompetencyplan']['userid']);
1583          $this->assertArrayNotHasKey('usercompetency', $result[0]);
1584          $this->assertEquals($c1c->get('id'), $result[1]['competency']['id']);
1585          $this->assertEquals($this->user->id, $result[1]['usercompetencyplan']['userid']);
1586          $this->assertArrayNotHasKey('usercompetency', $result[1]);
1587          $this->assertEquals($c2b->get('id'), $result[2]['competency']['id']);
1588          $this->assertEquals($this->user->id, $result[2]['usercompetencyplan']['userid']);
1589          $this->assertArrayNotHasKey('usercompetency', $result[2]);
1590          $this->assertEquals(null, $result[1]['usercompetencyplan']['grade']);
1591          $this->assertEquals(2, $result[2]['usercompetencyplan']['grade']);
1592          $this->assertEquals(1, $result[2]['usercompetencyplan']['proficiency']);
1593      }
1594  
1595      public function test_add_competency_to_template() {
1596          $this->setUser($this->creator);
1597  
1598          $syscontext = \context_system::instance();
1599  
1600          // Create a template.
1601          $template = $this->create_template(1, true);
1602  
1603          // Create a competency.
1604          $framework = $this->create_competency_framework(1, true);
1605          $competency = $this->create_competency(1, $framework->id);
1606  
1607          // Add the competency.
1608          external::add_competency_to_template($template->id, $competency->id);
1609  
1610          // Check that it was added.
1611          $this->assertEquals(1, external::count_competencies_in_template($template->id));
1612  
1613          // Unassign capability.
1614          unassign_capability('moodle/competency:templatemanage', $this->creatorrole, $syscontext->id);
1615          accesslib_clear_all_caches_for_unit_testing();
1616  
1617          // Check we can not add the competency now.
1618          try {
1619              external::add_competency_to_template($template->id, $competency->id);
1620              $this->fail('Exception expected due to not permissions to manage template competencies');
1621          } catch (\moodle_exception $e) {
1622              $this->assertEquals('nopermissions', $e->errorcode);
1623          }
1624      }
1625  
1626      public function test_remove_competency_from_template() {
1627          $syscontext = \context_system::instance();
1628          $this->setUser($this->creator);
1629          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
1630  
1631          // Create a template.
1632          $template = $this->create_template(1, true);
1633  
1634          // Create a competency.
1635          $framework = $lpg->create_framework();
1636          $competency = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
1637  
1638          // Add the competency.
1639          external::add_competency_to_template($template->id, $competency->get('id'));
1640  
1641          // Check that it was added.
1642          $this->assertEquals(1, external::count_competencies_in_template($template->id));
1643  
1644          // Check that we can remove the competency.
1645          external::remove_competency_from_template($template->id, $competency->get('id'));
1646  
1647          // Check that it was removed.
1648          $this->assertEquals(0, external::count_competencies_in_template($template->id));
1649  
1650          // Unassign capability.
1651          unassign_capability('moodle/competency:templatemanage', $this->creatorrole, $syscontext->id);
1652          accesslib_clear_all_caches_for_unit_testing();
1653  
1654          // Check we can not remove the competency now.
1655          try {
1656              external::add_competency_to_template($template->id, $competency->get('id'));
1657              $this->fail('Exception expected due to not permissions to manage template competencies');
1658          } catch (\moodle_exception $e) {
1659              $this->assertEquals('nopermissions', $e->errorcode);
1660          }
1661      }
1662  
1663      /**
1664       * Test we can re-order competency frameworks.
1665       */
1666      public function test_reorder_template_competencies() {
1667          $this->setUser($this->creator);
1668  
1669          $syscontext = \context_system::instance();
1670          $onehour = time() + 60 * 60;
1671  
1672          // Create a template.
1673          $template = $this->create_template(1, true);
1674  
1675          // Create a competency framework.
1676          $framework = $this->create_competency_framework(1, true);
1677  
1678          // Create multiple competencies.
1679          $competency1 = $this->create_competency(1, $framework->id);
1680          $competency2 = $this->create_competency(2, $framework->id);
1681          $competency3 = $this->create_competency(3, $framework->id);
1682          $competency4 = $this->create_competency(4, $framework->id);
1683  
1684          // Add the competencies.
1685          external::add_competency_to_template($template->id, $competency1->id);
1686          external::add_competency_to_template($template->id, $competency2->id);
1687          external::add_competency_to_template($template->id, $competency3->id);
1688          external::add_competency_to_template($template->id, $competency4->id);
1689  
1690          // Test if removing competency from template don't create sortorder holes.
1691          external::remove_competency_from_template($template->id, $competency3->id);
1692          $templcomp4 = template_competency::get_record(array(
1693              'templateid' => $template->id,
1694              'competencyid' => $competency4->id
1695          ));
1696  
1697          $this->assertEquals(2, $templcomp4->get('sortorder'));
1698  
1699          // This is a move up.
1700          external::reorder_template_competency($template->id, $competency4->id, $competency2->id);
1701          $result = external::list_competencies_in_template($template->id);
1702          $result = \external_api::clean_returnvalue(external::list_competencies_in_template_returns(), $result);
1703  
1704          $r1 = (object) $result[0];
1705          $r2 = (object) $result[1];
1706          $r3 = (object) $result[2];
1707  
1708          $this->assertEquals($competency1->id, $r1->id);
1709          $this->assertEquals($competency4->id, $r2->id);
1710          $this->assertEquals($competency2->id, $r3->id);
1711  
1712          // This is a move down.
1713          external::reorder_template_competency($template->id, $competency1->id, $competency4->id);
1714          $result = external::list_competencies_in_template($template->id);
1715          $result = \external_api::clean_returnvalue(external::list_competencies_in_template_returns(), $result);
1716  
1717          $r1 = (object) $result[0];
1718          $r2 = (object) $result[1];
1719          $r3 = (object) $result[2];
1720  
1721          $this->assertEquals($competency4->id, $r1->id);
1722          $this->assertEquals($competency1->id, $r2->id);
1723          $this->assertEquals($competency2->id, $r3->id);
1724  
1725          $this->expectException('\required_capability_exception');
1726          $this->setUser($this->user);
1727          external::reorder_template_competency($template->id, $competency1->id, $competency2->id);
1728      }
1729  
1730      /**
1731       * Test we can duplicate learning plan template.
1732       */
1733      public function test_duplicate_learning_plan_template() {
1734          $this->setUser($this->creator);
1735  
1736          $syscontext = \context_system::instance();
1737          $onehour = time() + 60 * 60;
1738  
1739          // Create a template.
1740          $template = $this->create_template(1, true);
1741  
1742          // Create a competency framework.
1743          $framework = $this->create_competency_framework(1, true);
1744  
1745          // Create multiple competencies.
1746          $competency1 = $this->create_competency(1, $framework->id);
1747          $competency2 = $this->create_competency(2, $framework->id);
1748          $competency3 = $this->create_competency(3, $framework->id);
1749  
1750          // Add the competencies.
1751          external::add_competency_to_template($template->id, $competency1->id);
1752          external::add_competency_to_template($template->id, $competency2->id);
1753          external::add_competency_to_template($template->id, $competency3->id);
1754  
1755          // Duplicate the learning plan template.
1756          $duplicatedtemplate = external::duplicate_template($template->id);
1757  
1758          $result = external::list_competencies_in_template($template->id);
1759          $resultduplicated = external::list_competencies_in_template($duplicatedtemplate->id);
1760  
1761          $this->assertEquals(count($result), count($resultduplicated));
1762          $this->assertStringContainsString($template->shortname, $duplicatedtemplate->shortname);
1763          $this->assertEquals($duplicatedtemplate->description, $template->description);
1764          $this->assertEquals($duplicatedtemplate->descriptionformat, $template->descriptionformat);
1765          $this->assertEquals($duplicatedtemplate->visible, $template->visible);
1766      }
1767  
1768      /**
1769       * Test that we can return scale values for a scale with the scale ID.
1770       */
1771      public function test_get_scale_values() {
1772          global $DB;
1773  
1774          $this->setUser($this->creator);
1775  
1776          // Create a scale.
1777          $record = new \stdClass();
1778          $record->courseid = 0;
1779          $record->userid = $this->creator->id;
1780          $record->name = 'Test scale';
1781          $record->scale = 'Poor, Not good, Okay, Fine, Excellent';
1782          $record->description = '<p>Test scale description.</p>';
1783          $record->descriptionformat = 1;
1784          $record->timemodified = time();
1785          $scaleid = $DB->insert_record('scale', $record);
1786          // Expected return value.
1787          $expected = array(array(
1788                  'id' => 1,
1789                  'name' => 'Poor'
1790              ), array(
1791                  'id' => 2,
1792                  'name' => 'Not good'
1793              ), array(
1794                  'id' => 3,
1795                  'name' => 'Okay'
1796              ), array(
1797                  'id' => 4,
1798                  'name' => 'Fine'
1799              ), array(
1800                  'id' => 5,
1801                  'name' => 'Excellent'
1802              )
1803          );
1804          // Call the webservice.
1805          $result = external::get_scale_values($scaleid);
1806          $this->assertEquals($expected, $result);
1807      }
1808  
1809      /**
1810       * Create a template.
1811       */
1812      public function test_create_template() {
1813          $syscontextid = \context_system::instance()->id;
1814          $catcontextid = \context_coursecat::instance($this->category->id)->id;
1815  
1816          // A user without permission.
1817          $this->setUser($this->user);
1818          try {
1819              $result = $this->create_template(1, true);
1820              $this->fail('Invalid permissions');
1821          } catch (\required_capability_exception $e) {
1822              // All good.
1823          }
1824  
1825          // A user without permission in a category.
1826          $this->setUser($this->catuser);
1827          try {
1828              $result = $this->create_template(1, false);
1829              $this->fail('Invalid permissions');
1830          } catch (\required_capability_exception $e) {
1831              // All good.
1832          }
1833  
1834          // A user with permissions in the system.
1835          $this->setUser($this->creator);
1836          $result = $this->create_template(1, true);
1837          $this->assertEquals('shortname1', $result->shortname);
1838          $this->assertEquals($syscontextid, $result->contextid);
1839          $this->assertNotEmpty($result->id);
1840  
1841          $result = $this->create_template(2, false);
1842          $this->assertEquals('shortname2', $result->shortname);
1843          $this->assertEquals($catcontextid, $result->contextid);
1844          $this->assertNotEmpty($result->id);
1845  
1846          // A user with permissions in the category.
1847          $this->setUser($this->catcreator);
1848          try {
1849              $result = $this->create_template(3, true);
1850              $this->fail('Invalid permissions');
1851          } catch (\required_capability_exception $e) {
1852              // All good.
1853          }
1854  
1855          $result = $this->create_template(3, false);
1856          $this->assertEquals('shortname3', $result->shortname);
1857          $this->assertEquals($catcontextid, $result->contextid);
1858          $this->assertNotEmpty($result->id);
1859      }
1860  
1861      /**
1862       * Read a template.
1863       */
1864      public function test_read_template() {
1865          $syscontextid = \context_system::instance()->id;
1866          $catcontextid = \context_coursecat::instance($this->category->id)->id;
1867  
1868          // Set a due date for the next year.
1869          $date = new \DateTime('now');
1870          $date->modify('+1 year');
1871          $duedate = $date->getTimestamp();
1872  
1873          // Creating two templates.
1874          $this->setUser($this->creator);
1875          $systemplate = $this->create_template(1, true);
1876          $cattemplate = $this->create_template(2, false);
1877  
1878          // User without permissions to read in system.
1879          assign_capability('moodle/competency:templateview', CAP_PROHIBIT, $this->userrole, $syscontextid, true);
1880          accesslib_clear_all_caches_for_unit_testing();
1881          $this->setUser($this->user);
1882          $this->assertFalse(has_capability('moodle/competency:templateview', \context_system::instance()));
1883          try {
1884              external::read_template($systemplate->id);
1885              $this->fail('Invalid permissions');
1886          } catch (\required_capability_exception $e) {
1887              // All good.
1888          }
1889          try {
1890              external::read_template($cattemplate->id);
1891              $this->fail('Invalid permissions');
1892          } catch (\required_capability_exception $e) {
1893              // All good.
1894          }
1895  
1896          // User with permissions to read in a category.
1897          assign_capability('moodle/competency:templateview', CAP_PREVENT, $this->userrole, $syscontextid, true);
1898          assign_capability('moodle/competency:templateview', CAP_ALLOW, $this->userrole, $catcontextid, true);
1899          accesslib_clear_all_caches_for_unit_testing();
1900          $this->assertFalse(has_capability('moodle/competency:templateview', \context_system::instance()));
1901          $this->assertTrue(has_capability('moodle/competency:templateview', \context_coursecat::instance($this->category->id)));
1902          try {
1903              external::read_template($systemplate->id);
1904              $this->fail('Invalid permissions');
1905          } catch (\required_capability_exception $e) {
1906              // All good.
1907          }
1908  
1909          $result = external::read_template($cattemplate->id);
1910          $result = \external_api::clean_returnvalue(external::read_template_returns(), $result);
1911          $this->assertEquals($cattemplate->id, $result['id']);
1912          $this->assertEquals('shortname2', $result['shortname']);
1913          $this->assertEquals('description2', $result['description']);
1914          $this->assertEquals(FORMAT_HTML, $result['descriptionformat']);
1915          $this->assertEquals(1, $result['visible']);
1916          $this->assertEquals(0, $result['duedate']);
1917          $this->assertEquals(userdate(0), $result['duedateformatted']);
1918  
1919          // User with permissions to read in the system.
1920          assign_capability('moodle/competency:templateview', CAP_ALLOW, $this->userrole, $syscontextid, true);
1921          accesslib_clear_all_caches_for_unit_testing();
1922          $this->assertTrue(has_capability('moodle/competency:templateview', \context_system::instance()));
1923          $result = external::read_template($systemplate->id);
1924          $result = \external_api::clean_returnvalue(external::read_template_returns(), $result);
1925          $this->assertEquals($systemplate->id, $result['id']);
1926          $this->assertEquals('shortname1', $result['shortname']);
1927          $this->assertEquals('description1', $result['description']);
1928          $this->assertEquals(FORMAT_HTML, $result['descriptionformat']);
1929          $this->assertEquals(true, $result['visible']);
1930          $this->assertEquals(0, $result['duedate']);
1931          $this->assertEquals(userdate(0), $result['duedateformatted']);
1932  
1933          $result = external::read_template($cattemplate->id);
1934          $result = \external_api::clean_returnvalue(external::read_template_returns(), $result);
1935          $this->assertEquals($cattemplate->id, $result['id']);
1936          $this->assertEquals('shortname2', $result['shortname']);
1937          $this->assertEquals('description2', $result['description']);
1938          $this->assertEquals(FORMAT_HTML, $result['descriptionformat']);
1939          $this->assertEquals(true, $result['visible']);
1940          $this->assertEquals(0, $result['duedate']);
1941          $this->assertEquals(userdate(0), $result['duedateformatted']);
1942      }
1943  
1944      /**
1945       * Update a template.
1946       */
1947      public function test_update_template() {
1948          $syscontextid = \context_system::instance()->id;
1949          $catcontextid = \context_coursecat::instance($this->category->id)->id;
1950  
1951          // Set a due date for the next year.
1952          $date = new \DateTime('now');
1953          $date->modify('+1 year');
1954          $duedate = $date->getTimestamp();
1955  
1956          // Creating two templates.
1957          $this->setUser($this->creator);
1958          $systemplate = $this->create_template(1, true);
1959          $cattemplate = $this->create_template(2, false);
1960  
1961          // Trying to update in a without permissions.
1962          $this->setUser($this->user);
1963          try {
1964              $this->update_template($systemplate->id, 3);
1965              $this->fail('Invalid permissions');
1966          } catch (\required_capability_exception $e) {
1967              // All good.
1968          }
1969  
1970          try {
1971              $this->update_template($cattemplate->id, 3);
1972              $this->fail('Invalid permissions');
1973          } catch (\required_capability_exception $e) {
1974              // All good.
1975          }
1976  
1977          // User with permissions to update in category.
1978          $this->setUser($this->catcreator);
1979          try {
1980              $this->update_template($systemplate->id, 3);
1981              $this->fail('Invalid permissions');
1982          } catch (\required_capability_exception $e) {
1983              // All good.
1984          }
1985  
1986          $result = $this->update_template($cattemplate->id, 3);
1987          $this->assertTrue($result);
1988          $result = external::read_template($cattemplate->id);
1989          $result = \external_api::clean_returnvalue(external::read_template_returns(), $result);
1990          $this->assertEquals($cattemplate->id, $result['id']);
1991          $this->assertEquals('shortname3', $result['shortname']);
1992          $this->assertEquals("description3", $result['description']);
1993          $this->assertEquals(FORMAT_HTML, $result['descriptionformat']);
1994          $this->assertEquals(true, $result['visible']);
1995          $this->assertEquals(0, $result['duedate']);
1996          $this->assertEquals(userdate(0), $result['duedateformatted']);
1997  
1998          // User with permissions to update in the system.
1999          $this->setUser($this->creator);
2000          $result = $this->update_template($systemplate->id, 4);
2001          $this->assertTrue($result);
2002          $result = external::read_template($systemplate->id);
2003          $result = \external_api::clean_returnvalue(external::read_template_returns(), $result);
2004          $this->assertEquals($systemplate->id, $result['id']);
2005          $this->assertEquals('shortname4', $result['shortname']);
2006          $this->assertEquals('description4', $result['description']);
2007          $this->assertEquals(FORMAT_HTML, $result['descriptionformat']);
2008          $this->assertEquals(true, $result['visible']);
2009          $this->assertEquals(0, $result['duedate']);
2010          $this->assertEquals(userdate(0), $result['duedateformatted']);
2011  
2012          $result = $this->update_template($cattemplate->id, 5);
2013          $this->assertTrue($result);
2014          $result = external::read_template($cattemplate->id);
2015          $result = \external_api::clean_returnvalue(external::read_template_returns(), $result);
2016          $this->assertEquals($cattemplate->id, $result['id']);
2017          $this->assertEquals('shortname5', $result['shortname']);
2018          $this->assertEquals('description5', $result['description']);
2019          $this->assertEquals(FORMAT_HTML, $result['descriptionformat']);
2020          $this->assertEquals(1, $result['visible']);
2021          $this->assertEquals(0, $result['duedate']);
2022          $this->assertEquals(userdate(0), $result['duedateformatted']);
2023      }
2024  
2025      /**
2026       * Delete a template.
2027       */
2028      public function test_delete_template() {
2029          global $DB;
2030          $syscontextid = \context_system::instance()->id;
2031          $catcontextid = \context_coursecat::instance($this->category->id)->id;
2032  
2033          // Creating a few templates.
2034          $this->setUser($this->creator);
2035          $sys1 = $this->create_template(1, true);
2036          $cat1 = $this->create_template(2, false);
2037          $cat2 = $this->create_template(3, false);
2038          $this->assertTrue($DB->record_exists(template::TABLE, array('id' => $sys1->id)));
2039          $this->assertTrue($DB->record_exists(template::TABLE, array('id' => $cat1->id)));
2040          $this->assertTrue($DB->record_exists(template::TABLE, array('id' => $cat2->id)));
2041  
2042          // User without permissions.
2043          $this->setUser($this->user);
2044          try {
2045              external::delete_template($sys1->id);
2046              $this->fail('Invalid permissions');
2047          } catch (\required_capability_exception $e) {
2048              // All good.
2049          }
2050          try {
2051              external::delete_template($cat1->id);
2052              $this->fail('Invalid permissions');
2053          } catch (\required_capability_exception $e) {
2054              // All good.
2055          }
2056  
2057          // User with category permissions.
2058          $this->setUser($this->catcreator);
2059          try {
2060              external::delete_template($sys1->id);
2061              $this->fail('Invalid permissions');
2062          } catch (\required_capability_exception $e) {
2063              // All good.
2064          }
2065  
2066          $result = external::delete_template($cat1->id);
2067          $result = \external_api::clean_returnvalue(external::delete_template_returns(), $result);
2068          $this->assertTrue($result);
2069          $this->assertFalse($DB->record_exists(template::TABLE, array('id' => $cat1->id)));
2070  
2071          // User with system permissions.
2072          $this->setUser($this->creator);
2073          $result = external::delete_template($sys1->id);
2074          $result = \external_api::clean_returnvalue(external::delete_template_returns(), $result);
2075          $this->assertTrue($result);
2076          $result = external::delete_template($cat2->id);
2077          $result = \external_api::clean_returnvalue(external::delete_template_returns(), $result);
2078          $this->assertTrue($result);
2079          $this->assertFalse($DB->record_exists(template::TABLE, array('id' => $sys1->id)));
2080          $this->assertFalse($DB->record_exists(template::TABLE, array('id' => $cat2->id)));
2081      }
2082  
2083      /**
2084       * List templates.
2085       */
2086      public function test_list_templates() {
2087          $syscontextid = \context_system::instance()->id;
2088          $catcontextid = \context_coursecat::instance($this->category->id)->id;
2089  
2090          // Creating a few templates.
2091          $this->setUser($this->creator);
2092          $sys1 = $this->create_template(1, true);
2093          $sys2 = $this->create_template(2, true);
2094          $cat1 = $this->create_template(3, false);
2095          $cat2 = $this->create_template(4, false);
2096  
2097          // User without permission.
2098          $this->setUser($this->user);
2099          assign_capability('moodle/competency:templateview', CAP_PROHIBIT, $this->userrole, $syscontextid, true);
2100          accesslib_clear_all_caches_for_unit_testing();
2101          try {
2102              external::list_templates('id', 'ASC', 0, 10, array('contextid' => $syscontextid), 'children', false);
2103              $this->fail('Invalid permissions');
2104          } catch (\required_capability_exception $e) {
2105              // All good.
2106          }
2107  
2108          // User with category permissions.
2109          assign_capability('moodle/competency:templateview', CAP_PREVENT, $this->userrole, $syscontextid, true);
2110          assign_capability('moodle/competency:templateview', CAP_ALLOW, $this->userrole, $catcontextid, true);
2111          accesslib_clear_all_caches_for_unit_testing();
2112          $result = external::list_templates('id', 'ASC', 0, 10, array('contextid' => $syscontextid), 'children', false);
2113          $result = \external_api::clean_returnvalue(external::list_templates_returns(), $result);
2114          $this->assertCount(2, $result);
2115          $this->assertEquals($cat1->id, $result[0]['id']);
2116          $this->assertEquals($cat2->id, $result[1]['id']);
2117  
2118          // User with system permissions.
2119          assign_capability('moodle/competency:templateview', CAP_ALLOW, $this->userrole, $syscontextid, true);
2120          accesslib_clear_all_caches_for_unit_testing();
2121          $result = external::list_templates('id', 'DESC', 0, 3, array('contextid' => $catcontextid), 'parents', false);
2122          $result = \external_api::clean_returnvalue(external::list_templates_returns(), $result);
2123          $this->assertCount(3, $result);
2124          $this->assertEquals($cat2->id, $result[0]['id']);
2125          $this->assertEquals($cat1->id, $result[1]['id']);
2126          $this->assertEquals($sys2->id, $result[2]['id']);
2127      }
2128  
2129      /**
2130       * List templates using competency.
2131       */
2132      public function test_list_templates_using_competency() {
2133          $this->setUser($this->creator);
2134  
2135          // Create a template.
2136          $template1 = $this->create_template(1, true);
2137          $template2 = $this->create_template(2, true);
2138          $template3 = $this->create_template(3, true);
2139          $template4 = $this->create_template(4, true);
2140  
2141          // Create a competency.
2142          $framework = $this->create_competency_framework(1, true);
2143          $competency1 = $this->create_competency(1, $framework->id);
2144          $competency2 = $this->create_competency(2, $framework->id);
2145  
2146          // Add the competency.
2147          external::add_competency_to_template($template1->id, $competency1->id);
2148          external::add_competency_to_template($template2->id, $competency1->id);
2149          external::add_competency_to_template($template3->id, $competency1->id);
2150  
2151          external::add_competency_to_template($template4->id, $competency2->id);
2152  
2153          $listcomp1 = external::list_templates_using_competency($competency1->id);
2154          $listcomp2 = external::list_templates_using_competency($competency2->id);
2155  
2156          // Test count_templates_using_competency.
2157          $counttempcomp1 = external::count_templates_using_competency($competency1->id);
2158          $counttempcomp2 = external::count_templates_using_competency($competency2->id);
2159  
2160          $comptemp1 = $listcomp1[0];
2161          $comptemp2 = $listcomp1[1];
2162          $comptemp3 = $listcomp1[2];
2163  
2164          $comptemp4 = $listcomp2[0];
2165  
2166          $this->assertCount(3, $listcomp1);
2167          $this->assertCount(1, $listcomp2);
2168          $this->assertEquals(3, $counttempcomp1);
2169          $this->assertEquals(1, $counttempcomp2);
2170          $this->assertEquals($template1->id, $comptemp1->id);
2171          $this->assertEquals($template2->id, $comptemp2->id);
2172          $this->assertEquals($template3->id, $comptemp3->id);
2173          $this->assertEquals($template4->id, $comptemp4->id);
2174      }
2175  
2176      public function test_count_templates() {
2177          $syscontextid = \context_system::instance()->id;
2178          $catcontextid = \context_coursecat::instance($this->category->id)->id;
2179  
2180          // Creating a few templates.
2181          $this->setUser($this->creator);
2182          $sys1 = $this->create_template(1, true);
2183          $sys2 = $this->create_template(2, true);
2184          $cat1 = $this->create_template(3, false);
2185          $cat2 = $this->create_template(4, false);
2186          $cat3 = $this->create_template(5, false);
2187  
2188          // User without permission.
2189          $this->setUser($this->user);
2190          assign_capability('moodle/competency:templateview', CAP_PROHIBIT, $this->userrole, $syscontextid, true);
2191          accesslib_clear_all_caches_for_unit_testing();
2192          try {
2193              external::count_templates(array('contextid' => $syscontextid), 'children');
2194              $this->fail('Invalid permissions');
2195          } catch (\required_capability_exception $e) {
2196              // All good.
2197          }
2198  
2199          // User with category permissions.
2200          assign_capability('moodle/competency:templateview', CAP_PREVENT, $this->userrole, $syscontextid, true);
2201          assign_capability('moodle/competency:templateview', CAP_ALLOW, $this->userrole, $catcontextid, true);
2202          accesslib_clear_all_caches_for_unit_testing();
2203          $result = external::count_templates(array('contextid' => $syscontextid), 'children');
2204          $result = \external_api::clean_returnvalue(external::count_templates_returns(), $result);
2205          $this->assertEquals(3, $result);
2206  
2207          // User with system permissions.
2208          assign_capability('moodle/competency:templateview', CAP_ALLOW, $this->userrole, $syscontextid, true);
2209          accesslib_clear_all_caches_for_unit_testing();
2210          $result = external::count_templates(array('contextid' => $catcontextid), 'parents');
2211          $result = \external_api::clean_returnvalue(external::count_templates_returns(), $result);
2212          $this->assertEquals(5, $result);
2213      }
2214  
2215      /**
2216       * Test that we can add related competencies.
2217       *
2218       * @return void
2219       */
2220      public function test_add_related_competency() {
2221          global $DB;
2222          $this->setUser($this->creator);
2223  
2224          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2225          $framework = $lpg->create_framework();
2226          $framework2 = $lpg->create_framework();
2227          $competency1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2228          $competency2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2229          $competency3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2230          $competency4 = $lpg->create_competency(array('competencyframeworkid' => $framework2->get('id')));
2231  
2232          // The lower one always as competencyid.
2233          $result = external::add_related_competency($competency1->get('id'), $competency2->get('id'));
2234          $result = \external_api::clean_returnvalue(external::add_related_competency_returns(), $result);
2235          $this->assertTrue($result);
2236          $this->assertTrue($DB->record_exists_select(
2237              related_competency::TABLE, 'competencyid = :cid AND relatedcompetencyid = :rid',
2238              array(
2239                  'cid' => $competency1->get('id'),
2240                  'rid' => $competency2->get('id')
2241              )
2242          ));
2243          $this->assertFalse($DB->record_exists_select(
2244              related_competency::TABLE, 'competencyid = :cid AND relatedcompetencyid = :rid',
2245              array(
2246                  'cid' => $competency2->get('id'),
2247                  'rid' => $competency1->get('id')
2248              )
2249          ));
2250  
2251          $result = external::add_related_competency($competency3->get('id'), $competency1->get('id'));
2252          $result = \external_api::clean_returnvalue(external::add_related_competency_returns(), $result);
2253          $this->assertTrue($result);
2254          $this->assertTrue($DB->record_exists_select(
2255              related_competency::TABLE, 'competencyid = :cid AND relatedcompetencyid = :rid',
2256              array(
2257                  'cid' => $competency1->get('id'),
2258                  'rid' => $competency3->get('id')
2259              )
2260          ));
2261          $this->assertFalse($DB->record_exists_select(
2262              related_competency::TABLE, 'competencyid = :cid AND relatedcompetencyid = :rid',
2263              array(
2264                  'cid' => $competency3->get('id'),
2265                  'rid' => $competency1->get('id')
2266              )
2267          ));
2268  
2269          // We can not allow a duplicate relation, not even in the other direction.
2270          $this->assertEquals(1, $DB->count_records_select(related_competency::TABLE,
2271              'competencyid = :cid AND relatedcompetencyid = :rid',
2272              array('cid' => $competency1->get('id'), 'rid' => $competency2->get('id'))));
2273          $this->assertEquals(0, $DB->count_records_select(related_competency::TABLE,
2274              'competencyid = :cid AND relatedcompetencyid = :rid',
2275              array('rid' => $competency1->get('id'), 'cid' => $competency2->get('id'))));
2276          $result = external::add_related_competency($competency2->get('id'), $competency1->get('id'));
2277          $result = \external_api::clean_returnvalue(external::add_related_competency_returns(), $result);
2278          $this->assertTrue($result);
2279          $this->assertEquals(1, $DB->count_records_select(related_competency::TABLE,
2280              'competencyid = :cid AND relatedcompetencyid = :rid',
2281              array('cid' => $competency1->get('id'), 'rid' => $competency2->get('id'))));
2282          $this->assertEquals(0, $DB->count_records_select(related_competency::TABLE,
2283              'competencyid = :cid AND relatedcompetencyid = :rid',
2284              array('rid' => $competency1->get('id'), 'cid' => $competency2->get('id'))));
2285  
2286          // Check that we cannot create links across frameworks.
2287          try {
2288              external::add_related_competency($competency1->get('id'), $competency4->get('id'));
2289              $this->fail('Exception expected due mis-use of shared competencies');
2290          } catch (invalid_persistent_exception $e) {
2291              // Yay!
2292          }
2293  
2294          // User without permission.
2295          $this->setUser($this->user);
2296  
2297          // Check we can not add the related competency now.
2298          try {
2299              external::add_related_competency($competency1->get('id'), $competency3->get('id'));
2300              $this->fail('Exception expected due to not permissions to manage template competencies');
2301          } catch (\moodle_exception $e) {
2302              $this->assertEquals('nopermissions', $e->errorcode);
2303          }
2304  
2305      }
2306  
2307      /**
2308       * Test that we can remove related competencies.
2309       *
2310       * @return void
2311       */
2312      public function test_remove_related_competency() {
2313          $this->setUser($this->creator);
2314  
2315          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2316          $framework = $lpg->create_framework();
2317          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2318          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2319          $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2320          $rc1 = $lpg->create_related_competency(array('competencyid' => $c1->get('id'), 'relatedcompetencyid' => $c2->get('id')));
2321          $rc2 = $lpg->create_related_competency(array('competencyid' => $c2->get('id'), 'relatedcompetencyid' => $c3->get('id')));
2322  
2323          $this->assertEquals(2, related_competency::count_records());
2324  
2325          // Returns false when the relation does not exist.
2326          $result = external::remove_related_competency($c1->get('id'), $c3->get('id'));
2327          $result = \external_api::clean_returnvalue(external::remove_related_competency_returns(), $result);
2328          $this->assertFalse($result);
2329  
2330          // Returns true on success.
2331          $result = external::remove_related_competency($c2->get('id'), $c3->get('id'));
2332          $result = \external_api::clean_returnvalue(external::remove_related_competency_returns(), $result);
2333          $this->assertTrue($result);
2334          $this->assertEquals(1, related_competency::count_records());
2335  
2336          // We don't need to specify competencyid and relatedcompetencyid in the right order.
2337          $result = external::remove_related_competency($c2->get('id'), $c1->get('id'));
2338          $result = \external_api::clean_returnvalue(external::remove_related_competency_returns(), $result);
2339          $this->assertTrue($result);
2340          $this->assertEquals(0, related_competency::count_records());
2341      }
2342  
2343      /**
2344       * Test that we can search and include related competencies.
2345       *
2346       * @return void
2347       */
2348      public function test_search_competencies_including_related() {
2349          $this->setUser($this->creator);
2350  
2351          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2352          $framework = $lpg->create_framework();
2353          $c1 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2354          $c2 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2355          $c3 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2356          $c4 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2357          $c5 = $lpg->create_competency(array('competencyframeworkid' => $framework->get('id')));
2358  
2359          // We have 1-2, 1-3, 2-4, and no relation between 2-3 nor 1-4 nor 5.
2360          $rc12 = $lpg->create_related_competency(array('competencyid' => $c1->get('id'), 'relatedcompetencyid' => $c2->get('id')));
2361          $rc13 = $lpg->create_related_competency(array('competencyid' => $c1->get('id'), 'relatedcompetencyid' => $c3->get('id')));
2362          $rc24 = $lpg->create_related_competency(array('competencyid' => $c2->get('id'), 'relatedcompetencyid' => $c4->get('id')));
2363  
2364          $result = external::search_competencies('comp', $framework->get('id'), true);
2365          $result = \external_api::clean_returnvalue(external::search_competencies_returns(), $result);
2366  
2367          $this->assertCount(5, $result);
2368  
2369      }
2370  
2371      /**
2372       * Test that we can add competency to plan if we have the right capability.
2373       *
2374       * @return void
2375       */
2376      public function test_add_competency_to_plan() {
2377          $this->resetAfterTest(true);
2378          $dg = $this->getDataGenerator();
2379          $lpg = $this->getDataGenerator()->get_plugin_generator('core_competency');
2380          $usermanage = $dg->create_user();
2381          $user = $dg->create_user();
2382  
2383          $syscontext = \context_system::instance();
2384  
2385          // Creating specific roles.
2386          $managerole = $dg->create_role(array(
2387              'name' => 'User manage',
2388              'shortname' => 'manage'
2389          ));
2390  
2391          assign_capability('moodle/competency:planmanage', CAP_ALLOW, $managerole, $syscontext->id);
2392          assign_capability('moodle/competency:planview', CAP_ALLOW, $managerole, $syscontext->id);
2393  
2394          $dg->role_assign($managerole, $usermanage->id, $syscontext->id);
2395  
2396          $this->setUser($usermanage);
2397          $plan = array (
2398              'userid' => $usermanage->id,
2399              'status' => \core_competency\plan::STATUS_ACTIVE
2400          );
2401          $pl1 = $lpg->create_plan($plan);
2402          $framework = $lpg->create_framework();
2403          $competency = $lpg->create_competency(
2404                  array('competencyframeworkid' => $framework->get('id'))
2405                  );
2406          $this->assertTrue(external::add_competency_to_plan($pl1->get('id'), $competency->get('id')));
2407  
2408          // A competency cannot be added to plan based on template.
2409          $template = $lpg->create_template();
2410          $plan = array (
2411              'userid' => $usermanage->id,
2412              'status' => \core_competency\plan::STATUS_ACTIVE,
2413              'templateid' => $template->get('id')
2414          );
2415          $pl2 = $lpg->create_plan($plan);
2416          try {
2417              external::add_competency_to_plan(