Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'MDL-32941' of git://github.com/mouneyrac/moodle

Conflicts:
	course/externallib.php
	lib/db/services.php
	version.php
  • Loading branch information...
commit 754c2deab608b82b078d9ae7dee9fd704183b5b3 2 parents 46e046b + 8c50754
@stronk7 stronk7 authored
View
252 admin/webservice/testclient_forms.php
@@ -727,3 +727,255 @@ public function get_params() {
return $params;
}
}
+
+/**
+ * Form class for create_categories() web service function test.
+ *
+ * @package core_webservice
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @copyright 2012 Fabio Souto
+ */
+class core_course_create_categories_form extends moodleform {
+ /**
+ * The form definition.
+ */
+ public function definition() {
+ global $CFG;
+
+ $mform = $this->_form;
+
+ $mform->addElement('header', 'wstestclienthdr', get_string('testclient', 'webservice'));
+
+ // Note: these values are intentionally PARAM_RAW - we want users to test any rubbish as parameters.
+ $data = $this->_customdata;
+ if ($data['authmethod'] == 'simple') {
+ $mform->addElement('text', 'wsusername', 'wsusername');
+ $mform->addElement('text', 'wspassword', 'wspassword');
+ } else if ($data['authmethod'] == 'token') {
+ $mform->addElement('text', 'token', 'token');
+ }
+
+ $mform->addElement('hidden', 'authmethod', $data['authmethod']);
+ $mform->setType('authmethod', PARAM_SAFEDIR);
+ $mform->addElement('text', 'name[0]', 'name[0]');
+ $mform->addElement('text', 'parent[0]', 'parent[0]');
+ $mform->addElement('text', 'idnumber[0]', 'idnumber[0]');
+ $mform->addElement('text', 'description[0]', 'description[0]');
+ $mform->addElement('text', 'name[1]', 'name[1]');
+ $mform->addElement('text', 'parent[1]', 'parent[1]');
+ $mform->addElement('text', 'idnumber[1]', 'idnumber[1]');
+ $mform->addElement('text', 'description[1]', 'description[1]');
+
+ $mform->addElement('hidden', 'function');
+ $mform->setType('function', PARAM_SAFEDIR);
+
+ $mform->addElement('hidden', 'protocol');
+ $mform->setType('protocol', PARAM_SAFEDIR);
+
+ $this->add_action_buttons(true, get_string('execute', 'webservice'));
+ }
+
+ /**
+ * Get the parameters that the user submitted using the form.
+ * @return array|null
+ */
+ public function get_params() {
+ if (!$data = $this->get_data()) {
+ return null;
+ }
+ // Remove unused from form data.
+ unset($data->submitbutton);
+ unset($data->protocol);
+ unset($data->function);
+ unset($data->wsusername);
+ unset($data->wspassword);
+ unset($data->token);
+ unset($data->authmethod);
+
+ $params = array();
+ $params['categories'] = array();
+ for ($i=0; $i<10; $i++) {
+ if (empty($data->name[$i]) or empty($data->parent[$i])) {
+ continue;
+ }
+ $params['categories'][] = array('name'=>$data->name[$i], 'parent'=>$data->parent[$i],
+ 'idnumber'=>$data->idnumber[$i], 'description'=>$data->description[$i]);
+ }
+ return $params;
+ }
+}
+
+/**
+ * Form class for delete_categories() web service function test.
+ *
+ * @package core_webservice
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @copyright 2012 Fabio Souto
+ */
+class core_course_delete_categories_form extends moodleform {
+ /**
+ * The form definition.
+ */
+ public function definition() {
+ global $CFG;
+
+ $mform = $this->_form;
+
+ $mform->addElement('header', 'wstestclienthdr', get_string('testclient', 'webservice'));
+
+ // Note: these values are intentionally PARAM_RAW - we want users to test any rubbish as parameters.
+ $data = $this->_customdata;
+ if ($data['authmethod'] == 'simple') {
+ $mform->addElement('text', 'wsusername', 'wsusername');
+ $mform->addElement('text', 'wspassword', 'wspassword');
+ } else if ($data['authmethod'] == 'token') {
+ $mform->addElement('text', 'token', 'token');
+ }
+
+ $mform->addElement('hidden', 'authmethod', $data['authmethod']);
+ $mform->setType('authmethod', PARAM_SAFEDIR);
+ $mform->addElement('text', 'id[0]', 'id[0]');
+ $mform->addElement('text', 'newparent[0]', 'newparent[0]');
+ $mform->addElement('text', 'recursive[0]', 'recursive[0]');
+ $mform->addElement('text', 'id[1]', 'id[1]');
+ $mform->addElement('text', 'newparent[1]', 'newparent[1]');
+ $mform->addElement('text', 'recursive[1]', 'recursive[1]');
+
+ $mform->addElement('hidden', 'function');
+ $mform->setType('function', PARAM_SAFEDIR);
+
+ $mform->addElement('hidden', 'protocol');
+ $mform->setType('protocol', PARAM_SAFEDIR);
+
+ $this->add_action_buttons(true, get_string('execute', 'webservice'));
+ }
+
+ /**
+ * Get the parameters that the user submitted using the form.
+ * @return array|null
+ */
+ public function get_params() {
+ if (!$data = $this->get_data()) {
+ return null;
+ }
+ // Remove unused from form data.
+ unset($data->submitbutton);
+ unset($data->protocol);
+ unset($data->function);
+ unset($data->wsusername);
+ unset($data->wspassword);
+ unset($data->token);
+ unset($data->authmethod);
+
+ $params = array();
+ $params['categories'] = array();
+ for ($i=0; $i<10; $i++) {
+ if (empty($data->id[$i])) {
+ continue;
+ }
+ $attrs = array();
+ $attrs['id'] = $data->id[$i];
+ if (!empty($data->newparent[$i])) {
+ $attrs['newparent'] = $data->newparent[$i];
+ }
+ if (!empty($data->recursive[$i])) {
+ $attrs['recursive'] = $data->recursive[$i];
+ }
+ $params['categories'][] = $attrs;
+ }
+ return $params;
+ }
+}
+
+/**
+ * Form class for create_categories() web service function test.
+ *
+ * @package core_webservice
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @copyright 2012 Fabio Souto
+ */
+class core_course_update_categories_form extends moodleform {
+ /**
+ * The form definition.
+ */
+ public function definition() {
+ global $CFG;
+
+ $mform = $this->_form;
+
+ $mform->addElement('header', 'wstestclienthdr', get_string('testclient', 'webservice'));
+
+ // Note: these values are intentionally PARAM_RAW - we want users to test any rubbish as parameters.
+ $data = $this->_customdata;
+ if ($data['authmethod'] == 'simple') {
+ $mform->addElement('text', 'wsusername', 'wsusername');
+ $mform->addElement('text', 'wspassword', 'wspassword');
+ } else if ($data['authmethod'] == 'token') {
+ $mform->addElement('text', 'token', 'token');
+ }
+
+ $mform->addElement('hidden', 'authmethod', $data['authmethod']);
+ $mform->setType('authmethod', PARAM_SAFEDIR);
+ $mform->addElement('text', 'id[0]', 'id[0]');
+ $mform->addElement('text', 'name[0]', 'name[0]');
+ $mform->addElement('text', 'parent[0]', 'parent[0]');
+ $mform->addElement('text', 'idnumber[0]', 'idnumber[0]');
+ $mform->addElement('text', 'description[0]', 'description[0]');
+ $mform->addElement('text', 'id[1]', 'id[1]');
+ $mform->addElement('text', 'name[1]', 'name[1]');
+ $mform->addElement('text', 'parent[1]', 'parent[1]');
+ $mform->addElement('text', 'idnumber[1]', 'idnumber[1]');
+ $mform->addElement('text', 'description[1]', 'description[1]');
+
+ $mform->addElement('hidden', 'function');
+ $mform->setType('function', PARAM_SAFEDIR);
+
+ $mform->addElement('hidden', 'protocol');
+ $mform->setType('protocol', PARAM_SAFEDIR);
+
+ $this->add_action_buttons(true, get_string('execute', 'webservice'));
+ }
+
+ /**
+ * Get the parameters that the user submitted using the form.
+ * @return array|null
+ */
+ public function get_params() {
+ if (!$data = $this->get_data()) {
+ return null;
+ }
+ // Remove unused from form data.
+ unset($data->submitbutton);
+ unset($data->protocol);
+ unset($data->function);
+ unset($data->wsusername);
+ unset($data->wspassword);
+ unset($data->token);
+ unset($data->authmethod);
+
+ $params = array();
+ $params['categories'] = array();
+ for ($i=0; $i<10; $i++) {
+
+ if (empty($data->id[$i])) {
+ continue;
+ }
+ $attrs = array();
+ $attrs['id'] = $data->id[$i];
+ if (!empty($data->name[$i])) {
+ $attrs['name'] = $data->name[$i];
+ }
+ if (!empty($data->parent[$i])) {
+ $attrs['parent'] = $data->parent[$i];
+ }
+ if (!empty($data->idnumber[$i])) {
+ $attrs['idnumber'] = $data->idnumber[$i];
+ }
+ if (!empty($data->description[$i])) {
+ $attrs['description'] = $data->description[$i];
+ }
+ $params['categories'][] = $attrs;
+ }
+ return $params;
+ }
+}
View
590 course/externallib.php
@@ -252,6 +252,298 @@ public static function get_course_contents_returns() {
* Returns description of method parameters
*
* @return external_function_parameters
+ * @since Moodle 2.3
+ */
+ public static function get_categories_parameters() {
+ return new external_function_parameters(
+ array(
+ 'criteria' => new external_multiple_structure(
+ new external_single_structure(
+ array(
+ 'key' => new external_value(PARAM_ALPHA,
+ 'The category column to search, expected keys (value format) are:'.
+ '"id" (int) the category id,'.
+ '"name" (string) the category name,'.
+ '"parent" (int) the parent category id,'.
+ '"idnumber" (string) category idnumber'.
+ ' - user must have \'moodle/category:manage\' to search on idnumber,'.
+ '"visible" (int) whether the category is visible or not'.
+ ' - user must have \'moodle/category:manage\' or \'moodle/category:viewhiddencategories\' to search on visible,'.
+ '"theme" (string) category theme'.
+ ' - user must have \'moodle/category:manage\' to search on theme'),
+ 'value' => new external_value(PARAM_RAW, 'the value to match')
+ )
+ ), VALUE_DEFAULT, array()
+ ),
+ 'addsubcategories' => new external_value(PARAM_BOOL, 'return the sub categories infos
+ (1 - default) otherwise only the category info (0)', VALUE_DEFAULT, 1)
+ )
+ );
+ }
+
+ /**
+ * Get categories
+ *
+ * @param array $criteria Criteria to match the results
+ * @param booln $addsubcategories obtain only the category (false) or its subcategories (true - default)
+ * @return array list of categories
+ * @since Moodle 2.3
+ */
+ public static function get_categories($criteria = array(), $addsubcategories = true) {
+ global $CFG, $DB;
+ require_once($CFG->dirroot . "/course/lib.php");
+
+ // Validate parameters.
+ $params = self::validate_parameters(self::get_categories_parameters(),
+ array('criteria' => $criteria, 'addsubcategories' => $addsubcategories));
+
+ // Retrieve the categories.
+ $categories = array();
+ if (!empty($params['criteria'])) {
+
+ $conditions = array();
+ $wheres = array();
+ foreach ($params['criteria'] as $crit) {
+ $key = trim($crit['key']);
+
+ // Trying to avoid duplicate keys.
+ if (!isset($conditions[$key])) {
+
+ $context = context_system::instance();
+ $value = null;
+ switch ($key) {
+ case 'id':
+ $value = clean_param($crit['value'], PARAM_INT);
+ break;
+
+ case 'idnumber':
+ if (has_capability('moodle/category:manage', $context)) {
+ $value = clean_param($crit['value'], PARAM_RAW);
+ } else {
+ // We must throw an exception.
+ // Otherwise the dev client would think no idnumber exists.
+ throw new moodle_exception('criteriaerror',
+ 'webservice', '', null,
+ 'You don\'t have the permissions to search on the "idnumber" field.');
+ }
+ break;
+
+ case 'name':
+ $value = clean_param($crit['value'], PARAM_TEXT);
+ break;
+
+ case 'parent':
+ $value = clean_param($crit['value'], PARAM_INT);
+ break;
+
+ case 'visible':
+ if (has_capability('moodle/category:manage', $context)
+ or has_capability('moodle/category:viewhiddencategories',
+ context_system::instance())) {
+ $value = clean_param($crit['value'], PARAM_INT);
+ } else {
+ throw new moodle_exception('criteriaerror',
+ 'webservice', '', null,
+ 'You don\'t have the permissions to search on the "visible" field.');
+ }
+ break;
+
+ case 'theme':
+ if (has_capability('moodle/category:manage', $context)) {
+ $value = clean_param($crit['value'], PARAM_THEME);
+ } else {
+ throw new moodle_exception('criteriaerror',
+ 'webservice', '', null,
+ 'You don\'t have the permissions to search on the "theme" field.');
+ }
+ break;
+
+ default:
+ throw new moodle_exception('criteriaerror',
+ 'webservice', '', null,
+ 'You can not search on this criteria: ' . $key);
+ }
+
+ if (isset($value)) {
+ $conditions[$key] = $crit['value'];
+ $wheres[] = $key . " = :" . $key;
+ }
+ }
+ }
+
+ if (!empty($wheres)) {
+ $wheres = implode(" AND ", $wheres);
+
+ $categories = $DB->get_records_select('course_categories', $wheres, $conditions);
+
+ // Retrieve its sub subcategories (all levels).
+ if ($categories and !empty($params['addsubcategories'])) {
+ $newcategories = array();
+
+ foreach ($categories as $category) {
+ $sqllike = $DB->sql_like('path', ':path');
+ $sqlparams = array('path' => $category->path.'/%'); // It will NOT include the specified category.
+ $subcategories = $DB->get_records_select('course_categories', $sqllike, $sqlparams);
+ $newcategories = $newcategories + $subcategories; // Both arrays have integer as keys.
+ }
+ $categories = $categories + $newcategories;
+ }
+ }
+
+ } else {
+ // Retrieve all categories in the database.
+ $categories = $DB->get_records('course_categories');
+ }
+
+ // The not returned categories. key => category id, value => reason of exclusion.
+ $excludedcats = array();
+
+ // The returned categories.
+ $categoriesinfo = array();
+
+ // We need to sort the categories by path.
+ // The parent cats need to be checked by the algo first.
+ usort($categories, "core_course_external::compare_categories_by_path");
+
+ foreach ($categories as $category) {
+
+ // Check if the category is a child of an excluded category, if yes exclude it too (excluded => do not return).
+ $parents = explode('/', $category->path);
+ unset($parents[0]); // First key is always empty because path start with / => /1/2/4.
+ foreach ($parents as $parentid) {
+ // Note: when the parent exclusion was due to the context,
+ // the sub category could still be returned.
+ if (isset($excludedcats[$parentid]) and $excludedcats[$parentid] != 'context') {
+ $excludedcats[$category->id] = 'parent';
+ }
+ }
+
+ // Check category depth is <= maxdepth (do not check for user who can manage categories).
+ if ((!empty($CFG->maxcategorydepth) && count($parents) > $CFG->maxcategorydepth)
+ and !has_capability('moodle/category:manage', $context)) {
+ $excludedcats[$category->id] = 'depth';
+ }
+
+ // Check the user can use the category context.
+ $context = context_coursecat::instance($category->id);
+ try {
+ self::validate_context($context);
+ } catch (Exception $e) {
+ $excludedcats[$category->id] = 'context';
+
+ // If it was the requested category then throw an exception.
+ if (isset($params['categoryid']) && $category->id == $params['categoryid']) {
+ $exceptionparam = new stdClass();
+ $exceptionparam->message = $e->getMessage();
+ $exceptionparam->catid = $category->id;
+ throw new moodle_exception('errorcatcontextnotvalid', 'webservice', '', $exceptionparam);
+ }
+ }
+
+ // Return the category information.
+ if (!isset($excludedcats[$category->id])) {
+
+ // Final check to see if the category is visible to the user.
+ if ($category->visible
+ or has_capability('moodle/category:viewhiddencategories', context_system::instance())
+ or has_capability('moodle/category:manage', $context)) {
+
+ $categoryinfo = array();
+ $categoryinfo['id'] = $category->id;
+ $categoryinfo['name'] = $category->name;
+ $categoryinfo['description'] = file_rewrite_pluginfile_urls($category->description,
+ 'webservice/pluginfile.php', $context->id, 'coursecat', 'description', null);
+ $options = new stdClass;
+ $options->noclean = true;
+ $options->para = false;
+ $categoryinfo['description'] = format_text($categoryinfo['description'],
+ $category->descriptionformat, $options);
+ $categoryinfo['parent'] = $category->parent;
+ $categoryinfo['sortorder'] = $category->sortorder;
+ $categoryinfo['coursecount'] = $category->coursecount;
+ $categoryinfo['depth'] = $category->depth;
+ $categoryinfo['path'] = $category->path;
+
+ // Some fields only returned for admin.
+ if (has_capability('moodle/category:manage', $context)) {
+ $categoryinfo['idnumber'] = $category->idnumber;
+ $categoryinfo['visible'] = $category->visible;
+ $categoryinfo['visibleold'] = $category->visibleold;
+ $categoryinfo['timemodified'] = $category->timemodified;
+ $categoryinfo['theme'] = $category->theme;
+ }
+
+ $categoriesinfo[] = $categoryinfo;
+ } else {
+ $excludedcats[$category->id] = 'visibility';
+ }
+ }
+ }
+
+ // Sorting the resulting array so it looks a bit better for the client developer.
+ usort($categoriesinfo, "core_course_external::compare_categories_by_sortorder");
+
+ return $categoriesinfo;
+ }
+
+ /**
+ * Sort categories array by path
+ * private function: only used by get_categories
+ *
+ * @param array $category1
+ * @param array $category2
+ * @return int result of strcmp
+ * @since Moodle 2.3
+ */
+ private static function compare_categories_by_path($category1, $category2) {
+ return strcmp($category1->path, $category2->path);
+ }
+
+ /**
+ * Sort categories array by sortorder
+ * private function: only used by get_categories
+ *
+ * @param array $category1
+ * @param array $category2
+ * @return int result of strcmp
+ * @since Moodle 2.3
+ */
+ private static function compare_categories_by_sortorder($category1, $category2) {
+ return strcmp($category1['sortorder'], $category2['sortorder']);
+ }
+
+ /**
+ * Returns description of method result value
+ *
+ * @return external_description
+ * @since Moodle 2.3
+ */
+ public static function get_categories_returns() {
+ return new external_multiple_structure(
+ new external_single_structure(
+ array(
+ 'id' => new external_value(PARAM_INT, 'category id'),
+ 'name' => new external_value(PARAM_TEXT, 'category name'),
+ 'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
+ 'description' => new external_value(PARAM_RAW, 'category description'),
+ 'parent' => new external_value(PARAM_INT, 'parent category id'),
+ 'sortorder' => new external_value(PARAM_INT, 'category sorting order'),
+ 'coursecount' => new external_value(PARAM_INT, 'number of courses in this category'),
+ 'visible' => new external_value(PARAM_INT, '1: available, 0:not available', VALUE_OPTIONAL),
+ 'visibleold' => new external_value(PARAM_INT, '1: available, 0:not available', VALUE_OPTIONAL),
+ 'timemodified' => new external_value(PARAM_INT, 'timestamp', VALUE_OPTIONAL),
+ 'depth' => new external_value(PARAM_INT, 'category depth'),
+ 'path' => new external_value(PARAM_TEXT, 'category path'),
+ 'theme' => new external_value(PARAM_THEME, 'category theme', VALUE_OPTIONAL),
+ ), 'List of categories'
+ )
+ );
+ }
+
+ /**
+ * Returns description of method parameters
+ *
+ * @return external_function_parameters
* @since Moodle 2.2
*/
public static function get_courses_parameters() {
@@ -422,6 +714,123 @@ public static function get_courses_returns() {
* Returns description of method parameters
*
* @return external_function_parameters
+ * @since Moodle 2.3
+ */
+ public static function create_categories_parameters() {
+ return new external_function_parameters(
+ array(
+ 'categories' => new external_multiple_structure(
+ new external_single_structure(
+ array(
+ 'name' => new external_value(PARAM_TEXT, 'new category name'),
+ 'parent' => new external_value(PARAM_INT,
+ 'the parent category id inside which the new category will be created'),
+ 'idnumber' => new external_value(PARAM_RAW,
+ 'the new category idnumber', VALUE_OPTIONAL),
+ 'description' => new external_value(PARAM_RAW,
+ 'the new category description', VALUE_OPTIONAL),
+ 'theme' => new external_value(PARAM_THEME,
+ 'the new category theme. This option must be enabled on moodle',
+ VALUE_OPTIONAL),
+ )
+ )
+ )
+ )
+ );
+ }
+
+ /**
+ * Create categories
+ *
+ * @param array $categories - see create_categories_parameters() for the array structure
+ * @return array - see create_categories_returns() for the array structure
+ * @since Moodle 2.3
+ */
+ public static function create_categories($categories) {
+ global $CFG, $DB;
+ require_once($CFG->dirroot . "/course/lib.php");
+
+ $params = self::validate_parameters(self::create_categories_parameters(),
+ array('categories' => $categories));
+
+ $transaction = $DB->start_delegated_transaction();
+
+ $createdcategories = array();
+ foreach ($params['categories'] as $category) {
+ if ($category['parent']) {
+ if (!$DB->record_exists('course_categories', array('id' => $category['parent']))) {
+ throw new moodle_exception('unknowcategory');
+ }
+ $context = context_coursecat::instance($category['parent']);
+ } else {
+ $context = context_system::instance();
+ }
+ self::validate_context($context);
+ require_capability('moodle/category:manage', $context);
+
+ // Check id number.
+ if (!empty($category['idnumber'])) { // Same as in course/editcategory_form.php .
+ if (textlib::strlen($category['idnumber'])>100) {
+ throw new moodle_exception('idnumbertoolong');
+ }
+ if ($existing = $DB->get_record('course_categories', array('idnumber' => $category['idnumber']))) {
+ if ($existing->id) {
+ throw new moodle_exception('idnumbertaken');
+ }
+ }
+ }
+ // Check name.
+ if (textlib::strlen($category['name'])>255) {
+ throw new moodle_exception('categorytoolong');
+ }
+
+ $newcategory = new stdClass();
+ $newcategory->name = $category['name'];
+ $newcategory->parent = $category['parent'];
+ $newcategory->idnumber = $category['idnumber'];
+ $newcategory->sortorder = 999; // Same as in the course/editcategory.php .
+ // Format the description.
+ if (!empty($category['description'])) {
+ $newcategory->description = $category['description'];
+ }
+ $newcategory->descriptionformat = FORMAT_HTML;
+ if (isset($category['theme']) and !empty($CFG->allowcategorythemes)) {
+ $newcategory->theme = $category['theme'];
+ }
+
+ $newcategory = create_course_category($newcategory);
+ // Populate special fields.
+ fix_course_sortorder();
+
+ $createdcategories[] = array('id' => $newcategory->id, 'name' => $newcategory->name);
+ }
+
+ $transaction->allow_commit();
+
+ return $createdcategories;
+ }
+
+ /**
+ * Returns description of method parameters
+ *
+ * @return external_function_parameters
+ * @since Moodle 2.3
+ */
+ public static function create_categories_returns() {
+ return new external_multiple_structure(
+ new external_single_structure(
+ array(
+ 'id' => new external_value(PARAM_INT, 'new category id'),
+ 'name' => new external_value(PARAM_TEXT, 'new category name'),
+ )
+ )
+ );
+ }
+
+ /**
+ * Returns description of method parameters
+ *
+ * @return external_function_parameters
* @since Moodle 2.2
*/
public static function create_courses_parameters() {
@@ -501,7 +910,6 @@ public static function create_courses($courses) {
require_once($CFG->dirroot . "/course/lib.php");
require_once($CFG->libdir . '/completionlib.php');
-
$params = self::validate_parameters(self::create_courses_parameters(),
array('courses' => $courses));
@@ -627,7 +1035,8 @@ public static function delete_courses($courseids) {
// Check if the current user has enought permissions.
if (!can_delete_course($courseid)) {
- throw new moodle_exception('cannotdeletecategorycourse', 'error', '', format_string($course->fullname)." (id: $courseid)");
+ throw new moodle_exception('cannotdeletecategorycourse', 'error',
+ '', format_string($course->fullname)." (id: $courseid)");
}
delete_course($course, false);
@@ -880,6 +1289,183 @@ public static function duplicate_course_returns() {
);
}
+ /**
+ * Returns description of method parameters
+ * @return external_function_parameters
+ * @since Moodle 2.3
+ */
+ public static function delete_categories_parameters() {
+ return new external_function_parameters(
+ array(
+ 'categories' => new external_multiple_structure(
+ new external_single_structure(
+ array(
+ 'id' => new external_value(PARAM_INT, 'category id to delete'),
+ 'newparent' => new external_value(PARAM_INT,
+ 'the parent category to move the contents to, if specified', VALUE_OPTIONAL),
+ 'recursive' => new external_value(PARAM_BOOL, '1: recursively delete all contents inside this
+ category, 0 (default): move contents to newparent or current parent category (except if parent is root)', VALUE_DEFAULT, 0)
+ )
+ )
+ )
+ )
+ );
+ }
+
+ /**
+ * Delete categories
+ * @param array $categories A list of category ids
+ * @return array
+ * @since Moodle 2.3
+ */
+ public static function delete_categories($categories) {
+ global $CFG, $DB;
+ require_once($CFG->dirroot . "/course/lib.php");
+
+ // Validate parameters.
+ $params = self::validate_parameters(self::delete_categories_parameters(), array('categories' => $categories));
+
+ foreach ($params['categories'] as $category) {
+ if (!$deletecat = $DB->get_record('course_categories', array('id' => $category['id']))) {
+ throw new moodle_exception('unknowcategory');
+ }
+ $context = context_coursecat::instance($deletecat->id);
+ require_capability('moodle/category:manage', $context);
+ self::validate_context($context);
+ self::validate_context(get_category_or_system_context($deletecat->parent));
+
+ if ($category['recursive']) {
+ // If recursive was specified, then we recursively delete the category's contents.
+ category_delete_full($deletecat, false);
+ } else {
+ // In this situation, we don't delete the category's contents, we either move it to newparent or parent.
+ // If the parent is the root, moving is not supported (because a course must always be inside a category).
+ // We must move to an existing category.
+ if (!empty($category['newparent'])) {
+ if (!$DB->record_exists('course_categories', array('id' => $category['newparent']))) {
+ throw new moodle_exception('unknowcategory');
+ }
+ $newparent = $category['newparent'];
+ } else {
+ $newparent = $deletecat->parent;
+ }
+
+ // This operation is not allowed. We must move contents to an existing category.
+ if ($newparent == 0) {
+ throw new moodle_exception('movecatcontentstoroot');
+ }
+
+ $parentcontext = get_category_or_system_context($newparent);
+ require_capability('moodle/category:manage', $parentcontext);
+ self::validate_context($parentcontext);
+ category_delete_move($deletecat, $newparent, false);
+ }
+ }
+
+ }
+
+ /**
+ * Returns description of method parameters
+ * @return external_function_parameters
+ * @since Moodle 2.3
+ */
+ public static function delete_categories_returns() {
+ return null;
+ }
+
+ /**
+ * Returns description of method parameters
+ * @return external_function_parameters
+ * @since Moodle 2.3
+ */
+ public static function update_categories_parameters() {
+ return new external_function_parameters(
+ array(
+ 'categories' => new external_multiple_structure(
+ new external_single_structure(
+ array(
+ 'id' => new external_value(PARAM_INT, 'course id'),
+ 'name' => new external_value(PARAM_TEXT, 'category name', VALUE_OPTIONAL),
+ 'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
+ 'parent' => new external_value(PARAM_INT, 'parent category id', VALUE_OPTIONAL),
+ 'description' => new external_value(PARAM_RAW, 'category description', VALUE_OPTIONAL),
+ 'theme' => new external_value(PARAM_THEME,
+ 'the category theme. This option must be enabled on moodle', VALUE_OPTIONAL),
+ )
+ )
+ )
+ )
+ );
+ }
+
+ /**
+ * Update categories
+ * @param array $categories The list of categories to update
+ * @return null
+ * @since Moodle 2.3
+ */
+ public static function update_categories($categories) {
+ global $CFG, $DB;
+ require_once($CFG->dirroot . "/course/lib.php");
+
+ // Validate parameters.
+ $params = self::validate_parameters(self::update_categories_parameters(), array('categories' => $categories));
+
+ $transaction = $DB->start_delegated_transaction();
+
+ foreach ($params['categories'] as $cat) {
+ if (!$category = $DB->get_record('course_categories', array('id' => $cat['id']))) {
+ throw new moodle_exception('unknowcategory');
+ }
+
+ $categorycontext = context_coursecat::instance($cat['id']);
+ self::validate_context($categorycontext);
+ require_capability('moodle/category:manage', $categorycontext);
+
+ if (!empty($cat['name'])) {
+ if (textlib::strlen($cat['name'])>255) {
+ throw new moodle_exception('categorytoolong');
+ }
+ $category->name = $cat['name'];
+ }
+ if (!empty($cat['idnumber'])) {
+ if (textlib::strlen($cat['idnumber'])>100) {
+ throw new moodle_exception('idnumbertoolong');
+ }
+ $category->idnumber = $cat['idnumber'];
+ }
+ if (!empty($cat['description'])) {
+ $category->description = $cat['description'];
+ $category->descriptionformat = FORMAT_HTML;
+ }
+ if (!empty($cat['theme'])) {
+ $category->theme = $cat['theme'];
+ }
+ if (!empty($cat['parent']) && ($category->parent != $cat['parent'])) {
+ // First check if parent exists.
+ if (!$parent_cat = $DB->get_record('course_categories', array('id' => $cat['parent']))) {
+ throw new moodle_exception('unknowcategory');
+ }
+ // Then check if we have capability.
+ self::validate_context(get_category_or_system_context((int)$cat['parent']));
+ require_capability('moodle/category:manage', get_category_or_system_context((int)$cat['parent']));
+ // Finally move the category.
+ move_category($category, $parent_cat);
+ $category->parent = $cat['parent'];
+ }
+ $DB->update_record('course_categories', $category);
+ }
+
+ $transaction->allow_commit();
+ }
+
+ /**
+ * Returns description of method result value
+ * @return external_description
+ */
+ public static function update_categories_returns() {
+ return null;
+ }
}
/**
View
17 course/lib.php
@@ -3522,10 +3522,14 @@ function category_delete_move($category, $newparentid, $showfeedback=true) {
if ($courses = $DB->get_records('course', array('category'=>$category->id), 'sortorder ASC', 'id')) {
if (!move_courses(array_keys($courses), $newparentid)) {
- echo $OUTPUT->notification("Error moving courses");
+ if ($showfeedback) {
+ echo $OUTPUT->notification("Error moving courses");
+ }
return false;
}
- echo $OUTPUT->notification(get_string('coursesmovedout', '', format_string($category->name)), 'notifysuccess');
+ if ($showfeedback) {
+ echo $OUTPUT->notification(get_string('coursesmovedout', '', format_string($category->name)), 'notifysuccess');
+ }
}
// move or delete cohorts in this context
@@ -3534,7 +3538,9 @@ function category_delete_move($category, $newparentid, $showfeedback=true) {
// now delete anything that may depend on course category context
grade_course_category_delete($category->id, $newparentid, $showfeedback);
if (!question_delete_course_category($category, $newparentcat, $showfeedback)) {
- echo $OUTPUT->notification(get_string('errordeletingquestionsfromcategory', 'question', $category), 'notifysuccess');
+ if ($showfeedback) {
+ echo $OUTPUT->notification(get_string('errordeletingquestionsfromcategory', 'question', $category), 'notifysuccess');
+ }
return false;
}
@@ -3544,8 +3550,9 @@ function category_delete_move($category, $newparentid, $showfeedback=true) {
events_trigger('course_category_deleted', $category);
- echo $OUTPUT->notification(get_string('coursecategorydeleted', '', format_string($category->name)), 'notifysuccess');
-
+ if ($showfeedback) {
+ echo $OUTPUT->notification(get_string('coursecategorydeleted', '', format_string($category->name)), 'notifysuccess');
+ }
return true;
}
View
3  lang/en/error.php
@@ -158,6 +158,7 @@
$string['cannotviewreport'] = 'You cannot view this report';
$string['cannotwritefile'] = 'Cannot write to file ({$a})';
$string['categoryerror'] = 'Category error';
+$string['categorytoolong'] = 'Category name too long';
$string['commentmisconf'] = 'Comment ID is misconfigured';
$string['componentisuptodate'] = 'Component is up-to-date';
$string['confirmsesskeybad'] = 'Sorry, but your session key could not be confirmed to carry out this action. This security feature prevents against accidental or malicious execution of important functions in your name. Please make sure you really wanted to execute this function.';
@@ -253,6 +254,7 @@
$string['hashpoolproblem'] = 'Incorrect pool file content {$a}.';
$string['headersent'] = 'Headers already sent';
$string['idnumbertaken'] = 'ID number is already used for another course';
+$string['idnumbertoolong'] = 'ID number is too long';
$string['importformatnotimplement'] = 'Sorry, importing this format is not yet implemented!';
$string['incorrectext'] = 'File has an incorrect extension';
$string['installproblem'] = 'It is usually not possible to recover from errors triggered during installation, you may need to create a new database or use a different database prefix if you want to retry the installation.';
@@ -359,6 +361,7 @@
$string['moduledoesnotexist'] = 'This module does not exist';
$string['moduleinstancedoesnotexist'] = 'The instance of this module does not exist';
$string['modulemissingcode'] = 'Module {$a} is missing the code needed to perform this function';
+$string['movecatcontentstoroot'] = 'Moving the category content to root is not allowed. You must move the contents to an existant category!';
$string['multiplerecordsfound'] = 'Multiple records found, only one record expected.';
$string['multiplerestorenotallow'] = 'Multiple restore execution not allowed!';
$string['mustbeloggedin'] = 'You must be logged in to do this';
View
1  lang/en/webservice.php
@@ -54,6 +54,7 @@
$string['createtokenforuserdescription'] = 'Create a token for the web services user.';
$string['createuser'] = 'Create a specific user';
$string['createuserdescription'] = 'A web services user is required to represent the system controlling Moodle.';
+$string['criteriaerror'] = 'Missing permissions to search on a criteria.';
$string['default'] = 'Default to "{$a}"';
$string['deleteaservice'] = 'Delete service';
$string['deleteservice'] = 'Delete the service: {$a->name} (id: {$a->id})';
View
36 lib/db/services.php
@@ -433,6 +433,24 @@
// === course related functions ===
+ 'core_course_get_categories' => array(
+ 'classname' => 'core_course_external',
+ 'methodname' => 'get_categories',
+ 'classpath' => 'course/externallib.php',
+ 'description' => 'Return category details',
+ 'type' => 'read',
+ 'capabilities'=> 'moodle/category:viewhiddencategories',
+ ),
+
+ 'core_course_update_categories' => array(
+ 'classname' => 'core_course_external',
+ 'methodname' => 'update_categories',
+ 'classpath' => 'course/externallib.php',
+ 'description' => 'Update categories',
+ 'type' => 'write',
+ 'capabilities'=> 'moodle:category/manage',
+ ),
+
'moodle_course_get_courses' => array(
'classname' => 'core_course_external',
'methodname' => 'get_courses',
@@ -496,6 +514,24 @@
'capabilities'=> 'moodle/backup:backupcourse,moodle/restore:restorecourse,moodle/course:create',
),
+ 'core_course_create_categories' => array(
+ 'classname' => 'core_course_external',
+ 'methodname' => 'create_categories',
+ 'classpath' => 'course/externallib.php',
+ 'description' => 'Create course categories',
+ 'type' => 'write',
+ 'capabilities'=> 'moodle/category:manage',
+ ),
+
+ 'core_course_delete_categories' => array(
+ 'classname' => 'core_course_external',
+ 'methodname' => 'delete_categories',
+ 'classpath' => 'course/externallib.php',
+ 'description' => 'Delete course categories',
+ 'type' => 'write',
+ 'capabilities'=> 'moodle/category:manage',
+ ),
+
// === message related functions ===
'moodle_message_send_instantmessages' => array(
View
2  version.php
@@ -30,7 +30,7 @@
defined('MOODLE_INTERNAL') || die();
-$version = 2012051700.00; // YYYYMMDD = weekly release date of this DEV branch
+$version = 2012051700.01; // YYYYMMDD = weekly release date of this DEV branch
// RR = release increments - 00 in DEV branches
// .XX = incremental changes
Please sign in to comment.
Something went wrong with that request. Please try again.