@ -44,13 +44,22 @@ class auto_mark extends \core\task\scheduled_task {
$cachecm = array();
$cachecm = array();
$cacheatt = array();
$cacheatt = array();
$cachecourse = array();
$cachecourse = array();
$now = time(); // Store current time to use in queries so they all match nicely.
$sessions = $DB->get_recordset_select('attendance_sessions',
$sessions = $DB->get_recordset_select('attendance_sessions',
'automark = 1 AND automarkcompleted = 0 AND sessdate < ? ', array(time()));
'automark > 0 AND automarkcompleted < 2 AND sessdate < ? ' , array ( $ now ) ) ;
foreach ($sessions as $session) {
foreach ($sessions as $session) {
// Would be nice to change duration field to a timestamp so we don't need this step.
if ($session->sessdate + $session->duration < $now || // If session is over.
if ($session->sessdate + $session->duration < time ( ) ) {
// OR if session is currently open and automark is set to do all.
($session->sessdate < $now & & $session->automark == 1)) {
$userfirstaccess = array();
$donesomething = false; // Only trigger grades/events when an update actually occurs.
$donesomething = false; // Only trigger grades/events when an update actually occurs.
$sessionover = false; // Is this session over?
if ($session->sessdate + $session->duration < $now) {
$sessionover = true;
}
// Store cm/att/course in cachefields so we don't make unnecessary db calls.
// Store cm/att/course in cachefields so we don't make unnecessary db calls.
// Would probably be nice to grab this stuff outside of the loop.
// Would probably be nice to grab this stuff outside of the loop.
@ -84,6 +93,42 @@ class auto_mark extends \core\task\scheduled_task {
}
}
$pageparams->sessionid = $session->id;
$pageparams->sessionid = $session->id;
if ($session->automark == 1) {
$userfirstacess = array();
// If set to do full automarking, get all users that have accessed course during session open.
$id = $DB->sql_concat('userid', 'ip'); // Users may access from multiple ip, make the first field unique.
$sql = "SELECT $id, userid, ip, min(timecreated) as timecreated
FROM {logstore_standard_log}
WHERE courseid = ? AND timecreated > ? AND timecreated < ?
GROUP BY userid, ip";
$timestart = $session->sessdate;
if (empty($session->lasttakenby) & & $session->lasttaken > $timestart) {
// If the last time session was taken it was done automatically, use the last time taken
// as the start time for the logs we are interested in to help with performance.
$timestart = $session->lasttaken;
}
$duration = $session->duration;
if (empty($duration)) {
$duration = get_config('attendance', 'studentscanmarksessiontimeend') * 60;
}
$timeend = $timestart + $duration;
$logusers = $DB->get_recordset_sql($sql, array($courseid, $timestart, $timeend));
// Check if user access is in allowed subnet.
foreach ($logusers as $loguser) {
if (!empty($session->subnet) & & !address_in_subnet($loguser->ip, $session->subnet)) {
// This record isn't in the right subnet.
continue;
}
if (empty($userfirstaccess[$loguser->userid]) ||
$userfirstaccess[$loguser->userid] > $loguser->timecreated) {
// Users may have accessed from mulitple ip addresses, find the earliest access.
$userfirstaccess[$loguser->userid] = $loguser->timecreated;
}
}
$logusers->close();
}
// Get all unmarked students.
// Get all unmarked students.
$att = new \mod_attendance_structure($cacheatt[$session->attendanceid],
$att = new \mod_attendance_structure($cacheatt[$session->attendanceid],
$cachecm[$session->attendanceid], $cachecourse[$courseid], $context, $pageparams);
$cachecm[$session->attendanceid], $cachecourse[$courseid], $context, $pageparams);
@ -95,15 +140,23 @@ class auto_mark extends \core\task\scheduled_task {
foreach ($existinglog as $log) {
foreach ($existinglog as $log) {
if (empty($log->statusid)) {
if (empty($log->statusid)) {
// Status needs updating.
if ($sessionover || !empty($userfirstaccess[$log->studentid])) {
$existinglog->statusid = $setunmarked;
// Status needs updating.
$existinglog->timetaken = time();
if ($sessionover) {
$existinglog->takenby = 0;
$log->statusid = $setunmarked;
$existinglog->remarks = get_string('autorecorded', 'attendance');
} else if (!empty($userfirstaccess[$log->studentid])) {
$log->statusid = $att->get_automark_status($userfirstaccess[$log->studentid], $session->id);
$DB->update_record('attendance_log', $existinglog);
}
$updated++;
if (!empty($log->statusid)) {
$donesomething = true;
$log->timetaken = $now;
$log->takenby = 0;
$log->remarks = get_string('autorecorded', 'attendance');
$DB->update_record('attendance_log', $log);
$updated++;
$donesomething = true;
}
}
}
}
unset($users[$log->studentid]);
unset($users[$log->studentid]);
}
}
@ -111,8 +164,7 @@ class auto_mark extends \core\task\scheduled_task {
mtrace($updated . " session status updated");
mtrace($updated . " session status updated");
$newlog = new \stdClass();
$newlog = new \stdClass();
$newlog->statusid = $setunmarked;
$newlog->timetaken = $now;
$newlog->timetaken = time();
$newlog->takenby = 0;
$newlog->takenby = 0;
$newlog->sessionid = $session->id;
$newlog->sessionid = $session->id;
$newlog->remarks = get_string('autorecorded', 'attendance');
$newlog->remarks = get_string('autorecorded', 'attendance');
@ -120,17 +172,31 @@ class auto_mark extends \core\task\scheduled_task {
$added = 0;
$added = 0;
foreach ($users as $user) {
foreach ($users as $user) {
$newlog->studentid = $user->id;
if ($sessionover || !empty($userfirstaccess[$user->id])) {
$DB->insert_record('attendance_log', $newlog);
if ($sessionover) {
$added++;
$newlog->statusid = $setunmarked;
$donesomething = true;
} else if (!empty($userfirstaccess[$user->id])) {
$newlog->statusid = $att->get_automark_status($userfirstaccess[$user->id], $session->id);
}
if (!empty($newlog->statusid)) {
$newlog->studentid = $user->id;
$DB->insert_record('attendance_log', $newlog);
$added++;
$donesomething = true;
}
}
}
}
mtrace($added . " session status inserted");
mtrace($added . " session status inserted");
// Update lasttaken time and automarkcompleted for this session.
// Update lasttaken time and automarkcompleted for this session.
$session->lasttaken = $newlog->timetaken;
$session->lasttaken = $now ;
$session->lasttakenby = 0;
$session->lasttakenby = 0;
$session->automarkcompleted = 1;
if ($sessionover) {
$session->automarkcompleted = 2;
} else {
$session->automarkcompleted = 1;
}
$DB->update_record('attendance_sessions', $session);
$DB->update_record('attendance_sessions', $session);
if ($donesomething) {
if ($donesomething) {