Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * External function test for get_user_attempts.
  19   *
  20   * @package    mod_h5pactivity
  21   * @category   external
  22   * @since      Moodle 3.11
  23   * @copyright  2020 Ilya Tregubov <ilya@moodle.com>
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  
  27  namespace mod_h5pactivity\external;
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  global $CFG;
  32  require_once($CFG->dirroot . '/webservice/tests/helpers.php');
  33  
  34  use mod_h5pactivity\local\manager;
  35  use external_api;
  36  use externallib_advanced_testcase;
  37  
  38  /**
  39   * External function test for get_user_attempts.
  40   *
  41   * @package    mod_h5pactivity
  42   * @copyright  2020 Ilya Tregubov <ilya@moodle.com>
  43   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  44   */
  45  class get_user_attempts_test extends externallib_advanced_testcase {
  46  
  47      /**
  48       * Test the behaviour of get_user_attempts getting more than one user at once.
  49       *
  50       * @dataProvider execute_multipleusers_data
  51       * @param string $loginuser the user which calls the webservice
  52       * @param string[] $participants the users to get the data
  53       * @param string[] $warnings the expected users with warnings
  54       * @param string[] $resultusers expected users in the resultusers
  55       */
  56      public function test_execute_multipleusers(string $loginuser, array $participants,
  57              array $warnings, array $resultusers): void {
  58          $this->resetAfterTest();
  59          $this->setAdminUser();
  60  
  61          $course = $this->getDataGenerator()->create_course();
  62          $activity = $this->getDataGenerator()->create_module('h5pactivity',
  63              ['course' => $course]);
  64  
  65          $manager = manager::create_from_instance($activity);
  66          $cm = $manager->get_coursemodule();
  67  
  68          $users = ['editingteacher' => $this->getDataGenerator()->create_and_enrol($course, 'editingteacher')];
  69  
  70          // Prepare users.
  71          foreach ($participants as $participant) {
  72              if ($participant == 'noenrolled') {
  73                  $users[$participant] = $this->getDataGenerator()->create_user();
  74              } else {
  75                  $users[$participant] = $this->getDataGenerator()->create_and_enrol($course, 'student');
  76              }
  77          }
  78  
  79          // Generate attempts (student1 with 1 attempt, student2 with 2 etc).
  80          $generator = $this->getDataGenerator()->get_plugin_generator('mod_h5pactivity');
  81  
  82          $attemptcount = 1;
  83          foreach ($users as $key => $user) {
  84              if (($key == 'noattempts') || ($key == 'noenrolled') || ($key == 'editingteacher')) {
  85                  $countattempts[$user->id] = 0;
  86              } else {
  87                  $params = ['cmid' => $cm->id, 'userid' => $user->id];
  88                  for ($i = 1; $i <= $attemptcount; $i++) {
  89                      $generator->create_content($activity, $params);
  90                  }
  91                  $countattempts[$user->id] = $attemptcount;
  92                  $attemptcount++;
  93              }
  94          }
  95  
  96          // Execute external method.
  97          $this->setUser($users[$loginuser]);
  98  
  99          if ($loginuser == 'student1') {
 100              $this->expectException('moodle_exception');
 101              $this->expectExceptionMessage('h5pactivity:reviewattempts required view attempts' .
 102                  ' of all enrolled users');
 103          }
 104          $result = get_user_attempts::execute($activity->id);
 105          $result = external_api::clean_returnvalue(
 106              get_user_attempts::execute_returns(),
 107              $result
 108          );
 109  
 110          $this->assertCount(count($warnings), $result['warnings']);
 111          // Teacher is excluded.
 112          $this->assertCount(count($resultusers), $result['usersattempts']);
 113  
 114          $expectedwarnings = [];
 115          foreach ($warnings as $warninguser) {
 116              $id = $users[$warninguser]->id;
 117              $expectedwarnings[$id] = $warninguser;
 118          }
 119  
 120          foreach ($result['warnings'] as $warning) {
 121              $this->assertEquals('user', $warning['item']);
 122              $this->assertEquals(1, $warning['warningcode']);
 123              $this->assertArrayHasKey($warning['itemid'], $expectedwarnings);
 124          }
 125  
 126          $expectedusers = [];
 127          foreach ($resultusers as $resultuser) {
 128              $id = $users[$resultuser]->id;
 129              $expectedusers[$id] = $resultuser;
 130          }
 131  
 132          foreach ($result['usersattempts'] as $usersattempts) {
 133              $this->assertArrayHasKey('userid', $usersattempts);
 134              $userid = $usersattempts['userid'];
 135              $this->assertArrayHasKey($userid, $expectedusers);
 136              $this->assertCount($countattempts[$userid], $usersattempts['attempts']);
 137              if ($countattempts[$userid]) {
 138                  $this->assertArrayHasKey('scored', $usersattempts);
 139              }
 140          }
 141      }
 142  
 143      /**
 144       * Data provider for the test_execute_multipleusers.
 145       *
 146       * @return  array
 147       */
 148      public function execute_multipleusers_data(): array {
 149          return [
 150              // Teacher checks.
 151              'Teacher checking students with attempts' => [
 152                  'editingteacher',
 153                  ['student1', 'student2', 'student3', 'student4', 'student5'],
 154                  [],
 155                  ['student1', 'student2', 'student3', 'student4', 'student5'],
 156              ],
 157              'Teacher checking 2 students with atempts and one not' => [
 158                  'editingteacher',
 159                  ['student1', 'student2', 'noattempts'],
 160                  [],
 161                  ['student1', 'student2', 'noattempts'],
 162              ],
 163              'Teacher checking no students' => [
 164                  'editingteacher',
 165                  [],
 166                  [],
 167                  [],
 168              ],
 169              'Teacher checking one student and a no enrolled user' => [
 170                  'editingteacher',
 171                  ['student1', 'noenrolled'],
 172                  [],
 173                  ['student1'],
 174              ],
 175  
 176              // Permission check.
 177              'Student checking attempts and another user' => [
 178                  'student1',
 179                  ['student1', 'student2'],
 180                  ['student2'],
 181                  ['student1'],
 182              ],
 183          ];
 184      }
 185  
 186      /**
 187       * Data provider for {@see test_execute_with_sortorder}
 188       *
 189       * @return array[]
 190       */
 191      public function execute_with_sortorder(): array {
 192          return [
 193              'Sort by id' => ['id', ['user01', 'user02']],
 194              'Sort by id desc' => ['id desc', ['user02', 'user01']],
 195              'Sort by id asc' => ['id asc', ['user01', 'user02']],
 196              'Sort by firstname' => ['firstname', ['user01', 'user02']],
 197              'Sort by firstname desc' => ['firstname desc', ['user02', 'user01']],
 198              'Sort by firstname asc' => ['firstname asc', ['user01', 'user02']],
 199              'Sort by lastname' => ['lastname', ['user02', 'user01']],
 200              'Sort by lastname desc' => ['lastname desc', ['user01', 'user02']],
 201              'Sort by lastname asc' => ['lastname asc', ['user02', 'user01']],
 202              // Edge cases (should fall back to default).
 203              'Sort by empty string' => ['', ['user01', 'user02']],
 204              'Sort by invalid field' => ['invalid', ['user01', 'user02']],
 205          ];
 206      }
 207  
 208      /**
 209       * Test external execute method with sortorder
 210       *
 211       * @param string $sortorder
 212       * @param string[] $expectedorder
 213       *
 214       * @dataProvider execute_with_sortorder
 215       */
 216      public function test_execute_with_sortorder(string $sortorder, array $expectedorder): void {
 217          $this->resetAfterTest();
 218          $this->setAdminUser();
 219  
 220          // Create course, module.
 221          $course = $this->getDataGenerator()->create_course();
 222          $module = $this->getDataGenerator()->create_module('h5pactivity', ['course' => $course]);
 223  
 224          // Couple of enrolled users in the course.
 225          $users['user01'] = $this->getDataGenerator()->create_and_enrol($course, 'student', [
 226              'username' => 'user01',
 227              'firstname' => 'Adam',
 228              'lastname' => 'Zebra',
 229          ]);
 230          $users['user02'] = $this->getDataGenerator()->create_and_enrol($course, 'student', [
 231              'username' => 'user02',
 232              'firstname' => 'Zoe',
 233              'lastname' => 'Apples',
 234          ]);
 235  
 236          $result = external_api::clean_returnvalue(
 237              get_user_attempts::execute_returns(),
 238              get_user_attempts::execute($module->id, $sortorder)
 239          );
 240  
 241          // Map expected order of usernames to user IDs.
 242          $expectedorderbyuserid = array_map(static function(string $username) use ($users): int {
 243              return $users[$username]->id;
 244          }, $expectedorder);
 245  
 246          // The order should match the ordering of user attempt user IDs.
 247          $this->assertEquals($expectedorderbyuserid, array_column($result['usersattempts'], 'userid'));
 248      }
 249  }