[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/course/ -> externallib.php (source)

   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  /**
  19   * External course API
  20   *
  21   * @package    core_course
  22   * @category   external
  23   * @copyright  2009 Petr Skodak
  24   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  25   */
  26  
  27  defined('MOODLE_INTERNAL') || die;
  28  
  29  require_once("$CFG->libdir/externallib.php");
  30  
  31  /**
  32   * Course external functions
  33   *
  34   * @package    core_course
  35   * @category   external
  36   * @copyright  2011 Jerome Mouneyrac
  37   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   * @since Moodle 2.2
  39   */
  40  class core_course_external extends external_api {
  41  
  42      /**
  43       * Returns description of method parameters
  44       *
  45       * @return external_function_parameters
  46       * @since Moodle 2.9 Options available
  47       * @since Moodle 2.2
  48       */
  49      public static function get_course_contents_parameters() {
  50          return new external_function_parameters(
  51                  array('courseid' => new external_value(PARAM_INT, 'course id'),
  52                        'options' => new external_multiple_structure (
  53                                new external_single_structure(
  54                                  array(
  55                                      'name' => new external_value(PARAM_ALPHANUM,
  56                                                  'The expected keys (value format) are:
  57                                                  excludemodules (bool) Do not return modules, return only the sections structure
  58                                                  excludecontents (bool) Do not return module contents (i.e: files inside a resource)
  59                                                  sectionid (int) Return only this section
  60                                                  sectionnumber (int) Return only this section with number (order)
  61                                                  cmid (int) Return only this module information (among the whole sections structure)
  62                                                  modname (string) Return only modules with this name "label, forum, etc..."
  63                                                  modid (int) Return only the module with this id (to be used with modname'),
  64                                      'value' => new external_value(PARAM_RAW, 'the value of the option,
  65                                                                      this param is personaly validated in the external function.')
  66                                )
  67                        ), 'Options, used since Moodle 2.9', VALUE_DEFAULT, array())
  68                  )
  69          );
  70      }
  71  
  72      /**
  73       * Get course contents
  74       *
  75       * @param int $courseid course id
  76       * @param array $options Options for filtering the results, used since Moodle 2.9
  77       * @return array
  78       * @since Moodle 2.9 Options available
  79       * @since Moodle 2.2
  80       */
  81      public static function get_course_contents($courseid, $options = array()) {
  82          global $CFG, $DB;
  83          require_once($CFG->dirroot . "/course/lib.php");
  84  
  85          //validate parameter
  86          $params = self::validate_parameters(self::get_course_contents_parameters(),
  87                          array('courseid' => $courseid, 'options' => $options));
  88  
  89          $filters = array();
  90          if (!empty($params['options'])) {
  91  
  92              foreach ($params['options'] as $option) {
  93                  $name = trim($option['name']);
  94                  // Avoid duplicated options.
  95                  if (!isset($filters[$name])) {
  96                      switch ($name) {
  97                          case 'excludemodules':
  98                          case 'excludecontents':
  99                              $value = clean_param($option['value'], PARAM_BOOL);
 100                              $filters[$name] = $value;
 101                              break;
 102                          case 'sectionid':
 103                          case 'sectionnumber':
 104                          case 'cmid':
 105                          case 'modid':
 106                              $value = clean_param($option['value'], PARAM_INT);
 107                              if (is_numeric($value)) {
 108                                  $filters[$name] = $value;
 109                              } else {
 110                                  throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
 111                              }
 112                              break;
 113                          case 'modname':
 114                              $value = clean_param($option['value'], PARAM_PLUGIN);
 115                              if ($value) {
 116                                  $filters[$name] = $value;
 117                              } else {
 118                                  throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
 119                              }
 120                              break;
 121                          default:
 122                              throw new moodle_exception('errorinvalidparam', 'webservice', '', $name);
 123                      }
 124                  }
 125              }
 126          }
 127  
 128          //retrieve the course
 129          $course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST);
 130  
 131          if ($course->id != SITEID) {
 132              // Check course format exist.
 133              if (!file_exists($CFG->dirroot . '/course/format/' . $course->format . '/lib.php')) {
 134                  throw new moodle_exception('cannotgetcoursecontents', 'webservice', '', null,
 135                                              get_string('courseformatnotfound', 'error', $course->format));
 136              } else {
 137                  require_once($CFG->dirroot . '/course/format/' . $course->format . '/lib.php');
 138              }
 139          }
 140  
 141          // now security checks
 142          $context = context_course::instance($course->id, IGNORE_MISSING);
 143          try {
 144              self::validate_context($context);
 145          } catch (Exception $e) {
 146              $exceptionparam = new stdClass();
 147              $exceptionparam->message = $e->getMessage();
 148              $exceptionparam->courseid = $course->id;
 149              throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
 150          }
 151  
 152          $canupdatecourse = has_capability('moodle/course:update', $context);
 153  
 154          //create return value
 155          $coursecontents = array();
 156  
 157          if ($canupdatecourse or $course->visible
 158                  or has_capability('moodle/course:viewhiddencourses', $context)) {
 159  
 160              //retrieve sections
 161              $modinfo = get_fast_modinfo($course);
 162              $sections = $modinfo->get_section_info_all();
 163  
 164              //for each sections (first displayed to last displayed)
 165              $modinfosections = $modinfo->get_sections();
 166              foreach ($sections as $key => $section) {
 167  
 168                  if (!$section->uservisible) {
 169                      continue;
 170                  }
 171  
 172                  // This becomes true when we are filtering and we found the value to filter with.
 173                  $sectionfound = false;
 174  
 175                  // Filter by section id.
 176                  if (!empty($filters['sectionid'])) {
 177                      if ($section->id != $filters['sectionid']) {
 178                          continue;
 179                      } else {
 180                          $sectionfound = true;
 181                      }
 182                  }
 183  
 184                  // Filter by section number. Note that 0 is a valid section number.
 185                  if (isset($filters['sectionnumber'])) {
 186                      if ($key != $filters['sectionnumber']) {
 187                          continue;
 188                      } else {
 189                          $sectionfound = true;
 190                      }
 191                  }
 192  
 193                  // reset $sectioncontents
 194                  $sectionvalues = array();
 195                  $sectionvalues['id'] = $section->id;
 196                  $sectionvalues['name'] = get_section_name($course, $section);
 197                  $sectionvalues['visible'] = $section->visible;
 198  
 199                  $options = (object) array('noclean' => true);
 200                  list($sectionvalues['summary'], $sectionvalues['summaryformat']) =
 201                          external_format_text($section->summary, $section->summaryformat,
 202                                  $context->id, 'course', 'section', $section->id, $options);
 203                  $sectionvalues['section'] = $section->section;
 204                  $sectioncontents = array();
 205  
 206                  //for each module of the section
 207                  if (empty($filters['excludemodules']) and !empty($modinfosections[$section->section])) {
 208                      foreach ($modinfosections[$section->section] as $cmid) {
 209                          $cm = $modinfo->cms[$cmid];
 210  
 211                          // stop here if the module is not visible to the user
 212                          if (!$cm->uservisible) {
 213                              continue;
 214                          }
 215  
 216                          // This becomes true when we are filtering and we found the value to filter with.
 217                          $modfound = false;
 218  
 219                          // Filter by cmid.
 220                          if (!empty($filters['cmid'])) {
 221                              if ($cmid != $filters['cmid']) {
 222                                  continue;
 223                              } else {
 224                                  $modfound = true;
 225                              }
 226                          }
 227  
 228                          // Filter by module name and id.
 229                          if (!empty($filters['modname'])) {
 230                              if ($cm->modname != $filters['modname']) {
 231                                  continue;
 232                              } else if (!empty($filters['modid'])) {
 233                                  if ($cm->instance != $filters['modid']) {
 234                                      continue;
 235                                  } else {
 236                                      // Note that if we are only filtering by modname we don't break the loop.
 237                                      $modfound = true;
 238                                  }
 239                              }
 240                          }
 241  
 242                          $module = array();
 243  
 244                          $modcontext = context_module::instance($cm->id);
 245  
 246                          //common info (for people being able to see the module or availability dates)
 247                          $module['id'] = $cm->id;
 248                          $module['name'] = external_format_string($cm->name, $modcontext->id);
 249                          $module['instance'] = $cm->instance;
 250                          $module['modname'] = $cm->modname;
 251                          $module['modplural'] = $cm->modplural;
 252                          $module['modicon'] = $cm->get_icon_url()->out(false);
 253                          $module['indent'] = $cm->indent;
 254  
 255                          if (!empty($cm->showdescription) or $cm->modname == 'label') {
 256                              // We want to use the external format. However from reading get_formatted_content(), $cm->content format is always FORMAT_HTML.
 257                              list($module['description'], $descriptionformat) = external_format_text($cm->content,
 258                                  FORMAT_HTML, $modcontext->id, $cm->modname, 'intro', $cm->id);
 259                          }
 260  
 261                          //url of the module
 262                          $url = $cm->url;
 263                          if ($url) { //labels don't have url
 264                              $module['url'] = $url->out(false);
 265                          }
 266  
 267                          $canviewhidden = has_capability('moodle/course:viewhiddenactivities',
 268                                              context_module::instance($cm->id));
 269                          //user that can view hidden module should know about the visibility
 270                          $module['visible'] = $cm->visible;
 271  
 272                          // Availability date (also send to user who can see hidden module).
 273                          if ($CFG->enableavailability && ($canviewhidden || $canupdatecourse)) {
 274                              $module['availability'] = $cm->availability;
 275                          }
 276  
 277                          $baseurl = 'webservice/pluginfile.php';
 278  
 279                          //call $modulename_export_contents
 280                          //(each module callback take care about checking the capabilities)
 281  
 282                          require_once($CFG->dirroot . '/mod/' . $cm->modname . '/lib.php');
 283                          $getcontentfunction = $cm->modname.'_export_contents';
 284                          if (function_exists($getcontentfunction)) {
 285                              if (empty($filters['excludecontents']) and $contents = $getcontentfunction($cm, $baseurl)) {
 286                                  $module['contents'] = $contents;
 287                              } else {
 288                                  $module['contents'] = array();
 289                              }
 290                          }
 291  
 292                          //assign result to $sectioncontents
 293                          $sectioncontents[] = $module;
 294  
 295                          // If we just did a filtering, break the loop.
 296                          if ($modfound) {
 297                              break;
 298                          }
 299  
 300                      }
 301                  }
 302                  $sectionvalues['modules'] = $sectioncontents;
 303  
 304                  // assign result to $coursecontents
 305                  $coursecontents[] = $sectionvalues;
 306  
 307                  // Break the loop if we are filtering.
 308                  if ($sectionfound) {
 309                      break;
 310                  }
 311              }
 312          }
 313          return $coursecontents;
 314      }
 315  
 316      /**
 317       * Returns description of method result value
 318       *
 319       * @return external_description
 320       * @since Moodle 2.2
 321       */
 322      public static function get_course_contents_returns() {
 323          return new external_multiple_structure(
 324              new external_single_structure(
 325                  array(
 326                      'id' => new external_value(PARAM_INT, 'Section ID'),
 327                      'name' => new external_value(PARAM_TEXT, 'Section name'),
 328                      'visible' => new external_value(PARAM_INT, 'is the section visible', VALUE_OPTIONAL),
 329                      'summary' => new external_value(PARAM_RAW, 'Section description'),
 330                      'summaryformat' => new external_format_value('summary'),
 331                      'section' => new external_value(PARAM_INT, 'Section number inside the course', VALUE_OPTIONAL),
 332                      'modules' => new external_multiple_structure(
 333                              new external_single_structure(
 334                                  array(
 335                                      'id' => new external_value(PARAM_INT, 'activity id'),
 336                                      'url' => new external_value(PARAM_URL, 'activity url', VALUE_OPTIONAL),
 337                                      'name' => new external_value(PARAM_RAW, 'activity module name'),
 338                                      'instance' => new external_value(PARAM_INT, 'instance id', VALUE_OPTIONAL),
 339                                      'description' => new external_value(PARAM_RAW, 'activity description', VALUE_OPTIONAL),
 340                                      'visible' => new external_value(PARAM_INT, 'is the module visible', VALUE_OPTIONAL),
 341                                      'modicon' => new external_value(PARAM_URL, 'activity icon url'),
 342                                      'modname' => new external_value(PARAM_PLUGIN, 'activity module type'),
 343                                      'modplural' => new external_value(PARAM_TEXT, 'activity module plural name'),
 344                                      'availability' => new external_value(PARAM_RAW, 'module availability settings', VALUE_OPTIONAL),
 345                                      'indent' => new external_value(PARAM_INT, 'number of identation in the site'),
 346                                      'contents' => new external_multiple_structure(
 347                                            new external_single_structure(
 348                                                array(
 349                                                    // content info
 350                                                    'type'=> new external_value(PARAM_TEXT, 'a file or a folder or external link'),
 351                                                    'filename'=> new external_value(PARAM_FILE, 'filename'),
 352                                                    'filepath'=> new external_value(PARAM_PATH, 'filepath'),
 353                                                    'filesize'=> new external_value(PARAM_INT, 'filesize'),
 354                                                    'fileurl' => new external_value(PARAM_URL, 'downloadable file url', VALUE_OPTIONAL),
 355                                                    'content' => new external_value(PARAM_RAW, 'Raw content, will be used when type is content', VALUE_OPTIONAL),
 356                                                    'timecreated' => new external_value(PARAM_INT, 'Time created'),
 357                                                    'timemodified' => new external_value(PARAM_INT, 'Time modified'),
 358                                                    'sortorder' => new external_value(PARAM_INT, 'Content sort order'),
 359  
 360                                                    // copyright related info
 361                                                    'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'),
 362                                                    'author' => new external_value(PARAM_TEXT, 'Content owner'),
 363                                                    'license' => new external_value(PARAM_TEXT, 'Content license'),
 364                                                )
 365                                            ), VALUE_DEFAULT, array()
 366                                        )
 367                                  )
 368                              ), 'list of module'
 369                      )
 370                  )
 371              )
 372          );
 373      }
 374  
 375      /**
 376       * Returns description of method parameters
 377       *
 378       * @return external_function_parameters
 379       * @since Moodle 2.3
 380       */
 381      public static function get_courses_parameters() {
 382          return new external_function_parameters(
 383                  array('options' => new external_single_structure(
 384                              array('ids' => new external_multiple_structure(
 385                                          new external_value(PARAM_INT, 'Course id')
 386                                          , 'List of course id. If empty return all courses
 387                                              except front page course.',
 388                                          VALUE_OPTIONAL)
 389                              ), 'options - operator OR is used', VALUE_DEFAULT, array())
 390                  )
 391          );
 392      }
 393  
 394      /**
 395       * Get courses
 396       *
 397       * @param array $options It contains an array (list of ids)
 398       * @return array
 399       * @since Moodle 2.2
 400       */
 401      public static function get_courses($options = array()) {
 402          global $CFG, $DB;
 403          require_once($CFG->dirroot . "/course/lib.php");
 404  
 405          //validate parameter
 406          $params = self::validate_parameters(self::get_courses_parameters(),
 407                          array('options' => $options));
 408  
 409          //retrieve courses
 410          if (!array_key_exists('ids', $params['options'])
 411                  or empty($params['options']['ids'])) {
 412              $courses = $DB->get_records('course');
 413          } else {
 414              $courses = $DB->get_records_list('course', 'id', $params['options']['ids']);
 415          }
 416  
 417          //create return value
 418          $coursesinfo = array();
 419          foreach ($courses as $course) {
 420  
 421              // now security checks
 422              $context = context_course::instance($course->id, IGNORE_MISSING);
 423              $courseformatoptions = course_get_format($course)->get_format_options();
 424              try {
 425                  self::validate_context($context);
 426              } catch (Exception $e) {
 427                  $exceptionparam = new stdClass();
 428                  $exceptionparam->message = $e->getMessage();
 429                  $exceptionparam->courseid = $course->id;
 430                  throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
 431              }
 432              require_capability('moodle/course:view', $context);
 433  
 434              $courseinfo = array();
 435              $courseinfo['id'] = $course->id;
 436              $courseinfo['fullname'] = external_format_string($course->fullname, $context->id);
 437              $courseinfo['shortname'] = external_format_string($course->shortname, $context->id);
 438              $courseinfo['displayname'] = external_format_string(get_course_display_name_for_list($course), $context->id);
 439              $courseinfo['categoryid'] = $course->category;
 440              list($courseinfo['summary'], $courseinfo['summaryformat']) =
 441                  external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', 0);
 442              $courseinfo['format'] = $course->format;
 443              $courseinfo['startdate'] = $course->startdate;
 444              if (array_key_exists('numsections', $courseformatoptions)) {
 445                  // For backward-compartibility
 446                  $courseinfo['numsections'] = $courseformatoptions['numsections'];
 447              }
 448  
 449              //some field should be returned only if the user has update permission
 450              $courseadmin = has_capability('moodle/course:update', $context);
 451              if ($courseadmin) {
 452                  $courseinfo['categorysortorder'] = $course->sortorder;
 453                  $courseinfo['idnumber'] = $course->idnumber;
 454                  $courseinfo['showgrades'] = $course->showgrades;
 455                  $courseinfo['showreports'] = $course->showreports;
 456                  $courseinfo['newsitems'] = $course->newsitems;
 457                  $courseinfo['visible'] = $course->visible;
 458                  $courseinfo['maxbytes'] = $course->maxbytes;
 459                  if (array_key_exists('hiddensections', $courseformatoptions)) {
 460                      // For backward-compartibility
 461                      $courseinfo['hiddensections'] = $courseformatoptions['hiddensections'];
 462                  }
 463                  $courseinfo['groupmode'] = $course->groupmode;
 464                  $courseinfo['groupmodeforce'] = $course->groupmodeforce;
 465                  $courseinfo['defaultgroupingid'] = $course->defaultgroupingid;
 466                  $courseinfo['lang'] = $course->lang;
 467                  $courseinfo['timecreated'] = $course->timecreated;
 468                  $courseinfo['timemodified'] = $course->timemodified;
 469                  $courseinfo['forcetheme'] = $course->theme;
 470                  $courseinfo['enablecompletion'] = $course->enablecompletion;
 471                  $courseinfo['completionnotify'] = $course->completionnotify;
 472                  $courseinfo['courseformatoptions'] = array();
 473                  foreach ($courseformatoptions as $key => $value) {
 474                      $courseinfo['courseformatoptions'][] = array(
 475                          'name' => $key,
 476                          'value' => $value
 477                      );
 478                  }
 479              }
 480  
 481              if ($courseadmin or $course->visible
 482                      or has_capability('moodle/course:viewhiddencourses', $context)) {
 483                  $coursesinfo[] = $courseinfo;
 484              }
 485          }
 486  
 487          return $coursesinfo;
 488      }
 489  
 490      /**
 491       * Returns description of method result value
 492       *
 493       * @return external_description
 494       * @since Moodle 2.2
 495       */
 496      public static function get_courses_returns() {
 497          return new external_multiple_structure(
 498                  new external_single_structure(
 499                          array(
 500                              'id' => new external_value(PARAM_INT, 'course id'),
 501                              'shortname' => new external_value(PARAM_TEXT, 'course short name'),
 502                              'categoryid' => new external_value(PARAM_INT, 'category id'),
 503                              'categorysortorder' => new external_value(PARAM_INT,
 504                                      'sort order into the category', VALUE_OPTIONAL),
 505                              'fullname' => new external_value(PARAM_TEXT, 'full name'),
 506                              'displayname' => new external_value(PARAM_TEXT, 'course display name'),
 507                              'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
 508                              'summary' => new external_value(PARAM_RAW, 'summary'),
 509                              'summaryformat' => new external_format_value('summary'),
 510                              'format' => new external_value(PARAM_PLUGIN,
 511                                      'course format: weeks, topics, social, site,..'),
 512                              'showgrades' => new external_value(PARAM_INT,
 513                                      '1 if grades are shown, otherwise 0', VALUE_OPTIONAL),
 514                              'newsitems' => new external_value(PARAM_INT,
 515                                      'number of recent items appearing on the course page', VALUE_OPTIONAL),
 516                              'startdate' => new external_value(PARAM_INT,
 517                                      'timestamp when the course start'),
 518                              'numsections' => new external_value(PARAM_INT,
 519                                      '(deprecated, use courseformatoptions) number of weeks/topics',
 520                                      VALUE_OPTIONAL),
 521                              'maxbytes' => new external_value(PARAM_INT,
 522                                      'largest size of file that can be uploaded into the course',
 523                                      VALUE_OPTIONAL),
 524                              'showreports' => new external_value(PARAM_INT,
 525                                      'are activity report shown (yes = 1, no =0)', VALUE_OPTIONAL),
 526                              'visible' => new external_value(PARAM_INT,
 527                                      '1: available to student, 0:not available', VALUE_OPTIONAL),
 528                              'hiddensections' => new external_value(PARAM_INT,
 529                                      '(deprecated, use courseformatoptions) How the hidden sections in the course are displayed to students',
 530                                      VALUE_OPTIONAL),
 531                              'groupmode' => new external_value(PARAM_INT, 'no group, separate, visible',
 532                                      VALUE_OPTIONAL),
 533                              'groupmodeforce' => new external_value(PARAM_INT, '1: yes, 0: no',
 534                                      VALUE_OPTIONAL),
 535                              'defaultgroupingid' => new external_value(PARAM_INT, 'default grouping id',
 536                                      VALUE_OPTIONAL),
 537                              'timecreated' => new external_value(PARAM_INT,
 538                                      'timestamp when the course have been created', VALUE_OPTIONAL),
 539                              'timemodified' => new external_value(PARAM_INT,
 540                                      'timestamp when the course have been modified', VALUE_OPTIONAL),
 541                              'enablecompletion' => new external_value(PARAM_INT,
 542                                      'Enabled, control via completion and activity settings. Disbaled,
 543                                          not shown in activity settings.',
 544                                      VALUE_OPTIONAL),
 545                              'completionnotify' => new external_value(PARAM_INT,
 546                                      '1: yes 0: no', VALUE_OPTIONAL),
 547                              'lang' => new external_value(PARAM_SAFEDIR,
 548                                      'forced course language', VALUE_OPTIONAL),
 549                              'forcetheme' => new external_value(PARAM_PLUGIN,
 550                                      'name of the force theme', VALUE_OPTIONAL),
 551                              'courseformatoptions' => new external_multiple_structure(
 552                                  new external_single_structure(
 553                                      array('name' => new external_value(PARAM_ALPHANUMEXT, 'course format option name'),
 554                                          'value' => new external_value(PARAM_RAW, 'course format option value')
 555                                  )),
 556                                      'additional options for particular course format', VALUE_OPTIONAL
 557                               ),
 558                          ), 'course'
 559                  )
 560          );
 561      }
 562  
 563      /**
 564       * Returns description of method parameters
 565       *
 566       * @return external_function_parameters
 567       * @since Moodle 2.2
 568       */
 569      public static function create_courses_parameters() {
 570          $courseconfig = get_config('moodlecourse'); //needed for many default values
 571          return new external_function_parameters(
 572              array(
 573                  'courses' => new external_multiple_structure(
 574                      new external_single_structure(
 575                          array(
 576                              'fullname' => new external_value(PARAM_TEXT, 'full name'),
 577                              'shortname' => new external_value(PARAM_TEXT, 'course short name'),
 578                              'categoryid' => new external_value(PARAM_INT, 'category id'),
 579                              'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
 580                              'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL),
 581                              'summaryformat' => new external_format_value('summary', VALUE_DEFAULT),
 582                              'format' => new external_value(PARAM_PLUGIN,
 583                                      'course format: weeks, topics, social, site,..',
 584                                      VALUE_DEFAULT, $courseconfig->format),
 585                              'showgrades' => new external_value(PARAM_INT,
 586                                      '1 if grades are shown, otherwise 0', VALUE_DEFAULT,
 587                                      $courseconfig->showgrades),
 588                              'newsitems' => new external_value(PARAM_INT,
 589                                      'number of recent items appearing on the course page',
 590                                      VALUE_DEFAULT, $courseconfig->newsitems),
 591                              'startdate' => new external_value(PARAM_INT,
 592                                      'timestamp when the course start', VALUE_OPTIONAL),
 593                              'numsections' => new external_value(PARAM_INT,
 594                                      '(deprecated, use courseformatoptions) number of weeks/topics',
 595                                      VALUE_OPTIONAL),
 596                              'maxbytes' => new external_value(PARAM_INT,
 597                                      'largest size of file that can be uploaded into the course',
 598                                      VALUE_DEFAULT, $courseconfig->maxbytes),
 599                              'showreports' => new external_value(PARAM_INT,
 600                                      'are activity report shown (yes = 1, no =0)', VALUE_DEFAULT,
 601                                      $courseconfig->showreports),
 602                              'visible' => new external_value(PARAM_INT,
 603                                      '1: available to student, 0:not available', VALUE_OPTIONAL),
 604                              'hiddensections' => new external_value(PARAM_INT,
 605                                      '(deprecated, use courseformatoptions) How the hidden sections in the course are displayed to students',
 606                                      VALUE_OPTIONAL),
 607                              'groupmode' => new external_value(PARAM_INT, 'no group, separate, visible',
 608                                      VALUE_DEFAULT, $courseconfig->groupmode),
 609                              'groupmodeforce' => new external_value(PARAM_INT, '1: yes, 0: no',
 610                                      VALUE_DEFAULT, $courseconfig->groupmodeforce),
 611                              'defaultgroupingid' => new external_value(PARAM_INT, 'default grouping id',
 612                                      VALUE_DEFAULT, 0),
 613                              'enablecompletion' => new external_value(PARAM_INT,
 614                                      'Enabled, control via completion and activity settings. Disabled,
 615                                          not shown in activity settings.',
 616                                      VALUE_OPTIONAL),
 617                              'completionnotify' => new external_value(PARAM_INT,
 618                                      '1: yes 0: no', VALUE_OPTIONAL),
 619                              'lang' => new external_value(PARAM_SAFEDIR,
 620                                      'forced course language', VALUE_OPTIONAL),
 621                              'forcetheme' => new external_value(PARAM_PLUGIN,
 622                                      'name of the force theme', VALUE_OPTIONAL),
 623                              'courseformatoptions' => new external_multiple_structure(
 624                                  new external_single_structure(
 625                                      array('name' => new external_value(PARAM_ALPHANUMEXT, 'course format option name'),
 626                                          'value' => new external_value(PARAM_RAW, 'course format option value')
 627                                  )),
 628                                      'additional options for particular course format', VALUE_OPTIONAL),
 629                          )
 630                      ), 'courses to create'
 631                  )
 632              )
 633          );
 634      }
 635  
 636      /**
 637       * Create  courses
 638       *
 639       * @param array $courses
 640       * @return array courses (id and shortname only)
 641       * @since Moodle 2.2
 642       */
 643      public static function create_courses($courses) {
 644          global $CFG, $DB;
 645          require_once($CFG->dirroot . "/course/lib.php");
 646          require_once($CFG->libdir . '/completionlib.php');
 647  
 648          $params = self::validate_parameters(self::create_courses_parameters(),
 649                          array('courses' => $courses));
 650  
 651          $availablethemes = core_component::get_plugin_list('theme');
 652          $availablelangs = get_string_manager()->get_list_of_translations();
 653  
 654          $transaction = $DB->start_delegated_transaction();
 655  
 656          foreach ($params['courses'] as $course) {
 657  
 658              // Ensure the current user is allowed to run this function
 659              $context = context_coursecat::instance($course['categoryid'], IGNORE_MISSING);
 660              try {
 661                  self::validate_context($context);
 662              } catch (Exception $e) {
 663                  $exceptionparam = new stdClass();
 664                  $exceptionparam->message = $e->getMessage();
 665                  $exceptionparam->catid = $course['categoryid'];
 666                  throw new moodle_exception('errorcatcontextnotvalid', 'webservice', '', $exceptionparam);
 667              }
 668              require_capability('moodle/course:create', $context);
 669  
 670              // Make sure lang is valid
 671              if (array_key_exists('lang', $course) and empty($availablelangs[$course['lang']])) {
 672                  throw new moodle_exception('errorinvalidparam', 'webservice', '', 'lang');
 673              }
 674  
 675              // Make sure theme is valid
 676              if (array_key_exists('forcetheme', $course)) {
 677                  if (!empty($CFG->allowcoursethemes)) {
 678                      if (empty($availablethemes[$course['forcetheme']])) {
 679                          throw new moodle_exception('errorinvalidparam', 'webservice', '', 'forcetheme');
 680                      } else {
 681                          $course['theme'] = $course['forcetheme'];
 682                      }
 683                  }
 684              }
 685  
 686              //force visibility if ws user doesn't have the permission to set it
 687              $category = $DB->get_record('course_categories', array('id' => $course['categoryid']));
 688              if (!has_capability('moodle/course:visibility', $context)) {
 689                  $course['visible'] = $category->visible;
 690              }
 691  
 692              //set default value for completion
 693              $courseconfig = get_config('moodlecourse');
 694              if (completion_info::is_enabled_for_site()) {
 695                  if (!array_key_exists('enablecompletion', $course)) {
 696                      $course['enablecompletion'] = $courseconfig->enablecompletion;
 697                  }
 698              } else {
 699                  $course['enablecompletion'] = 0;
 700              }
 701  
 702              $course['category'] = $course['categoryid'];
 703  
 704              // Summary format.
 705              $course['summaryformat'] = external_validate_format($course['summaryformat']);
 706  
 707              if (!empty($course['courseformatoptions'])) {
 708                  foreach ($course['courseformatoptions'] as $option) {
 709                      $course[$option['name']] = $option['value'];
 710                  }
 711              }
 712  
 713              //Note: create_course() core function check shortname, idnumber, category
 714              $course['id'] = create_course((object) $course)->id;
 715  
 716              $resultcourses[] = array('id' => $course['id'], 'shortname' => $course['shortname']);
 717          }
 718  
 719          $transaction->allow_commit();
 720  
 721          return $resultcourses;
 722      }
 723  
 724      /**
 725       * Returns description of method result value
 726       *
 727       * @return external_description
 728       * @since Moodle 2.2
 729       */
 730      public static function create_courses_returns() {
 731          return new external_multiple_structure(
 732              new external_single_structure(
 733                  array(
 734                      'id'       => new external_value(PARAM_INT, 'course id'),
 735                      'shortname' => new external_value(PARAM_TEXT, 'short name'),
 736                  )
 737              )
 738          );
 739      }
 740  
 741      /**
 742       * Update courses
 743       *
 744       * @return external_function_parameters
 745       * @since Moodle 2.5
 746       */
 747      public static function update_courses_parameters() {
 748          return new external_function_parameters(
 749              array(
 750                  'courses' => new external_multiple_structure(
 751                      new external_single_structure(
 752                          array(
 753                              'id' => new external_value(PARAM_INT, 'ID of the course'),
 754                              'fullname' => new external_value(PARAM_TEXT, 'full name', VALUE_OPTIONAL),
 755                              'shortname' => new external_value(PARAM_TEXT, 'course short name', VALUE_OPTIONAL),
 756                              'categoryid' => new external_value(PARAM_INT, 'category id', VALUE_OPTIONAL),
 757                              'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
 758                              'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL),
 759                              'summaryformat' => new external_format_value('summary', VALUE_OPTIONAL),
 760                              'format' => new external_value(PARAM_PLUGIN,
 761                                      'course format: weeks, topics, social, site,..', VALUE_OPTIONAL),
 762                              'showgrades' => new external_value(PARAM_INT,
 763                                      '1 if grades are shown, otherwise 0', VALUE_OPTIONAL),
 764                              'newsitems' => new external_value(PARAM_INT,
 765                                      'number of recent items appearing on the course page', VALUE_OPTIONAL),
 766                              'startdate' => new external_value(PARAM_INT,
 767                                      'timestamp when the course start', VALUE_OPTIONAL),
 768                              'numsections' => new external_value(PARAM_INT,
 769                                      '(deprecated, use courseformatoptions) number of weeks/topics', VALUE_OPTIONAL),
 770                              'maxbytes' => new external_value(PARAM_INT,
 771                                      'largest size of file that can be uploaded into the course', VALUE_OPTIONAL),
 772                              'showreports' => new external_value(PARAM_INT,
 773                                      'are activity report shown (yes = 1, no =0)', VALUE_OPTIONAL),
 774                              'visible' => new external_value(PARAM_INT,
 775                                      '1: available to student, 0:not available', VALUE_OPTIONAL),
 776                              'hiddensections' => new external_value(PARAM_INT,
 777                                      '(deprecated, use courseformatoptions) How the hidden sections in the course are
 778                                          displayed to students', VALUE_OPTIONAL),
 779                              'groupmode' => new external_value(PARAM_INT, 'no group, separate, visible', VALUE_OPTIONAL),
 780                              'groupmodeforce' => new external_value(PARAM_INT, '1: yes, 0: no', VALUE_OPTIONAL),
 781                              'defaultgroupingid' => new external_value(PARAM_INT, 'default grouping id', VALUE_OPTIONAL),
 782                              'enablecompletion' => new external_value(PARAM_INT,
 783                                      'Enabled, control via completion and activity settings. Disabled,
 784                                          not shown in activity settings.', VALUE_OPTIONAL),
 785                              'completionnotify' => new external_value(PARAM_INT, '1: yes 0: no', VALUE_OPTIONAL),
 786                              'lang' => new external_value(PARAM_SAFEDIR, 'forced course language', VALUE_OPTIONAL),
 787                              'forcetheme' => new external_value(PARAM_PLUGIN, 'name of the force theme', VALUE_OPTIONAL),
 788                              'courseformatoptions' => new external_multiple_structure(
 789                                  new external_single_structure(
 790                                      array('name' => new external_value(PARAM_ALPHANUMEXT, 'course format option name'),
 791                                          'value' => new external_value(PARAM_RAW, 'course format option value')
 792                                  )),
 793                                      'additional options for particular course format', VALUE_OPTIONAL),
 794                          )
 795                      ), 'courses to update'
 796                  )
 797              )
 798          );
 799      }
 800  
 801      /**
 802       * Update courses
 803       *
 804       * @param array $courses
 805       * @since Moodle 2.5
 806       */
 807      public static function update_courses($courses) {
 808          global $CFG, $DB;
 809          require_once($CFG->dirroot . "/course/lib.php");
 810          $warnings = array();
 811  
 812          $params = self::validate_parameters(self::update_courses_parameters(),
 813                          array('courses' => $courses));
 814  
 815          $availablethemes = core_component::get_plugin_list('theme');
 816          $availablelangs = get_string_manager()->get_list_of_translations();
 817  
 818          foreach ($params['courses'] as $course) {
 819              // Catch any exception while updating course and return as warning to user.
 820              try {
 821                  // Ensure the current user is allowed to run this function.
 822                  $context = context_course::instance($course['id'], MUST_EXIST);
 823                  self::validate_context($context);
 824  
 825                  $oldcourse = course_get_format($course['id'])->get_course();
 826  
 827                  require_capability('moodle/course:update', $context);
 828  
 829                  // Check if user can change category.
 830                  if (array_key_exists('categoryid', $course) && ($oldcourse->category != $course['categoryid'])) {
 831                      require_capability('moodle/course:changecategory', $context);
 832                      $course['category'] = $course['categoryid'];
 833                  }
 834  
 835                  // Check if the user can change fullname.
 836                  if (array_key_exists('fullname', $course) && ($oldcourse->fullname != $course['fullname'])) {
 837                      require_capability('moodle/course:changefullname', $context);
 838                  }
 839  
 840                  // Check if the user can change shortname.
 841                  if (array_key_exists('shortname', $course) && ($oldcourse->shortname != $course['shortname'])) {
 842                      require_capability('moodle/course:changeshortname', $context);
 843                  }
 844  
 845                  // Check if the user can change the idnumber.
 846                  if (array_key_exists('idnumber', $course) && ($oldcourse->idnumber != $course['idnumber'])) {
 847                      require_capability('moodle/course:changeidnumber', $context);
 848                  }
 849  
 850                  // Check if user can change summary.
 851                  if (array_key_exists('summary', $course) && ($oldcourse->summary != $course['summary'])) {
 852                      require_capability('moodle/course:changesummary', $context);
 853                  }
 854  
 855                  // Summary format.
 856                  if (array_key_exists('summaryformat', $course) && ($oldcourse->summaryformat != $course['summaryformat'])) {
 857                      require_capability('moodle/course:changesummary', $context);
 858                      $course['summaryformat'] = external_validate_format($course['summaryformat']);
 859                  }
 860  
 861                  // Check if user can change visibility.
 862                  if (array_key_exists('visible', $course) && ($oldcourse->visible != $course['visible'])) {
 863                      require_capability('moodle/course:visibility', $context);
 864                  }
 865  
 866                  // Make sure lang is valid.
 867                  if (array_key_exists('lang', $course) && empty($availablelangs[$course['lang']])) {
 868                      throw new moodle_exception('errorinvalidparam', 'webservice', '', 'lang');
 869                  }
 870  
 871                  // Make sure theme is valid.
 872                  if (array_key_exists('forcetheme', $course)) {
 873                      if (!empty($CFG->allowcoursethemes)) {
 874                          if (empty($availablethemes[$course['forcetheme']])) {
 875                              throw new moodle_exception('errorinvalidparam', 'webservice', '', 'forcetheme');
 876                          } else {
 877                              $course['theme'] = $course['forcetheme'];
 878                          }
 879                      }
 880                  }
 881  
 882                  // Make sure completion is enabled before setting it.
 883                  if (array_key_exists('enabledcompletion', $course) && !completion_info::is_enabled_for_site()) {
 884                      $course['enabledcompletion'] = 0;
 885                  }
 886  
 887                  // Make sure maxbytes are less then CFG->maxbytes.
 888                  if (array_key_exists('maxbytes', $course)) {
 889                      $course['maxbytes'] = get_max_upload_file_size($CFG->maxbytes, $course['maxbytes']);
 890                  }
 891  
 892                  if (!empty($course['courseformatoptions'])) {
 893                      foreach ($course['courseformatoptions'] as $option) {
 894                          if (isset($option['name']) && isset($option['value'])) {
 895                              $course[$option['name']] = $option['value'];
 896                          }
 897                      }
 898                  }
 899  
 900                  // Update course if user has all required capabilities.
 901                  update_course((object) $course);
 902              } catch (Exception $e) {
 903                  $warning = array();
 904                  $warning['item'] = 'course';
 905                  $warning['itemid'] = $course['id'];
 906                  if ($e instanceof moodle_exception) {
 907                      $warning['warningcode'] = $e->errorcode;
 908                  } else {
 909                      $warning['warningcode'] = $e->getCode();
 910                  }
 911                  $warning['message'] = $e->getMessage();
 912                  $warnings[] = $warning;
 913              }
 914          }
 915  
 916          $result = array();
 917          $result['warnings'] = $warnings;
 918          return $result;
 919      }
 920  
 921      /**
 922       * Returns description of method result value
 923       *
 924       * @return external_description
 925       * @since Moodle 2.5
 926       */
 927      public static function update_courses_returns() {
 928          return new external_single_structure(
 929              array(
 930                  'warnings' => new external_warnings()
 931              )
 932          );
 933      }
 934  
 935      /**
 936       * Returns description of method parameters
 937       *
 938       * @return external_function_parameters
 939       * @since Moodle 2.2
 940       */
 941      public static function delete_courses_parameters() {
 942          return new external_function_parameters(
 943              array(
 944                  'courseids' => new external_multiple_structure(new external_value(PARAM_INT, 'course ID')),
 945              )
 946          );
 947      }
 948  
 949      /**
 950       * Delete courses
 951       *
 952       * @param array $courseids A list of course ids
 953       * @since Moodle 2.2
 954       */
 955      public static function delete_courses($courseids) {
 956          global $CFG, $DB;
 957          require_once($CFG->dirroot."/course/lib.php");
 958  
 959          // Parameter validation.
 960          $params = self::validate_parameters(self::delete_courses_parameters(), array('courseids'=>$courseids));
 961  
 962          $warnings = array();
 963  
 964          foreach ($params['courseids'] as $courseid) {
 965              $course = $DB->get_record('course', array('id' => $courseid));
 966  
 967              if ($course === false) {
 968                  $warnings[] = array(
 969                                  'item' => 'course',
 970                                  'itemid' => $courseid,
 971                                  'warningcode' => 'unknowncourseidnumber',
 972                                  'message' => 'Unknown course ID ' . $courseid
 973                              );
 974                  continue;
 975              }
 976  
 977              // Check if the context is valid.
 978              $coursecontext = context_course::instance($course->id);
 979              self::validate_context($coursecontext);
 980  
 981              // Check if the current user has permission.
 982              if (!can_delete_course($courseid)) {
 983                  $warnings[] = array(
 984                                  'item' => 'course',
 985                                  'itemid' => $courseid,
 986                                  'warningcode' => 'cannotdeletecourse',
 987                                  'message' => 'You do not have the permission to delete this course' . $courseid
 988                              );
 989                  continue;
 990              }
 991  
 992              if (delete_course($course, false) === false) {
 993                  $warnings[] = array(
 994                                  'item' => 'course',
 995                                  'itemid' => $courseid,
 996                                  'warningcode' => 'cannotdeletecategorycourse',
 997                                  'message' => 'Course ' . $courseid . ' failed to be deleted'
 998                              );
 999                  continue;
1000              }
1001          }
1002  
1003          fix_course_sortorder();
1004  
1005          return array('warnings' => $warnings);
1006      }
1007  
1008      /**
1009       * Returns description of method result value
1010       *
1011       * @return external_description
1012       * @since Moodle 2.2
1013       */
1014      public static function delete_courses_returns() {
1015          return new external_single_structure(
1016              array(
1017                  'warnings' => new external_warnings()
1018              )
1019          );
1020      }
1021  
1022      /**
1023       * Returns description of method parameters
1024       *
1025       * @return external_function_parameters
1026       * @since Moodle 2.3
1027       */
1028      public static function duplicate_course_parameters() {
1029          return new external_function_parameters(
1030              array(
1031                  'courseid' => new external_value(PARAM_INT, 'course to duplicate id'),
1032                  'fullname' => new external_value(PARAM_TEXT, 'duplicated course full name'),
1033                  'shortname' => new external_value(PARAM_TEXT, 'duplicated course short name'),
1034                  'categoryid' => new external_value(PARAM_INT, 'duplicated course category parent'),
1035                  'visible' => new external_value(PARAM_INT, 'duplicated course visible, default to yes', VALUE_DEFAULT, 1),
1036                  'options' => new external_multiple_structure(
1037                      new external_single_structure(
1038                          array(
1039                                  'name' => new external_value(PARAM_ALPHAEXT, 'The backup option name:
1040                                              "activities" (int) Include course activites (default to 1 that is equal to yes),
1041                                              "blocks" (int) Include course blocks (default to 1 that is equal to yes),
1042                                              "filters" (int) Include course filters  (default to 1 that is equal to yes),
1043                                              "users" (int) Include users (default to 0 that is equal to no),
1044                                              "role_assignments" (int) Include role assignments  (default to 0 that is equal to no),
1045                                              "comments" (int) Include user comments  (default to 0 that is equal to no),
1046                                              "userscompletion" (int) Include user course completion information  (default to 0 that is equal to no),
1047                                              "logs" (int) Include course logs  (default to 0 that is equal to no),
1048                                              "grade_histories" (int) Include histories  (default to 0 that is equal to no)'
1049                                              ),
1050                                  'value' => new external_value(PARAM_RAW, 'the value for the option 1 (yes) or 0 (no)'
1051                              )
1052                          )
1053                      ), VALUE_DEFAULT, array()
1054                  ),
1055              )
1056          );
1057      }
1058  
1059      /**
1060       * Duplicate a course
1061       *
1062       * @param int $courseid
1063       * @param string $fullname Duplicated course fullname
1064       * @param string $shortname Duplicated course shortname
1065       * @param int $categoryid Duplicated course parent category id
1066       * @param int $visible Duplicated course availability
1067       * @param array $options List of backup options
1068       * @return array New course info
1069       * @since Moodle 2.3
1070       */
1071      public static function duplicate_course($courseid, $fullname, $shortname, $categoryid, $visible = 1, $options = array()) {
1072          global $CFG, $USER, $DB;
1073          require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
1074          require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
1075  
1076          // Parameter validation.
1077          $params = self::validate_parameters(
1078                  self::duplicate_course_parameters(),
1079                  array(
1080                        'courseid' => $courseid,
1081                        'fullname' => $fullname,
1082                        'shortname' => $shortname,
1083                        'categoryid' => $categoryid,
1084                        'visible' => $visible,
1085                        'options' => $options
1086                  )
1087          );
1088  
1089          // Context validation.
1090  
1091          if (! ($course = $DB->get_record('course', array('id'=>$params['courseid'])))) {
1092              throw new moodle_exception('invalidcourseid', 'error');
1093          }
1094  
1095          // Category where duplicated course is going to be created.
1096          $categorycontext = context_coursecat::instance($params['categoryid']);
1097          self::validate_context($categorycontext);
1098  
1099          // Course to be duplicated.
1100          $coursecontext = context_course::instance($course->id);
1101          self::validate_context($coursecontext);
1102  
1103          $backupdefaults = array(
1104              'activities' => 1,
1105              'blocks' => 1,
1106              'filters' => 1,
1107              'users' => 0,
1108              'role_assignments' => 0,
1109              'comments' => 0,
1110              'userscompletion' => 0,
1111              'logs' => 0,
1112              'grade_histories' => 0
1113          );
1114  
1115          $backupsettings = array();
1116          // Check for backup and restore options.
1117          if (!empty($params['options'])) {
1118              foreach ($params['options'] as $option) {
1119  
1120                  // Strict check for a correct value (allways 1 or 0, true or false).
1121                  $value = clean_param($option['value'], PARAM_INT);
1122  
1123                  if ($value !== 0 and $value !== 1) {
1124                      throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
1125                  }
1126  
1127                  if (!isset($backupdefaults[$option['name']])) {
1128                      throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
1129                  }
1130  
1131                  $backupsettings[$option['name']] = $value;
1132              }
1133          }
1134  
1135          // Capability checking.
1136  
1137          // The backup controller check for this currently, this may be redundant.
1138          require_capability('moodle/course:create', $categorycontext);
1139          require_capability('moodle/restore:restorecourse', $categorycontext);
1140          require_capability('moodle/backup:backupcourse', $coursecontext);
1141  
1142          if (!empty($backupsettings['users'])) {
1143              require_capability('moodle/backup:userinfo', $coursecontext);
1144              require_capability('moodle/restore:userinfo', $categorycontext);
1145          }
1146  
1147          // Check if the shortname is used.
1148          if ($foundcourses = $DB->get_records('course', array('shortname'=>$shortname))) {
1149              foreach ($foundcourses as $foundcourse) {
1150                  $foundcoursenames[] = $foundcourse->fullname;
1151              }
1152  
1153              $foundcoursenamestring = implode(',', $foundcoursenames);
1154              throw new moodle_exception('shortnametaken', '', '', $foundcoursenamestring);
1155          }
1156  
1157          // Backup the course.
1158  
1159          $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
1160          backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id);
1161  
1162          foreach ($backupsettings as $name => $value) {
1163              $bc->get_plan()->get_setting($name)->set_value($value);
1164          }
1165  
1166          $backupid       = $bc->get_backupid();
1167          $backupbasepath = $bc->get_plan()->get_basepath();
1168  
1169          $bc->execute_plan();
1170          $results = $bc->get_results();
1171          $file = $results['backup_destination'];
1172  
1173          $bc->destroy();
1174  
1175          // Restore the backup immediately.
1176  
1177          // Check if we need to unzip the file because the backup temp dir does not contains backup files.
1178          if (!file_exists($backupbasepath . "/moodle_backup.xml")) {
1179              $file->extract_to_pathname(get_file_packer('application/vnd.moodle.backup'), $backupbasepath);
1180          }
1181  
1182          // Create new course.
1183          $newcourseid = restore_dbops::create_new_course($params['fullname'], $params['shortname'], $params['categoryid']);
1184  
1185          $rc = new restore_controller($backupid, $newcourseid,
1186                  backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id, backup::TARGET_NEW_COURSE);
1187  
1188          foreach ($backupsettings as $name => $value) {
1189              $setting = $rc->get_plan()->get_setting($name);
1190              if ($setting->get_status() == backup_setting::NOT_LOCKED) {
1191                  $setting->set_value($value);
1192              }
1193          }
1194  
1195          if (!$rc->execute_precheck()) {
1196              $precheckresults = $rc->get_precheck_results();
1197              if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
1198                  if (empty($CFG->keeptempdirectoriesonbackup)) {
1199                      fulldelete($backupbasepath);
1200                  }
1201  
1202                  $errorinfo = '';
1203  
1204                  foreach ($precheckresults['errors'] as $error) {
1205                      $errorinfo .= $error;
1206                  }
1207  
1208                  if (array_key_exists('warnings', $precheckresults)) {
1209                      foreach ($precheckresults['warnings'] as $warning) {
1210                          $errorinfo .= $warning;
1211                      }
1212                  }
1213  
1214                  throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
1215              }
1216          }
1217  
1218          $rc->execute_plan();
1219          $rc->destroy();
1220  
1221          $course = $DB->get_record('course', array('id' => $newcourseid), '*', MUST_EXIST);
1222          $course->fullname = $params['fullname'];
1223          $course->shortname = $params['shortname'];
1224          $course->visible = $params['visible'];
1225  
1226          // Set shortname and fullname back.
1227          $DB->update_record('course', $course);
1228  
1229          if (empty($CFG->keeptempdirectoriesonbackup)) {
1230              fulldelete($backupbasepath);
1231          }
1232  
1233          // Delete the course backup file created by this WebService. Originally located in the course backups area.
1234          $file->delete();
1235  
1236          return array('id' => $course->id, 'shortname' => $course->shortname);
1237      }
1238  
1239      /**
1240       * Returns description of method result value
1241       *
1242       * @return external_description
1243       * @since Moodle 2.3
1244       */
1245      public static function duplicate_course_returns() {
1246          return new external_single_structure(
1247              array(
1248                  'id'       => new external_value(PARAM_INT, 'course id'),
1249                  'shortname' => new external_value(PARAM_TEXT, 'short name'),
1250              )
1251          );
1252      }
1253  
1254      /**
1255       * Returns description of method parameters for import_course
1256       *
1257       * @return external_function_parameters
1258       * @since Moodle 2.4
1259       */
1260      public static function import_course_parameters() {
1261          return new external_function_parameters(
1262              array(
1263                  'importfrom' => new external_value(PARAM_INT, 'the id of the course we are importing from'),
1264                  'importto' => new external_value(PARAM_INT, 'the id of the course we are importing to'),
1265                  'deletecontent' => new external_value(PARAM_INT, 'whether to delete the course content where we are importing to (default to 0 = No)', VALUE_DEFAULT, 0),
1266                  'options' => new external_multiple_structure(
1267                      new external_single_structure(
1268                          array(
1269                                  'name' => new external_value(PARAM_ALPHA, 'The backup option name:
1270                                              "activities" (int) Include course activites (default to 1 that is equal to yes),
1271                                              "blocks" (int) Include course blocks (default to 1 that is equal to yes),
1272                                              "filters" (int) Include course filters  (default to 1 that is equal to yes)'
1273                                              ),
1274                                  'value' => new external_value(PARAM_RAW, 'the value for the option 1 (yes) or 0 (no)'
1275                              )
1276                          )
1277                      ), VALUE_DEFAULT, array()
1278                  ),
1279              )
1280          );
1281      }
1282  
1283      /**
1284       * Imports a course
1285       *
1286       * @param int $importfrom The id of the course we are importing from
1287       * @param int $importto The id of the course we are importing to
1288       * @param bool $deletecontent Whether to delete the course we are importing to content
1289       * @param array $options List of backup options
1290       * @return null
1291       * @since Moodle 2.4
1292       */
1293      public static function import_course($importfrom, $importto, $deletecontent = 0, $options = array()) {
1294          global $CFG, $USER, $DB;
1295          require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
1296          require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
1297  
1298          // Parameter validation.
1299          $params = self::validate_parameters(
1300              self::import_course_parameters(),
1301              array(
1302                  'importfrom' => $importfrom,
1303                  'importto' => $importto,
1304                  'deletecontent' => $deletecontent,
1305                  'options' => $options
1306              )
1307          );
1308  
1309          if ($params['deletecontent'] !== 0 and $params['deletecontent'] !== 1) {
1310              throw new moodle_exception('invalidextparam', 'webservice', '', $params['deletecontent']);
1311          }
1312  
1313          // Context validation.
1314  
1315          if (! ($importfrom = $DB->get_record('course', array('id'=>$params['importfrom'])))) {
1316              throw new moodle_exception('invalidcourseid', 'error');
1317          }
1318  
1319          if (! ($importto = $DB->get_record('course', array('id'=>$params['importto'])))) {
1320              throw new moodle_exception('invalidcourseid', 'error');
1321          }
1322  
1323          $importfromcontext = context_course::instance($importfrom->id);
1324          self::validate_context($importfromcontext);
1325  
1326          $importtocontext = context_course::instance($importto->id);
1327          self::validate_context($importtocontext);
1328  
1329          $backupdefaults = array(
1330              'activities' => 1,
1331              'blocks' => 1,
1332              'filters' => 1
1333          );
1334  
1335          $backupsettings = array();
1336  
1337          // Check for backup and restore options.
1338          if (!empty($params['options'])) {
1339              foreach ($params['options'] as $option) {
1340  
1341                  // Strict check for a correct value (allways 1 or 0, true or false).
1342                  $value = clean_param($option['value'], PARAM_INT);
1343  
1344                  if ($value !== 0 and $value !== 1) {
1345                      throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
1346                  }
1347  
1348                  if (!isset($backupdefaults[$option['name']])) {
1349                      throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
1350                  }
1351  
1352                  $backupsettings[$option['name']] = $value;
1353              }
1354          }
1355  
1356          // Capability checking.
1357  
1358          require_capability('moodle/backup:backuptargetimport', $importfromcontext);
1359          require_capability('moodle/restore:restoretargetimport', $importtocontext);
1360  
1361          $bc = new backup_controller(backup::TYPE_1COURSE, $importfrom->id, backup::FORMAT_MOODLE,
1362                  backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
1363  
1364          foreach ($backupsettings as $name => $value) {
1365              $bc->get_plan()->get_setting($name)->set_value($value);
1366          }
1367  
1368          $backupid       = $bc->get_backupid();
1369          $backupbasepath = $bc->get_plan()->get_basepath();
1370  
1371          $bc->execute_plan();
1372          $bc->destroy();
1373  
1374          // Restore the backup immediately.
1375  
1376          // Check if we must delete the contents of the destination course.
1377          if ($params['deletecontent']) {
1378              $restoretarget = backup::TARGET_EXISTING_DELETING;
1379          } else {
1380              $restoretarget = backup::TARGET_EXISTING_ADDING;
1381          }
1382  
1383          $rc = new restore_controller($backupid, $importto->id,
1384                  backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, $restoretarget);
1385  
1386          foreach ($backupsettings as $name => $value) {
1387              $rc->get_plan()->get_setting($name)->set_value($value);
1388          }
1389  
1390          if (!$rc->execute_precheck()) {
1391              $precheckresults = $rc->get_precheck_results();
1392              if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
1393                  if (empty($CFG->keeptempdirectoriesonbackup)) {
1394                      fulldelete($backupbasepath);
1395                  }
1396  
1397                  $errorinfo = '';
1398  
1399                  foreach ($precheckresults['errors'] as $error) {
1400                      $errorinfo .= $error;
1401                  }
1402  
1403                  if (array_key_exists('warnings', $precheckresults)) {
1404                      foreach ($precheckresults['warnings'] as $warning) {
1405                          $errorinfo .= $warning;
1406                      }
1407                  }
1408  
1409                  throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
1410              }
1411          } else {
1412              if ($restoretarget == backup::TARGET_EXISTING_DELETING) {
1413                  restore_dbops::delete_course_content($importto->id);
1414              }
1415          }
1416  
1417          $rc->execute_plan();
1418          $rc->destroy();
1419  
1420          if (empty($CFG->keeptempdirectoriesonbackup)) {
1421              fulldelete($backupbasepath);
1422          }
1423  
1424          return null;
1425      }
1426  
1427      /**
1428       * Returns description of method result value
1429       *
1430       * @return external_description
1431       * @since Moodle 2.4
1432       */
1433      public static function import_course_returns() {
1434          return null;
1435      }
1436  
1437      /**
1438       * Returns description of method parameters
1439       *
1440       * @return external_function_parameters
1441       * @since Moodle 2.3
1442       */
1443      public static function get_categories_parameters() {
1444          return new external_function_parameters(
1445              array(
1446                  'criteria' => new external_multiple_structure(
1447                      new external_single_structure(
1448                          array(
1449                              'key' => new external_value(PARAM_ALPHA,
1450                                           'The category column to search, expected keys (value format) are:'.
1451                                           '"id" (int) the category id,'.
1452                                           '"ids" (string) category ids separated by commas,'.
1453                                           '"name" (string) the category name,'.
1454                                           '"parent" (int) the parent category id,'.
1455                                           '"idnumber" (string) category idnumber'.
1456                                           ' - user must have \'moodle/category:manage\' to search on idnumber,'.
1457                                           '"visible" (int) whether the returned categories must be visible or hidden. If the key is not passed,
1458                                               then the function return all categories that the user can see.'.
1459                                           ' - user must have \'moodle/category:manage\' or \'moodle/category:viewhiddencategories\' to search on visible,'.
1460                                           '"theme" (string) only return the categories having this theme'.
1461                                           ' - user must have \'moodle/category:manage\' to search on theme'),
1462                              'value' => new external_value(PARAM_RAW, 'the value to match')
1463                          )
1464                      ), 'criteria', VALUE_DEFAULT, array()
1465                  ),
1466                  'addsubcategories' => new external_value(PARAM_BOOL, 'return the sub categories infos
1467                                            (1 - default) otherwise only the category info (0)', VALUE_DEFAULT, 1)
1468              )
1469          );
1470      }
1471  
1472      /**
1473       * Get categories
1474       *
1475       * @param array $criteria Criteria to match the results
1476       * @param booln $addsubcategories obtain only the category (false) or its subcategories (true - default)
1477       * @return array list of categories
1478       * @since Moodle 2.3
1479       */
1480      public static function get_categories($criteria = array(), $addsubcategories = true) {
1481          global $CFG, $DB;
1482          require_once($CFG->dirroot . "/course/lib.php");
1483  
1484          // Validate parameters.
1485          $params = self::validate_parameters(self::get_categories_parameters(),
1486                  array('criteria' => $criteria, 'addsubcategories' => $addsubcategories));
1487  
1488          // Retrieve the categories.
1489          $categories = array();
1490          if (!empty($params['criteria'])) {
1491  
1492              $conditions = array();
1493              $wheres = array();
1494              foreach ($params['criteria'] as $crit) {
1495                  $key = trim($crit['key']);
1496  
1497                  // Trying to avoid duplicate keys.
1498                  if (!isset($conditions[$key])) {
1499  
1500                      $context = context_system::instance();
1501                      $value = null;
1502                      switch ($key) {
1503                          case 'id':
1504                              $value = clean_param($crit['value'], PARAM_INT);
1505                              $conditions[$key] = $value;
1506                              $wheres[] = $key . " = :" . $key;
1507                              break;
1508  
1509                          case 'ids':
1510                              $value = clean_param($crit['value'], PARAM_SEQUENCE);
1511                              $ids = explode(',', $value);
1512                              list($sqlids, $paramids) = $DB->get_in_or_equal($ids, SQL_PARAMS_NAMED);
1513                              $conditions = array_merge($conditions, $paramids);
1514                              $wheres[] = 'id ' . $sqlids;
1515                              break;
1516  
1517                          case 'idnumber':
1518                              if (has_capability('moodle/category:manage', $context)) {
1519                                  $value = clean_param($crit['value'], PARAM_RAW);
1520                                  $conditions[$key] = $value;
1521                                  $wheres[] = $key . " = :" . $key;
1522                              } else {
1523                                  // We must throw an exception.
1524                                  // Otherwise the dev client would think no idnumber exists.
1525                                  throw new moodle_exception('criteriaerror',
1526                                          'webservice', '', null,
1527                                          'You don\'t have the permissions to search on the "idnumber" field.');
1528                              }
1529                              break;
1530  
1531                          case 'name':
1532                              $value = clean_param($crit['value'], PARAM_TEXT);
1533                              $conditions[$key] = $value;
1534                              $wheres[] = $key . " = :" . $key;
1535                              break;
1536  
1537                          case 'parent':
1538                              $value = clean_param($crit['value'], PARAM_INT);
1539                              $conditions[$key] = $value;
1540                              $wheres[] = $key . " = :" . $key;
1541                              break;
1542  
1543                          case 'visible':
1544                              if (has_capability('moodle/category:manage', $context)
1545                                  or has_capability('moodle/category:viewhiddencategories',
1546                                          context_system::instance())) {
1547                                  $value = clean_param($crit['value'], PARAM_INT);
1548                                  $conditions[$key] = $value;
1549                                  $wheres[] = $key . " = :" . $key;
1550                              } else {
1551                                  throw new moodle_exception('criteriaerror',
1552                                          'webservice', '', null,
1553                                          'You don\'t have the permissions to search on the "visible" field.');
1554                              }
1555                              break;
1556  
1557                          case 'theme':
1558                              if (has_capability('moodle/category:manage', $context)) {
1559                                  $value = clean_param($crit['value'], PARAM_THEME);
1560                                  $conditions[$key] = $value;
1561                                  $wheres[] = $key . " = :" . $key;
1562                              } else {
1563                                  throw new moodle_exception('criteriaerror',
1564                                          'webservice', '', null,
1565                                          'You don\'t have the permissions to search on the "theme" field.');
1566                              }
1567                              break;
1568  
1569                          default:
1570                              throw new moodle_exception('criteriaerror',
1571                                      'webservice', '', null,
1572                                      'You can not search on this criteria: ' . $key);
1573                      }
1574                  }
1575              }
1576  
1577              if (!empty($wheres)) {
1578                  $wheres = implode(" AND ", $wheres);
1579  
1580                  $categories = $DB->get_records_select('course_categories', $wheres, $conditions);
1581  
1582                  // Retrieve its sub subcategories (all levels).
1583                  if ($categories and !empty($params['addsubcategories'])) {
1584                      $newcategories = array();
1585  
1586                      // Check if we required visible/theme checks.
1587                      $additionalselect = '';
1588                      $additionalparams = array();
1589                      if (isset($conditions['visible'])) {
1590                          $additionalselect .= ' AND visible = :visible';
1591                          $additionalparams['visible'] = $conditions['visible'];
1592                      }
1593                      if (isset($conditions['theme'])) {
1594                          $additionalselect .= ' AND theme= :theme';
1595                          $additionalparams['theme'] = $conditions['theme'];
1596                      }
1597  
1598                      foreach ($categories as $category) {
1599                          $sqlselect = $DB->sql_like('path', ':path') . $additionalselect;
1600                          $sqlparams = array('path' => $category->path.'/%') + $additionalparams; // It will NOT include the specified category.
1601                          $subcategories = $DB->get_records_select('course_categories', $sqlselect, $sqlparams);
1602                          $newcategories = $newcategories + $subcategories;   // Both arrays have integer as keys.
1603                      }
1604                      $categories = $categories + $newcategories;
1605                  }
1606              }
1607  
1608          } else {
1609              // Retrieve all categories in the database.
1610              $categories = $DB->get_records('course_categories');
1611          }
1612  
1613          // The not returned categories. key => category id, value => reason of exclusion.
1614          $excludedcats = array();
1615  
1616          // The returned categories.
1617          $categoriesinfo = array();
1618  
1619          // We need to sort the categories by path.
1620          // The parent cats need to be checked by the algo first.
1621          usort($categories, "core_course_external::compare_categories_by_path");
1622  
1623          foreach ($categories as $category) {
1624  
1625              // Check if the category is a child of an excluded category, if yes exclude it too (excluded => do not return).
1626              $parents = explode('/', $category->path);
1627              unset($parents[0]); // First key is always empty because path start with / => /1/2/4.
1628              foreach ($parents as $parentid) {
1629                  // Note: when the parent exclusion was due to the context,
1630                  // the sub category could still be returned.
1631                  if (isset($excludedcats[$parentid]) and $excludedcats[$parentid] != 'context') {
1632                      $excludedcats[$category->id] = 'parent';
1633                  }
1634              }
1635  
1636              // Check category depth is <= maxdepth (do not check for user who can manage categories).
1637              if ((!empty($CFG->maxcategorydepth) && count($parents) > $CFG->maxcategorydepth)
1638                      and !has_capability('moodle/category:manage', $context)) {
1639                  $excludedcats[$category->id] = 'depth';
1640              }
1641  
1642              // Check the user can use the category context.
1643              $context = context_coursecat::instance($category->id);
1644              try {
1645                  self::validate_context($context);
1646              } catch (Exception $e) {
1647                  $excludedcats[$category->id] = 'context';
1648  
1649                  // If it was the requested category then throw an exception.
1650                  if (isset($params['categoryid']) && $category->id == $params['categoryid']) {
1651                      $exceptionparam = new stdClass();
1652                      $exceptionparam->message = $e->getMessage();
1653                      $exceptionparam->catid = $category->id;
1654                      throw new moodle_exception('errorcatcontextnotvalid', 'webservice', '', $exceptionparam);
1655                  }
1656              }
1657  
1658              // Return the category information.
1659              if (!isset($excludedcats[$category->id])) {
1660  
1661                  // Final check to see if the category is visible to the user.
1662                  if ($category->visible
1663                          or has_capability('moodle/category:viewhiddencategories', context_system::instance())
1664                          or has_capability('moodle/category:manage', $context)) {
1665  
1666                      $categoryinfo = array();
1667                      $categoryinfo['id'] = $category->id;
1668                      $categoryinfo['name'] = $category->name;
1669                      list($categoryinfo['description'], $categoryinfo['descriptionformat']) =
1670                          external_format_text($category->description, $category->descriptionformat,
1671                                  $context->id, 'coursecat', 'description', null);
1672                      $categoryinfo['parent'] = $category->parent;
1673                      $categoryinfo['sortorder'] = $category->sortorder;
1674                      $categoryinfo['coursecount'] = $category->coursecount;
1675                      $categoryinfo['depth'] = $category->depth;
1676                      $categoryinfo['path'] = $category->path;
1677  
1678                      // Some fields only returned for admin.
1679                      if (has_capability('moodle/category:manage', $context)) {
1680                          $categoryinfo['idnumber'] = $category->idnumber;
1681                          $categoryinfo['visible'] = $category->visible;
1682                          $categoryinfo['visibleold'] = $category->visibleold;
1683                          $categoryinfo['timemodified'] = $category->timemodified;
1684                          $categoryinfo['theme'] = $category->theme;
1685                      }
1686  
1687                      $categoriesinfo[] = $categoryinfo;
1688                  } else {
1689                      $excludedcats[$category->id] = 'visibility';
1690                  }
1691              }
1692          }
1693  
1694          // Sorting the resulting array so it looks a bit better for the client developer.
1695          usort($categoriesinfo, "core_course_external::compare_categories_by_sortorder");
1696  
1697          return $categoriesinfo;
1698      }
1699  
1700      /**
1701       * Sort categories array by path
1702       * private function: only used by get_categories
1703       *
1704       * @param array $category1
1705       * @param array $category2
1706       * @return int result of strcmp
1707       * @since Moodle 2.3
1708       */
1709      private static function compare_categories_by_path($category1, $category2) {
1710          return strcmp($category1->path, $category2->path);
1711      }
1712  
1713      /**
1714       * Sort categories array by sortorder
1715       * private function: only used by get_categories
1716       *
1717       * @param array $category1
1718       * @param array $category2
1719       * @return int result of strcmp
1720       * @since Moodle 2.3
1721       */
1722      private static function compare_categories_by_sortorder($category1, $category2) {
1723          return strcmp($category1['sortorder'], $category2['sortorder']);
1724      }
1725  
1726      /**
1727       * Returns description of method result value
1728       *
1729       * @return external_description
1730       * @since Moodle 2.3
1731       */
1732      public static function get_categories_returns() {
1733          return new external_multiple_structure(
1734              new external_single_structure(
1735                  array(
1736                      'id' => new external_value(PARAM_INT, 'category id'),
1737                      'name' => new external_value(PARAM_TEXT, 'category name'),
1738                      'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
1739                      'description' => new external_value(PARAM_RAW, 'category description'),
1740                      'descriptionformat' => new external_format_value('description'),
1741                      'parent' => new external_value(PARAM_INT, 'parent category id'),
1742                      'sortorder' => new external_value(PARAM_INT, 'category sorting order'),
1743                      'coursecount' => new external_value(PARAM_INT, 'number of courses in this category'),
1744                      'visible' => new external_value(PARAM_INT, '1: available, 0:not available', VALUE_OPTIONAL),
1745                      'visibleold' => new external_value(PARAM_INT, '1: available, 0:not available', VALUE_OPTIONAL),
1746                      'timemodified' => new external_value(PARAM_INT, 'timestamp', VALUE_OPTIONAL),
1747                      'depth' => new external_value(PARAM_INT, 'category depth'),
1748                      'path' => new external_value(PARAM_TEXT, 'category path'),
1749                      'theme' => new external_value(PARAM_THEME, 'category theme', VALUE_OPTIONAL),
1750                  ), 'List of categories'
1751              )
1752          );
1753      }
1754  
1755      /**
1756       * Returns description of method parameters
1757       *
1758       * @return external_function_parameters
1759       * @since Moodle 2.3
1760       */
1761      public static function create_categories_parameters() {
1762          return new external_function_parameters(
1763              array(
1764                  'categories' => new external_multiple_structure(
1765                          new external_single_structure(
1766                              array(
1767                                  'name' => new external_value(PARAM_TEXT, 'new category name'),
1768                                  'parent' => new external_value(PARAM_INT,
1769                                          'the parent category id inside which the new category will be created
1770                                           - set to 0 for a root category',
1771                                          VALUE_DEFAULT, 0),
1772                                  'idnumber' => new external_value(PARAM_RAW,
1773                                          'the new category idnumber', VALUE_OPTIONAL),
1774                                  'description' => new external_value(PARAM_RAW,
1775                                          'the new category description', VALUE_OPTIONAL),
1776                                  'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
1777                                  'theme' => new external_value(PARAM_THEME,
1778                                          'the new category theme. This option must be enabled on moodle',
1779                                          VALUE_OPTIONAL),
1780                          )
1781                      )
1782                  )
1783              )
1784          );
1785      }
1786  
1787      /**
1788       * Create categories
1789       *
1790       * @param array $categories - see create_categories_parameters() for the array structure
1791       * @return array - see create_categories_returns() for the array structure
1792       * @since Moodle 2.3
1793       */
1794      public static function create_categories($categories) {
1795          global $CFG, $DB;
1796          require_once($CFG->libdir . "/coursecatlib.php");
1797  
1798          $params = self::validate_parameters(self::create_categories_parameters(),
1799                          array('categories' => $categories));
1800  
1801          $transaction = $DB->start_delegated_transaction();
1802  
1803          $createdcategories = array();
1804          foreach ($params['categories'] as $category) {
1805              if ($category['parent']) {
1806                  if (!$DB->record_exists('course_categories', array('id' => $category['parent']))) {
1807                      throw new moodle_exception('unknowcategory');
1808                  }
1809                  $context = context_coursecat::instance($category['parent']);
1810              } else {
1811                  $context = context_system::instance();
1812              }
1813              self::validate_context($context);
1814              require_capability('moodle/category:manage', $context);
1815  
1816              // this will validate format and throw an exception if there are errors
1817              external_validate_format($category['descriptionformat']);
1818  
1819              $newcategory = coursecat::create($category);
1820  
1821              $createdcategories[] = array('id' => $newcategory->id, 'name' => $newcategory->name);
1822          }
1823  
1824          $transaction->allow_commit();
1825  
1826          return $createdcategories;
1827      }
1828  
1829      /**
1830       * Returns description of method parameters
1831       *
1832       * @return external_function_parameters
1833       * @since Moodle 2.3
1834       */
1835      public static function create_categories_returns() {
1836          return new external_multiple_structure(
1837              new external_single_structure(
1838                  array(
1839                      'id' => new external_value(PARAM_INT, 'new category id'),
1840                      'name' => new external_value(PARAM_TEXT, 'new category name'),
1841                  )
1842              )
1843          );
1844      }
1845  
1846      /**
1847       * Returns description of method parameters
1848       *
1849       * @return external_function_parameters
1850       * @since Moodle 2.3
1851       */
1852      public static function update_categories_parameters() {
1853          return new external_function_parameters(
1854              array(
1855                  'categories' => new external_multiple_structure(
1856                      new external_single_structure(
1857                          array(
1858                              'id'       => new external_value(PARAM_INT, 'course id'),
1859                              'name' => new external_value(PARAM_TEXT, 'category name', VALUE_OPTIONAL),
1860                              'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
1861                              'parent' => new external_value(PARAM_INT, 'parent category id', VALUE_OPTIONAL),
1862                              'description' => new external_value(PARAM_RAW, 'category description', VALUE_OPTIONAL),
1863                              'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
1864                              'theme' => new external_value(PARAM_THEME,
1865                                      'the category theme. This option must be enabled on moodle', VALUE_OPTIONAL),
1866                          )
1867                      )
1868                  )
1869              )
1870          );
1871      }
1872  
1873      /**
1874       * Update categories
1875       *
1876       * @param array $categories The list of categories to update
1877       * @return null
1878       * @since Moodle 2.3
1879       */
1880      public static function update_categories($categories) {
1881          global $CFG, $DB;
1882          require_once($CFG->libdir . "/coursecatlib.php");
1883  
1884          // Validate parameters.
1885          $params = self::validate_parameters(self::update_categories_parameters(), array('categories' => $categories));
1886  
1887          $transaction = $DB->start_delegated_transaction();
1888  
1889          foreach ($params['categories'] as $cat) {
1890              $category = coursecat::get($cat['id']);
1891  
1892              $categorycontext = context_coursecat::instance($cat['id']);
1893              self::validate_context($categorycontext);
1894              require_capability('moodle/category:manage', $categorycontext);
1895  
1896              // this will throw an exception if descriptionformat is not valid
1897              external_validate_format($cat['descriptionformat']);
1898  
1899              $category->update($cat);
1900          }
1901  
1902          $transaction->allow_commit();
1903      }
1904  
1905      /**
1906       * Returns description of method result value
1907       *
1908       * @return external_description
1909       * @since Moodle 2.3
1910       */
1911      public static function update_categories_returns() {
1912          return null;
1913      }
1914  
1915      /**
1916       * Returns description of method parameters
1917       *
1918       * @return external_function_parameters
1919       * @since Moodle 2.3
1920       */
1921      public static function delete_categories_parameters() {
1922          return new external_function_parameters(
1923              array(
1924                  'categories' => new external_multiple_structure(
1925                      new external_single_structure(
1926                          array(
1927                              'id' => new external_value(PARAM_INT, 'category id to delete'),
1928                              'newparent' => new external_value(PARAM_INT,
1929                                  'the parent category to move the contents to, if specified', VALUE_OPTIONAL),
1930                              'recursive' => new external_value(PARAM_BOOL, '1: recursively delete all contents inside this
1931                                  category, 0 (default): move contents to newparent or current parent category (except if parent is root)', VALUE_DEFAULT, 0)
1932                          )
1933                      )
1934                  )
1935              )
1936          );
1937      }
1938  
1939      /**
1940       * Delete categories
1941       *
1942       * @param array $categories A list of category ids
1943       * @return array
1944       * @since Moodle 2.3
1945       */
1946      public static function delete_categories($categories) {
1947          global $CFG, $DB;
1948          require_once($CFG->dirroot . "/course/lib.php");
1949          require_once($CFG->libdir . "/coursecatlib.php");
1950  
1951          // Validate parameters.
1952          $params = self::validate_parameters(self::delete_categories_parameters(), array('categories' => $categories));
1953  
1954          $transaction = $DB->start_delegated_transaction();
1955  
1956          foreach ($params['categories'] as $category) {
1957              $deletecat = coursecat::get($category['id'], MUST_EXIST);
1958              $context = context_coursecat::instance($deletecat->id);
1959              require_capability('moodle/category:manage', $context);
1960              self::validate_context($context);
1961              self::validate_context(get_category_or_system_context($deletecat->parent));
1962  
1963              if ($category['recursive']) {
1964                  // If recursive was specified, then we recursively delete the category's contents.
1965                  if ($deletecat->can_delete_full()) {
1966                      $deletecat->delete_full(false);
1967                  } else {
1968                      throw new moodle_exception('youcannotdeletecategory', '', '', $deletecat->get_formatted_name());
1969                  }
1970              } else {
1971                  // In this situation, we don't delete the category's contents, we either move it to newparent or parent.
1972                  // If the parent is the root, moving is not supported (because a course must always be inside a category).
1973                  // We must move to an existing category.
1974                  if (!empty($category['newparent'])) {
1975                      $newparentcat = coursecat::get($category['newparent']);
1976                  } else {
1977                      $newparentcat = coursecat::get($deletecat->parent);
1978                  }
1979  
1980                  // This operation is not allowed. We must move contents to an existing category.
1981                  if (!$newparentcat->id) {
1982                      throw new moodle_exception('movecatcontentstoroot');
1983                  }
1984  
1985                  self::validate_context(context_coursecat::instance($newparentcat->id));
1986                  if ($deletecat->can_move_content_to($newparentcat->id)) {
1987                      $deletecat->delete_move($newparentcat->id, false);
1988                  } else {
1989                      throw new moodle_exception('youcannotdeletecategory', '', '', $deletecat->get_formatted_name());
1990                  }
1991              }
1992          }
1993  
1994          $transaction->allow_commit();
1995      }
1996  
1997      /**
1998       * Returns description of method parameters
1999       *
2000       * @return external_function_parameters
2001       * @since Moodle 2.3
2002       */
2003      public static function delete_categories_returns() {
2004          return null;
2005      }
2006  
2007      /**
2008       * Describes the parameters for delete_modules.
2009       *
2010       * @return external_external_function_parameters
2011       * @since Moodle 2.5
2012       */
2013      public static function delete_modules_parameters() {
2014          return new external_function_parameters (
2015              array(
2016                  'cmids' => new external_multiple_structure(new external_value(PARAM_INT, 'course module ID',
2017                          VALUE_REQUIRED, '', NULL_NOT_ALLOWED), 'Array of course module IDs'),
2018              )
2019          );
2020      }
2021  
2022      /**
2023       * Deletes a list of provided module instances.
2024       *
2025       * @param array $cmids the course module ids
2026       * @since Moodle 2.5
2027       */
2028      public static function delete_modules($cmids) {
2029          global $CFG, $DB;
2030  
2031          // Require course file containing the course delete module function.
2032          require_once($CFG->dirroot . "/course/lib.php");
2033  
2034          // Clean the parameters.
2035          $params = self::validate_parameters(self::delete_modules_parameters(), array('cmids' => $cmids));
2036  
2037          // Keep track of the course ids we have performed a capability check on to avoid repeating.
2038          $arrcourseschecked = array();
2039  
2040          foreach ($params['cmids'] as $cmid) {
2041              // Get the course module.
2042              $cm = $DB->get_record('course_modules', array('id' => $cmid), '*', MUST_EXIST);
2043  
2044              // Check if we have not yet confirmed they have permission in this course.
2045              if (!in_array($cm->course, $arrcourseschecked)) {
2046                  // Ensure the current user has required permission in this course.
2047                  $context = context_course::instance($cm->course);
2048                  self::validate_context($context);
2049                  // Add to the array.
2050                  $arrcourseschecked[] = $cm->course;
2051              }
2052  
2053              // Ensure they can delete this module.
2054              $modcontext = context_module::instance($cm->id);
2055              require_capability('moodle/course:manageactivities', $modcontext);
2056  
2057              // Delete the module.
2058              course_delete_module($cm->id);
2059          }
2060      }
2061  
2062      /**
2063       * Describes the delete_modules return value.
2064       *
2065       * @return external_single_structure
2066       * @since Moodle 2.5
2067       */
2068      public static function delete_modules_returns() {
2069          return null;
2070      }
2071  
2072      /**
2073       * Returns description of method parameters
2074       *
2075       * @return external_function_parameters
2076       * @since Moodle 2.9
2077       */
2078      public static function view_course_parameters() {
2079          return new external_function_parameters(
2080              array(
2081                  'courseid' => new external_value(PARAM_INT, 'id of the course'),
2082                  'sectionnumber' => new external_value(PARAM_INT, 'section number', VALUE_DEFAULT, 0)
2083              )
2084          );
2085      }
2086  
2087      /**
2088       * Trigger the course viewed event.
2089       *
2090       * @param int $courseid id of course
2091       * @param int $sectionnumber sectionnumber (0, 1, 2...)
2092       * @return array of warnings and status result
2093       * @since Moodle 2.9
2094       * @throws moodle_exception
2095       */
2096      public static function view_course($courseid, $sectionnumber = 0) {
2097          global $CFG;
2098          require_once($CFG->dirroot . "/course/lib.php");
2099  
2100          $params = self::validate_parameters(self::view_course_parameters(),
2101                                              array(
2102                                                  'courseid' => $courseid,
2103                                                  'sectionnumber' => $sectionnumber
2104                                              ));
2105  
2106          $warnings = array();
2107  
2108          $course = get_course($params['courseid']);
2109          $context = context_course::instance($course->id);
2110          self::validate_context($context);
2111  
2112          if (!empty($params['sectionnumber'])) {
2113  
2114              // Get section details and check it exists.
2115              $modinfo = get_fast_modinfo($course);
2116              $coursesection = $modinfo->get_section_info($params['sectionnumber'], MUST_EXIST);
2117  
2118              // Check user is allowed to see it.
2119              if (!$coursesection->uservisible) {
2120                  require_capability('moodle/course:viewhiddensections', $context);
2121              }
2122          }
2123  
2124          course_view($context, $params['sectionnumber']);
2125  
2126          $result = array();
2127          $result['status'] = true;
2128          $result['warnings'] = $warnings;
2129          return $result;
2130      }
2131  
2132      /**
2133       * Returns description of method result value
2134       *
2135       * @return external_description
2136       * @since Moodle 2.9
2137       */
2138      public static function view_course_returns() {
2139          return new external_single_structure(
2140              array(
2141                  'status' => new external_value(PARAM_BOOL, 'status: true if success'),
2142                  'warnings' => new external_warnings()
2143              )
2144          );
2145      }
2146  
2147      /**
2148       * Returns description of method parameters
2149       *
2150       * @return external_function_parameters
2151       * @since Moodle 3.0
2152       */
2153      public static function search_courses_parameters() {
2154          return new external_function_parameters(
2155              array(
2156                  'criterianame'  => new external_value(PARAM_ALPHA, 'criteria name
2157                                                          (search, modulelist (only admins), blocklist (only admins), tagid)'),
2158                  'criteriavalue' => new external_value(PARAM_RAW, 'criteria value'),
2159                  'page'          => new external_value(PARAM_INT, 'page number (0 based)', VALUE_DEFAULT, 0),
2160                  'perpage'       => new external_value(PARAM_INT, 'items per page', VALUE_DEFAULT, 0),
2161                  'requiredcapabilities' => new external_multiple_structure(
2162                      new external_value(PARAM_CAPABILITY, 'Capability string used to filter courses by permission'),
2163                      'Optional list of required capabilities (used to filter the list)', VALUE_DEFAULT, array()
2164                  ),
2165                  'limittoenrolled' => new external_value(PARAM_BOOL, 'limit to enrolled courses', VALUE_DEFAULT, 0),
2166              )
2167          );
2168      }
2169  
2170      /**
2171       * Search courses following the specified criteria.
2172       *
2173       * @param string $criterianame  Criteria name (search, modulelist (only admins), blocklist (only admins), tagid)
2174       * @param string $criteriavalue Criteria value
2175       * @param int $page             Page number (for pagination)
2176       * @param int $perpage          Items per page
2177       * @param array $requiredcapabilities Optional list of required capabilities (used to filter the list).
2178       * @param int $limittoenrolled  Limit to only enrolled courses
2179       * @return array of course objects and warnings
2180       * @since Moodle 3.0
2181       * @throws moodle_exception
2182       */
2183      public static function search_courses($criterianame,
2184                                            $criteriavalue,
2185                                            $page=0,
2186                                            $perpage=0,
2187                                            $requiredcapabilities=array(),
2188                                            $limittoenrolled=0) {
2189          global $CFG;
2190          require_once($CFG->libdir . '/coursecatlib.php');
2191  
2192          $warnings = array();
2193  
2194          $parameters = array(
2195              'criterianame'  => $criterianame,
2196              'criteriavalue' => $criteriavalue,
2197              'page'          => $page,
2198              'perpage'       => $perpage,
2199              'requiredcapabilities' => $requiredcapabilities
2200          );
2201          $params = self::validate_parameters(self::search_courses_parameters(), $parameters);
2202          self::validate_context(context_system::instance());
2203  
2204          $allowedcriterianames = array('search', 'modulelist', 'blocklist', 'tagid');
2205          if (!in_array($params['criterianame'], $allowedcriterianames)) {
2206              throw new invalid_parameter_exception('Invalid value for criterianame parameter (value: '.$params['criterianame'].'),' .
2207                  'allowed values are: '.implode(',', $allowedcriterianames));
2208          }
2209  
2210          if ($params['criterianame'] == 'modulelist' or $params['criterianame'] == 'blocklist') {
2211              require_capability('moodle/site:config', context_system::instance());
2212          }
2213  
2214          $paramtype = array(
2215              'search' => PARAM_RAW,
2216              'modulelist' => PARAM_PLUGIN,
2217              'blocklist' => PARAM_INT,
2218              'tagid' => PARAM_INT
2219          );
2220          $params['criteriavalue'] = clean_param($params['criteriavalue'], $paramtype[$params['criterianame']]);
2221  
2222          // Prepare the search API options.
2223          $searchcriteria = array();
2224          $searchcriteria[$params['criterianame']] = $params['criteriavalue'];
2225  
2226          $options = array();
2227          if ($params['perpage'] != 0) {
2228              $offset = $params['page'] * $params['perpage'];
2229              $options = array('offset' => $offset, 'limit' => $params['perpage']);
2230          }
2231  
2232          // Search the courses.
2233          $courses = coursecat::search_courses($searchcriteria, $options, $params['requiredcapabilities']);
2234          $totalcount = coursecat::search_courses_count($searchcriteria, $options, $params['requiredcapabilities']);
2235  
2236          if (!empty($limittoenrolled)) {
2237              // Get the courses where the current user has access.
2238              $enrolled = enrol_get_my_courses(array('id', 'cacherev'));
2239          }
2240  
2241          $finalcourses = array();
2242          $categoriescache = array();
2243  
2244          foreach ($courses as $course) {
2245              if (!empty($limittoenrolled)) {
2246                  // Filter out not enrolled courses.
2247                  if (!isset($enrolled[$course->id])) {
2248                      $totalcount--;
2249                      continue;
2250                  }
2251              }
2252  
2253              $coursecontext = context_course::instance($course->id);
2254  
2255              // Category information.
2256              if (!isset($categoriescache[$course->category])) {
2257                  $categoriescache[$course->category] = coursecat::get($course->category);
2258              }
2259              $category = $categoriescache[$course->category];
2260  
2261              // Retrieve course overfiew used files.
2262              $files = array();
2263              foreach ($course->get_course_overviewfiles() as $file) {
2264                  $fileurl = moodle_url::make_webservice_pluginfile_url($file->get_contextid(), $file->get_component(),
2265                                                                          $file->get_filearea(), null, $file->get_filepath(),
2266                                                                          $file->get_filename())->out(false);
2267                  $files[] = array(
2268                      'filename' => $file->get_filename(),
2269                      'fileurl' => $fileurl,
2270                      'filesize' => $file->get_filesize(),
2271                      'filepath' => $file->get_filepath(),
2272                      'mimetype' => $file->get_mimetype(),
2273                      'timemodified' => $file->get_timemodified(),
2274                  );
2275              }
2276  
2277              // Retrieve the course contacts,
2278              // we need here the users fullname since if we are not enrolled can be difficult to obtain them via other Web Services.
2279              $coursecontacts = array();
2280              foreach ($course->get_course_contacts() as $contact) {
2281                   $coursecontacts[] = array(
2282                      'id' => $contact['user']->id,
2283                      'fullname' => $contact['username']
2284                  );
2285              }
2286  
2287              // Allowed enrolment methods (maybe we can self-enrol).
2288              $enroltypes = array();
2289              $instances = enrol_get_instances($course->id, true);
2290              foreach ($instances as $instance) {
2291                  $enroltypes[] = $instance->enrol;
2292              }
2293  
2294              // Format summary.
2295              list($summary, $summaryformat) =
2296                  external_format_text($course->summary, $course->summaryformat, $coursecontext->id, 'course', 'summary', null);
2297  
2298              $displayname = get_course_display_name_for_list($course);
2299              $coursereturns = array();
2300              $coursereturns['id']                = $course->id;
2301              $coursereturns['fullname']          = external_format_string($course->fullname, $coursecontext->id);
2302              $coursereturns['displayname']       = external_format_string($displayname, $coursecontext->id);
2303              $coursereturns['shortname']         = external_format_string($course->shortname, $coursecontext->id);
2304              $coursereturns['categoryid']        = $course->category;
2305              $coursereturns['categoryname']      = $category->name;
2306              $coursereturns['summary']           = $summary;
2307              $coursereturns['summaryformat']     = $summaryformat;
2308              $coursereturns['overviewfiles']     = $files;
2309              $coursereturns['contacts']          = $coursecontacts;
2310              $coursereturns['enrollmentmethods'] = $enroltypes;
2311              $finalcourses[] = $coursereturns;
2312          }
2313  
2314          return array(
2315              'total' => $totalcount,
2316              'courses' => $finalcourses,
2317              'warnings' => $warnings
2318          );
2319      }
2320  
2321      /**
2322       * Returns description of method result value
2323       *
2324       * @return external_description
2325       * @since Moodle 3.0
2326       */
2327      public static function search_courses_returns() {
2328  
2329          return new external_single_structure(
2330              array(
2331                  'total' => new external_value(PARAM_INT, 'total course count'),
2332                  'courses' => new external_multiple_structure(
2333                      new external_single_structure(
2334                          array(
2335                              'id' => new external_value(PARAM_INT, 'course id'),
2336                              'fullname' => new external_value(PARAM_TEXT, 'course full name'),
2337                              'displayname' => new external_value(PARAM_TEXT, 'course display name'),
2338                              'shortname' => new external_value(PARAM_TEXT, 'course short name'),
2339                              'categoryid' => new external_value(PARAM_INT, 'category id'),
2340                              'categoryname' => new external_value(PARAM_TEXT, 'category name'),
2341                              'summary' => new external_value(PARAM_RAW, 'summary'),
2342                              'summaryformat' => new external_format_value('summary'),
2343                              'overviewfiles' => new external_files('additional overview files attached to this course'),
2344                              'contacts' => new external_multiple_structure(
2345                                  new external_single_structure(
2346                                      array(
2347                                          'id' => new external_value(PARAM_INT, 'contact user id'),
2348                                          'fullname'  => new external_value(PARAM_NOTAGS, 'contact user fullname'),
2349                                      )
2350                                  ),
2351                                  'contact users'
2352                              ),
2353                              'enrollmentmethods' => new external_multiple_structure(
2354                                  new external_value(PARAM_PLUGIN, 'enrollment method'),
2355                                  'enrollment methods list'
2356                              ),
2357                          )
2358                      ), 'course'
2359                  ),
2360                  'warnings' => new external_warnings()
2361              )
2362          );
2363      }
2364  
2365      /**
2366       * Returns description of method parameters
2367       *
2368       * @return external_function_parameters
2369       * @since Moodle 3.0
2370       */
2371      public static function get_course_module_parameters() {
2372          return new external_function_parameters(
2373              array(
2374                  'cmid' => new external_value(PARAM_INT, 'The course module id')
2375              )
2376          );
2377      }
2378  
2379      /**
2380       * Return information about a course module.
2381       *
2382       * @param int $cmid the course module id
2383       * @return array of warnings and the course module
2384       * @since Moodle 3.0
2385       * @throws moodle_exception
2386       */
2387      public static function get_course_module($cmid) {
2388  
2389          $params = self::validate_parameters(self::get_course_module_parameters(),
2390                                              array(
2391                                                  'cmid' => $cmid,
2392                                              ));
2393  
2394          $warnings = array();
2395  
2396          $cm = get_coursemodule_from_id(null, $params['cmid'], 0, true, MUST_EXIST);
2397          $context = context_module::instance($cm->id);
2398          self::validate_context($context);
2399  
2400          // If the user has permissions to manage the activity, return all the information.
2401          if (has_capability('moodle/course:manageactivities', $context)) {
2402              $info = $cm;
2403          } else {
2404              // Return information is safe to show to any user.
2405              $info = new stdClass();
2406              $info->id = $cm->id;
2407              $info->course = $cm->course;
2408              $info->module = $cm->module;
2409              $info->modname = $cm->modname;
2410              $info->instance = $cm->instance;
2411              $info->section = $cm->section;
2412              $info->sectionnum = $cm->sectionnum;
2413              $info->groupmode = $cm->groupmode;
2414              $info->groupingid = $cm->groupingid;
2415              $info->completion = $cm->completion;
2416          }
2417          // Format name.
2418          $info->name = external_format_string($cm->name, $context->id);
2419  
2420          $result = array();
2421          $result['cm'] = $info;
2422          $result['warnings'] = $warnings;
2423          return $result;
2424      }
2425  
2426      /**
2427       * Returns description of method result value
2428       *
2429       * @return external_description
2430       * @since Moodle 3.0
2431       */
2432      public static function get_course_module_returns() {
2433          return new external_single_structure(
2434              array(
2435                  'cm' => new external_single_structure(
2436                      array(
2437                          'id' => new external_value(PARAM_INT, 'The course module id'),
2438                          'course' => new external_value(PARAM_INT, 'The course id'),
2439                          'module' => new external_value(PARAM_INT, 'The module type id'),
2440                          'name' => new external_value(PARAM_RAW, 'The activity name'),
2441                          'modname' => new external_value(PARAM_COMPONENT, 'The module component name (forum, assign, etc..)'),
2442                          'instance' => new external_value(PARAM_INT, 'The activity instance id'),
2443                          'section' => new external_value(PARAM_INT, 'The module section id'),
2444                          'sectionnum' => new external_value(PARAM_INT, 'The module section number'),
2445                          'groupmode' => new external_value(PARAM_INT, 'Group mode'),
2446                          'groupingid' => new external_value(PARAM_INT, 'Grouping id'),
2447                          'completion' => new external_value(PARAM_INT, 'If completion is enabled'),
2448                          'idnumber' => new external_value(PARAM_RAW, 'Module id number', VALUE_OPTIONAL),
2449                          'added' => new external_value(PARAM_INT, 'Time added', VALUE_OPTIONAL),
2450                          'score' => new external_value(PARAM_INT, 'Score', VALUE_OPTIONAL),
2451                          'indent' => new external_value(PARAM_INT, 'Indentation', VALUE_OPTIONAL),
2452                          'visible' => new external_value(PARAM_INT, 'If visible', VALUE_OPTIONAL),
2453                          'visibleold' => new external_value(PARAM_INT, 'Visible old', VALUE_OPTIONAL),
2454                          'completiongradeitemnumber' => new external_value(PARAM_INT, 'Completion grade item', VALUE_OPTIONAL),
2455                          'completionview' => new external_value(PARAM_INT, 'Completion view setting', VALUE_OPTIONAL),
2456                          'completionexpected' => new external_value(PARAM_INT, 'Completion time expected', VALUE_OPTIONAL),
2457                          'showdescription' => new external_value(PARAM_INT, 'If the description is showed', VALUE_OPTIONAL),
2458                          'availability' => new external_value(PARAM_RAW, 'Availability settings', VALUE_OPTIONAL),
2459                      )
2460                  ),
2461                  'warnings' => new external_warnings()
2462              )
2463          );
2464      }
2465  
2466      /**
2467       * Returns description of method parameters
2468       *
2469       * @return external_function_parameters
2470       * @since Moodle 3.0
2471       */
2472      public static function get_course_module_by_instance_parameters() {
2473          return new external_function_parameters(
2474              array(
2475                  'module' => new external_value(PARAM_COMPONENT, 'The module name'),
2476                  'instance' => new external_value(PARAM_INT, 'The module instance id')
2477              )
2478          );
2479      }
2480  
2481      /**
2482       * Return information about a course module.
2483       *
2484       * @param string $module the module name
2485       * @param int $instance the activity instance id
2486       * @return array of warnings and the course module
2487       * @since Moodle 3.0
2488       * @throws moodle_exception
2489       */
2490      public static function get_course_module_by_instance($module, $instance) {
2491  
2492          $params = self::validate_parameters(self::get_course_module_by_instance_parameters(),
2493                                              array(
2494                                                  'module' => $module,
2495                                                  'instance' => $instance,
2496                                              ));
2497  
2498          $warnings = array();
2499          $cm = get_coursemodule_from_instance($params['module'], $params['instance'], 0, false, MUST_EXIST);
2500  
2501          return self::get_course_module($cm->id);
2502      }
2503  
2504      /**
2505       * Returns description of method result value
2506       *
2507       * @return external_description
2508       * @since Moodle 3.0
2509       */
2510      public static function get_course_module_by_instance_returns() {
2511          return self::get_course_module_returns();
2512      }
2513  
2514      /**
2515       * Returns description of method parameters
2516       *
2517       * @return external_function_parameters
2518       * @since Moodle 3.2
2519       */
2520      public static function get_activities_overview_parameters() {
2521          return new external_function_parameters(
2522              array(
2523                  'courseids' => new external_multiple_structure(new external_value(PARAM_INT, 'Course id.')),
2524              )
2525          );
2526      }
2527  
2528      /**
2529       * Return activities overview for the given courses.
2530       *
2531       * @param array $courseids a list of course ids
2532       * @return array of warnings and the activities overview
2533       * @since Moodle 3.2
2534       * @throws moodle_exception
2535       */
2536      public static function get_activities_overview($courseids) {
2537          global $USER;
2538  
2539          // Parameter validation.
2540          $params = self::validate_parameters(self::get_activities_overview_parameters(), array('courseids' => $courseids));
2541          $courseoverviews = array();
2542  
2543          list($courses, $warnings) = external_util::validate_courses($params['courseids']);
2544  
2545          if (!empty($courses)) {
2546              // Add lastaccess to each course (required by print_overview function).
2547              // We need the complete user data, the ws server does not load a complete one.
2548              $user = get_complete_user_data('id', $USER->id);
2549              foreach ($courses as $course) {
2550                  if (isset($user->lastcourseaccess[$course->id])) {
2551                      $course->lastaccess = $user->lastcourseaccess[$course->id];
2552                  } else {
2553                      $course->lastaccess = 0;
2554                  }
2555              }
2556  
2557              $overviews = array();
2558              if ($modules = get_plugin_list_with_function('mod', 'print_overview')) {
2559                  foreach ($modules as $fname) {
2560                      $fname($courses, $overviews);
2561                  }
2562              }
2563  
2564              // Format output.
2565              foreach ($overviews as $courseid => $modules) {
2566                  $courseoverviews[$courseid]['id'] = $courseid;
2567                  $courseoverviews[$courseid]['overviews'] = array();
2568  
2569                  foreach ($modules as $modname => $overviewtext) {
2570                      $courseoverviews[$courseid]['overviews'][] = array(
2571                          'module' => $modname,
2572                          'overviewtext' => $overviewtext // This text doesn't need formatting.
2573                      );
2574                  }
2575              }
2576          }
2577  
2578          $result = array(
2579              'courses' => $courseoverviews,
2580              'warnings' => $warnings
2581          );
2582          return $result;
2583      }
2584  
2585      /**
2586       * Returns description of method result value
2587       *
2588       * @return external_description
2589       * @since Moodle 3.2
2590       */
2591      public static function get_activities_overview_returns() {
2592          return new external_single_structure(
2593              array(
2594                  'courses' => new external_multiple_structure(
2595                      new external_single_structure(
2596                          array(
2597                              'id' => new external_value(PARAM_INT, 'Course id'),
2598                              'overviews' => new external_multiple_structure(
2599                                  new external_single_structure(
2600                                      array(
2601                                          'module' => new external_value(PARAM_PLUGIN, 'Module name'),
2602                                          'overviewtext' => new external_value(PARAM_RAW, 'Overview text'),
2603                                      )
2604                                  )
2605                              )
2606                          )
2607                      ), 'List of courses'
2608                  ),
2609                  'warnings' => new external_warnings()
2610              )
2611          );
2612      }
2613  
2614  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1