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

1.1       matthew     1: # The LearningOnline Network with CAPA
                      2: #
1.4     ! matthew     3: # $Id: lontrackstudent.pm,v 1.3 2004/08/19 21:07:35 matthew 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);
                     47: use Apache::lonnet();
                     48: use Apache::lonlocal;
                     49: use Time::HiRes;
                     50: 
                     51: ###################################################################
                     52: ###################################################################
1.2       matthew    53: sub get_all_data {
                     54:     my ($r,$prog_state,$navmap) = @_;
                     55:     ##
                     56:     ## Compose the query
                     57:     &Apache::lonhtmlcommon::Update_PrgWin
                     58:         ($r,$prog_state,&mt('Composing Query'));
                     59:     #
                     60:     my $query;
                     61:     my $cid = $ENV{'request.course.id'};
                     62:     my $domain = $ENV{'course.'.$cid.'.domain'};
                     63:     my $home = $ENV{'course.'.$cid.'.home'};
                     64:     my $course = $ENV{'course.'.$cid.'.num'};
                     65:     my $prefix = $course.'_'.$domain.'_';
                     66:     #
                     67:     my $student_table  = $prefix.'students';
                     68:     my $res_table      = $prefix.'resource';
                     69:     my $action_table   = $prefix.'actions';
                     70:     my $machine_table  = $prefix.'machine_table';
                     71:     my $activity_table = $prefix.'activity';
                     72:     #
                     73:     $query = qq{
1.4     ! matthew    74:         SELECT B.resource,A.time,C.student,D.action,E.machine,A.action_values 
1.2       matthew    75:             FROM $activity_table AS A
1.4     ! matthew    76:             LEFT JOIN $res_table      AS B ON B.res_id=A.res_id 
1.2       matthew    77:             LEFT JOIN $student_table  AS C ON C.student_id=A.student_id 
                     78:             LEFT JOIN $action_table   AS D ON D.action_id=A.action_id 
                     79:             LEFT JOIN $machine_table  AS E ON E.machine_id=A.machine_id
1.4     ! matthew    80:             WHERE A.student_id>10
        !            81:             ORDER BY A.time ASC
        !            82:             LIMIT 5000
1.2       matthew    83:     };
                     84:     $query =~ s|$/||g;
1.4     ! matthew    85:     &Apache::lonnet::logthis($query);
1.2       matthew    86:     ##
                     87:     ## Send it along
                     88:     my $reply=&Apache::lonnet::metadata_query($query,undef,undef,[$home]);
                     89:     if (ref($reply) ne 'HASH') {
                     90:         $r->print('<h2>'.
                     91:                   &mt('Error contacting home server for course: [_1]',
                     92:                       $reply).
                     93:                   '</h2>');
                     94:         return;
                     95:     }
                     96:     my $results_file = $r->dir_config('lonDaemons').'/tmp/'.$reply->{$home};
                     97:     my $endfile = $results_file.'.end';
                     98:     ##
                     99:     ## Check for the results
                    100:     &Apache::lonhtmlcommon::Update_PrgWin
                    101:         ($r,$prog_state,&mt('Waiting for results'));
                    102:     my $maxtime = 500;
                    103:     my $starttime = time;
                    104:     while (! -e $endfile && (time-$starttime < $maxtime)) {
1.4     ! matthew   105:         &Apache::lonhtmlcommon::Update_PrgWin
        !           106:             ($r,$prog_state,&mt('Waiting up to [_1] seconds for results',
        !           107:                                 $starttime+$maxtime-time));
1.2       matthew   108:         sleep(1);
                    109:     }
                    110:     if (! -e $endfile) {
                    111:         $r->print('<h2>'.
                    112:                   &mt('Unable to retrieve data.').'</h2>');
                    113:         $r->print(&mt('Please try again in a few minutes.'));
                    114:         return;
                    115:     }
                    116:     &Apache::lonhtmlcommon::Update_PrgWin
                    117:         ($r,$prog_state,&mt('Parsing results'));
1.4     ! matthew   118:     &output_results($r,$results_file,$navmap);
        !           119:     &Apache::lonhtmlcommon::Update_PrgWin
        !           120:         ($r,$prog_state,&mt('Finished!'));
        !           121:     return;
        !           122: }
        !           123: 
        !           124: sub output_results {
        !           125:     my ($r,$results_file,$navmap) = @_;
1.2       matthew   126:     if (! open(ACTIVITYDATA,$results_file)) {
1.4     ! matthew   127:         $r->print('<h2>'.&mt('Unable to read results file.').'</h2>'.
        !           128:                   '<p>'.
        !           129:                   &mt('This is a serious error and has been logged.  '.
        !           130:                       'You should contact your system administrator '.
        !           131:                       'to resolve this issue.').
        !           132:                   '</p>');
1.2       matthew   133:         return;
                    134:     }
                    135:     my $tableheader = 
                    136:         '<table><tr>'.
                    137:         '<th>'.&mt('Resource').'</th>'.
                    138:         '<th>'.&mt('Time').'</th>'.
                    139:         '<th>'.&mt('Student').'</th>'.
                    140:         '<th>'.&mt('Action').'</th>'.
                    141:         '<th>'.&mt('Originating Server').'</th>'.
                    142:         '<th>'.&mt('Data').'</th>'.
                    143:         '</tr>'.$/;
1.4     ! matthew   144:     my $count = 0;
1.2       matthew   145:     $r->print($tableheader);
                    146:     $r->rflush();
                    147:     while (my $line = <ACTIVITYDATA>) {
                    148:         $line = &Apache::lonnet::unescape($line);
                    149:         if (++$count % 50 == 0) {
                    150:             $r->print('</table>'.$/);
                    151:             $r->rflush();
                    152:             $r->print($tableheader);
                    153:         }
                    154:         my ($symb,$timestamp,$student,$action,$machine,$values) =
                    155:             map { &Apache::lonnet::unescape($_); } split(',',$line,6);
                    156:         my ($title,$src);
1.4     ! matthew   157:         if ($symb =~ m:^/adm/:) {
1.2       matthew   158:             $title = $symb;
                    159:             $src = $symb;
1.4     ! matthew   160:         } elsif ($symb eq '/prtspool/') {
        !           161:             $title = "Printout";
        !           162:             $src = undef;
1.2       matthew   163:         } else {
1.4     ! matthew   164:             my $nav_res = $navmap->getBySymb($symb);
        !           165:             if (defined($nav_res)) {
        !           166:                 $title = $nav_res->title();
        !           167:                 $src   = $nav_res->src();
        !           168:             } else {
        !           169:                 $title = 'unable to retrieve title';
        !           170:                 $src   = '/dev/null';
        !           171:             }
1.2       matthew   172:         }
1.4     ! matthew   173:         my $class = '';
        !           174:         #
        !           175:         if ($symb eq '/printout/') {
        !           176:             $class = 'print';
        !           177:             $title = 'retrieve printout';
        !           178:         } elsif ($symb =~ m|^/adm/([^/]+)|) {
        !           179:             $class = $1;
        !           180:         } elsif ($symb =~ m|^/adm/|) {
        !           181:             $class = 'adm';
        !           182:         }
        !           183:         if ($title eq 'unable to retrieve title') {
        !           184:             $title =~ s/ /\&nbsp;/g;
        !           185:             $class = 'warning';
        !           186:         }
        !           187:         if (! defined($title) || $title eq '') {
        !           188:             $title = 'untitled';
        !           189:             $class = 'warning';
        !           190:         }
        !           191:         $r->print('<tr class="'.$class.'">'.
        !           192:                   '<td><a href="'.$src.'">'.$title.'</a>'.'</td>'.
1.2       matthew   193:                   '<td><nobr>'.$timestamp.'</nobr></td>'.
                    194:                   '<td>'.$student.'</td>'.
                    195:                   '<td>'.$action.'</td>'.
                    196:                   '<td>'.$machine.'</td>'.
1.4     ! matthew   197:                   '<td>'.($class?$symb:'').'</td>'.'</tr>'.$/);
        !           198: #                  '<td>'.$symb.'</td>'.'</tr>'.$/);
1.2       matthew   199:     }
                    200:     $r->print('</table>'.$/);
                    201:     close(ACTIVITYDATA);
                    202:     return;
                    203: }
                    204: 
1.1       matthew   205: sub get_student_data {}
                    206: sub html_output_student_data {}
                    207: sub html_output_class_data {}
                    208: 
                    209: sub request_data_update {
                    210:     my $command = 'prepare activity log';
                    211:     my $cid = $ENV{'request.course.id'};
                    212:     my $domain = $ENV{'course.'.$cid.'.domain'};
                    213:     my $home = $ENV{'course.'.$cid.'.home'};
                    214:     my $course = $ENV{'course.'.$cid.'.num'};
                    215:     &Apache::lonnet::logthis($command.' '.$course.' '.$domain.' '.$home);
                    216:     my $result = &Apache::lonnet::metadata_query($command,$course,$domain,
                    217:                                                  [$home]);
                    218:     return $result;
                    219: }
                    220: 
                    221: ###################################################################
                    222: ###################################################################
                    223: 
1.4     ! matthew   224: sub styles {
        !           225:     return <<END;
        !           226: <STYLE TYPE="text/css">
        !           227:     tr.warning   { background-color: red; }
        !           228:     tr.chat      { background-color: yellow; }
        !           229:     tr.chatfetch { background-color: yellow; }
        !           230:     tr.navmaps   { background-color: \#777777; }
        !           231:     tr.roles     { background-color: \#999999; }
        !           232:     tr.flip      { background-color: \#BBBBBB; }
        !           233:     tr.adm       { background-color: green; }
        !           234:     tr.print     { background-color: blue; }
        !           235:     tr.printout  { background-color: blue; }
        !           236: </STYLE>
        !           237: END
        !           238: }
1.1       matthew   239: 
                    240: ###################################################################
                    241: ###################################################################
                    242: sub handler {
                    243:     my $r=shift;
                    244:     my $c = $r->connection();
                    245:     #
                    246:     # Check for overloading here and on the course home server
                    247:     my $loaderror=&Apache::lonnet::overloaderror($r);
                    248:     if ($loaderror) { return $loaderror; }
                    249:     $loaderror=
                    250:         &Apache::lonnet::overloaderror
                    251:         ($r,
                    252:          $ENV{'course.'.$ENV{'request.course.id'}.'.home'});
                    253:     if ($loaderror) { return $loaderror; }
                    254:     #
                    255:     # Check for access
                    256:     if (! &Apache::lonnet::allowed('vsa',$ENV{'request.course.id'})) {
                    257:         $ENV{'user.error.msg'}=
                    258:             $r->uri.":vsa:0:0:Cannot student activity for complete course";
                    259:         if (! 
                    260:             &Apache::lonnet::allowed('vsa',
                    261:                                      $ENV{'request.course.id'}.'/'.
                    262:                                      $ENV{'request.course.sec'})) {
                    263:             $ENV{'user.error.msg'}=
                    264:                 $r->uri.":vsa:0:0:Cannot view student activity with given role";
                    265:             return HTTP_NOT_ACCEPTABLE;
                    266:         }
                    267:     }
                    268:     #
                    269:     # Send the header
                    270:     &Apache::loncommon::no_cache($r);
                    271:     &Apache::loncommon::content_type($r,'text/html');
                    272:     $r->send_http_header;
                    273:     if ($r->header_only) { return OK; }
                    274:     #
                    275:     # Extract form elements from query string
                    276:     &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
                    277:                                             ['selected_student']);
                    278:     #
1.2       matthew   279:     # We will almost always need this...
                    280:     my $navmap = Apache::lonnavmaps::navmap->new();
1.1       matthew   281:     # 
                    282:     &Apache::lonhtmlcommon::clear_breadcrumbs();
                    283:     &Apache::lonhtmlcommon::add_breadcrumb({href=>'/adm/studentactivity',
                    284:                                             title=>'Student Activity',
                    285:                                             text =>'Student Activity',
                    286:                                             faq=>139,
                    287:                                             bug=>'instructor interface'});
                    288:     #
1.2       matthew   289:     # Give the LON-CAPA page header
1.4     ! matthew   290:     $r->print('<html><head>'.&styles.'<title>'.
1.2       matthew   291:               &mt('Student Activity').
                    292:               "</title></head>\n".
                    293:               &Apache::loncommon::bodytag('Student Activity').
                    294:               &Apache::lonhtmlcommon::breadcrumbs(undef,'Student Activity'));
                    295:     $r->rflush();
                    296:     #
1.1       matthew   297:     # Begin form output
1.2       matthew   298:     $r->print('<form name="trackstudent" method="post" action="/adm/trackstudent">');
                    299:     $r->print('<br />');
                    300:     $r->print('<div name="statusline">'.
                    301:               &mt('Status:[_1]',
                    302:                   '<input type="text" name="status" size="60" value="" />').
                    303:               '</div>');
1.1       matthew   304:     $r->rflush();
1.2       matthew   305:     my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin
                    306:         ($r,&mt('Student Activity Retrieval'),
                    307:          &mt('Student Activity Retrieval'),undef,'inline',undef,
                    308:          'trackstudent','status');
                    309:     &Apache::lonhtmlcommon::Update_PrgWin
                    310:         ($r,\%prog_state,&mt('Contacting course home server'));
1.1       matthew   311:     #
                    312:     my $result = &request_data_update();
                    313:     if (ref($result) eq 'HASH') {
1.2       matthew   314:         $result = join(' ',map { $_.'=>'.$result->{$_}; } keys(%$result));
1.1       matthew   315:     }
1.4     ! matthew   316:     &Apache::lonnet::logthis('result from request_data_update: '.$result);
1.1       matthew   317:     #
                    318:     if (! exists($ENV{'form.selected_student'})) {
1.4     ! matthew   319:         # For now, just show all the data, in the future allow selection of
        !           320:         # a student
        !           321:         &get_all_data($r,\%prog_state,$navmap);
1.1       matthew   322:     } else {
1.4     ! matthew   323:         # For now, just show all the data instead of limiting it to one student
        !           324:         &get_all_data($r,\%prog_state,$navmap);
1.1       matthew   325:     }
                    326:     #
1.4     ! matthew   327:     &Apache::lonhtmlcommon::Update_PrgWin($r,\%prog_state,&mt('Done'));
        !           328:     &Apache::lonhtmlcommon::Close_PrgWin($r,\%prog_state);
1.2       matthew   329:     #
1.1       matthew   330:     $r->print("</form>\n");
                    331:     $r->print("</body>\n</html>\n");
                    332:     $r->rflush();
                    333:     #
                    334:     return OK;
                    335: }
                    336: 
                    337: 1;
                    338: 
                    339: #######################################################
                    340: #######################################################
                    341: 
                    342: =pod
                    343: 
                    344: =back
                    345: 
                    346: =cut
                    347: 
                    348: #######################################################
                    349: #######################################################
                    350: 
                    351: __END__
                    352: 

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