Annotation of loncom/interface/lontrackstudent.pm, revision 1.41

1.1       matthew     1: # The LearningOnline Network with CAPA
                      2: #
1.41    ! raeburn     3: # $Id: lontrackstudent.pm,v 1.40 2017/11/12 23:06:51 raeburn Exp $
1.1       matthew     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);
1.13      matthew    47: use Apache::lonmysql;
1.15      albertel   48: use Apache::lonnet;
1.41    ! raeburn    49: use Apache::loncommon;
1.1       matthew    50: use Apache::lonlocal;
                     51: use Time::HiRes;
1.26      raeburn    52: use DateTime();
1.20      www        53: use lib '/home/httpd/lib/perl/';
                     54: use LONCAPA;
1.1       matthew    55: 
1.16      albertel   56: my $num_records=500;
                     57: 
1.5       matthew    58: sub get_data {
                     59:     my ($r,$prog_state,$navmap,$mode) = @_;
1.2       matthew    60:     ##
                     61:     ## Compose the query
                     62:     &Apache::lonhtmlcommon::Update_PrgWin
                     63:         ($r,$prog_state,&mt('Composing Query'));
                     64:     #
1.9       matthew    65:     # Allow the other server to begin processing the data before we ask for it.
                     66:     sleep(5);
1.10      matthew    67:     #
                     68:     my $max_time = &get_max_time_in_db($r,$prog_state);
                     69:     if (defined($max_time)) {
1.17      www        70:         $r->print('<h3>'.&mt('Activity data compiled up to [_1]',
1.10      matthew    71:                              &Apache::lonlocal::locallocaltime($max_time)).
1.17      www        72:                   '</h3>'.&mt('While data is processed, periodically reload this page for more recent activity').'<br />');
1.10      matthew    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);
1.2       matthew    79:     ##
                     80:     ## Send it along
1.15      albertel   81:     my $home = $env{'course.'.$env{'request.course.id'}.'.home'};
1.2       matthew    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)) {
1.4       matthew    99:         &Apache::lonhtmlcommon::Update_PrgWin
                    100:             ($r,$prog_state,&mt('Waiting up to [_1] seconds for results',
                    101:                                 $starttime+$maxtime-time));
1.2       matthew   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:     }
1.5       matthew   110:     $r->rflush();
1.10      matthew   111:     #
1.2       matthew   112:     &Apache::lonhtmlcommon::Update_PrgWin
                    113:         ($r,$prog_state,&mt('Parsing results'));
1.10      matthew   114:     #
1.22      albertel  115:     my $last = &output_results($r,$results_file,$navmap,$mode);
1.16      albertel  116:     my ($sname,$sdom) = ($mode=~/^student:(.*):(.*)$/);
1.22      albertel  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,
1.30      raeburn   123: 							 ($env{'form.start'}+$inc),
                    124:                                                          $env{'form.only_body'}
1.22      albertel  125: 							 ));
                    126: 	$r->print('<br />');
                    127:     }
1.27      bisitz    128:     $r->print('<hr />');
1.22      albertel  129:     $text = 'Resubmit last request to check for newer data';
                    130:     $r->print(&Apache::loncommon::track_student_link($text,$sname,$sdom,undef,
1.30      raeburn   131: 						     $env{'form.start'},
                    132:                                                      $env{'form.only_body'}));
1.16      albertel  133: 
1.5       matthew   134:     &Apache::lonhtmlcommon::Update_PrgWin($r,$prog_state,&mt('Finished!'));
1.4       matthew   135:     return;
                    136: }
                    137: 
1.10      matthew   138: sub table_names {
1.15      albertel  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'};
1.10      matthew   143:     my $prefix = $course.'_'.$domain.'_';
                    144:     #
                    145:     my %tables = 
1.13      matthew   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'),
1.10      matthew   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:     #
1.15      albertel  159:     my $home = $env{'course.'.$env{'request.course.id'}.'.home'};
1.10      matthew   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:     #
1.40      raeburn   189:     if (! open(TIMEDATA,"<",$results_file)) {
1.36      bisitz    190:         $r->print('<p class="LC_error">'.&mt('Unable to read results file.').'</p>'.
1.10      matthew   191:                   '<p>'.
1.36      bisitz    192:                   &mt('This is a serious error and has been logged.').
                    193:                   '<br />'.
                    194:                   &mt('Please alert your LON-CAPA administrator.').
1.10      matthew   195:                   '</p>');
                    196:         return;
                    197:     }
                    198:     #
                    199:     my $timestr = '';
                    200:     while (my $line = <TIMEDATA>) {
                    201:         chomp($line);
1.20      www       202:         $timestr = &unescape($line);
1.10      matthew   203:     }
                    204:     close(TIMEDATA);
1.12      matthew   205:     return &Apache::lonmysql::unsqltime($timestr);
1.10      matthew   206: }
                    207: 
1.5       matthew   208: sub build_query {
                    209:     my ($mode) = @_;
1.15      albertel  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'};
1.5       matthew   214:     my $prefix = $course.'_'.$domain.'_';
1.16      albertel  215:     my $start = ($env{'form.start'}+0);
1.5       matthew   216:     #
1.10      matthew   217:     my %table = &table_names();
1.5       matthew   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 
1.10      matthew   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
1.5       matthew   227:             ORDER BY A.time DESC
1.16      albertel  228:             LIMIT $start, $num_records
1.5       matthew   229:         };
                    230:     } elsif ($mode =~ /^student:(.*):(.*)$/) {
                    231:         my $student = $1.':'.$2;
                    232:         $query = qq{
1.6       matthew   233:             SELECT B.resource,A.time,A.action,E.machine,A.action_values 
1.10      matthew   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
1.6       matthew   238:                 WHERE C.student='$student'
                    239:                 ORDER BY A.time DESC
1.16      albertel  240:                 LIMIT $start, $num_records
1.6       matthew   241:             };
1.5       matthew   242:     }
                    243:     $query =~ s|$/||g;
                    244:     return $query;
                    245: }
                    246: 
                    247: ###################################################################
                    248: ###################################################################
1.4       matthew   249: sub output_results {
1.5       matthew   250:     my ($r,$results_file,$navmap,$mode) = @_;
1.6       matthew   251:     ##
                    252:     ##
1.12      matthew   253:     if (! -s $results_file) {
                    254:         # results file is empty, just let them know there is no data
1.34      bisitz    255:         $r->print('<p class="LC_info">'.&mt('So far, no data has been returned for your request').'</p>');
1.22      albertel  256:         return -1;
1.12      matthew   257:     }
1.40      raeburn   258:     if (! open(ACTIVITYDATA,"<",$results_file)) {
1.34      bisitz    259:         $r->print('<p class="LC_error">'.&mt('Unable to read results file.').'</p>'.
1.4       matthew   260:                   '<p>'.
1.36      bisitz    261:                   &mt('This is a serious error and has been logged.').
                    262:                   '<br />'.
                    263:                   &mt('Please alert your LON-CAPA administrator.').
1.4       matthew   264:                   '</p>');
1.22      albertel  265:         return -2;
1.2       matthew   266:     }
1.6       matthew   267:     ##
                    268:     ##
1.5       matthew   269:     my $tableheader;
                    270:     if ($mode eq 'full_class') { 
                    271:         $tableheader = 
                    272:             '<table><tr>'.
1.26      raeburn   273:             '<th>&nbsp;</th>'.
1.5       matthew   274:             '<th>'.&mt('Resource').'</th>'.
                    275:             '<th>'.&mt('Time').'</th>'.
                    276:             '<th>'.&mt('Student').'</th>'.
                    277:             '<th>'.&mt('Action').'</th>'.
1.6       matthew   278:  #           '<th>'.&mt('Originating Server').'</th>'.
                    279:             '<th align="left">'.&mt('Data').'</th>'.
                    280:             '</tr>'.$/;
                    281:     } elsif ($mode =~ /^student:(.*):(.*)$/) {
                    282:         $tableheader = 
                    283:             '<table><tr>'.
1.26      raeburn   284:             '<th>&nbsp;</th>'.
1.6       matthew   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>'.
1.5       matthew   290:             '</tr>'.$/;
                    291:     }
1.16      albertel  292:     my $count = $env{'form.start'}-1;
1.2       matthew   293:     $r->rflush();
1.6       matthew   294:     ##
                    295:     ##
1.26      raeburn   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: 
1.2       matthew   307:     while (my $line = <ACTIVITYDATA>) {
1.10      matthew   308:         # FIXME: does not pass symbs along :(
1.6       matthew   309:         chomp($line);
1.20      www       310:         $line = &unescape($line);
1.2       matthew   311:         if (++$count % 50 == 0) {
1.5       matthew   312:             if ($count != 0) { 
                    313:                 $r->print('</table>'.$/);
                    314:                 $r->rflush();
                    315:             }
1.2       matthew   316:             $r->print($tableheader);
                    317:         }
1.5       matthew   318:         my ($symb,$timestamp,$student,$action,$machine,$values);
                    319:         if ($mode eq 'full_class') {
1.11      albertel  320:             ($symb,$timestamp,$student,$action,$machine,$values) = split(',',$line,6);
1.5       matthew   321:         } else {
1.11      albertel  322:             ($symb,$timestamp,$action,$machine,$values) = split(',',$line,5);
1.5       matthew   323:         }
1.11      albertel  324: 	foreach ($symb,$timestamp,$student,$action,$machine) {
1.20      www       325: 	    $_=&unescape($_);
1.11      albertel  326: 	}
1.2       matthew   327:         my ($title,$src);
1.41    ! raeburn   328:         if ($symb =~ m{^\Q/tiny/$cdom/\E\w+$}) {
        !           329:             $symb = &Apache::loncommon::symb_from_tinyurl($symb,$cnum,$cdom);
        !           330:         }
1.4       matthew   331:         if ($symb =~ m:^/adm/:) {
1.2       matthew   332:             $title = $symb;
                    333:             $src = $symb;
                    334:         } else {
1.4       matthew   335:             my $nav_res = $navmap->getBySymb($symb);
                    336:             if (defined($nav_res)) {
1.11      albertel  337:                 $title = $nav_res->compTitle();
1.4       matthew   338:                 $src   = $nav_res->src();
                    339:             } else {
1.23      albertel  340: 		$src = $symb;
                    341: 		if ($src !~ m{/adm}) {
                    342: 		    $title = &Apache::lonnet::gettitle($src);
                    343: 		} elsif ($values =~ /^\s*$/ && 
                    344: 		    (! defined($src) || $src =~ /^\s*$/)) {
1.6       matthew   345:                     next;
                    346:                 } elsif ($values =~ /^\s*$/) {
                    347:                     $values = $src;
                    348:                 } else {
                    349:                     $title = 'unable to retrieve title';
                    350:                     $src   = '/dev/null';
                    351:                 }
1.4       matthew   352:             }
1.41    ! raeburn   353:             if ($src =~ /.sequence$/) {
        !           354:                 $src .= '?navmap=1';
        !           355:             }
1.2       matthew   356:         }
1.6       matthew   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};
1.4       matthew   363:         #
1.5       matthew   364:         if ($symb eq '/prtspool/') {
1.4       matthew   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:         }
1.6       matthew   380:         # Clean up the values
1.11      albertel  381: 	$values = &display_values($action,$values);
1.6       matthew   382:         #
                    383:         # Build the row for output
1.16      albertel  384:         my $tablerow = qq{<tr class="$class"><td>}.($count+1).qq{</td>};
1.6       matthew   385:         if ($src =~ m|^/adm/|) {
                    386:             $tablerow .= 
1.24      bisitz    387:                 '<td valign="top"><span class="LC_nobreak">'.$title.'</span></td>';
1.6       matthew   388:         } else {
                    389:             $tablerow .= 
1.24      bisitz    390:                 '<td valign="top"><span class="LC_nobreak">'.
1.6       matthew   391:                 '<a href="'.$src.'">'.$title.'</a>'.
1.24      bisitz    392:                 '</span></td>';
1.5       matthew   393:         }
1.26      raeburn   394:         if ($server_timezone ne '') {
                    395:             $timestamp = &convert_timezone($server_timezone,$timestamp);
                    396:         }
1.24      bisitz    397:         $tablerow .= '<td valign="top"><span class="LC_nobreak">'.$timestamp.'</span></td>';
1.5       matthew   398:         if ($mode eq 'full_class') {
1.11      albertel  399:             $tablerow.='<td valign="top">'.$student.'</td>';
1.5       matthew   400:         }
1.6       matthew   401:         $tablerow .= 
1.11      albertel  402:             '<td valign="top">'.$action.'</td>'.
1.6       matthew   403: #            '<td>'.$machine.'</td>'.
1.11      albertel  404:             '<td valign="top">'.$values.'</td>'.
1.6       matthew   405:             '</tr>';
                    406:         $r->print($tablerow.$/);
1.2       matthew   407:     }
1.16      albertel  408:     $r->print('</table>'.$/);### if (! $count % 50);
1.2       matthew   409:     close(ACTIVITYDATA);
1.22      albertel  410:     return $count;
1.2       matthew   411: }
                    412: 
1.26      raeburn   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: 
1.5       matthew   437: ###################################################################
                    438: ###################################################################
1.11      albertel  439: sub display_values {
                    440:     my ($action,$values)=@_;
                    441:     my $result='<table>';
1.41    ! raeburn   442:     if (($action eq 'CSTORE') || ($action eq 'PUTSTORE') || ($action eq 'EXPORT')) {
1.32      raeburn   443:         my $is_anon;
1.11      albertel  444: 	my %values=map {split('=',$_,-1)} split(/\&/,$values);
                    445: 	foreach my $key (sort(keys(%values))) {
1.32      raeburn   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:             }
1.11      albertel  453: 	    $result.='<tr><td align="right">'.
1.32      raeburn   454: 		$unesc_key.
1.11      albertel  455: 		'</td><td>=</td><td align="left">'.
1.20      www       456: 		&unescape($values{$key}).'</td></tr>';
1.11      albertel  457: 	}
                    458: 	$result.='</table>';
1.32      raeburn   459:         if ($is_anon) {
                    460:             $result = '<span class="LC_warning">'.&mt('Anonymous Survey Submission: details not shown').'</span>';
                    461:         }
1.11      albertel  462:     } elsif ($action eq 'POST') {
1.23      albertel  463: 	my %values;
                    464:         foreach my $pair (split(/\&/,$values)) {
                    465:             my ($key,$value) = split('=',&unescape($pair),-1);
                    466:             $values{$key} = $value;
                    467:         }
1.11      albertel  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 {
1.20      www       475: 	$result=&unescape($values)
1.11      albertel  476:     }
                    477:     return $result;
                    478: }
                    479: ###################################################################
                    480: ###################################################################
1.1       matthew   481: sub request_data_update {
                    482:     my $command = 'prepare activity log';
1.15      albertel  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'};
1.6       matthew   487: #    &Apache::lonnet::logthis($command.' '.$course.' '.$domain.' '.$home);
1.1       matthew   488:     my $result = &Apache::lonnet::metadata_query($command,$course,$domain,
                    489:                                                  [$home]);
                    490:     return $result;
                    491: }
                    492: 
                    493: ###################################################################
                    494: ###################################################################
1.5       matthew   495: sub pick_student {
                    496:     my ($r) = @_;
                    497:     $r->print("Sorry, cannot display classlist at this time.  Come back another time.");
                    498:     return;
                    499: }
1.1       matthew   500: 
1.5       matthew   501: ###################################################################
                    502: ###################################################################
1.4       matthew   503: sub styles {
                    504:     return <<END;
1.5       matthew   505: <style type="text/css">
1.6       matthew   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">
1.4       matthew   524:     tr.warning   { background-color: red; }
                    525:     tr.chat      { background-color: yellow; }
                    526:     tr.chatfetch { background-color: yellow; }
1.7       matthew   527:     tr.evaluate  { background-color: red; }
1.4       matthew   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; }
1.6       matthew   533:     tr.parmset   { background-color: \#000088; }
1.4       matthew   534:     tr.printout  { background-color: blue; }
1.6       matthew   535:     tr.grades    { background-color: \#CCCCCC; }
1.5       matthew   536: </style>
1.4       matthew   537: END
                    538: }
1.1       matthew   539: 
                    540: ###################################################################
                    541: ###################################################################
                    542: sub handler {
                    543:     my $r=shift;
                    544:     my $c = $r->connection();
                    545:     #
                    546:     # Check for access
1.15      albertel  547:     if (! &Apache::lonnet::allowed('vsa',$env{'request.course.id'})) {
                    548:         $env{'user.error.msg'}=
1.1       matthew   549:             $r->uri.":vsa:0:0:Cannot student activity for complete course";
                    550:         if (! 
                    551:             &Apache::lonnet::allowed('vsa',
1.15      albertel  552:                                      $env{'request.course.id'}.'/'.
                    553:                                      $env{'request.course.sec'})) {
                    554:             $env{'user.error.msg'}=
1.1       matthew   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'},
1.30      raeburn   568:                       ['selected_student','start','only_body']);
1.1       matthew   569:     #
1.2       matthew   570:     # We will almost always need this...
                    571:     my $navmap = Apache::lonnavmaps::navmap->new();
1.25      raeburn   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:     }
1.1       matthew   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,
1.37      bisitz    583:                                             bug=>'instructor interface',
                    584:                                             help=>'View_recent_activity'});
1.1       matthew   585:     #
1.2       matthew   586:     # Give the LON-CAPA page header
1.30      raeburn   587:     my $args;
                    588:     if ($env{'form.only_body'}) {
                    589:         $args = { only_body => 1, };
1.39      raeburn   590:         $args->{'add_progressbar'} = 1;
1.30      raeburn   591:     }
                    592:     $r->print(&Apache::loncommon::start_page('Student Activity',&styles(),$args).
1.19      albertel  593:               &Apache::lonhtmlcommon::breadcrumbs('Student Activity'));
1.2       matthew   594:     $r->rflush();
                    595:     #
1.1       matthew   596:     # Begin form output
1.2       matthew   597:     $r->print('<form name="trackstudent" method="post" action="/adm/trackstudent">');
1.1       matthew   598:     $r->rflush();
1.33      www       599:     my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin($r);
1.2       matthew   600:     &Apache::lonhtmlcommon::Update_PrgWin
                    601:         ($r,\%prog_state,&mt('Contacting course home server'));
1.1       matthew   602:     #
                    603:     my $result = &request_data_update();
                    604:     #
1.15      albertel  605:     if (exists($env{'form.selected_student'})) {
1.4       matthew   606:         # For now, just show all the data, in the future allow selection of
                    607:         # a student
1.15      albertel  608:         my ($sname,$sdom) = split(':',$env{'form.selected_student'});
1.21      albertel  609:         if ($sname =~ /^$LONCAPA::username_re$/ 
                    610: 	    && $sdom =~ /^$LONCAPA::domain_re$/) {
1.6       matthew   611:             $r->print('<h2>'.
1.29      bisitz    612:                       &mt('Recent activity of [_1]',$sname.':'.$sdom).
1.6       matthew   613:                       '</h2>');
1.27      bisitz    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:             );
1.6       matthew   619:             &get_data($r,\%prog_state,$navmap,
1.15      albertel  620:                       'student:'.$env{'form.selected_student'});
1.6       matthew   621:         } else {
1.34      bisitz    622:             $r->print(
                    623:                 '<p class="LC_error">'
                    624:                .&mt('Unable to process for [_1]:[_2]',$sname,$sdom)
                    625:                .'</p>'
                    626:             );
1.6       matthew   627:         }
1.1       matthew   628:     } else {
1.4       matthew   629:         # For now, just show all the data instead of limiting it to one student
1.5       matthew   630:         &get_data($r,\%prog_state,$navmap,'full_class');
1.1       matthew   631:     }
                    632:     #
1.4       matthew   633:     &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Done'));
                    634:     &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
1.2       matthew   635:     #
1.1       matthew   636:     $r->print("</form>\n");
1.18      albertel  637:     $r->print(&Apache::loncommon::end_page());
1.1       matthew   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>