Moodle

Complete activity user report shows incorrect first access time

Details

  • Type: Bug Bug
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Duplicate
  • Affects Version/s: 1.9.3
  • Fix Version/s: None
  • Component/s: SCORM
  • Labels:
    None
  • Affected Branches:
    MOODLE_19_STABLE

Description

the complete activity report shows the last access time in the place the first time access should be.
(e.g. course/user.php?id=3&user=2&mode=complete )

I've resiolved it on my own this way:

in the function below I've added the lines commented as josef:

mod/scorm/locallib.php

function scorm_get_tracks($scoid,$userid,$attempt='') {
/// Gets all tracks of specified sco and user
global $CFG;

if (empty($attempt)) {
if ($scormid = get_field('scorm_scoes','scorm','id',$scoid)) { $attempt = scorm_get_last_attempt($scormid,$userid); } else { $attempt = 1; }
}
$attemptsql = ' AND attempt=' . $attempt;
if ($tracks = get_records_select('scorm_scoes_track',"userid=$userid AND scoid=$scoid".$attemptsql,'element ASC')) {
$usertrack->userid = $userid;
$usertrack->scoid = $scoid;
// Defined in order to unify scorm1.2 and scorm2004
$usertrack->score_raw = '';
$usertrack->status = '';
$usertrack->total_time = '00:00:00';
$usertrack->session_time = '00:00:00';
$usertrack->timemodified = 0;
$usertrack->firsttimemodified = time(); // josef
foreach ($tracks as $track) {
$element = $track->element;
$usertrack->{$element} = $track->value;
switch ($element) {
case 'cmi.core.lesson_status':
case 'cmi.completion_status':
if ($track->value == 'not attempted') { $track->value = 'notattempted'; }
$usertrack->status = $track->value;
break;
case 'cmi.core.score.raw':
case 'cmi.score.raw':
$usertrack->score_raw = $track->value;
break;
case 'cmi.core.session_time':
case 'cmi.session_time':
$usertrack->session_time = $track->value;
break;
case 'cmi.core.total_time':
case 'cmi.total_time':
$usertrack->total_time = $track->value;
break;
}
if (isset($track->timemodified) && ($track->timemodified > $usertrack->timemodified)) { $usertrack->timemodified = $track->timemodified; }
if (isset($track->timemodified) && ($track->timemodified < $usertrack->firsttimemodified)) { // josef $usertrack->firsttimemodified = $track->timemodified; // josef } // josef
}
if (is_array($usertrack)) { ksort($usertrack); }
return $usertrack;
} else { return false; }
}

mod/scorm/lib.php

function scorm_user_complete($course, $user, $mod, $scorm) {
global $CFG;

$liststyle = 'structlist';
$scormpixdir = $CFG->modpixpath.'/scorm/pix';
$now = time();
$firstmodify = $now;
$lastmodify = 0;
$sometoreport = false;
$report = '';

if ($orgs = get_records_select('scorm_scoes',"scorm='$scorm->id' AND organization='' AND launch=''",'id','id,identifier,title')) {
if (count($orgs) <= 1) { unset($orgs); $orgs[]->identifier = ''; }
$report .= '<div class="mod-scorm">'."\n";
foreach ($orgs as $org) {
$organizationsql = '';
$currentorg = '';
if (!empty($org->identifier)) { $report .= '<div class="orgtitle">'.$org->title.'</div>'; $currentorg = $org->identifier; $organizationsql = "AND organization='$currentorg'"; }
$report .= "<ul id='0' class='$liststyle'>";
if ($scoes = get_records_select('scorm_scoes',"scorm='$scorm->id' $organizationsql order by id ASC")){
// drop keys so that we can access array sequentially
$scoes = array_values($scoes);
$level=0;
$sublist=1;
$parents[$level]='/';
foreach ($scoes as $pos=>$sco) {
if ($parents[$level]!=$sco->parent) {
if ($level>0 && $parents[$level-1]==$sco->parent) { $report .= "\t\t</ul></li>\n"; $level--; } else {
$i = $level;
$closelist = '';
while (($i > 0) && ($parents[$level] != $sco->parent)) { $closelist .= "\t\t</ul></li>\n"; $i--; }
if (($i == 0) && ($sco->parent != $currentorg)) { $report .= "\t\t<li><ul id='$sublist' class='$liststyle'>\n"; $level++; } else { $report .= $closelist; $level = $i; }
$parents[$level]=$sco->parent;
}
}
$report .= "\t\t<li>";
if (isset($scoes[$pos+1])) { $nextsco = $scoes[$pos+1]; } else { $nextsco = false; }
if (($nextsco !== false) && ($sco->parent != $nextsco->parent) && (($level==0) || (($level>0) && ($nextsco->parent == $sco->identifier)))) { $sublist++; } else { $report .= '<img src="'.$scormpixdir.'/spacer.gif" alt="" />'; }

if ($sco->launch) {
require_once('locallib.php');
$score = '';
$totaltime = '';
if ($usertrack=scorm_get_tracks($sco->id,$user->id)) {
if ($usertrack->status == '') { $usertrack->status = 'notattempted'; }
$strstatus = get_string($usertrack->status,'scorm');
$report .= "<img src='".$scormpixdir.'/'.$usertrack->status.".gif' alt='$strstatus' title='$strstatus' />";
if ($usertrack->timemodified != 0) {
if ($usertrack->timemodified > $lastmodify) { $lastmodify = $usertrack->timemodified; }
if ($usertrack->firsttimemodified < $firstmodify) { // josef $firstmodify = $usertrack->firsttimemodified; // josef }
}
} else {
if ($sco->scormtype == 'sco') { $report .= '<img src="'.$scormpixdir.'/'.'notattempted.gif" alt="'.get_string('notattempted','scorm').'" title="'.get_string('notattempted','scorm').'" />'; } else { $report .= '<img src="'.$scormpixdir.'/'.'asset.gif" alt="'.get_string('asset','scorm').'" title="'.get_string('asset','scorm').'" />'; }
}
$report .= " $sco->title $score$totaltime</li>\n";
if ($usertrack !== false) {
$sometoreport = true;
$report .= "\t\t\t<li><ul class='$liststyle'>\n";
foreach($usertrack as $element => $value) {
if (substr($element,0,3) == 'cmi') { $report .= '<li>'.$element.' => '.$value.'</li>'; }
}
$report .= "\t\t\t</ul></li>\n";
}
} else { $report .= " $sco->title</li>\n"; }
}
for ($i=0;$i<$level;$i++) { $report .= "\t\t</ul></li>\n"; }
}
$report .= "\t</ul><br />\n";
}
$report .= "</div>\n";
}
if ($sometoreport) {
if ($firstmodify < $now) { $timeago = format_time($now - $firstmodify); echo get_string('firstaccess','scorm').': '.userdate($firstmodify).' ('.$timeago.")<br />\n"; }
if ($lastmodify > 0) { $timeago = format_time($now - $lastmodify); echo get_string('lastaccess','scorm').': '.userdate($lastmodify).' ('.$timeago.")<br />\n"; }
echo get_string('report','scorm').":<br />\n";
echo $report;
} else { print_string('noactivity','scorm'); }

return true;
}

Issue Links

Activity

Hide
Dan Marsden added a comment -

this looks to be a duplicate of MDL-16184, but thanks for the report and the code! - in future, it's much easier for us developers if code patches are provided instead of full text in the bug like you've done here - feel free to add yourself as a watcher to MDL-16184 to see when we resolve this.

see here for details on how to create a patch:
http://docs.moodle.org/en/Development:How_to_create_a_patch

thanks!

Show
Dan Marsden added a comment - this looks to be a duplicate of MDL-16184, but thanks for the report and the code! - in future, it's much easier for us developers if code patches are provided instead of full text in the bug like you've done here - feel free to add yourself as a watcher to MDL-16184 to see when we resolve this. see here for details on how to create a patch: http://docs.moodle.org/en/Development:How_to_create_a_patch thanks!
Hide
Jose G. C. added a comment -

I think it's not a duplicate although it's related.

The issue I'm reporting is about how track data is extracted to compose the report.

The actual Moodle code collects last access time ("timemodified" in database) for each SCO. So, in the complete activity report, for a multi-SCO SCORM package the first access time showed corresponds to the last access time (really the last track modifying time) in the first SCO. In a 1-SCO SCORM package this is more manifest.

The problem reported in MDL-16184 is about keeping in the database the real first access time, not the modifying time.

Show
Jose G. C. added a comment - I think it's not a duplicate although it's related. The issue I'm reporting is about how track data is extracted to compose the report. The actual Moodle code collects last access time ("timemodified" in database) for each SCO. So, in the complete activity report, for a multi-SCO SCORM package the first access time showed corresponds to the last access time (really the last track modifying time) in the first SCO. In a 1-SCO SCORM package this is more manifest. The problem reported in MDL-16184 is about keeping in the database the real first access time, not the modifying time.
Hide
Dan Marsden added a comment -

Hi Jose,

my feeling is that both should be resolved using the same method, the problem reported in MDL-16184 mentions an issue with the first access time, but fundamentally it's a problem with how the track data dates are stored and calculated, which is what the bug you have reported is about also. This does need to be resolved - how we go about this is easier to manage with 1 bug report than 2.

thanks.

Show
Dan Marsden added a comment - Hi Jose, my feeling is that both should be resolved using the same method, the problem reported in MDL-16184 mentions an issue with the first access time, but fundamentally it's a problem with how the track data dates are stored and calculated, which is what the bug you have reported is about also. This does need to be resolved - how we go about this is easier to manage with 1 bug report than 2. thanks.

People

Vote (0)
Watch (1)

Dates

  • Created:
    Updated:
    Resolved: