// Note: We use jQuery.serializer here until we can rewrite Ajax to use XHR.send()
import jQuery from 'jquery';
+/**
+ * For a given component, contextid, itemname & gradeduserid we can fetch the currently assigned grade.
+ *
+ * @param {String} component
+ * @param {Number} contextid
+ * @param {String} itemname
+ * @param {Number} gradeduserid
+ *
+ * @returns {Promise}
+ */
export const fetchCurrentGrade = (component, contextid, itemname, gradeduserid) => {
return fetchMany([{
methodname: `gradingform_rubric_grader_gradingpanel_fetch`,
}])[0];
};
-
+/**
+ * For a given component, contextid, itemname & gradeduserid we can store the currently assigned grade in a given form.
+ *
+ * @param {String} component
+ * @param {Number} contextid
+ * @param {String} itemname
+ * @param {Number} gradeduserid
+ * @param {HTMLElement} rootNode
+ *
+ * @returns {Promise}
+ */
export const storeCurrentGrade = async(component, contextid, itemname, gradeduserid, rootNode) => {
const form = rootNode.querySelector('form');
namespace gradingform_rubric\grades\grader\gradingpanel\external;
+global $CFG;
+
use coding_exception;
use context;
use core_grades\component_gradeitem as gradeitem;
use external_warnings;
use stdClass;
use moodle_exception;
+require_once($CFG->dirroot.'/grade/grading/form/rubric/lib.php');
/**
* Web services relating to fetching of a rubric for the grading panel.
* @since Moodle 3.8
*/
public static function execute(string $component, int $contextid, string $itemname, int $gradeduserid): array {
- global $USER;
-
[
'component' => $component,
'contextid' => $contextid,
// Fetch the gradeitem instance.
$gradeitem = gradeitem::instance($component, $context, $itemname);
- if ('rubric' !== $gradeitem->get_advanced_grading_method()) {
+ if (RUBRIC !== $gradeitem->get_advanced_grading_method()) {
throw new moodle_exception(
"The {$itemname} item in {$component}/{$contextid} is not configured for advanced grading with a rubric"
);
}
/**
- * Get the data to be fetched.
+ * Get the data to be fetched and create the structure ready for Mustache.
*
* @param gradeitem $gradeitem
* @param stdClass $gradeduser
public static function get_fetch_data(gradeitem $gradeitem, stdClass $gradeduser): array {
global $USER;
+ // Set up all the controllers etc that we'll be needing.
$grade = $gradeitem->get_grade_for_user($gradeduser, $USER);
$instance = $gradeitem->get_advanced_grading_instance($USER, $grade);
$controller = $instance->get_controller();
$criterion = [];
if ($definition->rubric_criteria) {
+ // Iterate over the defined criterion in the rubric and map out what we need to render each item.
$criterion = array_map(function($criterion) use ($definitionid, $fillings, $context) {
+ // The general structure we'll be returning, we still need to get the remark (if any) and the levels associated.
$result = [
'id' => $criterion['id'],
'description' => self::get_formatted_text(
),
];
+ // Do we have an existing grade filling? if so lets get the remark associated to this criteria.
$filling = [];
if (array_key_exists($criterion['id'], $fillings['criteria'])) {
$filling = $fillings['criteria'][$criterion['id']];
);
}
+ // Lets build the levels within a criteria and figure out what needs to go where.
$result['levels'] = array_map(function($level) use ($criterion, $filling, $context, $definitionid) {
+ // The bulk of what'll be returned can be defined easily we'll add to this further down.
$result = [
'id' => $level['id'],
'criterionid' => $criterion['id'],
'checked' => null,
];
+ // Consult the grade filling to see if a level has been selected and if it is the current level.
if (array_key_exists('levelid', $filling) && $filling['levelid'] == $level['id']) {
$result['checked'] = true;
}
return $result;
}, $criterion['levels']);
+ $nulllevel = [
+ 'id' => null,
+ 'criterionid' => $criterion['id'],
+ 'score' => '-',
+ 'definition' => 'Not set',
+ 'checked' => null,
+ ];
+ // Consult the grade filling to see if a level has been selected and if it is the current level.
+ if (array_key_exists('levelid', $filling) && $filling['levelid'] == 0) {
+ $nulllevel['checked'] = true;
+ }
+
+ array_unshift($result['levels'], $nulllevel);
+
return $result;
}, $definition->rubric_criteria);
}
'levels' => new external_multiple_structure(new external_single_structure([
'id' => new external_value(PARAM_INT, 'ID of level'),
'criterionid' => new external_value(PARAM_INT, 'ID of the criterion this matches to'),
- 'score' => new external_value(PARAM_INT, 'What this level is worth'),
+ 'score' => new external_value(PARAM_RAW, 'What this level is worth'),
'definition' => new external_value(PARAM_RAW, 'Definition of the level'),
'checked' => new external_value(PARAM_BOOL, 'Selected flag'),
])),
namespace gradingform_rubric\grades\grader\gradingpanel\external;
+global $CFG;
+
use coding_exception;
use context;
use core_grades\component_gradeitem as gradeitem;
use external_single_structure;
use external_value;
use moodle_exception;
+require_once($CFG->dirroot.'/grade/grading/form/rubric/lib.php');
/**
* Web services relating to storing of a rubric for the grading panel.
// Require that this user can save grades.
$gradeitem->require_user_can_grade($gradeduser, $USER);
- if ('rubric' !== $gradeitem->get_advanced_grading_method()) {
+ if (RUBRIC !== $gradeitem->get_advanced_grading_method()) {
throw new moodle_exception(
"The {$itemname} item in {$component}/{$contextid} is not configured for advanced grading with a rubric"
);
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
+defined('MOODLE_INTERNAL') || die;
+
$functions = [
'gradingform_rubric_grader_gradingpanel_fetch' => [
'classname' => 'gradingform_rubric\\grades\\grader\\gradingpanel\\external\\fetch',
require_once($CFG->dirroot.'/grade/grading/form/lib.php');
require_once($CFG->dirroot.'/lib/filelib.php');
+/** rubric: Used to compare our gradeitem_type against. */
+const RUBRIC = 'rubric';
+
/**
* This controller encapsulates the rubric grading logic
*
@template gradingform_rubric/grades/grader/gradingpanel
Classes required for JS:
- * TODO
+ * none
Data attributes required for JS:
- * TODO
+ * none
Context variables required for this template:
- * TODO
+ * instanceid: Instance of the module this grading form belongs too
+ * criteria: A gradeable item in the Marking Guide
+ * id: The ID of the criteria
+ * description: Description of the criteria
+ * levels: The level that a criteria can be graded at
+ * criterionid: The ID of the criteria
+ * checked: Flag for if this is the currently selected level
+ * definition: Definition of the level
+ * remark: Text input for the teacher to relay to the student
Example context (json):
{
+ "instanceid": "42",
+ "criteria": [
+ {
+ "id": 13,
+ "description": "Show your motivation to rock climbing",
+ "levels": [
+ {
+ "criterionid": 13,
+ "checked": true,
+ "definition": "Great work!"
+ }
+ ],
+ "remark": "That's great!"
+ }
+ ]
}
}}
<form id="gradingform_rubric-{{uniqid}}">
<input type="hidden" name="instanceid" value="{{instanceid}}">
- <div class="gradingform_rubric-description">{{{teacherdescription}}}</div>
<div id="rubric-advancedgrading-{{uniqid}}" class="criterion">
{{#criteria}}
<div class="d-block mb-2">
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
-defined('MOODLE_INTERNAL') || die();
-
/**
* Coverage information for the gradingform_rubric plugin.
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
+defined('MOODLE_INTERNAL') || die();
+
/**
* Coverage information for the gradingform_rubric plugin.
*
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
return new class extends phpunit_coverage_info {
- /** @var array The list of folders relative to the plugin root to whitelist in coverage generation. */
+ // Array The list of folders relative to the plugin root to whitelist in coverage generation.
protected $whitelistfolders = [
'classes',
'tests/generator',
/**
* Unit tests for core_grades\component_gradeitems;
*
- * @package core_grades
+ * @package gradingform_rubric
* @category test
* @copyright 2019 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
/**
* Unit tests for core_grades\component_gradeitems;
*
- * @package core_grades
+ * @package gradingform_rubric
* @category test
* @copyright 2019 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
$levels = $criterion['levels'];
foreach ($levels as $level) {
$levelid = $level['id'];
+ if (!isset($levelid)) {
+ continue;
+ }
$sourcelevel = $sourcecriterion['levels'][$levelid];
$this->assertArrayHasKey('criterionid', $level);
$levels = $criterion['levels'];
foreach ($levels as $level) {
$levelid = $level['id'];
+ if (!isset($levelid)) {
+ continue;
+ }
$sourcelevel = $sourcecriterion['levels'][$levelid];
$this->assertArrayHasKey('criterionid', $level);
}
- $this->assertEquals(1, $criteria[0]['levels'][0]['checked']);
+ $this->assertEquals(1, $criteria[0]['levels'][1]['checked']);
$this->assertEquals('Too many mistakes. Please try again.', $criteria[0]['remark']);
- $this->assertEquals(1, $criteria[1]['levels'][2]['checked']);
+ $this->assertEquals(1, $criteria[1]['levels'][3]['checked']);
$this->assertEquals('Great number of pictures. Well done.', $criteria[1]['remark']);
}
/**
* Unit tests for core_grades\component_gradeitems;
*
- * @package core_grades
+ * @package gradingform_rubric
* @category test
* @copyright 2019 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
/**
* Unit tests for core_grades\component_gradeitems;
*
- * @package core_grades
+ * @package gradingform_rubric
* @category test
* @copyright 2019 Mathew May <mathew.solutions>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
$gradeitem = component_gradeitem::instance('mod_forum', $forum->get_context(), 'forum');
$this->expectException(moodle_exception::class);
- //$this->expectExceptionMessage("not configured for advanced grading with a rubric");
store::execute('mod_forum', (int) $forum->get_context()->id, 'forum', (int) $student->id, 'formdata');
}
$levels = $criterion['levels'];
foreach ($levels as $level) {
$levelid = $level['id'];
+ if (!isset($levelid)) {
+ continue;
+ }
$sourcelevel = $sourcecriterion['levels'][$levelid];
$this->assertArrayHasKey('criterionid', $level);
}
- $this->assertEquals(1, $criteria[0]['levels'][0]['checked']);
+ $this->assertEquals(1, $criteria[0]['levels'][1]['checked']);
$this->assertEquals('Too many mistakes. Please try again.', $criteria[0]['remark']);
- $this->assertEquals(1, $criteria[1]['levels'][2]['checked']);
+ $this->assertEquals(1, $criteria[1]['levels'][3]['checked']);
$this->assertEquals('Great number of pictures. Well done.', $criteria[1]['remark']);
}