Search moodle.org's
Developer Documentation

See Release Notes

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

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

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