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