Manual allocator uses the new subrendering feature

This commit is contained in:
David Mudrak
2010-01-04 17:46:33 +00:00
parent 6e3099730e
commit 66c9894dbc
9 changed files with 501 additions and 456 deletions
-106
View File
@@ -57,114 +57,8 @@ interface workshop_allocator {
*
* If a form is part of the UI, the caller should have call $PAGE->set_url(...)
*
* @access public
* @return string HTML to be displayed
*/
public function ui();
}
/**
* Return list of available allocation methods
*
* @access public
* @return array Array ['string' => 'string'] of localized allocation method names
*/
function workshop_installed_allocators() {
$installed = get_list_of_plugins('mod/workshop/allocation');
$forms = array();
foreach ($installed as $allocation) {
$forms[$allocation] = get_string('allocation' . $allocation, 'workshop');
}
// usability - make sure that manual allocation appears the first
if (isset($forms['manual'])) {
$m = array('manual' => $forms['manual']);
unset($forms['manual']);
$forms = array_merge($m, $forms);
}
return $forms;
}
/**
* Returns instance of submissions allocator
*
* @param object $workshop Workshop record
* @param object $method The name of the allocation method, must be PARAM_ALPHA
* @return object Instance of submissions allocator
*/
function workshop_allocator_instance(workshop $workshop, $method) {
$allocationlib = dirname(__FILE__) . '/' . $method . '/allocator.php';
if (is_readable($allocationlib)) {
require_once($allocationlib);
} else {
throw new moodle_exception('missingallocator', 'workshop');
}
$classname = 'workshop_' . $method . '_allocator';
return new $classname($workshop);
}
/**
* Returns the list of submissions and assessments allocated to them in the given workshop
*
* Submissions without allocated assessment are returned too, having assessment attributes null.
* This also fetches all other associated information (like details about the author and reviewer)
* needed to produce allocation reports.
* The returned structure is recordset of objects with following properties:
* [submissionid] [submissiontitle] [authorid] [authorfirstname]
* [authorlastname] [authorpicture] [authorimagealt] [assessmentid]
* [timeallocated] [reviewerid] [reviewerfirstname] [reviewerlastname]
* [reviewerpicture] [reviewerimagealt]
*
* @param object $workshop The workshop object
* @return object Recordset of allocations
*/
function workshop_get_allocations(workshop $workshop) {
global $DB;
$sql = 'SELECT s.id AS submissionid, s.title AS submissiontitle, s.userid AS authorid,
author.firstname AS authorfirstname, author.lastname AS authorlastname,
author.picture AS authorpicture, author.imagealt AS authorimagealt,
a.id AS assessmentid, a.timecreated AS timeallocated, a.userid AS reviewerid,
reviewer.firstname AS reviewerfirstname, reviewer.lastname AS reviewerlastname,
reviewer.picture as reviewerpicture, reviewer.imagealt AS reviewerimagealt
FROM {workshop_submissions} s
LEFT JOIN {workshop_assessments} a ON (s.id = a.submissionid)
LEFT JOIN {user} author ON (s.userid = author.id)
LEFT JOIN {user} reviewer ON (a.userid = reviewer.id)
WHERE s.workshopid = ?
ORDER BY author.lastname,author.firstname,reviewer.lastname,reviewer.firstname';
return $DB->get_recordset_sql($sql, array($workshop->id));
}
/**
* Allocate a submission to a user for review
*
* @param object $workshop Workshop record
* @param object $submission Submission record
* @param int $reviewerid User ID
* @access public
* @return int ID of the new assessment or an error code
*/
function workshop_add_allocation(workshop $workshop, stdClass $submission, $reviewerid) {
global $DB;
if ($DB->record_exists('workshop_assessments', array('submissionid' => $submission->id, 'userid' => $reviewerid))) {
return WORKSHOP_ALLOCATION_EXISTS;
}
$now = time();
$assessment = new stdClass();
$assessment->submissionid = $submission->id;
$assessment->userid = $reviewerid;
$assessment->timecreated = $now;
$assessment->timemodified = $now;
return $DB->insert_record('workshop_assessments', $assessment);
}
+29 -179
View File
@@ -75,10 +75,10 @@ class workshop_manual_allocator implements workshop_allocator {
$reviewerid = required_param('by', PARAM_INT);
$authorid = required_param('of', PARAM_INT);
$m = array(); // message object to be passed to the next page
$rs = $this->workshop->get_submissions($authorid);
$rs = $this->workshop->get_submissions_recordset($authorid);
$submission = $rs->current();
$rs->close();
if (!$submission) {
if (empty($submission->id)) {
// nothing submitted by the given user
$m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_NOSUBMISSION;
$m[] = $authorid;
@@ -109,10 +109,10 @@ class workshop_manual_allocator implements workshop_allocator {
}
$assessmentid = required_param('what', PARAM_INT);
$confirmed = optional_param('confirm', 0, PARAM_INT);
$rs = $this->workshop->get_assessments('all', $assessmentid);
$rs = $this->workshop->get_assessments_recordset('all', $assessmentid);
$assessment = $rs->current();
$rs->close();
if ($assessment) {
if (!empty($assessment)) {
if (!$confirmed) {
$m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_CONFIRM_DEL;
$m[] = $assessment->id;
@@ -134,9 +134,6 @@ class workshop_manual_allocator implements workshop_allocator {
}
break;
}
// if we stay on this page, set the environment
$PAGE->requires->css('mod/workshop/allocation/manual/ui.css');
}
@@ -146,71 +143,64 @@ class workshop_manual_allocator implements workshop_allocator {
public function ui() {
global $PAGE;
$o = ''; // output buffer
$hlauthorid = -1; // highlight this author
$hlreviewerid = -1; // highlight this reviewer
$msg = ''; // msg text
$sty = ''; // msg style
$m = optional_param('m', '', PARAM_ALPHANUMEXT); // message object
$hlauthorid = -1; // highlight this author
$hlreviewerid = -1; // highlight this reviewer
$msg = new stdClass; // message to render
$m = optional_param('m', '', PARAM_ALPHANUMEXT); // message object
if ($m) {
$m = explode('-', $m); // unserialize
switch ($m[0]) {
case WORKSHOP_ALLOCATION_MANUAL_MSG_ADDED:
$hlauthorid = $m[1];
$hlreviewerid = $m[2];
$msg = get_string('allocationadded', 'workshop');
$sty = 'ok';
$msg->text = get_string('allocationadded', 'workshop');
$msg->sty = 'ok';
break;
case WORKSHOP_ALLOCATION_MANUAL_MSG_EXISTS:
$hlauthorid = $m[1];
$hlreviewerid = $m[2];
$msg = get_string('allocationexists', 'workshop');
$sty = 'info';
$msg->text = get_string('allocationexists', 'workshop');
$msg->sty = 'info';
break;
case WORKSHOP_ALLOCATION_MANUAL_MSG_NOSUBMISSION:
$hlauthorid = $m[1];
$msg = get_string('nosubmissionfound', 'workshop');
$sty = 'error';
$msg->text = get_string('nosubmissionfound', 'workshop');
$msg->sty = 'error';
break;
case WORKSHOP_ALLOCATION_MANUAL_MSG_WOSUBMISSION:
$hlauthorid = $m[1];
$hlreviewerid = $m[2];
$msg = get_string('cantassesswosubmission', 'workshop');
$sty = 'error';
$msg->text = get_string('cantassesswosubmission', 'workshop');
$sty->sty = 'error';
break;
case WORKSHOP_ALLOCATION_MANUAL_MSG_CONFIRM_DEL:
$hlauthorid = $m[2];
$hlreviewerid = $m[3];
if ($m[4] == 0) {
$msg = get_string('areyousuretodeallocate', 'workshop');
$sty = 'info';
$msg->text = get_string('areyousuretodeallocate', 'workshop');
$msg->sty = 'info';
} else {
$msg = get_string('areyousuretodeallocategraded', 'workshop');
$sty = 'error';
$msg->text = get_string('areyousuretodeallocategraded', 'workshop');
$msg->sty = 'error';
}
break;
case WORKSHOP_ALLOCATION_MANUAL_MSG_DELETED:
$hlauthorid = $m[1];
$hlreviewerid = $m[2];
$msg = get_string('assessmentdeleted', 'workshop');
$sty = 'ok';
$msg->text = get_string('assessmentdeleted', 'workshop');
$msg->sty = 'ok';
break;
}
$o .= '<div id="message" class="' . $sty . '">';
$o .= ' <span>' . $msg . '</span>';
$o .= ' <div id="message-close"><a href="' . $PAGE->url->out() . '">' .
get_string('messageclose', 'workshop') . '</a></div>';
if ($m[0] == WORKSHOP_ALLOCATION_MANUAL_MSG_CONFIRM_DEL) {
$handler = $PAGE->url->out_action();
$o .= print_single_button($handler, array('mode' => 'del', 'what' => $m[1], 'confirm' => 1),
$msg->extra = print_single_button($handler, array('mode' => 'del', 'what' => $m[1], 'confirm' => 1),
get_string('iamsure', 'workshop'), 'post', '', true);
}
$o .= '</div>';
}
$peer = array(); // singular chosen due to readibility
$rs = $this->workshop->get_allocations();
$rs = $this->workshop->get_allocations_recordset();
foreach ($rs as $allocation) {
$currentuserid = $allocation->authorid;
if (!isset($peer[$currentuserid])) {
@@ -237,159 +227,19 @@ class workshop_manual_allocator implements workshop_allocator {
foreach ($peer as $author) {
foreach ($author->reviewedby as $reviewerid => $assessmentid) {
// example: "user with id 87 is reviewer of the work submitted by user id 45 in the assessment record 12"
if (isset($peer[$reviewerid])) {
// example: "user with id 87 is reviewer of the work submitted by user id 45 in the assessment record 12"
$peer[$reviewerid]->reviewerof[$author->id] = $assessmentid;
}
}
}
if (empty($peer)) {
$o .= '<div id="message" class="info">' . get_string('nosubmissions', 'workshop') . '</div>';
} else {
$o .= '<table class="allocations">' . "\n";
$o .= '<thead><tr>';
$o .= '<th>' . get_string('participantreviewedby', 'workshop') . '</th>';
$o .= '<th>' . get_string('participant', 'workshop') . '</th>';
$o .= '<th>' . get_string('participantrevierof', 'workshop') . '</th>';
$o .= '</thead><tbody>';
$counter = 0;
foreach ($peer as $user) {
$o .= '<tr class="r' . $counter % 2 . '">' . "\n";
if ($user->id == $hlauthorid) {
$highlight=' highlight';
} else {
$highlight='';
}
$o .= '<td class="reviewedby' . $highlight . '">' . "\n";
if (is_null($user->submissionid)) {
$o .= '<span class="info">' . "\n";
$o .= get_string('nothingtoreview', 'workshop');
$o .= '</span>' . "\n";
} else {
$handler = $PAGE->url->out_action() . '&amp;mode=new&amp;of=' . $user->id . '&amp;by=';
$o .= popup_form($handler, $this->available_reviewers($user->id), 'addreviewof' . $user->id, '',
get_string('chooseuser', 'workshop'), '', '', true, 'self', get_string('addreviewer', 'workshop'));
}
$o .= '<ul>' . "\n";
foreach ($user->reviewedby as $reviewerid => $assessmentid) {
$o .= '<li>';
$o .= print_user_picture($peer[$reviewerid], $this->workshop->course, null, 16, true);
$o .= fullname($peer[$reviewerid]);
// delete
$handler = $PAGE->url->out_action(array('mode' => 'del', 'what' => $assessmentid));
$o .= '<a class="action" href="' . $handler . '"> X </a>'; // todo icon and link title
$o .= '</li>';
}
$o .= '</ul>' . "\n";
$o .= '</td>' . "\n";
$o .= '<td class="peer">' . "\n";
$o .= print_user_picture($user, $this->workshop->course, null, 35, true);
$o .= fullname($user);
$o .= '<div class="submission">' . "\n";
if (is_null($user->submissionid)) {
$o .= '<span class="info">' . get_string('nosubmissionfound', 'workshop');
} else {
$o .= '<div class="title"><a href="#">' . s($user->submissiontitle) . '</a></div>';
if (is_null($user->submissiongrade)) {
$o .= '<div class="grade missing">' . get_string('nogradeyet', 'workshop') . '</div>';
} else {
$o .= '<div class="grade">' . s($user->submissiongrade) . '</div>'; // todo calculate
}
}
$o .= '</div>' . "\n";
$o .= '</td>' . "\n";
if ($user->id == $hlreviewerid) {
$highlight=' highlight';
} else {
$highlight='';
}
$o .= '<td class="reviewerof' . $highlight . '">' . "\n";
if (!($this->workshop->assesswosubmission) && is_null($user->submissionid)) {
$o .= '<span class="info">' . "\n";
$o .= get_string('cantassesswosubmission', 'workshop');
$o .= '</span>' . "\n";
} else {
$handler = $PAGE->url->out_action() . '&mode=new&amp;by=' . $user->id . '&amp;of=';
$o .= popup_form($handler, $this->available_reviewees($user->id), 'addreviewby' . $user->id, '',
get_string('chooseuser', 'workshop'), '', '', true, 'self', get_string('addreviewee', 'workshop'));
$o .= '<ul>' . "\n";
foreach ($user->reviewerof as $authorid => $assessmentid) {
$o .= '<li>';
$o .= print_user_picture($peer[$authorid], $this->workshop->course, null, 16, true);
$o .= fullname($peer[$authorid]);
// delete
$handler = $PAGE->url->out_action(array('mode' => 'del', 'what' => $assessmentid));
$o .= '<a class="action" href="' . $handler . '"> X </a>'; // todo icon and link title
$o .= '</li>';
}
$o .= '</ul>' . "\n";
}
$o .= '</td>' . "\n";
$o .= '</tr>' . "\n";
$counter++;
}
$o .= '</tbody></table>' . "\n";
}
return $o;
// ok, we have all data. Let it pass to the renderer and return the output
require_once(dirname(__FILE__) . '/renderer.php');
$uioutput = $PAGE->theme->get_renderer('mod_workshop', $PAGE, 'allocation_manual');
return $uioutput->display_allocations($this->workshop, $peer, $hlauthorid, $hlreviewerid, $msg);
}
/**
* Return a list of reviewers that can review a submission
*
* @param int $authorid User ID of the submission author
* @return array Select options
*/
protected function available_reviewers($authorid) {
$users = $this->workshop->get_peer_reviewers();
$options = array();
foreach ($users as $user) {
$options[$user->id] = fullname($user);
}
if (0 == $this->workshop->useselfassessment) {
// students can not review their own submissions in this workshop
if (isset($options[$authorid])) {
unset($options[$authorid]);
}
}
return $options;
}
/**
* Return a list of reviewees whom work can be reviewed by a given user
*
* @param int $reviewerid User ID of the reviewer
* @return array Select options
*/
protected function available_reviewees($reviewerid) {
$rs = $this->workshop->get_submissions();
$options = array();
foreach ($rs as $submission) {
$options[$submission->userid] = fullname((object)array('firstname' => $submission->authorfirstname,
'lastname' => $submission->authorlastname));
}
$rs->close();
if (0 == $this->workshop->useselfassessment) {
// students can not be reviewed by themselves in this workshop
if (isset($options[$reviewerid])) {
unset($options[$reviewerid]);
}
}
return $options;
}
}
+228
View File
@@ -0,0 +1,228 @@
<?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/>.
/**
* Renderer class for the manual allocation UI is defined here
*
* @package mod-workshop
* @copyright 2009 David Mudrak <[email protected]>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
/**
* Manual allocation renderer class
*/
class moodle_mod_workshop_allocation_manual_renderer {
/** the underlying renderer to use */
protected $output;
/** the page we are doing output for */
protected $page;
/**
* Workshop renderer constructor
*
* @param mixed $page the page we are doing output for
* @param mixed $output lower-level renderer, typically moodle_core_renderer
* @access public
* @return void
*/
public function __construct($page, $output) {
$this->page = $page;
$this->output = $output;
}
/**
* Display the table of all current allocations and widgets to modify them
*
* @param workshop $workshop workshop instance object
* @param array $peers prepared array of all allocations
* @param int $hlauthorid highlight this author
* @param int $hlreviewerid highlight this reviewer
* @param object message to display
* @return string html code
*/
public function display_allocations(workshop $workshop, &$peers, $hlauthorid=null, $hlreviewerid=null, $msg=null) {
if (empty($peers)) {
return $this->status_message((object)array('text' => get_string('nosubmissions', 'workshop')));
}
$table = new stdClass();
$table->class = 'allocations';
$table->head = array(get_string('participantreviewedby', 'workshop'),
get_string('participant', 'workshop'),
get_string('participantrevierof', 'workshop'));
$table->rowclass = array();
$table->colclasses = array('reviewedby', 'peer', 'reviewerof');
$table->data = array();
foreach ($peers as $user) {
$row = array();
$row[] = $this->reviewers_of_participant($user, $workshop, $peers);
$row[] = $this->participant($user);
$row[] = $this->reviewees_of_participant($user, $workshop, $peers);
$thisrowclasses = array();
if ($user->id == $hlauthorid) {
$thisrowclasses[] = 'highlightreviewedby';
}
if ($user->id == $hlreviewerid) {
$thisrowclasses[] = 'highlightreviewerof';
}
$table->rowclass[] = implode(' ', $thisrowclasses);
$table->data[] = $row;
}
return $this->output->container($this->status_message($msg) . print_table($table, true), 'manual-allocator');
}
/**
* Returns html code for a status message
*
* @param string $message to display
* @return string html
*/
protected function status_message(stdClass $message) {
if (empty($message->text)) {
return '';
}
$sty = $message->sty ? $message->sty : 'info';
$o = '<span>' . $message->text . '</span>';
$closer = '<a href="' . $this->page->url->out() . '">' . get_string('messageclose', 'workshop') . '</a>';
$o .= $this->output->container($closer, 'status-message-closer');
if (isset($message->extra)) {
$o .= $message->extra;
}
return $this->output->container($o, array('status-message', $sty));
}
protected function participant(stdClass $user) {
$o = print_user_picture($user, $this->page->course->id, null, 35, true);
$o .= fullname($user);
$o .= '<div class="submission">' . "\n";
if (is_null($user->submissionid)) {
$o .= '<span class="info">' . get_string('nosubmissionfound', 'workshop');
} else {
$o .= '<div class="title"><a href="#">' . s($user->submissiontitle) . '</a></div>';
if (is_null($user->submissiongrade)) {
$o .= '<div class="grade missing">' . get_string('nogradeyet', 'workshop') . '</div>';
} else {
$o .= '<div class="grade">' . s($user->submissiongrade) . '</div>'; // todo calculate
}
}
$o .= '</div>' . "\n";
return $o;
}
protected function reviewers_of_participant(stdClass $user, workshop $workshop, &$peers) {
$o = '';
if (is_null($user->submissionid)) {
$o .= '<span class="info">' . "\n";
$o .= get_string('nothingtoreview', 'workshop');
$o .= '</span>' . "\n";
} else {
$options = array();
foreach ($workshop->get_peer_reviewers() as $reviewer) {
$options[$reviewer->id] = fullname($reviewer);
}
if (!$workshop->useselfassessment) {
// students can not review their own submissions in this workshop
if (isset($options[$user->id])) {
unset($options[$user->id]);
}
}
$handler = $this->page->url->out_action() . '&amp;mode=new&amp;of=' . $user->id . '&amp;by=';
$o .= popup_form($handler, $options, 'addreviewof' . $user->id, '',
get_string('chooseuser', 'workshop'), '', '', true, 'self', get_string('addreviewer', 'workshop'));
}
$o .= '<ul>' . "\n";
foreach ($user->reviewedby as $reviewerid => $assessmentid) {
$o .= '<li>';
$o .= print_user_picture($peers[$reviewerid], $this->page->course->id, null, 16, true);
$o .= fullname($peers[$reviewerid]);
$handler = $this->page->url->out_action(array('mode' => 'del', 'what' => $assessmentid));
$o .= '<a class="action" href="' . $handler . '"> X </a>';
$o .= '</li>';
}
$o .= '</ul>' . "\n";
return $o;
}
protected function reviewees_of_participant(stdClass $user, workshop $workshop, &$peers) {
$o = '';
if (!$workshop->assesswosubmission && is_null($user->submissionid)) {
$o .= '<span class="info">' . "\n";
$o .= get_string('cantassesswosubmission', 'workshop');
$o .= '</span>' . "\n";
} else {
$options = array();
foreach ($workshop->get_peer_authors(true) as $author) {
$options[$author->id] = fullname($author);
}
if (!$workshop->useselfassessment) {
// students can not be reviewed by themselves in this workshop
if (isset($options[$user->id])) {
unset($options[$user->id]);
}
}
$handler = $this->page->url->out_action() . '&mode=new&amp;by=' . $user->id . '&amp;of=';
$o .= popup_form($handler, $options, 'addreviewby' . $user->id, '',
get_string('chooseuser', 'workshop'), '', '', true, 'self', get_string('addreviewee', 'workshop'));
$o .= '<ul>' . "\n";
foreach ($user->reviewerof as $authorid => $assessmentid) {
$o .= '<li>';
$o .= print_user_picture($peers[$authorid], $this->page->course->id, null, 16, true);
$o .= fullname($peers[$authorid]);
// delete
$handler = $this->page->url->out_action(array('mode' => 'del', 'what' => $assessmentid));
$o .= '<a class="action" href="' . $handler . '"> X </a>'; // todo icon and link title
$o .= '</li>';
}
$o .= '</ul>' . "\n";
}
return $o;
}
}
-81
View File
@@ -1,81 +0,0 @@
.allocations {
margin: 0px auto;
}
.allocations .r0 {
background-color: #eee;
}
.allocations .highlight {
background-color: #fff3d2;
}
.allocations tr td {
vertical-align: top;
padding: 5px;
}
.allocations tr td.peer {
border-left: 1px solid #ccc;
border-right: 1px solid #ccc;
}
.allocations .reviewedby .info,
.allocations .peer .info,
.allocations .reviewerof .info {
font-size: 80%;
color: #888;
font-style: italic;
}
.allocations .reviewedby img.userpicture,
.allocations .reviewerof img.userpicture {
height: 16px;
width: 16px;
margin-right: 3px;
vertical-align: middle;
}
.allocations .peer img.userpicture {
height: 35px;
width: 35px;
vertical-align: middle;
margin-right: 5px;
}
.allocations .peer .submission {
font-size: 90%;
margin-top: 1em;
}
#message {
padding: 5px 5em 5px 15px;
margin: 0px auto 20px auto;
width: 60%;
font-size: 80%;
position: relative;
}
#message-close {
font-weight: bold;
position: absolute;
top: 5px;
right: 15px;
}
#message.ok {
color: #547c22;
background-color: #e7f1c3;
}
#message.error {
color: #dd0221;
background-color: #ffd3d9;
}
#message.info {
color: #1666a9;
background-color: #d2ebff;
}