Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 311 and 402] [Versions 400 and 402] [Versions 401 and 402]

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