require_login($course, false, $cm);
require_capability('mod/workshop:overridegrades', $PAGE->context);
-// load the grading evaluator
+// load and init the grading evaluator
$evaluator = $workshop->grading_evaluation_instance();
+$settingsform = $evaluator->get_settings_form($PAGE->url);
-if ($confirm) {
- if (!confirm_sesskey()) {
- throw new moodle_exception('confirmsesskeybad');
- }
- $workshop->aggregate_submission_grades(); // updates 'grade' in {workshop_submissions}
- $evaluator->update_grading_grades(); // updates 'gradinggrade' in {workshop_assessments}
- $workshop->aggregate_grading_grades(); // updates 'gradinggrade' in {workshop_aggregations}
- $workshop->aggregate_total_grades(); // updates 'totalgrade' in {workshop_aggregations}
+if ($settingsform->is_cancelled()) {
+ redirect(new moodle_url($workshop->view_url(), compact('page', 'sortby', 'sorthow')));
+
+} elseif ($settingsdata = $settingsform->get_data()) {
+ $workshop->aggregate_submission_grades(); // updates 'grade' in {workshop_submissions}
+ $evaluator->update_grading_grades($settingsdata); // updates 'gradinggrade' in {workshop_assessments}
+ $workshop->aggregate_grading_grades(); // updates 'gradinggrade' in {workshop_aggregations}
+ $workshop->aggregate_total_grades(); // updates 'totalgrade' in {workshop_aggregations}
redirect(new moodle_url($workshop->view_url(), compact('page', 'sortby', 'sorthow')));
}
//
echo $OUTPUT->header();
echo $OUTPUT->confirm(get_string('aggregationinfo', 'workshop'),
- new moodle_url($PAGE->url, array('confirm' => 1)), $workshop->view_url());
+ new moodle_url($PAGE->url, $settingsdata),
+ new moodle_url($workshop->view_url(), compact('page', 'sortby', 'sorthow')));
echo $OUTPUT->footer();
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * English strings for 'best' grading evaluation subplugin
+ *
+ * @package mod-workshop
+ * @copyright 2009 David Mudrak <david.mudrak@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['comparison'] = 'Comparison of assessments';
+$string['comparisonlevel1'] = 'very strict';
+$string['comparisonlevel3'] = 'strict';
+$string['comparisonlevel5'] = 'fair';
+$string['comparisonlevel7'] = 'lax';
+$string['comparisonlevel9'] = 'very lax';
+$string['pluginname'] = 'Distance to the best assessment';
+$string['settings'] = 'Grading evaluation settings';
* @return void
*/
public function __construct(workshop $workshop) {
- $this->workshop = $workshop;
+ $this->workshop = $workshop;
}
/**
*
* @return void
*/
- public function update_grading_grades($restrict=null) {
+ public function update_grading_grades(stdClass $settings, $restrict=null) {
global $DB;
$grader = $this->workshop->grading_strategy_instance();
$batch[] = $current;
} else {
// process all the assessments of a sigle submission
- $this->process_assessments($batch, $diminfo);
+ $this->process_assessments($batch, $diminfo, $settings);
// start with a new batch to be processed
$batch = array($current);
$previous = $current;
}
}
// do not forget to process the last batch!
- $this->process_assessments($batch, $diminfo);
+ $this->process_assessments($batch, $diminfo, $settings);
$rs->close();
}
+ /**
+ * TODO: short description.
+ *
+ * @return TODO
+ */
+ public function get_settings_form(moodle_url $actionurl=null) {
+ global $CFG; // needed because the included files use it
+ require_once(dirname(__FILE__) . '/settings_form.php');
+
+ $current = null; // the recently used setting - todo where should it be stored?
+ $customdata['current'] = $current;
+ $customdata['workshop'] = $this->workshop;
+ $attributes = array('class' => 'evalsettingsform best');
+
+ return new workshop_best_evaluation_settings_form($actionurl, $customdata, 'post', '', $attributes);
+ }
+
////////////////////////////////////////////////////////////////////////////////
// Internal methods //
////////////////////////////////////////////////////////////////////////////////
*
* @param array $assessments of stdClass (->assessmentid ->assessmentweight ->reviewerid ->gradinggrade ->submissionid ->dimensionid ->grade)
* @param array $diminfo of stdClass (->id ->weight ->max ->min)
+ * @param stdClass grading evaluation settings
* @return void
*/
- protected function process_assessments(array $assessments, array $diminfo) {
+ protected function process_assessments(array $assessments, array $diminfo, stdClass $settings) {
global $DB;
// reindex the passed flat structure to be indexed by assessmentid
// for every assessment, calculate its distance from the average one
$distances = array();
foreach ($assessments as $asid => $assessment) {
- $distances[$asid] = $this->assessments_distance($assessment, $average, $diminfo);
+ $distances[$asid] = $this->assessments_distance($assessment, $average, $diminfo, $settings);
}
// identify the best assessments - it est those with the shortest distance from the best assessment
foreach ($bestids as $bestid) {
$best = $assessments[$bestid];
foreach ($assessments as $asid => $assessment) {
- $d = $this->assessments_distance($assessment, $best, $diminfo);
+ $d = $this->assessments_distance($assessment, $best, $diminfo, $settings);
if (!isset($distances[$asid]) or $d < $distances[$asid]) {
$distances[$asid] = $d;
}
// calculate the grading grade
foreach ($distances as $asid => $distance) {
$gradinggrade = (100 - $distance);
- /**
if ($gradinggrade < 0) {
$gradinggrade = 0;
}
if ($gradinggrade > 100) {
$gradinggrade = 100;
}
- */
$grades[$asid] = grade_floatval($gradinggrade);
}
* @param stdClass $assessment the assessment being measured
* @param stdClass $referential assessment
* @param array $diminfo of stdClass(->weight ->min ->max ->variance) indexed by dimension id
+ * @param stdClass $settings
* @return float|null rounded to 5 valid decimals
*/
- protected function assessments_distance(stdClass $assessment, stdClass $referential, array $diminfo) {
+ protected function assessments_distance(stdClass $assessment, stdClass $referential, array $diminfo, stdClass $settings) {
$distance = 0;
$n = 0;
foreach (array_keys($assessment->dimgrades) as $dimid) {
// variations very close to zero are too sensitive to a small change of data values
if ($var > 0.01 and $agrade != $rgrade) {
$absdelta = abs($agrade - $rgrade);
- // todo the following constant is the param. For 1 it is very strict, for 5 it is quite lax
- $reldelta = pow($agrade - $rgrade, 2) / (5 * $var);
+ $reldelta = pow($agrade - $rgrade, 2) / ($settings->comparison * $var);
$distance += $absdelta * $reldelta * $weight;
$n += $weight;
}
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Best evaluation settings form
+ *
+ * @package mod-workshop
+ * @copyright 2009 David Mudrak <david.mudrak@gmail.com>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot . '/lib/formslib.php');
+
+class workshop_best_evaluation_settings_form extends moodleform {
+
+ function definition() {
+ $mform = $this->_form;
+
+ $current = $this->_customdata['current'];
+ $workshop = $this->_customdata['workshop'];
+
+ $mform->addElement('header', 'general', get_string('settings', 'workshopeval_best'));
+
+ $label = get_string('gradingevaluationmethod', 'workshop');
+ $mform->addElement('static', 'methodname', $label, get_string('pluginname', 'workshopeval_best'));
+ $mform->setHelpButton('methodname', array('method', $label, 'workshopeval_best'));
+
+ $options = array();
+ for ($i = 9; $i >= 1; $i = $i-2) {
+ $options[$i] = get_string('comparisonlevel' . $i, 'workshopeval_best');
+ }
+ $label = get_string('comparison', 'workshopeval_best');
+ $mform->addElement('select', 'comparison', $label, $options);
+ $mform->setHelpButton('comparison', array('comparison', $label, 'workshopeval_best'));
+ $mform->setDefault('comparison', 5);
+
+ $mform->addElement('submit', 'submit', get_string('aggregategrades', 'workshop'));
+
+ $this->set_data($current);
+ }
+}
+++ /dev/null
-<h1>Grades aggregation</h1>
-
-<p>By clicking at <strong>Re-calculate grades</strong>, the grades for submission, grades for assessment and
-total grades will be aggregated and updated in the workshop database.</p>
-
-<p>The aggregated grade for submission is calculated as a weighted mean of grades as given by peers. Eventually,
-workshop moderators (like teachers or similar roles) can override such computed grades and set the grade manually.</p>
-
-... (todo be continued)
defined('MOODLE_INTERNAL') || die();
+$string[''] = '';
+$string[''] = '';
+$string[''] = '';
+$string[''] = '';
+$string[''] = '';
+$string[''] = '';
+$string[''] = '';
$string[''] = '';
$string[''] = '';
$string[''] = '';
$string['accesscontrol'] = 'Access control';
$string['aggregategrades'] = 'Re-calculate grades';
$string['aggregation'] = 'Grades aggregation';
-$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['agreeassessments'] = 'Assessments must be agreed';
$string['agreeassessmentsdesc'] = 'Authors may comment assessments of their work and agree/disagree with it';
$string['allocate'] = 'Allocate submissions';
$string['examplesbeforesubmission'] = 'Examples must be assessed before own submission';
$string['examplesmode'] = 'Mode of examples assessment';
$string['examplesvoluntary'] = 'Assessment of example submission is voluntary';
+$string['formataggregatedgrade'] = '$a->grade';
+$string['formataggregatedgradeover'] = '<del>$a->grade</del><br /><ins>$a->over</ins>';
$string['formatpeergrade'] = '$a->grade ($a->gradinggrade)';
$string['formatpeergradeover'] = '$a->grade (<del>$a->gradinggrade</del> / <ins>$a->gradinggradeover</ins>)';
$string['givengrade'] = 'Given grade: $a';
$string['givengrades'] = 'Given grades';
$string['gradedecimals'] = 'Decimal places in grades';
+$string['gradegivento'] = ' > ';
+$string['gradereceivedfrom'] = ' < ';
+$string['gradingevaluationmethod'] = 'Grading evaluation method';
$string['gradinggrade'] = 'Grade for assessment';
$string['gradinggradeof'] = 'Grade for assessment (of $a)';
$string['gradingsettings'] = 'Grading settings';
$string['tasksubmit'] = 'Submit your work';
$string['teacherweight'] = 'Weight of the teacher\'s assessments';
$string['totalgradeof'] = 'Total grade (of $a)';
+$string['totalgradesmissing'] = 'Unable to calculate some total grades - they will have to be set manually in Gradebook';
$string['totalgrade'] = 'Total grade';
$string['undersetup'] = 'The workshop is currently under setup. Please wait until it is switched to the next phase.';
$string['useexamplesdesc'] = 'Users practise evaluating on example submissions';
case FEATURE_MOD_INTRO: return true;
case FEATURE_MOD_SUBPLUGINS: return array(
'workshopform' => 'mod/workshop/form',
- 'workshopallocation' => 'mod/workshop/allocation'
+ 'workshopallocation' => 'mod/workshop/allocation',
+ 'workshopeval' => 'mod/workshop/eval',
);
default: return null;
}
} elseif ($this->phase > self::PHASE_EVALUATION) {
$task->completed = false;
}
- $phase->tasks['evaluateinfo'] = $task;
+ $phase->tasks['calculatetotalgrade'] = $task;
+ if ($known > 0 and $known < $expected) {
+ $task = new stdClass();
+ $task->title = get_string('totalgradesmissing', 'workshop');
+ $task->completed = 'info';
+ $phase->tasks['totalgradesmissinginfo'] = $task;
+ }
} else {
$task = new stdClass();
$task->title = get_string('evaluategradeswait', 'workshop');
'totalgrade', $sortby, $sorthow),
);
$table->rowclasses = array();
- $table->colclasses = array('reviewedby', 'peer', 'reviewerof');
+ $table->colclasses = array();
$table->data = array();
foreach ($grades as $participant) {
if ($tr % $spanreceived == 0) {
$idx = intval($tr / $spanreceived);
$cell = new html_table_cell();
- $cell->text = $this->grading_report_assessment(self::array_nth($participant->reviewedby, $idx));
+ $cell->text = $this->grading_report_assessment(self::array_nth($participant->reviewedby, $idx),
+ $showreviewernames, $userinfo, get_string('gradereceivedfrom', 'workshop'));
$cell->rowspan = $spanreceived;
$row->cells[] = $cell;
}
// column #4 - total grade for submission
if ($tr == 0) {
$cell = new html_table_cell();
- if (is_null($participant->submissiongrade)) {
- $cell->text = get_string('nullgrade', 'workshop');
- } else {
- $cell->text = $participant->submissiongrade;
- }
+ $cell->text = $this->grading_report_grade($participant->submissiongrade, $participant->submissiongradeover);
$cell->rowspan = $numoftrs;
$row->cells[] = $cell;
}
if ($tr % $spangiven == 0) {
$idx = intval($tr / $spangiven);
$cell = new html_table_cell();
- $cell->text = $this->grading_report_assessment(self::array_nth($participant->reviewerof, $idx));
+ $cell->text = $this->grading_report_assessment(self::array_nth($participant->reviewerof, $idx),
+ $showauthornames, $userinfo, get_string('gradegivento', 'workshop'));
$cell->rowspan = $spangiven;
$row->cells[] = $cell;
}
// column #6 - total grade for assessment
if ($tr == 0) {
$cell = new html_table_cell();
- if (is_null($participant->gradinggrade)) {
- $cell->text = get_string('nullgrade', 'workshop');
- } else {
- $cell->text = $participant->gradinggrade;
- }
+ $cell->text = $this->grading_report_grade($participant->gradinggrade);
$cell->rowspan = $numoftrs;
$row->cells[] = $cell;
}
} else {
$cell->text = $participant->totalgrade;
}
+ $cell->text = $this->grading_report_grade($participant->totalgrade);
$cell->rowspan = $numoftrs;
$row->cells[] = $cell;
}
* @return string
*/
protected function grading_report_submission(stdClass $participant) {
+ global $CFG;
+
if (is_null($participant->submissionid)) {
$out = $this->output->container(get_string('nosubmissionfound', 'workshop'), 'info');
} else {
- $out = $this->output->container(format_string($participant->submissiontitle), 'title');
+ $link = new html_link();
+ $link->url = new moodle_url($CFG->wwwroot . '/mod/workshop/submission.php',
+ array('cmid' => $this->page->context->instanceid, 'id' => $participant->submissionid));
+ $link->text = format_string($participant->submissiontitle);
+ $link->set_classes('title');
+ $out = $this->output->link($link);
}
return $out;
/**
* @todo Highlight the nulls
* @param stdClass|null $assessment
+ * @param bool $shownames
+ * @param string $separator between the grade and the reviewer/author
* @return string
*/
- protected function grading_report_assessment($assessment) {
+ protected function grading_report_assessment(stdClass $assessment, $shownames, array $userinfo, $separator) {
if (is_null($assessment)) {
return get_string('nullgrade', 'workshop');
}
$a->gradinggradeover = $assessment->gradinggradeover;
$grade = get_string('formatpeergradeover', 'workshop', $a);
}
+ $grade = $this->output->output_tag('span', array('class' => 'grade'), $grade);
+
+ if ($shownames) {
+ $userid = $assessment->userid;
+ $pic = new moodle_user_picture();
+ $pic->user = $userinfo[$userid];
+ $pic->courseid = $this->page->course->id;
+ $pic->url = true;
+ $pic->size = 16;
+
+ $name = $this->output->user_picture($pic);
+ $name .= $this->output->output_tag('span', array('class' => 'fullname'), fullname($userinfo[$userid]));
+ $name = $separator . $this->output->output_tag('span', array('class' => 'user'), $name);
+ } else {
+ $name = '';
+ }
+
+ return $this->output->container($grade . $name, 'assessmentdetails');
+ }
- return $grade;
+ /**
+ * Formats the aggreagated grades
+ */
+ protected function grading_report_grade($grade, $over=null) {
+ $a = new stdClass();
+ $a->grade = is_null($grade) ? get_string('nullgrade', 'workshop') : $grade;
+ if (is_null($over)) {
+ $text = get_string('formataggregatedgrade', 'workshop', $a);
+ } else {
+ $a->over = is_null($over) ? get_string('nullgrade', 'workshop') : $over;
+ $text = get_string('formataggregatedgradeover', 'workshop', $a);
+ }
+ return $text;
}
////////////////////////////////////////////////////////////////////////////
border: 1px solid #ddd;
}
+.mod-workshop .grading-report del {
+ color: red;
+ font-size: 90%
+ text-decoration:
+}
+
+.mod-workshop .grading-report ins {
+ color: green;
+ font-weight: bold;
+}
+
.mod-workshop .grading-report th {
white-space: normal;
}
border: 1px solid #ddd;
}
+.mod-workshop .grading-report .assessmentdetails {
+ white-space: nowrap;
+}
+
.mod-workshop .grading-report td.c3,
.mod-workshop .grading-report td.c5 {
text-align: center;
font-size: 160%;
+ white-space: nowrap;
}
.mod-workshop .grading-report td.c6 {
$PAGE->set_url(new moodle_url($PAGE->url, compact('sortby', 'sorthow', 'page')));
$data = $workshop->prepare_grading_report($USER->id, $groups, $page, $perpage, $sortby, $sorthow);
if ($data) {
- $showauthornames = has_capability('mod/workshop:viewauthornames', $PAGE->context);
- $showreviewernames = has_capability('mod/workshop:viewreviewernames', $PAGE->context);
-
- $form = new html_form();
- $form->url = new moodle_url($workshop->aggregate_url(), compact('sortby', 'sorthow', 'page'));
- $form->button = new html_button();
- $form->button->text = get_string('aggregategrades', 'workshop');
- $form->method = 'post';
-
- $helpicon = new moodle_help_icon();
- $helpicon->page = 'aggregate';
- $helpicon->text = get_string('aggregategrades', 'workshop');
- $helpicon->module = 'workshop';
-
- echo $OUTPUT->box_start('buttonsbar');
- echo $OUTPUT->box($OUTPUT->button($form) . $OUTPUT->help_icon($helpicon), 'buttonwithhelp');
- echo $OUTPUT->box_end();
+ $showauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context);
+ $showreviewernames = has_capability('mod/workshop:viewreviewernames', $workshop->context);
+
+ // load the grading evaluator
+ $evaluator = $workshop->grading_evaluation_instance();
+ $form = $evaluator->get_settings_form(new moodle_url($workshop->aggregate_url(), compact('sortby', 'sorthow', 'page')));
+ $form->display();
// prepare paging bar
$pagingbar = new moodle_paging_bar();
break;
case workshop::PHASE_CLOSED:
$page = optional_param('page', 0, PARAM_INT);
- $sortby = optional_param('sortby', 'lastname', PARAM_ALPHA);
- $sorthow = optional_param('sorthow', 'ASC', PARAM_ALPHA);
+ $sortby = optional_param('sortby', 'totalgrade', PARAM_ALPHA);
+ $sorthow = optional_param('sorthow', 'DESC', PARAM_ALPHA);
$perpage = 10; // todo let the user modify this
$groups = ''; // todo let the user choose the group
$PAGE->set_url(new moodle_url($PAGE->url, compact('sortby', 'sorthow', 'page')));
$data = $workshop->prepare_grading_report($USER->id, $groups, $page, $perpage, $sortby, $sorthow);
if ($data) {
- $showauthornames = has_capability('mod/workshop:viewauthornames', $PAGE->context);
- $showreviewernames = has_capability('mod/workshop:viewreviewernames', $PAGE->context);
+ $showauthornames = has_capability('mod/workshop:viewauthornames', $workshop->context);
+ $showreviewernames = has_capability('mod/workshop:viewreviewernames', $workshop->context);
// prepare paging bar
$pagingbar = new moodle_paging_bar();