Diff for /loncom/interface/lonnavmaps.pm between versions 1.52 and 1.56

version 1.52, 2002/09/24 02:41:21 version 1.56, 2002/09/30 16:45:01
Line 827  sub new_handle { Line 827  sub new_handle {
                         $ENV{"request.course.fn"}.".db",                          $ENV{"request.course.fn"}.".db",
                         $ENV{"request.course.fn"}."_parms.db", 1);                          $ENV{"request.course.fn"}."_parms.db", 1);
   
     # Grab a resource object so we have access to the constants; this  
     # is technically not proper, but should be harmless  
     my $res = $navmap->firstResource();  
   
     # Defines a status->color mapping, null string means don't color  
     my %colormap =   
     ( $res->NETWORK_FAILURE    => '',  
       $res->CORRECT            => '#BBFFBB',  
       $res->EXCUSED            => '#BBBBFF',  
       $res->PAST_DUE           => '#FFAA00',  
       $res->ANSWER_OPEN        => '#FF00AA',  
       $res->OPEN_LATER         => '',  
       $res->TRIES_LEFT         => '#FFFF00',  
       $res->INCORRECT          => '#FFAA00',  
       $res->OPEN               => '#FFFF88' );  
   
     if (!defined($navmap)) {      if (!defined($navmap)) {
         my $requrl = $r->uri;          my $requrl = $r->uri;
Line 849  sub new_handle { Line 834  sub new_handle {
         return HTTP_NOT_ACCEPTABLE;          return HTTP_NOT_ACCEPTABLE;
     }      }
   
       # Check that it's defined
       if (!($navmap->courseMapDefined())) {
           $r->print('<font size="+2" color="red">Coursemap undefined.</font>' .
                     '</body></html>');
           return OK;
       }
   
       # Grab a resource object so we have access to the constants; this
       # is technically not proper, but should be harmless
       my $res = $navmap->firstResource();
   
       # Defines a status->color mapping, null string means don't color
       my %colormap = 
       ( $res->NETWORK_FAILURE        => '',
         $res->CORRECT                => '#BBFFBB',
         $res->EXCUSED                => '#BBBBFF',
         $res->PAST_DUE_ANSWER_LATER  => '#FFAA00',
         $res->PAST_DUE_NO_ANSWER     => '#FFAA00',
         $res->ANSWER_OPEN            => '#FF00AA',
         $res->OPEN_LATER             => '',
         $res->TRIES_LEFT             => '#FFFF00',
         $res->INCORRECT              => '#FFAA00',
         $res->OPEN                   => '#FFFF88',
         $res->NOTHING_SET            => ''        );
   
     my %filterHash;      my %filterHash;
     # Figure out what we're not displaying      # Figure out what we're not displaying
     foreach (split(/\,/, $ENV{"form.filter"})) {      foreach (split(/\,/, $ENV{"form.filter"})) {
Line 863  sub new_handle { Line 873  sub new_handle {
   
     my $mapIterator = $navmap->getIterator(undef, undef, \%filterHash);      my $mapIterator = $navmap->getIterator(undef, undef, \%filterHash);
     my $curRes = $mapIterator->next();      my $curRes = $mapIterator->next();
       undef $res; # so we don't accidentally use it later
     my $indentLevel = -1;      my $indentLevel = -1;
     my $indentString = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";      my $indentString = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
   
Line 966  sub new_handle { Line 977  sub new_handle {
                                   
                 if ($curRes->kind() eq "res" and                   if ($curRes->kind() eq "res" and 
                     $curRes->is_problem() ) {                      $curRes->is_problem() ) {
                     $r->print (" Due: " . localtime($curRes->duedate()));                      $r->print (getDescription($curRes, $part));
                 }                  }
             }              }
         }          }
Line 1024  sub getLinkForResource { Line 1035  sub getLinkForResource {
     return $res->src();      return $res->src();
 }  }
   
   # Convenience function: This seperates the logic of how to create
   # the problem text strings ("Due: DATE", "Open: DATE", "Not yet assigned",
   # etc.) into a seperate function. It takes a resource object as the
   # first parameter, and the part number of the resource as the second.
   # It's basically a big switch statement on the status of the resource.
   
   sub getDescription {
       my $res = shift;
       my $part = shift;
       my $status = $res->getDateStatus();
   
       if ($status == $res->NETWORK_FAILURE) { return ""; }
       if ($status == $res->NOTHING_SET) {
           return "Not currently assigned.";
       }
       if ($status == $res->OPEN_LATER) {
           return "Opens: " . timeToHumanString($res->opendate($part));
       }
       if ($status == $res->OPEN) {
           return "Due: $status " . timeToHumanString($res->duedate($part));
       }
       if ($status == $res->PAST_DUE_ANSWER_LATER) {
           return "Answer: " . timeToHumanString($res->answerdate($part));
       }
       if ($status == $res->PAST_DUE_NO_ANSWER) {
           return "Was Due: " . timeToHumanString($res->duedate($part));
       }
       if ($status == $res->ANSWER_OPEN) {
           return "Answer available";
       }
   }
   
   # I want to change this into something more human-friendly. For
   # now, this is a simple call to localtime. The final function
   # probably belongs in loncommon.
   sub timeToHumanString {
       return localtime(shift);
   }
   
 1;  1;
   
 package Apache::lonnavmaps::navmap;  package Apache::lonnavmaps::navmap;
Line 1048  You must obtain resource objects through Line 1098  You must obtain resource objects through
   
 =over 4  =over 4
   
 =item * B<new>(filename, parmHashFile, genCourseAndUserOptions): Binds a new navmap object to the compiled course representation and parmHashFile. 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. Returns the navmap object if this is successful, or B<undef> if not. You must check for undef; errors will occur when you try to use the other methods otherwise.  =item * B<new>(filename, parmHashFile, genCourseAndUserOptions, genMailDiscussStatus): Binds a new navmap object to the compiled course representation and parmHashFile. 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<undef> if not. You must check for undef; errors will occur when you try to use the other methods otherwise.
   
 =item * B<getIterator>(first, finish, filter, condition): See iterator documentation below.  =item * B<getIterator>(first, finish, filter, condition): See iterator documentation below.
   
Line 1066  sub new { Line 1116  sub new {
     $self->{NAV_HASH_FILE} = shift;      $self->{NAV_HASH_FILE} = shift;
     $self->{PARM_HASH_FILE} = shift;      $self->{PARM_HASH_FILE} = shift;
     $self->{GENERATE_COURSE_USER_OPT} = shift;      $self->{GENERATE_COURSE_USER_OPT} = shift;
       $self->{GENERATE_EMAIL_DISCUSS_STATUS} = shift;
   
     # Resource cache stores navmapresource's as we reference them. We generate      # Resource cache stores navmapresource's as we reference them. We generate
     # them on-demand so we don't pay for creating resources unless we use them.      # them on-demand so we don't pay for creating resources unless we use them.
Line 1143  sub new { Line 1194  sub new {
                 $useropt{$userprefix.&Apache::lonnet::unescape($name)}=                  $useropt{$userprefix.&Apache::lonnet::unescape($name)}=
                     &Apache::lonnet::unescape($value);                      &Apache::lonnet::unescape($value);
             }              }
         $self->{COURSE_OPT} = \%courseopt;              $self->{COURSE_OPT} = \%courseopt;
         $self->{USER_OPT} = \%useropt;              $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;
           
       }    
       
     bless($self);      bless($self);
           
     return $self;      return $self;
 }  }
   
   # Checks to see if coursemap is defined, matching test in old lonnavmaps
   sub courseMapDefined {
       my $self = shift;
       my $uri = &Apache::lonnet::clutter($ENV{'request.course.uri'});
   
       my $firstres = $self->{NAV_HASH}->{"map_start_$uri"};
       my $lastres = $self->{NAV_HASH}->{"map_finish_$uri"};
       return $firstres && $lastres;
   }
   
 sub getIterator {  sub getIterator {
     my $self = shift;      my $self = shift;
     my $iterator = Apache::lonnavmaps::iterator->new($self, shift, shift,      my $iterator = Apache::lonnavmaps::iterator->new($self, shift, shift,
Line 1985  B<Date Codes> Line 2093  B<Date Codes>
   
 =item * B<OPEN>: Open and not yet due.  =item * B<OPEN>: Open and not yet due.
   
 =item * B<PAST_DUE>: The due date has passed, but the answer date has not yet arrived.  =item * B<PAST_DUE_ANSWER_LATER>: The due date has passed, but the answer date has not yet arrived.
   
   =item * B<PAST_DUE_NO_ANSWER>: The due date has passed and there is no answer opening date set.
   
 =item * B<ANSWER_OPEN>: The answer date is here.  =item * B<ANSWER_OPEN>: The answer date is here.
   
Line 1996  B<Date Codes> Line 2106  B<Date Codes>
 =cut  =cut
   
 # Apparently the compiler optimizes these into constants automatically  # Apparently the compiler optimizes these into constants automatically
 sub OPEN_LATER      { return 0; }  sub OPEN_LATER             { return 0; }
 sub OPEN            { return 1; }  sub OPEN                   { return 1; }
 sub PAST_DUE        { return 2; }  sub PAST_DUE_NO_ANSWER     { return 2; }
 sub ANSWER_OPEN     { return 3; }  sub PAST_DUE_ANSWER_LATER  { return 3; }
 sub NETWORK_FAILURE { return 100; }  sub ANSWER_OPEN            { return 4; }
   sub NOTHING_SET            { return 5; } 
   sub NETWORK_FAILURE        { return 100; }
   
   # getDateStatus gets the date status for a given problem part. 
   # Because answer date, due date, and open date are fully independent
   # (i.e., it is perfectly possible to *only* have an answer date), 
   # we have to completely cover the 3x3 maxtrix of (answer, due, open) x
   # (past, future, none given). This function handles this with a decision
   # tree. Read the comments to follow the decision tree.
   
 sub getDateStatus {  sub getDateStatus {
     my $self = shift;      my $self = shift;
     my $part = shift;      my $part = shift;
     $part = "0" if (!defined($part));      $part = "0" if (!defined($part));
   
       # Always return network failure if there was one.
     return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE});      return $self->NETWORK_FAILURE if ($self->{NAV_MAP}->{NETWORK_FAILURE});
   
     my $now = time();      my $now = time();
   
     my $o = $now - $self->opendate($part);      my $open = $self->opendate($part);
     my $d = $now - $self->duedate($part);      my $due = $self->duedate($part);
     my $a = $now - $self->answerdate($part);      my $answer = $self->answerdate($part);
   
     if ($o < 0) {return $self->OPEN_LATER};      if (!$open && !$due && !$answer) {
     if ($d < 0) {return $self->OPEN};          # no data on the problem at all
     if ($a < 0) {return $self->PAST_DUE};          # should this be the same as "open later"? think multipart.
     return $self->ANSWER_OPEN;          return $self->NOTHING_SET;
       }
       if (!$open || $now < $open) {return $self->OPEN_LATER};
       if (!$due || $now < $due) {return $self->OPEN};
       if ($answer && $now < $answer) {return $self->PAST_DUE_ANSWER_LATER};
       if ($answer) { return $self->ANSWER_OPEN; };
       return PAST_DUE_NO_ANSWER;
 }  }
   
 =pod  =pod
Line 2052  B<Completion Codes> Line 2179  B<Completion Codes>
   
 =cut  =cut
   
 sub NOT_ATTEMPTED         { return 0; }  sub NOT_ATTEMPTED         { return 10; }
 sub INCORRECT             { return 1; }  sub INCORRECT             { return 11; }
 sub INCORRECT_BY_OVERRIDE { return 2; }  sub INCORRECT_BY_OVERRIDE { return 12; }
 sub CORRECT               { return 3; }  sub CORRECT               { return 13; }
 sub CORRECT_BY_OVERRIDE   { return 4; }  sub CORRECT_BY_OVERRIDE   { return 14; }
 sub EXCUSED               { return 5; }  sub EXCUSED               { return 15; }
   
 sub getCompletionStatus {  sub getCompletionStatus {
     my $self = shift;      my $self = shift;
Line 2089  Along with directly returning the date o Line 2216  Along with directly returning the date o
   
 =item * NETWORK_FAILURE: The network has failed and the information is not available.  =item * NETWORK_FAILURE: The network has failed and the information is not available.
   
   =item * NOTHING_SET: No dates have been set for this problem (part) at all. (Because only certain parts of a multi-part problem may be assigned, this can not be collapsed into "open later", as we don't know a given part will EVER be opened.)
   
 =item * CORRECT: For any reason at all, the part is considered correct.  =item * CORRECT: For any reason at all, the part is considered correct.
   
 =item * EXCUSED: For any reason at all, the problem is excused.  =item * EXCUSED: For any reason at all, the problem is excused.
   
 =item * PAST_DUE: The problem is past due, and not considered correct.  =item * PAST_DUE_NO_ANSWER: The problem is past due, not considered correct, and no answer date is set.
   
   =item * PAST_DUE_ANSWER_LATER: The problem is past due, not considered correct, and an answer date in the future is set.
   
 =item * ANSWER_OPEN: The problem is past due, not correct, and the answer is now available.  =item * ANSWER_OPEN: The problem is past due, not correct, and the answer is now available.
   
Line 2120  sub status { Line 2251  sub status {
   
     # What we have is a two-dimensional matrix with 4 entries on one      # What we have is a two-dimensional matrix with 4 entries on one
     # dimension and 5 entries on the other, which we want to colorize,      # dimension and 5 entries on the other, which we want to colorize,
     # plus network failure.      # plus network failure and "no date data at all".
   
     # Don't colorize on network failure.      if ($completionStatus == NETWORK_FAILURE) { return NETWORK_FAILURE; }
     if ($completionStatus == NETWORK_FAILURE()) { return $self->NETWORK_FAILURE(); }  
   
     # There are a few whole rows we can dispose of:      # There are a few whole rows we can dispose of:
     # If the problem is CORRECT, color it green no matter what      if ($completionStatus == CORRECT ||
     if ($completionStatus == CORRECT() ||          $completionStatus == CORRECT_BY_OVERRIDE ) {
         $completionStatus == CORRECT_BY_OVERRIDE() ) {          return CORRECT(); 
         return $self->CORRECT(); # Return a nice green.      }
   
       # If it's EXCUSED, then return that no matter what
       if ($completionStatus == EXCUSED) {
           return EXCUSED; 
     }      }
   
     # If it's EXCUSED, then return something no matter what      if ($dateStatus == NOTHING_SET) {
     if ($completionStatus == EXCUSED()) {          return NOTHING_SET;
         return $self->EXCUSED(); # return a nice blue  
     }      }
   
     # Now we're down to a 3 (incorrect, incorrect_override, not_attempted)      # Now we're down to a 3 (incorrect, incorrect_override, not_attempted)
     # by 4 matrix (date status).      # by 4 matrix (date status).
   
     # If it's Past Due and we didn't bail earlier because it's correct,      if ($dateStatus == PAST_DUE_ANSWER_LATER ||
     # color it orange. (Red is sort inappropriate; too drastic a color          $dateStatus == PAST_DUE_NO_ANSWER) {
     # for something the student can't fix.          return $dateStatus; 
     if ($dateStatus == PAST_DUE()) {  
         return $self->PAST_DUE(); # return orange  
     }      }
   
     if ($dateStatus == ANSWER_OPEN()) {      if ($dateStatus == ANSWER_OPEN) {
         return $self->ANSWER_OPEN();          return ANSWER_OPEN;
     }      }
   
     # Now: (incorrect, incorrect_override, not_attempted) x       # Now: (incorrect, incorrect_override, not_attempted) x 
     # (open_later), (open)      # (open_later), (open)
           
     # If it's open later, then don't colorize      if ($dateStatus == OPEN_LATER) {
     if ($dateStatus == OPEN_LATER()) {          return OPEN_LATER;
         return $self->OPEN_LATER();  
     }      }
   
     # If it's WRONG...      # If it's WRONG...
     if ($completionStatus == INCORRECT() || $completionStatus == INCORRECT_BY_OVERRIDE()) {      if ($completionStatus == INCORRECT || $completionStatus == INCORRECT_BY_OVERRIDE) {
         # and there are TRIES LEFT:          # and there are TRIES LEFT:
         if ($self->tries() < $self->maxtries()) {          if ($self->tries() < $self->maxtries()) {
             return $self->TRIES_LEFT(); # return red: The student can fix this              return TRIES_LEFT;
         }          }
         return $self->INCORRECT(); # otherwise, return orange; student can't fix this          return INCORRECT; # otherwise, return orange; student can't fix this
     }      }
   
     # Otherwise, it's untried and open      # Otherwise, it's untried and open
     return $self->OPEN(); # Light yellow      return OPEN; 
 }  }
   
 =pod  =pod

Removed from v.1.52  
changed lines
  Added in v.1.56


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