Annotation of loncom/interface/lonnavmaps.pm, revision 1.10

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);
        !           157:     if ($duedate) {
        !           158:        $ctext.='Due: '.localtime($duedate);
        !           159:     }
1.9       www       160:     my $answer=&Apache::lonnet::reply(
                    161:               "restore:$ENV{'user.domain'}:$ENV{'user.name'}:".
1.10    ! www       162:               $ENV{'request.course.id'}.':'.
        !           163:               &Apache::lonnet::escape($symb),
1.9       www       164:               "$ENV{'user.home'}");
                    165:     my %returnhash=();
                    166:     map {
                    167: 	my ($name,$value)=split(/\=/,$_);
                    168:         $returnhash{&Apache::lonnet::unescape($name)}=
                    169:                     &Apache::lonnet::unescape($value);
                    170:     } split(/\&/,$answer);
                    171:     if ($returnhash{'version'}) {
                    172:        my $version;
                    173:        for ($version=1;$version<=$returnhash{'version'};$version++) {
                    174:           map {
                    175:              $returnhash{$_}=$returnhash{$version.':'.$_};
                    176:           } split(/\:/,$returnhash{$version.':keys'});
                    177:        }
                    178:        map {
                    179:            if (($_=~/\.(\w+)\.solved$/) && ($_!~/^\d+\:/)) {
                    180:                my $part=$1;
1.10    ! www       181:                if ($ctext) { $ctext.=', '; }
        !           182:                if ($part) {
        !           183: 		   $ctext.='Part '.$part.': ';
        !           184:                }
1.9       www       185: 	       if ($returnhash{$_} eq 'correct_by_student') {
                    186:                    unless ($code==2) { $code=3; }
1.10    ! www       187:                    $ctext.='solved';
1.9       www       188:                } elsif ($returnhash{$_} eq 'correct_by_override') {
                    189:                    unless ($code==2) { $code=3; }
1.10    ! www       190:                    $ctext.='override';
1.9       www       191:                } elsif ($returnhash{$_} eq 'incorrect_attempted') {
                    192:                    $code=2;
1.10    ! www       193:                    $ctext.=
1.9       www       194:                      $returnhash{'resource.'.$part.'.tries'}.' attempt(s)';
                    195:                } elsif ($returnhash{$_} eq 'incorrect_by_override') {
                    196:                    $code=2;
1.10    ! www       197:                    $ctext.='override';
1.9       www       198:                } elsif ($returnhash{$_} eq 'excused') {
                    199:                    unless ($code==2) { $code=3; }
1.10    ! www       200:                    $ctext.='excused';
1.9       www       201:                }
                    202:            }
                    203:        } keys %returnhash;
                    204:     }
                    205:     return 'p'.$code.'"'.$ctext.'"';
                    206: }
                    207: 
1.2       www       208: # ------------------------------------------------------------ Build page table
                    209: 
                    210: sub tracetable {
                    211:     my ($sofar,$rid,$beenhere)=@_;
                    212:     my $further=$sofar;
                    213:     unless ($beenhere=~/\&$rid\&/) {
                    214:        $beenhere.=$rid.'&';  
                    215: 
                    216:        if (defined($hash{'is_map_'.$rid})) {
1.7       www       217:            $sofar++;
                    218:            my $tprefix='';
                    219:            if ($hash{'map_type_'.$hash{'map_pc_'.$hash{'src_'.$rid}}} 
                    220:             eq 'sequence') { 
                    221:                $tprefix='h'; 
                    222:            }
1.6       www       223:            if (defined($rows[$sofar])) {
1.7       www       224:               $rows[$sofar].='&'.$tprefix.$rid;
1.6       www       225:            } else {
1.7       www       226:               $rows[$sofar]=$tprefix.$rid;
1.6       www       227:            }
1.2       www       228:            if ((defined($hash{'map_start_'.$hash{'src_'.$rid}})) &&
1.7       www       229:                (defined($hash{'map_finish_'.$hash{'src_'.$rid}})) &&
                    230:                ($tprefix eq 'h')) {
1.2       www       231:               my $frid=$hash{'map_finish_'.$hash{'src_'.$rid}};
                    232: 	      $sofar=
                    233:                 &tracetable($sofar,$hash{'map_start_'.$hash{'src_'.$rid}},
                    234:                 '&'.$frid.'&');
                    235:               $sofar++;
                    236:               if ($hash{'src_'.$frid}) {
                    237:                my $brepriv=&Apache::lonnet::allowed('bre',$hash{'src_'.$frid});
                    238:                if (($brepriv eq '2') || ($brepriv eq 'F')) {
1.7       www       239: 		 my $pprefix='';
1.9       www       240:                  if ($hash{'src_'.$frid}=~
                    241:                                  /\.(problem|exam|quiz|assess|survey|form)$/) {
                    242: 		     $pprefix=&astatus($frid);
                    243: 
1.7       www       244:                  }
1.2       www       245:                  if (defined($rows[$sofar])) {
1.7       www       246:                    $rows[$sofar].='&'.$pprefix.$frid;
1.2       www       247:                  } else {
1.7       www       248:                    $rows[$sofar]=$pprefix.$frid;
1.2       www       249:                  }
                    250: 	       }
                    251: 	      }
                    252: 	   }
                    253:        } else {
                    254:           $sofar++;
                    255:           if ($hash{'src_'.$rid}) {
                    256:            my $brepriv=&Apache::lonnet::allowed('bre',$hash{'src_'.$rid});
                    257:            if (($brepriv eq '2') || ($brepriv eq 'F')) {
1.7       www       258: 	     my $pprefix='';
1.9       www       259:              if ($hash{'src_'.$rid}=~
                    260:                                  /\.(problem|exam|quiz|assess|survey|form)$/) {
                    261: 	         $pprefix=&astatus($rid);
1.7       www       262:              }
1.2       www       263:              if (defined($rows[$sofar])) {
1.7       www       264:                 $rows[$sofar].='&'.$pprefix.$rid;
1.2       www       265:              } else {
1.7       www       266:                $rows[$sofar]=$pprefix.$rid;
1.2       www       267:              }
                    268: 	   }
                    269:           }
                    270:        }
                    271: 
                    272:        if (defined($hash{'to_'.$rid})) {
                    273: 	  my $mincond=1;
                    274:           my $next='';
                    275:           map {
                    276:               my $thiscond=
                    277:       &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$_}});
                    278:               if ($thiscond>=$mincond) {
                    279: 		  if ($next) {
                    280: 		      $next.=','.$_.':'.$thiscond;
                    281:                   } else {
                    282:                       $next=$_.':'.$thiscond;
                    283: 		  }
                    284:                   if ($thiscond>$mincond) { $mincond=$thiscond; }
                    285: 	      }
                    286:           } split(/\,/,$hash{'to_'.$rid});
                    287:           map {
                    288:               my ($linkid,$condval)=split(/\:/,$_);
                    289:               if ($condval>=$mincond) {
                    290:                 my $now=&tracetable($sofar,$hash{'goesto_'.$linkid},$beenhere);
                    291:                 if ($now>$further) { $further=$now; }
                    292: 	      }
                    293:           } split(/\,/,$next);
                    294: 
                    295:        }
                    296:     }
                    297:     return $further;
                    298: }
                    299: 
                    300: # ================================================================ Main Handler
1.1       www       301: 
                    302: sub handler {
1.2       www       303:   my $r=shift;
                    304: 
                    305: 
                    306: # ------------------------------------------- Set document type for header only
                    307: 
                    308:   if ($r->header_only) {
                    309:        if ($ENV{'browser.mathml'}) {
                    310:            $r->content_type('text/xml');
                    311:        } else {
                    312:            $r->content_type('text/html');
                    313:        }
                    314:        $r->send_http_header;
                    315:        return OK;
                    316:    }
                    317: 
                    318:   my $requrl=$r->uri;
                    319: # ----------------------------------------------------------------- Tie db file
                    320:   if ($ENV{'request.course.fn'}) {
                    321:       my $fn=$ENV{'request.course.fn'};
                    322:       if (-e "$fn.db") {
1.10    ! www       323:           if ((tie(%hash,'GDBM_File',"$fn.db",&GDBM_READER,0640)) &&
        !           324:              (tie(%parmhash,'GDBM_File',
        !           325:            $ENV{'request.course.fn'}.'_parms.db',&GDBM_READER,0640))) {
1.2       www       326: # ------------------------------------------------------------------- Hash tied
                    327:               my $firstres=$hash{'map_start_/res/'.$ENV{'request.course.uri'}};
                    328:               my $lastres=$hash{'map_finish_/res/'.$ENV{'request.course.uri'}};
                    329:               if (($firstres) && ($lastres)) {
                    330: # ----------------------------------------------------------------- Render page
1.10    ! www       331: # -------------------------------------------------------------- Set parameters
        !           332: 
        !           333: 
        !           334: # ---------------------------- initialize coursedata and userdata for this user
        !           335:     undef %courseopt;
        !           336:     undef %useropt;
        !           337: 
        !           338:     my $uname=$ENV{'user.name'};
        !           339:     my $udom=$ENV{'user.domain'};
        !           340:     my $uhome=$ENV{'user.home'};
        !           341:     my $cid=$ENV{'request.course.id'};
        !           342:     my $chome=$ENV{'course.'.$cid.'.home'};
        !           343:     my ($cdom,$cnum)=split(/\_/,$cid);
        !           344: 
        !           345:     my $userprefix=$uname.'_'.$udom.'_';
        !           346: 
        !           347:     unless ($uhome eq 'no_host') { 
        !           348: # -------------------------------------------------------------- Get coursedata
        !           349:       unless
        !           350:         ((time-$courserdatas{$cid.'.last_cache'})<240) {
        !           351:          my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum.
        !           352:               ':resourcedata',$chome);
        !           353:          if ($reply!~/^error\:/) {
        !           354:             $courserdatas{$cid}=$reply;
        !           355:             $courserdatas{$cid.'.last_cache'}=time;
        !           356:          }
        !           357:       }
        !           358:       map {
        !           359:          my ($name,$value)=split(/\=/,$_);
        !           360:          $courseopt{$userprefix.&Apache::lonnet::unescape($name)}=
        !           361:                     &Apache::lonnet::unescape($value);
        !           362:       } split(/\&/,$courserdatas{$cid});
        !           363: # --------------------------------------------------- Get userdata (if present)
        !           364:       unless
        !           365:         ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) {
        !           366:          my $reply=
        !           367:        &Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome);
        !           368:          if ($reply!~/^error\:/) {
        !           369: 	     $userrdatas{$uname.'___'.$udom}=$reply;
        !           370: 	     $userrdatas{$uname.'___'.$udom.'.last_cache'}=time;
        !           371:          }
        !           372:       }
        !           373:       map {
        !           374:          my ($name,$value)=split(/\=/,$_);
        !           375:          $useropt{$userprefix.&Apache::lonnet::unescape($name)}=
        !           376: 	          &Apache::lonnet::unescape($value);
        !           377:       } split(/\&/,$userrdatas{$uname.'___'.$udom});
        !           378:     }
1.2       www       379: 
                    380:                   @rows=();
                    381: 
                    382:                   &tracetable(0,$firstres,'&'.$lastres.'&');
                    383:                   if ($hash{'src_'.$lastres}) {
                    384:                      my $brepriv=
                    385:                         &Apache::lonnet::allowed('bre',$hash{'src_'.$lastres});
                    386:                      if (($brepriv eq '2') || ($brepriv eq 'F')) {
                    387:                         $rows[$#rows+1]=''.$lastres;
                    388: 		     }
                    389: 		  }
                    390: 
                    391: # ------------------------------------------------------------------ Page parms
                    392: 
                    393:                   my $j;
1.5       www       394:                   my $i;
1.2       www       395:                   my $lcm=1;
                    396:                   my $contents=0;
                    397: 
                    398: # ---------------------------------------------- Go through table to get layout
                    399: 
                    400:                   for ($i=0;$i<=$#rows;$i++) {
                    401: 		     if ($rows[$i]) {
                    402: 		      $contents++;
                    403:                       my @colcont=split(/\&/,$rows[$i]);
                    404:                       $lcm*=($#colcont+1)/euclid($lcm,($#colcont+1));
                    405:                      } 
                    406:                   }
1.5       www       407: 
1.2       www       408: 
                    409:                   unless ($contents) {
                    410:                       $r->content_type('text/html');
                    411:                       $r->send_http_header;
                    412:                       $r->print('<html><body>Empty Map.</body></html>');
                    413:                   } else {
1.10    ! www       414: 
1.2       www       415: # ------------------------------------------------------------------ Build page
                    416: 
                    417: # ---------------------------------------------------------------- Send headers
                    418: 
                    419:                           $r->content_type('text/html');
                    420:                           $r->send_http_header;
                    421:                           $r->print(
                    422:                    '<html><head><title>Navigate LON-CAPA Maps</title></head>');
                    423: 
                    424: 			  $r->print('<body bgcolor="#FFFFFF">'.
1.8       www       425:                                     '<script>window.focus();</script>'.
1.6       www       426:                            '<img align=right src=/adm/lonIcons/lonlogos.gif>'.
1.2       www       427:                                     '<h1>Navigate Course Map</h1>');
1.3       www       428:                           $r->rflush();
1.2       www       429: # ----------------------------------------------------------------- Start table
                    430:                       $r->print('<table cols="'.$lcm.'" border="0">');
                    431:                       for ($i=0;$i<=$#rows;$i++) {
                    432: 			if ($rows[$i]) {
                    433:                           $r->print("\n<tr>");
                    434:                           my @colcont=split(/\&/,$rows[$i]);
                    435:                           my $avespan=$lcm/($#colcont+1);
                    436:                           for ($j=0;$j<=$#colcont;$j++) {
                    437:                               my $rid=$colcont[$j];
1.6       www       438:                               my $add='<td>&nbsp;&nbsp;';
1.7       www       439:                               my $adde='</td>';
                    440:                               my $hwk='<font color="#223322">';
                    441:                               my $hwke='</font>';
1.6       www       442:                               if ($rid=~/^h(.+)/) {
                    443: 				  $rid=$1;
                    444:                                   $add='<th bgcolor="#AAFF55">';
1.7       www       445:                                   $adde='</th>';
                    446:                               }
1.10    ! www       447:                               if ($rid=~/^p(\d)\"([\w\: \(\)\,]*)\"(.+)/) {
1.7       www       448:                                   my $code=$1;
1.9       www       449:                                   my $ctext=$2;
                    450:                                   $rid=$3;
                    451:                                   $hwk='<font color="#888811"><b>';
                    452:                                   $hwke='</b></font>';
1.10    ! www       453:                                   if ($code eq '1') {
        !           454:                                      $hwke='</b> ('.$ctext.')</font>';
        !           455:                                   }
1.7       www       456:                                   if ($code eq '2') {
1.9       www       457:                                      $hwk='<font color="#992222"><b>';
                    458:                                      $hwke='</b> ('.$ctext.')</font>';
1.7       www       459:                                   }
                    460:                                   if ($code eq '3') {
1.9       www       461:                                      $hwk='<font color="#229922"><b>';
                    462:                                      $hwke='</b> ('.$ctext.')</font>';
1.7       www       463:                                   }
1.6       www       464:                               }
1.7       www       465:                               $r->print($add.'<a href="'.$hash{'src_'.$rid}.
                    466:                                 '">'.$hwk.
                    467:                                 $hash{'title_'.$rid}.$hwke.'</a>'.$adde);
1.2       www       468:                           }
                    469:                           $r->print('</tr>');
                    470: 		        }
                    471:                       }
                    472:                       $r->print("\n</table>");
                    473: 
                    474:                       $r->print('</body></html>');
                    475: # -------------------------------------------------------------------- End page
                    476:                   }                  
                    477: # ------------------------------------------------------------- End render page
                    478:               } else {
                    479:                   $r->content_type('text/html');
                    480:                   $r->send_http_header;
                    481: 		  $r->print('<html><body>Coursemap undefined.</body></html>');
                    482:               }
                    483: # ------------------------------------------------------------------ Untie hash
                    484:               unless (untie(%hash)) {
                    485:                    &Apache::lonnet::logthis("<font color=blue>WARNING: ".
                    486:                        "Could not untie coursemap $fn (browse).</font>"); 
1.10    ! www       487:               }
        !           488:               unless (untie(%parmhash)) {
        !           489:                    &Apache::lonnet::logthis("<font color=blue>WARNING: ".
        !           490:                        "Could not untie parmhash (browse).</font>"); 
1.2       www       491:               }
                    492: # -------------------------------------------------------------------- All done
                    493: 	      return OK;
                    494: # ----------------------------------------------- Errors, hash could no be tied
                    495:           }
                    496:       } 
                    497:   }
1.3       www       498: 
1.2       www       499:   $ENV{'user.error.msg'}="$requrl:bre:0:0:Course not initialized";
                    500:   return HTTP_NOT_ACCEPTABLE; 
                    501: }
1.1       www       502: 
                    503: 1;
                    504: __END__
1.2       www       505: 
                    506: 
                    507: 
                    508: 
                    509: 
                    510: 
                    511: 

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