Search moodle.org's
Developer Documentation

See Release Notes

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

Differences Between: [Versions 310 and 311] [Versions 310 and 400] [Versions 310 and 401] [Versions 310 and 402] [Versions 310 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   * Completion external API
  19   *
  20   * @package    core_completion
  21   * @category   external
  22   * @copyright  2015 Juan Leyva <juan@moodle.com>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   * @since      Moodle 2.9
  25   */
  26  
  27  defined('MOODLE_INTERNAL') || die;
  28  
  29  require_once("$CFG->libdir/externallib.php");
  30  require_once("$CFG->libdir/completionlib.php");
  31  
  32  /**
  33   * Completion external functions
  34   *
  35   * @package    core_completion
  36   * @category   external
  37   * @copyright  2015 Juan Leyva <juan@moodle.com>
  38   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39   * @since      Moodle 2.9
  40   */
  41  class core_completion_external extends external_api {
  42  
  43      /**
  44       * Describes the parameters for update_activity_completion_status_manually.
  45       *
  46       * @return external_function_parameters
  47       * @since Moodle 2.9
  48       */
  49      public static function update_activity_completion_status_manually_parameters() {
  50          return new external_function_parameters (
  51              array(
  52                  'cmid' => new external_value(PARAM_INT, 'course module id'),
  53                  'completed' => new external_value(PARAM_BOOL, 'activity completed or not'),
  54              )
  55          );
  56      }
  57  
  58      /**
  59       * Update completion status for the current user in an activity, only for activities with manual tracking.
  60       * @param  int $cmid      Course module id
  61       * @param  bool $completed Activity completed or not
  62       * @return array            Result and possible warnings
  63       * @since Moodle 2.9
  64       * @throws moodle_exception
  65       */
  66      public static function update_activity_completion_status_manually($cmid,  $completed) {
  67  
  68          // Validate and normalize parameters.
  69          $params = self::validate_parameters(self::update_activity_completion_status_manually_parameters(),
  70              array('cmid' => $cmid, 'completed' => $completed));
  71          $cmid = $params['cmid'];
  72          $completed = $params['completed'];
  73  
  74          $warnings = array();
  75  
  76          $context = context_module::instance($cmid);
  77          self::validate_context($context);
  78          require_capability('moodle/course:togglecompletion', $context);
  79  
  80          list($course, $cm) = get_course_and_cm_from_cmid($cmid);
  81  
  82          // Set up completion object and check it is enabled.
  83          $completion = new completion_info($course);
  84          if (!$completion->is_enabled()) {
  85              throw new moodle_exception('completionnotenabled', 'completion');
  86          }
  87  
  88          // Check completion state is manual.
  89          if ($cm->completion != COMPLETION_TRACKING_MANUAL) {
  90              throw new moodle_exception('cannotmanualctrack', 'error');
  91          }
  92  
  93          $targetstate = ($completed) ? COMPLETION_COMPLETE : COMPLETION_INCOMPLETE;
  94          $completion->update_state($cm, $targetstate);
  95  
  96          $result = array();
  97          $result['status'] = true;
  98          $result['warnings'] = $warnings;
  99          return $result;
 100      }
 101  
 102      /**
 103       * Describes the update_activity_completion_status_manually return value.
 104       *
 105       * @return external_single_structure
 106       * @since Moodle 2.9
 107       */
 108      public static function update_activity_completion_status_manually_returns() {
 109  
 110          return new external_single_structure(
 111              array(
 112                  'status'    => new external_value(PARAM_BOOL, 'status, true if success'),
 113                  'warnings'  => new external_warnings(),
 114              )
 115          );
 116      }
 117  
 118      /**
 119       * Describes the parameters for override_activity_completion_status.
 120       *
 121       * @return external_external_function_parameters
 122       * @since Moodle 3.4
 123       */
 124      public static function override_activity_completion_status_parameters() {
 125          return new external_function_parameters (
 126              array(
 127                  'userid' => new external_value(PARAM_INT, 'user id'),
 128                  'cmid' => new external_value(PARAM_INT, 'course module id'),
 129                  'newstate' => new external_value(PARAM_INT, 'the new activity completion state'),
 130              )
 131          );
 132      }
 133  
 134      /**
 135       * Update completion status for a user in an activity.
 136       * @param  int $userid    User id
 137       * @param  int $cmid      Course module id
 138       * @param  int $newstate  Activity completion
 139       * @return array          Array containing the current (updated) completion status.
 140       * @since Moodle 3.4
 141       * @throws moodle_exception
 142       */
 143      public static function override_activity_completion_status($userid, $cmid, $newstate) {
 144          // Validate and normalize parameters.
 145          $params = self::validate_parameters(self::override_activity_completion_status_parameters(),
 146              array('userid' => $userid, 'cmid' => $cmid, 'newstate' => $newstate));
 147          $userid = $params['userid'];
 148          $cmid = $params['cmid'];
 149          $newstate = $params['newstate'];
 150  
 151          $context = context_module::instance($cmid);
 152          self::validate_context($context);
 153  
 154          list($course, $cm) = get_course_and_cm_from_cmid($cmid);
 155  
 156          // Set up completion object and check it is enabled.
 157          $completion = new completion_info($course);
 158          if (!$completion->is_enabled()) {
 159              throw new moodle_exception('completionnotenabled', 'completion');
 160          }
 161  
 162          // Update completion state and get the new state back.
 163          $completion->update_state($cm, $newstate, $userid, true);
 164          $completiondata = $completion->get_data($cm, false, $userid);
 165  
 166          // Return the current state of completion.
 167          return [
 168              'cmid' => $completiondata->coursemoduleid,
 169              'userid' => $completiondata->userid,
 170              'state' => $completiondata->completionstate,
 171              'timecompleted' => $completiondata->timemodified,
 172              'overrideby' => $completiondata->overrideby,
 173              'tracking' => $completion->is_enabled($cm)
 174          ];
 175      }
 176  
 177      /**
 178       * Describes the override_activity_completion_status return value.
 179       *
 180       * @return external_single_structure
 181       * @since Moodle 3.4
 182       */
 183      public static function override_activity_completion_status_returns() {
 184  
 185          return new external_single_structure(
 186              array(
 187                  'cmid' => new external_value(PARAM_INT, 'The course module id'),
 188                  'userid' => new external_value(PARAM_INT, 'The user id to which the completion info belongs'),
 189                  'state'   => new external_value(PARAM_INT, 'The current completion state.'),
 190                  'timecompleted' => new external_value(PARAM_INT, 'time of completion'),
 191                  'overrideby' => new external_value(PARAM_INT, 'The user id who has overriden the status, or null'),
 192                  'tracking'      => new external_value(PARAM_INT, 'type of tracking:
 193                                                                      0 means none, 1 manual, 2 automatic'),
 194              )
 195          );
 196      }
 197  
 198      /**
 199       * Returns description of method parameters
 200       *
 201       * @return external_function_parameters
 202       * @since Moodle 2.9
 203       */
 204      public static function get_activities_completion_status_parameters() {
 205          return new external_function_parameters(
 206              array(
 207                  'courseid' => new external_value(PARAM_INT, 'Course ID'),
 208                  'userid'   => new external_value(PARAM_INT, 'User ID'),
 209              )
 210          );
 211      }
 212  
 213      /**
 214       * Get Activities completion status
 215       *
 216       * @param int $courseid ID of the Course
 217       * @param int $userid ID of the User
 218       * @return array of activities progress and warnings
 219       * @throws moodle_exception
 220       * @since Moodle 2.9
 221       * @throws moodle_exception
 222       */
 223      public static function get_activities_completion_status($courseid, $userid) {
 224          global $CFG, $USER;
 225          require_once($CFG->libdir . '/grouplib.php');
 226  
 227          $warnings = array();
 228          $arrayparams = array(
 229              'courseid' => $courseid,
 230              'userid'   => $userid,
 231          );
 232  
 233          $params = self::validate_parameters(self::get_activities_completion_status_parameters(), $arrayparams);
 234  
 235          $course = get_course($params['courseid']);
 236          $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
 237          core_user::require_active_user($user);
 238  
 239          $context = context_course::instance($course->id);
 240          self::validate_context($context);
 241  
 242          // Check that current user have permissions to see this user's activities.
 243          if ($user->id != $USER->id) {
 244              require_capability('report/progress:view', $context);
 245              if (!groups_user_groups_visible($course, $user->id)) {
 246                  // We are not in the same group!
 247                  throw new moodle_exception('accessdenied', 'admin');
 248              }
 249          }
 250  
 251          $completion = new completion_info($course);
 252          $activities = $completion->get_activities();
 253  
 254          $results = array();
 255          foreach ($activities as $activity) {
 256  
 257              // Check if current user has visibility on this activity.
 258              if (!$activity->uservisible) {
 259                  continue;
 260              }
 261  
 262              // Get progress information and state (we must use get_data because it works for all user roles in course).
 263              $activitycompletiondata = $completion->get_data($activity, true, $user->id);
 264  
 265              $results[] = array(
 266                         'cmid'          => $activity->id,
 267                         'modname'       => $activity->modname,
 268                         'instance'      => $activity->instance,
 269                         'state'         => $activitycompletiondata->completionstate,
 270                         'timecompleted' => $activitycompletiondata->timemodified,
 271                         'tracking'      => $activity->completion,
 272                         'overrideby'    => $activitycompletiondata->overrideby,
 273                         'valueused'     => core_availability\info::completion_value_used($course, $activity->id)
 274              );
 275          }
 276  
 277          $results = array(
 278              'statuses' => $results,
 279              'warnings' => $warnings
 280          );
 281          return $results;
 282      }
 283  
 284      /**
 285       * Returns description of method result value
 286       *
 287       * @return external_description
 288       * @since Moodle 2.9
 289       */
 290      public static function get_activities_completion_status_returns() {
 291          return new external_single_structure(
 292              array(
 293                  'statuses' => new external_multiple_structure(
 294                      new external_single_structure(
 295                          array(
 296                              'cmid'          => new external_value(PARAM_INT, 'comment ID'),
 297                              'modname'       => new external_value(PARAM_PLUGIN, 'activity module name'),
 298                              'instance'      => new external_value(PARAM_INT, 'instance ID'),
 299                              'state'         => new external_value(PARAM_INT, 'completion state value:
 300                                                                      0 means incomplete, 1 complete,
 301                                                                      2 complete pass, 3 complete fail'),
 302                              'timecompleted' => new external_value(PARAM_INT, 'timestamp for completed activity'),
 303                              'tracking'      => new external_value(PARAM_INT, 'type of tracking:
 304                                                                      0 means none, 1 manual, 2 automatic'),
 305                              'overrideby' => new external_value(PARAM_INT, 'The user id who has overriden the status, or null',
 306                                  VALUE_OPTIONAL),
 307                              'valueused' => new external_value(PARAM_BOOL, 'Whether the completion status affects the availability
 308                                      of another activity.', VALUE_OPTIONAL),
 309                          ), 'Activity'
 310                      ), 'List of activities status'
 311                  ),
 312                  'warnings' => new external_warnings()
 313              )
 314          );
 315      }
 316  
 317      /**
 318       * Returns description of method parameters
 319       *
 320       * @return external_function_parameters
 321       * @since Moodle 2.9
 322       */
 323      public static function get_course_completion_status_parameters() {
 324          return new external_function_parameters(
 325              array(
 326                  'courseid' => new external_value(PARAM_INT, 'Course ID'),
 327                  'userid'   => new external_value(PARAM_INT, 'User ID'),
 328              )
 329          );
 330      }
 331      /**
 332       * Get Course completion status
 333       *
 334       * @param int $courseid ID of the Course
 335       * @param int $userid ID of the User
 336       * @return array of course completion status and warnings
 337       * @since Moodle 2.9
 338       * @throws moodle_exception
 339       */
 340      public static function get_course_completion_status($courseid, $userid) {
 341          global $CFG, $USER;
 342          require_once($CFG->libdir . '/grouplib.php');
 343  
 344          $warnings = array();
 345          $arrayparams = array(
 346              'courseid' => $courseid,
 347              'userid'   => $userid,
 348          );
 349          $params = self::validate_parameters(self::get_course_completion_status_parameters(), $arrayparams);
 350  
 351          $course = get_course($params['courseid']);
 352          $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
 353          core_user::require_active_user($user);
 354  
 355          $context = context_course::instance($course->id);
 356          self::validate_context($context);
 357  
 358          // Can current user see user's course completion status?
 359          // This check verifies if completion is enabled because $course is mandatory.
 360          if (!completion_can_view_data($user->id, $course)) {
 361              throw new moodle_exception('cannotviewreport');
 362          }
 363  
 364          // The previous function doesn't check groups.
 365          if ($user->id != $USER->id) {
 366              if (!groups_user_groups_visible($course, $user->id)) {
 367                  // We are not in the same group!
 368                  throw new moodle_exception('accessdenied', 'admin');
 369              }
 370          }
 371  
 372          $info = new completion_info($course);
 373  
 374          // Check this user is enroled.
 375          if (!$info->is_tracked_user($user->id)) {
 376              if ($USER->id == $user->id) {
 377                  throw new moodle_exception('notenroled', 'completion');
 378              } else {
 379                  throw new moodle_exception('usernotenroled', 'completion');
 380              }
 381          }
 382  
 383          $completions = $info->get_completions($user->id);
 384          if (empty($completions)) {
 385              throw new moodle_exception('nocriteriaset', 'completion');
 386          }
 387  
 388          // Load course completion.
 389          $completionparams = array(
 390              'userid' => $user->id,
 391              'course' => $course->id,
 392          );
 393          $ccompletion = new completion_completion($completionparams);
 394  
 395          $completionrows = array();
 396          // Loop through course criteria.
 397          foreach ($completions as $completion) {
 398              $criteria = $completion->get_criteria();
 399  
 400              $completionrow = array();
 401              $completionrow['type'] = $criteria->criteriatype;
 402              $completionrow['title'] = $criteria->get_title();
 403              $completionrow['status'] = $completion->get_status();
 404              $completionrow['complete'] = $completion->is_complete();
 405              $completionrow['timecompleted'] = $completion->timecompleted;
 406              $completionrow['details'] = $criteria->get_details($completion);
 407              $completionrows[] = $completionrow;
 408          }
 409  
 410          $result = array(
 411                    'completed'   => $info->is_course_complete($user->id),
 412                    'aggregation' => $info->get_aggregation_method(),
 413                    'completions' => $completionrows
 414          );
 415  
 416          $results = array(
 417              'completionstatus' => $result,
 418              'warnings' => $warnings
 419          );
 420          return $results;
 421  
 422      }
 423      /**
 424       * Returns description of method result value
 425       *
 426       * @return external_description
 427       * @since Moodle 2.9
 428       */
 429      public static function get_course_completion_status_returns() {
 430          return new external_single_structure(
 431              array(
 432                  'completionstatus' => new external_single_structure(
 433                      array(
 434                          'completed'     => new external_value(PARAM_BOOL, 'true if the course is complete, false otherwise'),
 435                          'aggregation'   => new external_value(PARAM_INT, 'aggregation method 1 means all, 2 means any'),
 436                          'completions'   => new external_multiple_structure(
 437                              new external_single_structure(
 438                              array(
 439                                   'type'          => new external_value(PARAM_INT,   'Completion criteria type'),
 440                                   'title'         => new external_value(PARAM_TEXT,  'Completion criteria Title'),
 441                                   'status'        => new external_value(PARAM_NOTAGS, 'Completion status (Yes/No) a % or number'),
 442                                   'complete'      => new external_value(PARAM_BOOL,   'Completion status (true/false)'),
 443                                   'timecompleted' => new external_value(PARAM_INT,   'Timestamp for criteria completetion'),
 444                                   'details' => new external_single_structure(
 445                                       array(
 446                                           'type' => new external_value(PARAM_TEXT, 'Type description'),
 447                                           'criteria' => new external_value(PARAM_RAW, 'Criteria description'),
 448                                           'requirement' => new external_value(PARAM_TEXT, 'Requirement description'),
 449                                           'status' => new external_value(PARAM_RAW, 'Status description, can be anything'),
 450                                           ), 'details'),
 451                                   ), 'Completions'
 452                              ), ''
 453                           )
 454                      ), 'Course status'
 455                  ),
 456                  'warnings' => new external_warnings()
 457              ), 'Course completion status'
 458          );
 459      }
 460  
 461      /**
 462       * Describes the parameters for mark_course_self_completed.
 463       *
 464       * @return external_function_parameters
 465       * @since Moodle 3.0
 466       */
 467      public static function mark_course_self_completed_parameters() {
 468          return new external_function_parameters (
 469              array(
 470                  'courseid' => new external_value(PARAM_INT, 'Course ID')
 471              )
 472          );
 473      }
 474  
 475      /**
 476       * Update the course completion status for the current user (if course self-completion is enabled).
 477       *
 478       * @param  int $courseid    Course id
 479       * @return array            Result and possible warnings
 480       * @since Moodle 3.0
 481       * @throws moodle_exception
 482       */
 483      public static function mark_course_self_completed($courseid) {
 484          global $USER;
 485  
 486          $warnings = array();
 487          $params = self::validate_parameters(self::mark_course_self_completed_parameters(),
 488                                              array('courseid' => $courseid));
 489  
 490          $course = get_course($params['courseid']);
 491          $context = context_course::instance($course->id);
 492          self::validate_context($context);
 493  
 494          // Set up completion object and check it is enabled.
 495          $completion = new completion_info($course);
 496          if (!$completion->is_enabled()) {
 497              throw new moodle_exception('completionnotenabled', 'completion');
 498          }
 499  
 500          if (!$completion->is_tracked_user($USER->id)) {
 501              throw new moodle_exception('nottracked', 'completion');
 502          }
 503  
 504          $completion = $completion->get_completion($USER->id, COMPLETION_CRITERIA_TYPE_SELF);
 505  
 506          // Self completion criteria not enabled.
 507          if (!$completion) {
 508              throw new moodle_exception('noselfcompletioncriteria', 'completion');
 509          }
 510  
 511          // Check if the user has already marked himself as complete.
 512          if ($completion->is_complete()) {
 513              throw new moodle_exception('useralreadymarkedcomplete', 'completion');
 514          }
 515  
 516          // Mark the course complete.
 517          $completion->mark_complete();
 518  
 519          $result = array();
 520          $result['status'] = true;
 521          $result['warnings'] = $warnings;
 522          return $result;
 523      }
 524  
 525      /**
 526       * Describes the mark_course_self_completed return value.
 527       *
 528       * @return external_single_structure
 529       * @since Moodle 3.0
 530       */
 531      public static function mark_course_self_completed_returns() {
 532  
 533          return new external_single_structure(
 534              array(
 535                  'status'    => new external_value(PARAM_BOOL, 'status, true if success'),
 536                  'warnings'  => new external_warnings(),
 537              )
 538          );
 539      }
 540  
 541  }