Search moodle.org's
Developer Documentation

See Release Notes

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

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

   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  namespace mod_h5pactivity\external;
  18  
  19  use core_external\external_api;
  20  use core_external\external_function_parameters;
  21  use core_external\external_multiple_structure;
  22  use core_external\external_single_structure;
  23  use core_external\external_value;
  24  use core_external\external_warnings;
  25  use mod_h5pactivity\local\manager;
  26  use mod_h5pactivity\local\attempt;
  27  use mod_h5pactivity\local\report\attempts as report_attempts;
  28  use context_module;
  29  use stdClass;
  30  
  31  /**
  32   * This is the external method for getting the information needed to present an attempts report.
  33   *
  34   * @package    mod_h5pactivity
  35   * @since      Moodle 3.9
  36   * @copyright  2020 Ferran Recio <ferran@moodle.com>
  37   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class get_attempts extends external_api {
  40  
  41      /**
  42       * Webservice parameters.
  43       *
  44       * @return external_function_parameters
  45       */
  46      public static function execute_parameters(): external_function_parameters {
  47          return new external_function_parameters(
  48              [
  49                  'h5pactivityid' => new external_value(PARAM_INT, 'h5p activity instance id'),
  50                  'userids' => new external_multiple_structure(
  51                      new external_value(PARAM_INT, 'The user ids to get attempts (null means only current user)', VALUE_DEFAULT),
  52                      'User ids', VALUE_DEFAULT, []
  53                  ),
  54              ]
  55          );
  56      }
  57  
  58      /**
  59       * Return user attempts information in a h5p activity.
  60       *
  61       * @throws  moodle_exception if the user cannot see the report
  62       * @param  int $h5pactivityid The h5p activity id
  63       * @param  int[]|null $userids The user ids (if no provided $USER will be used)
  64       * @return stdClass report data
  65       */
  66      public static function execute(int $h5pactivityid, ?array $userids = []): stdClass {
  67          global $USER;
  68  
  69          $params = external_api::validate_parameters(self::execute_parameters(), [
  70              'h5pactivityid' => $h5pactivityid,
  71              'userids' => $userids,
  72          ]);
  73          $h5pactivityid = $params['h5pactivityid'];
  74          $userids = $params['userids'];
  75  
  76          if (empty($userids)) {
  77              $userids = [$USER->id];
  78          }
  79  
  80          $warnings = [];
  81  
  82          // Request and permission validation.
  83          list ($course, $cm) = get_course_and_cm_from_instance($h5pactivityid, 'h5pactivity');
  84  
  85          $context = context_module::instance($cm->id);
  86          self::validate_context($context);
  87  
  88          $manager = manager::create_from_coursemodule($cm);
  89  
  90          $instance = $manager->get_instance();
  91  
  92          $usersattempts = [];
  93          foreach ($userids as $userid) {
  94              $report = $manager->get_report($userid);
  95              if ($report && $report instanceof report_attempts) {
  96                  $usersattempts[] = self::export_user_attempts($report, $userid);
  97              } else {
  98                  $warnings[] = [
  99                      'item' => 'user',
 100                      'itemid' => $userid,
 101                      'warningcode' => '1',
 102                      'message' => "Cannot access user attempts",
 103                  ];
 104              }
 105          }
 106  
 107          $result = (object)[
 108              'activityid' => $instance->id,
 109              'usersattempts' => $usersattempts,
 110              'warnings' => $warnings,
 111          ];
 112  
 113          return $result;
 114      }
 115  
 116      /**
 117       * Export attempts data for a specific user.
 118       *
 119       * @param report_attempts $report the report attempts object
 120       * @param int $userid the user id
 121       * @return stdClass
 122       */
 123      public static function export_user_attempts(report_attempts $report, int $userid): stdClass {
 124  
 125          $scored = $report->get_scored();
 126          $attempts = $report->get_attempts();
 127  
 128          $result = (object)[
 129              'userid' => $userid,
 130              'attempts' => [],
 131          ];
 132  
 133          foreach ($attempts as $attempt) {
 134              $result->attempts[] = self::export_attempt($attempt);
 135          }
 136  
 137          if (!empty($scored)) {
 138              $result->scored = (object)[
 139                  'title' => $scored->title,
 140                  'grademethod' => $scored->grademethod,
 141                  'attempts' => [self::export_attempt($scored->attempt)],
 142              ];
 143          }
 144  
 145          return $result;
 146      }
 147  
 148      /**
 149       * Return a data object from an attempt.
 150       *
 151       * @param attempt $attempt the attempt object
 152       * @return stdClass a WS compatible version of the attempt
 153       */
 154      private static function export_attempt(attempt $attempt): stdClass {
 155          $result = (object)[
 156              'id' => $attempt->get_id(),
 157              'h5pactivityid' => $attempt->get_h5pactivityid(),
 158              'userid' => $attempt->get_userid(),
 159              'timecreated' => $attempt->get_timecreated(),
 160              'timemodified' => $attempt->get_timemodified(),
 161              'attempt' => $attempt->get_attempt(),
 162              'rawscore' => $attempt->get_rawscore(),
 163              'maxscore' => $attempt->get_maxscore(),
 164              'duration' => $attempt->get_duration(),
 165              'scaled' => $attempt->get_scaled(),
 166          ];
 167          if ($attempt->get_completion() !== null) {
 168              $result->completion = $attempt->get_completion();
 169          }
 170          if ($attempt->get_success() !== null) {
 171              $result->success = $attempt->get_success();
 172          }
 173          return $result;
 174      }
 175  
 176      /**
 177       * Describes the get_h5pactivity_access_information return value.
 178       *
 179       * @return external_single_structure
 180       */
 181      public static function execute_returns(): external_single_structure {
 182          return new external_single_structure([
 183              'activityid' => new external_value(PARAM_INT, 'Activity course module ID'),
 184              'usersattempts' => new external_multiple_structure(
 185                  self::get_user_attempts_returns(), 'The complete users attempts list'
 186              ),
 187              'warnings' => new external_warnings(),
 188          ], 'Activity attempts data');
 189      }
 190  
 191      /**
 192       * Describes the get_h5pactivity_access_information return value.
 193       *
 194       * @return external_single_structure
 195       */
 196      public static function get_user_attempts_returns(): external_single_structure {
 197          $structure = [
 198              'userid' => new external_value(PARAM_INT, 'The user id'),
 199              'attempts' => new external_multiple_structure(self::get_attempt_returns(), 'The complete attempts list'),
 200              'scored' => new external_single_structure([
 201                  'title' => new external_value(PARAM_NOTAGS, 'Scored attempts title'),
 202                  'grademethod' => new external_value(PARAM_NOTAGS, 'Scored attempts title'),
 203                  'attempts' => new external_multiple_structure(self::get_attempt_returns(), 'List of the grading attempts'),
 204              ], 'Attempts used to grade the activity', VALUE_OPTIONAL),
 205          ];
 206          return new external_single_structure($structure);
 207      }
 208  
 209      /**
 210       * Return the external structure of an attempt.
 211       *
 212       * @return external_single_structure
 213       */
 214      private static function get_attempt_returns(): external_single_structure {
 215  
 216          $result = new external_single_structure([
 217              'id' => new external_value(PARAM_INT, 'ID of the context'),
 218              'h5pactivityid' => new external_value(PARAM_INT, 'ID of the H5P activity'),
 219              'userid' => new external_value(PARAM_INT, 'ID of the user'),
 220              'timecreated' => new external_value(PARAM_INT, 'Attempt creation'),
 221              'timemodified' => new external_value(PARAM_INT, 'Attempt modified'),
 222              'attempt' => new external_value(PARAM_INT, 'Attempt number'),
 223              'rawscore' => new external_value(PARAM_INT, 'Attempt score value'),
 224              'maxscore' => new external_value(PARAM_INT, 'Attempt max score'),
 225              'duration' => new external_value(PARAM_INT, 'Attempt duration in seconds'),
 226              'completion' => new external_value(PARAM_INT, 'Attempt completion', VALUE_OPTIONAL),
 227              'success' => new external_value(PARAM_INT, 'Attempt success', VALUE_OPTIONAL),
 228              'scaled' => new external_value(PARAM_FLOAT, 'Attempt scaled'),
 229          ]);
 230          return $result;
 231      }
 232  }