--- /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/>.
+
+
+/**
+ * At this page, teachers allocate submissions to students for a review
+ *
+ * The allocation logic itself is delegated to allocators - subplugins in ./allocation
+ * folder.
+ *
+ * @package mod-workshop
+ * @copyright 2009 David Mudrak <david.mudrak@gmail.com>
+ * @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');
+require_once(dirname(__FILE__).'/allocation/lib.php');
+
+$cmid = required_param('cmid', PARAM_INT); // course module
+$method = optional_param('method', 'manual', PARAM_ALPHA); // method to use
+
+$PAGE->set_url('mod/workshop/allocation.php', array('cmid' => $cmid));
+
+if (!$cm = get_coursemodule_from_id('workshop', $cmid)) {
+ print_error('invalidcoursemodule');
+}
+if (!$course = $DB->get_record('course', array('id' => $cm->course))) {
+ print_error('coursemisconf');
+}
+if (!$workshop = $DB->get_record('workshop', array('id' => $cm->instance))) {
+ print_error('err_invalidworkshopid', 'workshop');
+}
+
+$workshop = new workshop_api($workshop, $cm);
+
+require_login($course, false, $cm);
+
+$context = $PAGE->context;
+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
+$navigation = build_navigation(get_string('allocation', 'workshop'), $cm);
+
+$allocator = workshop_allocator_instance($workshop, $method);
+try {
+ $allocator->init();
+}
+catch (moodle_workshop_exception $e) {
+ echo $OUTPUT->header($navigation);
+ throw $e;
+}
+
+//
+// Output starts here
+//
+echo $OUTPUT->header($navigation);
+
+$allocators = workshop_installed_allocators();
+$tabrow = array();
+foreach ($allocators as $methodid => $methodname) {
+ $tabrow[] = new tabobject($methodid, "allocation.php?cmid={$cmid}&method={$methodid}", $methodname);
+}
+print_tabs(array($tabrow), $method);
+
+echo $OUTPUT->container_start('allocator allocator-' . $method);
+echo $allocator->ui();
+echo $OUTPUT->container_end();
+
+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/>.
+
+
+/**
+ * Code for the submissions allocation support is defined here
+ *
+ * @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();
+
+
+/**
+ * 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
+ * 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).
+ * Allocation is actually done by creating an initial assessment record in the
+ * 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
+ * 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
+ */
+ public function init();
+
+
+ /**
+ * Returns HTML to be displayed as the user interface
+ *
+ * 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);
+}
+
--- /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/>.
+
+
+/**
+ * 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
+ */
+
+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);
+
+
+/**
+ * Allows users to allocate submissions for review manually
+ */
+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
+ */
+ public function init() {
+ global $PAGE;
+
+ $mode = optional_param('mode', 'display', PARAM_ALPHA);
+
+ switch ($mode) {
+ case 'new':
+ if (!confirm_sesskey()) {
+ throw new moodle_workshop_exception($this->workshop, 'confirmsesskeybad');
+ }
+ $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);
+ $submission = $rs->current();
+ $rs->close();
+ 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);
+ if ($res == WORKSHOP_ALLOCATION_EXISTS) {
+ $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;
+ $m[] = $reviewerid;
+ }
+ }
+ $m = implode('-', $m); // serialize message object to be passed via URL
+ redirect($PAGE->url->out(false, array('m' => $m), false));
+ break;
+ case 'del':
+ if (!confirm_sesskey()) {
+ throw new moodle_workshop_exception($this->workshop, 'confirmsesskeybad');
+ }
+ $assessmentid = required_param('what', PARAM_INT);
+ $confirmed = optional_param('confirm', 0, PARAM_INT);
+ $rs = $this->workshop->get_assessments('all', $assessmentid);
+ $assessment = $rs->current();
+ $rs->close();
+ if ($assessment) {
+ if (!$confirmed) {
+ $m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_CONFIRM_DEL;
+ $m[] = $assessment->id;
+ $m[] = $assessment->authorid;
+ $m[] = $assessment->reviewerid;
+ if (is_null($assessment->grade)) {
+ $m[] = 0;
+ } else {
+ $m[] = 1;
+ }
+ } else {
+ $res = $this->workshop->delete_assessment($assessment->id);
+ $m[] = WORKSHOP_ALLOCATION_MANUAL_MSG_DELETED;
+ $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));
+ }
+ break;
+ }
+
+ // if we stay on this page, set the environment
+ $PAGE->requires->css('mod/workshop/allocation/manual/ui.css');
+ }
+
+
+ /**
+ * Prints user interface - current allocation and a form to edit it
+ */
+ 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
+
+ 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';
+ break;
+ case WORKSHOP_ALLOCATION_MANUAL_MSG_EXISTS:
+ $hlauthorid = $m[1];
+ $hlreviewerid = $m[2];
+ $msg = get_string('allocationexists', 'workshop');
+ $sty = 'info';
+ break;
+ case WORKSHOP_ALLOCATION_MANUAL_MSG_NOSUBMISSION:
+ $hlauthorid = $m[1];
+ $msg = get_string('nosubmissionfound', 'workshop');
+ $sty = 'error';
+ break;
+ case WORKSHOP_ALLOCATION_MANUAL_MSG_WOSUBMISSION:
+ $hlauthorid = $m[1];
+ $hlreviewerid = $m[2];
+ $msg = get_string('cantassesswosubmission', 'workshop');
+ $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';
+ } else {
+ $msg = get_string('areyousuretodeallocategraded', 'workshop');
+ $sty = 'error';
+ }
+ break;
+ case WORKSHOP_ALLOCATION_MANUAL_MSG_DELETED:
+ $hlauthorid = $m[1];
+ $hlreviewerid = $m[2];
+ $msg = get_string('assessmentdeleted', 'workshop');
+ $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),
+ get_string('iamsure', 'workshop'), 'post', '', true);
+ }
+ $o .= '</div>';
+ }
+
+ $peer = array(); // singular chosen due to readibility
+ $rs = $this->workshop->get_allocations();
+ foreach ($rs as $allocation) {
+ $currentuserid = $allocation->authorid;
+ if (!isset($peer[$currentuserid])) {
+ $peer[$currentuserid] = new stdClass();
+ $peer[$currentuserid]->id = $allocation->authorid;
+ $peer[$currentuserid]->firstname = $allocation->authorfirstname;
+ $peer[$currentuserid]->lastname = $allocation->authorlastname;
+ $peer[$currentuserid]->picture = $allocation->authorpicture;
+ $peer[$currentuserid]->imagealt = $allocation->authorimagealt;
+ $peer[$currentuserid]->avatar = print_user_picture($peer[$currentuserid],
+ $this->workshop->course, null, 16, true);
+ $peer[$currentuserid]->submissionid = $allocation->submissionid;
+ $peer[$currentuserid]->submissiontitle = $allocation->submissiontitle;
+ $peer[$currentuserid]->submissiongrade = $allocation->submissiongrade;
+ $peer[$currentuserid]->reviewedby = array(); // users who are reviewing this user's submission
+ $peer[$currentuserid]->reviewerof = array(); // users whom submission is being reviewed by this user
+ }
+ if (!empty($allocation->reviewerid)) {
+ // example: "submission of user with id 45 is reviewed by user with id 87 in the assessment record 12"
+ $peer[$currentuserid]->reviewedby[$allocation->reviewerid] = $allocation->assessmentid;
+ }
+ }
+ $rs->close();
+
+ 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])) {
+ $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() . '&mode=new&of=' . $user->id . '&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&by=' . $user->id . '&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;
+ }
+
+
+ /**
+ * 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;
+ }
+
+}
+
--- /dev/null
+.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;
+}
+
+
--- /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/>.
+
+
+/**
+ * Allocates the submissions randomly
+ *
+ * @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(dirname(dirname(__FILE__)) . '/lib.php'); // interface definition
+
+
+class workshop_random_allocator implements workshop_allocator {
+
+ /** workshop instance */
+ protected $workshop;
+
+ /** array of allocations */
+ protected $allocation = array();
+
+ public function __construct(stdClass $workshop) {
+ global $DB, $USER;
+
+ $this->workshop = $workshop;
+
+ // submissions to be allocated
+ $submissions = $DB->get_records('workshop_submissions', array('workshopid' => $this->workshop->id, 'example' => 0),
+ '', 'id,userid,title');
+
+
+ // dummy allocation - allocate all submissions to the current USER
+ foreach ($submissions as $submissionid => $submission) {
+ $this->allocation[$submissionid] = new stdClass;
+ $this->allocation[$submissionid]->submissionid = $submissionid;
+ $this->allocation[$submissionid]->title = $submission->title;
+ $this->allocation[$submissionid]->authorid = $submission->userid;
+ $this->allocation[$submissionid]->reviewerid = $USER->id;
+ $this->allocation[$submissionid]->assessmentid = NULL;
+ }
+
+ // already created assessments
+ $assessments = $DB->get_records_list('workshop_assessments', 'submissionid', array_keys($submissions),
+ '', 'id,submissionid,userid');
+
+ foreach ($assessments as $assessmentid => $assessment) {
+ $this->allocation[$assessment->submissionid]->assessmentid = $assessmentid;
+ }
+ }
+
+
+ public function init() {
+ }
+
+
+ public function ui() {
+ return 'TODO';
+ }
+
+
+}
*/
require_once(dirname(dirname(dirname(__FILE__))).'/config.php');
-//require_once(dirname(__FILE__).'/lib.php');
require_once(dirname(__FILE__).'/locallib.php');
if ($preview = optional_param('preview', 0, PARAM_INT)) {
require_login($course, false, $cm);
-$context = get_context_instance(CONTEXT_MODULE, $cm->id);
+$workshop = new workshop_api($workshop, $cm);
+
+$context = $PAGE->context;
if (isguestuser()) {
print_error('err_noguests', 'workshop', "$CFG->wwwroot/mod/workshop/view.php?id=$cmid");
$editurl = "{$CFG->wwwroot}/mod/workshop/editform.php?cmid={$cm->id}";
// load the grading strategy logic
-$strategy = workshop_strategy_instance($workshop);
+$strategy = $workshop->grading_strategy_instance();
// load the assessment form definition from the database
// this must be called before get_assessment_form() where we have to know
*/
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
require_login($course, false, $cm);
-$context = get_context_instance(CONTEXT_MODULE, $cm->id);
+$context = $PAGE->context;
if (isguestuser()) {
print_error('err_noguests', 'workshop', "$CFG->wwwroot/mod/workshop/view.php?id=$cmid");
print_error('err_invalidworkshopid', 'workshop');
}
+$workshop = new workshop_api($workshop, $cm)l
+
// where should the user be sent after closing the editing form
$returnurl = "{$CFG->wwwroot}/mod/workshop/view.php?id={$cm->id}";
// the URL of this editing form
$previewurl = "{$CFG->wwwroot}/mod/workshop/assessment.php?preview={$cm->id}";
// load the grading strategy logic
-$strategy = workshop_strategy_instance($workshop);
+$strategy = $workshop->grading_strategy_instance();
// load the assessment form definition from the database
// this must be called before get_edit_strategy_form() where we have to know
$string[''] = '';
$string[''] = '';
$string[''] = '';
-$string[''] = '';
-$string[''] = '';
-$string[''] = '';
-$string[''] = '';
-$string[''] = '';
-$string[''] = '';
-$string[''] = '';
-$string[''] = '';
-$string[''] = '';
-$string[''] = '';
-$string[''] = '';
-$string[''] = '';
$string['accesscontrol'] = 'Access control';
$string['addmoredimensionsaccumulative'] = 'Blanks for $a more aspects';
$string['addmoredimensionsnoerrors'] = 'Blanks for $a more assertions';
+$string['addreviewee'] = 'Add reviewee';
+$string['addreviewer'] = 'Add reviewer';
+$string['addsubmissiontoreview'] = 'Assign submission';
$string['agreeassessments'] = 'Assessments must be agreed';
$string['agreeassessmentsdesc'] = 'Authors may comment assessments of their work and agree/disagree with it';
+$string['allocationadded'] = 'The submission has been successfully allocated';
+$string['allocationexists'] = 'The allocation already exists';
+$string['allocationmanual'] = 'Manual allocation';
+$string['allocationrandom'] = 'Random allocation';
+$string['allocation'] = 'Submission allocation';
+$string['allocationview'] = 'View current allocations';
+$string['areyousuretodeallocate'] = 'Are you sure you want deallocate the selected assessment?';
+$string['areyousuretodeallocategraded'] = 'You are going to remove the assessment that has already been graded. Are you really sure you want to do it?';
$string['assessallexamples'] = 'Assess all examples';
$string['assessingsubmission'] = 'Assessing submission';
$string['assessmentcomps'] = 'Required level of assessments similarity';
+$string['assessmentdeleted'] = 'Submission deallocated and assessment deleted';
$string['assessmentend'] = 'End of assessment phase';
$string['assessmentform'] = 'Assessment form';
$string['assessmentsettings'] = 'Assessment settings';
$string['assesswosubmission'] = 'Assess without submission';
$string['assesswosubmissiondesc'] = 'Users can assess peers even without their own submission';
$string['backtoeditform'] = 'Back to editing form';
+$string['cantassesswosubmission'] = 'Users can\'t assess without own submission in this workshop';
$string['comparisonhigh'] = 'High';
$string['comparisonlow'] = 'Low';
$string['comparisonnormal'] = 'Normal';
$string['gradeforassessment'] = 'Grade for assessment';
$string['gradeforsubmission'] = 'Grade for submission';
$string['gradingsettings'] = 'Grading settings';
+$string['chooseuser'] = 'Choose user...';
+$string['iamsure'] = 'Yes, I am sure';
$string['introduction'] = 'Introduction';
$string['latesubmissionsdesc'] = 'Allow submitting the work after the deadline';
$string['latesubmissions'] = 'Late submissions';
$string['maxbytes'] = 'Maximum file size';
+$string['messageclose'] = '(hide)';
$string['modulenameplural'] = 'Workshops';
$string['modulename'] = 'Workshop';
$string['nattachments'] = 'Maximum number of submission attachments';
$string['noerrorsgrade1'] = 'Word for the success';
$string['noerrorsmaperror'] = 'Number of errors is less than or equals';
$string['noerrorsmapgrade'] = 'Grade for submission';
+$string['nogradeyet'] = 'No grade yet';
+$string['nosubmissionfound'] = 'No submission found for this user';
+$string['nosubmissions'] = 'No submissions yet in this workshop';
+$string['nothingtoreview'] = 'Nothing to review';
$string['nsassessments'] = 'Number of required assessments of other users\' work';
+$string['participant'] = 'Participant';
+$string['participantrevierof'] = 'Participant is reviewer of';
+$string['participantreviewedby'] = 'Participant is reviewed by';
$string['percents'] = '$a%';
$string['previewassessmentform'] = 'Preview';
$string['releasegrades'] = 'Push final grades into the gradebook';
define('WORKSHOP_COMPARISON_VERYHIGH', 4); /* f = 5.00 */
+/**
+ * The base class of workshop instances
+ *
+ * The class just wraps the database record from the {workshop} table and adds some
+ * methods that implement the compulsory activity module API.
+ * For full-featured class see {@link workshop_api}.
+ */
+class workshop {
+
+ /** course module record */
+ public $cm;
+
+ /**
+ * Defines methods that are part of any activity module API and may be called by Moodle core
+ *
+ * Initializes the object using the data from DB. Makes deep copy of all $dbrecord properties.
+ *
+ * @param object $instance The instance data row from {workshop} table
+ * @param object $cm Course module record
+ */
+ public function __construct(stdClass $instance, stdClass $cm) {
+
+ foreach ($instance as $key => $val) {
+ if (is_object($val) || (is_array($val))) {
+ // this should not happen if the $dbrecord is really just the record returned by $DB
+ $this->{$key} = unserialize(serialize($val));
+ } else {
+ $this->{$key} = $val;
+ }
+ }
+ $this->cm = $cm;
+ }
+
+
+ /**
+ * Saves a new instance of the workshop into the database
+ *
+ * Given an object containing all the necessary data,
+ * (defined by the form in mod_form.php) this function
+ * will save a new instance and return the id number
+ * of the new instance.
+ *
+ * @param object $data An object from the form in mod_form.php
+ * @return int The id of the newly inserted workshop record
+ */
+ public static function add_instance($data) {
+ global $DB;
+
+ $data->timecreated = time();
+ $data->timemodified = $data->timecreated;
+
+ return $DB->insert_record('workshop', $data);
+ }
+}
+
+
/**
* Given an object containing all the necessary data,
* (defined by the form in mod_form.php) this function
* will create a new instance and return the id number
* of the new instance.
*
- * @param object $workshop An object from the form in mod_form.php
+ * @param object $data An object from the form in mod_form.php
* @return int The id of the newly inserted workshop record
*/
-function workshop_add_instance($workshop) {
- global $DB;
-
- $workshop->timecreated = time();
- $workshop->timemodified = $workshop->timecreated;
-
- return $DB->insert_record('workshop', $workshop);
+function workshop_add_instance($data) {
+ return workshop::add_instance($data);
}
}
-/**
- * Return an array of the localized allocation names
- *
- * @access public
- * @return array Array ['string' => 'string']
- */
-function workshop_get_allocations() {
-
- $installed = get_list_of_plugins('mod/workshop/allocation');
- $forms = array();
- foreach ($installed as $allocation) {
- $forms[$allocation] = get_string('allocation' . $allocation, 'workshop');
- }
-
- return $forms;
-}
-
-
/**
* Return an array of available example assessment modes
*
/**
- * Library of internal functions for module workshop
+ * Library of internal classes and functions for module workshop
*
* All the workshop specific functions, needed to implement the module
- * logic, should go to here.
+ * logic, should go to here. Instead of having bunch of function named
+ * workshop_something() taking the workshop instance as the first
+ * parameter, we use a class workshop_api that provides all methods.
*
* @package mod-workshop
* @copyright 2009 David Mudrak <david.mudrak@gmail.com>
defined('MOODLE_INTERNAL') || die();
-function workshop_strategy_instance($workshop) {
- /** static variable to hold the singleton */
- static $instance = null;
+require_once(dirname(__FILE__).'/lib.php'); // we extend this library here
- if (is_null($instance)) {
- $strategylib = dirname(__FILE__) . '/grading/' . $workshop->strategy . '/strategy.php';
- if (is_readable($strategylib)) {
- require_once($strategylib);
+define('WORKSHOP_ALLOCATION_EXISTS', -1); // return status of {@link add_allocation}
+define('WORKSHOP_ALLOCATION_WOSUBMISSION', -2); // return status of {@link add_allocation}
+
+
+/**
+ * Full-featured workshop API
+ *
+ * This extends the module base API and adds the internal methods that are called
+ * from the module itself. The class should be initialized right after you get
+ * $workshop and $cm records at the begining of the script.
+ */
+class workshop_api extends workshop {
+
+ /** grading strategy instance */
+ protected $strategy_api=null;
+
+ /**
+ * Initialize the object using the data from DB
+ *
+ * @param object $instance The instance data row from {workshop} table
+ * @param object $md Course module record
+ */
+ public function __construct($instance, $cm) {
+ parent::__construct($instance, $cm);
+ }
+
+
+ /**
+ * Fetches all users with the capability mod/workshop:submit in the current context
+ *
+ * Static variable used to cache the results. The returned objects contain id, lastname
+ * and firstname properties and are ordered by lastname,firstname
+ *
+ * @param object $context The context instance where the capability should be checked
+ * @return array Array of '(int)userid => (stdClass)userinfo'
+ */
+ public function get_peer_authors() {
+ static $users=null;
+
+ if (is_null($users)) {
+ $context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
+ $users = get_users_by_capability($context, 'mod/workshop:submit',
+ 'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
+ }
+ return $users;
+ }
+
+
+ /**
+ * Fetches all users with the capability mod/workshop:peerassess in the current context
+ *
+ * Static variable used to cache the results. The returned objects contain id, lastname
+ * and firstname properties and are ordered by lastname,firstname
+ *
+ * @param object $context The context instance where the capability should be checked
+ * @return array Array of '(int)userid => (stdClass)userinfo'
+ */
+ public function get_peer_reviewers() {
+ global $DB;
+ static $users=null;
+
+ if (is_null($users)) {
+ $context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
+ $users = get_users_by_capability($context, 'mod/workshop:peerassess',
+ 'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
+ }
+ if (!$this->assesswosubmission) {
+ $userswithsubmission = array();
+ // users without their own submission can not be reviewers
+ $rs = $DB->get_recordset_list('workshop_submissions', 'userid', array_keys($users),'', 'id,userid');
+ foreach ($rs as $submission) {
+ if (isset($users[$submission->userid])) {
+ $userswithsubmission[$submission->userid] = 'submission_exists';
+ } else {
+ // this is a submission by a user who does not have mod/workshop:peerassess
+ // this is either bug or workshop capabilities have been overridden after the submission
+ }
+ }
+ $rs->close();
+ return array_intersect_key($users, $userswithsubmission);
} else {
- throw new moodle_exception('missingstrategy', 'workshop');
+ return $users;
}
- $classname = 'workshop_' . $workshop->strategy . '_strategy';
- $instance = new $classname($workshop);
}
- return $instance;
+
+ /**
+ * Returns submissions from this workshop
+ *
+ * Fetches data from {workshop_submissions} and adds some useful information from other
+ * tables.
+ *
+ * @param mixed $userid If set to integer ID, return submission of the given user only
+ * @param mixed $examples false|true|all Only regular submissions, only examples, all submissions
+ * @todo unittest
+ * @return object moodle_recordset
+ */
+ public function get_submissions($userid='all', $examples=false) {
+ global $DB;
+
+ $sql = 'SELECT s.*, u.lastname AS authorlastname, u.firstname AS authorfirstname
+ FROM {workshop_submissions} s
+ JOIN {user} u ON (s.userid = u.id)
+ WHERE s.workshopid = ?';
+ $params[0] = $this->id;
+
+ if ($examples === false) {
+ $sql .= ' AND example = 0';
+ }
+ if ($examples === true) {
+ $sql .= ' AND example = 1';
+ }
+ if (is_int($userid)) {
+ $sql .= ' AND userid = ?';
+ $params = array_merge($params, array($userid));
+ }
+ if (is_array($userid)) {
+ list($usql, $uparams) = $DB->get_in_or_equal($userid);
+ $sql .= ' AND userid ' . $usql;
+ $params = array_merge($params, $uparams);
+ }
+
+ return $DB->get_recordset_sql($sql, $params);
+ }
+
+
+ /**
+ * Returns the list of assessments with some data added
+ *
+ * Fetches data from {workshop_assessments} and adds some useful information from other
+ * tables.
+ *
+ * @param mixed $reviewerid 'all'|int|array User ID of the reviewer
+ * @param mixed $id 'all'|int Assessment ID
+ * @return object moodle_recordset
+ */
+ public function get_assessments($reviewerid='all', $id='all') {
+ global $DB;
+
+ $sql = 'SELECT a.*,
+ reviewer.id AS reviewerid,reviewer.firstname AS reviewerfirstname,reviewer.lastname as reviewerlastname,
+ s.title,
+ author.id AS authorid, author.firstname AS authorfirstname,author.lastname as authorlastname
+ FROM {workshop_assessments} a
+ LEFT JOIN {user} reviewer ON (a.userid = reviewer.id)
+ LEFT JOIN {workshop_submissions} s ON (a.submissionid = s.id)
+ LEFT JOIN {user} author ON (s.userid = author.id)
+ WHERE s.workshopid = ?';
+ $params = array($this->id);
+ if (is_int($reviewerid)) {
+ $sql .= ' AND reviewerid = ?';
+ $params = array_merge($params, array($reviewerid));
+ }
+ if (is_array($reviewerid)) {
+ list($usql, $uparams) = $DB->get_in_or_equal($reviewerid);
+ $sql .= ' AND reviewerid ' . $usql;
+ $params = array_merge($params, $uparams);
+ }
+ if (is_int($id)) {
+ $sql .= ' AND a.id = ?';
+ $params = array_merge($params, array($id));
+ }
+
+ return $DB->get_recordset_sql($sql, $params);
+ }
+
+
+ /**
+ * Returns the list of allocations in the workshop
+ *
+ * This returns the list of all users who can submit their work or review submissions (or both
+ * which is the common case). So basically this is to return list of all students participating
+ * in the workshop. For every participant, it adds information about their submission and their
+ * reviews. This is mainly intended for allocation reports and originally was written for
+ * manula allocation ui.
+ *
+ * The returned structure is recordset of objects with following properties:
+ * [authorid] [authorfirstname] [authorlastname] [authorpicture] [authorimagealt]
+ * [submissionid] [submissiontitle] [submissiongrade] [assessmentid]
+ * [timeallocated] [reviewerid] [reviewerfirstname] [reviewerlastname]
+ * [reviewerpicture] [reviewerimagealt]
+ *
+ * This should be refactored when capability handling proposed by Petr is implemented so that
+ * we can check capabilities directly in SQL joins.
+ *
+ * @return object moodle_recordset
+ */
+ public function get_allocations() {
+ global $DB;
+ static $users=null;
+
+ if (is_null($users)) {
+ $context = get_context_instance(CONTEXT_MODULE, $this->cm->id);
+ $users = get_users_by_capability($context, array('mod/workshop:submit', 'mod/workshop:peerassess'),
+ 'u.id', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
+ }
+
+ list($usql, $params) = $DB->get_in_or_equal(array_keys($users));
+ $params[] = $this->id;
+
+ $sql = 'SELECT author.id AS authorid, author.firstname AS authorfirstname, author.lastname AS authorlastname,
+ author.picture AS authorpicture, author.imagealt AS authorimagealt,
+ s.id AS submissionid, s.title AS submissiontitle, s.grade AS submissiongrade,
+ 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 {user} author
+ LEFT JOIN {workshop_submissions} s ON (s.userid = author.id)
+ LEFT JOIN {workshop_assessments} a ON (s.id = a.submissionid)
+ LEFT JOIN {user} reviewer ON (a.userid = reviewer.id)
+ WHERE author.id ' . $usql . ' AND (s.workshopid = ? OR s.workshopid IS NULL)
+ ORDER BY author.lastname,author.firstname,reviewer.lastname,reviewer.firstname';
+ return $DB->get_recordset_sql($sql, $params);
+ }
+
+
+ /**
+ * Allocate a submission to a user for review
+ *
+ * @param object $submission Submission record
+ * @param int $reviewerid User ID
+ * @return int ID of the new assessment or an error code
+ */
+ public function add_allocation(stdClass $submission, $reviewerid) {
+ global $DB;
+
+ if ($DB->record_exists('workshop_assessments', array('submissionid' => $submission->id, 'userid' => $reviewerid))) {
+ return WORKSHOP_ALLOCATION_EXISTS;
+ }
+
+ if (!$this->assesswosubmission) {
+ // reviewer must have submitted his own work
+ if (!$DB->record_exists('workshop_submissions', array('workshopid' => $this->id, 'userid' => $reviewerid))) {
+ return WORKSHOP_ALLOCATION_WOSUBMISSION;
+ }
+ }
+
+ $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);
+ }
+
+
+ /**
+ * delete_assessment
+ *
+ * @todo finish and document this method
+ *
+ */
+ public function delete_assessment($id) {
+ global $DB;
+
+ // todo remove all given grades from workshop_grades;
+ return $DB->delete_records('workshop_assessments', array('id' => $id));
+ }
+
+
+ /**
+ * Returns instance of grading strategy class
+ *
+ * @param object $workshop Workshop record
+ * @return object Instance of a grading strategy
+ */
+ public function grading_strategy_instance() {
+
+ if (!($this->strategy === clean_param($workshop->strategy, PARAM_ALPHA))) {
+ throw new moodle_workshop_exception($this, 'invalidstrategyname');
+ }
+
+ if (is_null($this->strategy_api)) {
+ $strategylib = dirname(__FILE__) . '/grading/' . $workshop->strategy . '/strategy.php';
+ if (is_readable($strategylib)) {
+ require_once($strategylib);
+ } else {
+ throw new moodle_exception('missingstrategy', 'workshop');
+ }
+ $classname = 'workshop_' . $workshop->strategy . '_strategy';
+ $this->strategy_api = new $classname($this);
+ if (!in_array('workshop_strategy', class_implements($this->strategy_api))) {
+ throw new moodle_workshop_exception($this, 'strategynotimplemented');
+ }
+ }
+
+ return $this->strategy_api;
+ }
+
+
+
}
+
+
/**
- * Return the user's submission record in the given workshop
+ * Class for workshop exceptions. Just saves a couple of arguments of the
+ * constructor for a moodle_exception.
*
- * Example submissions are not returned. This is intended to return a submission for given
- * student.
- *
- * @param int $workshopid Workshop id
- * @param int $userid Owner id
- * @return mixed A fieldset object containing the first matching record or false if not found
+ * @param object $workshop Should be workshop or its subclass
+ * @param string $errorcode
+ * @param mixed $a Object/variable to pass to get_string
+ * @param string $link URL to continue after the error notice
+ * @param $debuginfo
*/
-function workshop_get_user_submission($workshopid, $userid) {
- global $DB;
+class moodle_workshop_exception extends moodle_exception {
- return $DB->get_record('workshop_submissions', array('workshopid' => $workshopid, 'userid' => $userid, 'example' => 0));
+ function __construct($workshop, $errorcode, $a = NULL, $link = '', $debuginfo = null) {
+ global $CFG;
+
+ if (!$link) {
+ $link = $CFG->wwwroot . '/mod/workshop/view.php?a=' . $workshop->id;
+ }
+ if ('confirmsesskeybad' == $errorcode) {
+ $module = '';
+ } else {
+ $module = 'workshop';
+ }
+ parent::__construct($errorcode, $module, $link, $a, $debuginfo);
+ }
}
+
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-defined('MOODLE_INTERNAL')) || die();
+defined('MOODLE_INTERNAL') || die();
// Make sure the code being tested is accessible.
require_once($CFG->dirroot . '/mod/workshop/lib.php'); // Include the code to test
--- /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/>.
+
+
+/**
+ * Unit tests for workshop_api class defined in mod/workshop/locallib.php
+ *
+ * @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();
+
+// Make sure the code being tested is accessible.
+require_once($CFG->dirroot . '/mod/workshop/locallib.php'); // Include the code to test
+
+
+/**
+ * Test subclass that makes all the protected methods we want to test public.
+ * Also re-implements bridging methods so we can test more easily.
+ */
+class testable_workshop_api extends workshop_api {
+
+}
+
+
+/**
+ * Test cases for the internal workshop api
+ */
+class workshop_api_test extends UnitTestCase {
+
+ /** workshop instance emulation */
+ protected $workshop;
+
+ /** setup testing environment */
+ public function setUp() {
+ $workshoprecord = new stdClass;
+ $workshoprecord->id = 42;
+
+ $cm = new stdClass;
+ $this->workshop = new testable_workshop_api($workshoprecord, $cm);
+ }
+
+ public function tearDown() {
+ $this->workshop = null;
+ }
+
+
+
+}
} else { // no submission specified
//todo require_capability('mod/workshop:submit', $context);
- if (!$submission = workshop_get_user_submission($workshop->id, $USER->id)) {
+ if (!$submission = workshop_get_user_submission($workshop, $USER->id)) {
$submission = new object();
$submission->id = null;
}
$mform = new workshop_submission_form(null, array('current' => $submission, 'cm' => $cm, 'workshop'=>$workshop,
'dataoptions' => $dataoptions, 'attachmentoptions'=>$attachmentoptions));
-if ($mform->is_cancelled()){
- die(); // todo
- if ($id){
- redirect("view.php?id=$cm->id");
- } else {
- redirect("view.php?id=$cm->id");
- }
-
+if ($mform->is_cancelled()) {
+ redirect("view.php?id=$cm->id");
} else if ($submission = $mform->get_data()) {
$timenow = time();
*/
require_once(dirname(dirname(dirname(__FILE__))).'/config.php');
-require_once(dirname(__FILE__).'/lib.php');
require_once(dirname(__FILE__).'/locallib.php');
$id = optional_param('id', 0, PARAM_INT); // course_module ID, or
require_login($course, true, $cm);
+$context = $PAGE->context;
+$workshop = new workshop_api($workshop, $cm);
+
+// todo has_capability() check
+
add_to_log($course->id, "workshop", "view", "view.php?id=$cm->id", "$workshop->id");
/// Print the page header
$PAGE->set_url('mod/workshop/view.php', array('id' => $cm->id));
$PAGE->set_title($workshop->name);
-$PAGE->set_heading($course->shortname);
+$PAGE->set_heading($course->fullname);
$PAGE->set_button(update_module_button($cm->id, $course->id, get_string('modulename', 'workshop')));
// other things you may want to set - remove if not needed
echo $OUTPUT->box_start();
echo $OUTPUT->heading('Workshop administration tools', 3);
-echo "<a href=\"editform.php?cmid={$cm->id}\">Edit grading form (".get_string('strategy' . $workshop->strategy, 'workshop').")</a>";
+echo '<ul>';
+echo "<li><a href=\"editform.php?cmid={$cm->id}\">Edit grading form (".get_string('strategy' . $workshop->strategy, 'workshop').")</a></li>";
+echo "<li><a href=\"allocation.php?cmid={$cm->id}\">Allocate submissions</a></li>";
+echo '</ul>';
echo $OUTPUT->box_end();
echo $OUTPUT->box_start();
echo $OUTPUT->box_start();
echo $OUTPUT->heading(get_string('assessment', 'workshop'), 3);
-$reviewstogive = workshop_get_assessments_for_reviewer($workshop->id, $USER->id);
+$rs = $workshop->get_assessments($USER->id);
echo "You are expected to assess following submissions:";
echo "<ul>";
-foreach ($reviewstogive as $review) {
- echo "<li><a href=\"assessment.php?asid={$review->assessmentid}\">Assessment of '{$review->title}' by {$review->authorid}</a></li>";
+foreach ($rs as $assessment) {
+ echo "<li><a href=\"assessment.php?asid={$assessment->id}\">Assessment of '{$assessment->title}' by {$assessment->authorid}</a></li>";
}
echo "</ul>";
+$rs->close();
echo $OUTPUT->box_end();
echo $OUTPUT->footer();