Annotation of loncom/interface/lonchart.pm, revision 1.25
1.1 www 1: # The LearningOnline Network with CAPA
1.25 ! minaeibi 2: # (Publication Handler
! 3: #
! 4: # $Id: lonstatistics.pm,v 1.24 2001/12/18 21:33:43 albertel Exp $
! 5: #
! 6: # Copyright Michigan State University Board of Trustees
! 7: #
! 8: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
! 9: #
! 10: # LON-CAPA is free software; you can redistribute it and/or modify
! 11: # it under the terms of the GNU General Public License as published by
! 12: # the Free Software Foundation; either version 2 of the License, or
! 13: # (at your option) any later version.
! 14: #
! 15: # LON-CAPA is distributed in the hope that it will be useful,
! 16: # but WITHOUT ANY WARRANTY; without even the implied warranty of
! 17: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 18: # GNU General Public License for more details.
! 19: #
! 20: # You should have received a copy of the GNU General Public License
! 21: # along with LON-CAPA; if not, write to the Free Software
! 22: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
! 23: #
! 24: # /home/httpd/html/adm/gpl.txt
! 25: #
! 26: # http://www.lon-capa.org/
! 27: #
! 28: #
1.1 www 29: # Homework Performance Chart
30: #
31: # (Navigate Maps Handler
32: #
33: # (Page Handler
34: #
35: # (TeX Content Handler
36: #
37: # 05/29/00,05/30 Gerd Kortemeyer)
38: # 08/30,08/31,09/06,09/14,09/15,09/16,09/19,09/20,09/21,09/23,
39: # 10/02,10/10,10/14,10/16,10/18,10/19,10/31,11/6,11/14,11/16 Gerd Kortemeyer)
40: #
1.14 minaeibi 41: # 3/1/1,6/1,17/1,29/1,30/1,31/1 Gerd Kortemeyer)
1.5 minaeibi 42: # 7/10/01 Behrouz Minaei
1.6 www 43: # 9/8 Gerd Kortemeyer
1.8 minaeibi 44: # 10/18/01, 10/19/01 Behrouz Minaei
1.21 minaeibi 45: # 11/17/01, 11/22/01, 11/24/01, 11/28/01 Behrouz Minaei
1.24 minaeibi 46: # 12/18/01 Behrouz Minaei
1.1 www 47:
48: package Apache::lonchart;
49:
50: use strict;
51: use Apache::Constants qw(:common :http);
52: use Apache::lonnet();
53: use HTML::TokeParser;
54: use GDBM_File;
55:
56: # -------------------------------------------------------------- Module Globals
57: my %hash;
58: my @cols;
59: my @rowlabels;
60: my @students;
61:
62: # ------------------------------------------------------------- Find out status
63:
1.5 minaeibi 64: sub ExtractStudentData {
65: my ($index,$coid)=@_;
66: my ($sname,$sdom) = split( /\:/, $students[$index] );
67: my $shome=&Apache::lonnet::homeserver( $sname,$sdom );
68: my $reply=&Apache::lonnet::reply('dump:'.$sdom.':'.$sname.':'.$coid,$shome );
69: my %result=();
70: my $ResId;
71: my $Code;
72: my $Tries;
73: my $Wrongs;
1.7 minaeibi 74: my %TempHash;
1.5 minaeibi 75: my $Version;
1.10 minaeibi 76: my $ProbNo;
77: my $PrTotal;
1.22 minaeibi 78: my $LatestVersion;
1.5 minaeibi 79: my $Str=substr($students[$index].
80: ' ',0,14).' ! '.
81: substr($rowlabels[$index].
82: ' ',0,45).' ! ';
83: unless ($reply=~/^error\:/) {
84: map {
85: my ($name,$value)=split(/\=/,&Apache::lonnet::unescape($_));
86: $result{$name}=$value;
87: } split(/\&/,$reply);
1.10 minaeibi 88: $ProbNo = 0;
89: $PrTotal = 0;
90: my $IterationNo = 0;
1.5 minaeibi 91: foreach $ResId (@cols) {
1.10 minaeibi 92: if ($IterationNo == 0) {$IterationNo++; next;}
93: if (!$ResId) {
94: my $PrNo = sprintf( "%3d", $ProbNo );
95: $Str .= ' '.'<font color="#007700">'.$PrNo.'</font> ';
96: $PrTotal += $ProbNo;
97: $ProbNo=0;
98: next;
99: }
1.5 minaeibi 100: $ResId=~/(\d+)\.(\d+)/;
1.11 minaeibi 101: my $meta=$hash{'src_'.$ResId};
102: my $PartNo = 0;
103: undef %TempHash;
104: map {
105: if ($_=~/^stores\_(\d+)\_tries$/) {
106: my $Part=&Apache::lonnet::metadata($meta,$_.'.part');
107: if ( $TempHash{"$Part"} eq '' ) {
108: $TempHash{"$Part"} = $Part;
109: $TempHash{$PartNo}=$Part;
110: $TempHash{"$Part.Code"} = ' ';
111: $PartNo++;
112: }
113: }
114: } split(/\,/,&Apache::lonnet::metadata($meta,'keys'));
115:
1.5 minaeibi 116: my $Prob = &Apache::lonnet::declutter( $hash{'map_id_'.$1} ).
117: '___'.$2.'___'.
118: &Apache::lonnet::declutter( $hash{'src_'.$ResId} );
119: $Code=' ';
120: $Tries = 0;
1.7 minaeibi 121: $LatestVersion = $result{"version:$Prob"};
1.14 minaeibi 122:
1.7 minaeibi 123: if ( $LatestVersion ) {
124: for ( my $Version=1; $Version<=$LatestVersion; $Version++ ) {
125: my $vkeys = $result{"$Version:keys:$Prob"};
126: my @keys = split(/\:/,$vkeys);
1.14 minaeibi 127:
1.7 minaeibi 128: foreach my $Key (@keys) {
129: if (($Key=~/\.(\w+)\.solved$/) && ($Key!~/^\d+\:/)) {
130: my $Part = $1;
131: $Tries = $result{"$Version:$Prob:resource.$Part.tries"};
1.19 minaeibi 132: $TempHash{"$Part.Tries"}=($Tries) ? $Tries : 0;
1.16 minaeibi 133: my $Val = $result{"$Version:$Prob:resource.$Part.solved"};
1.19 minaeibi 134: if ($Val eq 'correct_by_student'){$Code='*';}
1.7 minaeibi 135: elsif ($Val eq 'correct_by_override'){$Code = '+';}
136: elsif ($Val eq 'incorrect_attempted'){$Code = '.';}
137: elsif ($Val eq 'incorrect_by_override'){$Code = '-';}
138: elsif ($Val eq 'excused'){$Code = 'x';}
1.23 albertel 139: elsif ($Val eq 'ungraded_attempted'){$Code = '#';}
1.13 minaeibi 140: else {$Code = ' ';}
1.7 minaeibi 141: $TempHash{"$Part.Code"} = $Code;
142: }
1.5 minaeibi 143: }
144: }
1.7 minaeibi 145: for ( my $n = 0; $n < $PartNo; $n++ ) {
146: my $part = $TempHash{$n};
1.25 ! minaeibi 147: my $Code = $TempHash{"$part.Code"};
! 148: if ( $Code eq '*') {
1.10 minaeibi 149: $ProbNo++;
1.19 minaeibi 150: if (($TempHash{"$part.Tries"}<10) ||
1.20 minaeibi 151: ($TempHash{"$part.Tries"} eq '')) {
1.19 minaeibi 152: $TempHash{"$part.Code"}=$TempHash{"$part.Tries"};
1.10 minaeibi 153: }
1.7 minaeibi 154: }
1.25 ! minaeibi 155: elsif ( $Code eq '+' ) {$ProbNo++;}
1.19 minaeibi 156: $Str .= $TempHash{"$part.Code"};
1.7 minaeibi 157: }
1.5 minaeibi 158: }
1.11 minaeibi 159: else {for(my $n=0; $n<$PartNo; $n++) {$Str.=' ';}}
1.5 minaeibi 160: }
1.1 www 161: }
1.10 minaeibi 162: my $PrTot = sprintf( "%5d", $PrTotal );
1.11 minaeibi 163: $Str .= ' '.'<font color="#000088">'.$PrTot.'</font> ';
164:
1.10 minaeibi 165: return $Str ;
1.1 www 166: }
167:
1.5 minaeibi 168:
1.1 www 169: # ------------------------------------------------------------ Build page table
170:
171: sub tracetable {
172: my ($rid,$beenhere)=@_;
173: unless ($beenhere=~/\&$rid\&/) {
174: $beenhere.=$rid.'&';
1.7 minaeibi 175: # new ... updating the map according to sequence and page
1.1 www 176: if (defined($hash{'is_map_'.$rid})) {
1.7 minaeibi 177: my $cmap=$hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$rid}}};
178: if ( $cmap eq 'sequence' || $cmap eq 'page' ) {
1.1 www 179: $cols[$#cols+1]=0;
180: }
181: if ((defined($hash{'map_start_'.$hash{'src_'.$rid}})) &&
182: (defined($hash{'map_finish_'.$hash{'src_'.$rid}}))) {
183: my $frid=$hash{'map_finish_'.$hash{'src_'.$rid}};
184:
185: &tracetable($hash{'map_start_'.$hash{'src_'.$rid}},
186: '&'.$frid.'&');
187:
188: if ($hash{'src_'.$frid}) {
189: if ($hash{'src_'.$frid}=~
190: /\.(problem|exam|quiz|assess|survey|form)$/) {
191: $cols[$#cols+1]=$frid;
192: }
193: }
194:
195: }
196: } else {
197: if ($hash{'src_'.$rid}) {
198: if ($hash{'src_'.$rid}=~
199: /\.(problem|exam|quiz|assess|survey|form)$/) {
200: $cols[$#cols+1]=$rid;
201: }
202: }
203: }
204: if (defined($hash{'to_'.$rid})) {
205: map {
206: &tracetable($hash{'goesto_'.$_},$beenhere);
207: } split(/\,/,$hash{'to_'.$rid});
208: }
209: }
210: }
211:
212: # ================================================================ Main Handler
213:
214: sub handler {
1.24 minaeibi 215:
216: undef %hash;
217: undef @students;
218: undef @cols;
219: undef @rowlabels;
220:
1.22 minaeibi 221: my $r=shift;
1.1 www 222:
223: if (&Apache::lonnet::allowed('vgr',$ENV{'request.course.id'})) {
224: # ------------------------------------------- Set document type for header only
225:
226: if ($r->header_only) {
227: if ($ENV{'browser.mathml'}) {
228: $r->content_type('text/xml');
229: } else {
230: $r->content_type('text/html');
231: }
232: $r->send_http_header;
233: return OK;
234: }
235:
236: my $requrl=$r->uri;
237: # ----------------------------------------------------------------- Tie db file
238: if ($ENV{'request.course.fn'}) {
239: my $fn=$ENV{'request.course.fn'};
240: if (-e "$fn.db") {
241: if (tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER,0640)) {
242: # ------------------------------------------------------------------- Hash tied
243:
244:
245: # ------------------------------------------------------------------ Build page
246:
247: # ---------------------------------------------------------------- Send headers
248:
249: $r->content_type('text/html');
250: $r->send_http_header;
251: $r->print(
252: '<html><head><title>LON-CAPA Assessment Chart</title></head>');
253:
254: $r->print('<body bgcolor="#FFFFFF">'.
255: '<script>window.focus();</script>'.
256: '<img align=right src=/adm/lonIcons/lonlogos.gif>'.
257: '<h1>Assessment Chart</h1>');
258:
259: # ---------------------------------------------------------------- Course title
260:
261: $r->print('<h1>'.
1.6 www 262: $ENV{'course.'.$ENV{'request.course.id'}.'.description'}.'</h1><h3>'.
263: localtime()."</h3><p><pre>1..9: correct by student in 1..9 tries\n".
264: " *: correct by student in more than 9 tries\n".
265: " +: correct by override\n".
266: " -: incorrect by override\n".
267: " .: incorrect attempted\n".
1.23 albertel 268: " #: ungraded attempted\n".
1.6 www 269: " : not attempted\n".
270: " x: excused</pre><p>");
271:
1.1 www 272: # ------------------------------- This is going to take a while, produce output
273:
274: $r->rflush();
275:
276: # ----------------------- Get first and last resource, see if there is anything
277:
278:
279: my $firstres=$hash{'map_start_/res/'.$ENV{'request.course.uri'}};
280: my $lastres=$hash{'map_finish_/res/'.$ENV{'request.course.uri'}};
281: if (($firstres) && ($lastres)) {
282: # ----------------------------------------------------------------- Render page
283:
284: my $cid=$ENV{'request.course.id'};
285: my $chome=$ENV{'course.'.$cid.'.home'};
286: my ($cdom,$cnum)=split(/\_/,$cid);
287:
288: # ---------------------------------------------- Read class list and row labels
289:
290: my $classlst=&Apache::lonnet::reply
291: ('dump:'.$cdom.':'.$cnum.':classlist',$chome);
292: my $now=time;
293: unless ($classlst=~/^error\:/) {
294: map {
295: my ($name,$value)=split(/\=/,$_);
296: my ($end,$start)=split(/\:/,&Apache::lonnet::unescape($value));
297: my $active=1;
298: if (($end) && ($now>$end)) { $active=0; }
299: if ($active) {
300: my $thisindex=$#students+1;
301: $name=&Apache::lonnet::unescape($name);
302: $students[$thisindex]=$name;
303: my ($sname,$sdom)=split(/\:/,$name);
304: my $ssec=&Apache::lonnet::usection($sdom,$sname,$cid);
305: if ($ssec==-1) {
306: $rowlabels[$thisindex]=
307: 'Data not available: '.$name;
308: } else {
309: my %reply=&Apache::lonnet::idrget($sdom,$sname);
1.3 albertel 310: my $reply=&Apache::lonnet::reply('get:'.$sdom.':'.$sname.
311: ':environment:lastname&generation&firstname&middlename',
312: &Apache::lonnet::homeserver($sname,$sdom));
1.1 www 313: $rowlabels[$thisindex]=
1.3 albertel 314: sprintf('%3s',$ssec).' '.$reply{$sname}.' ';
315: my $i=0;
1.1 www 316: map {
1.3 albertel 317: $i++;
318: if ( $_ ne '') {
1.4 albertel 319: $rowlabels[$thisindex].=&Apache::lonnet::unescape($_).' ';
1.3 albertel 320: }
321: if ($i == 2) {
322: chop($rowlabels[$thisindex]);
323: $rowlabels[$thisindex].=', ';
324: }
1.1 www 325: } split(/\&/,$reply);
1.4 albertel 326:
327: }
1.1 www 328: }
329: } sort split(/\&/,$classlst);
330:
331: } else {
332: $r->print('<h1>Could not access course data</h1>');
333: }
334:
335: my $allstudents=$#students+1;
336: $r->print('<h3>'.$allstudents.' students</h3>');
337: $r->rflush();
338:
339: # --------------- Find all assessments and put them into some linear-like order
340:
341: &tracetable($firstres,'&'.$lastres.'&');
342:
343: # ----------------------------------------------------------------- Start table
344:
345: $r->print('<p><pre>');
346: my $index;
347: for ($index=0;$index<=$#students;$index++) {
1.5 minaeibi 348: $r->print(&ExtractStudentData($index,$cid).'<br>');
1.1 www 349: $r->rflush();
350: }
351: $r->print('</pre>');
352:
353: } else {
354: $r->print('<h3>Undefined course sequence</h3>');
355: }
356:
357: $r->print('</body></html>');
358:
359: # ------------------------------------------------------------- End render page
360: } else {
361: $r->content_type('text/html');
362: $r->send_http_header;
363: $r->print('<html><body>Coursemap undefined.</body></html>');
364: }
365: # ------------------------------------------------------------------ Untie hash
366: unless (untie(%hash)) {
367: &Apache::lonnet::logthis("<font color=blue>WARNING: ".
368: "Could not untie coursemap $fn (browse).</font>");
369: }
370:
371: # -------------------------------------------------------------------- All done
372: return OK;
373: # ----------------------------------------------- Errors, hash could no be tied
374: }
375: } else {
376: $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
377: return HTTP_NOT_ACCEPTABLE;
378: }
379: } else {
380: $ENV{'user.error.msg'}=
381: $r->uri.":vgr:0:0:Cannot view grades for complete course";
382: return HTTP_NOT_ACCEPTABLE;
383:
384: }
385: }
386: 1;
387: __END__
388:
389:
390:
391:
392:
393:
394:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>