File:  [LON-CAPA] / loncom / interface / lontrackstudent.pm
Revision 1.41: download - view: text, annotated - select for diffs
Thu Nov 21 07:26:03 2024 UTC (3 months ago) by raeburn
Branches: MAIN
CVS tags: version_2_12_X, version_2_11_6_msu, HEAD
- Where session launch was via LTI-mediated deep-linking from another CMS
  and launch payload included URL and uniqueID for return of score:
  (a) successful score transfer
     - logged in course's activity log (action = EXPORT)
     - passback information stored in student's $cdom_$cnum_lp_passback.db
  (b) unsuccessful score transfer
     - logged in student's activity log and lonnet.log
     - passback information stored in course's linkprot_passback_pending.db

    1: # The LearningOnline Network with CAPA
    2: #
    3: # $Id: lontrackstudent.pm,v 1.41 2024/11/21 07:26:03 raeburn Exp $
    4: #
    5: # Copyright Michigan State University Board of Trustees
    6: #
    7: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
    8: #
    9: # LON-CAPA is free software; you can redistribute it and/or modify
   10: # it under the terms of the GNU General Public License as published by
   11: # the Free Software Foundation; either version 2 of the License, or
   12: # (at your option) any later version.
   13: #
   14: # LON-CAPA is distributed in the hope that it will be useful,
   15: # but WITHOUT ANY WARRANTY; without even the implied warranty of
   16: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17: # GNU General Public License for more details.
   18: #
   19: # You should have received a copy of the GNU General Public License
   20: # along with LON-CAPA; if not, write to the Free Software
   21: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   22: #
   23: # /home/httpd/html/adm/gpl.txt
   24: #
   25: # http://www.lon-capa.org/
   26: #
   27: ###
   28: 
   29: =pod
   30: 
   31: =head1 NAME
   32: 
   33: lontrackstudent
   34: 
   35: =head1 SYNOPSIS
   36: 
   37: Track student progress through course materials
   38: 
   39: =over 4
   40: 
   41: =cut
   42: 
   43: package Apache::lontrackstudent;
   44: 
   45: use strict;
   46: use Apache::Constants qw(:common :http);
   47: use Apache::lonmysql;
   48: use Apache::lonnet;
   49: use Apache::loncommon;
   50: use Apache::lonlocal;
   51: use Time::HiRes;
   52: use DateTime();
   53: use lib '/home/httpd/lib/perl/';
   54: use LONCAPA;
   55: 
   56: my $num_records=500;
   57: 
   58: sub get_data {
   59:     my ($r,$prog_state,$navmap,$mode) = @_;
   60:     ##
   61:     ## Compose the query
   62:     &Apache::lonhtmlcommon::Update_PrgWin
   63:         ($r,$prog_state,&mt('Composing Query'));
   64:     #
   65:     # Allow the other server to begin processing the data before we ask for it.
   66:     sleep(5);
   67:     #
   68:     my $max_time = &get_max_time_in_db($r,$prog_state);
   69:     if (defined($max_time)) {
   70:         $r->print('<h3>'.&mt('Activity data compiled up to [_1]',
   71:                              &Apache::lonlocal::locallocaltime($max_time)).
   72:                   '</h3>'.&mt('While data is processed, periodically reload this page for more recent activity').'<br />');
   73:         $r->rflush();
   74:     } else {
   75:         $r->print('<h3>'.&mt('Unable to retrieve any data.  Please reload this page and try again.').'</h3>');
   76:         return;
   77:     }
   78:     my $query = &build_query($mode);
   79:     ##
   80:     ## Send it along
   81:     my $home = $env{'course.'.$env{'request.course.id'}.'.home'};
   82:     my $reply=&Apache::lonnet::metadata_query($query,undef,undef,[$home]);
   83:     if (ref($reply) ne 'HASH') {
   84:         $r->print('<h2>'.
   85:                   &mt('Error contacting home server for course: [_1]',
   86:                       $reply).
   87:                   '</h2>');
   88:         return;
   89:     }
   90:     my $results_file = $r->dir_config('lonDaemons').'/tmp/'.$reply->{$home};
   91:     my $endfile = $results_file.'.end';
   92:     ##
   93:     ## Check for the results
   94:     &Apache::lonhtmlcommon::Update_PrgWin
   95:         ($r,$prog_state,&mt('Waiting for results'));
   96:     my $maxtime = 500;
   97:     my $starttime = time;
   98:     while (! -e $endfile && (time-$starttime < $maxtime)) {
   99:         &Apache::lonhtmlcommon::Update_PrgWin
  100:             ($r,$prog_state,&mt('Waiting up to [_1] seconds for results',
  101:                                 $starttime+$maxtime-time));
  102:         sleep(1);
  103:     }
  104:     if (! -e $endfile) {
  105:         $r->print('<h2>'.
  106:                   &mt('Unable to retrieve data.').'</h2>');
  107:         $r->print(&mt('Please try again in a few minutes.'));
  108:         return;
  109:     }
  110:     $r->rflush();
  111:     #
  112:     &Apache::lonhtmlcommon::Update_PrgWin
  113:         ($r,$prog_state,&mt('Parsing results'));
  114:     #
  115:     my $last = &output_results($r,$results_file,$navmap,$mode);
  116:     my ($sname,$sdom) = ($mode=~/^student:(.*):(.*)$/);
  117:     
  118:     my ($text,$inc);
  119:     if ( $last > 0 && (($last+1) >= $env{'form.start'}+$num_records) ) {
  120: 	$text = 'View more activity by this student';
  121: 	$inc  = $num_records;
  122: 	$r->print(&Apache::loncommon::track_student_link($text,$sname,$sdom,undef,
  123: 							 ($env{'form.start'}+$inc),
  124:                                                          $env{'form.only_body'}
  125: 							 ));
  126: 	$r->print('<br />');
  127:     }
  128:     $r->print('<hr />');
  129:     $text = 'Resubmit last request to check for newer data';
  130:     $r->print(&Apache::loncommon::track_student_link($text,$sname,$sdom,undef,
  131: 						     $env{'form.start'},
  132:                                                      $env{'form.only_body'}));
  133: 
  134:     &Apache::lonhtmlcommon::Update_PrgWin($r,$prog_state,&mt('Finished!'));
  135:     return;
  136: }
  137: 
  138: sub table_names {
  139:     my $cid = $env{'request.course.id'};
  140:     my $domain = $env{'course.'.$cid.'.domain'};
  141:     my $home = $env{'course.'.$cid.'.home'};
  142:     my $course = $env{'course.'.$cid.'.num'};
  143:     my $prefix = $course.'_'.$domain.'_';
  144:     #
  145:     my %tables = 
  146:         ( student =>&Apache::lonmysql::fix_table_name($prefix.'students'),
  147:           res     =>&Apache::lonmysql::fix_table_name($prefix.'resource'),
  148:           machine =>&Apache::lonmysql::fix_table_name($prefix.'machine_table'),
  149:           activity=>&Apache::lonmysql::fix_table_name($prefix.'activity'),
  150:           );
  151:     return %tables;
  152: }
  153: 
  154: sub get_max_time_in_db {
  155:     my ($r,$prog_state) = @_;
  156:     my %table = &table_names();
  157:     my $query = qq{SELECT MAX(time) FROM $table{'activity'} };
  158:     #
  159:     my $home = $env{'course.'.$env{'request.course.id'}.'.home'};
  160:     my $reply=&Apache::lonnet::metadata_query($query,undef,undef,[$home]);
  161:     if (ref($reply) ne 'HASH') {
  162:         return undef;
  163:     }
  164:     my $results_file = $r->dir_config('lonDaemons').'/tmp/'.$reply->{$home};
  165:     my $endfile = $results_file.'.end';
  166:     ##
  167:     ## Check for the results
  168:     &Apache::lonhtmlcommon::Update_PrgWin
  169:         ($r,$prog_state,&mt('Waiting for results'));
  170:     my $maxtime = 500;
  171:     my $starttime = time;
  172:     while (! -e $endfile && (time-$starttime < $maxtime)) {
  173:         &Apache::lonhtmlcommon::Update_PrgWin
  174:             ($r,$prog_state,&mt('Waiting up to [_1] seconds for results',
  175:                                 $starttime+$maxtime-time));
  176:         sleep(1);
  177:     }
  178:     if (! -e $endfile) {
  179:         $r->print('<h2>'.
  180:                   &mt('Unable to retrieve data.').'</h2>');
  181:         $r->print(&mt('Please try again in a few minutes.'));
  182:         return undef;
  183:     }
  184:     $r->rflush();
  185:     #
  186:     &Apache::lonhtmlcommon::Update_PrgWin
  187:         ($r,$prog_state,&mt('Parsing results'));
  188:     #
  189:     if (! open(TIMEDATA,"<",$results_file)) {
  190:         $r->print('<p class="LC_error">'.&mt('Unable to read results file.').'</p>'.
  191:                   '<p>'.
  192:                   &mt('This is a serious error and has been logged.').
  193:                   '<br />'.
  194:                   &mt('Please alert your LON-CAPA administrator.').
  195:                   '</p>');
  196:         return;
  197:     }
  198:     #
  199:     my $timestr = '';
  200:     while (my $line = <TIMEDATA>) {
  201:         chomp($line);
  202:         $timestr = &unescape($line);
  203:     }
  204:     close(TIMEDATA);
  205:     return &Apache::lonmysql::unsqltime($timestr);
  206: }
  207: 
  208: sub build_query {
  209:     my ($mode) = @_;
  210:     my $cid = $env{'request.course.id'};
  211:     my $domain = $env{'course.'.$cid.'.domain'};
  212:     my $home = $env{'course.'.$cid.'.home'};
  213:     my $course = $env{'course.'.$cid.'.num'};
  214:     my $prefix = $course.'_'.$domain.'_';
  215:     my $start = ($env{'form.start'}+0);
  216:     #
  217:     my %table = &table_names();
  218:     #
  219:     my $query;
  220:     if ($mode eq 'full_class') {
  221:         $query = qq{
  222:         SELECT B.resource,A.time,C.student,A.action,E.machine,A.action_values 
  223:             FROM $table{'activity'} AS A
  224:             LEFT JOIN $table{'res'}      AS B ON B.res_id=A.res_id 
  225:             LEFT JOIN $table{'student'}  AS C ON C.student_id=A.student_id 
  226:             LEFT JOIN $table{'machine'}  AS E ON E.machine_id=A.machine_id
  227:             ORDER BY A.time DESC
  228:             LIMIT $start, $num_records
  229:         };
  230:     } elsif ($mode =~ /^student:(.*):(.*)$/) {
  231:         my $student = $1.':'.$2;
  232:         $query = qq{
  233:             SELECT B.resource,A.time,A.action,E.machine,A.action_values 
  234:                 FROM $table{'activity'} AS A
  235:                 LEFT JOIN $table{'res'}      AS B ON B.res_id=A.res_id 
  236:                 LEFT JOIN $table{'student'}  AS C ON C.student_id=A.student_id 
  237:                 LEFT JOIN $table{'machine'}  AS E ON E.machine_id=A.machine_id
  238:                 WHERE C.student='$student'
  239:                 ORDER BY A.time DESC
  240:                 LIMIT $start, $num_records
  241:             };
  242:     }
  243:     $query =~ s|$/||g;
  244:     return $query;
  245: }
  246: 
  247: ###################################################################
  248: ###################################################################
  249: sub output_results {
  250:     my ($r,$results_file,$navmap,$mode) = @_;
  251:     ##
  252:     ##
  253:     if (! -s $results_file) {
  254:         # results file is empty, just let them know there is no data
  255:         $r->print('<p class="LC_info">'.&mt('So far, no data has been returned for your request').'</p>');
  256:         return -1;
  257:     }
  258:     if (! open(ACTIVITYDATA,"<",$results_file)) {
  259:         $r->print('<p class="LC_error">'.&mt('Unable to read results file.').'</p>'.
  260:                   '<p>'.
  261:                   &mt('This is a serious error and has been logged.').
  262:                   '<br />'.
  263:                   &mt('Please alert your LON-CAPA administrator.').
  264:                   '</p>');
  265:         return -2;
  266:     }
  267:     ##
  268:     ##
  269:     my $tableheader;
  270:     if ($mode eq 'full_class') { 
  271:         $tableheader = 
  272:             '<table><tr>'.
  273:             '<th>&nbsp;</th>'.
  274:             '<th>'.&mt('Resource').'</th>'.
  275:             '<th>'.&mt('Time').'</th>'.
  276:             '<th>'.&mt('Student').'</th>'.
  277:             '<th>'.&mt('Action').'</th>'.
  278:  #           '<th>'.&mt('Originating Server').'</th>'.
  279:             '<th align="left">'.&mt('Data').'</th>'.
  280:             '</tr>'.$/;
  281:     } elsif ($mode =~ /^student:(.*):(.*)$/) {
  282:         $tableheader = 
  283:             '<table><tr>'.
  284:             '<th>&nbsp;</th>'.
  285:             '<th>'.&mt('Resource').'</th>'.
  286:             '<th>'.&mt('Time').'</th>'.
  287:             '<th>'.&mt('Action').'</th>'.
  288:  #           '<th>'.&mt('Originating Server').'</th>'.
  289:             '<th align="left">'.&mt('Data').'</th>'.
  290:             '</tr>'.$/;
  291:     }
  292:     my $count = $env{'form.start'}-1;
  293:     $r->rflush();
  294:     ##
  295:     ##
  296: 
  297:     my $cid = $env{'request.course.id'};
  298:     my $cnum = $env{'course.'.$cid.'.num'};
  299:     my $cdom = $env{'course.'.$cid.'.domain'};   
  300:     my $server_timezone = &Apache::lonnet::get_server_timezone($cnum,$cdom);
  301:     if ($server_timezone ne '') {
  302:         if (&Apache::lonlocal::gettimezone($server_timezone) eq 'local') {
  303:             $server_timezone = '';
  304:         }
  305:     }
  306: 
  307:     while (my $line = <ACTIVITYDATA>) {
  308:         # FIXME: does not pass symbs along :(
  309:         chomp($line);
  310:         $line = &unescape($line);
  311:         if (++$count % 50 == 0) {
  312:             if ($count != 0) { 
  313:                 $r->print('</table>'.$/);
  314:                 $r->rflush();
  315:             }
  316:             $r->print($tableheader);
  317:         }
  318:         my ($symb,$timestamp,$student,$action,$machine,$values);
  319:         if ($mode eq 'full_class') {
  320:             ($symb,$timestamp,$student,$action,$machine,$values) = split(',',$line,6);
  321:         } else {
  322:             ($symb,$timestamp,$action,$machine,$values) = split(',',$line,5);
  323:         }
  324: 	foreach ($symb,$timestamp,$student,$action,$machine) {
  325: 	    $_=&unescape($_);
  326: 	}
  327:         my ($title,$src);
  328:         if ($symb =~ m{^\Q/tiny/$cdom/\E\w+$}) {
  329:             $symb = &Apache::loncommon::symb_from_tinyurl($symb,$cnum,$cdom);
  330:         }
  331:         if ($symb =~ m:^/adm/:) {
  332:             $title = $symb;
  333:             $src = $symb;
  334:         } else {
  335:             my $nav_res = $navmap->getBySymb($symb);
  336:             if (defined($nav_res)) {
  337:                 $title = $nav_res->compTitle();
  338:                 $src   = $nav_res->src();
  339:             } else {
  340: 		$src = $symb;
  341: 		if ($src !~ m{/adm}) {
  342: 		    $title = &Apache::lonnet::gettitle($src);
  343: 		} elsif ($values =~ /^\s*$/ && 
  344: 		    (! defined($src) || $src =~ /^\s*$/)) {
  345:                     next;
  346:                 } elsif ($values =~ /^\s*$/) {
  347:                     $values = $src;
  348:                 } else {
  349:                     $title = 'unable to retrieve title';
  350:                     $src   = '/dev/null';
  351:                 }
  352:             }
  353:             if ($src =~ /.sequence$/) {
  354:                 $src .= '?navmap=1';
  355:             }
  356:         }
  357:         my %classes;
  358:         my $class_count=0;
  359:         if (! exists($classes{$symb})) {
  360:             $classes{$symb} = $class_count++;
  361:         }
  362:         my $class = 'a';#.$classes{$symb};
  363:         #
  364:         if ($symb eq '/prtspool/') {
  365:             $class = 'print';
  366:             $title = 'retrieve printout';
  367:         } elsif ($symb =~ m|^/adm/([^/]+)|) {
  368:             $class = $1;
  369:         } elsif ($symb =~ m|^/adm/|) {
  370:             $class = 'adm';
  371:         }
  372:         if ($title eq 'unable to retrieve title') {
  373:             $title =~ s/ /\&nbsp;/g;
  374:             $class = 'warning';
  375:         }
  376:         if (! defined($title) || $title eq '') {
  377:             $title = 'untitled';
  378:             $class = 'warning';
  379:         }
  380:         # Clean up the values
  381: 	$values = &display_values($action,$values);
  382:         #
  383:         # Build the row for output
  384:         my $tablerow = qq{<tr class="$class"><td>}.($count+1).qq{</td>};
  385:         if ($src =~ m|^/adm/|) {
  386:             $tablerow .= 
  387:                 '<td valign="top"><span class="LC_nobreak">'.$title.'</span></td>';
  388:         } else {
  389:             $tablerow .= 
  390:                 '<td valign="top"><span class="LC_nobreak">'.
  391:                 '<a href="'.$src.'">'.$title.'</a>'.
  392:                 '</span></td>';
  393:         }
  394:         if ($server_timezone ne '') {
  395:             $timestamp = &convert_timezone($server_timezone,$timestamp);
  396:         }
  397:         $tablerow .= '<td valign="top"><span class="LC_nobreak">'.$timestamp.'</span></td>';
  398:         if ($mode eq 'full_class') {
  399:             $tablerow.='<td valign="top">'.$student.'</td>';
  400:         }
  401:         $tablerow .= 
  402:             '<td valign="top">'.$action.'</td>'.
  403: #            '<td>'.$machine.'</td>'.
  404:             '<td valign="top">'.$values.'</td>'.
  405:             '</tr>';
  406:         $r->print($tablerow.$/);
  407:     }
  408:     $r->print('</table>'.$/);### if (! $count % 50);
  409:     close(ACTIVITYDATA);
  410:     return $count;
  411: }
  412: 
  413: sub convert_timezone {
  414:     my ($server_timezone,$timestamp) = @_;
  415:     if ($server_timezone && $timestamp) {
  416:         my ($date,$time) = split(/\s+/,$timestamp);
  417:         my ($year,$month,$day) = split(/\-/,$date);
  418:         my ($hour,$minute,$sec) = split(/:/,$time);
  419:         foreach ($month,$day,$hour,$minute,$sec) {
  420:             return $timestamp if $_ eq '';
  421:             $_ =~ s/^0//;
  422:         }
  423:         my $dt = DateTime->new(year      => $year,
  424:                                month     => $month,
  425:                                day       => $day,
  426:                                hour      => $hour,
  427:                                minute    => $minute,
  428:                                second    => $sec,
  429:                                time_zone => $server_timezone,
  430:                               );
  431:         my $unixtime = $dt->epoch;
  432:         $timestamp = &Apache::lonlocal::locallocaltime($unixtime);
  433:     }
  434:     return $timestamp;
  435: }
  436: 
  437: ###################################################################
  438: ###################################################################
  439: sub display_values {
  440:     my ($action,$values)=@_;
  441:     my $result='<table>';
  442:     if (($action eq 'CSTORE') || ($action eq 'PUTSTORE') || ($action eq 'EXPORT')) {
  443:         my $is_anon;
  444: 	my %values=map {split('=',$_,-1)} split(/\&/,$values);
  445: 	foreach my $key (sort(keys(%values))) {
  446:             my $unesc_key = &unescape($key);
  447:             if ($values{$key} eq 'anonsurvey' || $values{$key} eq 'anonsurveycred') {
  448:                 if ($unesc_key =~ /^resource\..+\.type$/) {
  449:                     $is_anon = 1;
  450:                     last;
  451:                 }
  452:             }
  453: 	    $result.='<tr><td align="right">'.
  454: 		$unesc_key.
  455: 		'</td><td>=</td><td align="left">'.
  456: 		&unescape($values{$key}).'</td></tr>';
  457: 	}
  458: 	$result.='</table>';
  459:         if ($is_anon) {
  460:             $result = '<span class="LC_warning">'.&mt('Anonymous Survey Submission: details not shown').'</span>';
  461:         }
  462:     } elsif ($action eq 'POST') {
  463: 	my %values;
  464:         foreach my $pair (split(/\&/,$values)) {
  465:             my ($key,$value) = split('=',&unescape($pair),-1);
  466:             $values{$key} = $value;
  467:         }
  468: 	foreach my $key (sort(keys(%values))) {
  469: 	    if ($key eq 'counter') { next; }
  470: 	    $result.='<tr><td align="right">'.$key.'</td>'.
  471: 		'<td>=</td><td align="left">'.$values{$key}.'</td></tr>';
  472: 	}
  473: 	$result.='</table>';
  474:     } else {
  475: 	$result=&unescape($values)
  476:     }
  477:     return $result;
  478: }
  479: ###################################################################
  480: ###################################################################
  481: sub request_data_update {
  482:     my $command = 'prepare activity log';
  483:     my $cid = $env{'request.course.id'};
  484:     my $domain = $env{'course.'.$cid.'.domain'};
  485:     my $home = $env{'course.'.$cid.'.home'};
  486:     my $course = $env{'course.'.$cid.'.num'};
  487: #    &Apache::lonnet::logthis($command.' '.$course.' '.$domain.' '.$home);
  488:     my $result = &Apache::lonnet::metadata_query($command,$course,$domain,
  489:                                                  [$home]);
  490:     return $result;
  491: }
  492: 
  493: ###################################################################
  494: ###################################################################
  495: sub pick_student {
  496:     my ($r) = @_;
  497:     $r->print("Sorry, cannot display classlist at this time.  Come back another time.");
  498:     return;
  499: }
  500: 
  501: ###################################################################
  502: ###################################################################
  503: sub styles {
  504:     return <<END;
  505: <style type="text/css">
  506:     tr.warning   { background-color: \#CCCCCC; }
  507:     tr.chat      { background-color: \#CCCCCC; }
  508:     tr.chatfetch { background-color: \#CCCCCC; }
  509:     tr.navmaps   { background-color: \#CCCCCC; }
  510:     tr.roles     { background-color: \#CCCCCC; }
  511:     tr.flip      { background-color: \#CCCCCC; }
  512:     tr.adm       { background-color: \#CCCCCC; }
  513:     tr.print     { background-color: \#CCCCCC; }
  514:     tr.printout  { background-color: \#CCCCCC; }
  515:     tr.parmset   { background-color: \#CCCCCC; }
  516:     tr.grades    { background-color: \#CCCCCC; }
  517: </style>
  518: END
  519: } 
  520: 
  521: sub developer_centric_styles {
  522:     return <<END;
  523: <style type="text/css">
  524:     tr.warning   { background-color: red; }
  525:     tr.chat      { background-color: yellow; }
  526:     tr.chatfetch { background-color: yellow; }
  527:     tr.evaluate  { background-color: red; }
  528:     tr.navmaps   { background-color: \#777777; }
  529:     tr.roles     { background-color: \#999999; }
  530:     tr.flip      { background-color: \#BBBBBB; }
  531:     tr.adm       { background-color: green; }
  532:     tr.print     { background-color: blue; }
  533:     tr.parmset   { background-color: \#000088; }
  534:     tr.printout  { background-color: blue; }
  535:     tr.grades    { background-color: \#CCCCCC; }
  536: </style>
  537: END
  538: }
  539: 
  540: ###################################################################
  541: ###################################################################
  542: sub handler {
  543:     my $r=shift;
  544:     my $c = $r->connection();
  545:     #
  546:     # Check for access
  547:     if (! &Apache::lonnet::allowed('vsa',$env{'request.course.id'})) {
  548:         $env{'user.error.msg'}=
  549:             $r->uri.":vsa:0:0:Cannot student activity for complete course";
  550:         if (! 
  551:             &Apache::lonnet::allowed('vsa',
  552:                                      $env{'request.course.id'}.'/'.
  553:                                      $env{'request.course.sec'})) {
  554:             $env{'user.error.msg'}=
  555:                 $r->uri.":vsa:0:0:Cannot view student activity with given role";
  556:             return HTTP_NOT_ACCEPTABLE;
  557:         }
  558:     }
  559:     #
  560:     # Send the header
  561:     &Apache::loncommon::no_cache($r);
  562:     &Apache::loncommon::content_type($r,'text/html');
  563:     $r->send_http_header;
  564:     if ($r->header_only) { return OK; }
  565:     #
  566:     # Extract form elements from query string
  567:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
  568:                       ['selected_student','start','only_body']);
  569:     #
  570:     # We will almost always need this...
  571:     my $navmap = Apache::lonnavmaps::navmap->new();
  572:     if (!defined($navmap)) {
  573:         my $requrl = $r->uri;
  574:         $env{'user.error.msg'} = "$requrl:bre:0:0:Navmap initialization failed.";
  575:         return HTTP_NOT_ACCEPTABLE;
  576:     }
  577:     # 
  578:     &Apache::lonhtmlcommon::clear_breadcrumbs();
  579:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/studentactivity',
  580:                                             title=>'Student Activity',
  581:                                             text =>'Student Activity',
  582:                                             faq=>139,
  583:                                             bug=>'instructor interface',
  584:                                             help=>'View_recent_activity'});
  585:     #
  586:     # Give the LON-CAPA page header
  587:     my $args;
  588:     if ($env{'form.only_body'}) {
  589:         $args = { only_body => 1, };
  590:         $args->{'add_progressbar'} = 1;
  591:     }
  592:     $r->print(&Apache::loncommon::start_page('Student Activity',&styles(),$args).
  593:               &Apache::lonhtmlcommon::breadcrumbs('Student Activity'));
  594:     $r->rflush();
  595:     #
  596:     # Begin form output
  597:     $r->print('<form name="trackstudent" method="post" action="/adm/trackstudent">');
  598:     $r->rflush();
  599:     my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r);
  600:     &Apache::lonhtmlcommon::Update_PrgWin
  601:         ($r,\%prog_state,&mt('Contacting course home server'));
  602:     #
  603:     my $result = &request_data_update();
  604:     #
  605:     if (exists($env{'form.selected_student'})) {
  606:         # For now, just show all the data, in the future allow selection of
  607:         # a student
  608:         my ($sname,$sdom) = split(':',$env{'form.selected_student'});
  609:         if ($sname =~ /^$LONCAPA::username_re$/ 
  610: 	    && $sdom =~ /^$LONCAPA::domain_re$/) {
  611:             $r->print('<h2>'.
  612:                       &mt('Recent activity of [_1]',$sname.':'.$sdom).
  613:                       '</h2>');
  614:             $r->print('<p class="LC_info">'
  615:                      .&mt('Compiling student activity data can take a long time.'
  616:                          .' Your request continues to be processed while results are displayed.')
  617:                      .'</p>'
  618:             );
  619:             &get_data($r,\%prog_state,$navmap,
  620:                       'student:'.$env{'form.selected_student'});
  621:         } else {
  622:             $r->print(
  623:                 '<p class="LC_error">'
  624:                .&mt('Unable to process for [_1]:[_2]',$sname,$sdom)
  625:                .'</p>'
  626:             );
  627:         }
  628:     } else {
  629:         # For now, just show all the data instead of limiting it to one student
  630:         &get_data($r,\%prog_state,$navmap,'full_class');
  631:     }
  632:     #
  633:     &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Done'));
  634:     &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
  635:     #
  636:     $r->print("</form>\n");
  637:     $r->print(&Apache::loncommon::end_page());
  638:     $r->rflush();
  639:     #
  640:     return OK;
  641: }
  642: 
  643: 1;
  644: 
  645: #######################################################
  646: #######################################################
  647: 
  648: =pod
  649: 
  650: =back
  651: 
  652: =cut
  653: 
  654: #######################################################
  655: #######################################################
  656: 
  657: __END__
  658: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>