Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 39 and 310]

   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   * Workshop module external functions tests
  19   *
  20   * @package    mod_workshop
  21   * @category   external
  22   * @copyright  2017 Juan Leyva <juan@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   * @since      Moodle 3.4
  25   */
  26  
  27  defined('MOODLE_INTERNAL') || die();
  28  
  29  global $CFG;
  30  
  31  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  32  require_once($CFG->dirroot . '/mod/workshop/lib.php');
  33  
  34  use mod_workshop\external\workshop_summary_exporter;
  35  use mod_workshop\external\submission_exporter;
  36  
  37  /**
  38   * Workshop module external functions tests
  39   *
  40   * @package    mod_workshop
  41   * @category   external
  42   * @copyright  2017 Juan Leyva <juan@moodle.com>
  43   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  44   * @since      Moodle 3.4
  45   */
  46  class mod_workshop_external_testcase extends externallib_advanced_testcase {
  47  
  48      /** @var stdClass course object */
  49      private $course;
  50      /** @var stdClass workshop object */
  51      private $workshop;
  52      /** @var stdClass context object */
  53      private $context;
  54      /** @var stdClass cm object */
  55      private $cm;
  56      /** @var stdClass student object */
  57      private $student;
  58      /** @var stdClass teacher object */
  59      private $teacher;
  60      /** @var stdClass student role object */
  61      private $studentrole;
  62      /** @var stdClass teacher role object */
  63      private $teacherrole;
  64  
  65      /**
  66       * Set up for every test
  67       */
  68      public function setUp(): void {
  69          global $DB;
  70          $this->resetAfterTest();
  71          $this->setAdminUser();
  72  
  73          // Setup test data.
  74          $course = new stdClass();
  75          $course->groupmode = SEPARATEGROUPS;
  76          $course->groupmodeforce = true;
  77          $this->course = $this->getDataGenerator()->create_course($course);
  78          $this->workshop = $this->getDataGenerator()->create_module('workshop',
  79              array(
  80                  'course' => $this->course->id,
  81                  'overallfeedbackfiles' => 1,
  82              )
  83          );
  84          $this->context = context_module::instance($this->workshop->cmid);
  85          $this->cm = get_coursemodule_from_instance('workshop', $this->workshop->id);
  86  
  87          // Add grading strategy data (accumulative is the default).
  88          $workshop = new workshop($this->workshop, $this->cm, $this->course);
  89          $strategy = $workshop->grading_strategy_instance();
  90          $data = array();
  91          for ($i = 0; $i < 4; $i++) {
  92              $data['dimensionid__idx_'.$i] = 0;
  93              $data['description__idx_'.$i.'_editor'] = array('text' => "Content $i", 'format' => FORMAT_MOODLE);
  94              $data['grade__idx_'.$i] = 25;
  95              $data['weight__idx_'.$i] = 25;
  96          }
  97          $data['workshopid'] = $workshop->id;
  98          $data['norepeats'] = 4;
  99          $strategy->save_edit_strategy_form((object) $data);
 100  
 101          // Create users.
 102          $this->student = self::getDataGenerator()->create_user();
 103          $this->anotherstudentg1 = self::getDataGenerator()->create_user();
 104          $this->anotherstudentg2 = self::getDataGenerator()->create_user();
 105          $this->teacher = self::getDataGenerator()->create_user();
 106  
 107          // Users enrolments.
 108          $this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
 109          $this->teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
 110          $this->getDataGenerator()->enrol_user($this->student->id, $this->course->id, $this->studentrole->id, 'manual');
 111          $this->getDataGenerator()->enrol_user($this->anotherstudentg1->id, $this->course->id, $this->studentrole->id, 'manual');
 112          $this->getDataGenerator()->enrol_user($this->anotherstudentg2->id, $this->course->id, $this->studentrole->id, 'manual');
 113          $this->getDataGenerator()->enrol_user($this->teacher->id, $this->course->id, $this->teacherrole->id, 'manual');
 114  
 115          $this->group1 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
 116          $this->group2 = $this->getDataGenerator()->create_group(array('courseid' => $this->course->id));
 117          groups_add_member($this->group1, $this->student);
 118          groups_add_member($this->group1, $this->anotherstudentg1);
 119          groups_add_member($this->group2, $this->anotherstudentg2);
 120      }
 121  
 122      /**
 123       * Test test_mod_workshop_get_workshops_by_courses
 124       */
 125      public function test_mod_workshop_get_workshops_by_courses() {
 126  
 127          // Create additional course.
 128          $course2 = self::getDataGenerator()->create_course();
 129  
 130          // Second workshop.
 131          $record = new stdClass();
 132          $record->course = $course2->id;
 133          $workshop2 = self::getDataGenerator()->create_module('workshop', $record);
 134  
 135          // Execute real Moodle enrolment as we'll call unenrol() method on the instance later.
 136          $enrol = enrol_get_plugin('manual');
 137          $enrolinstances = enrol_get_instances($course2->id, true);
 138          foreach ($enrolinstances as $courseenrolinstance) {
 139              if ($courseenrolinstance->enrol == "manual") {
 140                  $instance2 = $courseenrolinstance;
 141                  break;
 142              }
 143          }
 144          $enrol->enrol_user($instance2, $this->student->id, $this->studentrole->id);
 145  
 146          self::setUser($this->student);
 147  
 148          $returndescription = mod_workshop_external::get_workshops_by_courses_returns();
 149  
 150          // Create what we expect to be returned when querying the two courses.
 151          $properties = workshop_summary_exporter::read_properties_definition();
 152          $expectedfields = array_keys($properties);
 153  
 154          // Add expected coursemodule and data.
 155          $workshop1 = $this->workshop;
 156          $workshop1->coursemodule = $workshop1->cmid;
 157          $workshop1->introformat = 1;
 158          $workshop1->introfiles = [];
 159          $workshop1->instructauthorsfiles = [];
 160          $workshop1->instructauthorsformat = 1;
 161          $workshop1->instructreviewersfiles = [];
 162          $workshop1->instructreviewersformat = 1;
 163          $workshop1->conclusionfiles = [];
 164          $workshop1->conclusionformat = 1;
 165          $workshop1->submissiontypetext = 1;
 166          $workshop1->submissiontypefile = 1;
 167  
 168          $workshop2->coursemodule = $workshop2->cmid;
 169          $workshop2->introformat = 1;
 170          $workshop2->introfiles = [];
 171          $workshop2->instructauthorsfiles = [];
 172          $workshop2->instructauthorsformat = 1;
 173          $workshop2->instructreviewersfiles = [];
 174          $workshop2->instructreviewersformat = 1;
 175          $workshop2->conclusionfiles = [];
 176          $workshop2->conclusionformat = 1;
 177          $workshop2->submissiontypetext = 1;
 178          $workshop2->submissiontypefile = 1;
 179  
 180          foreach ($expectedfields as $field) {
 181              if (!empty($properties[$field]) && $properties[$field]['type'] == PARAM_BOOL) {
 182                  $workshop1->{$field} = (bool) $workshop1->{$field};
 183                  $workshop2->{$field} = (bool) $workshop2->{$field};
 184              }
 185              $expected1[$field] = $workshop1->{$field};
 186              $expected2[$field] = $workshop2->{$field};
 187          }
 188  
 189          $expectedworkshops = array($expected2, $expected1);
 190  
 191          // Call the external function passing course ids.
 192          $result = mod_workshop_external::get_workshops_by_courses(array($course2->id, $this->course->id));
 193          $result = external_api::clean_returnvalue($returndescription, $result);
 194  
 195          $this->assertEquals($expectedworkshops, $result['workshops']);
 196          $this->assertCount(0, $result['warnings']);
 197  
 198          // Call the external function without passing course id.
 199          $result = mod_workshop_external::get_workshops_by_courses();
 200          $result = external_api::clean_returnvalue($returndescription, $result);
 201          $this->assertEquals($expectedworkshops, $result['workshops']);
 202          $this->assertCount(0, $result['warnings']);
 203  
 204          // Unenrol user from second course and alter expected workshops.
 205          $enrol->unenrol_user($instance2, $this->student->id);
 206          array_shift($expectedworkshops);
 207  
 208          // Call the external function without passing course id.
 209          $result = mod_workshop_external::get_workshops_by_courses();
 210          $result = external_api::clean_returnvalue($returndescription, $result);
 211          $this->assertEquals($expectedworkshops, $result['workshops']);
 212  
 213          // Call for the second course we unenrolled the user from, expected warning.
 214          $result = mod_workshop_external::get_workshops_by_courses(array($course2->id));
 215          $this->assertCount(1, $result['warnings']);
 216          $this->assertEquals('1', $result['warnings'][0]['warningcode']);
 217          $this->assertEquals($course2->id, $result['warnings'][0]['itemid']);
 218      }
 219  
 220      /**
 221       * Test mod_workshop_get_workshop_access_information for students.
 222       */
 223      public function test_mod_workshop_get_workshop_access_information_student() {
 224  
 225          self::setUser($this->student);
 226          $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
 227          $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
 228          // Check default values for capabilities.
 229          $enabledcaps = array('canpeerassess', 'cansubmit', 'canview', 'canviewauthornames', 'canviewauthorpublished',
 230              'canviewpublishedsubmissions', 'canexportsubmissions');
 231  
 232          foreach ($result as $capname => $capvalue) {
 233              if (strpos($capname, 'can') !== 0) {
 234                  continue;
 235              }
 236              if (in_array($capname, $enabledcaps)) {
 237                  $this->assertTrue($capvalue);
 238              } else {
 239                  $this->assertFalse($capvalue);
 240              }
 241          }
 242          // Now, unassign some capabilities.
 243          unassign_capability('mod/workshop:peerassess', $this->studentrole->id);
 244          unassign_capability('mod/workshop:submit', $this->studentrole->id);
 245          unset($enabledcaps[0]);
 246          unset($enabledcaps[1]);
 247          accesslib_clear_all_caches_for_unit_testing();
 248  
 249          $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
 250          $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
 251          foreach ($result as $capname => $capvalue) {
 252              if (strpos($capname, 'can') !== 0) {
 253                  continue;
 254              }
 255              if (in_array($capname, $enabledcaps)) {
 256                  $this->assertTrue($capvalue);
 257              } else {
 258                  $this->assertFalse($capvalue);
 259              }
 260          }
 261  
 262          // Now, specific functionalities.
 263          $this->assertFalse($result['creatingsubmissionallowed']);
 264          $this->assertFalse($result['modifyingsubmissionallowed']);
 265          $this->assertFalse($result['assessingallowed']);
 266          $this->assertFalse($result['assessingexamplesallowed']);
 267          $this->assertTrue($result['examplesassessedbeforesubmission']);
 268          $this->assertTrue($result['examplesassessedbeforeassessment']);
 269  
 270          // Switch phase.
 271          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 272          $workshop->switch_phase(workshop::PHASE_SUBMISSION);
 273          $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
 274          $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
 275  
 276          $this->assertTrue($result['creatingsubmissionallowed']);
 277          $this->assertTrue($result['modifyingsubmissionallowed']);
 278          $this->assertFalse($result['assessingallowed']);
 279          $this->assertFalse($result['assessingexamplesallowed']);
 280          $this->assertTrue($result['examplesassessedbeforesubmission']);
 281          $this->assertTrue($result['examplesassessedbeforeassessment']);
 282  
 283          // Switch to next (to assessment).
 284          $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
 285          $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
 286          $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
 287  
 288          $this->assertFalse($result['creatingsubmissionallowed']);
 289          $this->assertFalse($result['modifyingsubmissionallowed']);
 290          $this->assertTrue($result['assessingallowed']);
 291          $this->assertFalse($result['assessingexamplesallowed']);
 292          $this->assertTrue($result['examplesassessedbeforesubmission']);
 293          $this->assertTrue($result['examplesassessedbeforeassessment']);
 294      }
 295  
 296      /**
 297       * Test mod_workshop_get_workshop_access_information for teachers.
 298       */
 299      public function test_mod_workshop_get_workshop_access_information_teacher() {
 300  
 301          self::setUser($this->teacher);
 302          $result = mod_workshop_external::get_workshop_access_information($this->workshop->id);
 303          $result = external_api::clean_returnvalue(mod_workshop_external::get_workshop_access_information_returns(), $result);
 304          // Check default values.
 305          $disabledcaps = array('canpeerassess', 'cansubmit');
 306  
 307          foreach ($result as $capname => $capvalue) {
 308              if (strpos($capname, 'can') !== 0) {
 309                  continue;
 310              }
 311              if (in_array($capname, $disabledcaps)) {
 312                  $this->assertFalse($capvalue);
 313              } else {
 314                  $this->assertTrue($capvalue);
 315              }
 316          }
 317  
 318          // Now, specific functionalities.
 319          $this->assertFalse($result['creatingsubmissionallowed']);
 320          $this->assertFalse($result['modifyingsubmissionallowed']);
 321          $this->assertFalse($result['assessingallowed']);
 322          $this->assertFalse($result['assessingexamplesallowed']);
 323      }
 324  
 325      /**
 326       * Test mod_workshop_get_user_plan for students.
 327       */
 328      public function test_mod_workshop_get_user_plan_student() {
 329  
 330          self::setUser($this->student);
 331          $result = mod_workshop_external::get_user_plan($this->workshop->id);
 332          $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
 333  
 334          $this->assertCount(0, $result['userplan']['examples']);  // No examples given.
 335          $this->assertCount(5, $result['userplan']['phases']);  // Always 5 phases.
 336          $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']);  // First phase always setup.
 337          $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops.
 338  
 339          // Switch phase.
 340          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 341          $workshop->switch_phase(workshop::PHASE_SUBMISSION);
 342  
 343          $result = mod_workshop_external::get_user_plan($this->workshop->id);
 344          $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
 345  
 346          $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']);
 347          $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase.
 348      }
 349  
 350      /**
 351       * Test mod_workshop_get_user_plan for teachers.
 352       */
 353      public function test_mod_workshop_get_user_plan_teacher() {
 354  
 355          self::setUser($this->teacher);
 356          $result = mod_workshop_external::get_user_plan($this->workshop->id);
 357          $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
 358  
 359          $this->assertCount(0, $result['userplan']['examples']);  // No examples given.
 360          $this->assertCount(5, $result['userplan']['phases']);  // Always 5 phases.
 361          $this->assertEquals(workshop::PHASE_SETUP, $result['userplan']['phases'][0]['code']);  // First phase always setup.
 362          $this->assertTrue($result['userplan']['phases'][0]['active']); // First phase "Setup" active in new workshops.
 363          $this->assertCount(4, $result['userplan']['phases'][0]['tasks']);  // For new empty workshops, always 4 tasks.
 364  
 365          foreach ($result['userplan']['phases'][0]['tasks'] as $task) {
 366              if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'editform') {
 367                  $this->assertEquals(1, $task['completed']);
 368              } else {
 369                  $this->assertEmpty($task['completed']);
 370              }
 371          }
 372  
 373          // Do some of the tasks asked - switch phase.
 374          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 375          $workshop->switch_phase(workshop::PHASE_SUBMISSION);
 376  
 377          $result = mod_workshop_external::get_user_plan($this->workshop->id);
 378          $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
 379          foreach ($result['userplan']['phases'][0]['tasks'] as $task) {
 380              if ($task['code'] == 'intro' || $task['code'] == 'instructauthors' || $task['code'] == 'editform' ||
 381                      $task['code'] == 'switchtonextphase') {
 382                  $this->assertEquals(1, $task['completed']);
 383              } else {
 384                  $this->assertEmpty($task['completed']);
 385              }
 386          }
 387  
 388          $result = mod_workshop_external::get_user_plan($this->workshop->id);
 389          $result = external_api::clean_returnvalue(mod_workshop_external::get_user_plan_returns(), $result);
 390  
 391          $this->assertEquals(workshop::PHASE_SUBMISSION, $result['userplan']['phases'][1]['code']);
 392          $this->assertTrue($result['userplan']['phases'][1]['active']); // We are now in submission phase.
 393      }
 394  
 395      /**
 396       * Test test_view_workshop invalid id.
 397       */
 398      public function test_view_workshop_invalid_id() {
 399          $this->expectException('moodle_exception');
 400          mod_workshop_external::view_workshop(0);
 401      }
 402  
 403      /**
 404       * Test test_view_workshop user not enrolled.
 405       */
 406      public function test_view_workshop_user_not_enrolled() {
 407          // Test not-enrolled user.
 408          $usernotenrolled = self::getDataGenerator()->create_user();
 409          $this->setUser($usernotenrolled);
 410          $this->expectException('moodle_exception');
 411          mod_workshop_external::view_workshop($this->workshop->id);
 412      }
 413  
 414      /**
 415       * Test test_view_workshop user student.
 416       */
 417      public function test_view_workshop_user_student() {
 418          // Test user with full capabilities.
 419          $this->setUser($this->student);
 420  
 421          // Trigger and capture the event.
 422          $sink = $this->redirectEvents();
 423  
 424          $result = mod_workshop_external::view_workshop($this->workshop->id);
 425          $result = external_api::clean_returnvalue(mod_workshop_external::view_workshop_returns(), $result);
 426          $this->assertTrue($result['status']);
 427  
 428          $events = $sink->get_events();
 429          $this->assertCount(1, $events);
 430          $event = array_shift($events);
 431  
 432          // Checking that the event contains the expected values.
 433          $this->assertInstanceOf('\mod_workshop\event\course_module_viewed', $event);
 434          $this->assertEquals($this->context, $event->get_context());
 435          $moodleworkshop = new \moodle_url('/mod/workshop/view.php', array('id' => $this->cm->id));
 436          $this->assertEquals($moodleworkshop, $event->get_url());
 437          $this->assertEventContextNotUsed($event);
 438          $this->assertNotEmpty($event->get_name());
 439      }
 440  
 441      /**
 442       * Test test_view_workshop user missing capabilities.
 443       */
 444      public function test_view_workshop_user_missing_capabilities() {
 445          // Test user with no capabilities.
 446          // We need a explicit prohibit since this capability is only defined in authenticated user and guest roles.
 447          assign_capability('mod/workshop:view', CAP_PROHIBIT, $this->studentrole->id, $this->context->id);
 448          // Empty all the caches that may be affected  by this change.
 449          accesslib_clear_all_caches_for_unit_testing();
 450          course_modinfo::clear_instance_cache();
 451  
 452          $this->setUser($this->student);
 453          $this->expectException('moodle_exception');
 454          mod_workshop_external::view_workshop($this->workshop->id);
 455      }
 456  
 457      /**
 458       * Test test_add_submission.
 459       */
 460      public function test_add_submission() {
 461          $fs = get_file_storage();
 462  
 463          // Test user with full capabilities.
 464          $this->setUser($this->student);
 465  
 466          $title = 'Submission title';
 467          $content = 'Submission contents';
 468  
 469          // Create a file in a draft area for inline attachments.
 470          $draftidinlineattach = file_get_unused_draft_itemid();
 471          $usercontext = context_user::instance($this->student->id);
 472          $filenameimg = 'shouldbeanimage.txt';
 473          $filerecordinline = array(
 474              'contextid' => $usercontext->id,
 475              'component' => 'user',
 476              'filearea'  => 'draft',
 477              'itemid'    => $draftidinlineattach,
 478              'filepath'  => '/',
 479              'filename'  => $filenameimg,
 480          );
 481          $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
 482  
 483          // Create a file in a draft area for regular attachments.
 484          $draftidattach = file_get_unused_draft_itemid();
 485          $filerecordattach = $filerecordinline;
 486          $attachfilename = 'attachment.txt';
 487          $filerecordattach['filename'] = $attachfilename;
 488          $filerecordattach['itemid'] = $draftidattach;
 489          $fs->create_file_from_string($filerecordattach, 'simple text attachment');
 490  
 491          // Switch to submission phase.
 492          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 493          $workshop->switch_phase(workshop::PHASE_SUBMISSION);
 494  
 495          $result = mod_workshop_external::add_submission($this->workshop->id, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
 496              $draftidattach);
 497          $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
 498          $this->assertEmpty($result['warnings']);
 499  
 500          // Check submission created.
 501          $submission = $workshop->get_submission_by_author($this->student->id);
 502          $this->assertTrue($result['status']);
 503          $this->assertEquals($result['submissionid'], $submission->id);
 504          $this->assertEquals($title, $submission->title);
 505          $this->assertEquals($content, $submission->content);
 506  
 507          // Check files.
 508          $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_content', $submission->id);
 509          $this->assertCount(2, $contentfiles);
 510          foreach ($contentfiles as $file) {
 511              if ($file->is_directory()) {
 512                  continue;
 513              } else {
 514                  $this->assertEquals($filenameimg, $file->get_filename());
 515              }
 516          }
 517          $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_attachment', $submission->id);
 518          $this->assertCount(2, $contentfiles);
 519          foreach ($contentfiles as $file) {
 520              if ($file->is_directory()) {
 521                  continue;
 522              } else {
 523                  $this->assertEquals($attachfilename, $file->get_filename());
 524              }
 525          }
 526      }
 527  
 528      /**
 529       * Test test_add_submission invalid phase.
 530       */
 531      public function test_add_submission_invalid_phase() {
 532          $this->setUser($this->student);
 533  
 534          $this->expectException('moodle_exception');
 535          mod_workshop_external::add_submission($this->workshop->id, 'Test');
 536      }
 537  
 538      /**
 539       * Test test_add_submission empty title.
 540       */
 541      public function test_add_submission_empty_title() {
 542          $this->setUser($this->student);
 543  
 544          // Switch to submission phase.
 545          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 546          $workshop->switch_phase(workshop::PHASE_SUBMISSION);
 547  
 548          $this->expectException('moodle_exception');
 549          mod_workshop_external::add_submission($this->workshop->id, '');
 550      }
 551  
 552      /**
 553       * Test test_add_submission already added.
 554       */
 555      public function test_add_submission_already_added() {
 556          $this->setUser($this->student);
 557  
 558          $usercontext = context_user::instance($this->student->id);
 559          $fs = get_file_storage();
 560          $draftidattach = file_get_unused_draft_itemid();
 561          $filerecordattach = [
 562              'contextid' => $usercontext->id,
 563              'component' => 'user',
 564              'filearea'  => 'draft',
 565              'itemid'    => $draftidattach,
 566              'filepath'  => '/',
 567              'filename'  => 'attachement.txt'
 568          ];
 569          $fs->create_file_from_string($filerecordattach, 'simple text attachment');
 570  
 571          // Switch to submission phase.
 572          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 573          $workshop->switch_phase(workshop::PHASE_SUBMISSION);
 574  
 575          // Create the submission.
 576          $result = mod_workshop_external::add_submission($this->workshop->id, 'My submission', '', FORMAT_MOODLE, 0, $draftidattach);
 577          $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
 578  
 579          // Try to create it again.
 580          $result = mod_workshop_external::add_submission($this->workshop->id, 'My submission', '', FORMAT_MOODLE, 0, $draftidattach);
 581          $result = external_api::clean_returnvalue(mod_workshop_external::add_submission_returns(), $result);
 582          $this->assertFalse($result['status']);
 583          $this->assertArrayNotHasKey('submissionid', $result);
 584          $this->assertCount(1, $result['warnings']);
 585          $this->assertEquals('fielderror', $result['warnings'][0]['warningcode']);
 586          $this->assertEquals('title', $result['warnings'][0]['item']);
 587      }
 588  
 589      /**
 590       * Helper method to create a submission for testing for the given user.
 591       *
 592       * @param int $user the submission will be created by this student.
 593       * @return int the submission id
 594       */
 595      protected function create_test_submission($user) {
 596          // Test user with full capabilities.
 597          $this->setUser($user);
 598  
 599          $title = 'Submission title';
 600          $content = 'Submission contents';
 601  
 602          // Create a file in a draft area for inline attachments.
 603          $fs = get_file_storage();
 604          $draftidinlineattach = file_get_unused_draft_itemid();
 605          $usercontext = context_user::instance($user->id);
 606          $filenameimg = 'shouldbeanimage.txt';
 607          $filerecordinline = array(
 608              'contextid' => $usercontext->id,
 609              'component' => 'user',
 610              'filearea'  => 'draft',
 611              'itemid'    => $draftidinlineattach,
 612              'filepath'  => '/',
 613              'filename'  => $filenameimg,
 614          );
 615          $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
 616  
 617          // Create a file in a draft area for regular attachments.
 618          $draftidattach = file_get_unused_draft_itemid();
 619          $filerecordattach = $filerecordinline;
 620          $attachfilename = 'attachment.txt';
 621          $filerecordattach['filename'] = $attachfilename;
 622          $filerecordattach['itemid'] = $draftidattach;
 623          $fs->create_file_from_string($filerecordattach, 'simple text attachment');
 624  
 625          // Switch to submission phase.
 626          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 627          $workshop->switch_phase(workshop::PHASE_SUBMISSION);
 628  
 629          $result = mod_workshop_external::add_submission($this->workshop->id, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
 630              $draftidattach);
 631          return $result['submissionid'];
 632      }
 633  
 634      /**
 635       * Test test_update_submission.
 636       */
 637      public function test_update_submission() {
 638  
 639          // Create the submission that will be updated.
 640          $submissionid = $this->create_test_submission($this->student);
 641  
 642          // Test user with full capabilities.
 643          $this->setUser($this->student);
 644  
 645          $title = 'Submission new title';
 646          $content = 'Submission new contents';
 647  
 648          // Create a different file in a draft area for inline attachments.
 649          $fs = get_file_storage();
 650          $draftidinlineattach = file_get_unused_draft_itemid();
 651          $usercontext = context_user::instance($this->student->id);
 652          $filenameimg = 'shouldbeanimage_new.txt';
 653          $filerecordinline = array(
 654              'contextid' => $usercontext->id,
 655              'component' => 'user',
 656              'filearea'  => 'draft',
 657              'itemid'    => $draftidinlineattach,
 658              'filepath'  => '/',
 659              'filename'  => $filenameimg,
 660          );
 661          $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
 662  
 663          // Create a different file in a draft area for regular attachments.
 664          $draftidattach = file_get_unused_draft_itemid();
 665          $filerecordattach = $filerecordinline;
 666          $attachfilename = 'attachment_new.txt';
 667          $filerecordattach['filename'] = $attachfilename;
 668          $filerecordattach['itemid'] = $draftidattach;
 669          $fs->create_file_from_string($filerecordattach, 'simple text attachment');
 670  
 671          $result = mod_workshop_external::update_submission($submissionid, $title, $content, FORMAT_MOODLE, $draftidinlineattach,
 672              $draftidattach);
 673          $result = external_api::clean_returnvalue(mod_workshop_external::update_submission_returns(), $result);
 674          $this->assertEmpty($result['warnings']);
 675  
 676          // Check submission updated.
 677          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 678          $submission = $workshop->get_submission_by_id($submissionid);
 679          $this->assertTrue($result['status']);
 680          $this->assertEquals($title, $submission->title);
 681          $this->assertEquals($content, $submission->content);
 682  
 683          // Check files.
 684          $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_content', $submission->id);
 685          $this->assertCount(2, $contentfiles);
 686          foreach ($contentfiles as $file) {
 687              if ($file->is_directory()) {
 688                  continue;
 689              } else {
 690                  $this->assertEquals($filenameimg, $file->get_filename());
 691              }
 692          }
 693          $contentfiles = $fs->get_area_files($this->context->id, 'mod_workshop', 'submission_attachment', $submission->id);
 694          $this->assertCount(2, $contentfiles);
 695          foreach ($contentfiles as $file) {
 696              if ($file->is_directory()) {
 697                  continue;
 698              } else {
 699                  $this->assertEquals($attachfilename, $file->get_filename());
 700              }
 701          }
 702      }
 703  
 704      /**
 705       * Test test_update_submission belonging to other user.
 706       */
 707      public function test_update_submission_of_other_user() {
 708          // Create the submission that will be updated.
 709          $submissionid = $this->create_test_submission($this->student);
 710  
 711          $this->setUser($this->teacher);
 712  
 713          $this->expectException('moodle_exception');
 714          mod_workshop_external::update_submission($submissionid, 'Test');
 715      }
 716  
 717      /**
 718       * Test test_update_submission invalid phase.
 719       */
 720      public function test_update_submission_invalid_phase() {
 721          // Create the submission that will be updated.
 722          $submissionid = $this->create_test_submission($this->student);
 723  
 724          $this->setUser($this->student);
 725  
 726          // Switch to assessment phase.
 727          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 728          $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
 729  
 730          $this->expectException('moodle_exception');
 731          mod_workshop_external::update_submission($submissionid, 'Test');
 732      }
 733  
 734      /**
 735       * Test test_update_submission empty title.
 736       */
 737      public function test_update_submission_empty_title() {
 738          // Create the submission that will be updated.
 739          $submissionid = $this->create_test_submission($this->student);
 740  
 741          $this->setUser($this->student);
 742  
 743          $this->expectException('moodle_exception');
 744          mod_workshop_external::update_submission($submissionid, '');
 745      }
 746  
 747      /**
 748       * Test test_delete_submission.
 749       */
 750      public function test_delete_submission() {
 751  
 752          // Create the submission that will be deleted.
 753          $submissionid = $this->create_test_submission($this->student);
 754  
 755          $this->setUser($this->student);
 756  
 757          // Trigger and capture the event.
 758          $sink = $this->redirectEvents();
 759  
 760          $result = mod_workshop_external::delete_submission($submissionid);
 761          $result = external_api::clean_returnvalue(mod_workshop_external::delete_submission_returns(), $result);
 762          $this->assertEmpty($result['warnings']);
 763          $this->assertTrue($result['status']);
 764          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 765          $submission = $workshop->get_submission_by_author($this->student->id);
 766          $this->assertFalse($submission);
 767  
 768          $events = $sink->get_events();
 769          $this->assertCount(1, $events);
 770          $event = array_shift($events);
 771  
 772          // Checking event.
 773          $this->assertInstanceOf('\mod_workshop\event\submission_deleted', $event);
 774          $this->assertEquals($this->context, $event->get_context());
 775      }
 776  
 777      /**
 778       * Test test_delete_submission_with_assessments.
 779       */
 780      public function test_delete_submission_with_assessments() {
 781  
 782          // Create the submission that will be deleted.
 783          $submissionid = $this->create_test_submission($this->student);
 784  
 785          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
 786          $workshopgenerator->create_assessment($submissionid, $this->teacher->id, array(
 787              'weight' => 3,
 788              'grade' => 95.00000,
 789          ));
 790  
 791          $this->setUser($this->student);
 792          $this->expectException('moodle_exception');
 793          mod_workshop_external::delete_submission($submissionid);
 794      }
 795  
 796      /**
 797       * Test test_delete_submission_invalid_phase.
 798       */
 799      public function test_delete_submission_invalid_phase() {
 800  
 801          // Create the submission that will be deleted.
 802          $submissionid = $this->create_test_submission($this->student);
 803  
 804          // Switch to assessment phase.
 805          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 806          $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
 807  
 808          $this->setUser($this->student);
 809          $this->expectException('moodle_exception');
 810          mod_workshop_external::delete_submission($submissionid);
 811      }
 812  
 813      /**
 814       * Test test_delete_submission_as_teacher.
 815       */
 816      public function test_delete_submission_as_teacher() {
 817  
 818          // Create the submission that will be deleted.
 819          $submissionid = $this->create_test_submission($this->student);
 820  
 821          $this->setUser($this->teacher);
 822          $result = mod_workshop_external::delete_submission($submissionid);
 823          $result = external_api::clean_returnvalue(mod_workshop_external::delete_submission_returns(), $result);
 824          $this->assertEmpty($result['warnings']);
 825          $this->assertTrue($result['status']);
 826      }
 827  
 828      /**
 829       * Test test_delete_submission_other_user.
 830       */
 831      public function test_delete_submission_other_user() {
 832  
 833          $anotheruser = self::getDataGenerator()->create_user();
 834          $this->getDataGenerator()->enrol_user($anotheruser->id, $this->course->id, $this->studentrole->id, 'manual');
 835          // Create the submission that will be deleted.
 836          $submissionid = $this->create_test_submission($this->student);
 837  
 838          $this->setUser($anotheruser);
 839          $this->expectException('moodle_exception');
 840          mod_workshop_external::delete_submission($submissionid);
 841      }
 842  
 843      /**
 844       * Test test_get_submissions_student.
 845       */
 846      public function test_get_submissions_student() {
 847  
 848          // Create a couple of submissions with files.
 849          $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
 850          $secondsubmissionid = $this->create_test_submission($this->anotherstudentg1);
 851  
 852          $this->setUser($this->student);
 853          $result = mod_workshop_external::get_submissions($this->workshop->id);
 854          $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
 855          // We should get just our submission.
 856          $this->assertCount(1, $result['submissions']);
 857          $this->assertEquals(1, $result['totalcount']);
 858          $this->assertEquals($firstsubmissionid, $result['submissions'][0]['id']);
 859          $this->assertCount(1, $result['submissions'][0]['contentfiles']); // Check we retrieve submission text files.
 860          $this->assertCount(1, $result['submissions'][0]['attachmentfiles']); // Check we retrieve attachment files.
 861          // We shoul not see the grade or feedback information.
 862          $properties = submission_exporter::properties_definition();
 863          foreach ($properties as $attribute => $settings) {
 864              if (!empty($settings['optional'])) {
 865                  if (isset($result['submissions'][0][$attribute])) {
 866                      echo "error $attribute";
 867                  }
 868                  $this->assertFalse(isset($result['submissions'][0][$attribute]));
 869              }
 870          }
 871      }
 872  
 873      /**
 874       * Test test_get_submissions_published_student.
 875       */
 876      public function test_get_submissions_published_student() {
 877  
 878          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 879          $workshop->switch_phase(workshop::PHASE_CLOSED);
 880          // Create a couple of submissions with files.
 881          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
 882          $submission = array('published' => 1);
 883          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id, $submission);
 884  
 885          $this->setUser($this->student);
 886          $result = mod_workshop_external::get_submissions($this->workshop->id);
 887          $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
 888          // We should get just our submission.
 889          $this->assertCount(1, $result['submissions']);
 890          $this->assertEquals(1, $result['totalcount']);
 891          $this->assertEquals($submissionid, $result['submissions'][0]['id']);
 892  
 893          // Check with group restrictions.
 894          $this->setUser($this->anotherstudentg2);
 895          $result = mod_workshop_external::get_submissions($this->workshop->id);
 896          $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
 897          $this->assertCount(0, $result['submissions']);  // I can't see other users in separated groups.
 898          $this->assertEquals(0, $result['totalcount']);
 899      }
 900  
 901      /**
 902       * Test test_get_submissions_from_student_with_feedback_from_teacher.
 903       */
 904      public function test_get_submissions_from_student_with_feedback_from_teacher() {
 905          global $DB;
 906  
 907          // Create a couple of submissions with files.
 908          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
 909          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
 910          // Create teacher feedback for submission.
 911          $record = new stdclass();
 912          $record->id = $submissionid;
 913          $record->gradeover = 9;
 914          $record->gradeoverby = $this->teacher->id;
 915          $record->feedbackauthor = 'Hey';
 916          $record->feedbackauthorformat = FORMAT_MOODLE;
 917          $record->published = 1;
 918          $DB->update_record('workshop_submissions', $record);
 919  
 920          // Remove teacher caps.
 921          assign_capability('mod/workshop:viewallsubmissions', CAP_PROHIBIT, $this->teacher->id, $this->context->id);
 922          // Empty all the caches that may be affected  by this change.
 923          accesslib_clear_all_caches_for_unit_testing();
 924          course_modinfo::clear_instance_cache();
 925  
 926          $this->setUser($this->teacher);
 927          $result = mod_workshop_external::get_submissions($this->workshop->id, $this->student->id);
 928          $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
 929          // We should get just our submission.
 930          $this->assertEquals(1, $result['totalcount']);
 931          $this->assertEquals($submissionid, $result['submissions'][0]['id']);
 932      }
 933  
 934      /**
 935       * Test test_get_submissions_from_students_as_teacher.
 936       */
 937      public function test_get_submissions_from_students_as_teacher() {
 938  
 939          // Create a couple of submissions with files.
 940          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
 941          $submissionid1 = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
 942          $submissionid2 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id);
 943          $submissionid3 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg2->id);
 944  
 945          $this->setUser($this->teacher);
 946          $result = mod_workshop_external::get_submissions($this->workshop->id); // Get all.
 947          $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
 948          $this->assertEquals(3, $result['totalcount']);
 949          $this->assertCount(3, $result['submissions']);
 950  
 951          $result = mod_workshop_external::get_submissions($this->workshop->id, 0, 0, 0, 2); // Check pagination.
 952          $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
 953          $this->assertEquals(3, $result['totalcount']);
 954          $this->assertCount(2, $result['submissions']);
 955  
 956          $result = mod_workshop_external::get_submissions($this->workshop->id, 0, $this->group2->id); // Get group 2.
 957          $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
 958          $this->assertEquals(1, $result['totalcount']);
 959          $this->assertCount(1, $result['submissions']);
 960          $this->assertEquals($submissionid3, $result['submissions'][0]['id']);
 961  
 962          $result = mod_workshop_external::get_submissions($this->workshop->id, $this->anotherstudentg1->id); // Get one.
 963          $result = external_api::clean_returnvalue(mod_workshop_external::get_submissions_returns(), $result);
 964          $this->assertEquals(1, $result['totalcount']);
 965          $this->assertEquals($submissionid2, $result['submissions'][0]['id']);
 966      }
 967  
 968      /**
 969       * Test test_get_submission_student.
 970       */
 971      public function test_get_submission_student() {
 972  
 973          // Create a couple of submissions with files.
 974          $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
 975  
 976          $workshop = new workshop($this->workshop, $this->cm, $this->course);
 977          $workshop->switch_phase(workshop::PHASE_CLOSED);
 978          $this->setUser($this->student);
 979          $result = mod_workshop_external::get_submission($firstsubmissionid);
 980          $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
 981          $this->assertEquals($firstsubmissionid, $result['submission']['id']);
 982          $this->assertCount(1, $result['submission']['contentfiles']); // Check we retrieve submission text files.
 983          $this->assertCount(1, $result['submission']['attachmentfiles']); // Check we retrieve attachment files.
 984          $this->assertArrayHasKey('feedbackauthor', $result['submission']);
 985          $this->assertArrayNotHasKey('grade', $result['submission']);
 986          $this->assertArrayNotHasKey('gradeover', $result['submission']);
 987          $this->assertArrayHasKey('gradeoverby', $result['submission']);
 988          $this->assertArrayNotHasKey('timegraded', $result['submission']);
 989  
 990          // Switch to a different phase (where feedback won't be available).
 991          $workshop->switch_phase(workshop::PHASE_EVALUATION);
 992          $result = mod_workshop_external::get_submission($firstsubmissionid);
 993          $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
 994          $this->assertEquals($firstsubmissionid, $result['submission']['id']);
 995          $this->assertCount(1, $result['submission']['contentfiles']); // Check we retrieve submission text files.
 996          $this->assertCount(1, $result['submission']['attachmentfiles']); // Check we retrieve attachment files.
 997          $this->assertArrayNotHasKey('feedbackauthor', $result['submission']);
 998          $this->assertArrayNotHasKey('grade', $result['submission']);
 999          $this->assertArrayNotHasKey('gradeover', $result['submission']);
1000          $this->assertArrayNotHasKey('gradeoverby', $result['submission']);
1001          $this->assertArrayNotHasKey('timegraded', $result['submission']);
1002      }
1003  
1004      /**
1005       * Test test_get_submission_i_reviewed.
1006       */
1007      public function test_get_submission_i_reviewed() {
1008  
1009          // Create a couple of submissions with files.
1010          $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
1011          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1012          $workshopgenerator->create_assessment($firstsubmissionid, $this->anotherstudentg1->id, array(
1013              'weight' => 3,
1014              'grade' => 95,
1015          ));
1016          // Now try to get the submission I just reviewed.
1017          $this->setUser($this->anotherstudentg1);
1018          $result = mod_workshop_external::get_submission($firstsubmissionid);
1019          $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1020          $this->assertEquals($firstsubmissionid, $result['submission']['id']);
1021          $this->assertCount(1, $result['submission']['contentfiles']); // Check we retrieve submission text files.
1022          $this->assertCount(1, $result['submission']['attachmentfiles']); // Check we retrieve attachment files.
1023          $this->assertArrayNotHasKey('feedbackauthor', $result['submission']);
1024          $this->assertArrayNotHasKey('grade', $result['submission']);
1025          $this->assertArrayNotHasKey('gradeover', $result['submission']);
1026          $this->assertArrayNotHasKey('gradeoverby', $result['submission']);
1027          $this->assertArrayNotHasKey('timegraded', $result['submission']);
1028      }
1029  
1030      /**
1031       * Test test_get_submission_other_student.
1032       */
1033      public function test_get_submission_other_student() {
1034  
1035          // Create a couple of submissions with files.
1036          $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
1037          // Expect failure.
1038          $this->setUser($this->anotherstudentg1);
1039          $this->expectException('moodle_exception');
1040          $result = mod_workshop_external::get_submission($firstsubmissionid);
1041      }
1042  
1043      /**
1044       * Test test_get_submission_published_student.
1045       */
1046      public function test_get_submission_published_student() {
1047  
1048          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1049          $workshop->switch_phase(workshop::PHASE_CLOSED);
1050          // Create a couple of submissions with files.
1051          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1052          $submission = array('published' => 1);
1053          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id, $submission);
1054  
1055          $this->setUser($this->student);
1056          $result = mod_workshop_external::get_submission($submissionid);
1057          $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1058          $this->assertEquals($submissionid, $result['submission']['id']);
1059          // Check that the student don't see the other student grade/feedback data even if is published.
1060          // We should not see the grade or feedback information.
1061          $properties = submission_exporter::properties_definition();
1062          $this->assertArrayNotHasKey('feedbackauthor', $result['submission']);
1063          $this->assertArrayNotHasKey('grade', $result['submission']);
1064          $this->assertArrayNotHasKey('gradeover', $result['submission']);
1065          $this->assertArrayNotHasKey('gradeoverby', $result['submission']);
1066          $this->assertArrayNotHasKey('timegraded', $result['submission']);
1067  
1068          // Check with group restrictions.
1069          $this->setUser($this->anotherstudentg2);
1070          $this->expectException('moodle_exception');
1071          mod_workshop_external::get_submission($submissionid);
1072      }
1073  
1074      /**
1075       * Test test_get_submission_from_student_with_feedback_from_teacher.
1076       */
1077      public function test_get_submission_from_student_with_feedback_from_teacher() {
1078          global $DB;
1079  
1080          // Create a couple of submissions with files.
1081          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1082          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1083          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1084          $workshop->switch_phase(workshop::PHASE_CLOSED);
1085          // Create teacher feedback for submission.
1086          $record = new stdclass();
1087          $record->id = $submissionid;
1088          $record->gradeover = 9;
1089          $record->gradeoverby = $this->teacher->id;
1090          $record->feedbackauthor = 'Hey';
1091          $record->feedbackauthorformat = FORMAT_MOODLE;
1092          $record->published = 1;
1093          $record->timegraded = time();
1094          $DB->update_record('workshop_submissions', $record);
1095  
1096          $this->setUser($this->teacher);
1097          $result = mod_workshop_external::get_submission($submissionid);
1098          $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1099          $this->assertEquals($submissionid, $result['submission']['id']);
1100          $this->assertEquals($record->feedbackauthor, $result['submission']['feedbackauthor']);
1101          $this->assertEquals($record->gradeover, $result['submission']['gradeover']);
1102          $this->assertEquals($record->gradeoverby, $result['submission']['gradeoverby']);
1103          $this->assertEquals($record->timegraded, $result['submission']['timegraded']);
1104  
1105          // Go to phase where feedback and grades are not yet available.
1106          $workshop->switch_phase(workshop::PHASE_SUBMISSION);
1107          $result = mod_workshop_external::get_submission($submissionid);
1108          $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1109          $this->assertArrayNotHasKey('feedbackauthor', $result['submission']);
1110          $this->assertArrayNotHasKey('grade', $result['submission']);
1111          $this->assertArrayNotHasKey('gradeover', $result['submission']);
1112          $this->assertArrayNotHasKey('gradeoverby', $result['submission']);
1113          $this->assertArrayNotHasKey('timegraded', $result['submission']);
1114  
1115          // Remove teacher caps to view and go to valid phase.
1116          $workshop->switch_phase(workshop::PHASE_EVALUATION);
1117          unassign_capability('mod/workshop:viewallsubmissions', $this->teacherrole->id);
1118          // Empty all the caches that may be affected  by this change.
1119          accesslib_clear_all_caches_for_unit_testing();
1120  
1121          $this->expectException('moodle_exception');
1122          mod_workshop_external::get_submission($submissionid);
1123      }
1124  
1125      /**
1126       * Test test_get_submission_from_students_as_teacher.
1127       */
1128      public function test_get_submission_from_students_as_teacher() {
1129          // Create a couple of submissions with files.
1130          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1131          $submissionid1 = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1132          $submissionid2 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id);
1133          $submissionid3 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg2->id);
1134  
1135          $this->setUser($this->teacher);
1136          $result = mod_workshop_external::get_submission($submissionid1); // Get all.
1137          $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1138          $this->assertEquals($submissionid1, $result['submission']['id']);
1139  
1140          $result = mod_workshop_external::get_submission($submissionid3); // Get group 2.
1141          $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_returns(), $result);
1142          $this->assertEquals($submissionid3, $result['submission']['id']);
1143      }
1144  
1145  
1146      /**
1147       * Test get_submission_assessments_student.
1148       */
1149      public function test_get_submission_assessments_student() {
1150  
1151          // Create the submission that will be deleted.
1152          $submissionid = $this->create_test_submission($this->student);
1153  
1154          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1155          $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1156              'weight' => 3,
1157              'grade' => 95,
1158          ));
1159          $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1160              'weight' => 2,
1161              'grade' => 90,
1162          ));
1163  
1164          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1165          $workshop->switch_phase(workshop::PHASE_CLOSED);
1166          $this->setUser($this->student);
1167          $result = mod_workshop_external::get_submission_assessments($submissionid);
1168          $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_assessments_returns(), $result);
1169          $this->assertCount(2, $result['assessments']);  // I received my two assessments.
1170          foreach ($result['assessments'] as $assessment) {
1171              if ($assessment['grade'] == 90) {
1172                  // My own assessment, I can see me.
1173                  $this->assertEquals($this->student->id, $assessment['reviewerid']);
1174              } else {
1175                  // Student's can't see who did the review.
1176                  $this->assertEquals(0, $assessment['reviewerid']);
1177              }
1178          }
1179      }
1180  
1181      /**
1182       * Test get_submission_assessments_invalid_phase.
1183       */
1184      public function test_get_submission_assessments_invalid_phase() {
1185  
1186          // Create the submission that will be deleted.
1187          $submissionid = $this->create_test_submission($this->student);
1188  
1189          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1190          $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1191              'weight' => 3,
1192              'grade' => 95,
1193          ));
1194  
1195          $this->expectException('moodle_exception');
1196          mod_workshop_external::get_submission_assessments($submissionid);
1197      }
1198  
1199      /**
1200       * Test get_submission_assessments_teacher.
1201       */
1202      public function test_get_submission_assessments_teacher() {
1203  
1204          // Create the submission that will be deleted.
1205          $submissionid = $this->create_test_submission($this->student);
1206  
1207          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1208          $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1209              'weight' => 1,
1210              'grade' => 50,
1211          ));
1212  
1213          $this->setUser($this->teacher);
1214          $result = mod_workshop_external::get_submission_assessments($submissionid);
1215          $result = external_api::clean_returnvalue(mod_workshop_external::get_submission_assessments_returns(), $result);
1216          $this->assertCount(1, $result['assessments']);
1217          $this->assertEquals(50, $result['assessments'][0]['grade']);
1218          $this->assertEquals($assessmentid, $result['assessments'][0]['id']);
1219      }
1220  
1221      /**
1222       * Test get_assessment_author.
1223       */
1224      public function test_get_assessment_author() {
1225  
1226          // Create the submission.
1227          $submissionid = $this->create_test_submission($this->anotherstudentg1);
1228  
1229          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1230          $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1231              'weight' => 2,
1232              'grade' => 90,
1233          ));
1234  
1235          // Switch to closed phase.
1236          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1237          $workshop->switch_phase(workshop::PHASE_CLOSED);
1238          $this->setUser($this->anotherstudentg1);
1239          $result = mod_workshop_external::get_assessment($assessmentid);
1240          $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1241          $this->assertEquals($assessmentid, $result['assessment']['id']);
1242          $this->assertEquals(90, $result['assessment']['grade']);
1243          // I can't see the reviewer review.
1244          $this->assertFalse(isset($result['assessment']['feedbackreviewer']));
1245      }
1246  
1247      /**
1248       * Test get_assessment_reviewer.
1249       */
1250      public function test_get_assessment_reviewer() {
1251  
1252          // Create the submission.
1253          $submissionid = $this->create_test_submission($this->anotherstudentg1);
1254  
1255          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1256          $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1257              'weight' => 2,
1258              'grade' => 90,
1259          ));
1260  
1261          // Switch to closed phase.
1262          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1263          $workshop->switch_phase(workshop::PHASE_CLOSED);
1264          $this->setUser($this->student);
1265          $result = mod_workshop_external::get_assessment($assessmentid);
1266          $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1267          $this->assertEquals($assessmentid, $result['assessment']['id']);
1268          $this->assertEquals(90, $result['assessment']['grade']);
1269          // I can see the reviewer review.
1270          $this->assertTrue(isset($result['assessment']['feedbackreviewer']));
1271      }
1272  
1273      /**
1274       * Test get_assessment_teacher.
1275       */
1276      public function test_get_assessment_teacher() {
1277  
1278          // Create the submission.
1279          $submissionid = $this->create_test_submission($this->anotherstudentg1);
1280  
1281          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1282          $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1283              'weight' => 2,
1284              'grade' => 90,
1285          ));
1286  
1287          // Switch to closed phase.
1288          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1289          $workshop->switch_phase(workshop::PHASE_CLOSED);
1290          $this->setUser($this->teacher);
1291          $result = mod_workshop_external::get_assessment($assessmentid);
1292          $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1293          $this->assertEquals($assessmentid, $result['assessment']['id']);
1294          $this->assertEquals(90, $result['assessment']['grade']);
1295      }
1296  
1297      /**
1298       * Test get_assessment_student_invalid_phase.
1299       */
1300      public function test_get_assessment_student_invalid_phase() {
1301  
1302          // Create the submission.
1303          $submissionid = $this->create_test_submission($this->anotherstudentg1);
1304  
1305          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1306          $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1307              'weight' => 2,
1308              'grade' => 90,
1309          ));
1310  
1311          // Switch to closed phase.
1312          $this->setUser($this->anotherstudentg1);
1313  
1314          $this->expectException('moodle_exception');
1315          mod_workshop_external::get_assessment($assessmentid);
1316      }
1317  
1318      /**
1319       * Test get_assessment_student_invalid_user.
1320       */
1321      public function test_get_assessment_student_invalid_user() {
1322  
1323          // Create the submission.
1324          $submissionid = $this->create_test_submission($this->anotherstudentg1);
1325  
1326          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1327          $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->student->id, array(
1328              'weight' => 2,
1329              'grade' => 90,
1330          ));
1331  
1332          // Switch to closed phase.
1333          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1334          $workshop->switch_phase(workshop::PHASE_CLOSED);
1335          $this->setUser($this->anotherstudentg2);
1336  
1337          $this->expectException('moodle_exception');
1338          mod_workshop_external::get_assessment($assessmentid);
1339      }
1340  
1341      /**
1342       * Test get_assessment_form_definition_reviewer_new_assessment.
1343       */
1344      public function test_get_assessment_form_definition_reviewer_new_assessment() {
1345  
1346          // Create the submission.
1347          $submissionid = $this->create_test_submission($this->anotherstudentg1);
1348  
1349          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1350          $submission = $workshop->get_submission_by_id($submissionid);
1351          $assessmentid = $workshop->add_allocation($submission, $this->student->id);
1352  
1353          // Switch to assessment phase.
1354          $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
1355          $this->setUser($this->student);
1356          $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1357          $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1358          $this->assertEquals(4, $result['dimenssionscount']);    // We receive the expected 4 dimensions.
1359          $this->assertEmpty($result['current']); // Assessment not yet done.
1360          foreach ($result['fields'] as $field) {
1361              if (strpos($field['name'], 'grade__idx_') === 0) {
1362                  $this->assertEquals(25, $field['value']); // Check one of the dimension fields attributes.
1363              }
1364          }
1365          // Check dimensions grading info.
1366          foreach ($result['dimensionsinfo'] as $dimension) {
1367              $this->assertEquals(0, $dimension['min']);
1368              $this->assertEquals(25, $dimension['max']);
1369              $this->assertEquals(25, $dimension['weight']);
1370              $this->assertFalse(isset($dimension['scale']));
1371          }
1372      }
1373  
1374      /**
1375       * Test get_assessment_form_definition_teacher_new_assessment.
1376       */
1377      public function test_get_assessment_form_definition_teacher_new_assessment() {
1378  
1379          // Create the submission.
1380          $submissionid = $this->create_test_submission($this->anotherstudentg1);
1381  
1382          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1383          $submission = $workshop->get_submission_by_id($submissionid);
1384          $assessmentid = $workshop->add_allocation($submission, $this->student->id);
1385  
1386          // Switch to assessment phase.
1387          $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
1388          // Teachers need to be able to view assessments.
1389          $this->setUser($this->teacher);
1390          $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1391          $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1392          $this->assertEquals(4, $result['dimenssionscount']);
1393      }
1394  
1395      /**
1396       * Test get_assessment_form_definition_invalid_phase.
1397       */
1398      public function test_get_assessment_form_definition_invalid_phase() {
1399  
1400          // Create the submission.
1401          $submissionid = $this->create_test_submission($this->anotherstudentg1);
1402  
1403          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1404          $submission = $workshop->get_submission_by_id($submissionid);
1405          $assessmentid = $workshop->add_allocation($submission, $this->anotherstudentg1->id);
1406  
1407          $workshop->switch_phase(workshop::PHASE_EVALUATION);
1408          $this->setUser($this->student);
1409          // Since we are not reviewers we can't see the assessment until the workshop is closed.
1410          $this->expectException('moodle_exception');
1411          mod_workshop_external::get_assessment_form_definition($assessmentid);
1412      }
1413  
1414      /**
1415       * Test get_reviewer_assessments.
1416       */
1417      public function test_get_reviewer_assessments() {
1418  
1419          // Create the submission.
1420          $submissionid1 = $this->create_test_submission($this->student);
1421          $submissionid2 = $this->create_test_submission($this->anotherstudentg1);
1422  
1423          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1424          $assessmentid1 = $workshopgenerator->create_assessment($submissionid1, $this->student->id, array(
1425              'weight' => 2,
1426              'grade' => 90,
1427          ));
1428          $assessmentid2 = $workshopgenerator->create_assessment($submissionid2, $this->student->id, array(
1429              'weight' => 3,
1430              'grade' => 80,
1431          ));
1432  
1433          // Switch to assessment phase.
1434          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1435          $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
1436          $this->setUser($this->student);
1437          // Get my assessments.
1438          $result = mod_workshop_external::get_reviewer_assessments($this->workshop->id);
1439          $result = external_api::clean_returnvalue(mod_workshop_external::get_reviewer_assessments_returns(), $result);
1440          $this->assertCount(2, $result['assessments']);
1441          foreach ($result['assessments'] as $assessment) {
1442              if ($assessment['id'] == $assessmentid1) {
1443                  $this->assertEquals(90, $assessment['grade']);
1444              } else {
1445                  $this->assertEquals($assessmentid2, $assessment['id']);
1446                  $this->assertEquals(80, $assessment['grade']);
1447              }
1448          }
1449  
1450          // Now, as teacher try to get the same student assessments.
1451          $result = mod_workshop_external::get_reviewer_assessments($this->workshop->id, $this->student->id);
1452          $result = external_api::clean_returnvalue(mod_workshop_external::get_reviewer_assessments_returns(), $result);
1453          $this->assertCount(2, $result['assessments']);
1454          $this->assertArrayNotHasKey('feedbackreviewer', $result['assessments'][0]);
1455      }
1456  
1457      /**
1458       * Test get_reviewer_assessments_other_student.
1459       */
1460      public function test_get_reviewer_assessments_other_student() {
1461  
1462          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1463          $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
1464          // Try to get other user assessments.
1465          $this->setUser($this->student);
1466          $this->expectException('moodle_exception');
1467          mod_workshop_external::get_reviewer_assessments($this->workshop->id, $this->anotherstudentg1->id);
1468      }
1469  
1470      /**
1471       * Test get_reviewer_assessments_invalid_phase.
1472       */
1473      public function test_get_reviewer_assessments_invalid_phase() {
1474  
1475          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1476          $workshop->switch_phase(workshop::PHASE_SUBMISSION);
1477          // Try to get other user assessments.
1478          $this->setUser($this->student);
1479          $this->expectException('moodle_exception');
1480          mod_workshop_external::get_reviewer_assessments($this->workshop->id, $this->anotherstudentg1->id);
1481      }
1482  
1483      /**
1484       * Test update_assessment.
1485       */
1486      public function test_update_assessment() {
1487  
1488          // Create the submission.
1489          $submissionid = $this->create_test_submission($this->anotherstudentg1);
1490  
1491          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1492          $submission = $workshop->get_submission_by_id($submissionid);
1493          $assessmentid = $workshop->add_allocation($submission, $this->student->id);
1494  
1495          // Switch to assessment phase.
1496          $workshop->switch_phase(workshop::PHASE_ASSESSMENT);
1497          $this->setUser($this->student);
1498          // Get the form definition.
1499          $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1500          $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1501  
1502          // Prepare the data to be sent.
1503          $data = $result['fields'];
1504          foreach ($data as $key => $param) {
1505              if (strpos($param['name'], 'peercomment__idx_') === 0) {
1506                  $data[$key]['value'] = 'Some content';
1507              } else if (strpos($param['name'], 'grade__idx_') === 0) {
1508                  $data[$key]['value'] = 25; // Set all to 25.
1509              }
1510          }
1511  
1512          // Required data.
1513          $data[] = array(
1514              'name' => 'nodims',
1515              'value' => $result['dimenssionscount'],
1516          );
1517  
1518          // General feedback.
1519          $data[] = array(
1520              'name' => 'feedbackauthor',
1521              'value' => 'Feedback for the author',
1522          );
1523          $data[] = array(
1524              'name' => 'feedbackauthorformat',
1525              'value' => FORMAT_MOODLE,
1526          );
1527  
1528          // Create a file in a draft area for inline attachments.
1529          $fs = get_file_storage();
1530          $draftidinlineattach = file_get_unused_draft_itemid();
1531          $usercontext = context_user::instance($this->student->id);
1532          $filenameimg = 'shouldbeanimage.txt';
1533          $filerecordinline = array(
1534              'contextid' => $usercontext->id,
1535              'component' => 'user',
1536              'filearea'  => 'draft',
1537              'itemid'    => $draftidinlineattach,
1538              'filepath'  => '/',
1539              'filename'  => $filenameimg,
1540          );
1541          $fs->create_file_from_string($filerecordinline, 'image contents (not really)');
1542  
1543          // Create a file in a draft area for regular attachments.
1544          $draftidattach = file_get_unused_draft_itemid();
1545          $filerecordattach = $filerecordinline;
1546          $attachfilename = 'attachment.txt';
1547          $filerecordattach['filename'] = $attachfilename;
1548          $filerecordattach['itemid'] = $draftidattach;
1549          $fs->create_file_from_string($filerecordattach, 'simple text attachment');
1550  
1551          $data[] = array(
1552              'name' => 'feedbackauthorinlineattachmentsid',
1553              'value' => $draftidinlineattach,
1554          );
1555          $data[] = array(
1556              'name' => 'feedbackauthorattachmentsid',
1557              'value' => $draftidattach,
1558          );
1559  
1560          // Update the assessment.
1561          $result = mod_workshop_external::update_assessment($assessmentid, $data);
1562          $result = external_api::clean_returnvalue(mod_workshop_external::update_assessment_returns(), $result);
1563          $this->assertEquals(100, $result['rawgrade']);
1564          $this->assertTrue($result['status']);
1565  
1566          // Get the assessment and check it was updated properly.
1567          $result = mod_workshop_external::get_assessment($assessmentid);
1568          $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1569          $this->assertEquals(100, $result['assessment']['grade']);
1570          $this->assertEquals($this->student->id, $result['assessment']['reviewerid']);
1571          $this->assertEquals('Feedback for the author', $result['assessment']['feedbackauthor']);
1572          $this->assertCount(1, $result['assessment']['feedbackcontentfiles']);
1573          $this->assertCount(1, $result['assessment']['feedbackattachmentfiles']);
1574  
1575          // Now, get again the form and check we received the data we already sent.
1576          $result = mod_workshop_external::get_assessment_form_definition($assessmentid);
1577          $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_form_definition_returns(), $result);
1578          foreach ($result['current'] as $currentdata) {
1579              if (strpos($currentdata['name'], 'peercomment__idx_') === 0) {
1580                  $this->assertEquals('Some content', $currentdata['value']);
1581              } else if (strpos($currentdata['name'], 'grade__idx_') === 0) {
1582                  $this->assertEquals(25, (int) $currentdata['value']);
1583              }
1584          }
1585      }
1586  
1587      /**
1588       * Test get_grades.
1589       */
1590      public function test_get_grades() {
1591  
1592          $timenow = time();
1593          $submissiongrade = array(
1594              'userid' => $this->student->id,
1595              'rawgrade' => 40,
1596              'feedback' => '',
1597              'feedbackformat' => 1,
1598              'datesubmitted' => $timenow,
1599              'dategraded' => $timenow,
1600          );
1601          $assessmentgrade = array(
1602              'userid' => $this->student->id,
1603              'rawgrade' => 10,
1604              'feedback' => '',
1605              'feedbackformat' => 1,
1606              'datesubmitted' => $timenow,
1607              'dategraded' => $timenow,
1608          );
1609  
1610          workshop_grade_item_update($this->workshop, (object) $submissiongrade, (object) $assessmentgrade);
1611  
1612          // First retrieve my grades.
1613          $this->setUser($this->student);
1614          $result = mod_workshop_external::get_grades($this->workshop->id);
1615          $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_returns(), $result);
1616          $this->assertCount(0, $result['warnings']);
1617          $this->assertEquals($assessmentgrade['rawgrade'], $result['assessmentrawgrade']);
1618          $this->assertEquals($submissiongrade['rawgrade'], $result['submissionrawgrade']);
1619          $this->assertFalse($result['assessmentgradehidden']);
1620          $this->assertFalse($result['submissiongradehidden']);
1621          $this->assertEquals($assessmentgrade['rawgrade'] . ".00 / 20.00", $result['assessmentlongstrgrade']);
1622          $this->assertEquals($submissiongrade['rawgrade'] . ".00 / 80.00", $result['submissionlongstrgrade']);
1623  
1624          // Second, teacher retrieve user grades.
1625          $this->setUser($this->teacher);
1626          $result = mod_workshop_external::get_grades($this->workshop->id, $this->student->id);
1627          $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_returns(), $result);
1628          $this->assertCount(0, $result['warnings']);
1629          $this->assertEquals($assessmentgrade['rawgrade'], $result['assessmentrawgrade']);
1630          $this->assertEquals($submissiongrade['rawgrade'], $result['submissionrawgrade']);
1631          $this->assertFalse($result['assessmentgradehidden']);
1632          $this->assertFalse($result['submissiongradehidden']);
1633          $this->assertEquals($assessmentgrade['rawgrade'] . ".00 / 20.00", $result['assessmentlongstrgrade']);
1634          $this->assertEquals($submissiongrade['rawgrade'] . ".00 / 80.00", $result['submissionlongstrgrade']);
1635      }
1636  
1637      /**
1638       * Test get_grades_other_student.
1639       */
1640      public function test_get_grades_other_student() {
1641  
1642          // Create the submission that will be deleted.
1643          $submissionid = $this->create_test_submission($this->student);
1644  
1645          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1646          $workshop->switch_phase(workshop::PHASE_CLOSED);
1647          $this->setUser($this->anotherstudentg1);
1648          $this->expectException('moodle_exception');
1649          mod_workshop_external::get_grades($this->workshop->id, $this->student->id);
1650      }
1651  
1652      /**
1653       * Test evaluate_assessment.
1654       */
1655      public function test_evaluate_assessment() {
1656          global $DB;
1657  
1658          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1659          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1660          $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1661              'weight' => 3,
1662              'grade' => 20,
1663          ));
1664  
1665          $this->setUser($this->teacher);
1666          $feedbacktext = 'The feedback';
1667          $feedbackformat = FORMAT_MOODLE;
1668          $weight = 10;
1669          $gradinggradeover = 10;
1670          $result = mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight,
1671              $gradinggradeover);
1672          $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_assessment_returns(), $result);
1673          $this->assertTrue($result['status']);
1674  
1675          $assessment = $DB->get_record('workshop_assessments', array('id' => $assessmentid));
1676          $this->assertEquals('The feedback', $assessment->feedbackreviewer);
1677          $this->assertEquals(10, $assessment->weight);
1678  
1679          // Now test passing incorrect weight and grade values.
1680          $weight = 17;
1681          $gradinggradeover = 100;
1682          $result = mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight,
1683              $gradinggradeover);
1684          $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_assessment_returns(), $result);
1685          $this->assertFalse($result['status']);
1686          $this->assertCount(2, $result['warnings']);
1687          $found = 0;
1688          foreach ($result['warnings'] as $warning) {
1689              if ($warning['item'] == 'weight' || $warning['item'] == 'gradinggradeover') {
1690                  $found++;
1691              }
1692          }
1693          $this->assertEquals(2, $found);
1694      }
1695  
1696      /**
1697       * Test evaluate_assessment_ignore_parameters.
1698       */
1699      public function test_evaluate_assessment_ignore_parameters() {
1700          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1701          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1702          $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1703              'weight' => 3,
1704              'grade' => 20,
1705          ));
1706  
1707          assign_capability('mod/workshop:allocate', CAP_PROHIBIT, $this->teacherrole->id, $this->context->id);
1708          // Empty all the caches that may be affected  by this change.
1709          accesslib_clear_all_caches_for_unit_testing();
1710  
1711          $this->setUser($this->teacher);
1712          $feedbacktext = 'The feedback';
1713          $feedbackformat = FORMAT_MOODLE;
1714          $weight = 10;
1715          $gradinggradeover = 19;
1716          $result = mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight,
1717              $gradinggradeover);
1718          $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_assessment_returns(), $result);
1719          $this->assertTrue($result['status']);
1720  
1721          $result = mod_workshop_external::get_assessment($assessmentid);
1722          $result = external_api::clean_returnvalue(mod_workshop_external::get_assessment_returns(), $result);
1723          $this->assertNotEquals(10, $result['assessment']['weight']);
1724      }
1725  
1726      /**
1727       * Test evaluate_assessment_no_permissions.
1728       */
1729      public function test_evaluate_assessment_no_permissions() {
1730          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1731          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1732          $assessmentid = $workshopgenerator->create_assessment($submissionid, $this->anotherstudentg1->id, array(
1733              'weight' => 3,
1734              'grade' => 20,
1735          ));
1736  
1737          $this->setUser($this->student);
1738          $feedbacktext = 'The feedback';
1739          $feedbackformat = FORMAT_MOODLE;
1740          $weight = 10;
1741          $gradinggradeover = 50;
1742          $this->expectException('moodle_exception');
1743          mod_workshop_external::evaluate_assessment($assessmentid, $feedbacktext, $feedbackformat, $weight, $gradinggradeover);
1744      }
1745  
1746      /**
1747       * Test get_grades_report.
1748       */
1749      public function test_get_grades_report() {
1750  
1751          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1752          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1753          $submissionid1 = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1754          $submissionid2 = $workshopgenerator->create_submission($this->workshop->id, $this->anotherstudentg1->id);
1755  
1756          $assessmentid1 = $workshopgenerator->create_assessment($submissionid2, $this->student->id, array(
1757              'weight' => 100,
1758              'grade' => 50,
1759          ));
1760          $assessmentid2 = $workshopgenerator->create_assessment($submissionid1, $this->anotherstudentg1->id, array(
1761              'weight' => 100,
1762              'grade' => 55,
1763          ));
1764  
1765          $workshop->switch_phase(workshop::PHASE_CLOSED);
1766          $this->setUser($this->teacher);
1767          $result = mod_workshop_external::get_grades_report($this->workshop->id);
1768          $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result);
1769          $this->assertEquals(3, $result['report']['totalcount']); // Expect 3 potential submissions.
1770  
1771          foreach ($result['report']['grades'] as $grade) {
1772              if ($grade['userid'] == $this->student->id) {
1773                  $this->assertEquals($this->anotherstudentg1->id, $grade['reviewedby'][0]['userid']); // Check reviewer.
1774                  $this->assertEquals($this->anotherstudentg1->id, $grade['reviewerof'][0]['userid']); // Check reviewer.
1775                  $this->assertEquals($workshop->real_grade(50), $grade['reviewerof'][0]['grade']); // Check grade (converted).
1776                  $this->assertEquals($workshop->real_grade(55), $grade['reviewedby'][0]['grade']); // Check grade (converted).
1777              } else if ($grade['userid'] == $this->anotherstudentg1->id) {
1778                  $this->assertEquals($this->student->id, $grade['reviewedby'][0]['userid']); // Check reviewer.
1779                  $this->assertEquals($this->student->id, $grade['reviewerof'][0]['userid']); // Check reviewer.
1780                  $this->assertEquals($workshop->real_grade(55), $grade['reviewerof'][0]['grade']); // Check grade (converted).
1781                  $this->assertEquals($workshop->real_grade(50), $grade['reviewedby'][0]['grade']); // Check grade (converted).
1782              }
1783          }
1784          // Now check pagination.
1785          $result = mod_workshop_external::get_grades_report($this->workshop->id, 0, 'lastname', 'ASC', 0, 1);
1786          $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result);
1787          $this->assertEquals(3, $result['report']['totalcount']); // Expect the total count.
1788          $this->assertCount(1, $result['report']['grades']);
1789  
1790          // Groups filtering.
1791          $result = mod_workshop_external::get_grades_report($this->workshop->id, $this->group1->id);
1792          $result = external_api::clean_returnvalue(mod_workshop_external::get_grades_report_returns(), $result);
1793          $this->assertEquals(2, $result['report']['totalcount']); // Expect the group count.
1794      }
1795  
1796      /**
1797       * Test get_grades_report_invalid_phase.
1798       */
1799      public function test_get_grades_report_invalid_phase() {
1800          $this->setUser($this->teacher);
1801          $this->expectException('moodle_exception');
1802          $this->expectExceptionMessage(get_string('nothingfound', 'workshop'));
1803          mod_workshop_external::get_grades_report($this->workshop->id);
1804      }
1805  
1806      /**
1807       * Test get_grades_report_missing_permissions.
1808       */
1809      public function test_get_grades_report_missing_permissions() {
1810          $this->setUser($this->student);
1811          $this->expectException('required_capability_exception');
1812          mod_workshop_external::get_grades_report($this->workshop->id);
1813      }
1814  
1815      /**
1816       * Test test_view_submission.
1817       */
1818      public function test_view_submission() {
1819  
1820          // Create a couple of submissions with files.
1821          $firstsubmissionid = $this->create_test_submission($this->student);  // Create submission with files.
1822  
1823          // Trigger and capture the event.
1824          $sink = $this->redirectEvents();
1825  
1826          $this->setUser($this->student);
1827          $result = mod_workshop_external::view_submission($firstsubmissionid);
1828          $result = external_api::clean_returnvalue(mod_workshop_external::view_submission_returns(), $result);
1829  
1830          $events = $sink->get_events();
1831          $this->assertCount(1, $events);
1832          $event = array_shift($events);
1833  
1834          // Checking that the event contains the expected values.
1835          $this->assertInstanceOf('\mod_workshop\event\submission_viewed', $event);
1836          $this->assertEquals($this->context, $event->get_context());
1837          $moodleworkshop = new \moodle_url('/mod/workshop/submission.php', array('id' => $firstsubmissionid,
1838              'cmid' => $this->cm->id));
1839          $this->assertEquals($moodleworkshop, $event->get_url());
1840          $this->assertEventContextNotUsed($event);
1841          $this->assertNotEmpty($event->get_name());
1842  
1843      }
1844  
1845      /**
1846       * Test evaluate_submission.
1847       */
1848      public function test_evaluate_submission() {
1849          global $DB;
1850  
1851          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1852          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1853  
1854          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1855          $workshop->switch_phase(workshop::PHASE_EVALUATION);
1856  
1857          $this->setUser($this->teacher);
1858          $feedbacktext = 'The feedback';
1859          $feedbackformat = FORMAT_MOODLE;
1860          $published = 1;
1861          $gradeover = 10;
1862          $result = mod_workshop_external::evaluate_submission($submissionid, $feedbacktext, $feedbackformat, $published,
1863              $gradeover);
1864          $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_submission_returns(), $result);
1865          $this->assertTrue($result['status']);
1866  
1867          $submission = $DB->get_record('workshop_submissions', array('id' => $submissionid));
1868          $this->assertEquals($feedbacktext, $submission->feedbackauthor);
1869          $this->assertEquals($workshop->raw_grade_value($gradeover, $workshop->grade), $submission->gradeover);  // Expected grade.
1870          $this->assertEquals(1, $submission->published); // Submission published.
1871      }
1872  
1873      /**
1874       * Test evaluate_submission_invalid_phase_for_override.
1875       */
1876      public function test_evaluate_submission_invalid_phase_for_override() {
1877          global $DB;
1878  
1879          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1880          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1881  
1882          $this->setUser($this->teacher);
1883          $feedbacktext = 'The feedback';
1884          $feedbackformat = FORMAT_MOODLE;
1885          $published = 1;
1886          $gradeover = 10;
1887          $result = mod_workshop_external::evaluate_submission($submissionid, $feedbacktext, $feedbackformat, $published,
1888              $gradeover);
1889          $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_submission_returns(), $result);
1890          $this->assertTrue($result['status']);
1891  
1892          $submission = $DB->get_record('workshop_submissions', array('id' => $submissionid));
1893          $this->assertEquals('', $submission->feedbackauthor);   // Feedback and grade not updated.
1894          $this->assertEquals(0, $submission->gradeover);
1895          $this->assertEquals(1, $submission->published); // Publishing status correctly updated.
1896      }
1897  
1898      /**
1899       * Test evaluate_submission_no_permissions.
1900       */
1901      public function test_evaluate_submission_no_permissions() {
1902  
1903          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1904          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1905          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1906          $workshop->switch_phase(workshop::PHASE_EVALUATION);
1907  
1908          $this->setUser($this->student);
1909          $feedbacktext = 'The feedback';
1910          $feedbackformat = FORMAT_MOODLE;
1911          $published = 1;
1912          $gradeover = 50;
1913          $this->expectException('moodle_exception');
1914          mod_workshop_external::evaluate_submission($submissionid, $feedbacktext, $feedbackformat, $published, $gradeover);
1915      }
1916  
1917      /**
1918       * Test evaluate_submission_invalid_grade.
1919       */
1920      public function test_evaluate_submission_invalid_grade() {
1921  
1922          $workshopgenerator = $this->getDataGenerator()->get_plugin_generator('mod_workshop');
1923          $submissionid = $workshopgenerator->create_submission($this->workshop->id, $this->student->id);
1924          $workshop = new workshop($this->workshop, $this->cm, $this->course);
1925          $workshop->switch_phase(workshop::PHASE_EVALUATION);
1926  
1927          $this->setUser($this->teacher);
1928          $feedbacktext = 'The feedback';
1929          $feedbackformat = FORMAT_MOODLE;
1930          $published = 1;
1931          $gradeover = 150;
1932          $result = mod_workshop_external::evaluate_submission($submissionid, $feedbacktext, $feedbackformat, $published, $gradeover);
1933          $result = external_api::clean_returnvalue(mod_workshop_external::evaluate_submission_returns(), $result);
1934          $this->assertCount(1, $result['warnings']);
1935          $this->assertFalse($result['status']);
1936          $this->assertEquals('gradeover', $result['warnings'][0]['item']);
1937      }
1938  }