echo "</style>\n";
echo '<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /></head>';
offlinequiz_load_useridentification();
$offlinequizconfig = get_config('offlinequiz');
$group = $groups[$result->offlinegroupid];
$offlinequiz->groupid = -$group->id;
list($maxquestions, $maxanswers, $formtype, $questionsperpage) = offlinequiz_get_question_numbers($offlinequiz, array($group));
$offlinequizconfig->papergray = $offlinequiz->papergray;
// Load corners from DB.
$dbcorners = $DB->get_records('offlinequiz_page_corners', array('scannedpageid' => $scannedpage->id));
$corners = array();
foreach ($dbcorners as $corner) {
    $corners[] = new oq_point($corner->x, $corner->y);
}
// Initialize a page scanner.
$scanner = new offlinequiz_page_scanner($offlinequiz, $context->id, $maxquestions, $maxanswers);
// Load the stored picture file.
$sheetloaded = $scanner->load_stored_image($scannedpage->filename, $corners);
$pagenumber = $scannedpage->pagenumber;
// Make a first check.
$scanner->check_deleted();
$scanner->calibrate_and_get_group();
$scanner->get_usernumber();
$scanner->get_page();
// Necessary s.t. we can get the answer hotspots from the scanner.
$scanner->set_page($pagenumber);
$quba = question_engine::load_questions_usage_by_activity($result->usageid);
$slots = $quba->get_slots();
// Determine the slice of slots we are interested in.
// We start at the top of the page (e.g. 0, 96, etc).
$startindex = min(($pagenumber - 1) * $questionsperpage, count($slots));
示例#2
0
function offlinequiz_evaluation_cron($jobid = 0, $verbose = false)
{
    global $CFG, $DB;
    raise_memory_limit(MEMORY_EXTRA);
    // Only count the jobs with status processing that have been started in the last 24 hours.
    $expiretime = time() - 86400;
    $runningsql = "SELECT COUNT(*)\n                     FROM {offlinequiz_queue}\n                    WHERE status = 'processing'\n                      AND timestart > :expiretime";
    $runningjobs = $DB->count_records_sql($runningsql, array('expiretime' => $expiretime));
    if ($runningjobs >= OFFLINEQUIZ_MAX_CRON_JOBS) {
        echo "Too many jobs running! Exiting!";
        return;
    }
    // TODO do this properly. Just for testing.
    $sql = "SELECT * FROM {offlinequiz_queue} WHERE status = 'new'";
    $params = array();
    if ($jobid) {
        $sql .= ' AND id = :jobid ';
        $params['jobid'] = $jobid;
    }
    $sql .= " ORDER BY id ASC";
    // If there are no new jobs, we simply exit.
    if (!($jobs = $DB->get_records_sql($sql, $params, 0, OFFLINEQUIZ_TOP_QUEUE_JOBS))) {
        if ($verbose) {
            echo get_string('nothingtodo', 'offlinequiz');
        }
        return;
    }
    $numberofjobs = count($jobs);
    if ($verbose) {
        $pbar = new progress_bar('offlinequizcronbar', 500, true);
        $pbar->create();
        $pbar->update(0, $numberofjobs, "Processing job - {0}/{$numberofjobs}.");
    }
    $numberdone = 0;
    foreach ($jobs as $job) {
        // Check whether the status is still 'new' (might have been changed by other cronjob).
        $transaction = $DB->start_delegated_transaction();
        $status = $DB->get_field('offlinequiz_queue', 'status', array('id' => $job->id));
        if ($status == 'new') {
            $DB->set_field('offlinequiz_queue', 'status', 'processing', array('id' => $job->id));
            $job->timestart = time();
            $DB->set_field('offlinequiz_queue', 'timestart', $job->timestart, array('id' => $job->id));
            $alreadydone = false;
        } else {
            $alreadydone = true;
        }
        $transaction->allow_commit();
        // If the job is still new, process it!
        if (!$alreadydone) {
            // Set up the context for this job.
            if (!($offlinequiz = $DB->get_record('offlinequiz', array('id' => $job->offlinequizid)))) {
                $DB->set_field('offlinequiz_queue', 'status', 'error', array('id' => $job->id));
                $DB->set_field('offlinequiz_queue', 'info', 'offlinequiz not found', array('id' => $job->id));
                continue;
            }
            if (!($course = $DB->get_record('course', array('id' => $offlinequiz->course)))) {
                $DB->set_field('offlinequiz_queue', 'status', 'error', array('id' => $job->id));
                $DB->set_field('offlinequiz_queue', 'info', 'course not found', array('id' => $job->id));
                continue;
            }
            if (!($cm = get_coursemodule_from_instance("offlinequiz", $offlinequiz->id, $course->id))) {
                $DB->set_field('offlinequiz_queue', 'status', 'error', array('id' => $job->id));
                $DB->set_field('offlinequiz_queue', 'info', 'course module found', array('id' => $job->id));
                continue;
            }
            if (!($context = context_module::instance($cm->id))) {
                $DB->set_field('offlinequiz_queue', 'status', 'error', array('id' => $job->id));
                $DB->set_field('offlinequiz_queue', 'info', 'context not found', array('id' => $job->id));
                continue;
            }
            if (!($groups = $DB->get_records('offlinequiz_groups', array('offlinequizid' => $offlinequiz->id), 'number', '*', 0, $offlinequiz->numgroups))) {
                $DB->set_field('offlinequiz_queue', 'status', 'error', array('id' => $job->id));
                $DB->set_field('offlinequiz_queue', 'info', 'no offlinequiz groups found', array('id' => $job->id));
                continue;
            }
            $coursecontext = context_course::instance($course->id);
            offlinequiz_load_useridentification();
            // TODO.
            $jobdata = $DB->get_records_sql("\n                    SELECT *\n                      FROM {offlinequiz_queue_data}\n                     WHERE queueid = :queueid\n                       AND status = 'new'", array('queueid' => $job->id));
            list($maxquestions, $maxanswers, $formtype, $questionsperpage) = offlinequiz_get_question_numbers($offlinequiz, $groups);
            $dirname = '';
            $doubleentry = 0;
            foreach ($jobdata as $data) {
                $starttime = time();
                $DB->set_field('offlinequiz_queue_data', 'status', 'processing', array('id' => $data->id));
                // We remember the directory name to be able to remove it later.
                if (empty($dirname)) {
                    $pathparts = pathinfo($data->filename);
                    $dirname = $pathparts['dirname'];
                }
                set_time_limit(120);
                try {
                    // Create a new scanner for every page.
                    $scanner = new offlinequiz_page_scanner($offlinequiz, $context->id, $maxquestions, $maxanswers);
                    // Try to load the image file.
                    echo 'job ' . $job->id . ': evaluating ' . $data->filename . "\n";
                    $scannedpage = $scanner->load_image($data->filename);
                    if ($scannedpage->status == 'ok') {
                        echo 'job ' . $job->id . ': image loaded ' . $scannedpage->filename . "\n";
                    } else {
                        if ($scannedpage->error == 'filenotfound') {
                            echo 'job ' . $job->id . ': image file not found: ' . $scannedpage->filename . "\n";
                        }
                    }
                    // Unset the origfilename because we don't need it in the DB.
                    unset($scannedpage->origfilename);
                    $scannedpage->offlinequizid = $offlinequiz->id;
                    // If we could load the image file, the status is 'ok', so we can check the page for errors.
                    if ($scannedpage->status == 'ok') {
                        // We autorotate so check_scanned_page will return a potentially new scanner and the scannedpage.
                        list($scanner, $scannedpage) = offlinequiz_check_scanned_page($offlinequiz, $scanner, $scannedpage, $job->importuserid, $coursecontext, true);
                    } else {
                        if (property_exists($scannedpage, 'id') && !empty($scannedpage->id)) {
                            $DB->update_record('offlinequiz_scanned_pages', $scannedpage);
                        } else {
                            $scannedpage->id = $DB->insert_record('offlinequiz_scanned_pages', $scannedpage);
                        }
                    }
                    echo 'job ' . $job->id . ': scannedpage id ' . $scannedpage->id . "\n";
                    // If the status is still 'ok', we can process the answers. This potentially submits the page and
                    // checks whether the result for a student is complete.
                    if ($scannedpage->status == 'ok') {
                        // We can process the answers and submit them if possible.
                        $scannedpage = offlinequiz_process_scanned_page($offlinequiz, $scanner, $scannedpage, $job->importuserid, $questionsperpage, $coursecontext, true);
                        echo 'job ' . $job->id . ': processed answers for ' . $scannedpage->id . "\n";
                    } else {
                        if ($scannedpage->status == 'error' && $scannedpage->error == 'resultexists') {
                            // Already process the answers but don't submit them.
                            $scannedpage = offlinequiz_process_scanned_page($offlinequiz, $scanner, $scannedpage, $job->importuserid, $questionsperpage, $coursecontext, false);
                            // Compare the old and the new result wrt. the choices.
                            $scannedpage = offlinequiz_check_different_result($scannedpage);
                        }
                    }
                    // If there is something to correct then store the hotspots for retrieval in correct.php.
                    if ($scannedpage->status != 'ok' && $scannedpage->error != 'couldnotgrab' && $scannedpage->error != 'notadjusted' && $scannedpage->error != 'grouperror') {
                        $scanner->store_hotspots($scannedpage->id);
                    }
                    if ($scannedpage->status == 'ok' || $scannedpage->status == 'submitted' || $scannedpage->status == 'suspended' || $scannedpage->error == 'missingpages') {
                        // Mark the file as processed.
                        $DB->set_field('offlinequiz_queue_data', 'status', 'processed', array('id' => $data->id));
                    } else {
                        $DB->set_field('offlinequiz_queue_data', 'status', 'error', array('id' => $data->id));
                        $DB->set_field('offlinequiz_queue_data', 'error', $scannedpage->error, array('id' => $data->id));
                    }
                    if ($scannedpage->error == 'doublepage') {
                        $doubleentry++;
                    }
                } catch (Exception $e) {
                    echo 'job ' . $job->id . ': ' . $e->getMessage() . "\n";
                    $DB->set_field('offlinequiz_queue_data', 'status', 'error', array('id' => $data->id));
                    $DB->set_field('offlinequiz_queue_data', 'error', 'couldnotgrab', array('id' => $data->id));
                    $DB->set_field('offlinequiz_queue_data', 'info', $e->getMessage(), array('id' => $data->id));
                    $scannedpage->status = 'error';
                    $scannedpage->error = 'couldnotgrab';
                    if ($scannedpage->id) {
                        $DB->update_record('offlinequiz_scanned_pages', $scannedpage);
                    } else {
                        $DB->insert_record('offlinequiz_scanned_pages', $scannedpage);
                    }
                }
            }
            // End foreach jobdata.
            offlinequiz_update_grades($offlinequiz);
            $job->timefinish = time();
            $DB->set_field('offlinequiz_queue', 'timefinish', $job->timefinish, array('id' => $job->id));
            $job->status = 'finished';
            $DB->set_field('offlinequiz_queue', 'status', 'finished', array('id' => $job->id));
            echo date('Y-m-d-H:i') . ": Import queue with id {$job->id} imported.\n\n";
            if ($user = $DB->get_record('user', array('id' => $job->importuserid))) {
                $mailtext = get_string('importisfinished', 'offlinequiz', format_text($offlinequiz->name, FORMAT_PLAIN));
                // How many pages have been imported successfully.
                $countsql = "SELECT COUNT(id)\n                               FROM {offlinequiz_queue_data}\n                              WHERE queueid = :queueid\n                                AND status = 'processed'";
                $params = array('queueid' => $job->id);
                $mailtext .= "\n\n" . get_string('importnumberpages', 'offlinequiz', $DB->count_records_sql($countsql, $params));
                // How many pages have an error.
                $countsql = "SELECT COUNT(id)\n                               FROM {offlinequiz_queue_data}\n                              WHERE queueid = :queueid\n                                AND status = 'error'";
                $mailtext .= "\n" . get_string('importnumberverify', 'offlinequiz', $DB->count_records_sql($countsql, $params));
                $mailtext .= "\n" . get_string('importnumberexisting', 'offlinequiz', $doubleentry);
                $linkoverview = "{$CFG->wwwroot}/mod/offlinequiz/report.php?q={$job->offlinequizid}&mode=overview";
                $mailtext .= "\n\n" . get_string('importlinkresults', 'offlinequiz', $linkoverview);
                $linkupload = "{$CFG->wwwroot}/mod/offlinequiz/report.php?q={$job->offlinequizid}&mode=rimport";
                $mailtext .= "\n" . get_string('importlinkverify', 'offlinequiz', $linkupload);
                $mailtext .= "\n\n" . get_string('importtimestart', 'offlinequiz', userdate($job->timestart));
                $mailtext .= "\n" . get_string('importtimefinish', 'offlinequiz', userdate($job->timefinish));
                email_to_user($user, $CFG->noreplyaddress, get_string('importmailsubject', 'offlinequiz'), $mailtext);
            }
        }
        // End !alreadydone.
        $numberdone++;
        if ($verbose) {
            ob_flush();
            $pbar->update($numberdone, $numberofjobs, "Processing job - {$numberdone}/{$numberofjobs}.");
        }
    }
    // End foreach.
}
         if ($instanceid = $enrol->add_default_instance($course)) {
             $instance = $DB->get_record('enrol', array('courseid' => $course->id, 'enrol' => 'manual'), '*', MUST_EXIST);
         }
     }
     if ($instance != false) {
         $enrol->enrol_user($instance, $userid, $offlinequizconfig->oneclickrole);
     }
 }
 // Now we look for other pages with that user and reset their status.
 $sql = "SELECT *\n              FROM {offlinequiz_scanned_pages}\n             WHERE offlinequizid = :offlinequizid\n               AND status = 'error'\n               AND error = 'usernotincourse'\n               AND userkey = :currentuserkey\n               AND id <> :currentpageid";
 $params = array('offlinequizid' => $offlinequiz->id, 'currentuserkey' => $scannedpage->userkey, 'currentpageid' => $scannedpage->id);
 $otherpages = $DB->get_records_sql($sql, $params);
 foreach ($otherpages as $otherpage) {
     $otherpage->status = 'ok';
     $otherpage->error = '';
     $tempscanner = new offlinequiz_page_scanner($offlinequiz, $context->id, $maxquestions, $maxanswers);
     $tempcorners = array();
     if ($dbcorners = $DB->get_records('offlinequiz_page_corners', array('scannedpageid' => $otherpage->id), 'position')) {
         foreach ($dbcorners as $corner) {
             $tempcorners[] = new oq_point($corner->x, $corner->y);
         }
     } else {
         $tempcorners[0] = new oq_point(55, 39);
         $tempcorners[1] = new oq_point(805, 49);
         $tempcorners[2] = new oq_point(44, 1160);
         $tempcorners[3] = new oq_point(805, 1160);
     }
     $tempscanner->load_stored_image($otherpage->filename, $tempcorners);
     $otherpage = offlinequiz_check_scanned_page($offlinequiz, $tempscanner, $otherpage, $USER->id, $coursecontext);
     if ($otherpage->status == 'ok') {
         $otherpage = offlinequiz_process_scanned_page($offlinequiz, $tempscanner, $otherpage, $USER->id, $questionsperpage, $coursecontext, true);
/**
 * Stores the choices made on a scanned page in the table offlinequiz_choices. If there are no insecure markings
 * the page is also submitted, i.e. the answers are processed by the question usage by activiy (quba).
 *
 * @param unknown_type $offlinequiz
 * @param unknown_type $scanner
 * @param unknown_type $scannedpage
 * @param unknown_type $teacherid
 * @param unknown_type $coursecontext
 */
function offlinequiz_process_scanned_page($offlinequiz, offlinequiz_page_scanner $scanner, $scannedpage, $teacherid, $questionsperpage, $coursecontext, $submit = false)
{
    global $DB;
    $offlinequizconfig = get_config('offlinequiz');
    if (property_exists($scannedpage, 'resultid') && $scannedpage->resultid) {
        $group = $DB->get_record('offlinequiz_groups', array('offlinequizid' => $offlinequiz->id, 'number' => $scannedpage->groupnumber));
        $user = $DB->get_record('user', array($offlinequizconfig->ID_field => $scannedpage->userkey));
        $result = $DB->get_record('offlinequiz_results', array('id' => $scannedpage->resultid));
        $quba = offlinequiz_load_questions_usage_by_activity($result->usageid);
        // Retrieve the answers. This initialises the answer hotspots.
        $answers = $scanner->get_answers();
        if (empty($answers)) {
            $scannedpage->status = 'error';
            $scannedpage->error = 'notadjusted';
            return $scannedpage;
        }
        $slots = $quba->get_slots();
        // We start at the top of the page (e.g. 0, 96, etc).
        $startindex = ($scannedpage->pagenumber - 1) * $questionsperpage;
        // We end on the bottom of the page or when the questions are gone (e.g., 95, 105).
        $endindex = min($scannedpage->pagenumber * $questionsperpage, count($slots));
        $answerindex = 0;
        $insecuremarkings = false;
        $choicesdata = array();
        for ($slotindex = $startindex; $slotindex < $endindex; $slotindex++) {
            $slot = $slots[$slotindex];
            $slotquestion = $quba->get_question($slot);
            $attempt = $quba->get_question_attempt($slot);
            $order = $slotquestion->get_order($attempt);
            // Order of the answers.
            // Note: The array length of a row is $maxanswers, so probably bigger than the number of answers in the slot.
            $row = $answers[$answerindex++];
            $count = 0;
            $response = array();
            if (!isset($choicesdata[$slot]) || !is_array($choicesdata[$slot])) {
                $choicesdata[$slot] = array();
            }
            // Go through all answers of the slot question.
            foreach ($order as $key => $notused) {
                // Create the data structure for the offlinequiz_choices table.
                $choice = new stdClass();
                $choice->scannedpageid = $scannedpage->id;
                $choice->slotnumber = $slot;
                $choice->choicenumber = $key;
                // Check what the scanner recognised.
                if ($row[$key] == 'marked') {
                    $choice->value = 1;
                } else {
                    if ($row[$key] == 'empty') {
                        $choice->value = 0;
                    } else {
                        $choice->value = -1;
                        $insecuremarkings = true;
                    }
                }
                // We really want to save every single cross  in the database.
                $choice->id = $DB->insert_record('offlinequiz_choices', $choice);
                $choicesdata[$slot][$key] = $choice;
            }
        }
        // End for (slot...
        if (!$insecuremarkings and $submit) {
            $scannedpage = offlinequiz_submit_scanned_page($offlinequiz, $scannedpage, $choicesdata, $startindex, $endindex);
            if ($scannedpage->status == 'submitted') {
                offlinequiz_check_result_completed($offlinequiz, $group, $result);
            }
        }
        // If insecure markings have been found, set the status appropriately.
        if (($scannedpage->status == 'ok' || $scannedpage->status == 'suspended') && $insecuremarkings) {
            $scannedpage->status = 'error';
            $scannedpage->error = 'insecuremarkings';
            $scannedpage->time = time();
            $DB->update_record('offlinequiz_scanned_pages', $scannedpage);
        }
    }
    // End if status ok.
    return $scannedpage;
}