--- loncom/interface/lonnavmaps.pm 2003/08/21 18:29:54 1.219.2.1 +++ loncom/interface/lonnavmaps.pm 2003/08/07 17:26:44 1.221 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Navigate Maps Handler # -# $Id: lonnavmaps.pm,v 1.219.2.1 2003/08/21 18:29:54 albertel Exp $ +# $Id: lonnavmaps.pm,v 1.221 2003/08/07 17:26:44 bowersj2 Exp $ # # Copyright Michigan State University Board of Trustees # @@ -129,9 +129,7 @@ sub real_handler { $r->send_http_header; # Create the nav map - my $navmap = Apache::lonnavmaps::navmap->new( - $ENV{"request.course.fn"}.".db", - $ENV{"request.course.fn"}."_parms.db", 1, 1); + my $navmap = Apache::lonnavmaps::navmap->new(); if (!defined($navmap)) { @@ -161,11 +159,6 @@ sub real_handler { $r->rflush(); - # Now that we've displayed some stuff to the user, init the navmap - $navmap->init(); - - $r->rflush(); - # Check that it's defined if (!($navmap->courseMapDefined())) { $r->print('Coursemap undefined.' . @@ -1172,12 +1165,9 @@ sub render { if (!$ENV{'form.folderManip'} && !defined($args->{'iterator'})) { # Step 1: Check to see if we have a navmap if (!defined($navmap)) { - $navmap = Apache::lonnavmaps::navmap->new( - $ENV{"request.course.fn"}.".db", - $ENV{"request.course.fn"}."_parms.db", 1, 1); + $navmap = Apache::lonnavmaps::navmap->new(); $mustCloseNavMap = 1; } - $navmap->init(); # Step two: Locate what kind of here marker is necessary # Determine where the "here" marker is and where the screen jumps to. @@ -1238,13 +1228,9 @@ sub render { # Step 1: Check to see if we have a navmap if (!defined($navmap)) { - $navmap = Apache::lonnavmaps::navmap->new($r, - $ENV{"request.course.fn"}.".db", - $ENV{"request.course.fn"}."_parms.db", 1, 1); + $navmap = Apache::lonnavmaps::navmap->new(); $mustCloseNavMap = 1; } - # Paranoia: Make sure it's ready - $navmap->init(); # See if we're being passed a specific map if ($args->{'iterator_map'}) { @@ -1646,29 +1632,13 @@ To create a navmap object, use the follo =over 4 -=item * Bnew>(navHashFile, parmHashFile, - genCourseAndUserOptions, genMailDiscussStatus, getUserData): +=item * Bnew>(): -Binds a new navmap object to the compiled nav map hash and parm hash -given as filenames. genCourseAndUserOptions is a flag saying whether -the course options and user options hash should be generated. This is -for when you are using the parameters of the resources that require -them; see documentation in resource object -documentation. genMailDiscussStatus causes the nav map to retreive -information about the email and discussion status of -resources. Returns the navmap object if this is successful, or -B if not. You must check for undef; errors will occur when you -try to use the other methods otherwise. getUserData, if true, will -retreive the user's performance data for various problems. +Creates a new navmap object. Returns the navmap object if this is +successful, or B if not. =back -Once you have the $navmap object, call ->init() on it when you are ready -to use it. This allows you to check if the course map is defined (see -B below) before engaging in potentially expensive -initialization routines for the genCourseAndUserOptions and -genMailDiscussStatus option. - When you are done with the $navmap object, you I call $navmap->untieHashes(), or you'll prevent the current user from using that course until the web server is restarted. (!) @@ -1692,12 +1662,6 @@ sub new { my $class = ref($proto) || $proto; my $self = {}; - $self->{NAV_HASH_FILE} = shift; - $self->{PARM_HASH_FILE} = shift; - $self->{GENERATE_COURSE_USER_OPT} = shift; - $self->{GENERATE_EMAIL_DISCUSS_STATUS} = shift; - $self->{GET_USER_DATA} = shift; - # Resource cache stores navmap resources as we reference them. We generate # them on-demand so we don't pay for creating resources unless we use them. $self->{RESOURCE_CACHE} = {}; @@ -1710,12 +1674,13 @@ sub new { my %navmaphash; my %parmhash; - if (!(tie(%navmaphash, 'GDBM_File', $self->{NAV_HASH_FILE}, + my $courseFn = $ENV{"request.course.fn"}; + if (!(tie(%navmaphash, 'GDBM_File', "${courseFn}.db", &GDBM_READER(), 0640))) { return undef; } - if (!(tie(%parmhash, 'GDBM_File', $self->{PARM_HASH_FILE}, + if (!(tie(%parmhash, 'GDBM_File', "${courseFn}_parms.db", &GDBM_READER(), 0640))) { untie %{$self->{PARM_HASH}}; @@ -1724,128 +1689,134 @@ sub new { $self->{NAV_HASH} = \%navmaphash; $self->{PARM_HASH} = \%parmhash; - $self->{INITED} = 0; + $self->{PARM_CACHE} = {}; bless($self); return $self; } -sub init { +sub generate_course_user_opt { my $self = shift; - if ($self->{INITED}) { return; } + if ($self->{COURSE_USER_OPT_GENERATED}) { return; } - # If the course opt hash and the user opt hash should be generated, - # generate them - if ($self->{GENERATE_COURSE_USER_OPT}) { - my $uname=$ENV{'user.name'}; - my $udom=$ENV{'user.domain'}; - my $uhome=$ENV{'user.home'}; - my $cid=$ENV{'request.course.id'}; - my $chome=$ENV{'course.'.$cid.'.home'}; - my ($cdom,$cnum)=split(/\_/,$cid); - - my $userprefix=$uname.'_'.$udom.'_'; - - my %courserdatas; my %useropt; my %courseopt; my %userrdatas; - unless ($uhome eq 'no_host') { + my $uname=$ENV{'user.name'}; + my $udom=$ENV{'user.domain'}; + my $uhome=$ENV{'user.home'}; + my $cid=$ENV{'request.course.id'}; + my $chome=$ENV{'course.'.$cid.'.home'}; + my ($cdom,$cnum)=split(/\_/,$cid); + + my $userprefix=$uname.'_'.$udom.'_'; + + my %courserdatas; my %useropt; my %courseopt; my %userrdatas; + unless ($uhome eq 'no_host') { # ------------------------------------------------- Get coursedata (if present) - unless ((time-$courserdatas{$cid.'.last_cache'})<240) { - my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum. - ':resourcedata',$chome); - # Check for network failure - if ( $reply =~ /no.such.host/i || $reply =~ /con_lost/i) { - $self->{NETWORK_FAILURE} = 1; - } elsif ($reply!~/^error\:/) { - $courserdatas{$cid}=$reply; - $courserdatas{$cid.'.last_cache'}=time; - } - } - foreach (split(/\&/,$courserdatas{$cid})) { - my ($name,$value)=split(/\=/,$_); - $courseopt{$userprefix.&Apache::lonnet::unescape($name)}= - &Apache::lonnet::unescape($value); - } + unless ((time-$courserdatas{$cid.'.last_cache'})<240) { + my $reply=&Apache::lonnet::reply('dump:'.$cdom.':'.$cnum. + ':resourcedata',$chome); + # Check for network failure + if ( $reply =~ /no.such.host/i || $reply =~ /con_lost/i) { + $self->{NETWORK_FAILURE} = 1; + } elsif ($reply!~/^error\:/) { + $courserdatas{$cid}=$reply; + $courserdatas{$cid.'.last_cache'}=time; + } + } + foreach (split(/\&/,$courserdatas{$cid})) { + my ($name,$value)=split(/\=/,$_); + $courseopt{$userprefix.&Apache::lonnet::unescape($name)}= + &Apache::lonnet::unescape($value); + } # --------------------------------------------------- Get userdata (if present) - unless ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) { - my $reply=&Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome); - if ($reply!~/^error\:/) { - $userrdatas{$uname.'___'.$udom}=$reply; - $userrdatas{$uname.'___'.$udom.'.last_cache'}=time; - } - # check to see if network failed - elsif ( $reply=~/no.such.host/i || $reply=~/con.*lost/i ) - { - $self->{NETWORK_FAILURE} = 1; - } - } - foreach (split(/\&/,$userrdatas{$uname.'___'.$udom})) { - my ($name,$value)=split(/\=/,$_); - $useropt{$userprefix.&Apache::lonnet::unescape($name)}= - &Apache::lonnet::unescape($value); - } - $self->{COURSE_OPT} = \%courseopt; - $self->{USER_OPT} = \%useropt; - } - } - - if ($self->{GENERATE_EMAIL_DISCUSS_STATUS}) { - my $cid=$ENV{'request.course.id'}; - my ($cdom,$cnum)=split(/\_/,$cid); - - my %emailstatus = &Apache::lonnet::dump('email_status'); - my $logoutTime = $emailstatus{'logout'}; - my $courseLeaveTime = $emailstatus{'logout_'.$ENV{'request.course.id'}}; - $self->{LAST_CHECK} = (($courseLeaveTime > $logoutTime) ? - $courseLeaveTime : $logoutTime); - my %discussiontime = &Apache::lonnet::dump('discussiontimes', - $cdom, $cnum); - my %feedback=(); - my %error=(); - my $keys = &Apache::lonnet::reply('keys:'. - $ENV{'user.domain'}.':'. - $ENV{'user.name'}.':nohist_email', - $ENV{'user.home'}); - - foreach my $msgid (split(/\&/, $keys)) { - $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; - } - } - } - } - - $self->{FEEDBACK} = \%feedback; - $self->{ERROR_MSG} = \%error; # what is this? JB - $self->{DISCUSSION_TIME} = \%discussiontime; - $self->{EMAIL_STATUS} = \%emailstatus; - + unless ((time-$userrdatas{$uname.'___'.$udom.'.last_cache'})<240) { + my $reply=&Apache::lonnet::reply('dump:'.$udom.':'.$uname.':resourcedata',$uhome); + if ($reply!~/^error\:/) { + $userrdatas{$uname.'___'.$udom}=$reply; + $userrdatas{$uname.'___'.$udom.'.last_cache'}=time; + } + # check to see if network failed + elsif ( $reply=~/no.such.host/i || $reply=~/con.*lost/i ) + { + $self->{NETWORK_FAILURE} = 1; + } + } + foreach (split(/\&/,$userrdatas{$uname.'___'.$udom})) { + my ($name,$value)=split(/\=/,$_); + $useropt{$userprefix.&Apache::lonnet::unescape($name)}= + &Apache::lonnet::unescape($value); + } + $self->{COURSE_OPT} = \%courseopt; + $self->{USER_OPT} = \%useropt; } - if ($self->{GET_USER_DATA}) { - # Retreive performance data on problems - my %student_data = Apache::lonnet::currentdump($ENV{'request.course.id'}, - $ENV{'user.domain'}, - $ENV{'user.name'}); - $self->{STUDENT_DATA} = \%student_data; + $self->{COURSE_USER_OPT_GENERATED} = 1; + + return; +} + +sub generate_email_discuss_status { + my $self = shift; + if ($self->{EMAIL_DISCUSS_GENERATED}) { return; } + + my $cid=$ENV{'request.course.id'}; + my ($cdom,$cnum)=split(/\_/,$cid); + + my %emailstatus = &Apache::lonnet::dump('email_status'); + my $logoutTime = $emailstatus{'logout'}; + my $courseLeaveTime = $emailstatus{'logout_'.$ENV{'request.course.id'}}; + $self->{LAST_CHECK} = (($courseLeaveTime > $logoutTime) ? + $courseLeaveTime : $logoutTime); + my %discussiontime = &Apache::lonnet::dump('discussiontimes', + $cdom, $cnum); + my %feedback=(); + my %error=(); + my $keys = &Apache::lonnet::reply('keys:'. + $ENV{'user.domain'}.':'. + $ENV{'user.name'}.':nohist_email', + $ENV{'user.home'}); + + foreach my $msgid (split(/\&/, $keys)) { + $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; + } + } + } } + + $self->{FEEDBACK} = \%feedback; + $self->{ERROR_MSG} = \%error; # what is this? JB + $self->{DISCUSSION_TIME} = \%discussiontime; + $self->{EMAIL_STATUS} = \%emailstatus; + + $self->{EMAIL_DISCUSS_GENERATED} = 1; +} - $self->{PARM_CACHE} = {}; - $self->{INITED} = 1; +sub get_user_data { + my $self = shift; + if ($self->{RETRIEVED_USER_DATA}) { return; } + + # Retrieve performance data on problems + my %student_data = Apache::lonnet::currentdump($ENV{'request.course.id'}, + $ENV{'user.domain'}, + $ENV{'user.name'}); + $self->{STUDENT_DATA} = \%student_data; + + $self->{RETRIEVED_USER_DATA} = 1; } # Internal function: Takes a key to look up in the nav hash and implements internal @@ -1893,6 +1864,9 @@ sub untieHashes { sub hasDiscussion { my $self = shift; my $symb = shift; + + $self->generate_email_discuss_status(); + if (!defined($self->{DISCUSSION_TIME})) { return 0; } #return defined($self->{DISCUSSION_TIME}->{$symb}); @@ -1907,6 +1881,8 @@ sub getFeedback { my $self = shift; my $symb = shift; + $self->generate_email_discuss_status(); + if (!defined($self->{FEEDBACK})) { return ""; } return $self->{FEEDBACK}->{$symb}; @@ -1916,7 +1892,9 @@ sub getFeedback { sub getErrors { my $self = shift; my $src = shift; - + + $self->generate_email_discuss_status(); + if (!defined($self->{ERROR_MSG})) { return ""; } return $self->{ERROR_MSG}->{$src}; } @@ -2029,6 +2007,9 @@ sub parmval_real { my $self = shift; my ($what,$symb,$recurse) = @_; + # Make sure the {USER_OPT} and {COURSE_OPT} hashes are populated + $self->generate_course_user_opt(); + my $cid=$ENV{'request.course.id'}; my $csec=$ENV{'request.course.sec'}; my $uname=$ENV{'user.name'}; @@ -3307,6 +3288,7 @@ sub answerdate { } sub awarded { my $self = shift; my $part = shift; + $self->{NAV_MAP}->get_user_data(); if (!defined($part)) { $part = '0'; } return $self->{NAV_MAP}->{STUDENT_DATA}->{$self->symb()}->{'resource.'.$part.'.awarded'}; } @@ -3945,8 +3927,8 @@ sub status { if ($completionStatus == INCORRECT || $completionStatus == INCORRECT_BY_OVERRIDE) { # and there are TRIES LEFT: if ($self->tries($part) < $self->maxtries($part) || !$self->maxtries($part)) { - return $suppressFeedback ? ANSWER_SUBMITTED : TRIES_LEFT; - } + return TRIES_LEFT; + } return $suppressFeedback ? ANSWER_SUBMITTED : INCORRECT; # otherwise, return orange; student can't fix this }