From 89c1aa977b9c1ac6d51dee7807d56efbdb629db7 Mon Sep 17 00:00:00 2001 From: David Mudrak Date: Mon, 4 Jan 2010 18:11:48 +0000 Subject: [PATCH] MDL-20058 Grading report, aggregation of submission grades Not finished yet --- mod/workshop/aggregate.php | 61 +++++++++++++ mod/workshop/db/install.xml | 11 ++- mod/workshop/lang/en_utf8/workshop.php | 5 ++ mod/workshop/locallib.php | 116 ++++++++++++++++++++++++- mod/workshop/version.php | 2 +- mod/workshop/view.php | 2 +- 6 files changed, 185 insertions(+), 12 deletions(-) create mode 100644 mod/workshop/aggregate.php diff --git a/mod/workshop/aggregate.php b/mod/workshop/aggregate.php new file mode 100644 index 0000000000..459c89f122 --- /dev/null +++ b/mod/workshop/aggregate.php @@ -0,0 +1,61 @@ +. + +/** + * Aggregates the grades for submission and grades for assessments and calculates the total grade for workshop + * + * @package mod-workshop + * @copyright 2009 David Mudrak + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); +require_once(dirname(__FILE__).'/locallib.php'); + +$cmid = required_param('cmid', PARAM_INT); // course module +$confirm = optional_param('confirm', false, PARAM_BOOL); // confirmation + +$cm = get_coursemodule_from_id('workshop', $cmid, 0, false, MUST_EXIST); +$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); +$workshop = $DB->get_record('workshop', array('id' => $cm->instance), '*', MUST_EXIST); +$workshop = new workshop($workshop, $cm, $course); + +$PAGE->set_url(new moodle_url($workshop->aggregate_url(), array('cmid' => $cmid))); + +require_login($course, false, $cm); +require_capability('mod/workshop:overridegrades', $PAGE->context); + +if ($confirm) { + if (!confirm_sesskey()) { + throw new moodle_exception('confirmsesskeybad'); + } + $workshop->update_submission_grades(); + $workshop->update_grading_grades(); + redirect($workshop->view_url()); +} + +$PAGE->set_title($workshop->name); +$PAGE->set_heading($course->fullname); +$PAGE->navbar->add(get_string('aggregation', 'workshop')); + +// +// Output starts here +// +echo $OUTPUT->header(); +echo $OUTPUT->confirm(get_string('aggregationinfo', 'workshop'), + new moodle_url($PAGE->url, array('confirm' => 1)), $workshop->view_url()); +echo $OUTPUT->footer(); diff --git a/mod/workshop/db/install.xml b/mod/workshop/db/install.xml index 5e31da1367..75e29dffd1 100644 --- a/mod/workshop/db/install.xml +++ b/mod/workshop/db/install.xml @@ -109,15 +109,14 @@ - +
- - - - - + + + + diff --git a/mod/workshop/lang/en_utf8/workshop.php b/mod/workshop/lang/en_utf8/workshop.php index e985496a98..53a3a57496 100644 --- a/mod/workshop/lang/en_utf8/workshop.php +++ b/mod/workshop/lang/en_utf8/workshop.php @@ -28,6 +28,11 @@ defined('MOODLE_INTERNAL') || die(); $string[''] = ''; $string[''] = ''; $string[''] = ''; +$string[''] = ''; +$string[''] = ''; +$string['aggregationinfo'] = 'During the aggregation process, the grades for submission, grades for assessment and total grades are re-calculated and stored into the Workshop database. This does not modify any manual overrides nor does not push the total grade into the gradebook.'; +$string['aggregation'] = 'Grades aggregation'; +$string['aggregategrades'] = 'Re-calculate grades'; $string['nullgrade'] = '?'; $string['formatpeergradeover'] = '$a->grade ($a->gradinggrade / $a->gradinggradeover)'; $string['formatpeergrade'] = '$a->grade ($a->gradinggrade)'; diff --git a/mod/workshop/locallib.php b/mod/workshop/locallib.php index d5655a73c4..64899a6177 100644 --- a/mod/workshop/locallib.php +++ b/mod/workshop/locallib.php @@ -30,8 +30,8 @@ defined('MOODLE_INTERNAL') || die(); -require_once(dirname(__FILE__).'/lib.php'); // we extend this library here -require_once($CFG->libdir . '/gradelib.php'); +require_once(dirname(__FILE__).'/lib.php'); // we extend this library here +require_once($CFG->libdir . '/gradelib.php'); // we use some rounding and comparing routines here /** * Full-featured workshop API @@ -587,6 +587,14 @@ class workshop { return new moodle_url($CFG->wwwroot . '/mod/workshop/switchphase.php', array('cmid' => $this->cm->id, 'phase' => $phasecode)); } + /** + * @return moodle_url to the aggregation page + */ + public function aggregate_url() { + global $CFG; + return new moodle_url($CFG->wwwroot . '/mod/workshop/aggregate.php', array('cmid' => $this->cm->id)); + } + /** * Returns an object containing all data to display the user's full name and picture * @@ -960,10 +968,10 @@ class workshop { $params['workshopid'] = $this->id; $sqlsort = $sortby . ' ' . $sorthow . ',u.lastname,u.firstname,u.id'; $sql = "SELECT u.id AS userid,u.firstname,u.lastname,u.picture,u.imagealt, - s.title AS submissiontitle, a.submissiongrade, a.gradinggrade, a.totalgrade + s.title AS submissiontitle, s.grade AS submissiongrade, ag.gradinggrade, ag.totalgrade FROM {user} u LEFT JOIN {workshop_submissions} s ON (s.authorid = u.id) - LEFT JOIN {workshop_aggregations} a ON (a.userid = u.id) + LEFT JOIN {workshop_aggregations} ag ON (ag.userid = u.id AND ag.workshopid = s.workshopid) WHERE s.workshopid = :workshopid AND s.example = 0 AND u.id $participantids ORDER BY $sqlsort"; $participants = $DB->get_records_sql($sql, $params, $page * $perpage, $perpage); @@ -1120,6 +1128,106 @@ class workshop { return grade_floatval((float)$grade + (float)$gradinggrade); } + /** + * Calculates grades for submission for the given participant(s) + * + * Grade for submission is calculated as a weighted mean of all given grades + * + * @param null|int|array $restrict If null, update all authors, otherwise update just grades for the given author(s) + * @return void + */ + public function update_submission_grades($restrict=null) { + global $DB; + + // fetch a recordset with all assessments to process + $sql = 'SELECT s.id AS submissionid, s.authorid, s.grade AS submissiongrade, s.gradeover, s.gradeoverby, + a.weight, a.grade + FROM {workshop_submissions} s + LEFT JOIN {workshop_assessments} a ON (a.submissionid = s.id) + WHERE s.example=0 AND s.workshopid=:workshopid'; // to be cont. + $params = array('workshopid' => $this->id); + + if (is_null($restrict)) { + // update all users - no more conditions + } elseif (!empty($restrict)) { + list($usql, $uparams) = $DB->get_in_or_equal($restrict, SQL_PARAMS_NAMED); + $sql .= " AND s.authorid $usql"; + $params = array_merge($params, $uparams); + } else { + throw new coding_exception('Empty value is not a valid parameter here'); + } + + $sql .= ' ORDER BY s.id'; // this is important for bulk processing + $rs = $DB->get_recordset_sql($sql, $params); + + $previous = null; + foreach ($rs as $current) { + if (is_null($previous)) { + // we are processing the very first record in the recordset + $previous = $current; + $sumgrades = 0; + $sumweights = 0; + } + if (is_null($current->grade)) { + // this was not assessed yet + continue; + } + if ($current->weight == 0) { + // this does not influence the calculation + continue; + } + if ($current->submissionid != $previous->submissionid) { + // firstly finish the calculation for the previous submission as we now have all its data + if ($sumweights > 0) { + // there is a chance that the aggregated grade has changed + $finalgrade = $sumgrades / $sumweights; + if (grade_floats_different($finalgrade, $previous->submissiongrade)) { + // we need to save new calculation into the database + $DB->set_field('workshop_submissions', 'grade', $finalgrade, array('id' => $previous->submissionid)); + } + } + // and then start to process another submission + $previous = $current; + if (is_null($current->grade)) { + $sumgrades = 0; + } else { + $sumgrades = $current->grade; + } + $sumweights = $current->weight; + continue; + } else { + // we are still processing the current submission + $sumgrades += $current->grade * $current->weight; + $sumweights += $current->weight; + continue; + } + } + // finally we must calculate the last submission's grade as it was not done in the previous loop + if ($sumweights > 0) { + // there is a chance that the aggregated grade has changed + $finalgrade = $sumgrades / $sumweights; + if (grade_floats_different($finalgrade, $current->submissiongrade)) { + // we need to save new calculation into the database + $DB->set_field('workshop_submissions', 'grade', $finalgrade, array('id' => $current->submissionid)); + } + } + $rs->close(); + } + + /** + * Calculates grades for assessment for the given participant(s) + * + * Grade for submission is calculated as a weighted mean of all given grades + * + * @param null|int|array $restrict If null, update all reviewers, otherwise update just grades for the given reviewer(s) + * @return void + */ + public function update_grading_grades($restrict=null) { + global $DB; + + // todo + } + //////////////////////////////////////////////////////////////////////////////// // Internal methods (implementation details) // //////////////////////////////////////////////////////////////////////////////// diff --git a/mod/workshop/version.php b/mod/workshop/version.php index 58d7bac505..3745395921 100644 --- a/mod/workshop/version.php +++ b/mod/workshop/version.php @@ -28,6 +28,6 @@ defined('MOODLE_INTERNAL') || die(); -$module->version = 2009092900; +$module->version = 2009092901; $module->requires = 2009090400; // Requires this Moodle version $module->cron = 60; diff --git a/mod/workshop/view.php b/mod/workshop/view.php index 066980687e..035a0ea1c6 100644 --- a/mod/workshop/view.php +++ b/mod/workshop/view.php @@ -160,7 +160,7 @@ case workshop::PHASE_EVALUATION: $page = optional_param($pagingvar, 0, PARAM_INT); $perpage = 10; // todo let the user modify this $groups = ''; // todo let the user choose the group - $sortby = 'totalgrade'; // todo let the user choose the column to sort by + $sortby = 'submissiongrade'; // todo let the user choose the column to sort by $sorthow = 'DESC'; // todo detto $data = $workshop->prepare_grading_report($USER->id, $groups, $page, $perpage, $sortby, $sorthow); -- 2.39.5