$string[''] = '';
$string[''] = '';
$string[''] = '';
-$string[''] = '';
-$string['configgradedecimals'] = 'Default number of digits that should be shown after the decimal point when displaying grades.';
-$string['gradedecimals'] = 'Decimal places in grades';
$string['accesscontrol'] = 'Access control';
$string['aggregategrades'] = 'Re-calculate grades';
$string['aggregation'] = 'Grades aggregation';
$string['assignedassessmentsnone'] = 'You have no assigned submission to assess';
$string['backtoeditform'] = 'Back to editing form';
$string['byfullname'] = 'by <a href=\"{$a->url}\">{$a->name}</a>';
+$string['calculatetotalgrades'] = 'Calculate total grades';
+$string['calculatetotalgradesdetails'] = 'expected: $a->expected<br />known: $a->known';
$string['comparisonhigh'] = 'High';
$string['comparisonlow'] = 'Low';
$string['comparisonnormal'] = 'Normal';
$string['configanonymity'] = 'Default anonymity mode in workshops';
$string['configassessmentcomps'] = 'Default value of the setting that influences the calculation of the grade for assessment.';
$string['configexamplesmode'] = 'Default mode of examples assessment in workshops';
+$string['configgradedecimals'] = 'Default number of digits that should be shown after the decimal point when displaying grades.';
$string['configgrade'] = 'Default maximum grade for submission in workshops';
$string['configgradinggrade'] = 'Default maximum grade for assessment in workshops';
$string['configmaxbytes'] = 'Default maximum submission file size for all workshops on the site (subject to course limits and other local settings)';
$string['editingsubmission'] = 'Editing submission';
$string['editsubmission'] = 'Edit submission';
$string['err_removegrademappings'] = 'Unable to remove the unused grade mappings';
+$string['evaluategradeswait'] = 'Please wait until the assessments are evaluated and total grades are calculated';
$string['examplesbeforeassessment'] = 'Examples are available after own submission and must be assessed before peer/self assessment phase';
$string['examplesbeforesubmission'] = 'Examples must be assessed before own submission';
$string['examplesmode'] = 'Mode of examples assessment';
$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['gradinggrade'] = 'Grade for assessment';
$string['gradinggradeof'] = 'Grade for assessment (of $a)';
$string['gradingsettings'] = 'Grading settings';
$string['taskintro'] = 'Set the workshop introduction';
$string['tasksubmit'] = 'Submit your work';
$string['teacherweight'] = 'Weight of the teacher\'s assessments';
+$string['totalgradeof'] = 'Total grade (of $a)';
$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';
*/
public function get_potential_authors($musthavesubmission=true) {
$users = get_users_by_capability($this->context, 'mod/workshop:submit',
- 'u.id,u.lastname,u.firstname', 'u.lastname,u.firstname,u.id', 0, 1000, '', '', false, false, true);
+ 'u.id,u.lastname,u.firstname', 'u.lastname,u.firstname,u.id', '', '', '', '', false, false, true);
if ($musthavesubmission) {
$users = array_intersect_key($users, $this->users_with_submission(array_keys($users)));
}
*/
public function get_potential_reviewers($musthavesubmission=false) {
$users = get_users_by_capability($this->context, 'mod/workshop:peerassess',
- 'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname,u.id', 0, 1000, '', '', false, false, true);
+ 'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname,u.id', '', '', '', '', false, false, true);
if ($musthavesubmission) {
// users without their own submission can not be reviewers
$users = array_intersect_key($users, $this->users_with_submission(array_keys($users)));
}
$phases[self::PHASE_ASSESSMENT] = $phase;
- // Prepare tasks for the grading evaluation phase - todo
+ // Prepare tasks for the grading evaluation phase
$phase = new stdClass();
$phase->title = get_string('phaseevaluation', 'workshop');
$phase->tasks = array();
+ if (has_capability('mod/workshop:overridegrades', $this->context)) {
+ $authors = $this->get_potential_authors(false);
+ $reviewers = $this->get_potential_reviewers(false);
+ $expected = count($authors + $reviewers);
+ unset($authors);
+ unset($reviewers);
+ $known = $DB->count_records_select('workshop_aggregations', 'workshopid = ? AND totalgrade IS NOT NULL',
+ array($this->id));
+ $task = new stdClass();
+ $task->title = get_string('calculatetotalgrades', 'workshop');
+ $a = new stdClass();
+ $a->expected = $expected;
+ $a->known = $known;
+ $task->details = get_string('calculatetotalgradesdetails', 'workshop', $a);
+ if ($known >= $expected) {
+ $task->completed = true;
+ } elseif ($this->phase > self::PHASE_EVALUATION) {
+ $task->completed = false;
+ }
+ $phase->tasks['evaluateinfo'] = $task;
+ } else {
+ $task = new stdClass();
+ $task->title = get_string('evaluategradeswait', 'workshop');
+ $task->completed = 'info';
+ $phase->tasks['evaluateinfo'] = $task;
+ }
$phases[self::PHASE_EVALUATION] = $phase;
// Prepare tasks for the "workshop closed" phase - todo
$data->totalcount = $numofparticipants;
$data->maxgrade = $this->real_grade(100);
$data->maxgradinggrade = $this->real_grading_grade(100);
+ $data->maxtotalgrade = $this->format_total_grade($data->maxgrade + $data->maxgradinggrade);
return $data;
}
if (is_null($raw)) {
return null;
}
- return format_float($raw, $this->gradedecimals, $localized);
+ return format_float($raw, $this->gradedecimals, true);
}
/**
public function aggregate_total_grades($restrict=null) {
global $DB;
- // todo
+ // fetch a recordset with all assessments to process
+ $sql = 'SELECT s.grade, s.gradeover, s.authorid AS userid,
+ ag.id AS agid, ag.gradinggrade, ag.totalgrade
+ FROM {workshop_submissions} s
+ INNER JOIN {workshop_aggregations} ag ON (ag.userid = s.authorid)
+ 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 ag.userid $usql";
+ $params = array_merge($params, $uparams);
+ } else {
+ throw new coding_exception('Empty value is not a valid parameter here');
+ }
+
+ $sql .= ' ORDER BY ag.userid'; // this is important for bulk processing
+
+ $rs = $DB->get_recordset_sql($sql, $params);
+
+ foreach ($rs as $current) {
+ $this->aggregate_total_grades_process($current);
+ }
+ $rs->close();
}
////////////////////////////////////////////////////////////////////////////
* was overridden by a teacher, the gradeover value is returned and the rest of grades are ignored.
*
* @param array $assessments of stdClass(->submissionid ->submissiongrade ->gradeover ->weight ->grade)
- * @return null|float the aggregated grade rounded to numeric(10,5)
+ * @return void
*/
protected function aggregate_submission_grades_process(array $assessments) {
global $DB;
* was overridden by a teacher, the gradinggradeover value is returned and the rest of grades are ignored.
*
* @param array $assessments of stdClass(->reviewerid ->gradinggrade ->gradinggradeover ->aggregationid ->aggregatedgrade)
- * @return null|float the aggregated grade rounded to numeric(10,5)
+ * @return void
*/
protected function aggregate_grading_grades_process(array $assessments) {
global $DB;
}
}
+ /**
+ * Given an object with final grade for submission and final grade for assessment, updates the total grade in DB
+ *
+ * @param stdClass $data
+ * @return void
+ */
+ protected function aggregate_total_grades_process(stdClass $data) {
+ global $DB;
+
+ if (!is_null($data->gradeover)) {
+ $submissiongrade = $data->gradeover;
+ } else {
+ $submissiongrade = $data->grade;
+ }
+
+ // If we do not have enough information to update totalgrade, do not do
+ // anything. Please note there may be a lot of reasons why the workshop
+ // participant does not have one of these grades - maybe she was ill or
+ // just did not reach the deadlines. Teacher has to fix grades in
+ // gradebook manually.
+
+ if (is_null($submissiongrade) or (!empty($this->gradinggrade) and is_null($this->gradinggrade))) {
+ return;
+ }
+
+ $totalgrade = $this->grade * $submissiongrade / 100 + $this->gradinggrade * $data->gradinggrade / 100;
+
+ // check if the new total grade differs from the one stored in the database
+ if (grade_floats_different($totalgrade, $data->totalgrade)) {
+ // we need to save new calculation into the database
+ if (is_null($data->agid)) {
+ // no aggregation record yet
+ $record = new stdClass();
+ $record->workshopid = $this->id;
+ $record->userid = $data->userid;
+ $record->totalgrade = $totalgrade;
+ $DB->insert_record('workshop_aggregations', $record);
+ } else {
+ $DB->set_field('workshop_aggregations', 'totalgrade', $totalgrade, array('id' => $data->agid));
+ }
+ }
+ }
+
/**
* Given a list of user ids, returns the filtered one containing just ids of users with own submission
*
$this->sortable_heading(get_string('givengrades', 'workshop')),
$this->sortable_heading(get_string('gradinggradeof', 'workshop', $data->maxgradinggrade),
'gradinggrade', $sortby, $sorthow),
- $this->sortable_heading(get_string('totalgrade', 'workshop'), 'totalgrade', $sortby, $sorthow),
+ $this->sortable_heading(get_string('totalgradeof', 'workshop', $data->maxtotalgrade),
+ 'totalgrade', $sortby, $sorthow),
);
$table->rowclasses = array();
$table->colclasses = array('reviewedby', 'peer', 'reviewerof');
// column #4 - total grade for submission
if ($tr == 0) {
$cell = new html_table_cell();
- $cell->text = $participant->submissiongrade;
+ if (is_null($participant->submissiongrade)) {
+ $cell->text = get_string('nullgrade', 'workshop');
+ } else {
+ $cell->text = $participant->submissiongrade;
+ }
$cell->rowspan = $numoftrs;
$row->cells[] = $cell;
}
// column #6 - total grade for assessment
if ($tr == 0) {
$cell = new html_table_cell();
- $cell->text = $participant->gradinggrade;
+ if (is_null($participant->gradinggrade)) {
+ $cell->text = get_string('nullgrade', 'workshop');
+ } else {
+ $cell->text = $participant->gradinggrade;
+ }
$cell->rowspan = $numoftrs;
$row->cells[] = $cell;
}
if (!is_null($sortid)) {
$iconasc = new moodle_action_icon();
- $iconasc->image->src = $this->old_icon_url('t/down');
+ $iconasc->image->src = $this->old_icon_url('t/up');
$iconasc->image->alt = get_string('sortasc', 'workshop');
$iconasc->image->set_classes('sort asc');
$newurl = clone($PAGE->url);
$iconasc->link->url = new moodle_url($newurl);
$icondesc = new moodle_action_icon();
- $icondesc->image->src = $this->old_icon_url('t/up');
+ $icondesc->image->src = $this->old_icon_url('t/down');
$icondesc->image->alt = get_string('sortdesc', 'workshop');
$icondesc->image->set_classes('sort desc');
$newurl = clone($PAGE->url);
public function aggregate_grading_grades_process(array $assessments) {
parent::aggregate_grading_grades_process($assessments);
}
+
+ public function aggregate_total_grades_process(stdClass $data) {
+ parent::aggregate_total_grades_process($data);
+ }
}
/**
$this->workshop->aggregate_grading_grades_process($batch);
}
+ public function test_aggregate_total_grades_process_normal_new() {
+ global $DB;
+
+ // fixture set-up
+ $this->workshop->grade = 85;
+ $this->workshop->gradinggrade = 15;
+
+ $data = new stdClass();
+ $data->agid = 1;
+ $data->grade = 95.00000;
+ $data->gradeover = null;
+ $data->gradinggrade = 67.34500;
+ $data->totalgrade = null;
+
+ $expected = grade_floatval(0.95 * 85 + 0.67345 * 15);
+ $DB->expectOnce('set_field', array('workshop_aggregations', 'totalgrade', $expected, array('id' => 1)));
+ // excercise SUT
+ $this->workshop->aggregate_total_grades_process($data);
+ }
+
+ public function test_aggregate_total_grades_process_overriden_new() {
+ global $DB;
+
+ // fixture set-up
+ $this->workshop->grade = 80;
+ $this->workshop->gradinggrade = 20;
+
+ $data = new stdClass();
+ $data->agid = 2;
+ $data->grade = 95.00000;
+ $data->gradeover = 87.5;
+ $data->gradinggrade = 67.34500;
+ $data->totalgrade = null;
+
+ $expected = grade_floatval(0.875 * 80 + 0.67345 * 20);
+ $DB->expectOnce('set_field', array('workshop_aggregations', 'totalgrade', $expected, array('id' => 2)));
+ // excercise SUT
+ $this->workshop->aggregate_total_grades_process($data);
+ }
+
+ public function test_aggregate_total_grades_process_uptodate() {
+ global $DB;
+
+ // fixture set-up
+ $this->workshop->grade = 100;
+ $this->workshop->gradinggrade = 100;
+
+ $data = new stdClass();
+ $data->agid = 3;
+ $data->grade = 45.00000;
+ $data->gradeover = null;
+ $data->gradinggrade = 40.00000;
+ $data->totalgrade = 85.00000;
+
+ $DB->expectNever('set_field');
+ // excercise SUT
+ $this->workshop->aggregate_total_grades_process($data);
+ }
+
+ public function test_aggregate_total_grades_process_null_grade() {
+ global $DB;
+ // fixture set-up
+ $this->workshop->grade = 70;
+ $this->workshop->gradinggrade = 30;
+
+ $data = new stdClass();
+ $data->agid = 4;
+ $data->grade = null;
+ $data->gradeover = null;
+ $data->gradinggrade = 95.00000;
+ $data->totalgrade = null;
+
+ $DB->expectNever('set_field');
+ // excercise SUT
+ $this->workshop->aggregate_total_grades_process($data);
+ }
+
+ /*
+ public function test_aggregate_total_grades_process_null_gradinggrade() {
+ global $DB;
+
+ // fixture set-up
+ $this->workshop->grade = 70;
+ $this->workshop->gradinggrade = 30;
+
+ $data = new stdClass();
+ $data->agid = 5;
+ $data->grade = 12.12345;
+ $data->gradeover = null;
+ $data->gradinggrade = null;
+ $data->totalgrade = null;
+
+ $DB->expectNever('set_field');
+ // excercise SUT
+ $this->workshop->aggregate_total_grades_process($data);
+ }
+
+ public function test_aggregate_total_grades_process_null_gradinggrade_of_zero() {
+ global $DB;
+
+ // fixture set-up
+ $this->workshop->grade = 100;
+ $this->workshop->gradinggrade = 0;
+
+ $data = new stdClass();
+ $data->agid = 6;
+ $data->grade = 56.00000;
+ $data->gradeover = null;
+ $data->gradinggrade = null;
+ $data->totalgrade = null;
+
+ $DB->expectOnce('set_field', array('workshop_aggregations', 'totalgrade', 56.00000, array('id' => 1)));
+ // excercise SUT
+ $this->workshop->aggregate_total_grades_process($data);
+ }
+ */
public function test_percent_to_value() {
// fixture setup
$total = 185;
border: 1px solid #ddd;
}
+.mod-workshop .grading-report td.c3,
+.mod-workshop .grading-report td.c5 {
+ text-align: center;
+ font-size: 160%;
+}
+
+.mod-workshop .grading-report td.c6 {
+ text-align: center;
+ font-size: 220%;
+}
+
/**
* Edit assessment form
*/
}
break;
case workshop::PHASE_EVALUATION:
- $page = optional_param('page', 0, PARAM_INT);
- $sortby = optional_param('sortby', 'lastname', PARAM_ALPHA);
- $sorthow = optional_param('sorthow', 'ASC', 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);
+ if (has_capability('mod/workshop:overridegrades', $PAGE->context)) {
+ $page = optional_param('page', 0, PARAM_INT);
+ $sortby = optional_param('sortby', 'lastname', PARAM_ALPHA);
+ $sorthow = optional_param('sorthow', 'ASC', 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);
- if (has_capability('mod/workshop:overridegrades', $PAGE->context)) {
$form = new html_form();
$form->url = new moodle_url($workshop->aggregate_url(), compact('sortby', 'sorthow', 'page'));
$form->button = new html_button();
echo $OUTPUT->box_start('buttonsbar');
echo $OUTPUT->box($OUTPUT->button($form) . $OUTPUT->help_icon($helpicon), 'buttonwithhelp');
echo $OUTPUT->box_end();
+
+ // prepare paging bar
+ $pagingbar = new moodle_paging_bar();
+ $pagingbar->totalcount = $data->totalcount;
+ $pagingbar->page = $page;
+ $pagingbar->perpage = $perpage;
+ $pagingbar->baseurl = $PAGE->url;
+ $pagingbar->pagevar = 'page';
+
+ echo $OUTPUT->paging_bar($pagingbar);
+ echo $wsoutput->grading_report($data, $showauthornames, $showreviewernames, $sortby, $sorthow);
+ echo $OUTPUT->paging_bar($pagingbar);
}
+ }
+ 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);
+ $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);
// prepare paging bar
$pagingbar = new moodle_paging_bar();
echo $OUTPUT->paging_bar($pagingbar);
}
break;
-case workshop::PHASE_CLOSED:
default:
}