From 2f951d866a69cb585960c39e85c461e3face81b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A1bio=20Souto?= Date: Thu, 29 Dec 2011 12:10:34 +0000 Subject: [PATCH] MDL-32941 Added service definition and implementation for core_course_delete_categories() Included is a bug correction to categories_delete_move() which does not respect showfeedback parameter, printing feedback even when not wanted (this breaks the webservice output) Conflicts: admin/webservice/testclient_forms.php lib/db/services.php --- admin/webservice/testclient_forms.php | 78 +++++++++++++++++++++++++ course/externallib.php | 83 +++++++++++++++++++++++++++ course/lib.php | 17 ++++-- lang/en/error.php | 1 + lib/db/services.php | 9 +++ 5 files changed, 183 insertions(+), 5 deletions(-) diff --git a/admin/webservice/testclient_forms.php b/admin/webservice/testclient_forms.php index 7e3e0b812dd..6a8dad9fb62 100644 --- a/admin/webservice/testclient_forms.php +++ b/admin/webservice/testclient_forms.php @@ -800,3 +800,81 @@ class core_course_create_categories_form extends moodleform { return $params; } } + +/** + * Form class for delete_categories() web service function test. + */ +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; + } +} diff --git a/course/externallib.php b/course/externallib.php index cb5db6f016a..d05e3b48183 100644 --- a/course/externallib.php +++ b/course/externallib.php @@ -763,6 +763,89 @@ class core_course_external extends external_api { return null; } + /** + * 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; + } } /** diff --git a/course/lib.php b/course/lib.php index 262582f4c5c..77b044fcd5c 100644 --- a/course/lib.php +++ b/course/lib.php @@ -3478,10 +3478,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 @@ -3490,7 +3494,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; } @@ -3500,8 +3506,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; } diff --git a/lang/en/error.php b/lang/en/error.php index 828d8103803..d97daf7f625 100644 --- a/lang/en/error.php +++ b/lang/en/error.php @@ -358,6 +358,7 @@ $string['moduledisable'] = 'This module ({$a}) has been disabled for this partic $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'; diff --git a/lib/db/services.php b/lib/db/services.php index 9360d1711a7..db5558d807c 100644 --- a/lib/db/services.php +++ b/lib/db/services.php @@ -439,6 +439,15 @@ $functions = array( '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 ===