diff --git a/mod/quiz/report/overview/report.php b/mod/quiz/report/overview/report.php index 14aaae75026..d18b7984e65 100644 --- a/mod/quiz/report/overview/report.php +++ b/mod/quiz/report/overview/report.php @@ -1,72 +1,104 @@ libdir.'/tablelib.php'); + /// Overview report just displays a big table of all the attempts class quiz_report extends quiz_default_report { function display($quiz, $cm, $course) { /// This function just displays the report - global $CFG, $QUIZ_GRADE_METHOD, $del; + global $CFG, $SESSION, $db; - $strreallydel = addslashes(get_string('deleteattemptcheck','quiz')); - $strdeleteselected = get_string('deleteselected'); - $strdeleteall = get_string('deleteall'); - $strname = get_string("name"); - $strattempts = get_string("attempts", "quiz"); + $strreallydel = addslashes(get_string('deleteattemptcheck','quiz')); $strnoattempts = get_string('noattempts','quiz'); - $strbestgrade = $QUIZ_GRADE_METHOD[$quiz->grademethod]; $strtimeformat = get_string('strftimedatetime'); - - if (!empty($del)) { /// Some attempts need to be deleted + $action = optional_param('action', ''); - if (record_exists('quiz_attempts', 'quiz', $quiz->id)) { + switch($action) { + case 'delete': /// Some attempts need to be deleted - if ($del == 'all'){ /// Delete all the attempts - $attempts = get_records('quiz_attempts','quiz',$quiz->id); - delete_records('quiz_attempts','quiz',$quiz->id); - delete_records('quiz_grades','quiz',$quiz->id); - if ($attempts) { - foreach ($attempts as $thisattempt){ - delete_records('quiz_responses','attempt',$thisattempt->id); - } + $attemptids = isset($_POST['attemptid']) ? $_POST['attemptid'] : array(); + if(!is_array($attemptids) || empty($attemptids)) { + break; + } + + foreach($attemptids as $num => $attemptid) { + if(empty($attemptid)) { + unset($attemptids[$num]); } + } - } else { /// Delete selected attempts + foreach($attemptids as $attemptid) { + if ($todelete = get_record('quiz_attempts', 'id', $attemptid)) { - $items = (array)data_submitted(); + delete_records('quiz_attempts', 'id', $attemptid); + delete_records('quiz_responses', 'attempt', $attemptid); - unset($items['del']); - unset($items['id']); + // Search quiz_attempts for other instances by this user. + // If none, then delete record for this quiz, this user from quiz_grades + // else recalculate best grade - if ($items) { - foreach ($items as $attemptid) { - if ($todelete = get_record('quiz_attempts', 'id', $attemptid)) { - delete_records('quiz_attempts', 'id', $attemptid); - delete_records('quiz_responses', 'attempt', $attemptid); - - // Search quiz_attempts for other instances by this user. - // If none, then delete record for this quiz, this user from quiz_grades - // else recalculate best grade - - $userid = $todelete->userid; - if (!record_exists('quiz_attempts', 'userid', $userid, 'quiz',$quiz->id)) { - delete_records('quiz_grades', 'userid', $userid,'quiz',$quiz->id); - } else { - quiz_save_best_grade($quiz, $userid); - } - } + $userid = $todelete->userid; + if (!record_exists('quiz_attempts', 'userid', $userid, 'quiz', $quiz->id)) { + delete_records('quiz_grades', 'userid', $userid,'quiz', $quiz->id); + } else { + quiz_save_best_grade($quiz, $userid); } } } + break; + } + + if(!isset($SESSION->quiz_overview_table)) { + $SESSION->quiz_overview_table = array('noattempts' => false, 'teacherattempts' => true, 'detailedmarks' => false); + } + + foreach($SESSION->quiz_overview_table as $option => $value) { + $urlparam = optional_param($option, NULL); + if($urlparam === NULL) { + $$option = $value; + } + else { + $$option = $SESSION->quiz_overview_table[$option] = $urlparam; } } - if (!$grades = quiz_get_grade_records($quiz)) { - print_heading($strnoattempts); - return true; + $tablecolumns = array('checkbox', 'picture', 'fullname', 'timefinish', 'duration', 'sumgrades'); + $tableheaders = array(NULL, '', get_string('fullname'), get_string('attemptedon', 'quiz'), get_string('attemptduration', 'quiz'), get_string('grade', 'quiz').'/'.$quiz->grade); + + if($detailedmarks) { + $questions = explode(',', $quiz->questions); + foreach($questions as $number => $questionid) { + $tablecolumns[] = '$'.$questionid; + $tableheaders[] = '#'.($number + 1); + } } + $table = new flexible_table('mod-quiz-report-overview-report'); + + $table->define_columns($tablecolumns); + $table->define_headers($tableheaders); + $table->define_baseurl($CFG->wwwroot.'/mod/quiz/report.php?id='.$cm->id); + + $table->sortable(true); + $table->collapsible(true); + $table->initialbars(true); + + $table->column_suppress('picture'); + $table->column_suppress('fullname'); + + $table->column_class('picture', 'picture'); + + $table->set_attribute('cellspacing', '0'); + $table->set_attribute('id', 'attempts'); + $table->set_attribute('class', 'generaltable generalbox'); + + // Start working -- this is necessary as soon as the niceties are over + $table->setup(); + + /// Check to see if groups are being used in this quiz if ($groupmode = groupmode($course, $cm)) { // Groups are being used $currentgroup = setup_and_print_groups($course, $groupmode, "report.php?id=$cm->id&mode=overview"); @@ -78,54 +110,135 @@ class quiz_report extends quiz_default_report { if ($currentgroup) { $users = get_group_users($currentgroup); } - - - $table->head = array(" ", $strname, $strattempts, "$strbestgrade /$quiz->grade"); - $table->align = array("center", "left", "left", "center"); - $table->wrap = array("nowrap", "nowrap", "nowrap", "nowrap"); - $table->width = 10; - $table->size = array(10, "*", "80%", "*"); - - foreach ($grades as $grade) { - if ($currentgroup) { - if (empty($users[$grade->userid])) { /// Using groups, but this user not in group - continue; - } - } - $picture = print_user_picture($grade->userid, $course->id, $grade->picture, false, true); - - if ($attempts = quiz_get_user_attempts($quiz->id, $grade->userid)) { - $userattempts = $this->quiz_get_user_attempts_list($quiz, $attempts, $grade->grade, $strtimeformat); - } else { - $userattempts = ""; - } - - $table->data[] = array ($picture, - "wwwroot/user/view.php?id=$grade->userid&course=$course->id\">". - fullname($grade).'', - "$userattempts", format_float($grade->grade,$quiz->decimalpoints)); + else { + $users = get_course_users($course->id); } - //Embed script for warning - echo "\n\n"; - - $onsub = "return confirm('$strreallydel')"; + if(!$teacherattempts) { + $teachers = get_course_teachers($course->id); + if(!empty($teachers)) { + $keys = array_keys($teachers); + } + foreach($keys as $key) { + unset($users[$key]); + } + } - echo "
\n"; - echo "\n"; - echo "id\" />\n"; + if(empty($users)) { + print_heading($strnoattempts); + return true; + } - print_table($table); + // Construct the SQL + + if($where = $table->get_sql_where()) { + $where .= ' AND '; + } + + if($sort = $table->get_sql_sort()) { + if(substr($sort, 0, 1) == '$') { + $qnum = intval(substr($sort, 1)); + $where.= '('.sql_isnull('qr.question').' OR qr.question = '.$qnum.') AND '; + $sort = ' ORDER BY grade '.(strpos($sort, 'ASC')? 'ASC' : 'DESC'); + } + else { + $sort = ' ORDER BY '.$sort; + } + } + + $select = 'SELECT '.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).' AS uvsa, u.id AS userid, u.firstname, u.lastname, u.picture, qa.id AS attempt, qa.sumgrades, qa.timefinish, qa.timefinish - qa.timestart AS duration '; + $group = 'GROUP BY uvsa'; + $sql = 'FROM '.$CFG->prefix.'user u '. + 'LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON u.id = qa.userid '. + 'LEFT JOIN '.$CFG->prefix.'quiz_responses qr ON qr.attempt = qa.id '. + 'WHERE '.$where.'u.id IN ('.implode(',', array_keys($users)).') AND ('.($noattempts ? sql_isnull('qa.quiz').' OR ' : '') . 'qa.quiz = '.$quiz->id.') '; + + $total = count_records_sql('SELECT COUNT(DISTINCT('.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).')) '.$sql); + $table->pagesize(10, $total); + + if($table->get_page_start() !== '' && $table->get_page_size() !== '') { + $limit = ' '.sql_paging_limit($table->get_page_start(), $table->get_page_size()); + } + else { + $limit = ''; + } + + $attempts = get_records_sql($select.$sql.$group.$sort.$limit); + + if(!empty($attempts)) { + + foreach ($attempts as $attempt) { - //There might be a more elegant way than using the
tag for this - echo "
 "; - echo "\n
\n"; - echo "\n"; + $picture = print_user_picture($attempt->userid, $course->id, $attempt->picture, false, true); + + $row = array( + '', + $picture, + ''.fullname($attempt).'', + empty($attempt->attempt) ? '-' : ''.userdate($attempt->timefinish, $strtimeformat).'', + empty($attempt->attempt) ? '-' : format_time($attempt->duration), + $attempt->sumgrades === NULL ? '-' : format_float($attempt->sumgrades / $quiz->sumgrades * $quiz->grade,$quiz->decimalpoints) + ); + + if($detailedmarks) { + if(empty($attempt->attempt)) { + foreach($questions as $question) { + $row[] = '-'; + } + } + else { + $responses = get_records('quiz_responses', 'attempt', $attempt->attempt, 'question'); + foreach($responses as $response) { + $row[] = $response->grade; + } + } + } + + $table->add_data($row); + } + + echo ''; + echo ''; + } + else { + print_heading(get_string('noattemptsmatchingfilter', 'quiz', strtolower($course->students))); + } + + echo '
'; + echo '
'; + echo '

'.get_string('displayoptions', 'quiz').': '; + echo ''; + echo ''; + echo ''; + echo ''; + echo ' '; + echo ' '; + echo ' '; + echo ''; + echo '

'; + echo '
'; + echo '
'; return true; } diff --git a/mod/quiz/report/overview/utility.js b/mod/quiz/report/overview/utility.js new file mode 100644 index 00000000000..120968b7c9b --- /dev/null +++ b/mod/quiz/report/overview/utility.js @@ -0,0 +1,24 @@ +function select_all() { + var inputs = document.getElementsByTagName('INPUT'); + for(var i = 0; i < inputs.length; ++i) { + if(inputs[i].type == 'checkbox') { + inputs[i].checked = 'checked'; + } + } +} + +function deselect_all() { + var inputs = document.getElementsByTagName('INPUT'); + for(var i = 0; i < inputs.length; ++i) { + if(inputs[i].type == 'checkbox') { + inputs[i].checked = ''; + } + } +} + +function confirm_if(expr, message) { + if(!expr) { + return true; + } + return confirm(message); +}