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/ /\ /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>