Commit 53fad4b9 authored by David Mudrak's avatar David Mudrak
Browse files

MDL-19870 Initial work on random allocator

Initial sketches of random allocator. Refactoring of the rest of the
module here and there. Also, this commit removes trailing whitespace and
running empty lines.
parent 59ef7847
<?php
// This file is part of Moodle - http://moodle.org/
//
// 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
......@@ -11,15 +11,14 @@
// 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/>.
/**
* At this page, teachers allocate submissions to students for a review
*
* The allocation logic itself is delegated to allocators - subplugins in ./allocation
* The allocation logic itself is delegated to allocators - subplugins in ./allocation
* folder.
*
* @package mod-workshop
......@@ -48,11 +47,11 @@ require_capability('mod/workshop:allocate', $context);
$PAGE->set_title($workshop->name);
$PAGE->set_heading($course->fullname);
//
// todo navigation will be changed yet for Moodle 2.0
// TODO navigation will be changed yet for Moodle 2.0
$navigation = build_navigation(get_string('allocation', 'workshop'), $cm);
$allocator = $workshop->allocator_instance($method);
$allocator->init();
$allocator = $workshop->allocator_instance($method);
$initresult = $allocator->init();
//
// Output starts here
......@@ -67,5 +66,13 @@ foreach ($allocators as $methodid => $methodname) {
}
print_tabs(array($tabrow), $method); // todo use $output call
echo $OUTPUT->container($allocator->ui(), 'allocator-ui');
if (!empty($initresult)) {
echo $OUTPUT->container_start('allocator-init-results');
echo $wsoutput->allocation_init_result($initresult);
echo $OUTPUT->container_end();
} else {
echo $OUTPUT->container_start('allocator-ui');
$allocator->ui($wsoutput);
echo $OUTPUT->container_end();
}
echo $OUTPUT->footer();
<?php
// This file is part of Moodle - http://moodle.org/
//
// 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
......@@ -11,11 +11,10 @@
// 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/>.
/**
* Code for the submissions allocation support is defined here
*
......@@ -26,11 +25,10 @@
defined('MOODLE_INTERNAL') || die();
/**
* Allocators are responsible for assigning submissions to reviewers for assessments
*
* The task of the allocator is to assign the correct number of submissions to reviewers
* The task of the allocator is to assign the correct number of submissions to reviewers
* for assessment. Several allocation methods are expected and they can be combined. For
* example, teacher can allocate several submissions manually (by 'manual' allocator) and
* then let the other submissions being allocated randomly (by 'random' allocator).
......@@ -38,27 +36,29 @@ defined('MOODLE_INTERNAL') || die();
* workshop_assessments table.
*/
interface workshop_allocator {
/**
* Initialize the allocator and eventually process submitted data
*
* This method is called soon after the allocator is constructed and before any output
* This method is called soon after the allocator is constructed and before any output
* is generated. Therefore is may process any data submitted and do other tasks.
* It should not generate any output
*
* @throws moodle_workshop_exception
* @return void
* @return mixed void or optional HTML string
*/
public function init();
/**
* Returns HTML to be displayed as the user interface
* Print HTML to be displayed as the user interface
*
* If a form is part of the UI, the caller should have call $PAGE->set_url(...)
*
* @return string HTML to be displayed
* If a form is part of the UI, the caller should have called $PAGE->set_url(...)
* The methods must produce output instead of just returning it so mform->display() can
* be used there.
*
* @param object $wsoutput workshop module renderer can be used
* @return void
*/
public function ui();
public function ui(moodle_mod_workshop_renderer $wsoutput);
}
<?php
// This file is part of Moodle - http://moodle.org/
//
// 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
......@@ -11,14 +11,13 @@
// 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/>.
/**
* Allows user to allocate the submissions manually
*
*
* @package mod-workshop
* @copyright 2009 David Mudrak <david.mudrak@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
......@@ -29,17 +28,15 @@ defined('MOODLE_INTERNAL') || die();
require_once(dirname(dirname(__FILE__)) . '/lib.php'); // interface definition
require_once(dirname(dirname(dirname(__FILE__))) . '/locallib.php'); // workshop internal API
/**
* These constants are used to pass status messages between init() and ui()
*/
define('WORKSHOP_ALLOCATION_MANUAL_MSG_ADDED', 1);
define('WORKSHOP_ALLOCATION_MANUAL_MSG_NOSUBMISSION', 2);
define('WORKSHOP_ALLOCATION_MANUAL_MSG_EXISTS', 3);
define('WORKSHOP_ALLOCATION_MANUAL_MSG_WOSUBMISSION', 4);
define('WORKSHOP_ALLOCATION_MANUAL_MSG_CONFIRM_DEL', 5);
define('WORKSHOP_ALLOCATION_MANUAL_MSG_DELETED', 6);
define('WORKSHOP_ALLOCATION_MANUAL_MSG_CONFIRM_DEL', 4);
define('WORKSHOP_ALLOCATION_MANUAL_MSG_DELETED', 5);
define('WORKSHOP_ALLOCATION_MANUAL_MSG_DELETE_ERROR', 6);
/**
* Allows users to allocate submissions for review manually
......@@ -49,16 +46,13 @@ class workshop_manual_allocator implements workshop_allocator {
/** workshop instance */
protected $workshop;
/**
* @param stdClass $workshop Workshop record
*/
public function __construct(workshop $workshop) {
$this->workshop = $workshop;
}
/**
* Allocate submissions as requested by user
*/
......@@ -75,14 +69,12 @@ 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_recordset($authorid);
$submission = $rs->current();
$rs->close();
if (empty($submission->id)) {
$submission = $this->workshop->get_submission_by_author($authorid);
if (!$submission) {
// nothing submitted by the given user
$m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_NOSUBMISSION;
$m[] = $authorid;
} else {
// ok, we have the submission
$res = $this->workshop->add_allocation($submission, $reviewerid);
......@@ -90,10 +82,6 @@ class workshop_manual_allocator implements workshop_allocator {
$m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_EXISTS;
$m[] = $submission->userid;
$m[] = $reviewerid;
} elseif ($res == WORKSHOP_ALLOCATION_WOSUBMISSION) {
$m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_WOSUBMISSION;
$m[] = $submission->userid;
$m[] = $reviewerid;
} else {
$m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_ADDED;
$m[] = $submission->userid;
......@@ -109,10 +97,8 @@ 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_recordset('all', $assessmentid);
$assessment = $rs->current();
$rs->close();
if (!empty($assessment)) {
$assessment = $this->workshop->get_assessment_by_id($assessmentid);
if ($assessment) {
if (!$confirmed) {
$m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_CONFIRM_DEL;
$m[] = $assessment->id;
......@@ -124,10 +110,15 @@ class workshop_manual_allocator implements workshop_allocator {
$m[] = 1;
}
} else {
$res = $this->workshop->delete_assessment($assessment->id);
$m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_DELETED;
$m[] = $assessment->authorid;
$m[] = $assessment->reviewerid;
if($this->workshop->delete_assessment($assessment->id)) {
$m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_DELETED;
$m[] = $assessment->authorid;
$m[] = $assessment->reviewerid;
} else {
$m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_DELETE_ERROR;
$m[] = $assessment->authorid;
$m[] = $assessment->reviewerid;
}
}
$m = implode('-', $m); // serialize message object to be passed via URL
redirect($PAGE->url->out(false, array('m' => $m), false));
......@@ -136,11 +127,10 @@ class workshop_manual_allocator implements workshop_allocator {
}
}
/**
* Prints user interface - current allocation and a form to edit it
*/
public function ui() {
public function ui(moodle_mod_workshop_renderer $wsoutput) {
global $PAGE;
$hlauthorid = -1; // highlight this author
......@@ -168,12 +158,6 @@ class workshop_manual_allocator implements workshop_allocator {
$msg->text = get_string('nosubmissionfound', 'workshop');
$msg->sty = 'error';
break;
case WORKSHOP_ALLOCATION_MANUAL_MSG_WOSUBMISSION:
$hlauthorid = $m[1];
$hlreviewerid = $m[2];
$msg->text = get_string('cantassesswosubmission', 'workshop');
$sty->sty = 'error';
break;
case WORKSHOP_ALLOCATION_MANUAL_MSG_CONFIRM_DEL:
$hlauthorid = $m[2];
$hlreviewerid = $m[3];
......@@ -191,6 +175,12 @@ class workshop_manual_allocator implements workshop_allocator {
$msg->text = get_string('assessmentdeleted', 'workshop');
$msg->sty = 'ok';
break;
case WORKSHOP_ALLOCATION_MANUAL_MSG_DELETE_ERROR:
$hlauthorid = $m[1];
$hlreviewerid = $m[2];
$msg->text = get_string('assessmentnotdeleted', 'workshop');
$msg->sty = 'error';
break;
}
if ($m[0] == WORKSHOP_ALLOCATION_MANUAL_MSG_CONFIRM_DEL) {
$handler = $PAGE->url->out_action();
......@@ -234,12 +224,12 @@ class workshop_manual_allocator implements workshop_allocator {
}
}
// ok, we have all data. Let it pass to the renderer and return the output
// We have all data. Let it pass to the renderer and return the output
// Here, we do not use neither the core renderer nor the workshop one but use an own one
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);
echo $uioutput->display_allocations($this->workshop, $peer, $hlauthorid, $hlreviewerid, $msg);
}
}
<?php
// This file is part of Moodle - http://moodle.org/
//
// 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
......@@ -11,11 +11,10 @@
// 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
*
......@@ -27,9 +26,9 @@
defined('MOODLE_INTERNAL') || die();
/**
* Manual allocation renderer class
* Manual allocation renderer class
*/
class moodle_mod_workshop_allocation_manual_renderer {
class moodle_mod_workshop_allocation_manual_renderer extends moodle_renderer_base {
/** the underlying renderer to use */
protected $output;
......@@ -39,7 +38,7 @@ class moodle_mod_workshop_allocation_manual_renderer {
/**
* 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
......@@ -50,11 +49,10 @@ class moodle_mod_workshop_allocation_manual_renderer {
$this->output = $output;
}
/**
* Display the table of all current allocations and widgets to modify them
*
* @param workshop $workshop workshop instance object
*
* @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
......@@ -63,12 +61,13 @@ class moodle_mod_workshop_allocation_manual_renderer {
*/
public function display_allocations(workshop $workshop, &$peers, $hlauthorid=null, $hlreviewerid=null, $msg=null) {
$wsoutput = $this->page->theme->get_renderer('mod_workshop', $this->page);
if (empty($peers)) {
return $this->status_message((object)array('text' => get_string('nosubmissions', 'workshop')));
return $wsoutput->status_message((object)array('text' => get_string('nosubmissions', 'workshop')));
}
$table = new html_table();
$table->set_classes = array('allocations');
$table->set_classes('allocations');
$table->head = array(get_string('participantreviewedby', 'workshop'),
get_string('participant', 'workshop'),
get_string('participantrevierof', 'workshop'));
......@@ -87,68 +86,53 @@ class moodle_mod_workshop_allocation_manual_renderer {
if ($user->id == $hlreviewerid) {
$thisrowclasses[] = 'highlightreviewerof';
}
$table->rowclass[] = implode(' ', $thisrowclasses);
$table->rowclasses[] = implode(' ', $thisrowclasses);
$table->data[] = $row;
}
return $this->output->container($this->status_message($msg) . $this->output->table($table), 'manual-allocator');
return $this->output->container($wsoutput->status_message($msg) . $this->output->table($table), 'manual-allocator');
}
/**
* Returns html code for a status message
*
* @param string $message to display
* @return string html
* Returns information about the workshop participant
*
* @param stdClass $user participant data
* @return string HTML code
*/
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";
$o .= $this->output->container_start(array('submission'));
if (is_null($user->submissionid)) {
$o .= '<span class="info">' . get_string('nosubmissionfound', 'workshop');
$o .= $this->output->output_tag('span', array('class' => 'info'), get_string('nosubmissionfound', 'workshop'));
} else {
$o .= '<div class="title"><a href="#">' . s($user->submissiontitle) . '</a></div>';
$submlink = $this->output->output_tag('a', array('href' => '#'), s($user->submissiontitle));
$o .= $this->output->container($submlink, array('title'));
if (is_null($user->submissiongrade)) {
$o .= '<div class="grade missing">' . get_string('nogradeyet', 'workshop') . '</div>';
$o .= $this->output->container(get_string('nogradeyet', 'workshop'), array('grade', 'missing'));
} else {
$o .= '<div class="grade">' . s($user->submissiongrade) . '</div>'; // todo calculate
$o .= $this->output->container(s($user->submissiongrade), array('grade')); // TODO calculate grade
}
}
$o .= '</div>' . "\n";
$o .= $this->output->container_end();
return $o;
}
protected function reviewers_of_participant(stdClass $user, workshop $workshop, &$peers) {
/**
* Returns information about the current reviewers of the given participant and a selector do add new one
*
* @param stdClass $user participant data
* @param workshop_api $workshop workshop record
* @param array $peers objects with properties to display picture and fullname
* @return string html code
*/
protected function reviewers_of_participant(stdClass $user, workshop_api $workshop, &$peers) {
$o = '';
if (is_null($user->submissionid)) {
$o .= '<span class="info">' . "\n";
$o .= get_string('nothingtoreview', 'workshop');
$o .= '</span>' . "\n";
$o .= $this->output->output_tag('span', array('class' => 'info'), get_string('nothingtoreview', 'workshop'));
} else {
$options = array();
foreach ($workshop->get_peer_reviewers() as $reviewer) {
foreach ($workshop->get_peer_reviewers(!$workshop->assesswosubmission) as $reviewer) {
$options[$reviewer->id] = fullname($reviewer);
}
if (!$workshop->useselfassessment) {
......@@ -156,73 +140,66 @@ class moodle_mod_workshop_allocation_manual_renderer {
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";
$o .= $this->output->output_start_tag('ul', array());
foreach ($user->reviewedby as $reviewerid => $assessmentid) {
$o .= '<li>';
$o .= $this->output->output_start_tag('li', array());
$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 .= $this->output->output_tag('a', array('href' => $handler), ' X ');
$o .= '</li>';
$o .= $this->output->output_end_tag('li');
}
$o .= '</ul>' . "\n";
$o .= $this->output->output_end_tag('ul');
return $o;
}
protected function reviewees_of_participant(stdClass $user, workshop $workshop, &$peers) {
/**
* Returns information about the current reviewees of the given participant and a selector do add new one
*
* @param stdClass $user participant data
* @param workshop_api $workshop workshop record
* @param array $peers objects with properties to display picture and fullname
* @return string html code
*/
protected function reviewees_of_participant(stdClass $user, workshop_api $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>';
if (is_null($user->submissionid)) {
$o .= $this->output->container(get_string('withoutsubmission', 'workshop'), 'info');
}
$options = array();
foreach ($workshop->get_peer_authors() 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]);
}
$o .= '</ul>' . "\n";
}
$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 .= $this->output->output_start_tag('ul', array());
foreach ($user->reviewerof as $authorid => $assessmentid) {
$o .= $this->output->output_start_tag('li', array());
$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 .= $this->output->output_tag('a', array('href' => $handler), ' X ');
$o .= $this->output->output_end_tag('li');
}
$o .= $this->output->output_end_tag('ul');
return $o;
}
}
<?php
// This file is part of Moodle - http://moodle.org/
//
// 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
......@@ -11,14 +11,13 @@
// 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.
//
//