--- loncom/interface/lonnavmaps.pm 2001/01/30 22:26:33 1.12 +++ loncom/interface/lonnavmaps.pm 2002/02/14 22:13:36 1.26 @@ -1,6 +1,30 @@ # The LearningOnline Network with CAPA # Navigate Maps Handler # +# $Id: lonnavmaps.pm,v 1.26 2002/02/14 22:13:36 harris41 Exp $ +# +# Copyright Michigan State University Board of Trustees +# +# This file is part of the LearningOnline Network with CAPA (LON-CAPA). +# +# LON-CAPA is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# LON-CAPA is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with LON-CAPA; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +# /home/httpd/html/adm/gpl.txt +# +# http://www.lon-capa.org/ +# # (Page Handler # # (TeX Content Handler @@ -9,13 +33,17 @@ # 08/30,08/31,09/06,09/14,09/15,09/16,09/19,09/20,09/21,09/23, # 10/02,10/10,10/14,10/16,10/18,10/19,10/31,11/6,11/14,11/16 Gerd Kortemeyer) # -# 3/1/1,6/1,17/1,29/1,30/1 Gerd Kortemeyer +# 3/1/1,6/1,17/1,29/1,30/1,2/8,9/21,9/24,9/25 Gerd Kortemeyer +# YEAR=2002 +# 1/1 Gerd Kortemeyer +# package Apache::lonnavmaps; use strict; use Apache::Constants qw(:common :http); use Apache::lonnet(); +use Apache::loncommon(); use HTML::TokeParser; use GDBM_File; @@ -39,7 +67,6 @@ my %courseopt; my %useropt; my %parmhash; - # ------------------------------------------------------------------ Euclid gcd sub euclid { @@ -76,155 +103,164 @@ sub parmval { my ($mapname,$id,$fn)=split(/\_\_\_/,$symb); # ----------------------------------------------------- Cascading lookup scheme - my $rwhat=$what; - $what=~s/^parameter\_//; - $what=~s/\_/\./; - - my $symbparm=$symb.'.'.$what; - my $mapparm=$mapname.'___(all).'.$what; - my $usercourseprefix=$uname.'_'.$udom.'_'.$cid; - - my $seclevel= - $usercourseprefix.'.['. - $csec.'].'.$what; - my $seclevelr= - $usercourseprefix.'.['. - $csec.'].'.$symbparm; - my $seclevelm= - $usercourseprefix.'.['. - $csec.'].'.$mapparm; - - my $courselevel= - $usercourseprefix.'.'.$what; - my $courselevelr= - $usercourseprefix.'.'.$symbparm; - my $courselevelm= - $usercourseprefix.'.'.$mapparm; - -# ---------------------------------------------------------- fourth, check user - - if ($uname) { - - if ($useropt{$courselevelr}) { return $useropt{$courselevelr}; } - - if ($useropt{$courselevelm}) { return $useropt{$courselevelm}; } - - if ($useropt{$courselevel}) { return $useropt{$courselevel}; } - - } - -# --------------------------------------------------------- third, check course - - if ($csec) { - - if ($courseopt{$seclevelr}) { return $courseopt{$seclevelr}; } - - if ($courseopt{$seclevelm}) { return $courseopt{$seclevelm}; } + my $rwhat=$what; + $what=~s/^parameter\_//; + $what=~s/\_/\./; + + my $symbparm=$symb.'.'.$what; + my $mapparm=$mapname.'___(all).'.$what; + my $usercourseprefix=$uname.'_'.$udom.'_'.$cid; + + my $seclevel= $usercourseprefix.'.['.$csec.'].'.$what; + my $seclevelr=$usercourseprefix.'.['.$csec.'].'.$symbparm; + my $seclevelm=$usercourseprefix.'.['.$csec.'].'.$mapparm; + + my $courselevel= $usercourseprefix.'.'.$what; + my $courselevelr=$usercourseprefix.'.'.$symbparm; + my $courselevelm=$usercourseprefix.'.'.$mapparm; + +# ---------------------------------------------------------- first, check user + if ($uname) { + if ($useropt{$courselevelr}) { return $useropt{$courselevelr}; } + if ($useropt{$courselevelm}) { return $useropt{$courselevelm}; } + if ($useropt{$courselevel}) { return $useropt{$courselevel}; } + } +# ------------------------------------------------------- second, check course + if ($csec) { + if ($courseopt{$seclevelr}) { return $courseopt{$seclevelr}; } + if ($courseopt{$seclevelm}) { return $courseopt{$seclevelm}; } if ($courseopt{$seclevel}) { return $courseopt{$seclevel}; } - - } - - if ($courseopt{$courselevelr}) { return $courseopt{$courselevelr}; } - - if ($courseopt{$courselevelm}) { return $courseopt{$courselevelm}; } - - if ($courseopt{$courselevel}) { return $courseopt{$courselevel}; } - -# ----------------------------------------------------- second, check map parms - - my $thisparm=$parmhash{$symbparm}; - if ($thisparm) { return $thisparm; } - -# -------------------------------------------------------- first, check default + } - return &Apache::lonnet::metadata($fn,$rwhat.'.default'); - + if ($courseopt{$courselevelr}) { return $courseopt{$courselevelr}; } + if ($courseopt{$courselevelm}) { return $courseopt{$courselevelm}; } + if ($courseopt{$courselevel}) { return $courseopt{$courselevel}; } + +# ----------------------------------------------------- third, check map parms + + my $thisparm=$parmhash{$symbparm}; + if ($thisparm) { return $thisparm; } + +# ----------------------------------------------------- fourth , check default + + my $default=&Apache::lonnet::metadata($fn,$rwhat.'.default'); + if ($default) { return $default} + +# --------------------------------------------------- fifth , cascade up parts + + my ($space,@qualifier)=split(/\./,$rwhat); + my $qualifier=join('.',@qualifier); + unless ($space eq '0') { + my ($part,$id)=split(/\_/,$space); + if ($id) { + my $partgeneral=&parmval($part.".$qualifier",$symb); + if ($partgeneral) { return $partgeneral; } + } else { + my $resourcegeneral=&parmval("0.$qualifier",$symb); + if ($resourcegeneral) { return $resourcegeneral; } + } + } + return ''; } # ------------------------------------------------------------- Find out status - +# return codes +# tcode (timecode) +# 1: will open later +# 2: is open and not past due yet +# 3: is past due date +# 4: due in the next 24 hours +# +# code (curent solved status) +# 1: not attempted +# 2: attempted but wrong, or incorrect by instructor +# 3: solved or correct by instructor +# "excused" needs to be supported, but is not yet. Could be code=4. sub astatus { my $rid=shift; my $code=1; my $ctext=''; $rid=~/(\d+)\.(\d+)/; my $symb=&Apache::lonnet::declutter($hash{'map_id_'.$1}).'___'.$2.'___'. - &Apache::lonnet::declutter($hash{'src_'.$rid}); - my $duedate=&parmval('0.duedate',$symb); - my $opendate=&parmval('0.opendate',$symb); - my $answerdate=&parmval('0.answerdate',$symb); - my $now=time; - my $tcode=0; - if ($opendate) { - if ($now<$duedate) { - $tcode=2; - $ctext='Due: '.localtime($duedate); - if ($now<$opendate) { - $tcode=1; - $ctext='Open: '.localtime($opendate); + &Apache::lonnet::declutter($hash{'src_'.$rid}); + $Apache::lonxml::debug=1; + my %duedate=(); + my %opendate=(); + my %answerdate=(); + # need to always check part 0's open/due/answer status + foreach (sort(split(/\,/,&Apache::lonnet::metadata($hash{'src_'.$rid},'keys')))) { + if ($_=~/^parameter\_(.*)\_opendate$/) { + my $part=$1; + $duedate{$part}=&parmval($part.'.duedate',$symb); + $opendate{$part}=&parmval($part.'.opendate',$symb); + $answerdate{$part}=&parmval($part.'.answerdate',$symb); } - if ($duedate-$now<86400) { - $tcode=4; - $ctext='Due: '.localtime($duedate); - } - } else { - $tcode=3; - if ($now<$answerdate) { - $ctext='Answer: '.localtime($duedate); - } } - } else { - $tcode=1; - } - my $answer=&Apache::lonnet::reply( - "restore:$ENV{'user.domain'}:$ENV{'user.name'}:". - $ENV{'request.course.id'}.':'. - &Apache::lonnet::escape($symb), - "$ENV{'user.home'}"); - my %returnhash=(); - map { - my ($name,$value)=split(/\=/,$_); - $returnhash{&Apache::lonnet::unescape($name)}= - &Apache::lonnet::unescape($value); - } split(/\&/,$answer); - if ($returnhash{'version'}) { - my $version; - for ($version=1;$version<=$returnhash{'version'};$version++) { - map { - $returnhash{$_}=$returnhash{$version.':'.$_}; - } split(/\:/,$returnhash{$version.':keys'}); - } - map { - if (($_=~/\.(\w+)\.solved$/) && ($_!~/^\d+\:/)) { - my $part=$1; - if ($ctext) { $ctext.=', '; } - if ($part) { - $ctext.='Part '.$part.': '; - } - if ($returnhash{$_} eq 'correct_by_student') { - unless ($code==2) { $code=3; } - $ctext.='solved'; - } elsif ($returnhash{$_} eq 'correct_by_override') { - unless ($code==2) { $code=3; } - $ctext.='override'; - } elsif ($returnhash{$_} eq 'incorrect_attempted') { - $code=2; - $ctext.= - $returnhash{'resource.'.$part.'.tries'}.'/'. - &parmval($part.'.maxtries',$symb).' tries'; - } elsif ($returnhash{$_} eq 'incorrect_by_override') { - $code=2; - $ctext.='override'; - } elsif ($returnhash{$_} eq 'excused') { - unless ($code==2) { $code=3; } - $ctext.='excused'; - } - } - } keys %returnhash; + my $now=time; + my $tcode=0; + + my %returnhash=&Apache::lonnet::restore($symb); + + foreach (sort(keys(%opendate))) { + my $duedate=$duedate{$_}; + my $opendate=$opendate{$_}; + my $answerdate=$answerdate{$_}; + my $preface=''; + unless ($_ eq '0') { $preface=' Part: '.$_.' '; } + if ($opendate) { + if ($now<$duedate || (!$duedate)) { + unless ($tcode==4) { $tcode=2; } + if ($duedate) { + $ctext.=$preface.'Due: '.localtime($duedate); + } else { + $ctext.=$preface.'No Due Date'; + } + if ($now<$opendate) { + unless ($tcode) { $tcode=1; } + $ctext.=$preface.'Open: '.localtime($opendate); + } + if ($duedate && $duedate-$now<86400) { + $tcode=4; + $ctext.=$preface.'Due: '.localtime($duedate); + } + } else { + unless (($tcode==4) || ($tcode eq 2)) { $tcode=3; } + if ($now<$answerdate) { + $ctext.='Answer: '.localtime($duedate); + } + } + } else { + unless (($tcode==2) || ($tcode==4)) { $tcode=1; } + } + + my $status=$returnhash{'resource.'.$_.'.solved'}; + + if ($status eq 'correct_by_student') { + unless ($code==2) { $code=3; } + $ctext.=' solved'; + } elsif ($status eq 'correct_by_override') { + unless ($code==2) { $code=3; } + $ctext.=' override'; + } elsif ($status eq 'incorrect_attempted') { + $code=2; + $ctext.=' ('. + ($returnhash{'resource.'.$_.'.tries'}? + $returnhash{'resource.'.$_.'.tries'}:'0'); + my $numtries = &parmval($_.'.maxtries',$symb); + if ($numtries) { $ctext.='/'.$numtries.' tries'; } + $ctext.=')'; + } elsif ($status eq 'incorrect_by_override') { + $code=2; + $ctext.=' override'; + } elsif ($status eq 'excused') { + unless ($code==2) { $code=3; } + $ctext.=' excused'; + } } + return 'p'.$code.$tcode.'"'.$ctext.'"'; } @@ -295,7 +331,7 @@ sub tracetable { if (defined($hash{'to_'.$rid})) { my $mincond=1; my $next=''; - map { + foreach (split(/\,/,$hash{'to_'.$rid})) { my $thiscond= &Apache::lonnet::directcondval($hash{'condid_'.$hash{'undercond_'.$_}}); if ($thiscond>=$mincond) { @@ -306,14 +342,14 @@ sub tracetable { } if ($thiscond>$mincond) { $mincond=$thiscond; } } - } split(/\,/,$hash{'to_'.$rid}); - map { + } + foreach (split(/\,/,$next)) { my ($linkid,$condval)=split(/\:/,$_); if ($condval>=$mincond) { my $now=&tracetable($sofar,$hash{'goesto_'.$linkid},$beenhere); if ($now>$further) { $further=$now; } } - } split(/\,/,$next); + } } } @@ -337,7 +373,6 @@ sub handler { $r->send_http_header; return OK; } - my $requrl=$r->uri; # ----------------------------------------------------------------- Tie db file if ($ENV{'request.course.fn'}) { @@ -378,11 +413,11 @@ sub handler { $courserdatas{$cid.'.last_cache'}=time; } } - map { + foreach (split(/\&/,$courserdatas{$cid})) { my ($name,$value)=split(/\=/,$_); $courseopt{$userprefix.&Apache::lonnet::unescape($name)}= &Apache::lonnet::unescape($value); - } split(/\&/,$courserdatas{$cid}); + } # --------------------------------------------------- Get userdata (if present) unless ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) { @@ -393,11 +428,11 @@ sub handler { $userrdatas{$uname.'___'.$udom.'.last_cache'}=time; } } - map { + foreach (split(/\&/,$userrdatas{$uname.'___'.$udom})) { my ($name,$value)=split(/\=/,$_); $useropt{$userprefix.&Apache::lonnet::unescape($name)}= &Apache::lonnet::unescape($value); - } split(/\&/,$userrdatas{$uname.'___'.$udom}); + } } @rows=(); @@ -437,20 +472,99 @@ sub handler { # ------------------------------------------------------------------ Build page + my $currenturl=$ENV{'form.postdata'}; + $currenturl=~s/^http\:\/\///; + $currenturl=~s/^[^\/]+//; + # ---------------------------------------------------------------- Send headers $r->content_type('text/html'); + &Apache::loncommon::no_cache($r); $r->send_http_header; - $r->print( - 'Navigate LON-CAPA Maps'); - $r->print(''. - ''. + my $date=localtime; + my $now=time; +# ----------------------------------------- Get email status and discussiontime + + my %emailstatus=&Apache::lonnet::dump('email_status'); + my $logouttime=$emailstatus{'logout'}; + my $courseleave= + $emailstatus{'logout_'.$ENV{'request.course.id'}}; + my $lastcheck= + ($courseleave>$logouttime?$courseleave:$logouttime); + + my %discussiontimes=&Apache::lonnet::dump( + 'discussiontimes', + $ENV{'course.'.$ENV{'request.course.id'}.'.domain'}, + $ENV{'course.'.$ENV{'request.course.id'}.'.num'}); + + my %feedback=(); + my %error=(); + foreach my $msgid ( + split(/\&/,&Apache::lonnet::reply('keys:'. + $ENV{'user.domain'}.':'. + $ENV{'user.name'}.':nohist_email', + $ENV{'user.home'}))) { + $msgid=&Apache::lonnet::unescape($msgid); + my $plain=&Apache::lonnet::unescape( + &Apache::lonnet::unescape($msgid)); + if ($plain=~/(Error|Feedback) \[([^\]]+)\]/) { + my ($what,$url)=($1,$2); + my %status= + &Apache::lonnet::get('email_status',[$msgid]); + if ($status{$msgid}=~/^error\:/) { + $status{$msgid}=''; + } + + if (($status{$msgid} eq 'new') || + (!$status{$msgid})) { + if ($what eq 'Error') { + $error{$url}.=','.$msgid; + } else { + $feedback{$url}.=','.$msgid; + } + } + } + } +# ----------------------------------------------------------- Start Page Output + $r->print( + 'Navigate LON-CAPA Maps'); + $r->print('print(' onLoad="window.location.hash='. + "'curloc'".'"'); + } + $r->print('>'. ''. - '

Navigate Course Map

'); - $r->rflush(); + '

Navigate Course Map

'. + "

$date

"); + $r->rflush(); + $r->print( + ' New discussion since '. + localtime($lastcheck). + '
New message (click to open)

'); + if (($currenturl=~/^\/res/) && + ($currenturl!~/^\/res\/adm/)) { + $r->print('Current Location

'); + } +# ----------------------------------------------------- The little content list + for ($i=0;$i<=$#rows;$i++) { + if ($rows[$i]) { + my @colcont=split(/\&/,$rows[$i]); + my $avespan=$lcm/($#colcont+1); + for ($j=0;$j<=$#colcont;$j++) { + my $rid=$colcont[$j]; + if ($rid=~/^h(.+)/) { + $rid=$1; + $r->print( + '   '.$hash{'title_'.$rid}.'
'); + } + } + } + } # ----------------------------------------------------------------- Start table - $r->print(''); + $r->print('
'); for ($i=0;$i<=$#rows;$i++) { if ($rows[$i]) { $r->print("\n"); @@ -464,10 +578,12 @@ sub handler { my $hwke=''; if ($rid=~/^h(.+)/) { $rid=$1; - $add=''; } if ($rid=~/^p(\d)(\d)\"([\w\: \(\)\/\,]*)\"(.+)/) { + # sub astatus describes what code/tcode mean my $code=$1; my $tcode=$2; my $ctext=$3; @@ -483,8 +599,8 @@ sub handler { $add=''; + $add=''; } } $hwk=''; @@ -501,6 +617,44 @@ sub handler { $hwke=' ('.$ctext.')'; } } + if ($hash{'src_'.$rid} eq $currenturl) { + $add=$add.''. + '> '; + $adde= + ' <'.$adde; + } + my $src= + &Apache::lonnet::declutter($hash{'src_'.$rid}); + $rid=~/^(\d+)\.(\d+)$/; + my $symb= + &Apache::lonnet::declutter($hash{'map_id_'.$1}).'___'.$2.'___'.$src; + if ($discussiontimes{$symb}>$lastcheck) { + $adde= + ''. + $adde; + } + if ($error{$src}) { + foreach (split(/\,/,$error{$src})) { + if ($_) { + $adde= + ' ' + .$adde; + } + } + } + if ($feedback{$src}) { + foreach (split(/\,/,$feedback{$src})) { + if ($_) { + $adde= + ' ' + .$adde; + } + } + } $r->print($add.''.$hwk. $hash{'title_'.$rid}.$hwke.''.$adde); @@ -509,7 +663,6 @@ sub handler { } } $r->print("\n
'; + $add= + ''; $adde=''; } if ($tcode eq '4') { - $add=''; - $adde=''; + $adde='
"); - $r->print(''); # -------------------------------------------------------------------- End page }