From cbf87967c7f3ee94dbe878c72c0e3cf61de3f45f Mon Sep 17 00:00:00 2001 From: David Mudrak Date: Mon, 4 Jan 2010 18:28:25 +0000 Subject: [PATCH] MDL-20652 workshop: more work on example submissions Important change: teacher's assessments of example submissions (now known as "reference assessments") are now displayed to students after they assess example submission. --- mod/workshop/exassessment.php | 11 ++- mod/workshop/excompare.php | 107 +++++++++++++++++++++++ mod/workshop/exsubmission.php | 1 - mod/workshop/lang/en_utf8/workshop.php | 5 +- mod/workshop/locallib.php | 113 ++++++++++++++++++++++--- mod/workshop/renderer.php | 51 ++++++----- mod/workshop/settings.php | 1 - mod/workshop/styles.css | 3 +- mod/workshop/submission.php | 1 - mod/workshop/view.php | 100 +++++++++++----------- 10 files changed, 305 insertions(+), 88 deletions(-) create mode 100644 mod/workshop/excompare.php diff --git a/mod/workshop/exassessment.php b/mod/workshop/exassessment.php index fadcaff301..55120ac9b3 100644 --- a/mod/workshop/exassessment.php +++ b/mod/workshop/exassessment.php @@ -70,9 +70,16 @@ if ($mform->is_cancelled()) { redirect($workshop->view_url()); } elseif ($assessmenteditable and ($data = $mform->get_data())) { $rawgrade = $strategy->save_assessment($assessment, $data); - $DB->set_field('workshop_assessments', 'reviewerid', $USER->id, array('id' => $assessment->id)); + if ($canmanage) { + // remember the last one who edited the reference assessment + $DB->set_field('workshop_assessments', 'reviewerid', $USER->id, array('id' => $assessment->id)); + } if (!is_null($rawgrade) and isset($data->saveandclose)) { - redirect($workshop->view_url()); + if ($canmanage) { + redirect($workshop->view_url()); + } else { + redirect($workshop->excompare_url($example->id, $assessment->id)); + } } else { // either it is not possible to calculate the $rawgrade // or the reviewer has chosen "Save and continue" diff --git a/mod/workshop/excompare.php b/mod/workshop/excompare.php new file mode 100644 index 0000000000..4d019b0d3f --- /dev/null +++ b/mod/workshop/excompare.php @@ -0,0 +1,107 @@ +. + +/** + * Display example submission followed by its reference assessment and the user's assessment to compare them + * + * @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 id +$sid = required_param('sid', PARAM_INT); // example submission id +$aid = required_param('aid', PARAM_INT); // the user's assessment id + +$cm = get_coursemodule_from_id('workshop', $cmid, 0, false, MUST_EXIST); +$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); + +require_login($course, false, $cm); +if (isguestuser()) { + print_error('guestsarenotallowed'); +} + +$workshop = $DB->get_record('workshop', array('id' => $cm->instance), '*', MUST_EXIST); +$workshop = new workshop($workshop, $cm, $course); +$strategy = $workshop->grading_strategy_instance(); + +$PAGE->set_url(new moodle_url($workshop->excompare_url($sid, $aid))); + +$example = $workshop->get_example_by_id($sid); +$assessment = $workshop->get_assessment_by_id($aid); +if ($assessment->submissionid != $example->id) { + print_error('invalidarguments'); +} +$mformassessment = $strategy->get_assessment_form($PAGE->url, 'assessment', $assessment, false); +if ($refasid = $DB->get_field('workshop_assessments', 'id', array('submissionid' => $example->id, 'weight' => 1))) { + $reference = $workshop->get_assessment_by_id($refasid); + $mformreference = $strategy->get_assessment_form($PAGE->url, 'assessment', $reference, false); +} + +$canmanage = has_capability('mod/workshop:manageexamples', $workshop->context); +$isreviewer = ($USER->id == $assessment->reviewerid); + +if ($canmanage) { + // ok you can go +} elseif ($isreviewer and $workshop->assessing_examples_allowed()) { + // ok you can go +} else { + print_error('nopermissions'); +} + +$PAGE->set_title($workshop->name); +$PAGE->set_heading($course->fullname); +$PAGE->navbar->add(get_string('examplecomparing', 'workshop')); +$wsoutput = $PAGE->theme->get_renderer('mod_workshop', $PAGE); + +// Output starts here +echo $OUTPUT->header(); +//$currenttab = 'example'; +//include(dirname(__FILE__) . '/tabs.php'); +//$currenttab = 'example'; +echo $OUTPUT->heading(get_string('assessedexample', 'workshop'), 2); + +echo $wsoutput->example_full($example, true); + +if (!empty($mformreference)) { + echo $OUTPUT->heading(get_string('assessmentreference', 'workshop'), 2); + $mformreference->display(); +} + +if ($isreviewer) { + echo $OUTPUT->heading(get_string('assessmentbyyourself', 'workshop'), 2); +} elseif ($canmanage) { + $reviewer = new stdClass(); + $reviewer->firstname = $assessment->reviewerfirstname; + $reviewer->lastname = $assessment->reviewerlastname; + echo $OUTPUT->heading(get_string('assessmentbyknown', 'workshop', fullname($reviewer)), 2); +} +$mformassessment->display(); +echo $OUTPUT->container_start('buttonsbar'); +if ($isreviewer and $workshop->assessing_examples_allowed()) { + $button = new html_form(); + $button->method = 'get'; + $button->button->text = get_string('reassess', 'workshop'); + $button->url = new moodle_url($workshop->exsubmission_url($example->id), array('assess' => 'on', 'sesskey' => sesskey())); + echo $OUTPUT->button($button); +} +echo $OUTPUT->container_end(); // buttonsbar + +echo $OUTPUT->footer(); diff --git a/mod/workshop/exsubmission.php b/mod/workshop/exsubmission.php index ac430596d0..e146966dde 100644 --- a/mod/workshop/exsubmission.php +++ b/mod/workshop/exsubmission.php @@ -24,7 +24,6 @@ */ require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); -require_once(dirname(__FILE__).'/lib.php'); require_once(dirname(__FILE__).'/locallib.php'); $cmid = required_param('cmid', PARAM_INT); // course module id diff --git a/mod/workshop/lang/en_utf8/workshop.php b/mod/workshop/lang/en_utf8/workshop.php index 4d29f725f1..e3107206d6 100644 --- a/mod/workshop/lang/en_utf8/workshop.php +++ b/mod/workshop/lang/en_utf8/workshop.php @@ -79,11 +79,14 @@ $string['evaluategradeswait'] = 'Please wait until the assessments are evaluated $string['evaluation'] = 'Grading evaluation'; $string['evaluationmethod'] = 'Grading evaluation method'; $string['exampleadd'] = 'Add example submission'; +$string['exampleassessments'] = 'Example submissions to assess'; +$string['examplecomparing'] = 'Comparing assessments of example submission'; $string['exampledeleteconfirm'] = 'Are you sure you want to delete the following example submission? Click \'Continue\' button to delete the submission.'; $string['exampledelete'] = 'Delete example'; $string['exampleedit'] = 'Edit example'; $string['exampleediting'] = 'Editing example'; $string['example'] = 'Example submission'; +$string['examplegrade'] = 'Grade: {$a->received} of {$a->max}'; $string['examplesbeforeassessment'] = 'Examples are available after own submission and must be assessed before assessment phase'; $string['examplesbeforesubmission'] = 'Examples must be assessed before own submission'; $string['examplesmode'] = 'Mode of examples assessment'; @@ -96,7 +99,6 @@ $string['formataggregatedgradeover'] = '$a->grade
$a->over< $string['formatpeergrade'] = '$a->grade ($a->gradinggrade)'; $string['formatpeergradeover'] = '$a->grade ($a->gradinggrade / $a->gradinggradeover)'; $string['givengrades'] = 'Given grades'; -$string['givengradestatus'] = 'Status: $a'; $string['gradecalculated'] = 'Calculated grade for submission'; $string['gradedecimals'] = 'Decimal places in grades'; $string['gradegivento'] = ' > '; @@ -124,6 +126,7 @@ $string['modulename'] = 'Workshop'; $string['mysubmission'] = 'My submission'; $string['nattachments'] = 'Maximum number of submission attachments'; $string['noexamples'] = 'No examples yet in this workshop'; +$string['noexamplesformready'] = 'You must define the assessment form before providing example submissions'; $string['nogradeyet'] = 'No grade yet'; $string['nosubmissionfound'] = 'No submission found for this user'; $string['nosubmissions'] = 'No submissions yet in this workshop'; diff --git a/mod/workshop/locallib.php b/mod/workshop/locallib.php index 74f4795c56..c685229c6e 100644 --- a/mod/workshop/locallib.php +++ b/mod/workshop/locallib.php @@ -43,8 +43,8 @@ require_once($CFG->libdir . '/gradelib.php'); // we use some rounding and comp class workshop { /** return statuses of {@link add_allocation} to be passed to a workshop renderer method */ - const ALLOCATION_EXISTS = -1; - const ALLOCATION_ERROR = -2; + const ALLOCATION_EXISTS = -9999; + const ALLOCATION_ERROR = -9998; /** the internal code of the workshop phases as are stored in the database */ const PHASE_SETUP = 10; @@ -421,16 +421,6 @@ class workshop { return $DB->get_record_sql($sql, $params); } - /** - * Returns example submissions for this workshop - * - * @return array of records or an empty array - */ - public function get_examples() { - global $DB; - return $DB->get_records('workshop_submissions', array('workshopid' => $this->id, 'example' => 1), 'title', 'id,title'); - } - /** * Returns full record of the given example submission * @@ -443,6 +433,76 @@ class workshop { array('id' => $id, 'workshopid' => $this->id, 'example' => 1), '*', MUST_EXIST); } + /** + * Returns the list of example submissions in this workshop with reference assessments attached + * + * @return array of objects or an empty array + * @see workshop::prepare_example_summary() + */ + public function get_examples_for_manager() { + global $DB; + + $sql = 'SELECT s.id, s.title, + a.id AS assessmentid, a.weight, a.grade, a.gradinggrade + FROM {workshop_submissions} s + LEFT JOIN {workshop_assessments} a ON (a.submissionid = s.id AND a.weight = 1) + WHERE s.example = 1 AND s.workshopid = :workshopid + ORDER BY s.title'; + return $DB->get_records_sql($sql, array('workshopid' => $this->id)); + } + + /** + * Returns the list of all example submissions in this workshop with the information of assessments done by the given user + * + * @param int $reviewerid user id + * @return array of objects, indexed by example submission id + * @see workshop::prepare_example_summary() + */ + public function get_examples_for_reviewer($reviewerid) { + global $DB; + + if (empty($reviewerid)) { + return false; + } + $sql = 'SELECT s.id, s.title, + a.id AS assessmentid, a.weight, a.grade, a.gradinggrade + FROM {workshop_submissions} s + LEFT JOIN {workshop_assessments} a ON (a.submissionid = s.id AND a.reviewerid = :reviewerid AND a.weight = 0) + WHERE s.example = 1 AND s.workshopid = :workshopid + ORDER BY s.title'; + return $DB->get_records_sql($sql, array('workshopid' => $this->id, 'reviewerid' => $reviewerid)); + } + + /** + * Prepares component containing summary of given example to be rendered + * + * @param stdClass $example as returned by {@link workshop::get_examples_for_manager()} or {@link workshop::get_examples_for_reviewer()} + * @return stdClass component to be rendered + */ + public function prepare_example_summary(stdClass $example) { + + $summary = new stdClass(); + $summary->example = $example; + if (is_null($example->grade)) { + $summary->status = 'notgraded'; + $buttontext = get_string('assess', 'workshop'); + } else { + $summary->status = 'graded'; + $buttontext = get_string('reassess', 'workshop'); + } + + $summary->gradeinfo = new stdClass(); + $summary->gradeinfo->received = $this->real_grade($example->grade); + $summary->gradeinfo->max = $this->real_grade(100); + + $summary->btnform = new html_form(); + $summary->btnform->method = 'get'; + $summary->btnform->button->text = $buttontext; + $summary->btnform->url = new moodle_url($this->exsubmission_url($example->id), array('assess' => 'on', 'sesskey' => sesskey())); + + return $summary; + } + /** * Removes the submission and all relevant data * @@ -535,7 +595,7 @@ class workshop { /** * Allocate a submission to a user for review * - * @param stdClass $submission Submission record + * @param stdClass $submission Submission object with at least id property * @param int $reviewerid User ID * @param bool $bulk repeated inserts into DB expected * @param int $weight of the new assessment, from 0 to 16 @@ -707,6 +767,33 @@ class workshop { return new moodle_url($CFG->wwwroot . '/mod/workshop/exsubmission.php', array('cmid' => $this->cm->id, 'id' => $id)); } + /** + * @param int $sid submission id + * @param array $aid of int assessment ids + * @return moodle_url of the page to compare assessments of the given submission + */ + public function compare_url($sid, array $aids) { + global $CFG; + + $url = new moodle_url($CFG->wwwroot . '/mod/workshop/compare.php', array('cmid' => $this->cm->id, 'sid' => $sid)); + $i = 0; + foreach ($aids as $aid) { + $url->param("aid{$i}", $aid); + $i++; + } + return $url; + } + + /** + * @param int $sid submission id + * @param int $aid assessment id + * @return moodle_url of the page to compare the reference assessments of the given example submission + */ + public function excompare_url($sid, $aid) { + global $CFG; + return new moodle_url($CFG->wwwroot . '/mod/workshop/excompare.php', array('cmid' => $this->cm->id, 'sid' => $sid, 'aid' => $aid)); + } + /** * @return moodle_url of the mod_edit form */ diff --git a/mod/workshop/renderer.php b/mod/workshop/renderer.php index 1cce3408cb..03b0356d41 100644 --- a/mod/workshop/renderer.php +++ b/mod/workshop/renderer.php @@ -294,37 +294,50 @@ class mod_workshop_renderer extends plugin_renderer_base { * * The passed submission object must define at least: id and title * - * @param stdClass $example The example submission record + * @param stdClass $data prepared by workshop::prepare_example_summary() * @return string html to be echoed */ - public function example_summary(stdClass $example) { + public function example_summary(stdClass $summary) { global $CFG; $o = ''; // output HTML code - $classes = 'submission-summary example'; - $o .= $this->output->container_start($classes); // main wrapper + + // wrapping box + $o .= $this->output->box_start('generalbox example-summary ' . $summary->status); + + // title + $o .= $this->output->container_start('example-title'); $link = new html_link(); $link->url = new moodle_url($CFG->wwwroot . '/mod/workshop/exsubmission.php', - array('cmid' => $this->page->context->instanceid, 'id' => $example->id)); - $link->text = format_string($example->title); + array('cmid' => $this->page->context->instanceid, 'id' => $summary->example->id)); + $link->text = format_string($summary->example->title); $link->set_classes('title'); $o .= $this->output->link($link); - $icon = new moodle_action_icon(); - $icon->image->src = $this->old_icon_url('i/edit'); - $icon->image->alt = get_string('edit'); - $icon->link->url = new moodle_url($CFG->wwwroot . '/mod/workshop/exsubmission.php', - array('cmid' => $this->page->context->instanceid, 'id' => $example->id, 'edit' => 'on')); - $o .= $this->output->action_icon($icon); + if ($summary->example->weight == 1) { + // dirty hack to guess if the current user is example manager or not + $icon = new moodle_action_icon(); + $icon->image->src = $this->old_icon_url('i/edit'); + $icon->image->alt = get_string('edit'); + $icon->link->url = new moodle_url($CFG->wwwroot . '/mod/workshop/exsubmission.php', + array('cmid' => $this->page->context->instanceid, 'id' => $summary->example->id, 'edit' => 'on')); + $o .= $this->output->action_icon($icon); + } + $o .= $this->output->container_end(); - $icon = new moodle_action_icon(); - $icon->image->src = $this->old_icon_url('t/delete'); - $icon->image->alt = get_string('delete'); - $icon->link->url = new moodle_url($CFG->wwwroot . '/mod/workshop/exsubmission.php', - array('cmid' => $this->page->context->instanceid, 'id' => $example->id, 'delete' => 1)); - $o .= $this->output->action_icon($icon); + // additional info + if ($summary->status == 'notgraded') { + $o .= $this->output->container(get_string('nogradeyet', 'workshop'), 'example-info nograde'); + } else { + $o .= $this->output->container(get_string('examplegrade', 'workshop' , $summary->gradeinfo), 'example-info grade'); + } + + // button to assess + $o .= $this->output->container($this->output->button($summary->btnform), 'example-actions'); + + // end of wrapping box + $o .= $this->output->box_end(); - $o .= $this->output->container_end(); // end of the main wrapper return $o; } diff --git a/mod/workshop/settings.php b/mod/workshop/settings.php index fe435ac82a..910b46757b 100644 --- a/mod/workshop/settings.php +++ b/mod/workshop/settings.php @@ -27,7 +27,6 @@ defined('MOODLE_INTERNAL') || die(); -require_once($CFG->dirroot.'/mod/workshop/lib.php'); require_once($CFG->dirroot.'/mod/workshop/locallib.php'); $grades = workshop::available_maxgrades_list(); diff --git a/mod/workshop/styles.css b/mod/workshop/styles.css index 9b1464b58d..2ab10d8bc3 100644 --- a/mod/workshop/styles.css +++ b/mod/workshop/styles.css @@ -337,7 +337,8 @@ /** * Assessment */ -.mod-workshop .assessment-summary.graded { +.mod-workshop .assessment-summary.graded, +.mod-workshop .example-summary.graded { background-color: #e7f1c3; } diff --git a/mod/workshop/submission.php b/mod/workshop/submission.php index 13852a9644..b04540ab07 100644 --- a/mod/workshop/submission.php +++ b/mod/workshop/submission.php @@ -24,7 +24,6 @@ */ require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); -require_once(dirname(__FILE__).'/lib.php'); require_once(dirname(__FILE__).'/locallib.php'); $cmid = required_param('cmid', PARAM_INT); // course module id diff --git a/mod/workshop/view.php b/mod/workshop/view.php index a1a6ab230c..bbb1ebe889 100644 --- a/mod/workshop/view.php +++ b/mod/workshop/view.php @@ -88,18 +88,22 @@ case workshop::PHASE_SETUP: if ($workshop->useexamples and has_capability('mod/workshop:manageexamples', $PAGE->context)) { print_collapsible_region_start('', 'workshop-viewlet-allexamples', get_string('examplesubmissions', 'workshop')); echo $OUTPUT->box_start('generalbox examples'); - echo $OUTPUT->heading(get_string('examplesubmissions', 'workshop'), 3); - if (! $examples = $workshop->get_examples()) { - echo $OUTPUT->container(get_string('noexamples', 'workshop'), 'noexamples'); - } - foreach ($examples as $example) { - echo $wsoutput->example_summary($example); + if ($workshop->grading_strategy_instance()->form_ready()) { + if (! $examples = $workshop->get_examples_for_manager()) { + echo $OUTPUT->container(get_string('noexamples', 'workshop'), 'noexamples'); + } + foreach ($examples as $example) { + $summary = $workshop->prepare_example_summary($example); + echo $wsoutput->example_summary($summary); + } + $editbutton = new html_form(); + $editbutton->method = 'get'; + $editbutton->button->text = get_string('exampleadd', 'workshop'); + $editbutton->url = new moodle_url($workshop->exsubmission_url(0), array('edit' => 'on')); + echo $OUTPUT->button($editbutton); + } else { + echo $OUTPUT->container(get_string('noexamplesformready', 'workshop')); } - $editbutton = new html_form(); - $editbutton->method = 'get'; - $editbutton->button->text = get_string('exampleadd', 'workshop'); - $editbutton->url = new moodle_url($workshop->exsubmission_url(0), array('edit' => 'on')); - echo $OUTPUT->button($editbutton); echo $OUTPUT->box_end(); } break; @@ -111,51 +115,46 @@ case workshop::PHASE_SUBMISSION: echo $OUTPUT->box(format_text($instructions, $workshop->instructauthorsformat), array('generalbox', 'instructions')); print_collapsible_region_end(); } - //print_collapsible_region_start('', 'workshop-viewlet-examples', get_string('hideshow', 'workshop')); - //echo 'Hello'; - //print_collapsible_region_end(); - /* todo pseudocode follows - if ($workshop->useexamples) { - if (examples are voluntary) { - submitting is allowed - assessing is allowed - display the example assessment tool - just offer the posibility to train assessment - } - if (examples must be done before submission) { - if (student assessed all example submissions) { - submitting is allowed - assessing is allowed - display - let the student to reassess to train - } else { - submitting is not allowed - assessing is not allowed - display - force student to assess the examples - } - } - - // the following goes into the next PHASE - if (examples must be done before assessment) { - if (student assessed all example submissions) { - assessing is allowed - let the student to optionally reassess to train + $examplesdone = true; + if ($workshop->assessing_examples_allowed() + and has_capability('mod/workshop:submit', $workshop->context) + and ! has_capability('mod/workshop:manageexamples', $workshop->context)) { + $examples = $workshop->get_examples_for_reviewer($USER->id); + $total = count($examples); + $done = 0; + $todo = 0; + // make sure the current user has all examples allocated + foreach ($examples as $exampleid => $example) { + if (is_null($example->assessmentid)) { + $examples[$exampleid]->assessmentid = $workshop->add_allocation($example, $USER->id, false, 0); + } + if (is_null($example->grade)) { + $todo++; } else { - assessing is not allowed - force student to assess the examples + $done++; } } - } - - */ - if ($workshop->useexamples and $workshop->examplesmode == workshop::EXAMPLES_BEFORE_SUBMISSION) { - if (has_capability('mod/workshop:manageexamples', $workshop->context)) { - // todo what is teacher expected to see here? some stats probably... + if ($todo > 0 and $workshop->examplesmode != workshop::EXAMPLES_VOLUNTARY) { + $examplesdone = false; } - if (has_capability('mod/workshop:peerassess', $workshop->context)) { - + print_collapsible_region_start('', 'workshop-viewlet-examples', get_string('exampleassessments', 'workshop')); + echo $OUTPUT->box_start('generalbox exampleassessments'); + if ($total == 0) { + echo $OUTPUT->heading(get_string('noexamples', 'workshop'), 3); + } else { + foreach ($examples as $example) { + $summary = $workshop->prepare_example_summary($example); + echo $wsoutput->example_summary($summary); + } } + echo $OUTPUT->box_end(); + print_collapsible_region_end(); } - if (has_capability('mod/workshop:submit', $PAGE->context)) { + + if ($workshop->submitting_allowed() + and has_capability('mod/workshop:submit', $PAGE->context) + and $examplesdone) { print_collapsible_region_start('', 'workshop-viewlet-ownsubmission', get_string('yoursubmission', 'workshop')); echo $OUTPUT->box_start('generalbox ownsubmission'); if ($submission = $workshop->get_submission_by_author($USER->id)) { @@ -173,6 +172,7 @@ case workshop::PHASE_SUBMISSION: echo $OUTPUT->box_end(); print_collapsible_region_end(); } + if (has_capability('mod/workshop:viewallsubmissions', $PAGE->context)) { $shownames = has_capability('mod/workshop:viewauthornames', $PAGE->context); print_collapsible_region_start('', 'workshop-viewlet-allsubmissions', get_string('allsubmissions', 'workshop')); @@ -186,7 +186,9 @@ case workshop::PHASE_SUBMISSION: echo $OUTPUT->box_end(); print_collapsible_region_end(); } + break; + case workshop::PHASE_ASSESSMENT: if (has_capability('mod/workshop:viewallassessments', $PAGE->context)) { $page = optional_param('page', 0, PARAM_INT); -- 2.39.5