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 310 and 311] [Versions 311 and 400] [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403] [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   * 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, $PAGE;
 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              // Check if current user has visibility on this activity.
 257              if (!$activity->uservisible) {
 258                  continue;
 259              }
 260              // Get progress information and state (we must use get_data because it works for all user roles in course).
 261              $exporter = new \core_completion\external\completion_info_exporter(
 262                  $course,
 263                  $activity,
 264                  $userid,
 265              );
 266              $renderer = $PAGE->get_renderer('core');
 267              $data = (array)$exporter->export($renderer);
 268              $results[] = array_merge([
 269                  'cmid'     => $activity->id,
 270                  'modname'  => $activity->modname,
 271                  'instance' => $activity->instance,
 272                  'tracking' => $activity->completion,
 273              ], $data);
 274          }
 275  
 276          $results = array(
 277              'statuses' => $results,
 278              'warnings' => $warnings
 279          );
 280          return $results;
 281      }
 282  
 283      /**
 284       * Returns description of method result value
 285       *
 286       * @return external_description
 287       * @since Moodle 2.9
 288       */
 289      public static function get_activities_completion_status_returns() {
 290          return new external_single_structure(
 291              array(
 292                  'statuses' => new external_multiple_structure(
 293                      new external_single_structure(
 294                          [
 295                              'cmid'          => new external_value(PARAM_INT, 'course module ID'),
 296                              'modname'       => new external_value(PARAM_PLUGIN, 'activity module name'),
 297                              'instance'      => new external_value(PARAM_INT, 'instance ID'),
 298                              'state'         => new external_value(PARAM_INT,
 299                                  "Completion state value:
 300                                      0 means incomplete,
 301                                      1 complete,
 302                                      2 complete pass,
 303                                      3 complete fail"
 304                                  ),
 305                              'timecompleted' => new external_value(PARAM_INT,
 306                                  'timestamp for completed activity'),
 307                              'tracking'      => new external_value(PARAM_INT,
 308                                  "type of tracking:
 309                                      0 means none,
 310                                      1 manual,
 311                                      2 automatic"
 312                                  ),
 313                              'overrideby' => new external_value(PARAM_INT,
 314                                  'The user id who has overriden the status, or null', VALUE_OPTIONAL),
 315                              'valueused' => new external_value(PARAM_BOOL,
 316                                  'Whether the completion status affects the availability of another activity.',
 317                                  VALUE_OPTIONAL),
 318                              'hascompletion' => new external_value(PARAM_BOOL,
 319                                  'Whether this activity module has completion enabled',
 320                                  VALUE_OPTIONAL),
 321                              'isautomatic' => new external_value(PARAM_BOOL,
 322                                  'Whether this activity module instance tracks completion automatically.',
 323                                  VALUE_OPTIONAL),
 324                              'istrackeduser' => new external_value(PARAM_BOOL,
 325                                  'Whether completion is being tracked for this user.',
 326                                  VALUE_OPTIONAL),
 327                              'uservisible' => new external_value(PARAM_BOOL,
 328                                  'Whether this activity is visible to the user.',
 329                                  VALUE_OPTIONAL),
 330                              'details' => new external_multiple_structure(
 331                                  new external_single_structure(
 332                                      [
 333                                          'rulename' => new external_value(PARAM_TEXT, 'Rule name'),
 334                                          'rulevalue' => new external_single_structure(
 335                                              [
 336                                                  'status' => new external_value(PARAM_INT, 'Completion status'),
 337                                                  'description' => new external_value(PARAM_TEXT, 'Completion description'),
 338                                              ]
 339                                          )
 340                                      ]
 341                                  ),
 342                                  VALUE_DEFAULT,
 343                                  []
 344                              ),
 345  
 346                          ], 'Activity'
 347                      ), 'List of activities status'
 348                  ),
 349                  'warnings' => new external_warnings()
 350              )
 351          );
 352      }
 353  
 354      /**
 355       * Returns description of method parameters
 356       *
 357       * @return external_function_parameters
 358       * @since Moodle 2.9
 359       */
 360      public static function get_course_completion_status_parameters() {
 361          return new external_function_parameters(
 362              array(
 363                  'courseid' => new external_value(PARAM_INT, 'Course ID'),
 364                  'userid'   => new external_value(PARAM_INT, 'User ID'),
 365              )
 366          );
 367      }
 368      /**
 369       * Get Course completion status
 370       *
 371       * @param int $courseid ID of the Course
 372       * @param int $userid ID of the User
 373       * @return array of course completion status and warnings
 374       * @since Moodle 2.9
 375       * @throws moodle_exception
 376       */
 377      public static function get_course_completion_status($courseid, $userid) {
 378          global $CFG, $USER;
 379          require_once($CFG->libdir . '/grouplib.php');
 380  
 381          $warnings = array();
 382          $arrayparams = array(
 383              'courseid' => $courseid,
 384              'userid'   => $userid,
 385          );
 386          $params = self::validate_parameters(self::get_course_completion_status_parameters(), $arrayparams);
 387  
 388          $course = get_course($params['courseid']);
 389          $user = core_user::get_user($params['userid'], '*', MUST_EXIST);
 390          core_user::require_active_user($user);
 391  
 392          $context = context_course::instance($course->id);
 393          self::validate_context($context);
 394  
 395          // Can current user see user's course completion status?
 396          // This check verifies if completion is enabled because $course is mandatory.
 397          if (!completion_can_view_data($user->id, $course)) {
 398              throw new moodle_exception('cannotviewreport');
 399          }
 400  
 401          // The previous function doesn't check groups.
 402          if ($user->id != $USER->id) {
 403              if (!groups_user_groups_visible($course, $user->id)) {
 404                  // We are not in the same group!
 405                  throw new moodle_exception('accessdenied', 'admin');
 406              }
 407          }
 408  
 409          $info = new completion_info($course);
 410  
 411          // Check this user is enroled.
 412          if (!$info->is_tracked_user($user->id)) {
 413              if ($USER->id == $user->id) {
 414                  throw new moodle_exception('notenroled', 'completion');
 415              } else {
 416                  throw new moodle_exception('usernotenroled', 'completion');
 417              }
 418          }
 419  
 420          $completions = $info->get_completions($user->id);
 421          if (empty($completions)) {
 422              throw new moodle_exception('nocriteriaset', 'completion');
 423          }
 424  
 425          // Load course completion.
 426          $completionparams = array(
 427              'userid' => $user->id,
 428              'course' => $course->id,
 429          );
 430          $ccompletion = new completion_completion($completionparams);
 431  
 432          $completionrows = array();
 433          // Loop through course criteria.
 434          foreach ($completions as $completion) {
 435              $criteria = $completion->get_criteria();
 436  
 437              $completionrow = array();
 438              $completionrow['type'] = $criteria->criteriatype;
 439              $completionrow['title'] = $criteria->get_title();
 440              $completionrow['status'] = $completion->get_status();
 441              $completionrow['complete'] = $completion->is_complete();
 442              $completionrow['timecompleted'] = $completion->timecompleted;
 443              $completionrow['details'] = $criteria->get_details($completion);
 444              $completionrows[] = $completionrow;
 445          }
 446  
 447          $result = array(
 448                    'completed'   => $info->is_course_complete($user->id),
 449                    'aggregation' => $info->get_aggregation_method(),
 450                    'completions' => $completionrows
 451          );
 452  
 453          $results = array(
 454              'completionstatus' => $result,
 455              'warnings' => $warnings
 456          );
 457          return $results;
 458  
 459      }
 460      /**
 461       * Returns description of method result value
 462       *
 463       * @return external_description
 464       * @since Moodle 2.9
 465       */
 466      public static function get_course_completion_status_returns() {
 467          return new external_single_structure(
 468              array(
 469                  'completionstatus' => new external_single_structure(
 470                      array(
 471                          'completed'     => new external_value(PARAM_BOOL, 'true if the course is complete, false otherwise'),
 472                          'aggregation'   => new external_value(PARAM_INT, 'aggregation method 1 means all, 2 means any'),
 473                          'completions'   => new external_multiple_structure(
 474                              new external_single_structure(
 475                              array(
 476                                   'type'          => new external_value(PARAM_INT,   'Completion criteria type'),
 477                                   'title'         => new external_value(PARAM_TEXT,  'Completion criteria Title'),
 478                                   'status'        => new external_value(PARAM_NOTAGS, 'Completion status (Yes/No) a % or number'),
 479                                   'complete'      => new external_value(PARAM_BOOL,   'Completion status (true/false)'),
 480                                   'timecompleted' => new external_value(PARAM_INT,   'Timestamp for criteria completetion'),
 481                                   'details' => new external_single_structure(
 482                                       array(
 483                                           'type' => new external_value(PARAM_TEXT, 'Type description'),
 484                                           'criteria' => new external_value(PARAM_RAW, 'Criteria description'),
 485                                           'requirement' => new external_value(PARAM_TEXT, 'Requirement description'),
 486                                           'status' => new external_value(PARAM_RAW, 'Status description, can be anything'),
 487                                           ), 'details'),
 488                                   ), 'Completions'
 489                              ), ''
 490                           )
 491                      ), 'Course status'
 492                  ),
 493                  'warnings' => new external_warnings()
 494              ), 'Course completion status'
 495          );
 496      }
 497  
 498      /**
 499       * Describes the parameters for mark_course_self_completed.
 500       *
 501       * @return external_function_parameters
 502       * @since Moodle 3.0
 503       */
 504      public static function mark_course_self_completed_parameters() {
 505          return new external_function_parameters (
 506              array(
 507                  'courseid' => new external_value(PARAM_INT, 'Course ID')
 508              )
 509          );
 510      }
 511  
 512      /**
 513       * Update the course completion status for the current user (if course self-completion is enabled).
 514       *
 515       * @param  int $courseid    Course id
 516       * @return array            Result and possible warnings
 517       * @since Moodle 3.0
 518       * @throws moodle_exception
 519       */
 520      public static function mark_course_self_completed($courseid) {
 521          global $USER;
 522  
 523          $warnings = array();
 524          $params = self::validate_parameters(self::mark_course_self_completed_parameters(),
 525                                              array('courseid' => $courseid));
 526  
 527          $course = get_course($params['courseid']);
 528          $context = context_course::instance($course->id);
 529          self::validate_context($context);
 530  
 531          // Set up completion object and check it is enabled.
 532          $completion = new completion_info($course);
 533          if (!$completion->is_enabled()) {
 534              throw new moodle_exception('completionnotenabled', 'completion');
 535          }
 536  
 537          if (!$completion->is_tracked_user($USER->id)) {
 538              throw new moodle_exception('nottracked', 'completion');
 539          }
 540  
 541          $completion = $completion->get_completion($USER->id, COMPLETION_CRITERIA_TYPE_SELF);
 542  
 543          // Self completion criteria not enabled.
 544          if (!$completion) {
 545              throw new moodle_exception('noselfcompletioncriteria', 'completion');
 546          }
 547  
 548          // Check if the user has already marked himself as complete.
 549          if ($completion->is_complete()) {
 550              throw new moodle_exception('useralreadymarkedcomplete', 'completion');
 551          }
 552  
 553          // Mark the course complete.
 554          $completion->mark_complete();
 555  
 556          $result = array();
 557          $result['status'] = true;
 558          $result['warnings'] = $warnings;
 559          return $result;
 560      }
 561  
 562      /**
 563       * Describes the mark_course_self_completed return value.
 564       *
 565       * @return external_single_structure
 566       * @since Moodle 3.0
 567       */
 568      public static function mark_course_self_completed_returns() {
 569  
 570          return new external_single_structure(
 571              array(
 572                  'status'    => new external_value(PARAM_BOOL, 'status, true if success'),
 573                  'warnings'  => new external_warnings(),
 574              )
 575          );
 576      }
 577  
 578  }