Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 9 May 2022 (12 months).
  • Bug fixes for security issues in 3.11.x will end 14 November 2022 (18 months).
  • 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 310 and 311] [Versions 35 and 311] [Versions 36 and 311] [Versions 37 and 311] [Versions 38 and 311] [Versions 39 and 311]

       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 grade report user API
      19   *
      20   * @package    gradereport_user
      21   * @copyright  2015 Juan Leyva <juan@moodle.com>
      22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      23   */
      24  
      25  defined('MOODLE_INTERNAL') || die;
      26  
      27  require_once("$CFG->libdir/externallib.php");
      28  
      29  
      30  /**
      31   * External grade report API implementation
      32   *
      33   * @package    gradereport_user
      34   * @copyright  2015 Juan Leyva <juan@moodle.com>
      35   * @category   external
      36   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      37   */
      38  class gradereport_user_external extends external_api {
      39  
      40  
      41      /**
      42       * Validate access permissions to the report
      43       *
      44       * @param  int  $courseid the courseid
      45       * @param  int  $userid   the user id to retrieve data from
      46       * @param  int $groupid   the group id
      47       * @return array with the parameters cleaned and other required information
      48       * @since  Moodle 3.2
      49       */
      50      protected static function check_report_access($courseid, $userid, $groupid = 0) {
      51          global $USER;
      52  
      53          // Validate the parameter.
      54          $params = self::validate_parameters(self::get_grades_table_parameters(),
      55              array(
      56                  'courseid' => $courseid,
      57                  'userid' => $userid,
      58                  'groupid' => $groupid,
      59              )
      60          );
      61  
      62          // Compact/extract functions are not recommended.
      63          $courseid = $params['courseid'];
      64          $userid   = $params['userid'];
      65          $groupid  = $params['groupid'];
      66  
      67          // Function get_course internally throws an exception if the course doesn't exist.
      68          $course = get_course($courseid);
      69  
      70          $context = context_course::instance($courseid);
      71          self::validate_context($context);
      72  
      73          // Specific capabilities.
      74          require_capability('gradereport/user:view', $context);
      75  
      76          $user = null;
      77  
      78          if (empty($userid)) {
      79              require_capability('moodle/grade:viewall', $context);
      80          } else {
      81              $user = core_user::get_user($userid, '*', MUST_EXIST);
      82              core_user::require_active_user($user);
      83              // Check if we can view the user group (if any).
      84              // When userid == 0, we are retrieving all the users, we'll check then if a groupid is required.
      85              if (!groups_user_groups_visible($course, $user->id)) {
      86                  throw new moodle_exception('notingroup');
      87              }
      88          }
      89  
      90          $access = false;
      91  
      92          if (has_capability('moodle/grade:viewall', $context)) {
      93              // Can view all course grades.
      94              $access = true;
      95          } else if ($userid == $USER->id and has_capability('moodle/grade:view', $context) and $course->showgrades) {
      96              // View own grades.
      97              $access = true;
      98          }
      99  
     100          if (!$access) {
     101              throw new moodle_exception('nopermissiontoviewgrades', 'error');
     102          }
     103  
     104          if (!empty($groupid)) {
     105              // Determine is the group is visible to user.
     106              if (!groups_group_visible($groupid, $course)) {
     107                  throw new moodle_exception('notingroup');
     108              }
     109          } else {
     110              // Check to see if groups are being used here.
     111              if ($groupmode = groups_get_course_groupmode($course)) {
     112                  $groupid = groups_get_course_group($course);
     113                  // Determine is the group is visible to user (this is particullary for the group 0).
     114                  if (!groups_group_visible($groupid, $course)) {
     115                      throw new moodle_exception('notingroup');
     116                  }
     117              } else {
     118                  $groupid = 0;
     119              }
     120          }
     121  
     122          return array($params, $course, $context, $user, $groupid);
     123      }
     124  
     125      /**
     126       * Get the report data
     127       * @param  stdClass $course  course object
     128       * @param  stdClass $context context object
     129       * @param  stdClass $user    user object (it can be null for all the users)
     130       * @param  int $userid       the user to retrieve data from, 0 for all
     131       * @param  int $groupid      the group id to filter
     132       * @param  bool $tabledata   whether to get the table data (true) or the gradeitemdata
     133       * @return array data and possible warnings
     134       * @since  Moodle 3.2
     135       */
     136      protected static function get_report_data($course, $context, $user, $userid, $groupid, $tabledata = true) {
     137          global $CFG;
     138  
     139          $warnings = array();
     140          // Require files here to save some memory in case validation fails.
     141          require_once($CFG->dirroot . '/group/lib.php');
     142          require_once($CFG->libdir  . '/gradelib.php');
     143          require_once($CFG->dirroot . '/grade/lib.php');
     144          require_once($CFG->dirroot . '/grade/report/user/lib.php');
     145  
     146          // Force regrade to update items marked as 'needupdate'.
     147          grade_regrade_final_grades($course->id);
     148  
     149          $gpr = new grade_plugin_return(
     150              array(
     151                  'type'           => 'report',
     152                  'plugin'         => 'user',
     153                  'courseid'       => $course->id,
     154                  'courseidnumber' => $course->idnumber,
     155                  'userid'         => $userid)
     156              );
     157  
     158          $reportdata = array();
     159  
     160          // Just one user.
     161          if ($user) {
     162              $report = new grade_report_user($course->id, $gpr, $context, $userid);
     163              $report->fill_table();
     164  
     165              $gradeuserdata = array(
     166                  'courseid'       => $course->id,
     167                  'courseidnumber' => $course->idnumber,
     168                  'userid'         => $user->id,
     169                  'userfullname'   => fullname($user),
     170                  'useridnumber'   => $user->idnumber,
     171                  'maxdepth'       => $report->maxdepth,
     172              );
     173              if ($tabledata) {
     174                  $gradeuserdata['tabledata'] = $report->tabledata;
     175              } else {
     176                  $gradeuserdata['gradeitems'] = $report->gradeitemsdata;
     177              }
     178              $reportdata[] = $gradeuserdata;
     179          } else {
     180              $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
     181              $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
     182              $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $context);
     183  
     184              $gui = new graded_users_iterator($course, null, $groupid);
     185              $gui->require_active_enrolment($showonlyactiveenrol);
     186              $gui->init();
     187  
     188              while ($userdata = $gui->next_user()) {
     189                  $currentuser = $userdata->user;
     190                  $report = new grade_report_user($course->id, $gpr, $context, $currentuser->id);
     191                  $report->fill_table();
     192  
     193                  $gradeuserdata = array(
     194                      'courseid'       => $course->id,
     195                      'courseidnumber' => $course->idnumber,
     196                      'userid'         => $currentuser->id,
     197                      'userfullname'   => fullname($currentuser),
     198                      'useridnumber'   => $currentuser->idnumber,
     199                      'maxdepth'       => $report->maxdepth,
     200                  );
     201                  if ($tabledata) {
     202                      $gradeuserdata['tabledata'] = $report->tabledata;
     203                  } else {
     204                      $gradeuserdata['gradeitems'] = $report->gradeitemsdata;
     205                  }
     206                  $reportdata[] = $gradeuserdata;
     207              }
     208              $gui->close();
     209          }
     210          return array($reportdata, $warnings);
     211      }
     212  
     213      /**
     214       * Describes the parameters for get_grades_table.
     215       *
     216       * @return external_function_parameters
     217       * @since Moodle 2.9
     218       */
     219      public static function get_grades_table_parameters() {
     220          return new external_function_parameters (
     221              array(
     222                  'courseid' => new external_value(PARAM_INT, 'Course Id', VALUE_REQUIRED),
     223                  'userid'   => new external_value(PARAM_INT, 'Return grades only for this user (optional)', VALUE_DEFAULT, 0),
     224                  'groupid'  => new external_value(PARAM_INT, 'Get users from this group only', VALUE_DEFAULT, 0)
     225              )
     226          );
     227      }
     228  
     229      /**
     230       * Returns a list of grades tables for users in a course.
     231       *
     232       * @param int $courseid Course Id
     233       * @param int $userid   Only this user (optional)
     234       * @param int $groupid  Get users from this group only
     235       *
     236       * @return array the grades tables
     237       * @since Moodle 2.9
     238       */
     239      public static function get_grades_table($courseid, $userid = 0, $groupid = 0) {
     240          global $CFG, $USER;
     241  
     242          list($params, $course, $context, $user, $groupid) = self::check_report_access($courseid, $userid, $groupid);
     243          $userid   = $params['userid'];
     244  
     245          // We pass userid because it can be still 0.
     246          list($tables, $warnings) = self::get_report_data($course, $context, $user, $userid, $groupid);
     247  
     248          $result = array();
     249          $result['tables'] = $tables;
     250          $result['warnings'] = $warnings;
     251          return $result;
     252      }
     253  
     254      /**
     255       * Creates a table column structure
     256       *
     257       * @return array
     258       * @since  Moodle 2.9
     259       */
     260      private static function grades_table_column() {
     261          return array (
     262              'class'   => new external_value(PARAM_RAW, 'class'),
     263              'content' => new external_value(PARAM_RAW, 'cell content'),
     264              'headers' => new external_value(PARAM_RAW, 'headers')
     265          );
     266      }
     267  
     268      /**
     269       * Describes tget_grades_table return value.
     270       *
     271       * @return external_single_structure
     272       * @since Moodle 2.9
     273       */
     274      public static function get_grades_table_returns() {
     275          return new external_single_structure(
     276              array(
     277                  'tables' => new external_multiple_structure(
     278                      new external_single_structure(
     279                          array(
     280                              'courseid' => new external_value(PARAM_INT, 'course id'),
     281                              'userid'   => new external_value(PARAM_INT, 'user id'),
     282                              'userfullname' => new external_value(PARAM_TEXT, 'user fullname'),
     283                              'maxdepth'   => new external_value(PARAM_INT, 'table max depth (needed for printing it)'),
     284                              'tabledata' => new external_multiple_structure(
     285                                  new external_single_structure(
     286                                      array(
     287                                          'itemname' => new external_single_structure(
     288                                              array (
     289                                                  'class' => new external_value(PARAM_RAW, 'class'),
     290                                                  'colspan' => new external_value(PARAM_INT, 'col span'),
     291                                                  'content'  => new external_value(PARAM_RAW, 'cell content'),
     292                                                  'celltype'  => new external_value(PARAM_RAW, 'cell type'),
     293                                                  'id'  => new external_value(PARAM_ALPHANUMEXT, 'id')
     294                                              ), 'The item returned data', VALUE_OPTIONAL
     295                                          ),
     296                                          'leader' => new external_single_structure(
     297                                              array (
     298                                                  'class' => new external_value(PARAM_RAW, 'class'),
     299                                                  'rowspan' => new external_value(PARAM_INT, 'row span')
     300                                              ), 'The item returned data', VALUE_OPTIONAL
     301                                          ),
     302                                          'weight' => new external_single_structure(
     303                                              self::grades_table_column(), 'weight column', VALUE_OPTIONAL
     304                                          ),
     305                                          'grade' => new external_single_structure(
     306                                              self::grades_table_column(), 'grade column', VALUE_OPTIONAL
     307                                          ),
     308                                          'range' => new external_single_structure(
     309                                              self::grades_table_column(), 'range column', VALUE_OPTIONAL
     310                                          ),
     311                                          'percentage' => new external_single_structure(
     312                                              self::grades_table_column(), 'percentage column', VALUE_OPTIONAL
     313                                          ),
     314                                          'lettergrade' => new external_single_structure(
     315                                              self::grades_table_column(), 'lettergrade column', VALUE_OPTIONAL
     316                                          ),
     317                                          'rank' => new external_single_structure(
     318                                              self::grades_table_column(), 'rank column', VALUE_OPTIONAL
     319                                          ),
     320                                          'average' => new external_single_structure(
     321                                              self::grades_table_column(), 'average column', VALUE_OPTIONAL
     322                                          ),
     323                                          'feedback' => new external_single_structure(
     324                                              self::grades_table_column(), 'feedback column', VALUE_OPTIONAL
     325                                          ),
     326                                          'contributiontocoursetotal' => new external_single_structure(
     327                                              self::grades_table_column(), 'contributiontocoursetotal column', VALUE_OPTIONAL
     328                                          ),
     329                                      ), 'table'
     330                                  )
     331                              )
     332                          )
     333                      )
     334                  ),
     335                  'warnings' => new external_warnings()
     336              )
     337          );
     338      }
     339  
     340      /**
     341       * Returns description of method parameters
     342       *
     343       * @return external_function_parameters
     344       * @since Moodle 2.9
     345       */
     346      public static function view_grade_report_parameters() {
     347          return new external_function_parameters(
     348              array(
     349                  'courseid' => new external_value(PARAM_INT, 'id of the course'),
     350                  'userid' => new external_value(PARAM_INT, 'id of the user, 0 means current user', VALUE_DEFAULT, 0),
     351              )
     352          );
     353      }
     354  
     355      /**
     356       * Trigger the user report events, do the same that the web interface view of the report
     357       *
     358       * @param int $courseid id of course
     359       * @param int $userid id of the user the report belongs to
     360       * @return array of warnings and status result
     361       * @since Moodle 2.9
     362       * @throws moodle_exception
     363       */
     364      public static function view_grade_report($courseid, $userid = 0) {
     365          global $CFG, $USER;
     366          require_once($CFG->dirroot . "/grade/lib.php");
     367          require_once($CFG->dirroot . "/grade/report/user/lib.php");
     368  
     369          $params = self::validate_parameters(self::view_grade_report_parameters(),
     370                                              array(
     371                                                  'courseid' => $courseid,
     372                                                  'userid' => $userid
     373                                              ));
     374  
     375          $warnings = array();
     376  
     377          $course = get_course($params['courseid']);
     378  
     379          $context = context_course::instance($course->id);
     380          self::validate_context($context);
     381  
     382          $userid = $params['userid'];
     383          if (empty($userid)) {
     384              $userid = $USER->id;
     385          } else {
     386              $user = core_user::get_user($userid, '*', MUST_EXIST);
     387              core_user::require_active_user($user);
     388          }
     389  
     390          $access = false;
     391  
     392          if (has_capability('moodle/grade:viewall', $context)) {
     393              // Can view all course grades (any user).
     394              $access = true;
     395          } else if ($userid == $USER->id and has_capability('moodle/grade:view', $context) and $course->showgrades) {
     396              // View own grades.
     397              $access = true;
     398          }
     399  
     400          if (!$access) {
     401              throw new moodle_exception('nopermissiontoviewgrades', 'error');
     402          }
     403  
     404          // Create a report instance. We don't need the gpr second parameter.
     405          $report = new grade_report_user($course->id, null, $context, $userid);
     406          $report->viewed();
     407  
     408          $result = array();
     409          $result['status'] = true;
     410          $result['warnings'] = $warnings;
     411          return $result;
     412      }
     413  
     414      /**
     415       * Returns description of method result value
     416       *
     417       * @return external_description
     418       * @since Moodle 2.9
     419       */
     420      public static function view_grade_report_returns() {
     421          return new external_single_structure(
     422              array(
     423                  'status' => new external_value(PARAM_BOOL, 'status: true if success'),
     424                  'warnings' => new external_warnings()
     425              )
     426          );
     427      }
     428  
     429      /**
     430       * Describes the parameters for get_grade_items.
     431       *
     432       * @return external_function_parameters
     433       * @since Moodle 3.2
     434       */
     435      public static function get_grade_items_parameters() {
     436          return self::get_grades_table_parameters();
     437      }
     438  
     439      /**
     440       * Returns the complete list of grade items for users in a course.
     441       *
     442       * @param int $courseid Course Id
     443       * @param int $userid   Only this user (optional)
     444       * @param int $groupid  Get users from this group only
     445       *
     446       * @return array the grades tables
     447       * @since Moodle 3.2
     448       */
     449      public static function get_grade_items($courseid, $userid = 0, $groupid = 0) {
     450          global $CFG, $USER;
     451  
     452          list($params, $course, $context, $user, $groupid) = self::check_report_access($courseid, $userid, $groupid);
     453          $userid   = $params['userid'];
     454  
     455          // We pass userid because it can be still 0.
     456          list($gradeitems, $warnings) = self::get_report_data($course, $context, $user, $userid, $groupid, false);
     457  
     458          foreach ($gradeitems as $gradeitem) {
     459              if (isset($gradeitem['feedback']) and isset($gradeitem['feedbackformat'])) {
     460                  list($gradeitem['feedback'], $gradeitem['feedbackformat']) =
     461                      external_format_text($gradeitem['feedback'], $gradeitem['feedbackformat'], $context->id);
     462              }
     463          }
     464  
     465          $result = array();
     466          $result['usergrades'] = $gradeitems;
     467          $result['warnings'] = $warnings;
     468          return $result;
     469      }
     470  
     471      /**
     472       * Describes tget_grade_items return value.
     473       *
     474       * @return external_single_structure
     475       * @since Moodle 3.2
     476       */
     477      public static function get_grade_items_returns() {
     478          return new external_single_structure(
     479              array(
     480                  'usergrades' => new external_multiple_structure(
     481                      new external_single_structure(
     482                          array(
     483                              'courseid' => new external_value(PARAM_INT, 'course id'),
     484                              'courseidnumber' => new external_value(PARAM_TEXT, 'course idnumber'),
     485                              'userid'   => new external_value(PARAM_INT, 'user id'),
     486                              'userfullname' => new external_value(PARAM_TEXT, 'user fullname'),
     487                              'useridnumber' => new external_value(
     488                                  core_user::get_property_type('idnumber'), 'user idnumber'),
     489                              'maxdepth'   => new external_value(PARAM_INT, 'table max depth (needed for printing it)'),
     490                              'gradeitems' => new external_multiple_structure(
     491                                  new external_single_structure(
     492                                      array(
     493                                          'id' => new external_value(PARAM_INT, 'Grade item id'),
     494                                          'itemname' => new external_value(PARAM_TEXT, 'Grade item name'),
     495                                          'itemtype' => new external_value(PARAM_ALPHA, 'Grade item type'),
     496                                          'itemmodule' => new external_value(PARAM_PLUGIN, 'Grade item module'),
     497                                          'iteminstance' => new external_value(PARAM_INT, 'Grade item instance'),
     498                                          'itemnumber' => new external_value(PARAM_INT, 'Grade item item number'),
     499                                          'idnumber' => new external_value(PARAM_TEXT, 'Grade item idnumber'),
     500                                          'categoryid' => new external_value(PARAM_INT, 'Grade item category id'),
     501                                          'outcomeid' => new external_value(PARAM_INT, 'Outcome id'),
     502                                          'scaleid' => new external_value(PARAM_INT, 'Scale id'),
     503                                          'locked' => new external_value(PARAM_BOOL, 'Grade item for user locked?', VALUE_OPTIONAL),
     504                                          'cmid' => new external_value(PARAM_INT, 'Course module id (if type mod)', VALUE_OPTIONAL),
     505                                          'weightraw' => new external_value(PARAM_FLOAT, 'Weight raw', VALUE_OPTIONAL),
     506                                          'weightformatted' => new external_value(PARAM_NOTAGS, 'Weight', VALUE_OPTIONAL),
     507                                          'status' => new external_value(PARAM_ALPHA, 'Status', VALUE_OPTIONAL),
     508                                          'graderaw' => new external_value(PARAM_FLOAT, 'Grade raw', VALUE_OPTIONAL),
     509                                          'gradedatesubmitted' => new external_value(PARAM_INT, 'Grade submit date', VALUE_OPTIONAL),
     510                                          'gradedategraded' => new external_value(PARAM_INT, 'Grade graded date', VALUE_OPTIONAL),
     511                                          'gradehiddenbydate' => new external_value(PARAM_BOOL, 'Grade hidden by date?', VALUE_OPTIONAL),
     512                                          'gradeneedsupdate' => new external_value(PARAM_BOOL, 'Grade needs update?', VALUE_OPTIONAL),
     513                                          'gradeishidden' => new external_value(PARAM_BOOL, 'Grade is hidden?', VALUE_OPTIONAL),
     514                                          'gradeislocked' => new external_value(PARAM_BOOL, 'Grade is locked?', VALUE_OPTIONAL),
     515                                          'gradeisoverridden' => new external_value(PARAM_BOOL, 'Grade overridden?', VALUE_OPTIONAL),
     516                                          'gradeformatted' => new external_value(PARAM_NOTAGS, 'The grade formatted', VALUE_OPTIONAL),
     517                                          'grademin' => new external_value(PARAM_FLOAT, 'Grade min', VALUE_OPTIONAL),
     518                                          'grademax' => new external_value(PARAM_FLOAT, 'Grade max', VALUE_OPTIONAL),
     519                                          'rangeformatted' => new external_value(PARAM_NOTAGS, 'Range formatted', VALUE_OPTIONAL),
     520                                          'percentageformatted' => new external_value(PARAM_NOTAGS, 'Percentage', VALUE_OPTIONAL),
     521                                          'lettergradeformatted' => new external_value(PARAM_NOTAGS, 'Letter grade', VALUE_OPTIONAL),
     522                                          'rank' => new external_value(PARAM_INT, 'Rank in the course', VALUE_OPTIONAL),
     523                                          'numusers' => new external_value(PARAM_INT, 'Num users in course', VALUE_OPTIONAL),
     524                                          'averageformatted' => new external_value(PARAM_NOTAGS, 'Grade average', VALUE_OPTIONAL),
     525                                          'feedback' => new external_value(PARAM_RAW, 'Grade feedback', VALUE_OPTIONAL),
     526                                          'feedbackformat' => new external_format_value('feedback', VALUE_OPTIONAL),
     527                                      ), 'Grade items'
     528                                  )
     529                              )
     530                          )
     531                      )
     532                  ),
     533                  'warnings' => new external_warnings()
     534              )
     535          );
     536      }
     537  }