Annotation of loncom/interface/lonnavmaps.pm, revision 1.11
1.2 www 1: # The LearningOnline Network with CAPA
2: # Navigate Maps Handler
1.1 www 3: #
1.2 www 4: # (Page Handler
1.1 www 5: #
1.2 www 6: # (TeX Content Handler
1.1 www 7: #
1.2 www 8: # 05/29/00,05/30 Gerd Kortemeyer)
9: # 08/30,08/31,09/06,09/14,09/15,09/16,09/19,09/20,09/21,09/23,
10: # 10/02,10/10,10/14,10/16,10/18,10/19,10/31,11/6,11/14,11/16 Gerd Kortemeyer)
1.1 www 11: #
1.10 www 12: # 3/1/1,6/1,17/1,29/1,30/1 Gerd Kortemeyer
1.2 www 13:
1.1 www 14: package Apache::lonnavmaps;
15:
16: use strict;
1.2 www 17: use Apache::Constants qw(:common :http);
18: use Apache::lonnet();
19: use HTML::TokeParser;
20: use GDBM_File;
21:
22: # -------------------------------------------------------------- Module Globals
23: my %hash;
24: my @rows;
25:
1.10 www 26: #
27: # These cache hashes need to be independent of user, resource and course
28: # (user and course can/should be in the keys)
29: #
30:
31: my %courserdatas;
32: my %userrdatas;
33:
34: #
35: # These global hashes are dependent on user, course and resource,
36: # and need to be initialized every time when a sheet is calculated
37: #
38: my %courseopt;
39: my %useropt;
40: my %parmhash;
41:
42:
1.2 www 43: # ------------------------------------------------------------------ Euclid gcd
44:
45: sub euclid {
46: my ($e,$f)=@_;
47: my $a; my $b; my $r;
48: if ($e>$f) { $b=$e; $r=$f; } else { $r=$e; $b=$f; }
49: while ($r!=0) {
50: $a=$b; $b=$r;
51: $r=$a%$b;
52: }
53: return $b;
54: }
55:
1.10 www 56: # --------------------------------------------------------------------- Parmval
57:
58: # -------------------------------------------- Figure out a cascading parameter
59: #
60: # For this function to work
61: #
62: # * parmhash needs to be tied
63: # * courseopt and useropt need to be initialized for this user and course
64: #
65:
66: sub parmval {
67: my ($what,$symb)=@_;
68: my $cid=$ENV{'request.course.id'};
69: my $csec=$ENV{'request.course.sec'};
70: my $uname=$ENV{'user.name'};
71: my $udom=$ENV{'user.domain'};
72:
73: unless ($symb) { return ''; }
74: my $result='';
75:
76: my ($mapname,$id,$fn)=split(/\_\_\_/,$symb);
77:
78: # ----------------------------------------------------- Cascading lookup scheme
79: my $rwhat=$what;
80: $what=~s/^parameter\_//;
81: $what=~s/\_/\./;
82:
83: my $symbparm=$symb.'.'.$what;
84: my $mapparm=$mapname.'___(all).'.$what;
85: my $usercourseprefix=$uname.'_'.$udom.'_'.$cid;
86:
87: my $seclevel=
88: $usercourseprefix.'.['.
89: $csec.'].'.$what;
90: my $seclevelr=
91: $usercourseprefix.'.['.
92: $csec.'].'.$symbparm;
93: my $seclevelm=
94: $usercourseprefix.'.['.
95: $csec.'].'.$mapparm;
96:
97: my $courselevel=
98: $usercourseprefix.'.'.$what;
99: my $courselevelr=
100: $usercourseprefix.'.'.$symbparm;
101: my $courselevelm=
102: $usercourseprefix.'.'.$mapparm;
103:
104: # ---------------------------------------------------------- fourth, check user
105:
106: if ($uname) {
107:
108: if ($useropt{$courselevelr}) { return $useropt{$courselevelr}; }
109:
110: if ($useropt{$courselevelm}) { return $useropt{$courselevelm}; }
111:
112: if ($useropt{$courselevel}) { return $useropt{$courselevel}; }
113:
114: }
115:
116: # --------------------------------------------------------- third, check course
117:
118: if ($csec) {
119:
120: if ($courseopt{$seclevelr}) { return $courseopt{$seclevelr}; }
121:
122: if ($courseopt{$seclevelm}) { return $courseopt{$seclevelm}; }
123:
124: if ($courseopt{$seclevel}) { return $courseopt{$seclevel}; }
125:
126: }
127:
128: if ($courseopt{$courselevelr}) { return $courseopt{$courselevelr}; }
129:
130: if ($courseopt{$courselevelm}) { return $courseopt{$courselevelm}; }
131:
132: if ($courseopt{$courselevel}) { return $courseopt{$courselevel}; }
133:
134: # ----------------------------------------------------- second, check map parms
135:
136: my $thisparm=$parmhash{$symbparm};
137: if ($thisparm) { return $thisparm; }
138:
139: # -------------------------------------------------------- first, check default
140:
141: return &Apache::lonnet::metadata($fn,$rwhat.'.default');
142:
143: }
144:
145:
146:
1.9 www 147: # ------------------------------------------------------------- Find out status
148:
149: sub astatus {
150: my $rid=shift;
151: my $code=1;
152: my $ctext='';
153: $rid=~/(\d+)\.(\d+)/;
1.10 www 154: my $symb=&Apache::lonnet::declutter($hash{'map_id_'.$1}).'___'.$2.'___'.
155: &Apache::lonnet::declutter($hash{'src_'.$rid});
156: my $duedate=&parmval('0.duedate',$symb);
1.11 ! www 157: my $opendate=&parmval('0.opendate',$symb);
! 158: my $answerdate=&parmval('0.answerdate',$symb);
! 159: my $now=time;
! 160: my $tcode=0;
! 161: if ($now<$duedate) {
! 162: $tcode=2;
! 163: $ctext='Due: '.localtime($duedate);
! 164: if ($now<$opendate) {
! 165: $tcode=1;
! 166: $ctext='Open: '.localtime($opendate);
! 167: }
! 168: if ($duedate-$now<86400) {
! 169: $tcode=4;
! 170: $ctext='Due: '.localtime($duedate);
! 171: }
! 172: } else {
! 173: $tcode=3;
! 174: if ($now<$answerdate) {
! 175: $ctext='Answer: '.localtime($duedate);
! 176: }
1.10 www 177: }
1.9 www 178: my $answer=&Apache::lonnet::reply(
179: "restore:$ENV{'user.domain'}:$ENV{'user.name'}:".
1.10 www 180: $ENV{'request.course.id'}.':'.
181: &Apache::lonnet::escape($symb),
1.9 www 182: "$ENV{'user.home'}");
183: my %returnhash=();
184: map {
185: my ($name,$value)=split(/\=/,$_);
186: $returnhash{&Apache::lonnet::unescape($name)}=
187: &Apache::lonnet::unescape($value);
188: } split(/\&/,$answer);
189: if ($returnhash{'version'}) {
190: my $version;
191: for ($version=1;$version<=$returnhash{'version'};$version++) {
192: map {
193: $returnhash{$_}=$returnhash{$version.':'.$_};
194: } split(/\:/,$returnhash{$version.':keys'});
195: }
196: map {
197: if (($_=~/\.(\w+)\.solved$/) && ($_!~/^\d+\:/)) {
198: my $part=$1;
1.10 www 199: if ($ctext) { $ctext.=', '; }
200: if ($part) {
201: $ctext.='Part '.$part.': ';
202: }
1.9 www 203: if ($returnhash{$_} eq 'correct_by_student') {
204: unless ($code==2) { $code=3; }
1.10 www 205: $ctext.='solved';
1.9 www 206: } elsif ($returnhash{$_} eq 'correct_by_override') {
207: unless ($code==2) { $code=3; }
1.10 www 208: $ctext.='override';
1.9 www 209: } elsif ($returnhash{$_} eq 'incorrect_attempted') {
210: $code=2;
1.10 www 211: $ctext.=
1.11 ! www 212: $returnhash{'resource.'.$part.'.tries'}.'/'.
! 213: &parmval($part.'.maxtries',$symb).' tries';
1.9 www 214: } elsif ($returnhash{$_} eq 'incorrect_by_override') {
215: $code=2;
1.10 www 216: $ctext.='override';
1.9 www 217: } elsif ($returnhash{$_} eq 'excused') {
218: unless ($code==2) { $code=3; }
1.10 www 219: $ctext.='excused';
1.9 www 220: }
221: }
222: } keys %returnhash;
223: }
1.11 ! www 224: return 'p'.$code.$tcode.'"'.$ctext.'"';
1.9 www 225: }
226:
1.2 www 227: # ------------------------------------------------------------ Build page table
228:
229: sub tracetable {
230: my ($sofar,$rid,$beenhere)=@_;
231: my $further=$sofar;
232: unless ($beenhere=~/\&$rid\&/) {
233: $beenhere.=$rid.'&';
234:
235: if (defined($hash{'is_map_'.$rid})) {
1.7 www 236: $sofar++;
237: my $tprefix='';
238: if ($hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$rid}}}
239: eq 'sequence') {
240: $tprefix='h';
241: }
1.6 www 242: if (defined($rows[$sofar])) {
1.7 www 243: $rows[$sofar].='&'.$tprefix.$rid;
1.6 www 244: } else {
1.7 www 245: $rows[$sofar]=$tprefix.$rid;
1.6 www 246: }
1.2 www 247: if ((defined($hash{'map_start_'.$hash{'src_'.$rid}})) &&
1.7 www 248: (defined($hash{'map_finish_'.$hash{'src_'.$rid}})) &&
249: ($tprefix eq 'h')) {
1.2 www 250: my $frid=$hash{'map_finish_'.$hash{'src_'.$rid}};
251: $sofar=
252: &tracetable($sofar,$hash{'map_start_'.$hash{'src_'.$rid}},
253: '&'.$frid.'&');
254: $sofar++;
255: if ($hash{'src_'.$frid}) {
256: my $brepriv=&Apache::lonnet::allowed('bre',$hash{'src_'.$frid});
257: if (($brepriv eq '2') || ($brepriv eq 'F')) {
1.7 www 258: my $pprefix='';
1.9 www 259: if ($hash{'src_'.$frid}=~
260: /\.(problem|exam|quiz|assess|survey|form)$/) {
261: $pprefix=&astatus($frid);
262:
1.7 www 263: }
1.2 www 264: if (defined($rows[$sofar])) {
1.7 www 265: $rows[$sofar].='&'.$pprefix.$frid;
1.2 www 266: } else {
1.7 www 267: $rows[$sofar]=$pprefix.$frid;
1.2 www 268: }
269: }
270: }
271: }
272: } else {
273: $sofar++;
274: if ($hash{'src_'.$rid}) {
275: my $brepriv=&Apache::lonnet::allowed('bre',$hash{'src_'.$rid});
276: if (($brepriv eq '2') || ($brepriv eq 'F')) {
1.7 www 277: my $pprefix='';
1.9 www 278: if ($hash{'src_'.$rid}=~
279: /\.(problem|exam|quiz|assess|survey|form)$/) {
280: $pprefix=&astatus($rid);
1.7 www 281: }
1.2 www 282: if (defined($rows[$sofar])) {
1.7 www 283: $rows[$sofar].='&'.$pprefix.$rid;
1.2 www 284: } else {
1.7 www 285: $rows[$sofar]=$pprefix.$rid;
1.2 www 286: }
287: }
288: }
289: }
290:
291: if (defined($hash{'to_'.$rid})) {
292: my $mincond=1;
293: my $next='';
294: map {
295: my $thiscond=
296: &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$_}});
297: if ($thiscond>=$mincond) {
298: if ($next) {
299: $next.=','.$_.':'.$thiscond;
300: } else {
301: $next=$_.':'.$thiscond;
302: }
303: if ($thiscond>$mincond) { $mincond=$thiscond; }
304: }
305: } split(/\,/,$hash{'to_'.$rid});
306: map {
307: my ($linkid,$condval)=split(/\:/,$_);
308: if ($condval>=$mincond) {
309: my $now=&tracetable($sofar,$hash{'goesto_'.$linkid},$beenhere);
310: if ($now>$further) { $further=$now; }
311: }
312: } split(/\,/,$next);
313:
314: }
315: }
316: return $further;
317: }
318:
319: # ================================================================ Main Handler
1.1 www 320:
321: sub handler {
1.2 www 322: my $r=shift;
323:
324:
325: # ------------------------------------------- Set document type for header only
326:
327: if ($r->header_only) {
328: if ($ENV{'browser.mathml'}) {
329: $r->content_type('text/xml');
330: } else {
331: $r->content_type('text/html');
332: }
333: $r->send_http_header;
334: return OK;
335: }
336:
337: my $requrl=$r->uri;
338: # ----------------------------------------------------------------- Tie db file
339: if ($ENV{'request.course.fn'}) {
340: my $fn=$ENV{'request.course.fn'};
341: if (-e "$fn.db") {
1.10 www 342: if ((tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER,0640)) &&
343: (tie(%parmhash,'GDBM_File',
344: $ENV{'request.course.fn'}.'_parms.db',&GDBM_READER,0640))) {
1.2 www 345: # ------------------------------------------------------------------- Hash tied
346: my $firstres=$hash{'map_start_/res/'.$ENV{'request.course.uri'}};
347: my $lastres=$hash{'map_finish_/res/'.$ENV{'request.course.uri'}};
348: if (($firstres) && ($lastres)) {
349: # ----------------------------------------------------------------- Render page
1.10 www 350: # -------------------------------------------------------------- Set parameters
351:
352:
353: # ---------------------------- initialize coursedata and userdata for this user
354: undef %courseopt;
355: undef %useropt;
356:
357: my $uname=$ENV{'user.name'};
358: my $udom=$ENV{'user.domain'};
359: my $uhome=$ENV{'user.home'};
360: my $cid=$ENV{'request.course.id'};
361: my $chome=$ENV{'course.'.$cid.'.home'};
362: my ($cdom,$cnum)=split(/\_/,$cid);
363:
364: my $userprefix=$uname.'_'.$udom.'_';
365:
366: unless ($uhome eq 'no_host') {
367: # -------------------------------------------------------------- Get coursedata
368: unless
369: ((time-$courserdatas{$cid.'.last_cache'})<240) {
370: my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.
371: ':resourcedata',$chome);
372: if ($reply!~/^error\:/) {
373: $courserdatas{$cid}=$reply;
374: $courserdatas{$cid.'.last_cache'}=time;
375: }
376: }
377: map {
378: my ($name,$value)=split(/\=/,$_);
379: $courseopt{$userprefix.&Apache::lonnet::unescape($name)}=
380: &Apache::lonnet::unescape($value);
381: } split(/\&/,$courserdatas{$cid});
382: # --------------------------------------------------- Get userdata (if present)
383: unless
384: ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) {
385: my $reply=
386: &Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome);
387: if ($reply!~/^error\:/) {
388: $userrdatas{$uname.'___'.$udom}=$reply;
389: $userrdatas{$uname.'___'.$udom.'.last_cache'}=time;
390: }
391: }
392: map {
393: my ($name,$value)=split(/\=/,$_);
394: $useropt{$userprefix.&Apache::lonnet::unescape($name)}=
395: &Apache::lonnet::unescape($value);
396: } split(/\&/,$userrdatas{$uname.'___'.$udom});
397: }
1.2 www 398:
399: @rows=();
400:
401: &tracetable(0,$firstres,'&'.$lastres.'&');
402: if ($hash{'src_'.$lastres}) {
403: my $brepriv=
404: &Apache::lonnet::allowed('bre',$hash{'src_'.$lastres});
405: if (($brepriv eq '2') || ($brepriv eq 'F')) {
406: $rows[$#rows+1]=''.$lastres;
407: }
408: }
409:
410: # ------------------------------------------------------------------ Page parms
411:
412: my $j;
1.5 www 413: my $i;
1.2 www 414: my $lcm=1;
415: my $contents=0;
416:
417: # ---------------------------------------------- Go through table to get layout
418:
419: for ($i=0;$i<=$#rows;$i++) {
420: if ($rows[$i]) {
421: $contents++;
422: my @colcont=split(/\&/,$rows[$i]);
423: $lcm*=($#colcont+1)/euclid($lcm,($#colcont+1));
424: }
425: }
1.5 www 426:
1.2 www 427:
428: unless ($contents) {
429: $r->content_type('text/html');
430: $r->send_http_header;
431: $r->print('<html><body>Empty Map.</body></html>');
432: } else {
1.10 www 433:
1.2 www 434: # ------------------------------------------------------------------ Build page
435:
436: # ---------------------------------------------------------------- Send headers
437:
438: $r->content_type('text/html');
439: $r->send_http_header;
440: $r->print(
441: '<html><head><title>Navigate LON-CAPA Maps</title></head>');
442:
443: $r->print('<body bgcolor="#FFFFFF">'.
1.8 www 444: '<script>window.focus();</script>'.
1.6 www 445: '<img align=right src=/adm/lonIcons/lonlogos.gif>'.
1.2 www 446: '<h1>Navigate Course Map</h1>');
1.3 www 447: $r->rflush();
1.2 www 448: # ----------------------------------------------------------------- Start table
449: $r->print('<table cols="'.$lcm.'" border="0">');
450: for ($i=0;$i<=$#rows;$i++) {
451: if ($rows[$i]) {
452: $r->print("\n<tr>");
453: my @colcont=split(/\&/,$rows[$i]);
454: my $avespan=$lcm/($#colcont+1);
455: for ($j=0;$j<=$#colcont;$j++) {
456: my $rid=$colcont[$j];
1.6 www 457: my $add='<td> ';
1.7 www 458: my $adde='</td>';
459: my $hwk='<font color="#223322">';
460: my $hwke='</font>';
1.6 www 461: if ($rid=~/^h(.+)/) {
462: $rid=$1;
463: $add='<th bgcolor="#AAFF55">';
1.7 www 464: $adde='</th>';
465: }
1.11 ! www 466: if ($rid=~/^p(\d)(\d)\"([\w\: \(\)\/\,]*)\"(.+)/) {
1.7 www 467: my $code=$1;
1.11 ! www 468: my $tcode=$2;
! 469: my $ctext=$3;
! 470: $rid=$4;
! 471: if ($tcode eq '1') {
! 472: $add='<td bgcolor="#AAAAAA">';
! 473: }
! 474: if ($code eq '3') {
! 475: $add='<td bgcolor="#AAFFAA">';
! 476: } else {
! 477: $add='<td bgcolor="#FFAAAA">';
! 478: if ($tcode eq '2') {
! 479: $add='<td bgcolor="#FFFFAA">';
! 480: }
! 481: if ($tcode eq '4') {
! 482: $add='<td bgcolor="#FFFF33"><blink>';
! 483: $adde='</blink></td>';
! 484: }
! 485: }
1.9 www 486: $hwk='<font color="#888811"><b>';
487: $hwke='</b></font>';
1.10 www 488: if ($code eq '1') {
489: $hwke='</b> ('.$ctext.')</font>';
490: }
1.7 www 491: if ($code eq '2') {
1.9 www 492: $hwk='<font color="#992222"><b>';
493: $hwke='</b> ('.$ctext.')</font>';
1.7 www 494: }
495: if ($code eq '3') {
1.9 www 496: $hwk='<font color="#229922"><b>';
497: $hwke='</b> ('.$ctext.')</font>';
1.7 www 498: }
1.6 www 499: }
1.7 www 500: $r->print($add.'<a href="'.$hash{'src_'.$rid}.
501: '">'.$hwk.
502: $hash{'title_'.$rid}.$hwke.'</a>'.$adde);
1.2 www 503: }
504: $r->print('</tr>');
505: }
506: }
507: $r->print("\n</table>");
508:
509: $r->print('</body></html>');
510: # -------------------------------------------------------------------- End page
511: }
512: # ------------------------------------------------------------- End render page
513: } else {
514: $r->content_type('text/html');
515: $r->send_http_header;
516: $r->print('<html><body>Coursemap undefined.</body></html>');
517: }
518: # ------------------------------------------------------------------ Untie hash
519: unless (untie(%hash)) {
520: &Apache::lonnet::logthis("<font color=blue>WARNING: ".
521: "Could not untie coursemap $fn (browse).</font>");
1.10 www 522: }
523: unless (untie(%parmhash)) {
524: &Apache::lonnet::logthis("<font color=blue>WARNING: ".
525: "Could not untie parmhash (browse).</font>");
1.2 www 526: }
527: # -------------------------------------------------------------------- All done
528: return OK;
529: # ----------------------------------------------- Errors, hash could no be tied
530: }
531: }
532: }
1.3 www 533:
1.2 www 534: $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
535: return HTTP_NOT_ACCEPTABLE;
536: }
1.1 www 537:
538: 1;
539: __END__
1.2 www 540:
541:
542:
543:
544:
545:
546:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>