MDL-19717 workshop manual allocator - pagination support and performance issues

This commit is contained in:
David Mudrak 2010-01-04 18:07:38 +00:00
parent 87a5368df1
commit aa40adbf9f
4 changed files with 319 additions and 230 deletions

View File

@ -57,7 +57,7 @@ $initresult = $allocator->init();
$wsoutput = $PAGE->theme->get_renderer('mod_workshop', $PAGE);
echo $OUTPUT->header();
$allocators = $workshop->installed_allocators();
$allocators = workshop::installed_allocators();
$currenttab = 'allocation';
include(dirname(__FILE__) . '/tabs.php');

View File

@ -33,6 +33,9 @@ require_once(dirname(dirname(dirname(__FILE__))) . '/locallib.php'); // works
*/
class workshop_manual_allocator implements workshop_allocator {
/** participants per page */
const PERPAGE = 30;
/** constants that are used to pass status messages between init() and ui() */
const MSG_ADDED = 1;
const MSG_NOSUBMISSION = 2;
@ -129,15 +132,17 @@ class workshop_manual_allocator implements workshop_allocator {
* Prints user interface - current allocation and a form to edit it
*/
public function ui() {
global $PAGE, $OUTPUT;
global $PAGE, $OUTPUT, $DB;
$pagingvar = 'page';
$page = optional_param($pagingvar, 0, PARAM_INT);
$hlauthorid = -1; // highlight this author
$hlreviewerid = -1; // highlight this reviewer
$msg = new stdClass(); // message to render
$m = optional_param('m', '', PARAM_ALPHANUMEXT); // message stdClass
$m = optional_param('m', '', PARAM_ALPHANUMEXT); // message code
if ($m) {
$m = explode('-', $m); // unserialize
$m = explode('-', $m);
switch ($m[0]) {
case self::MSG_ADDED:
$hlauthorid = $m[1];
@ -190,56 +195,170 @@ class workshop_manual_allocator implements workshop_allocator {
}
}
$peers = array();
$rs = $this->workshop->get_allocations_recordset();
if (!is_null($rs)) {
foreach ($rs as $allocation) {
$currentuserid = $allocation->authorid;
if (!isset($peers[$currentuserid])) {
$peers[$currentuserid] = new stdClass();
$peers[$currentuserid]->id = $allocation->authorid;
$peers[$currentuserid]->firstname = $allocation->authorfirstname;
$peers[$currentuserid]->lastname = $allocation->authorlastname;
$peers[$currentuserid]->picture = $allocation->authorpicture;
$peers[$currentuserid]->imagealt = $allocation->authorimagealt;
$peers[$currentuserid]->submissionid = $allocation->submissionid;
$peers[$currentuserid]->submissiontitle = $allocation->submissiontitle;
$peers[$currentuserid]->submissiongrade = $allocation->submissiongrade;
$peers[$currentuserid]->reviewedby = array(); // users who are reviewing this user's submission
$peers[$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"
$peers[$currentuserid]->reviewedby[$allocation->reviewerid] = $allocation->assessmentid;
}
}
$rs->close();
if ($hlauthorid > 0 and $hlreviewerid > 0) {
// display just those users, no pagination
$participants = get_users_by_capability($PAGE->context, array('mod/workshop:submit', 'mod/workshop:peerassess'),
'u.id,u.lastname,u.firstname,u.picture,u.imagealt', 'u.lastname,u.firstname,u.id',
'', '', '', '', false, false, true);
$participants = array_intersect_key($participants, array($hlauthorid => null, $hlreviewerid => null));
} else {
// the paginated list of users to be displayed in the middle column ("Participant")
$participants = get_users_by_capability($PAGE->context, array('mod/workshop:submit', 'mod/workshop:peerassess'),
'u.id,u.lastname,u.firstname,u.picture,u.imagealt', 'u.lastname,u.firstname,u.id',
$page * self::PERPAGE, self::PERPAGE, '', '', false, false, true);
}
foreach ($peers as $author) {
foreach ($author->reviewedby as $reviewerid => $assessmentid) {
if (isset($peers[$reviewerid])) {
// example: "user with id 87 is reviewer of the work submitted by user id 45 in the assessment record 12"
$peers[$reviewerid]->reviewerof[$author->id] = $assessmentid;
// this will hold the information needed to display user names and pictures
$userinfo = $participants;
// load the participants' submissions
$submissions = $this->workshop->get_submissions(array_keys($participants), false);
// get current reviewers
$reviewers = array();
if ($submissions) {
list($submissionids, $params) = $DB->get_in_or_equal(array_keys($submissions), SQL_PARAMS_NAMED);
$sql = "SELECT a.id AS assessmentid, a.submissionid,
r.id AS reviewerid, r.lastname, r.firstname, r.picture, r.imagealt,
s.id AS submissionid, s.userid AS authorid
FROM {workshop_assessments} a
JOIN {user} r ON (a.userid = r.id)
JOIN {workshop_submissions} s ON (a.submissionid = s.id)
WHERE a.submissionid $submissionids";
$reviewers = $DB->get_records_sql($sql, $params);
foreach ($reviewers as $reviewer) {
if (!isset($userinfo[$reviewer->reviewerid])) {
$userinfo[$reviewer->reviewerid] = new stdClass();
$userinfo[$reviewer->reviewerid]->id = $reviewer->reviewerid;
$userinfo[$reviewer->reviewerid]->firstname = $reviewer->firstname;
$userinfo[$reviewer->reviewerid]->lastname = $reviewer->lastname;
$userinfo[$reviewer->reviewerid]->picture = $reviewer->picture;
$userinfo[$reviewer->reviewerid]->imagealt = $reviewer->imagealt;
$userinfo[$reviewer->reviewerid]->firstname = $reviewer->firstname;
}
}
}
// get current reviewees
list($participantids, $params) = $DB->get_in_or_equal(array_keys($participants), SQL_PARAMS_NAMED);
$params['workshopid'] = $this->workshop->id;
$sql = "SELECT a.id AS assessmentid, a.submissionid,
u.id AS reviewerid,
s.id AS submissionid,
r.id AS revieweeid, r.lastname, r.firstname, r.picture, r.imagealt
FROM {user} u
JOIN {workshop_assessments} a ON (a.userid = u.id)
JOIN {workshop_submissions} s ON (a.submissionid = s.id)
JOIN {user} r ON (s.userid = r.id)
WHERE u.id $participantids AND s.workshopid = :workshopid";
$reviewees = $DB->get_records_sql($sql, $params);
foreach ($reviewees as $reviewee) {
if (!isset($userinfo[$reviewee->revieweeid])) {
$userinfo[$reviewee->revieweeid] = new stdClass();
$userinfo[$reviewee->revieweeid]->id = $reviewee->revieweeid;
$userinfo[$reviewee->revieweeid]->firstname = $reviewee->firstname;
$userinfo[$reviewee->revieweeid]->lastname = $reviewee->lastname;
$userinfo[$reviewee->revieweeid]->picture = $reviewee->picture;
$userinfo[$reviewee->revieweeid]->imagealt = $reviewee->imagealt;
$userinfo[$reviewee->revieweeid]->firstname = $reviewee->firstname;
}
}
// the information about the allocations
$allocations = array();
foreach ($participants as $participant) {
$allocations[$participant->id] = new stdClass;
$allocations[$participant->id]->userid = $participant->id;
$allocations[$participant->id]->submissionid = null;
$allocations[$participant->id]->reviewedby = array();
$allocations[$participant->id]->reviewerof = array();
}
unset($participants);
foreach ($submissions as $submission) {
$allocations[$submission->authorid]->submissionid = $submission->id;
$allocations[$submission->authorid]->submissiontitle = $submission->title;
$allocations[$submission->authorid]->submissiongrade = $submission->grade;
}
unset($submissions);
foreach($reviewers as $reviewer) {
$allocations[$reviewer->authorid]->reviewedby[$reviewer->reviewerid] = $reviewer->assessmentid;
}
unset($reviewers);
foreach($reviewees as $reviewee) {
$allocations[$reviewee->reviewerid]->reviewerof[$reviewee->revieweeid] = $reviewee->assessmentid;
}
unset($reviewees);
// we have all data, let us pass it to the renderer and return the output
$wsoutput = $PAGE->theme->get_renderer('mod_workshop', $PAGE);
$uioutput = $PAGE->theme->get_renderer('workshopallocation_manual', $PAGE);
// prepare data to be displayed
$data = new stdClass();
$data->wsoutput = $wsoutput;
$data->peers = $peers;
$data->authors = $this->workshop->get_potential_authors($PAGE->context);
$data->reviewers = $this->workshop->get_potential_reviewers($PAGE->context);
$data->hlauthorid = $hlauthorid;
$data->hlreviewerid = $hlreviewerid;
$data->msg = $msg;
$data->useselfassessment = $this->workshop->useselfassessment;
return $uioutput->display_allocations($data);
// prepare data to be displayed
$data = new stdClass();
$data->wsoutput = $wsoutput;
$data->allocations = $allocations;
$data->userinfo = $userinfo;
$data->authors = $this->workshop->get_potential_authors($PAGE->context);
$data->reviewers = $this->workshop->get_potential_reviewers($PAGE->context);
$data->hlauthorid = $hlauthorid;
$data->hlreviewerid = $hlreviewerid;
$data->selfassessment = $this->workshop->useselfassessment;
// prepare paging bar
$pagingbar = new moodle_paging_bar();
$pagingbar->totalcount = count($data->authors);
$pagingbar->page = $page;
$pagingbar->perpage = self::PERPAGE;
$pagingbar->baseurl = $PAGE->url;
$pagingbar->pagevar = $pagingvar;
$pagingbar->nocurr = true;
$pagingbarout = $OUTPUT->paging_bar($pagingbar);
return $pagingbarout . $wsoutput->status_message($msg) . $uioutput->display_allocations($data) . $pagingbarout;
}
/**
* Returns the list of all allocations where the given users are involved
*
* We must use recordset here because we do not have any unique identifier available
*
* @param array [userid] => whatever
* @return moodle_recordset|null
*/
protected function get_allocations_recordset(array $users) {
global $DB, $PAGE;
if (empty($users)) {
return null;
}
if (count($users) > 9999) {
throw coding_exception('two many users');
}
list($authorids, $authorparams) = $DB->get_in_or_equal(array_keys($users), SQL_PARAMS_NAMED, 'a0000');
list($reviewerids, $reviewerparams) = $DB->get_in_or_equal(array_keys($users), SQL_PARAMS_NAMED, 'r0000');
$params = array_merge($authorparams, $reviewerparams);
$params['workshopid'] = $this->workshop->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 $authorids OR reviewer.id $reviewerids) AND (s.id IS NULL OR s.workshopid = :workshopid)
ORDER BY author.lastname,author.firstname,author.id,reviewer.lastname,reviewer.firstname,reviewer.id";
return $DB->get_recordset_sql($sql, $params);
}
}

View File

@ -56,16 +56,16 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
*/
public function display_allocations(stdClass $data) {
$wsoutput = $data->wsoutput; // moodle_mod_workshop_renderer
$peers = $data->peers; // array prepared array of all allocations data
$authors = $data->authors; // array submission authors
$allocations = $data->allocations; // array prepared array of all allocations data
$userinfo = $data->userinfo; // names and pictures of all required users
$authors = $data->authors; // array potential reviewees
$reviewers = $data->reviewers; // array potential submission reviewers
$hlauthorid = $data->hlauthorid; // int id of the author to highlight
$hlreviewerid = $data->hlreviewerid; // int id of the reviewer to highlight
$useselfassessment = $data->useselfassessment; // bool is the self-assessment allowed in this workshop?
$msg = $data->msg; // stdClass message to display
$selfassessment = $data->selfassessment; // bool is the self-assessment allowed in this workshop?
$wsoutput = $this->page->theme->get_renderer('mod_workshop', $this->page);
if (empty($peers)) {
if (empty($allocations)) {
return $wsoutput->status_message((object)array('text' => get_string('nosubmissions', 'workshop')));
}
@ -77,41 +77,39 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
$table->rowclasses = array();
$table->colclasses = array('reviewedby', 'peer', 'reviewerof');
$table->data = array();
foreach ($peers as $user) {
foreach ($allocations as $allocation) {
$row = array();
$row[] = $this->reviewers_of_participant($user, $peers, $reviewers, $useselfassessment);
$row[] = $this->participant($user);
$row[] = $this->reviewees_of_participant($user, $peers, $authors, $useselfassessment);
$row[] = $this->reviewers_of_participant($allocation, $userinfo, $reviewers, $selfassessment);
$row[] = $this->participant($allocation, $userinfo);
$row[] = $this->reviewees_of_participant($allocation, $userinfo, $authors, $selfassessment);
$thisrowclasses = array();
if ($user->id == $hlauthorid) {
if ($allocation->userid == $hlauthorid) {
$thisrowclasses[] = 'highlightreviewedby';
}
if ($user->id == $hlreviewerid) {
if ($allocation->userid == $hlreviewerid) {
$thisrowclasses[] = 'highlightreviewerof';
}
$table->rowclasses[] = implode(' ', $thisrowclasses);
$table->data[] = $row;
}
return $this->output->container($wsoutput->status_message($msg) . $this->output->table($table), 'manual-allocator');
return $this->output->container($this->output->table($table), 'manual-allocator');
}
/**
* Returns information about the workshop participant
*
* @param stdClass $user participant data
* @param workshop API
* @return string HTML code
*/
protected function participant(stdClass $user) {
$o = $this->output->user_picture($user, $this->page->course->id);
$o .= fullname($user);
protected function participant(stdClass $allocation, array $userinfo) {
$o = $this->output->user_picture($userinfo[$allocation->userid], $this->page->course->id);
$o .= fullname($userinfo[$allocation->userid]);
$o .= $this->output->container_start(array('submission'));
if (is_null($user->submissionid)) {
if (is_null($allocation->submissionid)) {
$o .= $this->output->container(get_string('nosubmissionfound', 'workshop'), 'info');
} else {
$o .= $this->output->container(format_string($user->submissiontitle), 'title');
if (is_null($user->submissiongrade)) {
$o .= $this->output->container(format_string($allocation->submissiontitle), 'title');
if (is_null($allocation->submissiongrade)) {
$o .= $this->output->container(get_string('nogradeyet', 'workshop'), array('grade', 'missing'));
} else {
$o .= $this->output->container(get_string('alreadygraded', 'workshop'), array('grade', 'missing'));
@ -124,41 +122,38 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
/**
* Returns information about the current reviewers of the given participant and a selector do add new one
*
* @param stdClass $user participant data
* @param array $peers objects with properties to display picture and fullname
* @param array $reviewers potential reviewers
* @param bool $useselfassessment shall a user be offered as a reviewer of him/herself
* @return string html code
*/
protected function reviewers_of_participant(stdClass $user, array $peers, array $reviewers, $useselfassessment) {
protected function reviewers_of_participant(stdClass $allocation, array $userinfo, array $reviewers, $selfassessment) {
$o = '';
if (is_null($user->submissionid)) {
if (is_null($allocation->submissionid)) {
$o .= $this->output->container(get_string('nothingtoreview', 'workshop'), 'info');
} else {
$exclude = array();
if (! $useselfassessment) {
$exclude[$user->id] = true;
if (! $selfassessment) {
$exclude[$allocation->userid] = true;
}
// todo add an option to exclude users without own submission
$options = $this->users_to_menu_options($reviewers, $exclude);
if ($options) {
$handler = new moodle_url($this->page->url, array('mode' => 'new', 'of' => $user->id, 'sesskey' => sesskey()));
$select = html_select::make_popup_form($handler, 'by', $options, 'addreviewof' . $user->id, '',
get_string('addreviewer', 'workshopallocation_manual'));
$handler = new moodle_url($this->page->url,
array('mode' => 'new', 'of' => $allocation->userid, 'sesskey' => sesskey()));
$select = html_select::make_popup_form($handler, 'by', $options, 'addreviewof' . $allocation->userid, '',
get_string('addreviewer', 'workshopallocation_manual'));
$select->nothinglabel = get_string('chooseuser', 'workshop');
$select->set_label(get_string('addreviewer', 'workshopallocation_manual'), $select->id);
$o .= $this->output->select($select);
}
}
$o .= $this->output->output_start_tag('ul', array());
foreach ($user->reviewedby as $reviewerid => $assessmentid) {
foreach ($allocation->reviewedby as $reviewerid => $assessmentid) {
$o .= $this->output->output_start_tag('li', array());
$userpic = new moodle_user_picture();
$userpic->user = $peers[$reviewerid];
$userpic->courseid = $this->page->course->id;
$userpic->size = 16;
$o .= $this->output->user_picture($userpic);
$o .= fullname($peers[$reviewerid]);
$allocationpic = new moodle_user_picture();
$allocationpic->user = $userinfo[$reviewerid];
$allocationpic->courseid = $this->page->course->id;
$allocationpic->size = 16;
$o .= $this->output->user_picture($allocationpic);
$o .= fullname($userinfo[$reviewerid]);
// delete icon
$handler = new moodle_url($this->page->url, array('mode' => 'del', 'what' => $assessmentid, 'sesskey' => sesskey()));
@ -173,28 +168,25 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
/**
* Returns information about the current reviewees of the given participant and a selector do add new one
*
* @param stdClass $user participant data
* @param array $peers objects with properties to display picture and fullname
* @param array $authors potential authors to be reviewed
* @param bool $useselfassessment shall a user be offered as a reviewer of him/herself
* @return string html code
*/
protected function reviewees_of_participant(stdClass $user, array $peers, array $authors, $useselfassessment) {
protected function reviewees_of_participant(stdClass $allocation, array $userinfo, array $authors, $selfassessment) {
$o = '';
if (is_null($user->submissionid)) {
if (is_null($allocation->submissionid)) {
$o .= $this->output->container(get_string('withoutsubmission', 'workshop'), 'info');
}
$exclude = array();
if (! $useselfassessment) {
$exclude[$user->id] = true;
if (! $selfassessment) {
$exclude[$allocation->userid] = true;
$o .= $this->output->container(get_string('selfassessmentdisabled', 'workshop'), 'info');
}
// todo add an option to exclude users without own submission
$options = $this->users_to_menu_options($authors, $exclude);
if ($options) {
$handler = new moodle_url($this->page->url, array('mode' => 'new', 'by' => $user->id, 'sesskey' => sesskey()));
$select = html_select::make_popup_form($handler, 'of', $options, 'addreviewby' . $user->id, '',
get_string('addreviewee', 'workshopallocation_manual'));
$handler = new moodle_url($this->page->url,
array('mode' => 'new', 'by' => $allocation->userid, 'sesskey' => sesskey()));
$select = html_select::make_popup_form($handler, 'of', $options, 'addreviewby' . $allocation->userid, '',
get_string('addreviewee', 'workshopallocation_manual'));
$select->nothinglabel = get_string('chooseuser', 'workshop');
$select->set_label(get_string('addreviewee', 'workshopallocation_manual'), $select->id);
$o .= $this->output->select($select);
@ -202,14 +194,14 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
$o .= $this->output->container(get_string('nothingtoreview', 'workshop'), 'info');
}
$o .= $this->output->output_start_tag('ul', array());
foreach ($user->reviewerof as $authorid => $assessmentid) {
foreach ($allocation->reviewerof as $authorid => $assessmentid) {
$o .= $this->output->output_start_tag('li', array());
$userpic = new moodle_user_picture();
$userpic->user = $peers[$authorid];
$userpic->courseid = $this->page->course->id;
$userpic->size = 16;
$o .= $this->output->user_picture($userpic, $this->page->course->id);
$o .= fullname($peers[$authorid]);
$allocationpic = new moodle_user_picture();
$allocationpic->user = $userinfo[$authorid];
$allocationpic->courseid = $this->page->course->id;
$allocationpic->size = 16;
$o .= $this->output->user_picture($allocationpic, $this->page->course->id);
$o .= fullname($userinfo[$authorid]);
// delete icon
$handler = new moodle_url($this->page->url, array('mode' => 'del', 'what' => $assessmentid, 'sesskey' => sesskey()));
@ -252,6 +244,4 @@ class moodle_workshopallocation_manual_renderer extends moodle_renderer_base {
return $this->output->action_icon($icon);
}
}

View File

@ -91,47 +91,60 @@ class workshop {
// 3rd normal form with no real performance gain
}
////////////////////////////////////////////////////////////////////////////////
// Static methods //
////////////////////////////////////////////////////////////////////////////////
/**
* Given a list of user ids, returns the filtered one containing just ids of users with own submission
* Return list of available allocation methods
*
* Example submissions are ignored.
* @return array Array ['string' => 'string'] of localized allocation method names
*/
public static function installed_allocators() {
$installed = get_plugin_list('workshopallocation');
$forms = array();
foreach ($installed as $allocation => $allocationpath) {
if (file_exists($allocationpath . '/lib.php')) {
$forms[$allocation] = get_string('pluginname', 'workshopallocation_' . $allocation);
}
}
// 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 an array of options for the editors that are used for submitting and assessing instructions
*
* @param array $userids
* @param stdClass $context
* @return array
*/
protected function users_with_submission(array $userids) {
global $DB;
if (empty($userids)) {
return array();
}
$userswithsubmission = array();
list($usql, $uparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$sql = "SELECT id,userid
FROM {workshop_submissions}
WHERE example = 0 AND workshopid = :workshopid AND userid $usql";
$params = array('workshopid' => $this->id);
$params = array_merge($params, $uparams);
$submissions = $DB->get_records_sql($sql, $params);
foreach ($submissions as $submission) {
$userswithsubmission[$submission->userid] = null;
}
return $userswithsubmission;
public static function instruction_editors_options(stdClass $context) {
return array('subdirs' => 1, 'maxbytes' => 0, 'maxfiles' => EDITOR_UNLIMITED_FILES,
'changeformat' => 1, 'context' => $context, 'noclean' => 1, 'trusttext' => 0);
}
////////////////////////////////////////////////////////////////////////////////
// Workshop API //
////////////////////////////////////////////////////////////////////////////////
/**
* Fetches all users with the capability mod/workshop:submit in the current context
*
* The returned objects contain id, lastname and firstname properties and are ordered by lastname,firstname
*
* @todo handle with limits and groups
* @param stdClass $context
* @param bool $musthavesubmission If true, return only users who have already submitted. All possible authors otherwise.
* @return array array[userid] => stdClass{->id ->lastname ->firstname}
*/
public function get_potential_authors(stdClass $context, $musthavesubmission=true) {
$users = get_users_by_capability($context, 'mod/workshop:submit',
'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
'u.id,u.lastname,u.firstname', 'u.lastname,u.firstname,u.id', 0, 1000, '', '', false, false, true);
if ($musthavesubmission) {
$users = array_intersect_key($users, $this->users_with_submission(array_keys($users)));
}
@ -143,13 +156,14 @@ class workshop {
*
* The returned objects contain id, lastname and firstname properties and are ordered by lastname,firstname
*
* @todo handle with limits and groups
* @param stdClass $context
* @param bool $musthavesubmission If true, return only users who have already submitted. All possible users otherwise.
* @return array array[userid] => stdClass{->id ->lastname ->firstname}
*/
public function get_potential_reviewers(stdClass $context, $musthavesubmission=false) {
$users = get_users_by_capability($context, 'mod/workshop:peerassess',
'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
'u.id, u.lastname, u.firstname', 'u.lastname,u.firstname,u.id', 0, 1000, '', '', false, false, true);
if ($musthavesubmission) {
// users without their own submission can not be reviewers
$users = array_intersect_key($users, $this->users_with_submission(array_keys($users)));
@ -201,6 +215,26 @@ class workshop {
return $grouped;
}
/**
* Returns the list of all allocations (it est assigned assessments) in the workshop
*
* Assessments of example submissions are ignored
*
* @return array
*/
public function get_allocations() {
global $DB;
$sql = 'SELECT a.id, a.submissionid, a.userid AS reviewerid,
s.userid AS authorid
FROM {workshop_assessments} a
INNER JOIN {workshop_submissions} s ON (a.submissionid = s.id)
WHERE s.example = 0 AND s.workshopid = :workshopid';
$params = array('workshopid' => $this->id);
return $DB->get_records_sql($sql, $params);
}
/**
* Returns submissions from this workshop
*
@ -365,56 +399,6 @@ class workshop {
return $DB->get_records_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, if such information is available (null elsewhere).
*
* 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]
*
* TODO This should be refactored when capability handling proposed by Petr is implemented so that
* we can check capabilities directly in SQL joins.
* Note that the returned recordset includes participants without submission as well as those
* without any review allocated yet.
*
* @return null|stdClass moodle_recordset
*/
public function get_allocations_recordset() {
global $DB, $PAGE;
$users = get_users_by_capability($PAGE->context, array('mod/workshop:submit', 'mod/workshop:peerassess'),
'u.id', 'u.lastname,u.firstname', '', '', '', '', false, false, true);
if (empty($users)) {
return null;
}
list($usql, $params) = $DB->get_in_or_equal(array_keys($users), SQL_PARAMS_NAMED);
$params['workshopid'] = $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.id IS NULL OR s.workshopid = :workshopid)
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
*
@ -506,28 +490,6 @@ class workshop {
return $this->evaluationinstance;
}
/**
* Return list of available allocation methods
*
* @return array Array ['string' => 'string'] of localized allocation method names
*/
public function installed_allocators() {
$installed = get_plugin_list('workshopallocation');
$forms = array();
foreach ($installed as $allocation => $allocationpath) {
if (file_exists($allocationpath . '/lib.php')) {
$forms[$allocation] = get_string('pluginname', 'workshopallocation_' . $allocation);
}
}
// 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
*
@ -761,22 +723,19 @@ class workshop {
$task->link = $this->allocation_url();
$authors = array();
$allocations = array(); // 'submissionid' => isallocated
$rs = $this->get_allocations_recordset();
if (!is_null($rs)) {
foreach ($rs as $allocation) {
if (!isset($authors[$allocation->authorid])) {
$authors[$allocation->authorid] = true;
$records = $this->get_allocations();
foreach ($records as $allocation) {
if (!isset($authors[$allocation->authorid])) {
$authors[$allocation->authorid] = true;
}
if (isset($allocation->submissionid)) {
if (!isset($allocations[$allocation->submissionid])) {
$allocations[$allocation->submissionid] = false;
}
if (isset($allocation->submissionid)) {
if (!isset($allocations[$allocation->submissionid])) {
$allocations[$allocation->submissionid] = false;
}
if (!empty($allocation->reviewerid)) {
$allocations[$allocation->submissionid] = true;
}
if (!empty($allocation->reviewerid)) {
$allocations[$allocation->submissionid] = true;
}
}
$rs->close();
}
$numofauthors = count($authors);
$numofsubmissions = count($allocations);
@ -914,19 +873,6 @@ class workshop {
return $this->grading_strategy_instance()->form_ready();
}
/**
* @return array of available workshop phases
*/
protected function available_phases() {
return array(
self::PHASE_SETUP => true,
self::PHASE_SUBMISSION => true,
self::PHASE_ASSESSMENT => true,
self::PHASE_EVALUATION => true,
self::PHASE_CLOSED => true,
);
}
/**
* Switch to a new workshop phase
*
@ -966,17 +912,51 @@ class workshop {
return $grade;
}
// Static methods
////////////////////////////////////////////////////////////////////////////////
// Internal methods (implementation details) //
////////////////////////////////////////////////////////////////////////////////
/**
* Returns an array of options for the editors that are used for submitting and assessing instructions
* Given a list of user ids, returns the filtered one containing just ids of users with own submission
*
* @param stdClass $context
* Example submissions are ignored.
*
* @param array $userids
* @return array
*/
public static function instruction_editors_options(stdClass $context) {
return array('subdirs' => 1, 'maxbytes' => 0, 'maxfiles' => EDITOR_UNLIMITED_FILES,
'changeformat' => 1, 'context' => $context, 'noclean' => 1, 'trusttext' => 0);
protected function users_with_submission(array $userids) {
global $DB;
if (empty($userids)) {
return array();
}
$userswithsubmission = array();
list($usql, $uparams) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED);
$sql = "SELECT id,userid
FROM {workshop_submissions}
WHERE example = 0 AND workshopid = :workshopid AND userid $usql";
$params = array('workshopid' => $this->id);
$params = array_merge($params, $uparams);
$submissions = $DB->get_records_sql($sql, $params);
foreach ($submissions as $submission) {
$userswithsubmission[$submission->userid] = null;
}
return $userswithsubmission;
}
/**
* @return array of available workshop phases
*/
protected function available_phases() {
return array(
self::PHASE_SETUP => true,
self::PHASE_SUBMISSION => true,
self::PHASE_ASSESSMENT => true,
self::PHASE_EVALUATION => true,
self::PHASE_CLOSED => true,
);
}
}