Some code cleanup, relying more on the functions from questionlib.php. Not currently functional, awaiting the central manual grading feature.
This commit is contained in:
+106
-117
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
// This file allows a teacher to grade essay questions.
|
||||
// This file allows a teacher to grade essay questions.
|
||||
// Could be later expanded to change grades for all question types
|
||||
|
||||
# Flow of the file:
|
||||
@@ -19,7 +19,7 @@ class quiz_report extends quiz_default_report {
|
||||
|
||||
function display($quiz, $cm, $course) { /// This function just displays the report
|
||||
global $CFG, $SESSION, $USER, $db, $QTYPES;
|
||||
|
||||
|
||||
$action = optional_param('action', 'viewquestions', PARAM_ALPHA);
|
||||
$questionid = optional_param('questionid', 0, PARAM_INT);
|
||||
$attemptid = optional_param('attemptid', 0, PARAM_INT);
|
||||
@@ -27,16 +27,32 @@ class quiz_report extends quiz_default_report {
|
||||
$userid = optional_param('userid', 0, PARAM_INT);
|
||||
|
||||
$this->print_header_and_tabs($cm, $course, $quiz, $reportmode="grading");
|
||||
|
||||
notice('The manual grading is temporarily disabled during development work', $CFG->wwwroot.'/mod/quiz/report.php?q='.$quiz->id);
|
||||
|
||||
if (!empty($questionid)) {
|
||||
if (! $question = get_record('question', 'id', $questionid)) {
|
||||
error("Question with id $questionid not found");
|
||||
}
|
||||
///$number = optional_param('number', 0, PARAM_INT);
|
||||
$question->maxgrade = get_field('quiz_question_instances', 'grade', 'quiz', $quiz->id, 'question', $question->id);
|
||||
|
||||
// Some of the questions code is optimised to work with several questions
|
||||
// at once so it wants the question to be in an array. The array key
|
||||
// must be the question id.
|
||||
$key = $question->id;
|
||||
$questions[$key] = &$question;
|
||||
|
||||
// We need to add additional questiontype specific information to
|
||||
// the question objects.
|
||||
if (!get_question_options($questions)) {
|
||||
error("Unable to load questiontype specific question information");
|
||||
}
|
||||
// This will have extended the question object so that it now holds
|
||||
// all the information about the questions that may be needed later.
|
||||
}
|
||||
|
||||
|
||||
add_to_log($course->id, "quiz", "manualgrading", "report.php?mode=grading&q=$quiz->id", "$quiz->id", "$cm->id");
|
||||
|
||||
|
||||
/// GROUP CODE FROM ATTEMPTS.PHP no sure how to use just yet... need to update later perhaps
|
||||
/// Check to see if groups are being used in this quiz
|
||||
# if ($groupmode = groupmode($course, $cm)) { // Groups are being used
|
||||
@@ -44,7 +60,7 @@ class quiz_report extends quiz_default_report {
|
||||
# } else {
|
||||
# $currentgroup = false;
|
||||
# }
|
||||
|
||||
|
||||
/// Get all students
|
||||
# if ($currentgroup) {
|
||||
# $users = get_group_students($currentgroup);
|
||||
@@ -52,23 +68,20 @@ class quiz_report extends quiz_default_report {
|
||||
# else {
|
||||
$users = get_course_students($course->id);
|
||||
# }
|
||||
|
||||
|
||||
if(empty($users)) {
|
||||
print_heading(get_string("noattempts", "quiz"));
|
||||
return true;
|
||||
} else {
|
||||
// for sql queries
|
||||
$userids = implode(', ', array_keys($users));
|
||||
$userids = implode(', ', array_keys($users));
|
||||
}
|
||||
|
||||
|
||||
echo '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:1000;"></div>'; // for overlib
|
||||
|
||||
|
||||
if ($data = data_submitted()) { // post data submitted, process it
|
||||
confirm_sesskey();
|
||||
|
||||
$question->maxgrade = get_field('quiz_question_instances', 'grade', 'quiz', $quiz->id, 'question', $question->id);
|
||||
$QTYPES[$question->qtype]->get_question_options($question);
|
||||
|
||||
|
||||
// first, process all the data to extract the teacher's new responses for the question(s)
|
||||
foreach ($data as $key => $response) {
|
||||
$keyparts = explode('_', $key); // valid keys are in this format: attemptid_stateid_fieldname
|
||||
@@ -77,7 +90,7 @@ class quiz_report extends quiz_default_report {
|
||||
$attemptid = $keyparts[0];
|
||||
$stateid = $keyparts[1];
|
||||
$fieldname = $keyparts[2];
|
||||
|
||||
|
||||
$responses[$attemptid.'_'.$stateid][$fieldname] = $response;
|
||||
}
|
||||
}
|
||||
@@ -88,63 +101,48 @@ class quiz_report extends quiz_default_report {
|
||||
$ids = explode('_', $ids);
|
||||
$attemptid = $ids[0];
|
||||
$stateid = $ids[1];
|
||||
|
||||
|
||||
// get our attempt
|
||||
if (! $attempt = get_record('quiz_attempts', 'id', $attemptid)) {
|
||||
error('No such attempt ID exists');
|
||||
}
|
||||
|
||||
// get the state
|
||||
$statefields = 'n.questionid as question, s.*, n.sumpenalty';
|
||||
$sql = "SELECT $statefields".
|
||||
" FROM {$CFG->prefix}question_states s,".
|
||||
" {$CFG->prefix}question_sessions n".
|
||||
" WHERE s.id = n.newest".
|
||||
" AND n.attemptid = '$attempt->uniqueid'".
|
||||
" AND n.questionid = $question->id";
|
||||
$state = get_record_sql($sql);
|
||||
|
||||
// restore the state of the question
|
||||
restore_question_state($question, $state);
|
||||
|
||||
}
|
||||
|
||||
// Load the state for this attempt (The questions array was created earlier)
|
||||
$states = get_question_states($questions, $quiz, $attempt);
|
||||
// The $states array is indexed by question id but because we are dealing
|
||||
// with only one question there is only one entry in this array
|
||||
$state = &$states[$question->id];
|
||||
|
||||
// this is the new response from the teacher
|
||||
$state->responses = $response;
|
||||
|
||||
// grade the question with the new state made by the teacher
|
||||
$QTYPES[$question->qtype]->grade_responses($question, $state, $quiz);
|
||||
|
||||
// finalize the grade
|
||||
$state->last_graded->grade = 0; // we dont want the next function to care about the last grade
|
||||
question_apply_penalty_and_timelimit($question, $state, $attempt, $quiz);
|
||||
|
||||
// want to update session. Also set changed to 1 to trick save_question_session to save our session
|
||||
$state->update = 1;
|
||||
|
||||
// Process the teacher responses
|
||||
$QTYPES[$question->qtype]->process_teacher_responses($question, $state, $quiz);
|
||||
|
||||
// We need to indicate that the state has changed in order for it to be saved
|
||||
$state->changed = 1;
|
||||
// We want to update existing state (rather than creating new one) if it
|
||||
// was itself created by a manual grading event
|
||||
$state->update = ($state->event == QUESTION_EVENTMANUALGRADE) ? 1 : 0;
|
||||
// Go ahead and save
|
||||
save_question_session($question, $state);
|
||||
|
||||
// method for changing sumgrades from report type regrade. Thanks!
|
||||
$sumgrades = 0;
|
||||
$questionids = explode(',', quiz_questions_in_quiz($attempt->layout));
|
||||
foreach($questionids as $questionid) {
|
||||
$lastgradedid = get_field('question_sessions', 'newgraded', 'attemptid', $attempt->uniqueid, 'questionid', $questionid);
|
||||
$sumgrades += get_field('question_states', 'grade', 'id', $lastgradedid);
|
||||
}
|
||||
|
||||
|
||||
if ($attempt->sumgrades != $sumgrades) {
|
||||
set_field('quiz_attempts', 'sumgrades', $sumgrades, 'id', $attempt->id);
|
||||
}
|
||||
|
||||
|
||||
// update user's grade
|
||||
quiz_save_best_grade($quiz, $attempt->userid);
|
||||
}
|
||||
notify(get_string('changessaved', 'quiz'));
|
||||
|
||||
} else if ( ( !empty($attemptid) or !empty($gradeall) or !empty($userid)) and !empty($questionid) ) { // need attemptid and questionid or gradeall and a questionid
|
||||
// this sql joins the attempts table and the user table
|
||||
$select = 'SELECT '.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).' AS userattemptid,
|
||||
qa.id AS attemptid, qa.uniqueid, qa.attempt, qa.timefinish, qa.preview,
|
||||
$select = 'SELECT '.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).' AS userattemptid,
|
||||
qa.id AS attemptid, qa.uniqueid, qa.attempt, qa.timefinish, qa.preview,
|
||||
u.id AS userid, u.firstname, u.lastname, u.picture ';
|
||||
$from = 'FROM '.$CFG->prefix.'user u LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON (u.id = qa.userid AND qa.quiz = '.$quiz->id.') ';
|
||||
|
||||
|
||||
if ($gradeall) { // get all user attempts
|
||||
$where = 'WHERE u.id IN ('.implode(',', array_keys($users)).') ';
|
||||
} else if ($userid) { // get all the attempts for a specific user
|
||||
@@ -152,70 +150,58 @@ class quiz_report extends quiz_default_report {
|
||||
} else { // get a specific attempt
|
||||
$where = 'WHERE qa.id='.$attemptid.' ';
|
||||
}
|
||||
|
||||
|
||||
$where .= 'AND '.$db->IfNull('qa.attempt', '0').' != 0 ';
|
||||
$where .= 'AND '.$db->IfNull('qa.timefinish', '0').' != 0 ';
|
||||
$where .= 'AND '.$db->IfNull('qa.timefinish', '0').' != 0 ';
|
||||
$sort = 'ORDER BY u.firstname, u.lastname, qa.attempt ASC';
|
||||
$attempts = get_records_sql($select.$from.$where.$sort);
|
||||
|
||||
|
||||
echo '<form method="post" action="report.php">'.
|
||||
'<input type="hidden" name="mode" value="grading">'.
|
||||
'<input type="hidden" name="q" value="'.$quiz->id.'">'.
|
||||
'<input type="hidden" name="sesskey" value="'.$USER->sesskey.'">'.
|
||||
'<input type="hidden" name="action" value="viewquestion">'.
|
||||
'<input type="hidden" name="questionid" value="'.$questionid.'">';
|
||||
|
||||
'<input type="hidden" name="questionid" value="'.$questionid.'">';
|
||||
|
||||
foreach ($attempts as $attempt) {
|
||||
// retrieve the state
|
||||
if (!$neweststate = get_record('question_sessions', 'attemptid', $attempt->uniqueid, 'questionid', $questionid)) {
|
||||
error("Can not find newest states for attempt $attempt->uniqueid for question $questionid");
|
||||
}
|
||||
if (! $state = get_record('question_states', 'id', $neweststate->newest)) {
|
||||
error('Invalid state id');
|
||||
}
|
||||
|
||||
// get everything ready for the question to be printed
|
||||
$instance = get_record('quiz_question_instances', 'quiz', $quiz->id, 'question', $question->id);
|
||||
$question->instance = $instance->id;
|
||||
$question->maxgrade = $instance->grade;
|
||||
$question->name_prefix = $attempt->attemptid.'_'.$state->id.'_';
|
||||
$QTYPES[$question->qtype]->get_question_options($question);
|
||||
|
||||
restore_question_state($question, $state);
|
||||
$state->last_graded = $state;
|
||||
|
||||
|
||||
// Load the state for this attempt (The questions array was created earlier)
|
||||
$states = get_question_states($questions, $quiz, $attempt);
|
||||
// The $states array is indexed by question id but because we are dealing
|
||||
// with only one question there is only one entry in this array
|
||||
$state = &$states[$question->id];
|
||||
|
||||
$options = quiz_get_reviewoptions($quiz, $attempt, true);
|
||||
$options->validation = ($state->event == QUESTION_EVENTVALIDATE); // not sure what this is
|
||||
//$options->history = 'all'; // had this on, but seemed confusing for this
|
||||
|
||||
// IF this code is expanded to manually regrade any question type, then
|
||||
// readonly would be set to 0 and the essay question would have to be
|
||||
// updated. Also, regrade would most likly be tossed.
|
||||
|
||||
$options->readonly = 1;
|
||||
$options->regrade = 1;
|
||||
|
||||
|
||||
// print the user name, attempt count, the question, and some more hidden fields
|
||||
echo '<div align="center" width="80%" style="padding:15px;">'.
|
||||
'<p>'."$attempt->firstname $attempt->lastname: ".
|
||||
get_string('attempt', 'quiz')." $attempt->attempt".
|
||||
'</p>';
|
||||
|
||||
|
||||
print_question($question, $state, '', $quiz, $options);
|
||||
echo '<input type="hidden" name="attemptids[]" value="'.$attempt->attemptid.'">'.
|
||||
'<input type="hidden" name="stateids[]" value="'.$state->id.'">';
|
||||
echo '</div>';
|
||||
|
||||
// TODO: This is where the code for printing the comment box and grade selector
|
||||
// should go.
|
||||
}
|
||||
echo '<div align="center"><input type="submit" value="'.get_string('savechanges').'"></div>'.
|
||||
'</form>';
|
||||
print_footer($course);
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
// our 2 different views
|
||||
// the first one displays all of the essay questions in the quiz
|
||||
// the first one displays all of the essay questions in the quiz
|
||||
// with the number of ungraded attempts for each essay question
|
||||
|
||||
// the second view displays the users who have answered the essay question
|
||||
|
||||
// the second view displays the users who have answered the essay question
|
||||
// and all of their attempts at answering the question
|
||||
switch($action) {
|
||||
case 'viewquestions':
|
||||
@@ -226,9 +212,9 @@ class quiz_report extends quiz_default_report {
|
||||
$table->align = array("left", "left");
|
||||
$table->wrap = array("wrap", "wrap");
|
||||
$table->width = "20%";
|
||||
$table->size = array("*", "*");
|
||||
$table->size = array("*", "*");
|
||||
$table->data = array();
|
||||
|
||||
|
||||
// get the essay questions
|
||||
$questionlist = quiz_questions_in_quiz($quiz->questions);
|
||||
$sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance".
|
||||
@@ -246,10 +232,12 @@ class quiz_report extends quiz_default_report {
|
||||
// get all the finished attempts by the users
|
||||
if ($attempts = get_records_select('quiz_attempts', "quiz = $quiz->id and timefinish > 0 and userid IN ($userids)", 'userid, attempt')) {
|
||||
foreach($questions as $question) {
|
||||
|
||||
|
||||
$link = "<a href=\"report.php?mode=grading&q=$quiz->id&action=viewquestion&questionid=$question->id\">".
|
||||
$question->name."</a>";
|
||||
// determine the number of ungraded attempts (essay question thing only)
|
||||
// TODO: This should be done with more efficient SQL
|
||||
// It should use the event field of the newest graded state
|
||||
$ungraded = 0;
|
||||
foreach ($attempts as $attempt) {
|
||||
// grab the state then check if it is graded
|
||||
@@ -263,7 +251,7 @@ class quiz_report extends quiz_default_report {
|
||||
$ungraded++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$table->data[] = array($link, $ungraded);
|
||||
}
|
||||
print_table($table);
|
||||
@@ -275,43 +263,43 @@ class quiz_report extends quiz_default_report {
|
||||
// gonna use flexible_table (first time!)
|
||||
$tablecolumns = array('picture', 'fullname', 'attempt');
|
||||
$tableheaders = array('', get_string('fullname'), get_string("attempts", "quiz"));
|
||||
|
||||
|
||||
$table = new flexible_table('mod-quiz-report-grading');
|
||||
|
||||
|
||||
$table->define_columns($tablecolumns);
|
||||
$table->define_headers($tableheaders);
|
||||
$table->define_baseurl($CFG->wwwroot.'/mod/quiz/report.php?mode=grading&q='.$quiz->id.'&action=viewquestion&questionid='.$question->id);
|
||||
|
||||
|
||||
$table->sortable(true);
|
||||
$table->initialbars(count($users)>20); // will show initialbars if there are more than 20 users
|
||||
$table->pageable(true);
|
||||
|
||||
|
||||
$table->column_suppress('fullname');
|
||||
$table->column_suppress('picture');
|
||||
|
||||
|
||||
$table->column_class('picture', 'picture');
|
||||
|
||||
|
||||
// attributes in the table tag
|
||||
$table->set_attribute('cellspacing', '0');
|
||||
$table->set_attribute('id', 'grading');
|
||||
$table->set_attribute('class', 'generaltable generalbox');
|
||||
$table->set_attribute('align', 'center');
|
||||
$table->set_attribute('width', '50%');
|
||||
|
||||
|
||||
// get it ready!
|
||||
$table->setup();
|
||||
|
||||
$table->setup();
|
||||
|
||||
// this sql is a join of the attempts table and the user table. I do this so I can sort by user name and attempt number (not id)
|
||||
$select = 'SELECT '.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).' AS userattemptid, qa.id AS attemptid, qa.uniqueid, qa.attempt, u.id AS userid, u.firstname, u.lastname, u.picture ';
|
||||
$from = 'FROM '.$CFG->prefix.'user u LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON (u.id = qa.userid AND qa.quiz = '.$quiz->id.') ';
|
||||
$where = 'WHERE u.id IN ('.implode(',', array_keys($users)).') ';
|
||||
$where .= 'AND '.$db->IfNull('qa.attempt', '0').' != 0 ';
|
||||
$where .= 'AND '.$db->IfNull('qa.timefinish', '0').' != 0 ';
|
||||
|
||||
$where .= 'AND '.$db->IfNull('qa.timefinish', '0').' != 0 ';
|
||||
|
||||
if($table->get_sql_where()) { // forgot what this does
|
||||
$where .= 'AND '.$table->get_sql_where();
|
||||
}
|
||||
|
||||
|
||||
// sorting of the table
|
||||
if($sort = $table->get_sql_sort()) {
|
||||
$sort = 'ORDER BY '.$sort; // seems like I would need to have u. or qa. infront of the ORDER BY attribues... but seems to work..
|
||||
@@ -319,11 +307,11 @@ class quiz_report extends quiz_default_report {
|
||||
// my default sort rule
|
||||
$sort = 'ORDER BY u.firstname, u.lastname, qa.attempt ASC';
|
||||
}
|
||||
|
||||
|
||||
// set up the pagesize
|
||||
$total = count_records_sql('SELECT COUNT(DISTINCT('.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).')) '.$from.$where);
|
||||
$table->pagesize(10, $total);
|
||||
|
||||
|
||||
// this is for getting the correct records for a given page
|
||||
if($table->get_page_start() !== '' && $table->get_page_size() !== '') {
|
||||
$limit = ' '.sql_paging_limit($table->get_page_start(), $table->get_page_size());
|
||||
@@ -334,18 +322,19 @@ class quiz_report extends quiz_default_report {
|
||||
// get the attempts and process them
|
||||
if ($attempts = get_records_sql($select.$from.$where.$sort.$limit)) {
|
||||
foreach($attempts as $attempt) {
|
||||
|
||||
|
||||
$picture = print_user_picture($attempt->userid, $course->id, $attempt->picture, false, true);
|
||||
|
||||
// link here... grades all for this student
|
||||
|
||||
// link here... grades all for this student
|
||||
$userlink = "<a href=\"report.php?mode=grading&q=$quiz->id&questionid=$question->id&userid=$attempt->userid\">".
|
||||
$attempt->firstname.' '.$attempt->lastname.'</a>';
|
||||
|
||||
|
||||
// nab the state of the attempt to see if it is graded or not
|
||||
// TODO: should be changed to use the event field
|
||||
if (!$neweststate = get_record('question_sessions', 'attemptid', $attempt->uniqueid, 'questionid', $question->id)) {
|
||||
error("Can not find newest states for attempt $attempt->uniqueid for question $questionid");
|
||||
}
|
||||
|
||||
|
||||
if (!$questionstate = get_record('question_essay_states', 'stateid', $neweststate->newest)) {
|
||||
error('Could not find question state');
|
||||
}
|
||||
@@ -355,27 +344,27 @@ class quiz_report extends quiz_default_report {
|
||||
} else {
|
||||
$style = 'style="color:#008000"'; // green
|
||||
}
|
||||
|
||||
|
||||
// link for the attempt
|
||||
$attemptlink = "<a $style href=\"report.php?mode=grading&q=$quiz->id&questionid=$question->id&attemptid=$attempt->attemptid\">". // &number=$number
|
||||
$question->name." attempt $attempt->attempt</a>";
|
||||
|
||||
|
||||
$table->add_data( array($picture, $userlink, $attemptlink) );
|
||||
}
|
||||
//$number += $question->length;
|
||||
}
|
||||
|
||||
|
||||
// grade all and "back" links
|
||||
$links = "<center><a href=\"report.php?mode=grading&q=$quiz->id&questionid=$questionid&gradeall=1\">".get_string('gradeall', 'quiz').'</a> | '.
|
||||
"<a href=\"report.php?mode=grading&q=$quiz->id&action=viewquestions\">".get_string('backtoquestionlist', 'quiz').'</a></center>'.
|
||||
|
||||
|
||||
// print everything here
|
||||
print_heading($question->name);
|
||||
echo $links;
|
||||
echo '<div id="tablecontainer">';
|
||||
$table->print_html();
|
||||
echo '</div>';
|
||||
echo $links;
|
||||
echo $links;
|
||||
break;
|
||||
default:
|
||||
error("Invalid Action");
|
||||
|
||||
Reference in New Issue
Block a user