Diff for /loncom/interface/lonnavmaps.pm between versions 1.449 and 1.477

version 1.449, 2010/06/24 14:21:39 version 1.477, 2011/12/25 20:41:53
Line 225  automatically. Line 225  automatically.
   
 =over 4  =over 4
   
 =item * B<iterator>: default: constructs one from %env  =item * B<iterator: default: constructs one from %env
   
 A reference to a fresh ::iterator to use from the navmaps. The  A reference to a fresh ::iterator to use from the navmaps. The
 rendering will reflect the options passed to the iterator, so you can  rendering will reflect the options passed to the iterator, so you can
Line 464  returns 4 Line 464  returns 4
   
 =item add_linkitem()  =item add_linkitem()
   
 =item show_linkitems()  =item show_linkitems_toolbar()
   
 =back  =back
   
Line 478  use Apache::loncommon(); Line 478  use Apache::loncommon();
 use Apache::lonenc();  use Apache::lonenc();
 use Apache::lonlocal;  use Apache::lonlocal;
 use Apache::lonnet;  use Apache::lonnet;
   use Apache::lonmap;
   
 use POSIX qw (floor strftime);  use POSIX qw (floor strftime);
 use Time::HiRes qw( gettimeofday tv_interval );  use Time::HiRes qw( gettimeofday tv_interval );
 use LONCAPA;  use LONCAPA;
 use DateTime();  use DateTime();
   
   # For debugging
   
   # use Data::Dumper;
   
   
 # symbolic constants  # symbolic constants
 sub SYMB { return 1; }  sub SYMB { return 1; }
 sub URL { return 2; }  sub URL { return 2; }
Line 509  my %statusIconMap = Line 515  my %statusIconMap =
 my %iconAltTags =   #texthash does not work here  my %iconAltTags =   #texthash does not work here
     ( 'navmap.correct.gif'  => 'Correct',      ( 'navmap.correct.gif'  => 'Correct',
       'navmap.wrong.gif'    => 'Incorrect',        'navmap.wrong.gif'    => 'Incorrect',
       'navmap.open.gif'     => 'Open',        'navmap.open.gif'     => 'Is Open',
       'navmap.partial.gif'  => 'Partially Correct',        'navmap.partial.gif'  => 'Partially Correct',
       'navmap.ellipsis.gif' => 'Attempted',        'navmap.ellipsis.gif' => 'Attempted',
      );       );
Line 528  my %colormap = Line 534  my %colormap =
       $resObj->OPEN                   => '',        $resObj->OPEN                   => '',
       $resObj->NOTHING_SET            => '',        $resObj->NOTHING_SET            => '',
       $resObj->ATTEMPTED              => '',        $resObj->ATTEMPTED              => '',
         $resObj->CREDIT_ATTEMPTED       => '',
       $resObj->ANSWER_SUBMITTED       => '',        $resObj->ANSWER_SUBMITTED       => '',
       $resObj->PARTIALLY_CORRECT      => '#006600'        $resObj->PARTIALLY_CORRECT      => '#006600'
       );        );
Line 535  my %colormap = Line 542  my %colormap =
 # is not yet done and due in less than 24 hours  # is not yet done and due in less than 24 hours
 my $hurryUpColor = "#FF0000";  my $hurryUpColor = "#FF0000";
   
 my $future_slots_checked = 0;  
 my $future_slots = 0;  
   
 sub addToFilter {  sub addToFilter {
     my $hashIn = shift;      my $hashIn = shift;
     my $addition = shift;      my $addition = shift;
Line 608  sub getDescription { Line 612  sub getDescription {
         return &mt("Having technical difficulties; please check status later");           return &mt("Having technical difficulties; please check status later"); 
     }      }
     if ($status == $res->NOTHING_SET) {      if ($status == $res->NOTHING_SET) {
         return &mt("Not currently assigned.");          return &Apache::lonhtmlcommon::direct_parm_link(&mt("Not currently assigned.",$res->symb(),'opendate'),$part);
     }      }
     if ($status == $res->OPEN_LATER) {      if ($status == $res->OPEN_LATER) {
         return &mt("Open ") .timeToHumanString($open,'start');          return &mt("Open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($open,'start'),$res->symb(),'opendate',$part));
     }      }
     if ($res->simpleStatus($part) == $res->OPEN) {      if ($res->simpleStatus($part) == $res->OPEN) {
         unless (&Apache::lonnet::allowed('mgr',$env{'request.course.id'})) {          unless (&Apache::lonnet::allowed('mgr',$env{'request.course.id'})) {
Line 628  sub getDescription { Line 632  sub getDescription {
                 return &mt('Reserved - next open [_1]',                  return &mt('Reserved - next open [_1]',
                            timeToHumanString($slot_time,'start'));                             timeToHumanString($slot_time,'start'));
             } elsif ($slot_status == $res->RESERVABLE) {              } elsif ($slot_status == $res->RESERVABLE) {
                 return &mt('Reservable ending [_1]',                  return &mt('Reservable, reservations close [_1]',
                            timeToHumanString($slot_time,'end'));                             timeToHumanString($slot_time,'end'));
             } elsif ($slot_status == $res->RESERVABLE_LATER) {              } elsif ($slot_status == $res->RESERVABLE_LATER) {
                 return &mt('Reservable starting [_1]',                  return &mt('Reservable, reservations open [_1]',
                            timeToHumanString($slot_time,'start'));                             timeToHumanString($slot_time,'start'));
             } elsif ($slot_status == $res->NOT_IN_A_SLOT) {              } elsif ($slot_status == $res->NOT_IN_A_SLOT) {
                 return &mt('Reserve a time/place to work');                  return &mt('Reserve a time/place to work');
Line 645  sub getDescription { Line 649  sub getDescription {
     if ($status == $res->OPEN) {      if ($status == $res->OPEN) {
         if ($due) {          if ($due) {
     if ($res->is_practice()) {      if ($res->is_practice()) {
  return &mt("Closes ")."  " .timeToHumanString($due,'start');   return &mt("Closes [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'duedate',$part));
     } else {      } else {
  return &mt("Due")."  " .timeToHumanString($due,'end');   return &mt("Due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'duedate',$part));
     }      }
         } else {          } else {
             return &mt("Open, no due date");              return &Apache::lonhtmlcommon::direct_parm_link(&mt("Open, no due date"),$res->symb(),'duedate',$part);
         }          }
     }      }
     if ($status == $res->PAST_DUE_ANSWER_LATER) {      if ($status == $res->PAST_DUE_ANSWER_LATER) {
         return &mt("Answer open")." " .timeToHumanString($answer,'start');          return &mt("Answer open [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($answer,'start'),$res->symb(),'answerdate',$part));
     }      }
     if ($status == $res->PAST_DUE_NO_ANSWER) {      if ($status == $res->PAST_DUE_NO_ANSWER) {
  if ($res->is_practice()) {   if ($res->is_practice()) {
     return &mt("Closed")." " . timeToHumanString($due,'start');      return &mt("Closed [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'start'),$res->symb(),'answerdate,duedate',$part));
  } else {   } else {
     return &mt("Was due")." " . timeToHumanString($due,'end');      return &mt("Was due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'answerdate,duedate',$part));
  }   }
     }      }
     if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT)      if (($status == $res->ANSWER_OPEN || $status == $res->PARTIALLY_CORRECT)
  && $res->handgrade($part) ne 'yes') {   && $res->handgrade($part) ne 'yes') {
         return &mt("Answer available");          return &Apache::lonhtmlcommon::direct_parm_link(&mt("Answer available"),$res->symb(),'answerdate,duedate',$part);
     }      }
     if ($status == $res->EXCUSED) {      if ($status == $res->EXCUSED) {
         return &mt("Excused by instructor");          return &mt("Excused by instructor");
Line 677  sub getDescription { Line 681  sub getDescription {
             return &mt("Answer submitted, not yet graded");              return &mt("Answer submitted, not yet graded");
         }          }
     }      }
       if ($status == $res->CREDIT_ATTEMPTED) {
           if ($res->is_anonsurvey($part) || $res->is_survey($part)) {
               return &mt("Credit for survey submission");
           }
       }
     if ($status == $res->TRIES_LEFT) {      if ($status == $res->TRIES_LEFT) {
         my $tries = $res->tries($part);          my $tries = $res->tries($part);
         my $maxtries = $res->maxtries($part);          my $maxtries = $res->maxtries($part);
Line 688  sub getDescription { Line 697  sub getDescription {
             }              }
         }          }
         if ($due) {          if ($due) {
             return &mt("Due")." " . timeToHumanString($due,'end') .              return &mt("Due [_1]",&Apache::lonhtmlcommon::direct_parm_link(&timeToHumanString($due,'end'),$res->symb(),'duedate',$part)) .
                 " $triesString";                  " $triesString";
         } else {          } else {
             return &mt("No due date")." $triesString";              return &Apache::lonhtmlcommon::direct_parm_link(&mt("No due date"),$res->symb(),'duedate',$part)." $triesString";
         }          }
     }      }
     if ($status == $res->ANSWER_SUBMITTED) {      if ($status == $res->ANSWER_SUBMITTED) {
Line 773  sub timeToHumanString { Line 782  sub timeToHumanString {
   
         # Less than an hour          # Less than an hour
         if ( $delta < $hour ) {          if ( $delta < $hour ) {
             # If so, use minutes              # If so, use minutes; or minutes, seconds (if format requires)
             my $minutes = floor($delta / 60);              my $minutes = floor($delta / 60);
               if (($format ne '') && ($format =~ /\%(T|S)/)) {
                   my $display;
                   if ($minutes == 1) {
                       $display = "${prefix}1 minute";
                   } else {
                       $display = "$prefix$minutes minutes";
                   }
                   my $seconds = $delta % $minute;
                   if ($seconds == 0) {
                       $display .= $tense;
                   } elsif ($seconds == 1) {
                       $display .= ", 1 second$tense";
                   } else {
                       $display .= ", $seconds seconds$tense";
                   }
                   return $display;
               }
             if ($minutes == 1) { return "${prefix}1 minute$tense"; }              if ($minutes == 1) { return "${prefix}1 minute$tense"; }
             return "$prefix$minutes minutes$tense";              return "$prefix$minutes minutes$tense";
         }          }
                   
         # Is it less than 24 hours away? If so,          # Is it less than 24 hours away? If so,
         # display hours + minutes          # display hours + minutes, (and + seconds, if format specified it)  
         if ( $delta < $hour * 24) {          if ( $delta < $hour * 24) {
             my $hours = floor($delta / $hour);              my $hours = floor($delta / $hour);
             my $minutes = floor(($delta % $hour) / $minute);              my $minutes = floor(($delta % $hour) / $minute);
Line 795  sub timeToHumanString { Line 821  sub timeToHumanString {
             if ($minutes == 0) {              if ($minutes == 0) {
                 $minuteString = "";                  $minuteString = "";
             }              }
               if (($format ne '') && ($format =~ /\%(T|S)/)) {
                   my $display = "$prefix$hourString$minuteString";
                   my $seconds = $delta-(($hours * $hour)+($minutes * $minute));
                   if ($seconds == 0) {
                       $display .= $tense;
                   } elsif ($seconds == 1) {
                       $display .= ", 1 second$tense";
                   } else {
                       $display .= ", $seconds seconds$tense";
                   }
                   return $display;
               }
             return "$prefix$hourString$minuteString$tense";              return "$prefix$hourString$minuteString$tense";
         }          }
   
           # Date/time is more than 24 hours away
   
  my $dt = DateTime->from_epoch(epoch => $time)   my $dt = DateTime->from_epoch(epoch => $time)
                  ->set_time_zone(&Apache::lonlocal::gettimezone());                   ->set_time_zone(&Apache::lonlocal::gettimezone());
   
  # If there's a caller supplied format, use it.   # If there's a caller supplied format, use it, unless it only displays
           # H:M:S or H:M.
   
  if ($format ne '') {   if (($format ne '') && ($format ne '%T') && ($format ne '%R')) {
     my $timeStr = $dt->strftime($format);      my $timeStr = $dt->strftime($format);
     return $timeStr.' ('.$dt->time_zone_short_name().')';      return $timeStr.' ('.$dt->time_zone_short_name().')';
  }   }
Line 855  sub part_status_summary { return 4; } Line 896  sub part_status_summary { return 4; }
 sub render_resource {  sub render_resource {
     my ($resource, $part, $params) = @_;      my ($resource, $part, $params) = @_;
   
       my $editmapLink;
     my $nonLinkedText = ''; # stuff after resource title not in link      my $nonLinkedText = ''; # stuff after resource title not in link
   
     my $link = $params->{"resourceLink"};      my $link = $params->{"resourceLink"};
Line 936  sub render_resource { Line 978  sub render_resource {
             $linkopen = "";              $linkopen = "";
             $linkclose = "";              $linkclose = "";
         }          }
           if ((&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) &&
               ($resource->symb=~/\_\_\_[^\_]+\_\_\_uploaded/)) {
               my $icon = &Apache::loncommon::lonhttpdurl('/res/adm/pages').'/editmap.png';
               $editmapLink='&nbsp;'.
                            '<a href="/adm/coursedocs?command=direct&symb='.&escape($resource->symb()).'">'.
                            '<img src="'.$icon.'" alt="'.&mt('Edit Content').'" title="'.&mt('Edit Content').'" />'.
                            '</a>';
           }
     }      }
   
     if ($resource->randomout()) {      if ($resource->randomout()) {
         $nonLinkedText .= ' <i>('.&mt('hidden').')</i> ';          $nonLinkedText .= ' <span class="LC_warning">('.&mt('hidden').')</span> ';
     }      }
     if (!$resource->condval()) {      if (!$resource->condval()) {
         $nonLinkedText .= ' <i>('.&mt('conditionally hidden').')</i> ';          $nonLinkedText .= ' <span class="LC_info">('.&mt('conditionally hidden').')</span> ';
     }      }
     if (($resource->is_practice()) && ($resource->is_raw_problem())) {      if (($resource->is_practice()) && ($resource->is_raw_problem())) {
         $nonLinkedText .=' <font color="green"><b>'.&mt('not graded').'</b></font>';          $nonLinkedText .=' <font color="green"><b>'.&mt('not graded').'</b></font>';
Line 969  sub render_resource { Line 1019  sub render_resource {
     # Is this the current resource?      # Is this the current resource?
     if (!$params->{'displayedHereMarker'} &&       if (!$params->{'displayedHereMarker'} && 
         $resource->symb() eq $params->{'here'} ) {          $resource->symb() eq $params->{'here'} ) {
         $curMarkerBegin = '<em>';          unless ($resource->is_map()) {
         $curMarkerEnd = '</em>';              $curMarkerBegin = '<span class="LC_current_nav_location">';
               $curMarkerEnd = '</span>';
           }
  $params->{'displayedHereMarker'} = 1;   $params->{'displayedHereMarker'} = 1;
     }      }
   
Line 989  sub render_resource { Line 1041  sub render_resource {
     if (!$params->{'resource_nolink'} && !$resource->is_sequence() && !$resource->is_empty_sequence) {      if (!$params->{'resource_nolink'} && !$resource->is_sequence() && !$resource->is_empty_sequence) {
         $result .= "$curMarkerBegin<a href=\"$link\">$title$partLabel</a>$curMarkerEnd$nonLinkedText</td>";          $result .= "$curMarkerBegin<a href=\"$link\">$title$partLabel</a>$curMarkerEnd$nonLinkedText</td>";
     } else {      } else {
         $result .= "$curMarkerBegin$linkopen$title$partLabel</a>$curMarkerEnd$nonLinkedText</td>";          $result .= "$curMarkerBegin$linkopen$title$partLabel</a>$curMarkerEnd$editmapLink$nonLinkedText</td>";
     }      }
   
     return $result;      return $result;
Line 1003  sub render_communication_status { Line 1055  sub render_communication_status {
     my $linkopen = "<a href=\"$link\">";      my $linkopen = "<a href=\"$link\">";
     my $linkclose = "</a>";      my $linkclose = "</a>";
     my $location=&Apache::loncommon::lonhttpdurl("/adm/lonMisc");      my $location=&Apache::loncommon::lonhttpdurl("/adm/lonMisc");
   
     if ($resource->hasDiscussion()) {      if ($resource->hasDiscussion()) {
         $discussionHTML = $linkopen .          $discussionHTML = $linkopen .
             '<img alt="'.&mt('New Discussion').'" src="'.$location.'/chat.gif" title="'.&mt('New Discussion').'"/>' .              '<img alt="'.&mt('New Discussion').'" src="'.$location.'/chat.gif" title="'.&mt('New Discussion').'"/>' .
Line 1085  sub render_long_status { Line 1138  sub render_long_status {
     }      }
           
     if ($resource->kind() eq "res" &&      if ($resource->kind() eq "res" &&
         ($resource->is_problem() || $resource->is_practice()) &&          $resource->is_raw_problem() &&
         !$firstDisplayed) {          !$firstDisplayed) {
         if ($color) {$result .= "<font color=\"$color\"><b>"; }          if ($color) {$result .= "<font color=\"$color\"><b>"; }
         $result .= getDescription($resource, $part);          $result .= getDescription($resource, $part);
Line 1345  sub render { Line 1398  sub render {
         }          }
     }      }
   
   
     # (re-)Locate the jump point, if any      # (re-)Locate the jump point, if any
     # Note this does not take filtering or hidden into account... need      # Note this does not take filtering or hidden into account... need
     # to be fixed?      # to be fixed?
Line 1453  END Line 1507  END
             }              }
  }   }
  $result.='</form>';   $result.='</form>';
           if (&Apache::lonnet::allowed('mdc',$env{'request.course.id'})) {
               my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
               my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
               if ($env{'course.'.$env{'request.course.id'}.'.url'} eq 
                   "uploaded/$cdom/$cnum/default.sequence") {
                   &add_linkitem($args->{'linkitems'},'edittoplevel',
                                 "javascript:gocmd('/adm/coursedocs','editdocs');",
                                 'Content Editor');
               }
           }
     }      }
   
     if ($args->{'caller'} eq 'navmapsdisplay') {      if ($args->{'caller'} eq 'navmapsdisplay') {
         $result .= '<table><tr><td>'.          $result .= &show_linkitems_toolbar($args,$condition);
                    &Apache::loncommon::help_open_menu('Navigation Screen','Navigation_Screen',undef,'RAT').'</td>';  
     $result .= '<td>&nbsp;</td>';   
  $result.='<td class="LC_middle">'.&mt('Tools:').'</td>';  
  $result.=&show_linkitems_toolbar($args->{'linkitems'});  
         if ($args->{'sort_html'}) {  
             $result.='<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>'.  
                 '<td align="right">'.$args->{'sort_html'}.'</td></tr>';  
         }  
         $result .= '</table>';  
     } elsif ($args->{'sort_html'}) {       } elsif ($args->{'sort_html'}) { 
         $result.=$args->{'sort_html'};           $result.=$args->{'sort_html'}; 
     }      }
Line 1597  END Line 1652  END
     $curRes = shift(@resources);      $curRes = shift(@resources);
  } else {   } else {
     $curRes = $it->next($closeAllPages);      $curRes = $it->next($closeAllPages);
   
  }   }
  if (!$curRes) { last; }   if (!$curRes) { last; }
   
Line 1802  sub add_linkitem { Line 1858  sub add_linkitem {
 }  }
   
 sub show_linkitems_toolbar {  sub show_linkitems_toolbar {
     my ($linkitems,$condition)=@_;      my ($args,$condition) = @_;
     my @linkorder = ('firsthomework','everything','uncompleted',      my $result =
                      'changefolder','clearbubbles');          '<table><tr><td>'.
     my $result .='<td align="left">'."\n".           &Apache::loncommon::help_open_menu('Navigation Screen','Navigation_Screen',undef,'RAT').
                  '<span class="LC_nobreak">'."\n".          '</td>'.
                  '<ul id="LC_toolbar">';          '<td>&nbsp;</td>'.
     foreach my $link (@linkorder) {          '<td class="LC_middle">'.&mt('Tools:').'</td>';
         my $link_id = 'LC_content_toolbar_'.$link;      if (ref($args) eq 'HASH') {
         if (defined($linkitems->{$link})) {          if (ref($args->{'linkitems'}) eq 'HASH') {
             if ($linkitems->{$link}{'text'} ne '') {              my @linkorder = ('firsthomework','everything','uncompleted',
                 $linkitems->{$link}{'cmd'}=~s/"/'/g;                               'changefolder','clearbubbles','edittoplevel');
                 if ($linkitems->{$link}{'cmd'}) {              $result .='<td align="left">'."\n".
                     if ($link eq 'changefolder') {                        '<span class="LC_nobreak">'."\n".
                         if ($condition) {                        '<ul id="LC_toolbar">';
                             $link_id='LC_content_toolbar_changefolder_toggled';              foreach my $link (@linkorder) {
                         } else {                  my $link_id = 'LC_content_toolbar_'.$link;
                             $link_id='LC_content_toolbar_changefolder';                  if (ref($args->{'linkitems'}{$link}) eq 'HASH') {
                       if ($args->{'linkitems'}{$link}{'text'} ne '') {
                           $args->{'linkitems'}{$link}{'cmd'}=~s/"/'/g;
                           if ($args->{'linkitems'}{$link}{'cmd'}) {
                               if ($link eq 'changefolder') {
                                   if ($condition) {
                                       $link_id='LC_content_toolbar_changefolder_toggled';
                                   } else {
                                       $link_id='LC_content_toolbar_changefolder';
                                   }
                               }
                               $result .= '<li><a href="#" '.
                                          'onclick="'.$args->{'linkitems'}{$link}{'cmd'}.'" '.
                                          'id="'.$link_id.'" '.
                                          'class="LC_toolbarItem" '.
                                          'title="'.$args->{'linkitems'}{$link}{'text'}.'">'.
                                          '</a></li>'."\n";
                         }                          }
                     }                      }
                     $result .= '<li><a href="#" '.  
                                'onclick="'.$linkitems->{$link}{'cmd'}.'" '.  
                                'id="'.$link_id.'" '.  
                                'class="LC_toolbarItem" '.  
                                'title="'.$linkitems->{$link}{'text'}.'">'.  
                                '</a></li>'."\n";  
                 }                  }
             }              }
               $result .= '</ul>'.
                          '</span></td>'."\n";
           }
           if ($args->{'sort_html'}) {
               $result .= '<td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td>'.
                          '<td align="right">'.$args->{'sort_html'}.'</td>';
         }          }
     }      }
     $result .= '</ul>'.      $result .= '</tr></table>';
                '</span></td>'."\n";  
     return $result;      return $result;
 }  }
   
   
 1;  1;
   
   
Line 1923  sub new { Line 1993  sub new {
     my $proto = shift;      my $proto = shift;
     my $class = ref($proto) || $proto;      my $class = ref($proto) || $proto;
     my $self = {};      my $self = {};
       bless($self); # So we can call change_user if neceesary
   
       $self->{USERNAME} = shift || $env{'user.name'};
       $self->{DOMAIN}   = shift || $env{'user.domain'};
   
   
   
     # Resource cache stores navmap resources as we reference them. We generate      # 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.      # them on-demand so we don't pay for creating resources unless we use them.
Line 1932  sub new { Line 2008  sub new {
     # failed      # failed
     $self->{NETWORK_FAILURE} = 0;      $self->{NETWORK_FAILURE} = 0;
   
     # tie the nav hash      # We can only tie the nav hash as done below if the username/domain
       # match the env one. Otherwise change_user does everything we need...since we can't
       # assume there are course hashes for the specific requested user@domamin:
       #
   
     my %navmaphash;      if ( ($self->{USERNAME} eq $env{'user.name'}) && ($self->{DOMAIN} eq $env{'user.domain'})) {
     my %parmhash;  
     my $courseFn = $env{"request.course.fn"};   # tie the nav hash
     if (!(tie(%navmaphash, 'GDBM_File', "${courseFn}.db",  
               &GDBM_READER(), 0640))) {   my %navmaphash;
         return undef;   my %parmhash;
     }   my $courseFn = $env{"request.course.fn"};
        if (!(tie(%navmaphash, 'GDBM_File', "${courseFn}.db",
     if (!(tie(%parmhash, 'GDBM_File', "${courseFn}_parms.db",    &GDBM_READER(), 0640))) {
               &GDBM_READER(), 0640)))      return undef;
     {   }
         untie %{$self->{PARM_HASH}};  
         return undef;   if (!(tie(%parmhash, 'GDBM_File', "${courseFn}_parms.db",
     &GDBM_READER(), 0640)))
    {
       untie %{$self->{PARM_HASH}};
       return undef;
    }
   
    $self->{NAV_HASH} = \%navmaphash;
    $self->{PARM_HASH} = \%parmhash;
    $self->{PARM_CACHE} = {};
       } else {
    $self->change_user($self->{USERNAME}, $self->{DOMAIN});
     }      }
   
     $self->{NAV_HASH} = \%navmaphash;      my $d = Data::Dumper->new([$self]);
     $self->{PARM_HASH} = \%parmhash;  
     $self->{PARM_CACHE} = {};  
   
     bless($self);  
           
     return $self;      return $self;
 }  }
   
   #
   #  In some instances it is useful to be able to dynamically change the
   # username/domain associated with a navmap (e.g. to navigate for someone
   # else besides the current user...if sufficiently privileged.
   # Parameters:
   #    user  - New user.
   #    domain- Domain the user belongs to.
   # Implicit inputs:
   #   
   sub change_user {
       my $self = shift;
       $self->{USERNAME} = shift;
       $self->{DOMAIN}   = shift;
   
       # If the hashes are already tied make sure to break that bond:
   
       untie %{$self->{NAV_HASH}}; 
       untie %{$self->{PARM_HASH}};
   
       # The assumption is that we have to
       # use lonmap here to re-read the hash and from it reconstruct
       # new big and parameter hashes.  An implicit assumption at this time
       # is that the course file is probably not created locally yet
       # an that we will therefore just read without tying.
   
       my ($cdom, $cnum) = split(/\_/, $env{'request.course.id'});
   
       my %big_hash;
       &Apache::lonmap::loadmap($cnum, $cdom, $self->{USERNAME}, $self->{DOMAIN}, \%big_hash);
       $self->{NAV_HASH} = \%big_hash;
   
   
   
       # Now clear the parm cache and reconstruct the parm hash fromt he big_hash
       # param.xxxx keys.
   
       $self->{PARM_CACHE} = {};
       
       my %parm_hash = {};
       foreach my $key (keys %big_hash) {
    if ($key =~ /^param\./) {
       my $param_key = $key;
       $param_key =~ s/^param\.//;
       $parm_hash{$param_key} = $big_hash{$key};
    }
       }
   
       $self->{PARM_HASH} = \%parm_hash;
      
   
   
       
   } 
   
 sub generate_course_user_opt {  sub generate_course_user_opt {
     my $self = shift;      my $self = shift;
     if ($self->{COURSE_USER_OPT_GENERATED}) { return; }      if ($self->{COURSE_USER_OPT_GENERATED}) { return; }
   
     my $uname=$env{'user.name'};      my $uname=$self->{USERNAME};
     my $udom=$env{'user.domain'};      my $udom=$self->{DOMAIN};
   
     my $cid=$env{'request.course.id'};      my $cid=$env{'request.course.id'};
     my $cdom=$env{'course.'.$cid.'.domain'};      my $cdom=$env{'course.'.$cid.'.domain'};
     my $cnum=$env{'course.'.$cid.'.num'};      my $cnum=$env{'course.'.$cid.'.num'};
Line 2006  sub generate_email_discuss_status { Line 2147  sub generate_email_discuss_status {
     my $cdom=$env{'course.'.$cid.'.domain'};      my $cdom=$env{'course.'.$cid.'.domain'};
     my $cnum=$env{'course.'.$cid.'.num'};      my $cnum=$env{'course.'.$cid.'.num'};
           
     my %emailstatus = &Apache::lonnet::dump('email_status');      my %emailstatus = &Apache::lonnet::dump('email_status',$self->{DOMAIN},$self->{USERNAME});
     my $logoutTime = $emailstatus{'logout'};      my $logoutTime = $emailstatus{'logout'};
     my $courseLeaveTime = $emailstatus{'logout_'.$env{'request.course.id'}};      my $courseLeaveTime = $emailstatus{'logout_'.$env{'request.course.id'}};
     $self->{LAST_CHECK} = (($courseLeaveTime > $logoutTime) ?      $self->{LAST_CHECK} = (($courseLeaveTime > $logoutTime) ?
Line 2014  sub generate_email_discuss_status { Line 2155  sub generate_email_discuss_status {
     my %discussiontime = &Apache::lonnet::dump('discussiontimes',       my %discussiontime = &Apache::lonnet::dump('discussiontimes', 
        $cdom, $cnum);         $cdom, $cnum);
     my %lastread = &Apache::lonnet::dump('nohist_'.$cid.'_discuss',      my %lastread = &Apache::lonnet::dump('nohist_'.$cid.'_discuss',
                                         $env{'user.domain'},$env{'user.name'},'lastread');                                          $self->{DOMAIN},$self->{USERNAME},'lastread');
     my %lastreadtime = ();      my %lastreadtime = ();
     foreach my $key (keys %lastread) {      foreach my $key (keys %lastread) {
         my $shortkey = $key;          my $shortkey = $key;
Line 2024  sub generate_email_discuss_status { Line 2165  sub generate_email_discuss_status {
   
     my %feedback=();      my %feedback=();
     my %error=();      my %error=();
     my @keys = &Apache::lonnet::getkeys('nohist_email',$env{'user.domain'},      my @keys = &Apache::lonnet::getkeys('nohist_email',$self->{DOMAIN},
  $env{'user.name'});   $self->{USERNAME});
           
     foreach my $msgid (@keys) {      foreach my $msgid (@keys) {
  if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) {   if ((!$emailstatus{$msgid}) || ($emailstatus{$msgid} eq 'new')) {
Line 2073  sub get_user_data { Line 2214  sub get_user_data {
   
     # Retrieve performance data on problems      # Retrieve performance data on problems
     my %student_data = Apache::lonnet::currentdump($env{'request.course.id'},      my %student_data = Apache::lonnet::currentdump($env{'request.course.id'},
    $env{'user.domain'},     $self->{DOMAIN},
    $env{'user.name'});     $self->{USERNAME});
     $self->{STUDENT_DATA} = \%student_data;      $self->{STUDENT_DATA} = \%student_data;
   
     $self->{RETRIEVED_USER_DATA} = 1;      $self->{RETRIEVED_USER_DATA} = 1;
Line 2388  sub parmval { Line 2529  sub parmval {
     my $self = shift;      my $self = shift;
     my ($what,$symb,$recurse)=@_;      my ($what,$symb,$recurse)=@_;
     my $hashkey = $what."|||".$symb;      my $hashkey = $what."|||".$symb;
       my $cache = $self->{PARM_CACHE};
     if (defined($self->{PARM_CACHE}->{$hashkey})) {      if (defined($self->{PARM_CACHE}->{$hashkey})) {
         if (ref($self->{PARM_CACHE}->{$hashkey}) eq 'ARRAY') {           if (ref($self->{PARM_CACHE}->{$hashkey}) eq 'ARRAY') { 
             if (defined($self->{PARM_CACHE}->{$hashkey}->[0])) {              if (defined($self->{PARM_CACHE}->{$hashkey}->[0])) {
Line 2425  sub parmval_real { Line 2566  sub parmval_real {
         @cgrps = sort(@cgrps);          @cgrps = sort(@cgrps);
         $cgroup = $cgrps[0];          $cgroup = $cgrps[0];
     }       } 
     my $uname=$env{'user.name'};      my $uname=$self->{USERNAME};
     my $udom=$env{'user.domain'};      my $udom=$self->{DOMAIN};
   
     unless ($symb) { return ['']; }      unless ($symb) { return ['']; }
     my $result='';      my $result='';
Line 2828  sub new { Line 2969  sub new {
     weaken($self->{NAV_MAP} = shift);      weaken($self->{NAV_MAP} = shift);
     return undef unless ($self->{NAV_MAP});      return undef unless ($self->{NAV_MAP});
   
       $self->{USERNAME} = $self->{NAV_MAP}->{USERNAME};
       $self->{DOMAIN}   = $self->{NAV_MAP}->{DOMAIN};
   
     # Handle the parameters      # Handle the parameters
     $self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource();      $self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource();
     $self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource();      $self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource();
Line 2941  sub new { Line 3085  sub new {
     if ($resourceCount == 1 && $resource->is_sequence() && !$self->{FORCE_TOP}) {       if ($resourceCount == 1 && $resource->is_sequence() && !$self->{FORCE_TOP}) { 
         my $firstResource = $resource->map_start();          my $firstResource = $resource->map_start();
         my $finishResource = $resource->map_finish();          my $finishResource = $resource->map_finish();
         return    my $result;
             Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,   my $rdump  = Data::Dumper->new([$result]);
                                               $finishResource, $self->{FILTER},   $result =  Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
                                               $self->{ALREADY_SEEN},        $finishResource, $self->{FILTER},
                                               $self->{CONDITION},       $self->{ALREADY_SEEN}, 
       $self->{FORCE_TOP});       $self->{CONDITION},
        $self->{FORCE_TOP});
    return $result;
              
                   
     }      }
   
Line 2966  sub new { Line 3113  sub new {
     $self->{ALREADY_SEEN}->{$self->{FIRST_RESOURCE}->{ID}} = 1;      $self->{ALREADY_SEEN}->{$self->{FIRST_RESOURCE}->{ID}} = 1;
   
     bless ($self);      bless ($self);
       my $selfDump = Data::Dumper->new([$self]);
   
     return $self;      return $self;
 }  }
Line 2981  sub next { Line 3129  sub next {
     # do so.      # do so.
     if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0}) {      if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0}) {
         $self->{HAVE_RETURNED_0} = 1;          $self->{HAVE_RETURNED_0} = 1;
    my $nextTopLevel = $self->{NAV_MAP}->getById('0.0');
   
         return $self->{NAV_MAP}->getById('0.0');          return $self->{NAV_MAP}->getById('0.0');
     }      }
     if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0_BEGIN_MAP}) {      if ($self->{RETURN_0} && !$self->{HAVE_RETURNED_0_BEGIN_MAP}) {
Line 3000  sub next { Line 3150  sub next {
         if ($self->{RECURSIVE_DEPTH} == 0) {          if ($self->{RECURSIVE_DEPTH} == 0) {
             $self->{RECURSIVE_ITERATOR_FLAG} = 0;              $self->{RECURSIVE_ITERATOR_FLAG} = 0;
         }          }
   
         return $next;          return $next;
     }      }
   
     if (defined($self->{FORCE_NEXT})) {      if (defined($self->{FORCE_NEXT})) {
         my $tmp = $self->{FORCE_NEXT};          my $tmp = $self->{FORCE_NEXT};
         $self->{FORCE_NEXT} = undef;          $self->{FORCE_NEXT} = undef;
   
         return $tmp;          return $tmp;
     }      }
   
Line 3076  sub next { Line 3226  sub next {
     # So we need to look at all the resources we can get to from here,      # So we need to look at all the resources we can get to from here,
     # categorize them if we haven't seen them, remember if we have a new      # categorize them if we haven't seen them, remember if we have a new
     my $nextUnfiltered = $here->getNext();      my $nextUnfiltered = $here->getNext();
   
   
     my $maxDepthAdded = -1;      my $maxDepthAdded = -1;
           
     for (@$nextUnfiltered) {      for (@$nextUnfiltered) {
Line 3109  sub next { Line 3261  sub next {
         $self->{RECURSIVE_ITERATOR_FLAG} = 1;          $self->{RECURSIVE_ITERATOR_FLAG} = 1;
         my $firstResource = $self->{HERE}->map_start();          my $firstResource = $self->{HERE}->map_start();
         my $finishResource = $self->{HERE}->map_finish();          my $finishResource = $self->{HERE}->map_finish();
   
         $self->{RECURSIVE_ITERATOR} =           $self->{RECURSIVE_ITERATOR} = 
             Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,              Apache::lonnavmaps::iterator->new($self->{NAV_MAP}, $firstResource,
                                               $finishResource, $self->{FILTER},                                                $finishResource, $self->{FILTER},
Line 3127  sub next { Line 3278  sub next {
         return $self->next($closeAllPages);          return $self->next($closeAllPages);
     }      }
   
       my $hereResource = $self->{HERE};
   
     return $self->{HERE};      return $self->{HERE};
   
 }  }
Line 3201  sub new { Line 3354  sub new {
     weaken($self->{NAV_MAP} = shift);      weaken($self->{NAV_MAP} = shift);
     return undef unless ($self->{NAV_MAP});      return undef unless ($self->{NAV_MAP});
   
       $self->{USERNAME} = $self->{NAV_MAP}->{USERNAME};
       $self->{DOMAIN}   = $self->{NAV_MAP}->{DOMAIN};
   
     $self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource();      $self->{FIRST_RESOURCE} = shift || $self->{NAV_MAP}->firstResource();
     $self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource();      $self->{FINISH_RESOURCE} = shift || $self->{NAV_MAP}->finishResource();
   
Line 3290  sub next { Line 3446  sub next {
     my $nextUnfiltered;      my $nextUnfiltered;
     if ($self->{DIRECTION} == FORWARD()) {      if ($self->{DIRECTION} == FORWARD()) {
         $nextUnfiltered = $self->{HERE}->getNext();          $nextUnfiltered = $self->{HERE}->getNext();
   
     } else {      } else {
         $nextUnfiltered = $self->{HERE}->getPrevious();          $nextUnfiltered = $self->{HERE}->getPrevious();
     }      }
Line 3437  sub new { Line 3594  sub new {
     weaken($self->{NAV_MAP} = shift);      weaken($self->{NAV_MAP} = shift);
     $self->{ID} = shift;      $self->{ID} = shift;
   
       $self->{USERNAME} = $self->{NAV_MAP}->{USERNAME};
       $self->{DOMAIN}   = $self->{NAV_MAP}->{DOMAIN};
   
     # Store this new resource in the parent nav map's cache.      # Store this new resource in the parent nav map's cache.
     $self->{NAV_MAP}->{RESOURCE_CACHE}->{$self->{ID}} = $self;      $self->{NAV_MAP}->{RESOURCE_CACHE}->{$self->{ID}} = $self;
     $self->{RESOURCE_ERROR} = 0;      $self->{RESOURCE_ERROR} = 0;
Line 3459  sub navHash { Line 3619  sub navHash {
     my $param = shift;      my $param = shift;
     my $id = shift;      my $id = shift;
     my $arg = $param . ($id?$self->{ID}:"");      my $arg = $param . ($id?$self->{ID}:"");
     if (defined($arg)) {      if (ref($self) && ref($self->{NAV_MAP}) && defined($arg)) {
         return $self->{NAV_MAP}->navhash($arg);          return $self->{NAV_MAP}->navhash($arg);
     }      }
     return;      return;
Line 3700  sub is_practice { Line 3860  sub is_practice {
 sub is_problem {  sub is_problem {
     my $self=shift;      my $self=shift;
     my $src = $self->src();      my $src = $self->src();
     if ($src =~ /\.(problem|exam|quiz|assess|survey|form|library|task)$/) {      if ($src =~ /$LONCAPA::assess_re/) {
  return !($self->is_practice());   return !($self->is_practice());
     }      }
     return 0;      return 0;
Line 3723  my %incomplete_hash = Line 3883  my %incomplete_hash =
 sub is_incomplete {  sub is_incomplete {
     my $self = shift;      my $self = shift;
     if ($self->is_problem()) {      if ($self->is_problem()) {
  &Apache::lonnet::logthis('is problem');  
  foreach my $part (@{$self->parts()}) {   foreach my $part (@{$self->parts()}) {
     &Apache::lonnet::logthis("$part status ".$self->status($part));  
     if (exists($incomplete_hash{$self->status($part)})) {      if (exists($incomplete_hash{$self->status($part)})) {
  return 1;   return 1;
     }      }
Line 3737  sub is_incomplete { Line 3895  sub is_incomplete {
 sub is_raw_problem {  sub is_raw_problem {
     my $self=shift;      my $self=shift;
     my $src = $self->src();      my $src = $self->src();
     if ($src =~ /\.(problem|exam|quiz|assess|survey|form|library|task)$/) {      if ($src =~ /$LONCAPA::assess_re/) {
         return 1;          return 1;
     }      }
     return 0;      return 0;
Line 3910  their code.) Line 4068  their code.)
   
 =over 4  =over 4
   
 =item * B<acc>:  =item * B<printable>
   
   returns true if the current date is such that the 
   specified resource part is printable.
   
   =item * B<resprintable>
   
   Returns true if all parts in the resource are printable making the
   entire resource printable.
   
   =item * B<acc>
   
 Get the Client IP/Name Access Control information.  Get the Client IP/Name Access Control information.
   
Line 3963  Get the weight for the problem. Line 4131  Get the weight for the problem.
   
 =cut  =cut
   
   sub printable {
   
       my ($self, $part) = @_;
   
       # Get the print open/close dates for the resource.
   
       my $start = $self->parmval("prinstartdate", $part);
       my $end   = $self->parmval("printenddate", $part);
   
       #  The following cases apply:
       #  - No dates set: Printable.
       #  - Start date set but no end date: Printable if now >= start date.
       #  - End date set but no start date: Printable if now <= end date.
       #  - both defined: printable if start <= now <= end
       #
       my $now  = time();
   
       my $startok = 1;
       my $endok   = 1;
   
       if ((defined $start) && ($start ne '')) {
    $startok = $start <= $now;
       }
       if ((defined $end) && ($end != '')) {
    $endok = $end >= $now;
       }
       return $startok && $endok;
   }
   
   sub resprintable {
       my $self = shift;
   
       # get parts...or realize there are no parts.
   
       my $partsref = $self->parts();
       my @parts    = @$partsref;
   
       if ((!defined(@parts)) || (scalar(@parts) == 0)) {
    return $self->printable(0);
       } else {
    foreach my $part  (@parts) {
       if (!$self->printable($part)) { 
    return 0; 
       }
    }
    return 1;
       }
   }
   
 sub acc {  sub acc {
     (my $self, my $part) = @_;      (my $self, my $part) = @_;
     my $acc = $self->parmval("acc", $part);      my $acc = $self->parmval("acc", $part);
Line 4015  sub checkedin { Line 4232  sub checkedin {
     }      }
 }  }
 # this should work exactly like the copy in lonhomework.pm  # this should work exactly like the copy in lonhomework.pm
   # Why is there a copy in lonhomework?  Why not centralized?
   #
   #  TODO: Centralize duedate.
   #
   
 sub duedate {  sub duedate {
     (my $self, my $part) = @_;      (my $self, my $part) = @_;
     my $date;      my $date;
Line 4094  sub weight { Line 4316  sub weight {
     my $self = shift; my $part = shift;      my $self = shift; my $part = shift;
     if (!defined($part)) { $part = '0'; }      if (!defined($part)) { $part = '0'; }
     my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',      my $weight = &Apache::lonnet::EXT('resource.'.$part.'.weight',
                                 $self->symb(), $env{'user.domain'},                                  $self->symb(), $self->{DOMAIN},
                                 $env{'user.name'},                                  $self->{USERNAME},
                                 $env{'request.course.sec'});                                  $env{'request.course.sec'});
     return $weight;      return $weight;
 }  }
Line 4123  sub getReturnHash { Line 4345  sub getReturnHash {
     my $self = shift;      my $self = shift;
           
     if (!defined($self->{RETURN_HASH})) {      if (!defined($self->{RETURN_HASH})) {
         my %tmpHash  = &Apache::lonnet::restore($self->symb());          my %tmpHash  = &Apache::lonnet::restore($self->symb(),undef,$self->{DOMAIN},$self->{USERNAME});
         $self->{RETURN_HASH} = \%tmpHash;          $self->{RETURN_HASH} = \%tmpHash;
     }      }
 }         }       
Line 4635  Information not available due to network Line 4857  Information not available due to network
   
 Attempted, and not yet graded.  Attempted, and not yet graded.
   
   =item * B<CREDIT_ATTEMPTED>:
   
   Attempted, and credit received for attempt (survey and anonymous survey only).
   
 =back  =back
   
 =cut  =cut
Line 4646  sub CORRECT               { return 13; } Line 4872  sub CORRECT               { return 13; }
 sub CORRECT_BY_OVERRIDE   { return 14; }  sub CORRECT_BY_OVERRIDE   { return 14; }
 sub EXCUSED               { return 15; }  sub EXCUSED               { return 15; }
 sub ATTEMPTED             { return 16; }  sub ATTEMPTED             { return 16; }
   sub CREDIT_ATTEMPTED      { return 17; }
   
 sub getCompletionStatus {  sub getCompletionStatus {
     my $self = shift;      my $self = shift;
Line 4664  sub getCompletionStatus { Line 4891  sub getCompletionStatus {
     if ($status eq 'incorrect_by_override') {return $self->INCORRECT_BY_OVERRIDE; }      if ($status eq 'incorrect_by_override') {return $self->INCORRECT_BY_OVERRIDE; }
     if ($status eq 'excused') {return $self->EXCUSED; }      if ($status eq 'excused') {return $self->EXCUSED; }
     if ($status eq 'ungraded_attempted') {return $self->ATTEMPTED; }      if ($status eq 'ungraded_attempted') {return $self->ATTEMPTED; }
       if ($status eq 'credit_attempted') {
           if ($self->is_anonsurvey($part) || $self->is_survey($part)) {
               return $self->CREDIT_ATTEMPTED;
           } else {
               return $self->ATTEMPTED;
           }
       }
     return $self->NOT_ATTEMPTED;      return $self->NOT_ATTEMPTED;
 }  }
   
Line 4753  The item is open and not yet tried. Line 4987  The item is open and not yet tried.
   
 The problem has been attempted.  The problem has been attempted.
   
   =item * B<CREDIT_ATTEMPTED>:
   
   The problem has been attempted, and credit given for the attempt (survey and anonymous survey only).
   
 =item * B<ANSWER_SUBMITTED>:  =item * B<ANSWER_SUBMITTED>:
   
 An answer has been submitted, but the student should not see it.  An answer has been submitted, but the student should not see it.
Line 4826  sub status { Line 5064  sub status {
         return ATTEMPTED;          return ATTEMPTED;
     }      }
   
       if ($completionStatus == CREDIT_ATTEMPTED) {
           return CREDIT_ATTEMPTED;
       }
   
     # If it's EXCUSED, then return that no matter what      # If it's EXCUSED, then return that no matter what
     if ($completionStatus == EXCUSED) {      if ($completionStatus == EXCUSED) {
         return EXCUSED;           return EXCUSED; 
Line 4864  sub status { Line 5106  sub status {
     }      }
   
     # Otherwise, it's untried and open      # Otherwise, it's untried and open
     return OPEN;       return OPEN;
 }  }
   
 sub check_for_slot {  sub check_for_slot {
     my $self = shift;      my $self = shift;
     my $part = shift;      my $part = shift;
       my $symb = $self->symb();
     my ($use_slots,$available,$availablestudent) = $self->slot_control($part);      my ($use_slots,$available,$availablestudent) = $self->slot_control($part);
     if (($use_slots ne '') && ($use_slots !~ /^\s*no\s*$/i)) {      if (($use_slots ne '') && ($use_slots !~ /^\s*no\s*$/i)) {
         my @slots = (split(/:/,$availablestudent),split(/:/,$available));          my @slots = (split(/:/,$availablestudent),split(/:/,$available));
Line 4877  sub check_for_slot { Line 5120  sub check_for_slot {
         my $cdom=$env{'course.'.$cid.'.domain'};          my $cdom=$env{'course.'.$cid.'.domain'};
         my $cnum=$env{'course.'.$cid.'.num'};          my $cnum=$env{'course.'.$cid.'.num'};
         my $now = time;          my $now = time;
           my $num_usable_slots = 0;
         if (@slots > 0) {          if (@slots > 0) {
             my %slots=&Apache::lonnet::get('slots',[@slots],$cdom,$cnum);              my %slots=&Apache::lonnet::get('slots',[@slots],$cdom,$cnum);
             if (&Apache::lonnet::error(%slots)) {              if (&Apache::lonnet::error(%slots)) {
                 return (UNKNOWN);                  return (UNKNOWN);
             }              }
             my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots);              my @sorted_slots = &Apache::loncommon::sorted_slots(\@slots,\%slots,'starttime');
             my ($checkedin,$checkedinslot);              my ($checkedin,$checkedinslot);
             foreach my $slot_name (@sorted_slots) {              foreach my $slot_name (@sorted_slots) {
                 next if (!defined($slots{$slot_name}) ||                  next if (!defined($slots{$slot_name}) || !ref($slots{$slot_name}));
                          !ref($slots{$slot_name}));  
                 my $end = $slots{$slot_name}->{'endtime'};                  my $end = $slots{$slot_name}->{'endtime'};
                 my $start = $slots{$slot_name}->{'starttime'};                  my $start = $slots{$slot_name}->{'starttime'};
                 my $ip = $slots{$slot_name}->{'ip'};                  my $ip = $slots{$slot_name}->{'ip'};
                 if ($self->simpleStatus() == OPEN) {                  if ($self->simpleStatus() == OPEN) {
                     my $startreserve = $slots{$slot_name}->{'startreserve'};  
                     my @proctors;  
                     if ($slots{$slot_name}->{'proctor'} ne '') {  
                         @proctors = split(',',$slots{$slot_name}->{'proctor'});  
                     }  
                     if ($end > $now) {                      if ($end > $now) {
                         ($checkedin,$checkedinslot) = $self->checkedin();                          if ($start > $now) {
                         if ($startreserve < $now) {                              return (RESERVED_LATER,$start,$slot_name);
                             if ($start > $now) {                          } else {
                                 return (RESERVED_LATER,$start,$slot_name);                              if ($ip ne '') {
                             } else {                                  if (!&Apache::loncommon::check_ip_acc($ip)) {
                                 if ($ip ne '') {                                      return (RESERVED_LOCATION,$ip,$slot_name);
                                     if (!&Apache::loncommon::check_ip_acc($ip)) {  
                                         return (RESERVED_LOCATION,$ip,$slot_name);  
                                     }  
                                 }   
                                 if (@proctors > 0) {  
                                     unless ((grep(/^\Q$checkedin\E/,@proctors)) &&  
                                         ($checkedinslot eq $slot_name)) {  
                                         return (NEEDS_CHECKIN,undef,$slot_name);   
                                     }  
                                 }                                  }
                                 return (RESERVED,$end,$slot_name);  
                             }                              }
                         } else {                              my @proctors;
                             if ($start > $now) {                              if ($slots{$slot_name}->{'proctor'} ne '') {
                                 return (RESERVABLE,$startreserve,$slot_name);                                  @proctors = split(',',$slots{$slot_name}->{'proctor'});
                             }                              }
                               if (@proctors > 0) {
                                   ($checkedin,$checkedinslot) = $self->checkedin();
                                   unless ((grep(/^\Q$checkedin\E/,@proctors)) &&
                                           ($checkedinslot eq $slot_name)) {
                                       return (NEEDS_CHECKIN,undef,$slot_name); 
                                   }
                               }
                               return (RESERVED,$end,$slot_name);
                         }                          }
                     }                      }
                   } elsif ($end > $now) {
                       $num_usable_slots ++;
                 }                  }
             }              }
             my ($is_correct,$got_grade);              my ($is_correct,$got_grade);
Line 4928  sub check_for_slot { Line 5166  sub check_for_slot {
                 my $taskstatus = $self->taskstatus();                  my $taskstatus = $self->taskstatus();
                 $is_correct = (($taskstatus eq 'pass') ||                   $is_correct = (($taskstatus eq 'pass') || 
                                ($self->solved() =~ /^correct_/));                                 ($self->solved() =~ /^correct_/));
                 $got_grade = ($self->solved() =~ /^(?:pass|fail)$/);                  $got_grade = ($taskstatus =~ /^(?:pass|fail)$/);
             } else {              } else {
                 $got_grade = 1;                  $got_grade = 1;
                 $is_correct = ($self->solved() =~ /^correct_/);                     $is_correct = ($self->solved() =~ /^correct_/);   
Line 4941  sub check_for_slot { Line 5179  sub check_for_slot {
                     return (CORRECT);                       return (CORRECT); 
                 }                  }
             }              }
             return(NOT_IN_A_SLOT);              if ($num_usable_slots) {
         } else {  
             if (!$future_slots_checked) {  
                 $future_slots = &get_future_slots($cdom,$cnum,$now);  
                 $future_slots_checked = 1;  
             }  
             if ($future_slots) {  
                 return(NOT_IN_A_SLOT);                  return(NOT_IN_A_SLOT);
             }              }
             return(NOTRESERVABLE);  
         }          }
     }          my $reservable = &Apache::lonnet::get_reservable_slots($cnum,$cdom,$env{'user.name'},
     return;                                                                 $env{'user.domain'});
 }          if (ref($reservable) eq 'HASH') {
               if ((ref($reservable->{'now_order'}) eq 'ARRAY') && (ref($reservable->{'now'}) eq 'HASH')) {
 sub get_future_slots {                  foreach my $slot (reverse (@{$reservable->{'now_order'}})) {
     my ($cdom,$cnum,$now) = @_;                      if (($reservable->{'now'}{$slot}{'symb'} eq '') ||
     my %slots=&Apache::lonnet::dump('slots',$cdom,$cnum);                          ($reservable->{'now'}{$slot}{'symb'} eq $symb)) {
     my $future_slots = 0;                          return(RESERVABLE,$reservable->{'now'}{$slot}{'endreserve'});
     foreach my $slot (keys(%slots)) {                      }
         if (($slots{$slot}->{'starttime'} > $now) &&                  }
             ($slots{$slot}->{'endtime'} > $now)) {              }
             $future_slots ++;              if ((ref($reservable->{'future_order'}) eq 'ARRAY') && (ref($reservable->{'future'}) eq 'HASH')) {
                   foreach my $slot (@{$reservable->{'future_order'}}) {
                       if (($reservable->{'future'}{$slot}{'symb'} eq '') ||
                           ($reservable->{'future'}{$slot}{'symb'} eq $symb)) {
                           return(RESERVABLE_LATER,$reservable->{'future'}{$slot}{'startreserve'});
                       }
                   }
               }
         }          }
           return(NOTRESERVABLE);
     }      }
     return $future_slots;      return;
 }  }
   
 sub CLOSED { return 23; }  sub CLOSED { return 23; }
Line 5018  my %compositeToSimple = Line 5257  my %compositeToSimple =
       INCORRECT()             => INCORRECT,        INCORRECT()             => INCORRECT,
       OPEN()                  => OPEN,        OPEN()                  => OPEN,
       ATTEMPTED()             => ATTEMPTED,        ATTEMPTED()             => ATTEMPTED,
         CREDIT_ATTEMPTED()      => CORRECT,
       ANSWER_SUBMITTED()      => ATTEMPTED        ANSWER_SUBMITTED()      => ATTEMPTED
      );       );
   
Line 5092  sub completable { Line 5332  sub completable {
         # and it is not "attempted" (manually graded problem), it is          # and it is not "attempted" (manually graded problem), it is
         # not "complete"          # not "complete"
  if ($self->getCompletionStatus($part) == ATTEMPTED() ||   if ($self->getCompletionStatus($part) == ATTEMPTED() ||
               $self->getCompletionStatus($part) == CREDIT_ATTEMPTED() ||
     $status == ANSWER_SUBMITTED() ) {      $status == ANSWER_SUBMITTED() ) {
     # did this part already, as well as we can      # did this part already, as well as we can
     next;      next;

Removed from v.1.449  
changed lines
  Added in v.1.477


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