Search moodle.org's
Developer Documentation

   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.2
  47       */
  48      public static function get_course_contents_parameters() {
  49          return new external_function_parameters(
  50                  array('courseid' => new external_value(PARAM_INT, 'course id'),
  51                        'options' => new external_multiple_structure (
  52                                new external_single_structure(
  53                                      array('name' => new external_value(PARAM_ALPHANUM, 'option name'),
  54                                            'value' => new external_value(PARAM_RAW, 'the value of the option, this param is personaly validated in the external function.')
  55                                )
  56                        ), 'Options, not used yet, might be used in later version', VALUE_DEFAULT, array())
  57                  )
  58          );
  59      }
  60  
  61      /**
  62       * Get course contents
  63       *
  64       * @param int $courseid course id
  65       * @param array $options These options are not used yet, might be used in later version
  66       * @return array
  67       * @since Moodle 2.2
  68       */
  69      public static function get_course_contents($courseid, $options = array()) {
  70          global $CFG, $DB;
  71          require_once($CFG->dirroot . "/course/lib.php");
  72  
  73          //validate parameter
  74          $params = self::validate_parameters(self::get_course_contents_parameters(),
  75                          array('courseid' => $courseid, 'options' => $options));
  76  
  77          //retrieve the course
  78          $course = $DB->get_record('course', array('id' => $params['courseid']), '*', MUST_EXIST);
  79  
  80          if ($course->id != SITEID) {
  81              // Check course format exist.
  82              if (!file_exists($CFG->dirroot . '/course/format/' . $course->format . '/lib.php')) {
  83                  throw new moodle_exception('cannotgetcoursecontents', 'webservice', '', null,
  84                                              get_string('courseformatnotfound', 'error', $course->format));
  85              } else {
  86                  require_once($CFG->dirroot . '/course/format/' . $course->format . '/lib.php');
  87              }
  88          }
  89  
  90          // now security checks
  91          $context = context_course::instance($course->id, IGNORE_MISSING);
  92          try {
  93              self::validate_context($context);
  94          } catch (Exception $e) {
  95              $exceptionparam = new stdClass();
  96              $exceptionparam->message = $e->getMessage();
  97              $exceptionparam->courseid = $course->id;
  98              throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
  99          }
 100  
 101          $canupdatecourse = has_capability('moodle/course:update', $context);
 102  
 103          //create return value
 104          $coursecontents = array();
 105  
 106          if ($canupdatecourse or $course->visible
 107                  or has_capability('moodle/course:viewhiddencourses', $context)) {
 108  
 109              //retrieve sections
 110              $modinfo = get_fast_modinfo($course);
 111              $sections = $modinfo->get_section_info_all();
 112  
 113              //for each sections (first displayed to last displayed)
 114              $modinfosections = $modinfo->get_sections();
 115              foreach ($sections as $key => $section) {
 116  
 117                  if (!$section->uservisible) {
 118                      continue;
 119                  }
 120  
 121                  // reset $sectioncontents
 122                  $sectionvalues = array();
 123                  $sectionvalues['id'] = $section->id;
 124                  $sectionvalues['name'] = get_section_name($course, $section);
 125                  $sectionvalues['visible'] = $section->visible;
 126                  list($sectionvalues['summary'], $sectionvalues['summaryformat']) =
 127                          external_format_text($section->summary, $section->summaryformat,
 128                                  $context->id, 'course', 'section', $section->id);
 129                  $sectioncontents = array();
 130  
 131                  //for each module of the section
 132                  if (!empty($modinfosections[$section->section])) {
 133                      foreach ($modinfosections[$section->section] as $cmid) {
 134                          $cm = $modinfo->cms[$cmid];
 135  
 136                          // stop here if the module is not visible to the user
 137                          if (!$cm->uservisible) {
 138                              continue;
 139                          }
 140  
 141                          $module = array();
 142  
 143                          //common info (for people being able to see the module or availability dates)
 144                          $module['id'] = $cm->id;
 145                          $module['name'] = format_string($cm->name, true);
 146                          $module['instance'] = $cm->instance;
 147                          $module['modname'] = $cm->modname;
 148                          $module['modplural'] = $cm->modplural;
 149                          $module['modicon'] = $cm->get_icon_url()->out(false);
 150                          $module['indent'] = $cm->indent;
 151  
 152                          $modcontext = context_module::instance($cm->id);
 153  
 154                          if (!empty($cm->showdescription) or $cm->modname == 'label') {
 155                              // We want to use the external format. However from reading get_formatted_content(), $cm->content format is always FORMAT_HTML.
 156                              list($module['description'], $descriptionformat) = external_format_text($cm->content,
 157                                  FORMAT_HTML, $modcontext->id, $cm->modname, 'intro', $cm->id);
 158                          }
 159  
 160                          //url of the module
 161                          $url = $cm->url;
 162                          if ($url) { //labels don't have url
 163                              $module['url'] = $url->out(false);
 164                          }
 165  
 166                          $canviewhidden = has_capability('moodle/course:viewhiddenactivities',
 167                                              context_module::instance($cm->id));
 168                          //user that can view hidden module should know about the visibility
 169                          $module['visible'] = $cm->visible;
 170  
 171                          // Availability date (also send to user who can see hidden module).
 172                          if ($CFG->enableavailability && ($canviewhidden || $canupdatecourse)) {
 173                              $module['availability'] = $cm->availability;
 174                          }
 175  
 176                          $baseurl = 'webservice/pluginfile.php';
 177  
 178                          //call $modulename_export_contents
 179                          //(each module callback take care about checking the capabilities)
 180                          require_once($CFG->dirroot . '/mod/' . $cm->modname . '/lib.php');
 181                          $getcontentfunction = $cm->modname.'_export_contents';
 182                          if (function_exists($getcontentfunction)) {
 183                              if ($contents = $getcontentfunction($cm, $baseurl)) {
 184                                  $module['contents'] = $contents;
 185                              }
 186                          }
 187  
 188                          //assign result to $sectioncontents
 189                          $sectioncontents[] = $module;
 190  
 191                      }
 192                  }
 193                  $sectionvalues['modules'] = $sectioncontents;
 194  
 195                  // assign result to $coursecontents
 196                  $coursecontents[] = $sectionvalues;
 197              }
 198          }
 199          return $coursecontents;
 200      }
 201  
 202      /**
 203       * Returns description of method result value
 204       *
 205       * @return external_description
 206       * @since Moodle 2.2
 207       */
 208      public static function get_course_contents_returns() {
 209          return new external_multiple_structure(
 210              new external_single_structure(
 211                  array(
 212                      'id' => new external_value(PARAM_INT, 'Section ID'),
 213                      'name' => new external_value(PARAM_TEXT, 'Section name'),
 214                      'visible' => new external_value(PARAM_INT, 'is the section visible', VALUE_OPTIONAL),
 215                      'summary' => new external_value(PARAM_RAW, 'Section description'),
 216                      'summaryformat' => new external_format_value('summary'),
 217                      'modules' => new external_multiple_structure(
 218                              new external_single_structure(
 219                                  array(
 220                                      'id' => new external_value(PARAM_INT, 'activity id'),
 221                                      'url' => new external_value(PARAM_URL, 'activity url', VALUE_OPTIONAL),
 222                                      'name' => new external_value(PARAM_RAW, 'activity module name'),
 223                                      'instance' => new external_value(PARAM_INT, 'instance id', VALUE_OPTIONAL),
 224                                      'description' => new external_value(PARAM_RAW, 'activity description', VALUE_OPTIONAL),
 225                                      'visible' => new external_value(PARAM_INT, 'is the module visible', VALUE_OPTIONAL),
 226                                      'modicon' => new external_value(PARAM_URL, 'activity icon url'),
 227                                      'modname' => new external_value(PARAM_PLUGIN, 'activity module type'),
 228                                      'modplural' => new external_value(PARAM_TEXT, 'activity module plural name'),
 229                                      'availability' => new external_value(PARAM_RAW, 'module availability settings', VALUE_OPTIONAL),
 230                                      'indent' => new external_value(PARAM_INT, 'number of identation in the site'),
 231                                      'contents' => new external_multiple_structure(
 232                                            new external_single_structure(
 233                                                array(
 234                                                    // content info
 235                                                    'type'=> new external_value(PARAM_TEXT, 'a file or a folder or external link'),
 236                                                    'filename'=> new external_value(PARAM_FILE, 'filename'),
 237                                                    'filepath'=> new external_value(PARAM_PATH, 'filepath'),
 238                                                    'filesize'=> new external_value(PARAM_INT, 'filesize'),
 239                                                    'fileurl' => new external_value(PARAM_URL, 'downloadable file url', VALUE_OPTIONAL),
 240                                                    'content' => new external_value(PARAM_RAW, 'Raw content, will be used when type is content', VALUE_OPTIONAL),
 241                                                    'timecreated' => new external_value(PARAM_INT, 'Time created'),
 242                                                    'timemodified' => new external_value(PARAM_INT, 'Time modified'),
 243                                                    'sortorder' => new external_value(PARAM_INT, 'Content sort order'),
 244  
 245                                                    // copyright related info
 246                                                    'userid' => new external_value(PARAM_INT, 'User who added this content to moodle'),
 247                                                    'author' => new external_value(PARAM_TEXT, 'Content owner'),
 248                                                    'license' => new external_value(PARAM_TEXT, 'Content license'),
 249                                                )
 250                                            ), VALUE_DEFAULT, array()
 251                                        )
 252                                  )
 253                              ), 'list of module'
 254                      )
 255                  )
 256              )
 257          );
 258      }
 259  
 260      /**
 261       * Returns description of method parameters
 262       *
 263       * @return external_function_parameters
 264       * @since Moodle 2.3
 265       */
 266      public static function get_courses_parameters() {
 267          return new external_function_parameters(
 268                  array('options' => new external_single_structure(
 269                              array('ids' => new external_multiple_structure(
 270                                          new external_value(PARAM_INT, 'Course id')
 271                                          , 'List of course id. If empty return all courses
 272                                              except front page course.',
 273                                          VALUE_OPTIONAL)
 274                              ), 'options - operator OR is used', VALUE_DEFAULT, array())
 275                  )
 276          );
 277      }
 278  
 279      /**
 280       * Get courses
 281       *
 282       * @param array $options It contains an array (list of ids)
 283       * @return array
 284       * @since Moodle 2.2
 285       */
 286      public static function get_courses($options = array()) {
 287          global $CFG, $DB;
 288          require_once($CFG->dirroot . "/course/lib.php");
 289  
 290          //validate parameter
 291          $params = self::validate_parameters(self::get_courses_parameters(),
 292                          array('options' => $options));
 293  
 294          //retrieve courses
 295          if (!array_key_exists('ids', $params['options'])
 296                  or empty($params['options']['ids'])) {
 297              $courses = $DB->get_records('course');
 298          } else {
 299              $courses = $DB->get_records_list('course', 'id', $params['options']['ids']);
 300          }
 301  
 302          //create return value
 303          $coursesinfo = array();
 304          foreach ($courses as $course) {
 305  
 306              // now security checks
 307              $context = context_course::instance($course->id, IGNORE_MISSING);
 308              $courseformatoptions = course_get_format($course)->get_format_options();
 309              try {
 310                  self::validate_context($context);
 311              } catch (Exception $e) {
 312                  $exceptionparam = new stdClass();
 313                  $exceptionparam->message = $e->getMessage();
 314                  $exceptionparam->courseid = $course->id;
 315                  throw new moodle_exception('errorcoursecontextnotvalid', 'webservice', '', $exceptionparam);
 316              }
 317              require_capability('moodle/course:view', $context);
 318  
 319              $courseinfo = array();
 320              $courseinfo['id'] = $course->id;
 321              $courseinfo['fullname'] = $course->fullname;
 322              $courseinfo['shortname'] = $course->shortname;
 323              $courseinfo['categoryid'] = $course->category;
 324              list($courseinfo['summary'], $courseinfo['summaryformat']) =
 325                  external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', 0);
 326              $courseinfo['format'] = $course->format;
 327              $courseinfo['startdate'] = $course->startdate;
 328              if (array_key_exists('numsections', $courseformatoptions)) {
 329                  // For backward-compartibility
 330                  $courseinfo['numsections'] = $courseformatoptions['numsections'];
 331              }
 332  
 333              //some field should be returned only if the user has update permission
 334              $courseadmin = has_capability('moodle/course:update', $context);
 335              if ($courseadmin) {
 336                  $courseinfo['categorysortorder'] = $course->sortorder;
 337                  $courseinfo['idnumber'] = $course->idnumber;
 338                  $courseinfo['showgrades'] = $course->showgrades;
 339                  $courseinfo['showreports'] = $course->showreports;
 340                  $courseinfo['newsitems'] = $course->newsitems;
 341                  $courseinfo['visible'] = $course->visible;
 342                  $courseinfo['maxbytes'] = $course->maxbytes;
 343                  if (array_key_exists('hiddensections', $courseformatoptions)) {
 344                      // For backward-compartibility
 345                      $courseinfo['hiddensections'] = $courseformatoptions['hiddensections'];
 346                  }
 347                  $courseinfo['groupmode'] = $course->groupmode;
 348                  $courseinfo['groupmodeforce'] = $course->groupmodeforce;
 349                  $courseinfo['defaultgroupingid'] = $course->defaultgroupingid;
 350                  $courseinfo['lang'] = $course->lang;
 351                  $courseinfo['timecreated'] = $course->timecreated;
 352                  $courseinfo['timemodified'] = $course->timemodified;
 353                  $courseinfo['forcetheme'] = $course->theme;
 354                  $courseinfo['enablecompletion'] = $course->enablecompletion;
 355                  $courseinfo['completionnotify'] = $course->completionnotify;
 356                  $courseinfo['courseformatoptions'] = array();
 357                  foreach ($courseformatoptions as $key => $value) {
 358                      $courseinfo['courseformatoptions'][] = array(
 359                          'name' => $key,
 360                          'value' => $value
 361                      );
 362                  }
 363              }
 364  
 365              if ($courseadmin or $course->visible
 366                      or has_capability('moodle/course:viewhiddencourses', $context)) {
 367                  $coursesinfo[] = $courseinfo;
 368              }
 369          }
 370  
 371          return $coursesinfo;
 372      }
 373  
 374      /**
 375       * Returns description of method result value
 376       *
 377       * @return external_description
 378       * @since Moodle 2.2
 379       */
 380      public static function get_courses_returns() {
 381          return new external_multiple_structure(
 382                  new external_single_structure(
 383                          array(
 384                              'id' => new external_value(PARAM_INT, 'course id'),
 385                              'shortname' => new external_value(PARAM_TEXT, 'course short name'),
 386                              'categoryid' => new external_value(PARAM_INT, 'category id'),
 387                              'categorysortorder' => new external_value(PARAM_INT,
 388                                      'sort order into the category', VALUE_OPTIONAL),
 389                              'fullname' => new external_value(PARAM_TEXT, 'full name'),
 390                              'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
 391                              'summary' => new external_value(PARAM_RAW, 'summary'),
 392                              'summaryformat' => new external_format_value('summary'),
 393                              'format' => new external_value(PARAM_PLUGIN,
 394                                      'course format: weeks, topics, social, site,..'),
 395                              'showgrades' => new external_value(PARAM_INT,
 396                                      '1 if grades are shown, otherwise 0', VALUE_OPTIONAL),
 397                              'newsitems' => new external_value(PARAM_INT,
 398                                      'number of recent items appearing on the course page', VALUE_OPTIONAL),
 399                              'startdate' => new external_value(PARAM_INT,
 400                                      'timestamp when the course start'),
 401                              'numsections' => new external_value(PARAM_INT,
 402                                      '(deprecated, use courseformatoptions) number of weeks/topics',
 403                                      VALUE_OPTIONAL),
 404                              'maxbytes' => new external_value(PARAM_INT,
 405                                      'largest size of file that can be uploaded into the course',
 406                                      VALUE_OPTIONAL),
 407                              'showreports' => new external_value(PARAM_INT,
 408                                      'are activity report shown (yes = 1, no =0)', VALUE_OPTIONAL),
 409                              'visible' => new external_value(PARAM_INT,
 410                                      '1: available to student, 0:not available', VALUE_OPTIONAL),
 411                              'hiddensections' => new external_value(PARAM_INT,
 412                                      '(deprecated, use courseformatoptions) How the hidden sections in the course are displayed to students',
 413                                      VALUE_OPTIONAL),
 414                              'groupmode' => new external_value(PARAM_INT, 'no group, separate, visible',
 415                                      VALUE_OPTIONAL),
 416                              'groupmodeforce' => new external_value(PARAM_INT, '1: yes, 0: no',
 417                                      VALUE_OPTIONAL),
 418                              'defaultgroupingid' => new external_value(PARAM_INT, 'default grouping id',
 419                                      VALUE_OPTIONAL),
 420                              'timecreated' => new external_value(PARAM_INT,
 421                                      'timestamp when the course have been created', VALUE_OPTIONAL),
 422                              'timemodified' => new external_value(PARAM_INT,
 423                                      'timestamp when the course have been modified', VALUE_OPTIONAL),
 424                              'enablecompletion' => new external_value(PARAM_INT,
 425                                      'Enabled, control via completion and activity settings. Disbaled,
 426                                          not shown in activity settings.',
 427                                      VALUE_OPTIONAL),
 428                              'completionnotify' => new external_value(PARAM_INT,
 429                                      '1: yes 0: no', VALUE_OPTIONAL),
 430                              'lang' => new external_value(PARAM_SAFEDIR,
 431                                      'forced course language', VALUE_OPTIONAL),
 432                              'forcetheme' => new external_value(PARAM_PLUGIN,
 433                                      'name of the force theme', VALUE_OPTIONAL),
 434                              'courseformatoptions' => new external_multiple_structure(
 435                                  new external_single_structure(
 436                                      array('name' => new external_value(PARAM_ALPHANUMEXT, 'course format option name'),
 437                                          'value' => new external_value(PARAM_RAW, 'course format option value')
 438                                  )),
 439                                      'additional options for particular course format', VALUE_OPTIONAL
 440                               ),
 441                          ), 'course'
 442                  )
 443          );
 444      }
 445  
 446      /**
 447       * Returns description of method parameters
 448       *
 449       * @return external_function_parameters
 450       * @since Moodle 2.2
 451       */
 452      public static function create_courses_parameters() {
 453          $courseconfig = get_config('moodlecourse'); //needed for many default values
 454          return new external_function_parameters(
 455              array(
 456                  'courses' => new external_multiple_structure(
 457                      new external_single_structure(
 458                          array(
 459                              'fullname' => new external_value(PARAM_TEXT, 'full name'),
 460                              'shortname' => new external_value(PARAM_TEXT, 'course short name'),
 461                              'categoryid' => new external_value(PARAM_INT, 'category id'),
 462                              'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
 463                              'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL),
 464                              'summaryformat' => new external_format_value('summary', VALUE_DEFAULT),
 465                              'format' => new external_value(PARAM_PLUGIN,
 466                                      'course format: weeks, topics, social, site,..',
 467                                      VALUE_DEFAULT, $courseconfig->format),
 468                              'showgrades' => new external_value(PARAM_INT,
 469                                      '1 if grades are shown, otherwise 0', VALUE_DEFAULT,
 470                                      $courseconfig->showgrades),
 471                              'newsitems' => new external_value(PARAM_INT,
 472                                      'number of recent items appearing on the course page',
 473                                      VALUE_DEFAULT, $courseconfig->newsitems),
 474                              'startdate' => new external_value(PARAM_INT,
 475                                      'timestamp when the course start', VALUE_OPTIONAL),
 476                              'numsections' => new external_value(PARAM_INT,
 477                                      '(deprecated, use courseformatoptions) number of weeks/topics',
 478                                      VALUE_OPTIONAL),
 479                              'maxbytes' => new external_value(PARAM_INT,
 480                                      'largest size of file that can be uploaded into the course',
 481                                      VALUE_DEFAULT, $courseconfig->maxbytes),
 482                              'showreports' => new external_value(PARAM_INT,
 483                                      'are activity report shown (yes = 1, no =0)', VALUE_DEFAULT,
 484                                      $courseconfig->showreports),
 485                              'visible' => new external_value(PARAM_INT,
 486                                      '1: available to student, 0:not available', VALUE_OPTIONAL),
 487                              'hiddensections' => new external_value(PARAM_INT,
 488                                      '(deprecated, use courseformatoptions) How the hidden sections in the course are displayed to students',
 489                                      VALUE_OPTIONAL),
 490                              'groupmode' => new external_value(PARAM_INT, 'no group, separate, visible',
 491                                      VALUE_DEFAULT, $courseconfig->groupmode),
 492                              'groupmodeforce' => new external_value(PARAM_INT, '1: yes, 0: no',
 493                                      VALUE_DEFAULT, $courseconfig->groupmodeforce),
 494                              'defaultgroupingid' => new external_value(PARAM_INT, 'default grouping id',
 495                                      VALUE_DEFAULT, 0),
 496                              'enablecompletion' => new external_value(PARAM_INT,
 497                                      'Enabled, control via completion and activity settings. Disabled,
 498                                          not shown in activity settings.',
 499                                      VALUE_OPTIONAL),
 500                              'completionnotify' => new external_value(PARAM_INT,
 501                                      '1: yes 0: no', VALUE_OPTIONAL),
 502                              'lang' => new external_value(PARAM_SAFEDIR,
 503                                      'forced course language', VALUE_OPTIONAL),
 504                              'forcetheme' => new external_value(PARAM_PLUGIN,
 505                                      'name of the force theme', VALUE_OPTIONAL),
 506                              'courseformatoptions' => new external_multiple_structure(
 507                                  new external_single_structure(
 508                                      array('name' => new external_value(PARAM_ALPHANUMEXT, 'course format option name'),
 509                                          'value' => new external_value(PARAM_RAW, 'course format option value')
 510                                  )),
 511                                      'additional options for particular course format', VALUE_OPTIONAL),
 512                          )
 513                      ), 'courses to create'
 514                  )
 515              )
 516          );
 517      }
 518  
 519      /**
 520       * Create  courses
 521       *
 522       * @param array $courses
 523       * @return array courses (id and shortname only)
 524       * @since Moodle 2.2
 525       */
 526      public static function create_courses($courses) {
 527          global $CFG, $DB;
 528          require_once($CFG->dirroot . "/course/lib.php");
 529          require_once($CFG->libdir . '/completionlib.php');
 530  
 531          $params = self::validate_parameters(self::create_courses_parameters(),
 532                          array('courses' => $courses));
 533  
 534          $availablethemes = core_component::get_plugin_list('theme');
 535          $availablelangs = get_string_manager()->get_list_of_translations();
 536  
 537          $transaction = $DB->start_delegated_transaction();
 538  
 539          foreach ($params['courses'] as $course) {
 540  
 541              // Ensure the current user is allowed to run this function
 542              $context = context_coursecat::instance($course['categoryid'], IGNORE_MISSING);
 543              try {
 544                  self::validate_context($context);
 545              } catch (Exception $e) {
 546                  $exceptionparam = new stdClass();
 547                  $exceptionparam->message = $e->getMessage();
 548                  $exceptionparam->catid = $course['categoryid'];
 549                  throw new moodle_exception('errorcatcontextnotvalid', 'webservice', '', $exceptionparam);
 550              }
 551              require_capability('moodle/course:create', $context);
 552  
 553              // Make sure lang is valid
 554              if (array_key_exists('lang', $course) and empty($availablelangs[$course['lang']])) {
 555                  throw new moodle_exception('errorinvalidparam', 'webservice', '', 'lang');
 556              }
 557  
 558              // Make sure theme is valid
 559              if (array_key_exists('forcetheme', $course)) {
 560                  if (!empty($CFG->allowcoursethemes)) {
 561                      if (empty($availablethemes[$course['forcetheme']])) {
 562                          throw new moodle_exception('errorinvalidparam', 'webservice', '', 'forcetheme');
 563                      } else {
 564                          $course['theme'] = $course['forcetheme'];
 565                      }
 566                  }
 567              }
 568  
 569              //force visibility if ws user doesn't have the permission to set it
 570              $category = $DB->get_record('course_categories', array('id' => $course['categoryid']));
 571              if (!has_capability('moodle/course:visibility', $context)) {
 572                  $course['visible'] = $category->visible;
 573              }
 574  
 575              //set default value for completion
 576              $courseconfig = get_config('moodlecourse');
 577              if (completion_info::is_enabled_for_site()) {
 578                  if (!array_key_exists('enablecompletion', $course)) {
 579                      $course['enablecompletion'] = $courseconfig->enablecompletion;
 580                  }
 581              } else {
 582                  $course['enablecompletion'] = 0;
 583              }
 584  
 585              $course['category'] = $course['categoryid'];
 586  
 587              // Summary format.
 588              $course['summaryformat'] = external_validate_format($course['summaryformat']);
 589  
 590              if (!empty($course['courseformatoptions'])) {
 591                  foreach ($course['courseformatoptions'] as $option) {
 592                      $course[$option['name']] = $option['value'];
 593                  }
 594              }
 595  
 596              //Note: create_course() core function check shortname, idnumber, category
 597              $course['id'] = create_course((object) $course)->id;
 598  
 599              $resultcourses[] = array('id' => $course['id'], 'shortname' => $course['shortname']);
 600          }
 601  
 602          $transaction->allow_commit();
 603  
 604          return $resultcourses;
 605      }
 606  
 607      /**
 608       * Returns description of method result value
 609       *
 610       * @return external_description
 611       * @since Moodle 2.2
 612       */
 613      public static function create_courses_returns() {
 614          return new external_multiple_structure(
 615              new external_single_structure(
 616                  array(
 617                      'id'       => new external_value(PARAM_INT, 'course id'),
 618                      'shortname' => new external_value(PARAM_TEXT, 'short name'),
 619                  )
 620              )
 621          );
 622      }
 623  
 624      /**
 625       * Update courses
 626       *
 627       * @return external_function_parameters
 628       * @since Moodle 2.5
 629       */
 630      public static function update_courses_parameters() {
 631          return new external_function_parameters(
 632              array(
 633                  'courses' => new external_multiple_structure(
 634                      new external_single_structure(
 635                          array(
 636                              'id' => new external_value(PARAM_INT, 'ID of the course'),
 637                              'fullname' => new external_value(PARAM_TEXT, 'full name', VALUE_OPTIONAL),
 638                              'shortname' => new external_value(PARAM_TEXT, 'course short name', VALUE_OPTIONAL),
 639                              'categoryid' => new external_value(PARAM_INT, 'category id', VALUE_OPTIONAL),
 640                              'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
 641                              'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL),
 642                              'summaryformat' => new external_format_value('summary', VALUE_OPTIONAL),
 643                              'format' => new external_value(PARAM_PLUGIN,
 644                                      'course format: weeks, topics, social, site,..', VALUE_OPTIONAL),
 645                              'showgrades' => new external_value(PARAM_INT,
 646                                      '1 if grades are shown, otherwise 0', VALUE_OPTIONAL),
 647                              'newsitems' => new external_value(PARAM_INT,
 648                                      'number of recent items appearing on the course page', VALUE_OPTIONAL),
 649                              'startdate' => new external_value(PARAM_INT,
 650                                      'timestamp when the course start', VALUE_OPTIONAL),
 651                              'numsections' => new external_value(PARAM_INT,
 652                                      '(deprecated, use courseformatoptions) number of weeks/topics', VALUE_OPTIONAL),
 653                              'maxbytes' => new external_value(PARAM_INT,
 654                                      'largest size of file that can be uploaded into the course', VALUE_OPTIONAL),
 655                              'showreports' => new external_value(PARAM_INT,
 656                                      'are activity report shown (yes = 1, no =0)', VALUE_OPTIONAL),
 657                              'visible' => new external_value(PARAM_INT,
 658                                      '1: available to student, 0:not available', VALUE_OPTIONAL),
 659                              'hiddensections' => new external_value(PARAM_INT,
 660                                      '(deprecated, use courseformatoptions) How the hidden sections in the course are
 661                                          displayed to students', VALUE_OPTIONAL),
 662                              'groupmode' => new external_value(PARAM_INT, 'no group, separate, visible', VALUE_OPTIONAL),
 663                              'groupmodeforce' => new external_value(PARAM_INT, '1: yes, 0: no', VALUE_OPTIONAL),
 664                              'defaultgroupingid' => new external_value(PARAM_INT, 'default grouping id', VALUE_OPTIONAL),
 665                              'enablecompletion' => new external_value(PARAM_INT,
 666                                      'Enabled, control via completion and activity settings. Disabled,
 667                                          not shown in activity settings.', VALUE_OPTIONAL),
 668                              'completionnotify' => new external_value(PARAM_INT, '1: yes 0: no', VALUE_OPTIONAL),
 669                              'lang' => new external_value(PARAM_SAFEDIR, 'forced course language', VALUE_OPTIONAL),
 670                              'forcetheme' => new external_value(PARAM_PLUGIN, 'name of the force theme', VALUE_OPTIONAL),
 671                              'courseformatoptions' => new external_multiple_structure(
 672                                  new external_single_structure(
 673                                      array('name' => new external_value(PARAM_ALPHANUMEXT, 'course format option name'),
 674                                          'value' => new external_value(PARAM_RAW, 'course format option value')
 675                                  )),
 676                                      'additional options for particular course format', VALUE_OPTIONAL),
 677                          )
 678                      ), 'courses to update'
 679                  )
 680              )
 681          );
 682      }
 683  
 684      /**
 685       * Update courses
 686       *
 687       * @param array $courses
 688       * @since Moodle 2.5
 689       */
 690      public static function update_courses($courses) {
 691          global $CFG, $DB;
 692          require_once($CFG->dirroot . "/course/lib.php");
 693          $warnings = array();
 694  
 695          $params = self::validate_parameters(self::update_courses_parameters(),
 696                          array('courses' => $courses));
 697  
 698          $availablethemes = core_component::get_plugin_list('theme');
 699          $availablelangs = get_string_manager()->get_list_of_translations();
 700  
 701          foreach ($params['courses'] as $course) {
 702              // Catch any exception while updating course and return as warning to user.
 703              try {
 704                  // Ensure the current user is allowed to run this function.
 705                  $context = context_course::instance($course['id'], MUST_EXIST);
 706                  self::validate_context($context);
 707  
 708                  $oldcourse = course_get_format($course['id'])->get_course();
 709  
 710                  require_capability('moodle/course:update', $context);
 711  
 712                  // Check if user can change category.
 713                  if (array_key_exists('categoryid', $course) && ($oldcourse->category != $course['categoryid'])) {
 714                      require_capability('moodle/course:changecategory', $context);
 715                      $course['category'] = $course['categoryid'];
 716                  }
 717  
 718                  // Check if the user can change fullname.
 719                  if (array_key_exists('fullname', $course) && ($oldcourse->fullname != $course['fullname'])) {
 720                      require_capability('moodle/course:changefullname', $context);
 721                  }
 722  
 723                  // Check if the user can change shortname.
 724                  if (array_key_exists('shortname', $course) && ($oldcourse->shortname != $course['shortname'])) {
 725                      require_capability('moodle/course:changeshortname', $context);
 726                  }
 727  
 728                  // Check if the user can change the idnumber.
 729                  if (array_key_exists('idnumber', $course) && ($oldcourse->idnumber != $course['idnumber'])) {
 730                      require_capability('moodle/course:changeidnumber', $context);
 731                  }
 732  
 733                  // Check if user can change summary.
 734                  if (array_key_exists('summary', $course) && ($oldcourse->summary != $course['summary'])) {
 735                      require_capability('moodle/course:changesummary', $context);
 736                  }
 737  
 738                  // Summary format.
 739                  if (array_key_exists('summaryformat', $course) && ($oldcourse->summaryformat != $course['summaryformat'])) {
 740                      require_capability('moodle/course:changesummary', $context);
 741                      $course['summaryformat'] = external_validate_format($course['summaryformat']);
 742                  }
 743  
 744                  // Check if user can change visibility.
 745                  if (array_key_exists('visible', $course) && ($oldcourse->visible != $course['visible'])) {
 746                      require_capability('moodle/course:visibility', $context);
 747                  }
 748  
 749                  // Make sure lang is valid.
 750                  if (array_key_exists('lang', $course) && empty($availablelangs[$course['lang']])) {
 751                      throw new moodle_exception('errorinvalidparam', 'webservice', '', 'lang');
 752                  }
 753  
 754                  // Make sure theme is valid.
 755                  if (array_key_exists('forcetheme', $course)) {
 756                      if (!empty($CFG->allowcoursethemes)) {
 757                          if (empty($availablethemes[$course['forcetheme']])) {
 758                              throw new moodle_exception('errorinvalidparam', 'webservice', '', 'forcetheme');
 759                          } else {
 760                              $course['theme'] = $course['forcetheme'];
 761                          }
 762                      }
 763                  }
 764  
 765                  // Make sure completion is enabled before setting it.
 766                  if (array_key_exists('enabledcompletion', $course) && !completion_info::is_enabled_for_site()) {
 767                      $course['enabledcompletion'] = 0;
 768                  }
 769  
 770                  // Make sure maxbytes are less then CFG->maxbytes.
 771                  if (array_key_exists('maxbytes', $course)) {
 772                      $course['maxbytes'] = get_max_upload_file_size($CFG->maxbytes, $course['maxbytes']);
 773                  }
 774  
 775                  if (!empty($course['courseformatoptions'])) {
 776                      foreach ($course['courseformatoptions'] as $option) {
 777                          if (isset($option['name']) && isset($option['value'])) {
 778                              $course[$option['name']] = $option['value'];
 779                          }
 780                      }
 781                  }
 782  
 783                  // Update course if user has all required capabilities.
 784                  update_course((object) $course);
 785              } catch (Exception $e) {
 786                  $warning = array();
 787                  $warning['item'] = 'course';
 788                  $warning['itemid'] = $course['id'];
 789                  if ($e instanceof moodle_exception) {
 790                      $warning['warningcode'] = $e->errorcode;
 791                  } else {
 792                      $warning['warningcode'] = $e->getCode();
 793                  }
 794                  $warning['message'] = $e->getMessage();
 795                  $warnings[] = $warning;
 796              }
 797          }
 798  
 799          $result = array();
 800          $result['warnings'] = $warnings;
 801          return $result;
 802      }
 803  
 804      /**
 805       * Returns description of method result value
 806       *
 807       * @return external_description
 808       * @since Moodle 2.5
 809       */
 810      public static function update_courses_returns() {
 811          return new external_single_structure(
 812              array(
 813                  'warnings' => new external_warnings()
 814              )
 815          );
 816      }
 817  
 818      /**
 819       * Returns description of method parameters
 820       *
 821       * @return external_function_parameters
 822       * @since Moodle 2.2
 823       */
 824      public static function delete_courses_parameters() {
 825          return new external_function_parameters(
 826              array(
 827                  'courseids' => new external_multiple_structure(new external_value(PARAM_INT, 'course ID')),
 828              )
 829          );
 830      }
 831  
 832      /**
 833       * Delete courses
 834       *
 835       * @param array $courseids A list of course ids
 836       * @since Moodle 2.2
 837       */
 838      public static function delete_courses($courseids) {
 839          global $CFG, $DB;
 840          require_once($CFG->dirroot."/course/lib.php");
 841  
 842          // Parameter validation.
 843          $params = self::validate_parameters(self::delete_courses_parameters(), array('courseids'=>$courseids));
 844  
 845          $transaction = $DB->start_delegated_transaction();
 846  
 847          foreach ($params['courseids'] as $courseid) {
 848              $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
 849  
 850              // Check if the context is valid.
 851              $coursecontext = context_course::instance($course->id);
 852              self::validate_context($coursecontext);
 853  
 854              // Check if the current user has enought permissions.
 855              if (!can_delete_course($courseid)) {
 856                  fix_course_sortorder();
 857                  throw new moodle_exception('cannotdeletecategorycourse', 'error',
 858                      '', format_string($course->fullname)." (id: $courseid)");
 859              }
 860  
 861              delete_course($course, false);
 862          }
 863  
 864          $transaction->allow_commit();
 865          fix_course_sortorder();
 866  
 867          return null;
 868      }
 869  
 870      /**
 871       * Returns description of method result value
 872       *
 873       * @return external_description
 874       * @since Moodle 2.2
 875       */
 876      public static function delete_courses_returns() {
 877          return null;
 878      }
 879  
 880      /**
 881       * Returns description of method parameters
 882       *
 883       * @return external_function_parameters
 884       * @since Moodle 2.3
 885       */
 886      public static function duplicate_course_parameters() {
 887          return new external_function_parameters(
 888              array(
 889                  'courseid' => new external_value(PARAM_INT, 'course to duplicate id'),
 890                  'fullname' => new external_value(PARAM_TEXT, 'duplicated course full name'),
 891                  'shortname' => new external_value(PARAM_TEXT, 'duplicated course short name'),
 892                  'categoryid' => new external_value(PARAM_INT, 'duplicated course category parent'),
 893                  'visible' => new external_value(PARAM_INT, 'duplicated course visible, default to yes', VALUE_DEFAULT, 1),
 894                  'options' => new external_multiple_structure(
 895                      new external_single_structure(
 896                          array(
 897                                  'name' => new external_value(PARAM_ALPHAEXT, 'The backup option name:
 898                                              "activities" (int) Include course activites (default to 1 that is equal to yes),
 899                                              "blocks" (int) Include course blocks (default to 1 that is equal to yes),
 900                                              "filters" (int) Include course filters  (default to 1 that is equal to yes),
 901                                              "users" (int) Include users (default to 0 that is equal to no),
 902                                              "role_assignments" (int) Include role assignments  (default to 0 that is equal to no),
 903                                              "comments" (int) Include user comments  (default to 0 that is equal to no),
 904                                              "userscompletion" (int) Include user course completion information  (default to 0 that is equal to no),
 905                                              "logs" (int) Include course logs  (default to 0 that is equal to no),
 906                                              "grade_histories" (int) Include histories  (default to 0 that is equal to no)'
 907                                              ),
 908                                  'value' => new external_value(PARAM_RAW, 'the value for the option 1 (yes) or 0 (no)'
 909                              )
 910                          )
 911                      ), VALUE_DEFAULT, array()
 912                  ),
 913              )
 914          );
 915      }
 916  
 917      /**
 918       * Duplicate a course
 919       *
 920       * @param int $courseid
 921       * @param string $fullname Duplicated course fullname
 922       * @param string $shortname Duplicated course shortname
 923       * @param int $categoryid Duplicated course parent category id
 924       * @param int $visible Duplicated course availability
 925       * @param array $options List of backup options
 926       * @return array New course info
 927       * @since Moodle 2.3
 928       */
 929      public static function duplicate_course($courseid, $fullname, $shortname, $categoryid, $visible = 1, $options = array()) {
 930          global $CFG, $USER, $DB;
 931          require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
 932          require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
 933  
 934          // Parameter validation.
 935          $params = self::validate_parameters(
 936                  self::duplicate_course_parameters(),
 937                  array(
 938                        'courseid' => $courseid,
 939                        'fullname' => $fullname,
 940                        'shortname' => $shortname,
 941                        'categoryid' => $categoryid,
 942                        'visible' => $visible,
 943                        'options' => $options
 944                  )
 945          );
 946  
 947          // Context validation.
 948  
 949          if (! ($course = $DB->get_record('course', array('id'=>$params['courseid'])))) {
 950              throw new moodle_exception('invalidcourseid', 'error');
 951          }
 952  
 953          // Category where duplicated course is going to be created.
 954          $categorycontext = context_coursecat::instance($params['categoryid']);
 955          self::validate_context($categorycontext);
 956  
 957          // Course to be duplicated.
 958          $coursecontext = context_course::instance($course->id);
 959          self::validate_context($coursecontext);
 960  
 961          $backupdefaults = array(
 962              'activities' => 1,
 963              'blocks' => 1,
 964              'filters' => 1,
 965              'users' => 0,
 966              'role_assignments' => 0,
 967              'comments' => 0,
 968              'userscompletion' => 0,
 969              'logs' => 0,
 970              'grade_histories' => 0
 971          );
 972  
 973          $backupsettings = array();
 974          // Check for backup and restore options.
 975          if (!empty($params['options'])) {
 976              foreach ($params['options'] as $option) {
 977  
 978                  // Strict check for a correct value (allways 1 or 0, true or false).
 979                  $value = clean_param($option['value'], PARAM_INT);
 980  
 981                  if ($value !== 0 and $value !== 1) {
 982                      throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
 983                  }
 984  
 985                  if (!isset($backupdefaults[$option['name']])) {
 986                      throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
 987                  }
 988  
 989                  $backupsettings[$option['name']] = $value;
 990              }
 991          }
 992  
 993          // Capability checking.
 994  
 995          // The backup controller check for this currently, this may be redundant.
 996          require_capability('moodle/course:create', $categorycontext);
 997          require_capability('moodle/restore:restorecourse', $categorycontext);
 998          require_capability('moodle/backup:backupcourse', $coursecontext);
 999  
1000          if (!empty($backupsettings['users'])) {
1001              require_capability('moodle/backup:userinfo', $coursecontext);
1002              require_capability('moodle/restore:userinfo', $categorycontext);
1003          }
1004  
1005          // Check if the shortname is used.
1006          if ($foundcourses = $DB->get_records('course', array('shortname'=>$shortname))) {
1007              foreach ($foundcourses as $foundcourse) {
1008                  $foundcoursenames[] = $foundcourse->fullname;
1009              }
1010  
1011              $foundcoursenamestring = implode(',', $foundcoursenames);
1012              throw new moodle_exception('shortnametaken', '', '', $foundcoursenamestring);
1013          }
1014  
1015          // Backup the course.
1016  
1017          $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
1018          backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id);
1019  
1020          foreach ($backupsettings as $name => $value) {
1021              $bc->get_plan()->get_setting($name)->set_value($value);
1022          }
1023  
1024          $backupid       = $bc->get_backupid();
1025          $backupbasepath = $bc->get_plan()->get_basepath();
1026  
1027          $bc->execute_plan();
1028          $results = $bc->get_results();
1029          $file = $results['backup_destination'];
1030  
1031          $bc->destroy();
1032  
1033          // Restore the backup immediately.
1034  
1035          // Check if we need to unzip the file because the backup temp dir does not contains backup files.
1036          if (!file_exists($backupbasepath . "/moodle_backup.xml")) {
1037              $file->extract_to_pathname(get_file_packer('application/vnd.moodle.backup'), $backupbasepath);
1038          }
1039  
1040          // Create new course.
1041          $newcourseid = restore_dbops::create_new_course($params['fullname'], $params['shortname'], $params['categoryid']);
1042  
1043          $rc = new restore_controller($backupid, $newcourseid,
1044                  backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $USER->id, backup::TARGET_NEW_COURSE);
1045  
1046          foreach ($backupsettings as $name => $value) {
1047              $setting = $rc->get_plan()->get_setting($name);
1048              if ($setting->get_status() == backup_setting::NOT_LOCKED) {
1049                  $setting->set_value($value);
1050              }
1051          }
1052  
1053          if (!$rc->execute_precheck()) {
1054              $precheckresults = $rc->get_precheck_results();
1055              if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
1056                  if (empty($CFG->keeptempdirectoriesonbackup)) {
1057                      fulldelete($backupbasepath);
1058                  }
1059  
1060                  $errorinfo = '';
1061  
1062                  foreach ($precheckresults['errors'] as $error) {
1063                      $errorinfo .= $error;
1064                  }
1065  
1066                  if (array_key_exists('warnings', $precheckresults)) {
1067                      foreach ($precheckresults['warnings'] as $warning) {
1068                          $errorinfo .= $warning;
1069                      }
1070                  }
1071  
1072                  throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
1073              }
1074          }
1075  
1076          $rc->execute_plan();
1077          $rc->destroy();
1078  
1079          $course = $DB->get_record('course', array('id' => $newcourseid), '*', MUST_EXIST);
1080          $course->fullname = $params['fullname'];
1081          $course->shortname = $params['shortname'];
1082          $course->visible = $params['visible'];
1083  
1084          // Set shortname and fullname back.
1085          $DB->update_record('course', $course);
1086  
1087          if (empty($CFG->keeptempdirectoriesonbackup)) {
1088              fulldelete($backupbasepath);
1089          }
1090  
1091          // Delete the course backup file created by this WebService. Originally located in the course backups area.
1092          $file->delete();
1093  
1094          return array('id' => $course->id, 'shortname' => $course->shortname);
1095      }
1096  
1097      /**
1098       * Returns description of method result value
1099       *
1100       * @return external_description
1101       * @since Moodle 2.3
1102       */
1103      public static function duplicate_course_returns() {
1104          return new external_single_structure(
1105              array(
1106                  'id'       => new external_value(PARAM_INT, 'course id'),
1107                  'shortname' => new external_value(PARAM_TEXT, 'short name'),
1108              )
1109          );
1110      }
1111  
1112      /**
1113       * Returns description of method parameters for import_course
1114       *
1115       * @return external_function_parameters
1116       * @since Moodle 2.4
1117       */
1118      public static function import_course_parameters() {
1119          return new external_function_parameters(
1120              array(
1121                  'importfrom' => new external_value(PARAM_INT, 'the id of the course we are importing from'),
1122                  'importto' => new external_value(PARAM_INT, 'the id of the course we are importing to'),
1123                  'deletecontent' => new external_value(PARAM_INT, 'whether to delete the course content where we are importing to (default to 0 = No)', VALUE_DEFAULT, 0),
1124                  'options' => new external_multiple_structure(
1125                      new external_single_structure(
1126                          array(
1127                                  'name' => new external_value(PARAM_ALPHA, 'The backup option name:
1128                                              "activities" (int) Include course activites (default to 1 that is equal to yes),
1129                                              "blocks" (int) Include course blocks (default to 1 that is equal to yes),
1130                                              "filters" (int) Include course filters  (default to 1 that is equal to yes)'
1131                                              ),
1132                                  'value' => new external_value(PARAM_RAW, 'the value for the option 1 (yes) or 0 (no)'
1133                              )
1134                          )
1135                      ), VALUE_DEFAULT, array()
1136                  ),
1137              )
1138          );
1139      }
1140  
1141      /**
1142       * Imports a course
1143       *
1144       * @param int $importfrom The id of the course we are importing from
1145       * @param int $importto The id of the course we are importing to
1146       * @param bool $deletecontent Whether to delete the course we are importing to content
1147       * @param array $options List of backup options
1148       * @return null
1149       * @since Moodle 2.4
1150       */
1151      public static function import_course($importfrom, $importto, $deletecontent = 0, $options = array()) {
1152          global $CFG, $USER, $DB;
1153          require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
1154          require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
1155  
1156          // Parameter validation.
1157          $params = self::validate_parameters(
1158              self::import_course_parameters(),
1159              array(
1160                  'importfrom' => $importfrom,
1161                  'importto' => $importto,
1162                  'deletecontent' => $deletecontent,
1163                  'options' => $options
1164              )
1165          );
1166  
1167          if ($params['deletecontent'] !== 0 and $params['deletecontent'] !== 1) {
1168              throw new moodle_exception('invalidextparam', 'webservice', '', $params['deletecontent']);
1169          }
1170  
1171          // Context validation.
1172  
1173          if (! ($importfrom = $DB->get_record('course', array('id'=>$params['importfrom'])))) {
1174              throw new moodle_exception('invalidcourseid', 'error');
1175          }
1176  
1177          if (! ($importto = $DB->get_record('course', array('id'=>$params['importto'])))) {
1178              throw new moodle_exception('invalidcourseid', 'error');
1179          }
1180  
1181          $importfromcontext = context_course::instance($importfrom->id);
1182          self::validate_context($importfromcontext);
1183  
1184          $importtocontext = context_course::instance($importto->id);
1185          self::validate_context($importtocontext);
1186  
1187          $backupdefaults = array(
1188              'activities' => 1,
1189              'blocks' => 1,
1190              'filters' => 1
1191          );
1192  
1193          $backupsettings = array();
1194  
1195          // Check for backup and restore options.
1196          if (!empty($params['options'])) {
1197              foreach ($params['options'] as $option) {
1198  
1199                  // Strict check for a correct value (allways 1 or 0, true or false).
1200                  $value = clean_param($option['value'], PARAM_INT);
1201  
1202                  if ($value !== 0 and $value !== 1) {
1203                      throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
1204                  }
1205  
1206                  if (!isset($backupdefaults[$option['name']])) {
1207                      throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
1208                  }
1209  
1210                  $backupsettings[$option['name']] = $value;
1211              }
1212          }
1213  
1214          // Capability checking.
1215  
1216          require_capability('moodle/backup:backuptargetimport', $importfromcontext);
1217          require_capability('moodle/restore:restoretargetimport', $importtocontext);
1218  
1219          $bc = new backup_controller(backup::TYPE_1COURSE, $importfrom->id, backup::FORMAT_MOODLE,
1220                  backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
1221  
1222          foreach ($backupsettings as $name => $value) {
1223              $bc->get_plan()->get_setting($name)->set_value($value);
1224          }
1225  
1226          $backupid       = $bc->get_backupid();
1227          $backupbasepath = $bc->get_plan()->get_basepath();
1228  
1229          $bc->execute_plan();
1230          $bc->destroy();
1231  
1232          // Restore the backup immediately.
1233  
1234          // Check if we must delete the contents of the destination course.
1235          if ($params['deletecontent']) {
1236              $restoretarget = backup::TARGET_EXISTING_DELETING;
1237          } else {
1238              $restoretarget = backup::TARGET_EXISTING_ADDING;
1239          }
1240  
1241          $rc = new restore_controller($backupid, $importto->id,
1242                  backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id, $restoretarget);
1243  
1244          foreach ($backupsettings as $name => $value) {
1245              $rc->get_plan()->get_setting($name)->set_value($value);
1246          }
1247  
1248          if (!$rc->execute_precheck()) {
1249              $precheckresults = $rc->get_precheck_results();
1250              if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
1251                  if (empty($CFG->keeptempdirectoriesonbackup)) {
1252                      fulldelete($backupbasepath);
1253                  }
1254  
1255                  $errorinfo = '';
1256  
1257                  foreach ($precheckresults['errors'] as $error) {
1258                      $errorinfo .= $error;
1259                  }
1260  
1261                  if (array_key_exists('warnings', $precheckresults)) {
1262                      foreach ($precheckresults['warnings'] as $warning) {
1263                          $errorinfo .= $warning;
1264                      }
1265                  }
1266  
1267                  throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
1268              }
1269          } else {
1270              if ($restoretarget == backup::TARGET_EXISTING_DELETING) {
1271                  restore_dbops::delete_course_content($importto->id);
1272              }
1273          }
1274  
1275          $rc->execute_plan();
1276          $rc->destroy();
1277  
1278          if (empty($CFG->keeptempdirectoriesonbackup)) {
1279              fulldelete($backupbasepath);
1280          }
1281  
1282          return null;
1283      }
1284  
1285      /**
1286       * Returns description of method result value
1287       *
1288       * @return external_description
1289       * @since Moodle 2.4
1290       */
1291      public static function import_course_returns() {
1292          return null;
1293      }
1294  
1295      /**
1296       * Returns description of method parameters
1297       *
1298       * @return external_function_parameters
1299       * @since Moodle 2.3
1300       */
1301      public static function get_categories_parameters() {
1302          return new external_function_parameters(
1303              array(
1304                  'criteria' => new external_multiple_structure(
1305                      new external_single_structure(
1306                          array(
1307                              'key' => new external_value(PARAM_ALPHA,
1308                                           'The category column to search, expected keys (value format) are:'.
1309                                           '"id" (int) the category id,'.
1310                                           '"name" (string) the category name,'.
1311                                           '"parent" (int) the parent category id,'.
1312                                           '"idnumber" (string) category idnumber'.
1313                                           ' - user must have \'moodle/category:manage\' to search on idnumber,'.
1314                                           '"visible" (int) whether the returned categories must be visible or hidden. If the key is not passed,
1315                                               then the function return all categories that the user can see.'.
1316                                           ' - user must have \'moodle/category:manage\' or \'moodle/category:viewhiddencategories\' to search on visible,'.
1317                                           '"theme" (string) only return the categories having this theme'.
1318                                           ' - user must have \'moodle/category:manage\' to search on theme'),
1319                              'value' => new external_value(PARAM_RAW, 'the value to match')
1320                          )
1321                      ), 'criteria', VALUE_DEFAULT, array()
1322                  ),
1323                  'addsubcategories' => new external_value(PARAM_BOOL, 'return the sub categories infos
1324                                            (1 - default) otherwise only the category info (0)', VALUE_DEFAULT, 1)
1325              )
1326          );
1327      }
1328  
1329      /**
1330       * Get categories
1331       *
1332       * @param array $criteria Criteria to match the results
1333       * @param booln $addsubcategories obtain only the category (false) or its subcategories (true - default)
1334       * @return array list of categories
1335       * @since Moodle 2.3
1336       */
1337      public static function get_categories($criteria = array(), $addsubcategories = true) {
1338          global $CFG, $DB;
1339          require_once($CFG->dirroot . "/course/lib.php");
1340  
1341          // Validate parameters.
1342          $params = self::validate_parameters(self::get_categories_parameters(),
1343                  array('criteria' => $criteria, 'addsubcategories' => $addsubcategories));
1344  
1345          // Retrieve the categories.
1346          $categories = array();
1347          if (!empty($params['criteria'])) {
1348  
1349              $conditions = array();
1350              $wheres = array();
1351              foreach ($params['criteria'] as $crit) {
1352                  $key = trim($crit['key']);
1353  
1354                  // Trying to avoid duplicate keys.
1355                  if (!isset($conditions[$key])) {
1356  
1357                      $context = context_system::instance();
1358                      $value = null;
1359                      switch ($key) {
1360                          case 'id':
1361                              $value = clean_param($crit['value'], PARAM_INT);
1362                              break;
1363  
1364                          case 'idnumber':
1365                              if (has_capability('moodle/category:manage', $context)) {
1366                                  $value = clean_param($crit['value'], PARAM_RAW);
1367                              } else {
1368                                  // We must throw an exception.
1369                                  // Otherwise the dev client would think no idnumber exists.
1370                                  throw new moodle_exception('criteriaerror',
1371                                          'webservice', '', null,
1372                                          'You don\'t have the permissions to search on the "idnumber" field.');
1373                              }
1374                              break;
1375  
1376                          case 'name':
1377                              $value = clean_param($crit['value'], PARAM_TEXT);
1378                              break;
1379  
1380                          case 'parent':
1381                              $value = clean_param($crit['value'], PARAM_INT);
1382                              break;
1383  
1384                          case 'visible':
1385                              if (has_capability('moodle/category:manage', $context)
1386                                  or has_capability('moodle/category:viewhiddencategories',
1387                                          context_system::instance())) {
1388                                  $value = clean_param($crit['value'], PARAM_INT);
1389                              } else {
1390                                  throw new moodle_exception('criteriaerror',
1391                                          'webservice', '', null,
1392                                          'You don\'t have the permissions to search on the "visible" field.');
1393                              }
1394                              break;
1395  
1396                          case 'theme':
1397                              if (has_capability('moodle/category:manage', $context)) {
1398                                  $value = clean_param($crit['value'], PARAM_THEME);
1399                              } else {
1400                                  throw new moodle_exception('criteriaerror',
1401                                          'webservice', '', null,
1402                                          'You don\'t have the permissions to search on the "theme" field.');
1403                              }
1404                              break;
1405  
1406                          default:
1407                              throw new moodle_exception('criteriaerror',
1408                                      'webservice', '', null,
1409                                      'You can not search on this criteria: ' . $key);
1410                      }
1411  
1412                      if (isset($value)) {
1413                          $conditions[$key] = $crit['value'];
1414                          $wheres[] = $key . " = :" . $key;
1415                      }
1416                  }
1417              }
1418  
1419              if (!empty($wheres)) {
1420                  $wheres = implode(" AND ", $wheres);
1421  
1422                  $categories = $DB->get_records_select('course_categories', $wheres, $conditions);
1423  
1424                  // Retrieve its sub subcategories (all levels).
1425                  if ($categories and !empty($params['addsubcategories'])) {
1426                      $newcategories = array();
1427  
1428                      // Check if we required visible/theme checks.
1429                      $additionalselect = '';
1430                      $additionalparams = array();
1431                      if (isset($conditions['visible'])) {
1432                          $additionalselect .= ' AND visible = :visible';
1433                          $additionalparams['visible'] = $conditions['visible'];
1434                      }
1435                      if (isset($conditions['theme'])) {
1436                          $additionalselect .= ' AND theme= :theme';
1437                          $additionalparams['theme'] = $conditions['theme'];
1438                      }
1439  
1440                      foreach ($categories as $category) {
1441                          $sqlselect = $DB->sql_like('path', ':path') . $additionalselect;
1442                          $sqlparams = array('path' => $category->path.'/%') + $additionalparams; // It will NOT include the specified category.
1443                          $subcategories = $DB->get_records_select('course_categories', $sqlselect, $sqlparams);
1444                          $newcategories = $newcategories + $subcategories;   // Both arrays have integer as keys.
1445                      }
1446                      $categories = $categories + $newcategories;
1447                  }
1448              }
1449  
1450          } else {
1451              // Retrieve all categories in the database.
1452              $categories = $DB->get_records('course_categories');
1453          }
1454  
1455          // The not returned categories. key => category id, value => reason of exclusion.
1456          $excludedcats = array();
1457  
1458          // The returned categories.
1459          $categoriesinfo = array();
1460  
1461          // We need to sort the categories by path.
1462          // The parent cats need to be checked by the algo first.
1463          usort($categories, "core_course_external::compare_categories_by_path");
1464  
1465          foreach ($categories as $category) {
1466  
1467              // Check if the category is a child of an excluded category, if yes exclude it too (excluded => do not return).
1468              $parents = explode('/', $category->path);
1469              unset($parents[0]); // First key is always empty because path start with / => /1/2/4.
1470              foreach ($parents as $parentid) {
1471                  // Note: when the parent exclusion was due to the context,
1472                  // the sub category could still be returned.
1473                  if (isset($excludedcats[$parentid]) and $excludedcats[$parentid] != 'context') {
1474                      $excludedcats[$category->id] = 'parent';
1475                  }
1476              }
1477  
1478              // Check category depth is <= maxdepth (do not check for user who can manage categories).
1479              if ((!empty($CFG->maxcategorydepth) && count($parents) > $CFG->maxcategorydepth)
1480                      and !has_capability('moodle/category:manage', $context)) {
1481                  $excludedcats[$category->id] = 'depth';
1482              }
1483  
1484              // Check the user can use the category context.
1485              $context = context_coursecat::instance($category->id);
1486              try {
1487                  self::validate_context($context);
1488              } catch (Exception $e) {
1489                  $excludedcats[$category->id] = 'context';
1490  
1491                  // If it was the requested category then throw an exception.
1492                  if (isset($params['categoryid']) && $category->id == $params['categoryid']) {
1493                      $exceptionparam = new stdClass();
1494                      $exceptionparam->message = $e->getMessage();
1495                      $exceptionparam->catid = $category->id;
1496                      throw new moodle_exception('errorcatcontextnotvalid', 'webservice', '', $exceptionparam);
1497                  }
1498              }
1499  
1500              // Return the category information.
1501              if (!isset($excludedcats[$category->id])) {
1502  
1503                  // Final check to see if the category is visible to the user.
1504                  if ($category->visible
1505                          or has_capability('moodle/category:viewhiddencategories', context_system::instance())
1506                          or has_capability('moodle/category:manage', $context)) {
1507  
1508                      $categoryinfo = array();
1509                      $categoryinfo['id'] = $category->id;
1510                      $categoryinfo['name'] = $category->name;
1511                      list($categoryinfo['description'], $categoryinfo['descriptionformat']) =
1512                          external_format_text($category->description, $category->descriptionformat,
1513                                  $context->id, 'coursecat', 'description', null);
1514                      $categoryinfo['parent'] = $category->parent;
1515                      $categoryinfo['sortorder'] = $category->sortorder;
1516                      $categoryinfo['coursecount'] = $category->coursecount;
1517                      $categoryinfo['depth'] = $category->depth;
1518                      $categoryinfo['path'] = $category->path;
1519  
1520                      // Some fields only returned for admin.
1521                      if (has_capability('moodle/category:manage', $context)) {
1522                          $categoryinfo['idnumber'] = $category->idnumber;
1523                          $categoryinfo['visible'] = $category->visible;
1524                          $categoryinfo['visibleold'] = $category->visibleold;
1525                          $categoryinfo['timemodified'] = $category->timemodified;
1526                          $categoryinfo['theme'] = $category->theme;
1527                      }
1528  
1529                      $categoriesinfo[] = $categoryinfo;
1530                  } else {
1531                      $excludedcats[$category->id] = 'visibility';
1532                  }
1533              }
1534          }
1535  
1536          // Sorting the resulting array so it looks a bit better for the client developer.
1537          usort($categoriesinfo, "core_course_external::compare_categories_by_sortorder");
1538  
1539          return $categoriesinfo;
1540      }
1541  
1542      /**
1543       * Sort categories array by path
1544       * private function: only used by get_categories
1545       *
1546       * @param array $category1
1547       * @param array $category2
1548       * @return int result of strcmp
1549       * @since Moodle 2.3
1550       */
1551      private static function compare_categories_by_path($category1, $category2) {
1552          return strcmp($category1->path, $category2->path);
1553      }
1554  
1555      /**
1556       * Sort categories array by sortorder
1557       * private function: only used by get_categories
1558       *
1559       * @param array $category1
1560       * @param array $category2
1561       * @return int result of strcmp
1562       * @since Moodle 2.3
1563       */
1564      private static function compare_categories_by_sortorder($category1, $category2) {
1565          return strcmp($category1['sortorder'], $category2['sortorder']);
1566      }
1567  
1568      /**
1569       * Returns description of method result value
1570       *
1571       * @return external_description
1572       * @since Moodle 2.3
1573       */
1574      public static function get_categories_returns() {
1575          return new external_multiple_structure(
1576              new external_single_structure(
1577                  array(
1578                      'id' => new external_value(PARAM_INT, 'category id'),
1579                      'name' => new external_value(PARAM_TEXT, 'category name'),
1580                      'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
1581                      'description' => new external_value(PARAM_RAW, 'category description'),
1582                      'descriptionformat' => new external_format_value('description'),
1583                      'parent' => new external_value(PARAM_INT, 'parent category id'),
1584                      'sortorder' => new external_value(PARAM_INT, 'category sorting order'),
1585                      'coursecount' => new external_value(PARAM_INT, 'number of courses in this category'),
1586                      'visible' => new external_value(PARAM_INT, '1: available, 0:not available', VALUE_OPTIONAL),
1587                      'visibleold' => new external_value(PARAM_INT, '1: available, 0:not available', VALUE_OPTIONAL),
1588                      'timemodified' => new external_value(PARAM_INT, 'timestamp', VALUE_OPTIONAL),
1589                      'depth' => new external_value(PARAM_INT, 'category depth'),
1590                      'path' => new external_value(PARAM_TEXT, 'category path'),
1591                      'theme' => new external_value(PARAM_THEME, 'category theme', VALUE_OPTIONAL),
1592                  ), 'List of categories'
1593              )
1594          );
1595      }
1596  
1597      /**
1598       * Returns description of method parameters
1599       *
1600       * @return external_function_parameters
1601       * @since Moodle 2.3
1602       */
1603      public static function create_categories_parameters() {
1604          return new external_function_parameters(
1605              array(
1606                  'categories' => new external_multiple_structure(
1607                          new external_single_structure(
1608                              array(
1609                                  'name' => new external_value(PARAM_TEXT, 'new category name'),
1610                                  'parent' => new external_value(PARAM_INT,
1611                                          'the parent category id inside which the new category will be created
1612                                           - set to 0 for a root category',
1613                                          VALUE_DEFAULT, 0),
1614                                  'idnumber' => new external_value(PARAM_RAW,
1615                                          'the new category idnumber', VALUE_OPTIONAL),
1616                                  'description' => new external_value(PARAM_RAW,
1617                                          'the new category description', VALUE_OPTIONAL),
1618                                  'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
1619                                  'theme' => new external_value(PARAM_THEME,
1620                                          'the new category theme. This option must be enabled on moodle',
1621                                          VALUE_OPTIONAL),
1622                          )
1623                      )
1624                  )
1625              )
1626          );
1627      }
1628  
1629      /**
1630       * Create categories
1631       *
1632       * @param array $categories - see create_categories_parameters() for the array structure
1633       * @return array - see create_categories_returns() for the array structure
1634       * @since Moodle 2.3
1635       */
1636      public static function create_categories($categories) {
1637          global $CFG, $DB;
1638          require_once($CFG->libdir . "/coursecatlib.php");
1639  
1640          $params = self::validate_parameters(self::create_categories_parameters(),
1641                          array('categories' => $categories));
1642  
1643          $transaction = $DB->start_delegated_transaction();
1644  
1645          $createdcategories = array();
1646          foreach ($params['categories'] as $category) {
1647              if ($category['parent']) {
1648                  if (!$DB->record_exists('course_categories', array('id' => $category['parent']))) {
1649                      throw new moodle_exception('unknowcategory');
1650                  }
1651                  $context = context_coursecat::instance($category['parent']);
1652              } else {
1653                  $context = context_system::instance();
1654              }
1655              self::validate_context($context);
1656              require_capability('moodle/category:manage', $context);
1657  
1658              // this will validate format and throw an exception if there are errors
1659              external_validate_format($category['descriptionformat']);
1660  
1661              $newcategory = coursecat::create($category);
1662  
1663              $createdcategories[] = array('id' => $newcategory->id, 'name' => $newcategory->name);
1664          }
1665  
1666          $transaction->allow_commit();
1667  
1668          return $createdcategories;
1669      }
1670  
1671      /**
1672       * Returns description of method parameters
1673       *
1674       * @return external_function_parameters
1675       * @since Moodle 2.3
1676       */
1677      public static function create_categories_returns() {
1678          return new external_multiple_structure(
1679              new external_single_structure(
1680                  array(
1681                      'id' => new external_value(PARAM_INT, 'new category id'),
1682                      'name' => new external_value(PARAM_TEXT, 'new category name'),
1683                  )
1684              )
1685          );
1686      }
1687  
1688      /**
1689       * Returns description of method parameters
1690       *
1691       * @return external_function_parameters
1692       * @since Moodle 2.3
1693       */
1694      public static function update_categories_parameters() {
1695          return new external_function_parameters(
1696              array(
1697                  'categories' => new external_multiple_structure(
1698                      new external_single_structure(
1699                          array(
1700                              'id'       => new external_value(PARAM_INT, 'course id'),
1701                              'name' => new external_value(PARAM_TEXT, 'category name', VALUE_OPTIONAL),
1702                              'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
1703                              'parent' => new external_value(PARAM_INT, 'parent category id', VALUE_OPTIONAL),
1704                              'description' => new external_value(PARAM_RAW, 'category description', VALUE_OPTIONAL),
1705                              'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
1706                              'theme' => new external_value(PARAM_THEME,
1707                                      'the category theme. This option must be enabled on moodle', VALUE_OPTIONAL),
1708                          )
1709                      )
1710                  )
1711              )
1712          );
1713      }
1714  
1715      /**
1716       * Update categories
1717       *
1718       * @param array $categories The list of categories to update
1719       * @return null
1720       * @since Moodle 2.3
1721       */
1722      public static function update_categories($categories) {
1723          global $CFG, $DB;
1724          require_once($CFG->libdir . "/coursecatlib.php");
1725  
1726          // Validate parameters.
1727          $params = self::validate_parameters(self::update_categories_parameters(), array('categories' => $categories));
1728  
1729          $transaction = $DB->start_delegated_transaction();
1730  
1731          foreach ($params['categories'] as $cat) {
1732              $category = coursecat::get($cat['id']);
1733  
1734              $categorycontext = context_coursecat::instance($cat['id']);
1735              self::validate_context($categorycontext);
1736              require_capability('moodle/category:manage', $categorycontext);
1737  
1738              // this will throw an exception if descriptionformat is not valid
1739              external_validate_format($cat['descriptionformat']);
1740  
1741              $category->update($cat);
1742          }
1743  
1744          $transaction->allow_commit();
1745      }
1746  
1747      /**
1748       * Returns description of method result value
1749       *
1750       * @return external_description
1751       * @since Moodle 2.3
1752       */
1753      public static function update_categories_returns() {
1754          return null;
1755      }
1756  
1757      /**
1758       * Returns description of method parameters
1759       *
1760       * @return external_function_parameters
1761       * @since Moodle 2.3
1762       */
1763      public static function delete_categories_parameters() {
1764          return new external_function_parameters(
1765              array(
1766                  'categories' => new external_multiple_structure(
1767                      new external_single_structure(
1768                          array(
1769                              'id' => new external_value(PARAM_INT, 'category id to delete'),
1770                              'newparent' => new external_value(PARAM_INT,
1771                                  'the parent category to move the contents to, if specified', VALUE_OPTIONAL),
1772                              'recursive' => new external_value(PARAM_BOOL, '1: recursively delete all contents inside this
1773                                  category, 0 (default): move contents to newparent or current parent category (except if parent is root)', VALUE_DEFAULT, 0)
1774                          )
1775                      )
1776                  )
1777              )
1778          );
1779      }
1780  
1781      /**
1782       * Delete categories
1783       *
1784       * @param array $categories A list of category ids
1785       * @return array
1786       * @since Moodle 2.3
1787       */
1788      public static function delete_categories($categories) {
1789          global $CFG, $DB;
1790          require_once($CFG->dirroot . "/course/lib.php");
1791          require_once($CFG->libdir . "/coursecatlib.php");
1792  
1793          // Validate parameters.
1794          $params = self::validate_parameters(self::delete_categories_parameters(), array('categories' => $categories));
1795  
1796          $transaction = $DB->start_delegated_transaction();
1797  
1798          foreach ($params['categories'] as $category) {
1799              $deletecat = coursecat::get($category['id'], MUST_EXIST);
1800              $context = context_coursecat::instance($deletecat->id);
1801              require_capability('moodle/category:manage', $context);
1802              self::validate_context($context);
1803              self::validate_context(get_category_or_system_context($deletecat->parent));
1804  
1805              if ($category['recursive']) {
1806                  // If recursive was specified, then we recursively delete the category's contents.
1807                  if ($deletecat->can_delete_full()) {
1808                      $deletecat->delete_full(false);
1809                  } else {
1810                      throw new moodle_exception('youcannotdeletecategory', '', '', $deletecat->get_formatted_name());
1811                  }
1812              } else {
1813                  // In this situation, we don't delete the category's contents, we either move it to newparent or parent.
1814                  // If the parent is the root, moving is not supported (because a course must always be inside a category).
1815                  // We must move to an existing category.
1816                  if (!empty($category['newparent'])) {
1817                      $newparentcat = coursecat::get($category['newparent']);
1818                  } else {
1819                      $newparentcat = coursecat::get($deletecat->parent);
1820                  }
1821  
1822                  // This operation is not allowed. We must move contents to an existing category.
1823                  if (!$newparentcat->id) {
1824                      throw new moodle_exception('movecatcontentstoroot');
1825                  }
1826  
1827                  self::validate_context(context_coursecat::instance($newparentcat->id));
1828                  if ($deletecat->can_move_content_to($newparentcat->id)) {
1829                      $deletecat->delete_move($newparentcat->id, false);
1830                  } else {
1831                      throw new moodle_exception('youcannotdeletecategory', '', '', $deletecat->get_formatted_name());
1832                  }
1833              }
1834          }
1835  
1836          $transaction->allow_commit();
1837      }
1838  
1839      /**
1840       * Returns description of method parameters
1841       *
1842       * @return external_function_parameters
1843       * @since Moodle 2.3
1844       */
1845      public static function delete_categories_returns() {
1846          return null;
1847      }
1848  
1849      /**
1850       * Describes the parameters for delete_modules.
1851       *
1852       * @return external_external_function_parameters
1853       * @since Moodle 2.5
1854       */
1855      public static function delete_modules_parameters() {
1856          return new external_function_parameters (
1857              array(
1858                  'cmids' => new external_multiple_structure(new external_value(PARAM_INT, 'course module ID',
1859                          VALUE_REQUIRED, '', NULL_NOT_ALLOWED), 'Array of course module IDs'),
1860              )
1861          );
1862      }
1863  
1864      /**
1865       * Deletes a list of provided module instances.
1866       *
1867       * @param array $cmids the course module ids
1868       * @since Moodle 2.5
1869       */
1870      public static function delete_modules($cmids) {
1871          global $CFG, $DB;
1872  
1873          // Require course file containing the course delete module function.
1874          require_once($CFG->dirroot . "/course/lib.php");
1875  
1876          // Clean the parameters.
1877          $params = self::validate_parameters(self::delete_modules_parameters(), array('cmids' => $cmids));
1878  
1879          // Keep track of the course ids we have performed a capability check on to avoid repeating.
1880          $arrcourseschecked = array();
1881  
1882          foreach ($params['cmids'] as $cmid) {
1883              // Get the course module.
1884              $cm = $DB->get_record('course_modules', array('id' => $cmid), '*', MUST_EXIST);
1885  
1886              // Check if we have not yet confirmed they have permission in this course.
1887              if (!in_array($cm->course, $arrcourseschecked)) {
1888                  // Ensure the current user has required permission in this course.
1889                  $context = context_course::instance($cm->course);
1890                  self::validate_context($context);
1891                  // Add to the array.
1892                  $arrcourseschecked[] = $cm->course;
1893              }
1894  
1895              // Ensure they can delete this module.
1896              $modcontext = context_module::instance($cm->id);
1897              require_capability('moodle/course:manageactivities', $modcontext);
1898  
1899              // Delete the module.
1900              course_delete_module($cm->id);
1901          }
1902      }
1903  
1904      /**
1905       * Describes the delete_modules return value.
1906       *
1907       * @return external_single_structure
1908       * @since Moodle 2.5
1909       */
1910      public static function delete_modules_returns() {
1911          return null;
1912      }
1913  }
1914  
1915  /**
1916   * Deprecated course external functions
1917   *
1918   * @package    core_course
1919   * @copyright  2009 Petr Skodak
1920   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1921   * @since Moodle 2.0
1922   * @deprecated Moodle 2.2 MDL-29106 - Please do not use this class any more.
1923   * @see core_course_external
1924   */
1925  class moodle_course_external extends external_api {
1926  
1927      /**
1928       * Returns description of method parameters
1929       *
1930       * @return external_function_parameters
1931       * @since Moodle 2.0
1932       * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1933       * @see core_course_external::get_courses_parameters()
1934       */
1935      public static function get_courses_parameters() {
1936          return core_course_external::get_courses_parameters();
1937      }
1938  
1939      /**
1940       * Get courses
1941       *
1942       * @param array $options
1943       * @return array
1944       * @since Moodle 2.0
1945       * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1946       * @see core_course_external::get_courses()
1947       */
1948      public static function get_courses($options) {
1949          return core_course_external::get_courses($options);
1950      }
1951  
1952      /**
1953       * Returns description of method result value
1954       *
1955       * @return external_description
1956       * @since Moodle 2.0
1957       * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1958       * @see core_course_external::get_courses_returns()
1959       */
1960      public static function get_courses_returns() {
1961          return core_course_external::get_courses_returns();
1962      }
1963  
1964      /**
1965       * Returns description of method parameters
1966       *
1967       * @return external_function_parameters
1968       * @since Moodle 2.0
1969       * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1970       * @see core_course_external::create_courses_parameters()
1971       */
1972      public static function create_courses_parameters() {
1973          return core_course_external::create_courses_parameters();
1974      }
1975  
1976      /**
1977       * Create  courses
1978       *
1979       * @param array $courses
1980       * @return array courses (id and shortname only)
1981       * @since Moodle 2.0
1982       * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1983       * @see core_course_external::create_courses()
1984       */
1985      public static function create_courses($courses) {
1986          return core_course_external::create_courses($courses);
1987      }
1988  
1989      /**
1990       * Returns description of method result value
1991       *
1992       * @return external_description
1993       * @since Moodle 2.0
1994       * @deprecated Moodle 2.2 MDL-29106 - Please do not call this function any more.
1995       * @see core_course_external::create_courses_returns()
1996       */
1997      public static function create_courses_returns() {
1998          return core_course_external::create_courses_returns();
1999      }
2000  
2001  }

Search This Site: