mirror of
https://github.com/moodle/moodle.git
synced 2025-08-06 17:36:38 +02:00
MDL-31861 add web service function save_definitions
This commit is contained in:
parent
337075d17b
commit
0ff4ebb4a3
5 changed files with 505 additions and 21 deletions
|
@ -226,6 +226,7 @@ class core_grading_external extends external_api {
|
|||
'cmid' => new external_value(PARAM_INT, 'course module id'),
|
||||
'contextid' => new external_value(PARAM_INT, 'context id'),
|
||||
'component' => new external_value(PARAM_TEXT, 'component name'),
|
||||
'areaname' => new external_value(PARAM_TEXT, 'area name'),
|
||||
'activemethod' => new external_value(PARAM_TEXT, 'active method', VALUE_OPTIONAL),
|
||||
'definitions' => new external_multiple_structure(self::definition(), 'definitions')
|
||||
)
|
||||
|
@ -240,11 +241,11 @@ class core_grading_external extends external_api {
|
|||
private static function definition() {
|
||||
global $CFG;
|
||||
$definition = array();
|
||||
$definition['id'] = new external_value(PARAM_INT, 'definition id');
|
||||
$definition['id'] = new external_value(PARAM_INT, 'definition id', VALUE_OPTIONAL);
|
||||
$definition['method'] = new external_value(PARAM_TEXT, 'method');
|
||||
$definition['name'] = new external_value(PARAM_TEXT, 'name');
|
||||
$definition['description'] = new external_value(PARAM_RAW, 'description');
|
||||
$definition['descriptionformat'] = new external_format_value('description');
|
||||
$definition['description'] = new external_value(PARAM_RAW, 'description', VALUE_OPTIONAL);
|
||||
$definition['descriptionformat'] = new external_format_value('description', VALUE_OPTIONAL);
|
||||
$definition['status'] = new external_value(PARAM_INT, 'status');
|
||||
$definition['copiedfromid'] = new external_value(PARAM_INT, 'copied from id', VALUE_OPTIONAL);
|
||||
$definition['timecreated'] = new external_value(PARAM_INT, 'creation time');
|
||||
|
@ -442,4 +443,140 @@ class core_grading_external extends external_api {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the parameters for save_definitions
|
||||
*
|
||||
* @return external_function_parameters
|
||||
* @since Moodle 2.8
|
||||
*/
|
||||
public static function save_definitions_parameters() {
|
||||
return new external_function_parameters(
|
||||
array(
|
||||
'areas' => new external_multiple_structure(self::grading_area(), 'areas with definitions to save')
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the areas and definitions
|
||||
* @param array $areas array of areas containing definitions to be saved
|
||||
* @return null
|
||||
* @throws invalid_parameter_exception
|
||||
* @since Moodle 2.8
|
||||
*/
|
||||
public static function save_definitions($areas) {
|
||||
$params = self::validate_parameters(self::save_definitions_parameters(),
|
||||
array('areas' => $areas));
|
||||
|
||||
foreach ($params['areas'] as $area) {
|
||||
|
||||
$context = context::instance_by_id($area['contextid']);
|
||||
require_capability('moodle/grade:managegradingforms', $context);
|
||||
$gradingmanager = get_grading_manager($context, $area['component'], $area['areaname']);
|
||||
$gradingmanager->set_active_method($area['activemethod']);
|
||||
$availablemethods = $gradingmanager->get_available_methods();
|
||||
|
||||
foreach ($area['definitions'] as $definition) {
|
||||
if (array_key_exists($definition['method'], $availablemethods)) {
|
||||
$controller = $gradingmanager->get_controller($definition['method']);
|
||||
$controller->update_definition(self::create_definition_object($definition));
|
||||
} else {
|
||||
throw new invalid_parameter_exception('Unknown Grading method: '. $definition['method']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the return value for save_definitions
|
||||
*
|
||||
* @return external_single_structure
|
||||
* @since Moodle 2.8
|
||||
*/
|
||||
public static function save_definitions_returns() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a definition stdClass object using the values from the definition
|
||||
* array that is passed in as a parameter
|
||||
*
|
||||
* @param array $definition
|
||||
* @return stdClass definition object
|
||||
* @since Moodle 2.8
|
||||
*/
|
||||
private static function create_definition_object($definition) {
|
||||
global $CFG;
|
||||
|
||||
$method = $definition['method'];
|
||||
$definitionobject = new stdClass();
|
||||
foreach ($definition as $key => $value) {
|
||||
if (!is_array($value)) {
|
||||
$definitionobject->$key = $value;
|
||||
}
|
||||
}
|
||||
$text = '';
|
||||
$format = FORMAT_MOODLE;
|
||||
if (isset($definition['description'])) {
|
||||
$text = $definition['description'];
|
||||
if (isset($definition['descriptionformat'])) {
|
||||
$format = $definition['descriptionformat'];
|
||||
}
|
||||
}
|
||||
$definitionobject->description_editor = array('text' => $text, 'format' => $format);
|
||||
|
||||
require_once("$CFG->libdir/filelib.php");
|
||||
require_once($CFG->dirroot.'/grade/grading/form/'.$method.'/lib.php');
|
||||
$details = call_user_func('gradingform_'.$method.'_controller::get_external_definition_details');
|
||||
$methodarray = array();
|
||||
foreach (array_keys($details) as $definitionkey) {
|
||||
$items = array();
|
||||
$idnumber = 1;
|
||||
foreach ($definition[$method][$definitionkey] as $item) {
|
||||
$processeditem = self::set_new_ids($item, $idnumber);
|
||||
$items[$processeditem['id']] = $processeditem;
|
||||
$idnumber++;
|
||||
}
|
||||
$definitionobjectkey = substr($definitionkey, strlen($method.'_'));
|
||||
$methodarray[$definitionobjectkey] = $items;
|
||||
$definitionobject->$method = $methodarray;
|
||||
}
|
||||
|
||||
return $definitionobject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively iterates through arrays. Any array without an id key-value combination
|
||||
* is assumed to be an array of values to be inserted and an id key-value is added with
|
||||
* the value matching the regex '/^NEWID\d+$/' that is expected by each grading form implementation.
|
||||
*
|
||||
* @param array $arraytoset the array to be processed
|
||||
* @param int $startnumber the starting number for the new id numbers
|
||||
* @return array with missing id keys added for all arrays
|
||||
* @since Moodle 2.8
|
||||
*/
|
||||
private static function set_new_ids($arraytoset, $startnumber) {
|
||||
$result = array();
|
||||
$foundid = false;
|
||||
$number = $startnumber;
|
||||
foreach ($arraytoset as $key1 => $value1) {
|
||||
if (is_array($value1)) {
|
||||
foreach ($value1 as $key2 => $value2) {
|
||||
$processedvalue = self::set_new_ids($value2, $number);
|
||||
$result[$key1][$processedvalue['id']] = $processedvalue;
|
||||
$number++;
|
||||
}
|
||||
} else {
|
||||
$result[$key1] = $value1;
|
||||
}
|
||||
if ($key1 === 'id') {
|
||||
$foundid = true;
|
||||
}
|
||||
}
|
||||
if (!$foundid) {
|
||||
$result['id'] = 'NEWID'.$number;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -825,6 +825,13 @@ $functions = array(
|
|||
'type' => 'read'
|
||||
),
|
||||
|
||||
'core_grading_save_definitions' => array(
|
||||
'classname' => 'core_grading_external',
|
||||
'methodname' => 'save_definitions',
|
||||
'description' => 'Save grading definitions',
|
||||
'type' => 'write'
|
||||
),
|
||||
|
||||
'core_grading_get_gradingform_instances' => array(
|
||||
'classname' => 'core_grading_external',
|
||||
'methodname' => 'get_gradingform_instances',
|
||||
|
|
|
@ -298,4 +298,344 @@ class core_grading_externallib_testcase extends externallib_advanced_testcase {
|
|||
$this->assertEquals($levelid, $criteria[$criterionid]['levelid']);
|
||||
$this->assertEquals('excellent work', $criteria[$criterionid]['remark']);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Test save_definitions for rubric grading method
|
||||
*/
|
||||
public function test_save_definitions_rubric() {
|
||||
global $DB, $CFG, $USER;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
// Create a course and assignment.
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
|
||||
$params['course'] = $course->id;
|
||||
$instance = $generator->create_instance($params);
|
||||
$cm = get_coursemodule_from_instance('assign', $instance->id);
|
||||
$context = context_module::instance($cm->id);
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
|
||||
// Create the teacher.
|
||||
$teacher = self::getDataGenerator()->create_user();
|
||||
$USER->id = $teacher->id;
|
||||
$teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
|
||||
$this->assignUserCapability('moodle/grade:managegradingforms', $context->id, $teacherrole->id);
|
||||
$this->getDataGenerator()->enrol_user($teacher->id,
|
||||
$course->id,
|
||||
$teacherrole->id);
|
||||
|
||||
// The grading area to insert.
|
||||
$gradingarea = array(
|
||||
'cmid' => $cm->id,
|
||||
'contextid' => $context->id,
|
||||
'component' => 'mod_assign',
|
||||
'areaname' => 'submissions',
|
||||
'activemethod' => 'rubric'
|
||||
);
|
||||
|
||||
// The rubric definition to insert.
|
||||
$rubricdefinition = array(
|
||||
'method' => 'rubric',
|
||||
'name' => 'test',
|
||||
'description' => '',
|
||||
'status' => 20,
|
||||
'copiedfromid' => 1,
|
||||
'timecreated' => 1,
|
||||
'usercreated' => $teacher->id,
|
||||
'timemodified' => 1,
|
||||
'usermodified' => $teacher->id,
|
||||
'timecopied' => 0
|
||||
);
|
||||
|
||||
// The criterion to insert.
|
||||
$rubriccriteria1 = array (
|
||||
'sortorder' => 1,
|
||||
'description' => 'Demonstrate an understanding of disease control',
|
||||
'descriptionformat' => 0
|
||||
);
|
||||
|
||||
// 3 levels for the criterion.
|
||||
$rubriclevel1 = array (
|
||||
'score' => 50,
|
||||
'definition' => 'pass',
|
||||
'definitionformat' => 0
|
||||
);
|
||||
$rubriclevel2 = array (
|
||||
'score' => 100,
|
||||
'definition' => 'excellent',
|
||||
'definitionformat' => 0
|
||||
);
|
||||
$rubriclevel3 = array (
|
||||
'score' => 0,
|
||||
'definition' => 'fail',
|
||||
'definitionformat' => 0
|
||||
);
|
||||
|
||||
$rubriccriteria1['levels'] = array($rubriclevel1, $rubriclevel2, $rubriclevel3);
|
||||
$rubricdefinition['rubric'] = array('rubric_criteria' => array($rubriccriteria1));
|
||||
$gradingarea['definitions'] = array($rubricdefinition);
|
||||
|
||||
$results = core_grading_external::save_definitions(array($gradingarea));
|
||||
|
||||
$area = $DB->get_record('grading_areas',
|
||||
array('contextid' => $context->id, 'component' => 'mod_assign', 'areaname' => 'submissions'),
|
||||
'*', MUST_EXIST);
|
||||
$this->assertEquals($area->activemethod, 'rubric');
|
||||
|
||||
$definition = $DB->get_record('grading_definitions', array('areaid' => $area->id, 'method' => 'rubric'), '*', MUST_EXIST);
|
||||
$this->assertEquals($rubricdefinition['name'], $definition->name);
|
||||
|
||||
$criterion1 = $DB->get_record('gradingform_rubric_criteria', array('definitionid' => $definition->id), '*', MUST_EXIST);
|
||||
$levels = $DB->get_records('gradingform_rubric_levels', array('criterionid' => $criterion1->id));
|
||||
$validlevelcount = 0;
|
||||
$expectedvalue = true;
|
||||
foreach ($levels as $level) {
|
||||
if ($level->score == 0) {
|
||||
$this->assertEquals('fail', $level->definition);
|
||||
$validlevelcount++;
|
||||
} else if ($level->score == 50) {
|
||||
$this->assertEquals('pass', $level->definition);
|
||||
$validlevelcount++;
|
||||
} else if ($level->score == 100) {
|
||||
$this->assertEquals('excellent', $level->definition);
|
||||
$excellentlevelid = $level->id;
|
||||
$validlevelcount++;
|
||||
} else {
|
||||
$expectedvalue = false;
|
||||
}
|
||||
}
|
||||
$this->assertEquals(3, $validlevelcount);
|
||||
$this->assertTrue($expectedvalue, 'A level with an unexpected score was found');
|
||||
|
||||
// Test add a new level and modify an existing.
|
||||
// Test add a new criteria and modify an existing.
|
||||
// Test modify a definition.
|
||||
|
||||
// The rubric definition to update.
|
||||
$rubricdefinition = array(
|
||||
'id' => $definition->id,
|
||||
'method' => 'rubric',
|
||||
'name' => 'test changed',
|
||||
'description' => '',
|
||||
'status' => 20,
|
||||
'copiedfromid' => 1,
|
||||
'timecreated' => 1,
|
||||
'usercreated' => $teacher->id,
|
||||
'timemodified' => 1,
|
||||
'usermodified' => $teacher->id,
|
||||
'timecopied' => 0
|
||||
);
|
||||
|
||||
// A criterion to update.
|
||||
$rubriccriteria1 = array (
|
||||
'id' => $criterion1->id,
|
||||
'sortorder' => 1,
|
||||
'description' => 'Demonstrate an understanding of rabies control',
|
||||
'descriptionformat' => 0
|
||||
);
|
||||
|
||||
// A new criterion to add.
|
||||
$rubriccriteria2 = array (
|
||||
'sortorder' => 2,
|
||||
'description' => 'Demonstrate an understanding of anthrax control',
|
||||
'descriptionformat' => 0
|
||||
);
|
||||
|
||||
// A level to update.
|
||||
$rubriclevel2 = array (
|
||||
'id' => $excellentlevelid,
|
||||
'score' => 75,
|
||||
'definition' => 'excellent',
|
||||
'definitionformat' => 0
|
||||
);
|
||||
|
||||
// A level to insert.
|
||||
$rubriclevel4 = array (
|
||||
'score' => 100,
|
||||
'definition' => 'superb',
|
||||
'definitionformat' => 0
|
||||
);
|
||||
|
||||
$rubriccriteria1['levels'] = array($rubriclevel1, $rubriclevel2, $rubriclevel3, $rubriclevel4);
|
||||
$rubricdefinition['rubric'] = array('rubric_criteria' => array($rubriccriteria1, $rubriccriteria2));
|
||||
$gradingarea['definitions'] = array($rubricdefinition);
|
||||
|
||||
$results = core_grading_external::save_definitions(array($gradingarea));
|
||||
|
||||
// Test definition name change.
|
||||
$definition = $DB->get_record('grading_definitions', array('id' => $definition->id), '*', MUST_EXIST);
|
||||
$this->assertEquals('test changed', $definition->name);
|
||||
|
||||
// Test criteria description change.
|
||||
$modifiedcriteria = $DB->get_record('gradingform_rubric_criteria', array('id' => $criterion1->id), '*', MUST_EXIST);
|
||||
$this->assertEquals('Demonstrate an understanding of rabies control', $modifiedcriteria->description);
|
||||
|
||||
// Test new criteria added.
|
||||
$newcriteria = $DB->get_record('gradingform_rubric_criteria',
|
||||
array('definitionid' => $definition->id, 'sortorder' => 2), '*', MUST_EXIST);
|
||||
$this->assertEquals('Demonstrate an understanding of anthrax control', $newcriteria->description);
|
||||
|
||||
// Test excellent level score change from 100 to 75.
|
||||
$modifiedlevel = $DB->get_record('gradingform_rubric_levels', array('id' => $excellentlevelid), '*', MUST_EXIST);
|
||||
$this->assertEquals(75, $modifiedlevel->score);
|
||||
|
||||
// Test new superb level added.
|
||||
$newlevel = $DB->get_record('gradingform_rubric_levels',
|
||||
array('criterionid' => $criterion1->id, 'score' => 100), '*', MUST_EXIST);
|
||||
$this->assertEquals('superb', $newlevel->definition);
|
||||
|
||||
// Test remove a level
|
||||
// Test remove a criterion
|
||||
// The rubric definition with the removed criterion and levels.
|
||||
$rubricdefinition = array(
|
||||
'id' => $definition->id,
|
||||
'method' => 'rubric',
|
||||
'name' => 'test changed',
|
||||
'description' => '',
|
||||
'status' => 20,
|
||||
'copiedfromid' => 1,
|
||||
'timecreated' => 1,
|
||||
'usercreated' => $teacher->id,
|
||||
'timemodified' => 1,
|
||||
'usermodified' => $teacher->id,
|
||||
'timecopied' => 0
|
||||
);
|
||||
|
||||
$rubriccriteria1 = array (
|
||||
'id' => $criterion1->id,
|
||||
'sortorder' => 1,
|
||||
'description' => 'Demonstrate an understanding of rabies control',
|
||||
'descriptionformat' => 0
|
||||
);
|
||||
|
||||
$rubriclevel1 = array (
|
||||
'score' => 0,
|
||||
'definition' => 'fail',
|
||||
'definitionformat' => 0
|
||||
);
|
||||
$rubriclevel2 = array (
|
||||
'score' => 100,
|
||||
'definition' => 'pass',
|
||||
'definitionformat' => 0
|
||||
);
|
||||
|
||||
$rubriccriteria1['levels'] = array($rubriclevel1, $rubriclevel2);
|
||||
$rubricdefinition['rubric'] = array('rubric_criteria' => array($rubriccriteria1));
|
||||
$gradingarea['definitions'] = array($rubricdefinition);
|
||||
|
||||
$results = core_grading_external::save_definitions(array($gradingarea));
|
||||
|
||||
// Only 1 criterion should now exist.
|
||||
$this->assertEquals(1, $DB->count_records('gradingform_rubric_criteria', array('definitionid' => $definition->id)));
|
||||
$criterion1 = $DB->get_record('gradingform_rubric_criteria', array('definitionid' => $definition->id), '*', MUST_EXIST);
|
||||
$this->assertEquals('Demonstrate an understanding of rabies control', $criterion1->description);
|
||||
// This criterion should only have 2 levels.
|
||||
$this->assertEquals(2, $DB->count_records('gradingform_rubric_levels', array('criterionid' => $criterion1->id)));
|
||||
|
||||
$gradingarea['activemethod'] = 'invalid';
|
||||
$this->setExpectedException('moodle_exception');
|
||||
$results = core_grading_external::save_definitions(array($gradingarea));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Tests save_definitions for the marking guide grading method
|
||||
*/
|
||||
public function test_save_definitions_marking_guide() {
|
||||
global $DB, $CFG, $USER;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
// Create a course and assignment.
|
||||
$course = self::getDataGenerator()->create_course();
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
|
||||
$params['course'] = $course->id;
|
||||
$instance = $generator->create_instance($params);
|
||||
$cm = get_coursemodule_from_instance('assign', $instance->id);
|
||||
$context = context_module::instance($cm->id);
|
||||
$coursecontext = context_course::instance($course->id);
|
||||
|
||||
// Create the teacher.
|
||||
$teacher = self::getDataGenerator()->create_user();
|
||||
$USER->id = $teacher->id;
|
||||
$teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
|
||||
$this->assignUserCapability('moodle/grade:managegradingforms', $context->id, $teacherrole->id);
|
||||
$this->getDataGenerator()->enrol_user($teacher->id,
|
||||
$course->id,
|
||||
$teacherrole->id);
|
||||
|
||||
// Test insert a grading area with guide definition, criteria and comments.
|
||||
$gradingarea = array(
|
||||
'cmid' => $cm->id,
|
||||
'contextid' => $context->id,
|
||||
'component' => 'mod_assign',
|
||||
'areaname' => 'submissions',
|
||||
'activemethod' => 'guide'
|
||||
);
|
||||
|
||||
$guidedefinition = array(
|
||||
'method' => 'guide',
|
||||
'name' => 'test',
|
||||
'description' => '',
|
||||
'status' => 20,
|
||||
'copiedfromid' => 1,
|
||||
'timecreated' => 1,
|
||||
'usercreated' => $teacher->id,
|
||||
'timemodified' => 1,
|
||||
'usermodified' => $teacher->id,
|
||||
'timecopied' => 0
|
||||
);
|
||||
|
||||
$guidecomment = array(
|
||||
'sortorder' => 1,
|
||||
'description' => 'Students need to show that they understand the control of zoonoses',
|
||||
'descriptionformat' => 0
|
||||
);
|
||||
$guidecriteria1 = array (
|
||||
'sortorder' => 1,
|
||||
'shortname' => 'Rabies Control',
|
||||
'description' => 'Understand rabies control techniques',
|
||||
'descriptionformat' => 0,
|
||||
'descriptionmarkers' => 'Student must demonstrate that they understand rabies control',
|
||||
'descriptionmarkersformat' => 0,
|
||||
'maxscore' => 50
|
||||
);
|
||||
$guidecriteria2 = array (
|
||||
'sortorder' => 2,
|
||||
'shortname' => 'Anthrax Control',
|
||||
'description' => 'Understand anthrax control',
|
||||
'descriptionformat' => 0,
|
||||
'descriptionmarkers' => 'Student must demonstrate that they understand anthrax control',
|
||||
'descriptionmarkersformat' => 0,
|
||||
'maxscore' => 50
|
||||
);
|
||||
|
||||
$guidedefinition['guide'] = array('guide_criteria' => array($guidecriteria1, $guidecriteria2),
|
||||
'guide_comments' => array($guidecomment));
|
||||
$gradingarea['definitions'] = array($guidedefinition);
|
||||
|
||||
$results = core_grading_external::save_definitions(array($gradingarea));
|
||||
$area = $DB->get_record('grading_areas',
|
||||
array('contextid' => $context->id, 'component' => 'mod_assign', 'areaname' => 'submissions'),
|
||||
'*', MUST_EXIST);
|
||||
$this->assertEquals($area->activemethod, 'guide');
|
||||
|
||||
$definition = $DB->get_record('grading_definitions', array('areaid' => $area->id, 'method' => 'guide'), '*', MUST_EXIST);
|
||||
$this->assertEquals($guidedefinition['name'], $definition->name);
|
||||
$this->assertEquals(2, $DB->count_records('gradingform_guide_criteria', array('definitionid' => $definition->id)));
|
||||
$this->assertEquals(1, $DB->count_records('gradingform_guide_comments', array('definitionid' => $definition->id)));
|
||||
|
||||
// Test removal of a criteria.
|
||||
$guidedefinition['guide'] = array('guide_criteria' => array($guidecriteria1),
|
||||
'guide_comments' => array($guidecomment));
|
||||
$gradingarea['definitions'] = array($guidedefinition);
|
||||
$results = core_grading_external::save_definitions(array($gradingarea));
|
||||
$this->assertEquals(1, $DB->count_records('gradingform_guide_criteria', array('definitionid' => $definition->id)));
|
||||
|
||||
// Test an invalid method in the definition.
|
||||
$guidedefinition['method'] = 'invalid';
|
||||
$gradingarea['definitions'] = array($guidedefinition);
|
||||
$this->setExpectedException('invalid_parameter_exception');
|
||||
$results = core_grading_external::save_definitions(array($gradingarea));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue