Ejemplo n.º 1
0
// Initialize a page scanner.
$scanner = new offlinequiz_page_scanner($offlinequiz, $context->id, $maxquestions, $maxanswers);
// Load the stored image file.
if (property_exists($scannedpage, 'id')) {
    // If we re-adjust, rotate, or changed the user we have to delete the stored hotspots.
    if ($action == 'readjust' || $action == 'rotate' || $action == 'checkuser') {
        $DB->delete_records('offlinequiz_hotspots', array('scannedpageid' => $scannedpage->id));
    }
    // Load the stored image and the hotspots from the DB if they have not been deleted.
    $sheetloaded = $scanner->load_stored_image($scannedpage->filename, $corners, $scannedpage->id);
} else {
    // Load the stored image and adjust the hotspots from scratch.
    $sheetloaded = $scanner->load_stored_image($scannedpage->filename, $corners);
}
// Make a first check.
if (!$scanner->check_deleted()) {
    $scannedpage->status = 'error';
    $scannedpage->error = 'notadjusted';
}
// O=======================================.
// O Step 1. Get the data from the stored scanned page.
// O=======================================.
if ($action == 'load') {
    $filename = $scannedpage->filename;
    $userkey = $scannedpage->userkey;
    $usernumber = substr($userkey, strlen($offlinequizconfig->ID_prefix), $offlinequizconfig->ID_digits);
    $groupnumber = intval($scannedpage->groupnumber);
    $pagenumber = intval($scannedpage->pagenumber);
    // Remember initial data for cancel action.
    $origfilename = $filename;
    $origuserkey = $userkey;
Ejemplo n.º 2
0
$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));
// We end on the bottom of the page or when the questions are gone (e.g., 95, 105).
$endindex = min($pagenumber * $questionsperpage, count($slots));
// Load the choices made before from the database. There might not be any.
$choices = $DB->get_records('offlinequiz_choices', array('scannedpageid' => $scannedpage->id), 'slotnumber, choicenumber');
// Choicesdata contains the choices data from the DB indexed by slotnumber and choicenumber.
Ejemplo n.º 3
0
/**
 * Checks  groupnumber, userkey, and pagenumber of a scanned answer form
 *
 * @param unknown_type $offlinequiz
 * @param offlinequiz_page_scanner $scanner
 * @param unknown_type $scannedpage
 * @param unknown_type $teacherid
 * @param unknown_type $coursecontext
 */
function offlinequiz_check_scanned_page($offlinequiz, offlinequiz_page_scanner $scanner, $scannedpage, $teacherid, $coursecontext, $autorotate = false, $recheckresult = false, $ignoremaxanswers = false)
{
    global $DB, $CFG;
    $offlinequizconfig = get_config('offlinequiz');
    if (!$scanner->check_deleted()) {
        $scannedpage->status = 'error';
        $scannedpage->error = 'notadjusted';
    }
    if ($scannedpage->status == 'error' && $scanner->ontop && $autorotate) {
        echo 'rotating...' . "\n";
        $oldfilename = $scannedpage->filename;
        if ($newfile = $scanner->rotate_180()) {
            $scannedpage->status = 'ok';
            $scannedpage->error = '';
            $scannedpage->userkey = null;
            $scannedpage->pagenumber = null;
            $scannedpage->groupnumber = null;
            $scannedpage->filename = $newfile->get_filename();
            $corners = $scanner->get_corners();
            $newcorners = array();
            // Create a completely new scanner.
            $scanner = new offlinequiz_page_scanner($offlinequiz, $scanner->contextid, $scanner->maxquestions, $scanner->maxanswers);
            $sheetloaded = $scanner->load_stored_image($scannedpage->filename, $newcorners);
            if (!$sheetloaded) {
                $scannedpage->status = 'error';
                $scannedpage->error = 'fatalerror';
            } else {
                if (!$scanner->check_deleted()) {
                    $scannedpage->status = 'error';
                    $scannedpage->error = 'notadjusted';
                } else {
                    $scannedpage->status = 'ok';
                    $scannedpage->error = '';
                }
            }
        }
    }
    // Check the group number.
    $groupnumber = $scanner->calibrate_and_get_group();
    // Call group first for callibration, such a crap!
    if (!property_exists($scannedpage, 'groupnumber') || $scannedpage->groupnumber == 0) {
        $scannedpage->groupnumber = $groupnumber;
    }
    $group = null;
    if ($scannedpage->status == 'ok' || $scannedpage->status == 'suspended') {
        if (!($group = $DB->get_record('offlinequiz_groups', array('offlinequizid' => $offlinequiz->id, 'number' => $scannedpage->groupnumber)))) {
            $scannedpage->status = 'error';
            $scannedpage->error = 'grouperror';
        }
    }
    // Adjust the maxanswers of the scanner according to the offlinequiz group deterimined above.
    if ($group && !$ignoremaxanswers) {
        $maxanswers = offlinequiz_get_maxanswers($offlinequiz, array($group));
        if ($maxanswers != $scanner->maxanswers) {
            // Create a completely new scanner.
            $corners = $scanner->get_corners();
            $scanner = new offlinequiz_page_scanner($offlinequiz, $scanner->contextid, $scanner->maxquestions, $maxanswers);
            $sheetloaded = $scanner->load_stored_image($scannedpage->filename, $corners);
            // Recursively call this method this time ignoring the maxanswers change.
            return offlinequiz_check_scanned_page($offlinequiz, $scanner, $scannedpage, $teacherid, $coursecontext, $autorotate, $recheckresult, true);
        }
    }
    // Check the user key (username, or userid, or other).
    $usernumber = $scanner->get_usernumber();
    if (empty($scannedpage->userkey)) {
        $scannedpage->userkey = $offlinequizconfig->ID_prefix . $usernumber . $offlinequizconfig->ID_postfix;
    }
    if ($scannedpage->status == 'ok' || $scannedpage->status == 'suspended') {
        if (!($user = $DB->get_record('user', array($offlinequizconfig->ID_field => $scannedpage->userkey)))) {
            $scannedpage->status = 'error';
            $scannedpage->error = 'nonexistinguser';
        } else {
            $coursestudents = get_enrolled_users($coursecontext, 'mod/offlinequiz:attempt');
            if (empty($coursestudents[$user->id])) {
                $scannedpage->status = 'error';
                $scannedpage->error = 'usernotincourse';
            }
        }
    }
    // Check the pagenumber.
    // Patch for old answer forms that did not have the page barcode.
    // With this patch the old forms can be uploaded in Moodle 2.x anyway.
    $pagenumber = $scanner->get_page();
    if ($group && $group->numberofpages == 1) {
        $scannedpage->pagenumber = 1;
        $scanner->set_page(1);
        $page = 1;
    } else {
        if (!property_exists($scannedpage, 'pagenumber') || $scannedpage->pagenumber == 0 || $scannedpage->pagenumber == null) {
            $scannedpage->pagenumber = $pagenumber;
        } else {
            // This is neede because otherwise the scanner doesn't return answers (questionsonpage not set).
            $scanner->set_page($scannedpage->pagenumber);
        }
        $page = $scannedpage->pagenumber;
        if ($scannedpage->status == 'ok' || $scannedpage->status == 'suspended') {
            if ($page < 1 || $page > $group->numberofpages) {
                $scannedpage->status = 'error';
                $scannedpage->error = 'invalidpagenumber';
            }
        }
    }
    // If we have a valid userkey, a group and a page number then we can
    // check whether there is already a scanned page or even a completed result with the same group, userid, etc.
    if (($scannedpage->status == 'ok' || $scannedpage->status == 'suspended') && $user && $group && $page) {
        $resultexists = false;
        if (!property_exists($scannedpage, 'resultid') || !$scannedpage->resultid || $recheckresult) {
            $sql = "SELECT id\n                      FROM {offlinequiz_results}\n                     WHERE offlinequizid = :offlinequizid\n                       AND userid = :userid\n                       AND status = 'complete'";
            $params = array('offlinequizid' => $offlinequiz->id, 'offlinegroupid' => $group->id, 'userid' => $user->id);
            if ($DB->get_record_sql($sql, $params)) {
                $resultexists = true;
            }
        }
        if ($resultexists) {
            $scannedpage->status = 'error';
            $scannedpage->error = 'resultexists';
        } else {
            if (!property_exists($scannedpage, 'id') || !$scannedpage->id) {
                $otherpages = $DB->get_records('offlinequiz_scanned_pages', array('offlinequizid' => $offlinequiz->id, 'userkey' => $user->{$offlinequizconfig->ID_field}, 'groupnumber' => $group->number, 'pagenumber' => $page));
            } else {
                $sql = "SELECT id\n                          FROM {offlinequiz_scanned_pages}\n                         WHERE offlinequizid = :offlinequizid\n                           AND userkey = :userkey\n                           AND groupnumber = :groupnumber\n                           AND pagenumber = :pagenumber\n                           AND (status = 'ok' OR status = 'submitted')\n                           AND id <> :id";
                $params = array('offlinequizid' => $offlinequiz->id, 'userkey' => $user->{$offlinequizconfig->ID_field}, 'groupnumber' => $group->number, 'pagenumber' => $page, 'id' => $scannedpage->id);
                $otherpages = $DB->get_records_sql($sql, $params);
            }
            if ($otherpages) {
                $scannedpage->status = 'error';
                $scannedpage->error = 'doublepage';
            }
        }
    }
    // Still everything OK, so we have a user and a group. Thus we can get/create the associated result
    // we also do that if another result exists, s.t. we have the answers later.
    if (empty($scannedpage->resultid)) {
        if ($scannedpage->status == 'ok' || $scannedpage->status == 'suspended' || $scannedpage->status == 'error' && $scannedpage->error == 'resultexists' || $scannedpage->status == 'error' && $scannedpage->error == 'usernotincourse') {
            // We have a group and a userid, so we can check if there is a matching partial result in the offlinequiz_results table.
            // The problem with this is that we could have several partial results with several pages.
            $sql = "SELECT *\n                      FROM {offlinequiz_results}\n                     WHERE offlinequizid = :offlinequizid\n                       AND offlinegroupid = :offlinegroupid\n                       AND userid = :userid\n                       AND status = 'partial'\n                  ORDER BY id ASC";
            $params = array('offlinequizid' => $offlinequiz->id, 'offlinegroupid' => $group->id, 'userid' => $user->id);
            if (!($result = $DB->get_record_sql($sql, $params))) {
                // There is no result. First we have to clone the template question usage of the offline group.
                // We have to use our own loading function in order to get the right class.
                $templateusage = offlinequiz_load_questions_usage_by_activity($group->templateusageid);
                // Get the question instances for initial maxmarks.
                $sql = "SELECT questionid, maxmark\n                          FROM {offlinequiz_group_questions}\n                         WHERE offlinequizid = :offlinequizid\n                           AND offlinegroupid = :offlinegroupid";
                $qinstances = $DB->get_records_sql($sql, array('offlinequizid' => $offlinequiz->id, 'offlinegroupid' => $group->id));
                // Clone it...
                $quba = $templateusage->get_clone($qinstances);
                // And save it. The clone contains the same question in the same order and the same order of the answers.
                question_engine::save_questions_usage_by_activity($quba);
                $result = new stdClass();
                $result->offlinequizid = $offlinequiz->id;
                $result->offlinegroupid = $group->id;
                $result->userid = $user->id;
                $result->teacherid = $teacherid;
                $result->usageid = $quba->get_id();
                $result->attendant = 'scanonly';
                $result->status = 'partial';
                $result->timecreated = time();
                $result->timemodified = time();
                $newid = $DB->insert_record('offlinequiz_results', $result);
                if ($newid) {
                    $result->id = $newid;
                    $scannedpage->resultid = $result->id;
                } else {
                    $scannedpage->status = 'error';
                    $scannedpage->error = 'noresult';
                }
            } else {
                // There is a partial result, so we can just load the user's question usage.
                // From now on we can use the default question usage class.
                $scannedpage->resultid = $result->id;
            }
        }
    }
    // We insert the scanned page into the database in any case.
    $scannedpage->time = time();
    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);
    }
    // Now the scanned page definitely has an ID, so we can store the corners.
    if (!$DB->get_records('offlinequiz_page_corners', array('scannedpageid' => $scannedpage->id))) {
        $corners = $scanner->get_corners();
        offlinequiz_save_page_corners($scannedpage, $corners);
    }
    if ($autorotate) {
        return array($scanner, $scannedpage);
    } else {
        return $scannedpage;
    }
}