]> git.mjollnir.org Git - moodle.git/commitdiff
Improved quiz report plugin mechanism and converted the manual grading script into...
authorgustav_delius <gustav_delius>
Mon, 27 Mar 2006 08:41:20 +0000 (08:41 +0000)
committergustav_delius <gustav_delius>
Mon, 27 Mar 2006 08:41:20 +0000 (08:41 +0000)
lang/en_utf8/quiz.php
lang/en_utf8/quiz_analysis.php
lang/en_utf8/quiz_grading.php [new file with mode: 0644]
lang/en_utf8/quiz_overview.php [new file with mode: 0644]
lang/en_utf8/quiz_regrade.php [new file with mode: 0644]
lang/en_utf8/quiz_responses.php
mod/quiz/grading.php [deleted file]
mod/quiz/report/analysis/report.php
mod/quiz/report/grading/report.php [new file with mode: 0644]
mod/quiz/report/overview/report.php
mod/quiz/tabs.php

index f18807c0ed8d345599a4e78a6701ff545bb355f1..5c564a976cc0b8b3a535f10e4367fa9a2a901523 100644 (file)
@@ -493,5 +493,16 @@ $string['xmltypeunsupported'] = 'Question type $a is not supported by xml import
 $string['yourfinalgradeis'] = 'Your final grade for this quiz is $a';
 $string['zerosignificantfiguresnotallowed'] = 'The correct answer cannot have zero significant figures!';
 
+$string['backtoquestionlist'] = 'Back to Question List';
+$string['changessaved'] = 'Grading Changes Saved';
+$string['comments'] = 'Comments';
+$string['editingessay'] = 'Editing Essay';
+$string['essay'] = 'Essay';
+$string['essayquestions'] = 'Essay Questions';
+$string['gradeall'] = 'Grade All';
+$string['gradeessays'] = 'Grade Essays';
+$string['nocommentsyet'] = 'No comments yet.';
+$string['noessayquestionsfound'] = 'No Essay Questions Found';
+$string['ungraded'] = 'Ungraded';
 
 ?>
index 161db3aea70b4b1d0f0d3189d23aa487bfaeb57e..48654547a88ad8101fc0a29422151916e27de383 100644 (file)
@@ -1,6 +1,6 @@
 <?php // $Id$
-      // quiz.php - created with Moodle 1.4 development (2004080300)
 
+$string['analysis'] = 'Item analysis';
 $string['analysisoptions'] = 'Analysis options';
 $string['attemptselection'] = 'Attempts to analyze per user ';
 $string['lowmarkslimit'] = "Don't analyse if score is less than: ";
diff --git a/lang/en_utf8/quiz_grading.php b/lang/en_utf8/quiz_grading.php
new file mode 100644 (file)
index 0000000..ca67be9
--- /dev/null
@@ -0,0 +1,5 @@
+<?php // $Id$
+
+$string['grading'] = 'Manual grading';
+$string['essayonly'] = 'Manual grading has so far been implemented for essay questions only';
+?>
diff --git a/lang/en_utf8/quiz_overview.php b/lang/en_utf8/quiz_overview.php
new file mode 100644 (file)
index 0000000..04373ee
--- /dev/null
@@ -0,0 +1,5 @@
+<?php // $Id$
+
+$string['overview'] = 'Overview';
+
+?>
diff --git a/lang/en_utf8/quiz_regrade.php b/lang/en_utf8/quiz_regrade.php
new file mode 100644 (file)
index 0000000..6df6ab9
--- /dev/null
@@ -0,0 +1,5 @@
+<?php // $Id$
+
+$string['regrade'] = 'Regrade';
+
+?>
index 79fd1467817b21b4c0c80e77f4da66d89191a290..bf732d11eec06edec9741178c774ce79d6b63ff0 100644 (file)
@@ -4,4 +4,5 @@ $string['responsesoptions'] = 'Responses options';
 $string['responsestitle'] = 'Detailed responses';
 $string['pagesize'] = 'Attempts per page: ';
 $string['reportresponses'] = 'Detailed responses';
+$string['responses'] = 'Detailed responses';
 ?>
diff --git a/mod/quiz/grading.php b/mod/quiz/grading.php
deleted file mode 100644 (file)
index d709b88..0000000
+++ /dev/null
@@ -1,414 +0,0 @@
-<?php  
-
-// This file allows a teacher to grade essay questions.  
-// Could be later expanded to change user responses for all question types
-
-# Flow of the file:
-#     Get variables, run essential queries, print header and print tabs
-#     Check for post data submitted.  If exists, then process data (the data is the grades and comments for essay questions)
-#     Check for userid, attemptid, or gradeall and for questionid.  If found, print out the appropriate essay question attempts
-#     Switch:
-#         first case: print out all essay questions in quiz and the number of ungraded attempts
-#         second case: print out all users and their attempts for a specific essay question
-
-
-    require_once("../../config.php");
-    require_once("lib.php");
-    require_once("editlib.php");
-    require_once($CFG->libdir.'/tablelib.php');
-
-    $quizid = required_param('quizid', PARAM_INT);    // Course Module ID, or
-    $action = optional_param('action', 'viewquestions', PARAM_ALPHA);
-    $questionid = optional_param('questionid', 0, PARAM_INT);
-    $attemptid = optional_param('attemptid', 0, PARAM_INT);
-    $gradeall = optional_param('gradeall', 0, PARAM_INT);
-    $userid = optional_param('userid', 0, PARAM_INT);
-
-
-    if (!empty($questionid)) {
-        if (! $question = get_record('question', 'id', $questionid)) {
-            error("Question with id $questionid not found");
-        }
-        ///$number = optional_param('number', 0, PARAM_INT);
-    }
-
-    if (! $quiz = get_record("quiz", "id", $quizid)) {
-        error("Quiz with id $quizid not found");
-    }
-    if (! $course = get_record("course", "id", $quiz->course)) {
-        error("Course is misconfigured");
-    }
-    if (! $cm = get_coursemodule_from_instance("quiz", $quiz->id, $course->id)) {
-        error("Course Module ID was incorrect");
-    }
-
-    require_login($course->id);
-
-    if (!$isteacher = isteacheredit($course->id)) {
-        error("Only teachers authorized to edit the course '{$course->fullname}' can use this page!");
-    }
-
-    // if no questions have been set up yet redirect to edit.php
-    if (!$quiz->questions) {
-        redirect('edit.php?quizid='.$quiz->id);
-    }
-
-    add_to_log($course->id, "quiz", "manualgrading", "grading.php?quizid=$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
-    #     $currentgroup = setup_and_print_groups($course, $groupmode, "attempts.php?id=$cm->id&amp;mode=overview");
-    # } else {
-    #     $currentgroup = false;
-    # }
-
-/// Get all students
-    # if ($currentgroup) {
-    #     $users = get_group_students($currentgroup);
-    # }
-    # 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)); 
-    }
-
-    $strquizzes = get_string("modulenameplural", "quiz");
-    $strmanualgrading  = get_string("manualgrading", "quiz");
-
-    print_header_simple("$quiz->name", "",
-                 "<a href=\"index.php?id=$course->id\">$strquizzes</a> 
-                  -> <a href=\"view.php?id=$cm->id\">$quiz->name</a> -> $strmanualgrading", 
-                 "", "", true);
-
-
-    $currenttab = 'manualgrading';
-    include('tabs.php');
-    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
-            if (count($keyparts) == 3) { // must have 3 parts to the key
-                // re-assign to nice variable names for readability
-                $attemptid = $keyparts[0];
-                $stateid = $keyparts[1];
-                $fieldname = $keyparts[2];
-                
-                $responses[$attemptid.'_'.$stateid][$fieldname] = $response;
-            }
-        }
-        // now go through all of the responses to grade them and save them.
-        // not totally sure if this process is correct or fully optimized.  I need help here!
-        foreach($responses as $ids => $response) {
-            // get our necessary ids
-            $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);
-
-            // 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;
-            $state->changed = 1;
-            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, 
-                    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
-            $where = 'WHERE u.id='.$userid.' ';
-        } 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 '; 
-        $sort = 'ORDER BY u.firstname, u.lastname, qa.attempt ASC';
-        $attempts = get_records_sql($select.$from.$where.$sort);
-        
-        echo '<form method="post" action="grading.php">'.
-            '<input type="hidden" name="quizid" 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.'">';        
-        
-        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;
-
-            $options = quiz_get_reviewoptions($quiz, $attempt, $isteacher);
-            $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>';
-        }
-        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 
-    // with the number of ungraded attempts for each 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':
-            notify(get_string('essayonly', 'quiz'));
-            // just a basic table for this...
-            $table = new stdClass;
-            $table->head = array(get_string("essayquestions", "quiz"), get_string("ungraded", "quiz"));
-            $table->align = array("left", "left");
-            $table->wrap = array("wrap", "wrap");
-            $table->width = "20%";
-            $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".
-                   "  FROM {$CFG->prefix}question q,".
-                   "       {$CFG->prefix}quiz_question_instances i".
-                   " WHERE i.quiz = '$quiz->id' AND q.id = i.question".
-                   "   AND q.id IN ($questionlist)".
-                   "   AND q.qtype = '".ESSAY."'".
-                   "   ORDER BY q.name";
-            if (empty($questionlist) or !$questions = get_records_sql($sql)) {
-                print_heading(get_string('noessayquestionsfound', 'quiz'));
-                print_footer($course);
-                exit();
-            }
-            // 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=\"grading.php?quizid=$quiz->id&amp;action=viewquestion&amp;questionid=$question->id\">".
-                            $question->name."</a>";
-                    // determine the number of ungraded attempts (essay question thing only)
-                    $ungraded = 0;
-                    foreach ($attempts as $attempt) {
-                        // grab the state then check if it is graded
-                        if (!$neweststate = get_record('question_sessions', 'attemptid', $attempt->uniqueid, 'questionid', $question->id)) {
-                            error("Can not find newest states for attempt $attempt->uniqueid for question $question->id");
-                        }
-                        if (!$questionstate = get_record('question_essay_states', 'stateid', $neweststate->newest)) {
-                            error('Could not find question state');
-                        }
-                        if (!$questionstate->graded) {
-                            $ungraded++;
-                        }
-                    }
-
-                    $table->data[] = array($link, $ungraded);
-                }
-                print_table($table);
-            } else {
-                print_heading(get_string('noattempts', 'quiz'));
-            }
-            break;
-        case 'viewquestion':
-            // 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/grading.php?quizid='.$quiz->id.'&amp;action=viewquestion&amp;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();                    
-            
-            // 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 '; 
-     
-            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..
-            } else {
-                // 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());
-            } else {
-                $limit = '';
-            }
-            //$number = 1;
-            // 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                        
-                    $userlink = "<a href=\"grading.php?quizid=$quiz->id&amp;questionid=$question->id&amp;userid=$attempt->userid\">".
-                                $attempt->firstname.' '.$attempt->lastname.'</a>';
-                    
-                    // nab the state of the attempt to see if it is graded or not
-                    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');
-                    }
-                    // change the color of the link based on being graded or not
-                    if (!$questionstate->graded) {
-                        $style = 'style="color:#FF0000"';  // red
-                    } else {
-                        $style = 'style="color:#008000"';  // green
-                    }
-                    
-                    // link for the attempt
-                    $attemptlink = "<a $style href=\"grading.php?quizid=$quiz->id&amp;questionid=$question->id&amp;attemptid=$attempt->attemptid\">".  // &amp;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=\"grading.php?quizid=$quiz->id&amp;questionid=$questionid&amp;gradeall=1\">".get_string('gradeall', 'quiz').'</a> | '.
-                    "<a href=\"grading.php?quizid=$quiz->id&amp;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;            
-            break;
-        default:
-            error("Invalid Action");
-    }
-    
-    print_footer($course);
-
-?>
index 295ded257f079ab162973dcf6d99d67092849c4c..a4a4cc8835c9d9b3e86139dc0bd4203aaa19934e 100644 (file)
@@ -348,10 +348,7 @@ class quiz_report extends quiz_default_report {
             }
         }
         
-        echo '<div id="titlecontainer" class="quiz-report-title">';
-        echo get_string("analysistitle", "quiz_analysis");
-        helpbutton("itemanalysis", get_string("reportanalysis","quiz_analysis"), "quiz");
-        echo '</div>';
+        print_heading_with_help(get_string("analysistitle", "quiz_analysis"),"itemanalysis", "quiz");
 
         echo '<div id="tablecontainer">';
         $table->print_html();
diff --git a/mod/quiz/report/grading/report.php b/mod/quiz/report/grading/report.php
new file mode 100644 (file)
index 0000000..6f68767
--- /dev/null
@@ -0,0 +1,388 @@
+<?php  
+
+// This file allows a teacher to grade essay questions.  
+// Could be later expanded to change grades for all question types
+
+# Flow of the file:
+#     Get variables, run essential queries
+#     Check for post data submitted.  If exists, then process data (the data is the grades and comments for essay questions)
+#     Check for userid, attemptid, or gradeall and for questionid.  If found, print out the appropriate essay question attempts
+#     Switch:
+#         first case: print out all essay questions in quiz and the number of ungraded attempts
+#         second case: print out all users and their attempts for a specific essay question
+
+
+    require_once("editlib.php");
+    require_once($CFG->libdir.'/tablelib.php');
+
+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);
+        $gradeall = optional_param('gradeall', 0, PARAM_INT);
+        $userid = optional_param('userid', 0, PARAM_INT);
+
+        $this->print_header_and_tabs($cm, $course, $quiz, $reportmode="grading");
+
+        if (!empty($questionid)) {
+            if (! $question = get_record('question', 'id', $questionid)) {
+                error("Question with id $questionid not found");
+            }
+            ///$number = optional_param('number', 0, PARAM_INT);
+        }
+    
+        add_to_log($course->id, "quiz", "manualgrading", "report.php?mode=grading&amp;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
+        #     $currentgroup = setup_and_print_groups($course, $groupmode, "attempts.php?id=$cm->id&amp;mode=overview");
+        # } else {
+        #     $currentgroup = false;
+        # }
+    
+    /// Get all students
+        # if ($currentgroup) {
+        #     $users = get_group_students($currentgroup);
+        # }
+        # 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)); 
+        }
+    
+        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
+                if (count($keyparts) == 3) { // must have 3 parts to the key
+                    // re-assign to nice variable names for readability
+                    $attemptid = $keyparts[0];
+                    $stateid = $keyparts[1];
+                    $fieldname = $keyparts[2];
+                    
+                    $responses[$attemptid.'_'.$stateid][$fieldname] = $response;
+                }
+            }
+            // now go through all of the responses to grade them and save them.
+            // not totally sure if this process is correct or fully optimized.  I need help here!
+            foreach($responses as $ids => $response) {
+                // get our necessary ids
+                $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);
+    
+                // 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;
+                $state->changed = 1;
+                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, 
+                        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
+                $where = 'WHERE u.id='.$userid.' ';
+            } 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 '; 
+            $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.'">';        
+            
+            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;
+    
+                $options = quiz_get_reviewoptions($quiz, $attempt, isteacher());
+                $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>';
+            }
+            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 
+        // with the number of ungraded attempts for each 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':
+                notify(get_string('essayonly', 'quiz_grading'));
+                // just a basic table for this...
+                $table = new stdClass;
+                $table->head = array(get_string("essayquestions", "quiz"), get_string("ungraded", "quiz"));
+                $table->align = array("left", "left");
+                $table->wrap = array("wrap", "wrap");
+                $table->width = "20%";
+                $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".
+                       "  FROM {$CFG->prefix}question q,".
+                       "       {$CFG->prefix}quiz_question_instances i".
+                       " WHERE i.quiz = '$quiz->id' AND q.id = i.question".
+                       "   AND q.id IN ($questionlist)".
+                       "   AND q.qtype = '".ESSAY."'".
+                       "   ORDER BY q.name";
+                if (empty($questionlist) or !$questions = get_records_sql($sql)) {
+                    print_heading(get_string('noessayquestionsfound', 'quiz'));
+                    print_footer($course);
+                    exit();
+                }
+                // 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&amp;q=$quiz->id&amp;action=viewquestion&amp;questionid=$question->id\">".
+                                $question->name."</a>";
+                        // determine the number of ungraded attempts (essay question thing only)
+                        $ungraded = 0;
+                        foreach ($attempts as $attempt) {
+                            // grab the state then check if it is graded
+                            if (!$neweststate = get_record('question_sessions', 'attemptid', $attempt->uniqueid, 'questionid', $question->id)) {
+                                error("Can not find newest states for attempt $attempt->uniqueid for question $question->id");
+                            }
+                            if (!$questionstate = get_record('question_essay_states', 'stateid', $neweststate->newest)) {
+                                error('Could not find question state');
+                            }
+                            if (!$questionstate->graded) {
+                                $ungraded++;
+                            }
+                        }
+    
+                        $table->data[] = array($link, $ungraded);
+                    }
+                    print_table($table);
+                } else {
+                    print_heading(get_string('noattempts', 'quiz'));
+                }
+                break;
+            case 'viewquestion':
+                // 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&amp;q='.$quiz->id.'&amp;action=viewquestion&amp;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();                    
+                
+                // 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 '; 
+         
+                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..
+                } else {
+                    // 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());
+                } else {
+                    $limit = '';
+                }
+                //$number = 1;
+                // 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                        
+                        $userlink = "<a href=\"report.php?mode=grading&amp;q=$quiz->id&amp;questionid=$question->id&amp;userid=$attempt->userid\">".
+                                    $attempt->firstname.' '.$attempt->lastname.'</a>';
+                        
+                        // nab the state of the attempt to see if it is graded or not
+                        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');
+                        }
+                        // change the color of the link based on being graded or not
+                        if (!$questionstate->graded) {
+                            $style = 'style="color:#FF0000"';  // red
+                        } else {
+                            $style = 'style="color:#008000"';  // green
+                        }
+                        
+                        // link for the attempt
+                        $attemptlink = "<a $style href=\"report.php?mode=grading&amp;q=$quiz->id&amp;questionid=$question->id&amp;attemptid=$attempt->attemptid\">".  // &amp;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&amp;q=$quiz->id&amp;questionid=$questionid&amp;gradeall=1\">".get_string('gradeall', 'quiz').'</a> | '.
+                        "<a href=\"report.php?mode=grading&amp;q=$quiz->id&amp;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;            
+                break;
+            default:
+                error("Invalid Action");
+        }
+        return true;
+    }
+
+}
+
+?>
index 5ba029faa588ec68475cb908f91467ee4000ed38..9f03e554a9d86cbb3700e08ad2e13b2d27f6cc1c 100644 (file)
@@ -245,13 +245,13 @@ class quiz_report extends quiz_default_report {
                 // So join on groups_members and do an inner join on attempts.
                 $from  = 'FROM '.$CFG->prefix.'user u JOIN '.$CFG->prefix.'user_students us ON us.userid = u.id JOIN '.$CFG->prefix.'groups_members gm ON u.id = gm.userid '.
                     'JOIN '.$CFG->prefix.'quiz_attempts qa ON u.id = qa.userid AND qa.quiz = '.$quiz->id;
-                $where = ' WHERE  us.course = '.$course->id.' AND gm.groupid = '.$currentgroup;                
+                $where = ' WHERE  us.course = '.$course->id.' AND gm.groupid = '.$currentgroup.' AND qa.preview = 0';                
             } else if (!empty($currentgroup) && !empty($noattempts)) {
                 // We want a particular group and we want to do something funky with attempts
                 // So join on groups_members and left join on attempts... 
                 $from  = 'FROM '.$CFG->prefix.'user u JOIN '.$CFG->prefix.'user_students us ON us.userid = u.id JOIN '.$CFG->prefix.'groups_members gm ON u.id = gm.userid '.
                     'LEFT JOIN '.$CFG->prefix.'quiz_attempts qa ON u.id = qa.userid AND qa.quiz = '.$quiz->id;
-                $where = ' WHERE us.course = '.$course->id.' AND gm.groupid = '.$currentgroup;
+                $where = ' WHERE us.course = '.$course->id.' AND gm.groupid = '.$currentgroup.' AND qa.preview = 0';
                 if ($noattempts == 1) {
                     // noattempts = 1 means only no attempts, so make the left join ask for only records where the right is null (no attempts)
                     $where .= ' AND qa.userid IS NULL'; // show ONLY no attempts;
@@ -260,7 +260,7 @@ class quiz_report extends quiz_default_report {
                 // We don't care about group, and we only want to see students WITH attempts.
                 // So just do a striaght inner join on attempts, don't worry about the groups_members table
                 $from  = 'FROM '.$CFG->prefix.'user u JOIN '.$CFG->prefix.'quiz_attempts qa ON u.id = qa.userid ';
-                $where = ' WHERE qa.quiz = '.$quiz->id;
+                $where = ' WHERE qa.quiz = '.$quiz->id.' AND qa.preview = 0';
             } else if (empty($currentgroup) && !empty($noattempts)) {
                 // We don't care about group, and we to do something funky with attempts
                 // So do a left join on attempts
@@ -275,7 +275,7 @@ class quiz_report extends quiz_default_report {
         } else {
             if (empty($noattempts)) {
                 $from   = 'FROM '.$CFG->prefix.'user u JOIN '.$CFG->prefix.'quiz_attempts qa ON u.id = qa.userid ';
-                $where = ' WHERE qa.quiz = '.$quiz->id;
+                $where = ' WHERE qa.quiz = '.$quiz->id.' AND qa.preview = 0';
                 $countsql = 'SELECT COUNT(DISTINCT('.$db->Concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')).')) '.$from.$where;
             }
         }
index e8768a960b8c6d0b7067bbfa2a46cabb8c86c0bb..502a5c4727d68375c51ce4179b604a99a0442518 100644 (file)
@@ -41,7 +41,7 @@
     if ($currenttab == 'reports' and isset($mode)) {
         $inactive[] = 'reports';
         $allreports = get_list_of_plugins("mod/quiz/report");
-        $reportlist = array ('overview', 'regrade', 'analysis');   // Standard reports we want to show first
+        $reportlist = array ('overview', 'regrade', 'grading', 'analysis');   // Standard reports we want to show first
 
         foreach ($allreports as $report) {
             if (!in_array($report, $reportlist)) {
@@ -53,7 +53,7 @@
         $currenttab = '';
         foreach ($reportlist as $report) {
             $row[] = new tabobject($report, "$CFG->wwwroot/mod/quiz/report.php?q=$quiz->id&amp;mode=$report",
-                                    get_string("report$report", "quiz"));
+                                    get_string($report, 'quiz_'.$report));
             if ($report == $mode) {
                 $currenttab = $report;
             }