Diff for /loncom/interface/loncommon.pm between versions 1.1385 and 1.1412

version 1.1385, 2022/06/30 21:04:14 version 1.1412, 2023/09/25 22:36:29
Line 71  use Apache::lonuserutils(); Line 71  use Apache::lonuserutils();
 use Apache::lonuserstate();  use Apache::lonuserstate();
 use Apache::courseclassifier();  use Apache::courseclassifier();
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
   use LONCAPA::ltiutils;
 use LONCAPA::LWPReq;  use LONCAPA::LWPReq;
   use LONCAPA::map();
 use HTTP::Request;  use HTTP::Request;
 use DateTime::TimeZone;  use DateTime::TimeZone;
 use DateTime::Locale;  use DateTime::Locale;
Line 957  ENDSCRT Line 959  ENDSCRT
 }  }
   
 sub select_timezone {  sub select_timezone {
    my ($name,$selected,$onchange,$includeempty,$disabled)=@_;     my ($name,$selected,$onchange,$includeempty,$id,$disabled)=@_;
    my $output='<select name="'.$name.'" '.$onchange.$disabled.'>'."\n";     my $output='<select name="'.$name.'" '.$id.$onchange.$disabled.'>'."\n";
    if ($includeempty) {     if ($includeempty) {
        $output .= '<option value=""';         $output .= '<option value=""';
        if (($selected eq '') || ($selected eq 'local')) {         if (($selected eq '') || ($selected eq 'local')) {
Line 1232  END Line 1234  END
         $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";          $result.=">".&mt($hashref->{$value}->{'text'})."</option>\n";
     }      }
     $result .= "</select>\n";      $result .= "</select>\n";
     my %select2 = %{$hashref->{$firstdefault}->{'select2'}};      my %select2;
       if (ref($hashref->{$firstdefault}) eq 'HASH') {
           if (ref($hashref->{$firstdefault}->{'select2'}) eq 'HASH') {
               %select2 = %{$hashref->{$firstdefault}->{'select2'}};
           }
       }
     $result .= $middletext;      $result .= $middletext;
     $result .= "<select size=\"1\" name=\"$secondselectname\"";      $result .= "<select size=\"1\" name=\"$secondselectname\"";
     if ($onchangesecond) {      if ($onchangesecond) {
Line 1815  sub colorfuleditor_js { Line 1822  sub colorfuleditor_js {
             save => 'Save page to make this permanent',              save => 'Save page to make this permanent',
         );          );
         &js_escape(\%js_lt);          &js_escape(\%js_lt);
           my $showfile_js = &show_crsfiles_js();
         $browse_or_search = <<"END";          $browse_or_search = <<"END";
   
       $showfile_js
   
     function toggleChooser(form,element,titleid,only,search) {      function toggleChooser(form,element,titleid,only,search) {
         var disp = 'none';          var disp = 'none';
         if (document.getElementById('chooser_'+element)) {          if (document.getElementById('chooser_'+element)) {
Line 1831  sub colorfuleditor_js { Line 1841  sub colorfuleditor_js {
                 toggleResImport(form,element);                  toggleResImport(form,element);
             }              }
             document.getElementById('chooser_'+element).style.display = disp;              document.getElementById('chooser_'+element).style.display = disp;
               var dirsel = '';
               var filesel = '';
               if (document.getElementById('chooser_'+element+'_crsres')) {
                   var currcrsres = document.getElementById('chooser_'+element+'_crsres').style.display;
                   if (currcrsres == 'none') {
                       dirsel = 'coursepath_'+element;
                       var filesel = 'coursefile_'+element;
                       var include;
                       if (document.getElementById('crsres_include_'+element)) {
                           include = document.getElementById('crsres_include_'+element).value;
                       }
                       populateCrsSelects(form,dirsel,filesel,1,include,1,0,1,1,0);
                   }
               }
               if (document.getElementById('chooser_'+element+'_upload')) {
                   var currcrsupload = document.getElementById('chooser_'+element+'_upload').style.display;
                   if (currcrsupload == 'none') {
                       dirsel = 'crsauthorpath_'+element;
                       filesel = '';
                       populateCrsSelects(form,dirsel,filesel,0,'',1,0,1,0,1);
                   }
               }
         }          }
     }      }
   
     function toggleCrsFile(form,element,numdirs) {      function toggleCrsFile(form,element) {
         if (document.getElementById('chooser_'+element+'_crsres')) {          if (document.getElementById('chooser_'+element+'_crsres')) {
             var curr = document.getElementById('chooser_'+element+'_crsres').style.display;              var curr = document.getElementById('chooser_'+element+'_crsres').style.display;
             if (curr == 'none') {              if (curr == 'none') {
                 if (numdirs) {                  if (document.getElementById('coursepath_'+element)) {
                       var numdirs;
                       if (document.getElementById('coursepath_'+element).length) {
                           numdirs = document.getElementById('coursepath_'+element).length;
                       }
                       if ((document.getElementById('hascrsres_'+element)) &&
                           (document.getElementById('nocrsres_'+element))) {
                           if (numdirs) {
                               document.getElementById('hascrsres_'+element).style.display='inline-block';
                               document.getElementById('nocrsres_'+element).style.display='none';
                           } else {
                               document.getElementById('hascrsres_'+element).style.display='none';
                               document.getElementById('nocrsres_'+element).style.display='inline-block';
                           }
                       }
                     form.elements['coursepath_'+element].selectedIndex = 0;                      form.elements['coursepath_'+element].selectedIndex = 0;
                     if (numdirs > 1) {                      if (numdirs > 1) {
                         window['select1'+element+'_changed']();                          var selelem = form.elements['coursefile_'+element];
                           var i, len = selelem.options.length -1;
                           if (len >=0) {
                               for (i = len; i >= 0; i--) {
                                   selelem.remove(i);
                               }
                               selelem.options[0] = new Option('','');
                           }
                     }                      }
                 }                  }
             }               }
             document.getElementById('chooser_'+element+'_crsres').style.display = 'block';              document.getElementById('chooser_'+element+'_crsres').style.display = 'block';
               
         }          }
         if (document.getElementById('chooser_'+element+'_upload')) {          if (document.getElementById('chooser_'+element+'_upload')) {
             document.getElementById('chooser_'+element+'_upload').style.display = 'none';              document.getElementById('chooser_'+element+'_upload').style.display = 'none';
Line 1857  sub colorfuleditor_js { Line 1909  sub colorfuleditor_js {
         return;          return;
     }      }
   
     function toggleCrsUpload(form,element,numcrsdirs) {      function toggleCrsUpload(form,element) {
         if (document.getElementById('chooser_'+element+'_crsres')) {          if (document.getElementById('chooser_'+element+'_crsres')) {
             document.getElementById('chooser_'+element+'_crsres').style.display = 'none';              document.getElementById('chooser_'+element+'_crsres').style.display = 'none';
         }          }
         if (document.getElementById('chooser_'+element+'_upload')) {          if (document.getElementById('chooser_'+element+'_upload')) {
             var curr = document.getElementById('chooser_'+element+'_upload').style.display;              var curr = document.getElementById('chooser_'+element+'_upload').style.display;
             if (curr == 'none') {              if (curr == 'none') {
                 if (numcrsdirs) {                  form.elements['newsubdir_'+element][0].checked = true;
                    form.elements['crsauthorpath_'+element].selectedIndex = 0;                  toggleNewsubdir(form,element);
                    form.elements['newsubdir_'+element][0].checked = true;                  document.getElementById('chooser_'+element+'_upload').style.display = 'block';
                    toggleNewsubdir(form,element);                  if (document.getElementById('uploadcrsres_'+element)) {
                       document.getElementById('uploadcrsres_'+element).value = '';
                 }                  }
             }              }
             document.getElementById('chooser_'+element+'_upload').style.display = 'block';  
         }          }
         return;          return;
     }      }
Line 1914  sub colorfuleditor_js { Line 1966  sub colorfuleditor_js {
         var filename = form.elements['coursefile_'+element];          var filename = form.elements['coursefile_'+element];
         var path = directory.options[directory.selectedIndex].value;          var path = directory.options[directory.selectedIndex].value;
         var file = filename.options[filename.selectedIndex].value;          var file = filename.options[filename.selectedIndex].value;
         form.elements[element].value = '$respath';          if (file != '') {
         if (path == '/') {              form.elements[element].value = '$respath';
             form.elements[element].value += file;              if (path == '/') {
         } else {                  form.elements[element].value += file;
             form.elements[element].value += path+'/'+file;              } else {
         }                  form.elements[element].value += path+'/'+file;
         unClean();              }
         if (document.getElementById('previewimg_'+element)) {              unClean();
             document.getElementById('previewimg_'+element).src = form.elements[element].value;              if (document.getElementById('previewimg_'+element)) {
             var newsrc = document.getElementById('previewimg_'+element).src;                   document.getElementById('previewimg_'+element).src = form.elements[element].value;
         }                  var newsrc = document.getElementById('previewimg_'+element).src; 
         if (document.getElementById('showimg_'+element)) {              }
             document.getElementById('showimg_'+element).innerHTML = '($js_lt{save})';              if (document.getElementById('showimg_'+element)) {
                   document.getElementById('showimg_'+element).innerHTML = '($js_lt{save})';
               }
         }          }
         toggleChooser(form,element);          toggleChooser(form,element);
         return;          return;
Line 2215  sub crsauthor_url { Line 2269  sub crsauthor_url {
 }  }
   
 sub import_crsauthor_form {  sub import_crsauthor_form {
     my ($form,$firstselectname,$secondselectname,$onchangefirst,$only,$suffix,$disabled) = @_;      my ($firstselectname,$secondselectname,$onchangefirst,$only,$suffix,$disabled) = @_;
     return (0) unless ($env{'request.course.id'});      return (0) unless ($env{'request.course.id'});
     my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};      my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
     my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};      my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
     my $crshome = $env{'course.'.$env{'request.course.id'}.'.home'};      my $crshome = $env{'course.'.$env{'request.course.id'}.'.home'};
     return (0) unless (($cnum ne '') && ($cdom ne ''));      return (0) unless (($cnum ne '') && ($cdom ne ''));
     my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};  
     my @ids=&Apache::lonnet::current_machine_ids();      my @ids=&Apache::lonnet::current_machine_ids();
     my ($output,$is_home,$relpath,%subdirs,%files,%selimport_menus);      my ($output,$is_home,$toppath,%subdirs,%files,%selimport_menus,$include,$exclude);
       
     if (grep(/^\Q$crshome\E$/,@ids)) {      if (grep(/^\Q$crshome\E$/,@ids)) {
         $is_home = 1;          $is_home = 1;
     }      }
     $relpath = "/priv/$cdom/$cnum";      $toppath = "/priv/$cdom/$cnum";
     &Apache::lonnet::recursedirs($is_home,'priv',$londocroot,$relpath,'',\%subdirs,\%files);      my $nonemptydir = 1;
       my $js_only;
       if ($only) {
           map { $include->{$_} = 1; } split(/\s*,\s*/,$only);
           $js_only = join(',',map { &js_escape($_); } sort(keys(%{$include})));
       }
       $exclude = &Apache::lonnet::priv_exclude();
       &Apache::lonnet::recursedirs($is_home,1,$include,$exclude,1,0,$toppath,'',\%subdirs,\%files);
       my $numdirs = scalar(keys(%files));
     my %lt = &Apache::lonlocal::texthash (      my %lt = &Apache::lonlocal::texthash (
         fnam => 'Filename',          fnam => 'Filename',
         dire => 'Directory',          dire => 'Directory',
           se   => 'Select',
     );      );
     my $numdirs = scalar(keys(%files));      $output = $lt{'dire'}.':&nbsp;'.
     my (%possexts,$singledir,@singledirfiles);                '<select id="'.$firstselectname.'" name="'.$firstselectname.'" '.
     if ($only) {                'onchange="populateCrsSelects(this.form,'."'$firstselectname','$secondselectname',1,'$js_only',0,1,0,0,0".');">'.
         map { $possexts{$_} = 1; } split(/\s*,\s*/,$only);                '<option value="" selected="selected">'.$lt{'se'}.'</option>';
     }      if ($files{'/'}) {
     my (%nonemptydirs,$possdirs);          $output .= '<option value="/">/</option>'."\n";
     if ($numdirs > 1) {      }
         my @order;      foreach my $key (sort { lc($a) cmp lc($b) } (keys(%files))) {
         foreach my $key (sort { lc($a) cmp lc($b) } (keys(%files))) {          next if ($key eq '/');
             if (ref($files{$key}) eq 'HASH') {          $output .= '<option value="'.$key.'">'.$key.'</option>'."\n";
                 my $shown = $key;      }
                 if ($key eq '') {      $output .= '</select><br />'."\n".
                     $shown = '/';                 $lt{'fnam'}.':&nbsp;<select id="'.$secondselectname.'" name="'.$secondselectname.'">'."\n".
                 }                 '<option value="" selected="selected"></option>'."\n".
                 my @ordered = ();                 '</select>'."\n".
                 foreach my $file (sort { lc($a) cmp lc($b) } (keys(%{$files{$key}}))) {                 '<input type="hidden" id="crsres_include_'.$suffix.'" value="'.$only.'" />';
                     next if ($file =~ /\.rights$/);      return ($numdirs,$output);
                     if ($only) {  }
                         my ($ext) = ($file =~ /\.([^.]+)$/);  
                         unless ($possexts{lc($ext)}) {  sub show_crsfiles_js {
                             next;      my $excluderef = &Apache::lonnet::priv_exclude();
                         }      my $se = &js_escape(&mt('Select'));
       my $exclude;
       if (ref($excluderef) eq 'HASH') {
           $exclude = join(',', map { &js_escape($_); } sort(keys(%{$excluderef})));
       }
       my $js = <<"END";
   
   
       function populateCrsSelects (form,dirsel,filesel,exc,include,setdir,setfile,recurse,nonemptydir,addtopdir) {
           var relpath = '';
           if ((setfile) && (dirsel != null) && (dirsel != 'undefined') && (dirsel != '')) {
               var currdir = form.elements[dirsel].options[form.elements[dirsel].selectedIndex].value;
               if (currdir == '') {
                   if ((filesel != null) && (filesel != 'undefined') && (filesel != '')) {
                       selelem = form.elements[filesel];
                       var j, numfiles = selelem.options.length -1;
                       if (numfiles >=0) {
                           for (j = numfiles; j >= 0; j--) {
                               selelem.remove(j);
                           }
                       }
                       if (selelem.options.length == 0) {
                           selelem.options[selelem.options.length] = new Option('','');
                           selelem.selectedIndex = 0;
                     }                      }
                     $selimport_menus{$key}->{'select2'}->{$file} = $file;  
                     push(@ordered,$file);  
                 }  
                 if (@ordered) {  
                     push(@order,$key);  
                     $nonemptydirs{$key} = 1;  
                     $selimport_menus{$key}->{'text'} = $shown;  
                     $selimport_menus{$key}->{'default'} = '';  
                     $selimport_menus{$key}->{'select2'}->{''} = '';  
                     $selimport_menus{$key}->{'order'} = \@ordered;  
                 }                  }
                   return;
               } else {
                   relpath = encodeURIComponent(form.elements[dirsel].options[form.elements[dirsel].selectedIndex].value);
             }              }
         }          }
         $possdirs = scalar(keys(%nonemptydirs));          var http = new XMLHttpRequest();
         if ($possdirs > 1) {          var url = "/adm/courseauthor";
             my @order = sort { lc($a) cmp lc($b) } (keys(%nonemptydirs));          var crsrole = "$env{'request.role'}";
             $output = $lt{'dire'}.          var exclude = '';
                       &linked_select_forms($form,'<br />'.          if (exc) {
                                            $lt{'fnam'},'',              exclude = '$exclude';
                                            $firstselectname,$secondselectname,          }
                                            \%selimport_menus,\@order,          var params = "role=course&files=1&rec="+recurse+"&nonempty="+nonemptydir+"&exc="+exclude+"&inc="+include+"&addtop="+addtopdir+"&path="+relpath;
                                            $onchangefirst,'',$suffix).'<br />';          http.open("POST", url, true);
         } elsif ($possdirs == 1) {          http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
             $singledir = (keys(%nonemptydirs))[0];          http.onreadystatechange = function() {
             if (ref($selimport_menus{$singledir}->{'order'}) eq 'ARRAY') {              if (http.readyState == 4 && http.status == 200) {
                 @singledirfiles = @{$selimport_menus{$singledir}->{'order'}};                  var data = JSON.parse(http.responseText);
             }                  var selelem;
             delete($selimport_menus{$singledir});                  if ((setdir) && (dirsel != null) && (dirsel != 'undefined') && (dirsel != '')) {
         }                      if (Array.isArray(data.dirs)) {
     } elsif ($numdirs == 1) {                          selelem = form.elements[dirsel];
         $singledir = (keys(%files))[0];                          var i, numdirs = selelem.options.length -1;
         foreach my $file (sort { lc($a) cmp lc($b) } (keys(%{$files{$singledir}}))) {                          if (numdirs >=0) {
             if ($only) {                              for (i = numdirs; i >= 0; i--) {
                 my ($ext) = ($file =~ /\.([^.]+)$/);                                  selelem.remove(i);
                 unless ($possexts{lc($ext)}) {                              }
                     next;                          }
                           var len = data.dirs.length;
                           if (len) {
                               selelem.options[selelem.options.length] = new Option('$se','');
                               var j;
                               for (j = 0; j < len; j++) {
                                   selelem.options[selelem.options.length] = new Option(data.dirs[j],data.dirs[j]);
                               }
                               selelem.selectedIndex = 0;
                           }
                           if (!setfile) {
                               if ((filesel != null) && (filesel != 'undefined') && (filesel != '')) {
                                   selelem = form.elements[filesel];
                                   var j, numfiles = selelem.options.length -1;
                                   if (numfiles >=0) {
                                       for (j = numfiles; j >= 0; j--) {
                                           selelem.remove(j);
                                       }
                                   }
                                   if (selelem.options.length == 0) {
                                       selelem.options[selelem.options.length] = new Option('','');
                                       selelem.selectedIndex = 0;
                                   }
                               }
                           }
                       }
                   }
                   if ((setfile) && (filesel != null) && (filesel != 'undefined') && (filesel != '')) {
                       selelem = form.elements[filesel];
                       var i, numfiles = selelem.options.length -1;
                       if (numfiles >=0) {
                           for (i = numfiles; i >= 0; i--) {
                               selelem.remove(i);
                           }
                       }
                       var x;
                       for (x in data.files) {
                           if (Array.isArray(data.files[x])) {
                               if (data.files[x].length > 1) {
                                   selelem.options[selelem.options.length] = new Option('$se','');
                               }
                               var len = data.files[x].length;
                               if (len) {
                                   var k;
                                   for (k = 0; k < len; k++) {
                                       selelem.options[selelem.options.length] = new Option(data.files[x][k],data.files[x][k]);
                                   }
                                   selelem.selectedIndex = 0;
                               }
                           }
                       }
                       if (selelem.options.length == 0) {
                           selelem.options[selelem.options.length] = new Option('','');
                           selelem.selectedIndex = 0;
                       }
                 }                  }
             } else {  
                 next if ($file =~ /\.rights$/);  
             }              }
             push(@singledirfiles,$file);  
         }  
         if (@singledirfiles) {  
             $possdirs = 1;  
         }          }
           http.send(params);
     }      }
     if (($possdirs == 1) && (@singledirfiles)) {  END
         my $showdir = $singledir;  
         if ($singledir eq '') {  
             $showdir = '/';  
         }  
         $output = $lt{'dire'}.  
                   '<select name="'.$firstselectname.'">'.  
                   '<option value="'.$singledir.'">'.$showdir.'</option>'."\n".  
                   '</select><br />'.  
                   $lt{'fnam'}.'<select name="'.$secondselectname.'">'."\n".  
                   '<option value="" selected="selected">'.$lt{'se'}.'</option>'."\n";  
         foreach my $file (@singledirfiles) {  
             $output .= '<option value="'.$file.'">'.$file.'</option>'."\n";  
         }  
         $output .= '</select><br />'."\n";  
     }  
     return ($possdirs,$output);  
 }  }
   
 =pod  =pod
Line 2671  sub display_filter { Line 2782  sub display_filter {
     my $onchange = "javascript:toggleHistoryOptions(this,'containingphrase','$context',      my $onchange = "javascript:toggleHistoryOptions(this,'containingphrase','$context',
                                                     '$secondid','$thirdid')";                                                      '$secondid','$thirdid')";
     return '<span class="LC_nobreak"><label>'.&mt('Records: [_1]',      return '<span class="LC_nobreak"><label>'.&mt('Records: [_1]',
        &Apache::lonmeta::selectbox('show',$env{'form.show'},undef,         &Apache::lonmeta::selectbox('show',$env{'form.show'},'',undef,
    (&mt('all'),10,20,50,100,1000,10000))).     (&mt('all'),10,20,50,100,1000,10000))).
    '</label></span> <span class="LC_nobreak">'.     '</label></span> <span class="LC_nobreak">'.
            &mt('Filter: [_1]',             &mt('Filter: [_1]',
Line 4284  sub syllabuswrapper { Line 4395  sub syllabuswrapper {
   
 # -----------------------------------------------------------------------------  # -----------------------------------------------------------------------------
   
   sub aboutme_on {
       my ($uname,$udom)=@_;
       unless ($uname) { $uname=$env{'user.name'}; }
       unless ($udom)  { $udom=$env{'user.domain'}; }
       return if ($udom eq 'public' && $uname eq 'public');
       my $hashkey=$uname.':'.$udom;
       my ($aboutme,$cached)=&Apache::lonnet::is_cached_new('aboutme',$hashkey);
       if ($cached) {
           return $aboutme;
       }
       $aboutme = &Apache::lonnet::usertools_access($uname,$udom,'aboutme');
       &Apache::lonnet::do_cache_new('aboutme',$hashkey,$aboutme,3600);
       return $aboutme;
   }
   
   sub devalidate_aboutme_cache {
       my ($uname,$udom)=@_;
       if (!$udom)  { $udom =$env{'user.domain'}; }
       if (!$uname) { $uname=$env{'user.name'};   }
       return if ($udom eq 'public' && $uname eq 'public');
       my $id=$uname.':'.$udom;
       &Apache::lonnet::devalidate_cache_new('aboutme',$id);
   }
   
 sub track_student_link {  sub track_student_link {
     my ($linktext,$sname,$sdom,$target,$start,$only_body) = @_;      my ($linktext,$sname,$sdom,$target,$start,$only_body) = @_;
     my $link ="/adm/trackstudent?";      my $link ="/adm/trackstudent?";
Line 5998  sub get_domainconf { Line 6133  sub get_domainconf {
                                 foreach my $host (keys(%{$domconfig{'login'}{$key}})) {                                  foreach my $host (keys(%{$domconfig{'login'}{$key}})) {
                                     if (ref($domconfig{'login'}{$key}{$host}) eq 'HASH') {                                      if (ref($domconfig{'login'}{$key}{$host}) eq 'HASH') {
                                         $designhash{$udom.'.login.'.$key.'_'.$host} = 1;                                          $designhash{$udom.'.login.'.$key.'_'.$host} = 1;
                                         foreach my $item ('text','img','alt','url','title','notsso') {                                          foreach my $item ('text','img','alt','url','title','window','notsso') {
                                             $designhash{$udom.'.login.'.$key.'_'.$item.'_'.$host} = $domconfig{'login'}{$key}{$host}{$item};                                              $designhash{$udom.'.login.'.$key.'_'.$item.'_'.$host} = $domconfig{'login'}{$key}{$host}{$item};
                                         }                                          }
                                     }                                      }
Line 6235  Input: (optional) filename from which br Line 6370  Input: (optional) filename from which br
        If page header is being requested for use in a frameset, then         If page header is being requested for use in a frameset, then
        the second (option) argument -- frameset will be true, and         the second (option) argument -- frameset will be true, and
        the target attribute set for links should be target="_parent".         the target attribute set for links should be target="_parent".
          If $title is supplied as the thitd arg, that will be used to 
          the left of the breadcrumbs tail for the current path.
   
 Returns: HTML div with CSTR path and recent box  Returns: HTML div with CSTR path and recent box
          To be included on Authoring Space pages           To be included on Authoring Space pages
Line 6242  Returns: HTML div with CSTR path and rec Line 6379  Returns: HTML div with CSTR path and rec
 =cut  =cut
   
 sub CSTR_pageheader {  sub CSTR_pageheader {
     my ($trailfile,$frameset) = @_;      my ($trailfile,$frameset,$title) = @_;
     if ($trailfile eq '') {      if ($trailfile eq '') {
         $trailfile = $env{'request.filename'};          $trailfile = $env{'request.filename'};
     }      }
Line 6265  sub CSTR_pageheader { Line 6402  sub CSTR_pageheader {
         $lastitem = $thisdisfn;          $lastitem = $thisdisfn;
     }      }
   
     my ($crsauthor,$title);      my $crsauthor;
     if (($env{'request.course.id'}) &&      if (($env{'request.course.id'}) &&
         ($env{'course.'.$env{'request.course.id'}.'.num'} eq $uname) &&          ($env{'course.'.$env{'request.course.id'}.'.num'} eq $uname) &&
         ($env{'course.'.$env{'request.course.id'}.'.domain'} eq $udom)) {          ($env{'course.'.$env{'request.course.id'}.'.domain'} eq $udom)) {
         $crsauthor = 1;          $crsauthor = 1;
         $title = &mt('Course Authoring Space');          if ($title eq '') {
     } else {              $title = &mt('Course Authoring Space');
           }
       } elsif ($title eq '') {
         $title = &mt('Authoring Space');          $title = &mt('Authoring Space');
     }      }
   
Line 6674  sub endbodytag { Line 6813  sub endbodytag {
     }      }
     if ( exists( $env{'internal.head.redirect'} ) ) {      if ( exists( $env{'internal.head.redirect'} ) ) {
         if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {          if (!(ref($args) eq 'HASH' && $args->{'noredirectlink'})) {
               my ($endbodyjs,$idattr);
               if ($env{'internal.head.to_opener'}) {
                   my $linkid = 'LC_continue_link';
                   $idattr = ' id="'.$linkid.'"';
                   my $redirect_for_js = &js_escape($env{'internal.head.redirect'});
                   $endbodyjs=<<ENDJS;
   <script type="text/javascript">
   // <![CDATA[
   function ebFunction(evt) {
       evt.preventDefault();
       var dest = '$redirect_for_js';
       if (window.opener != null && !window.opener.closed) {
           window.opener.location.href=dest;
           window.close();
       } else {
           window.location.href=dest;
       }
       return false;
   }
   
   \$(document).ready(function () {
     if (document.getElementById('$linkid')) {
       var clickelem = document.getElementById('$linkid');
       clickelem.addEventListener('click',ebFunction,false);
     }
   });
   // ]]>
   </script>
   ENDJS
               }
     $endbodytag=      $endbodytag=
         "<br /><a href=\"$env{'internal.head.redirect'}\">".          "$endbodyjs<br /><a href=\"$env{'internal.head.redirect'}\"$idattr>".
         &mt('Continue').'</a>'.          &mt('Continue').'</a>'.
         $endbodytag;          $endbodytag;
         }          }
     }      }
       if ((ref($args) eq 'HASH') && ($args->{'dashjs'})) {
           $endbodytag = &Apache::lonhtmlcommon::dash_to_minus_js().$endbodytag;
       }
     return $endbodytag;      return $endbodytag;
 }  }
   
Line 7996  fieldset { Line 8168  fieldset {
   /* overflow: hidden; */    /* overflow: hidden; */
 }  }
   
   fieldset#LC_selectuser {
       margin: 0;
       padding: 0;
   }
   
 article.geogebraweb div {  article.geogebraweb div {
     margin: 0;      margin: 0;
 }  }
Line 8845  Inputs: $title - optional title for the Line 9022  Inputs: $title - optional title for the
                                    3- whether the side effect should occur                                     3- whether the side effect should occur
                            (side effect of setting                              (side effect of setting 
                                $env{'internal.head.redirect'} to the url                                  $env{'internal.head.redirect'} to the url 
                                redirected too)                                 redirected to)
                                      4- whether the redirect target should be
                                         the opener of the current (pop-up)
                                         window (side effect of setting
                                         $env{'internal.head.to_opener'} to
                                         1, if true.
                                      5- whether encrypt check should be skipped
             domain         -> force to color decorate a page for a specific              domain         -> force to color decorate a page for a specific
                                domain                                 domain
             function       -> force usage of a specific rolish color scheme              function       -> force usage of a specific rolish color scheme
Line 8908  sub headtag { Line 9091  sub headtag {
         }          }
     }      }
     if (ref($args->{'redirect'})) {      if (ref($args->{'redirect'})) {
  my ($time,$url,$inhibit_continue) = @{$args->{'redirect'}};   my ($time,$url,$inhibit_continue,$to_opener,$skip_enc_check) = @{$args->{'redirect'}};
  $url = &Apache::lonenc::check_encrypt($url);          if (!$skip_enc_check) {
               $url = &Apache::lonenc::check_encrypt($url);
           }
  if (!$inhibit_continue) {   if (!$inhibit_continue) {
     $env{'internal.head.redirect'} = $url;      $env{'internal.head.redirect'} = $url;
  }   }
  $result.=<<ADDMETA   $result.=<<"ADDMETA";
 <meta http-equiv="pragma" content="no-cache" />  <meta http-equiv="pragma" content="no-cache" />
   ADDMETA
           if ($to_opener) {
               $env{'internal.head.to_opener'} = 1;
               my $dest = &js_escape($url);
               my $timeout = int($time * 1000);
               $result .=<<"ENDJS";
   <script type="text/javascript">
   // <![CDATA[
   function LC_To_Opener() {
       var dest = '$dest';
       if (dest != '') {
           if (window.opener != null && !window.opener.closed) {
               window.opener.location.href=dest;
               window.close();
           } else {
               window.location.href=dest;
           }
       }
   }
   \$(document).ready(function () {
       setTimeout('LC_To_Opener()',$timeout);
   });
   // ]]>
   </script>
   ENDJS
           } else {
               $result.=<<"ADDMETA";
 <meta http-equiv="Refresh" content="$time; url=$url" />  <meta http-equiv="Refresh" content="$time; url=$url" />
 ADDMETA  ADDMETA
           }
     } else {      } else {
         unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) {          unless (($args->{'frameset'}) || ($args->{'js_ready'}) || ($args->{'only_body'}) || ($args->{'no_nav_bar'})) {
             my $requrl = $env{'request.uri'};              my $requrl = $env{'request.uri'};
Line 9559  sub symb_from_tinyurl { Line 9772  sub symb_from_tinyurl {
     }      }
 }  }
   
   sub usable_exttools {
       my %tooltypes;
       if ($env{'request.course.id'}) {
           if ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'}) {
              if ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'both') {
                  %tooltypes = (
                                crs => 1,
                                dom => 1,
                               );
              } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'crs') {
                  $tooltypes{'crs'} = 1;
              } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.exttool'} eq 'dom') {
                  $tooltypes{'dom'} = 1;
              }
           } else {
               my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
               my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
               my $crstype = lc($env{'course.'.$env{'request.course.id'}.'.type'});
               if ($crstype eq '') {
                   $crstype = 'course';
               }
               if ($crstype eq 'course') {
                   if ($env{'course.'.$env{'request.course.id'}.'internal.coursecode'}) {
                       $crstype = 'official';
                   } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.textbook'}) {
                       $crstype = 'textbook';
                   } elsif ($env{'course.'.$env{'request.course.id'}.'.internal.lti'}) {
                       $crstype = 'lti';
                   } else {
                       $crstype = 'unofficial';
                   }
               }
               my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom);
               if ($domdefaults{$crstype.'domexttool'}) {
                   $tooltypes{'dom'} = 1;
               }
               if ($domdefaults{$crstype.'exttool'}) {
                   $tooltypes{'crs'} = 1;
               }
           }
       }
       return %tooltypes;
   }
   
 sub wishlist_window {  sub wishlist_window {
     return(<<'ENDWISHLIST');      return(<<'ENDWISHLIST');
 <script type="text/javascript">  <script type="text/javascript">
Line 10247  Scalar: 1 if 'Course' to be used, 0 othe Line 10504  Scalar: 1 if 'Course' to be used, 0 othe
   
 ###############################################  ###############################################
 sub show_course {  sub show_course {
       my ($udom,$uname) = @_;
       if (($udom ne '') && ($uname ne '')) {
           if (($udom ne $env{'user.domain'}) || ($uname ne $env{'user.name'})) {
               if (&Apache::lonnet::is_advanced_user($udom,$uname)) {
                   return 0;
               } else {
                   return 1;
               }
           }
       }
     my $course = !$env{'user.adv'};      my $course = !$env{'user.adv'};
     if (!$env{'user.adv'}) {      if (!$env{'user.adv'}) {
         foreach my $env (keys(%env)) {          foreach my $env (keys(%env)) {
Line 14221  sub process_extracted_files { Line 14488  sub process_extracted_files {
                             my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.                              my $url = '/uploaded/'.$docudom.'/'.$docuname.'/'.
                                       $docstype.'/'.$mapinner{$outer}.'/'.$newidx.'/'.                                        $docstype.'/'.$mapinner{$outer}.'/'.$newidx.'/'.
                                       $title;                                        $title;
                             if (($outer !~ /\D/) && ($mapinner{$outer} !~ /\D/) && ($newidx !~ /\D/)) {                              if (($outer !~ /\D/) &&
                                   (($mapinner{$outer} eq 'default') || ($mapinner{$outer} !~ /\D/)) &&
                                   ($newidx !~ /\D/)) {
                                 if (!-e "$prefix$dir/$docstype/$mapinner{$outer}") {                                  if (!-e "$prefix$dir/$docstype/$mapinner{$outer}") {
                                     mkdir("$prefix$dir/$docstype/$mapinner{$outer}",0755);                                      mkdir("$prefix$dir/$docstype/$mapinner{$outer}",0755);
                                 }                                  }
Line 16276  sub assign_category_rows { Line 16545  sub assign_category_rows {
   
   
 sub commit_customrole {  sub commit_customrole {
     my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context) = @_;      my ($udom,$uname,$url,$three,$four,$five,$start,$end,$context,$othdomby,$requester) = @_;
       my $result = &Apache::lonnet::assigncustomrole(
                        $udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,
                        $context,$othdomby,$requester);
     my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.      my $output = &mt('Assigning custom role').' "'.$five.'" by '.$four.':'.$three.' in '.$url.
                          ($start?', '.&mt('starting').' '.localtime($start):'').                           ($start?', '.&mt('starting').' '.localtime($start):'').
                          ($end?', ending '.localtime($end):'').': <b>'.                           ($end?', ending '.localtime($end):'').': <b>'.$result.'</b><br />';
               &Apache::lonnet::assigncustomrole(      if (wantarray) {
                  $udom,$uname,$url,$three,$four,$five,$end,$start,undef,undef,$context).          return ($output,$result);
                  '</b><br />';      } else {
     return $output;          return $output;
       }
 }  }
   
 sub commit_standardrole {  sub commit_standardrole {
     my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,$credits) = @_;      my ($udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,$credits,
     my ($output,$logmsg,$linefeed);          $othdomby,$requester) = @_;
       my ($output,$logmsg,$linefeed,$result);
     if ($context eq 'auto') {      if ($context eq 'auto') {
         $linefeed = "\n";          $linefeed = "\n";
     } else {      } else {
         $linefeed = "<br />\n";          $linefeed = "<br />\n";
     }        }  
     if ($three eq 'st') {      if ($three eq 'st') {
         my $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,          $result = &commit_studentrole(\$logmsg,$udom,$uname,$url,$three,$start,$end,
                                          $one,$two,$sec,$context,$credits);                                        $one,$two,$sec,$context,$credits,$othdomby,
                                         $requester);
         if (($result =~ /^error/) || ($result eq 'not_in_class') ||           if (($result =~ /^error/) || ($result eq 'not_in_class') || 
             ($result eq 'unknown_course') || ($result eq 'refused')) {              ($result eq 'unknown_course') || ($result eq 'refused')) {
             $output = $logmsg.' '.&mt('Error: ').$result."\n";               $output = $logmsg.' '.&mt('Error: ').$result."\n"; 
Line 16316  sub commit_standardrole { Line 16591  sub commit_standardrole {
         $output = &mt('Assigning').' '.$three.' in '.$url.          $output = &mt('Assigning').' '.$three.' in '.$url.
                ($start?', '.&mt('starting').' '.localtime($start):'').                 ($start?', '.&mt('starting').' '.localtime($start):'').
                ($end?', '.&mt('ending').' '.localtime($end):'').': ';                 ($end?', '.&mt('ending').' '.localtime($end):'').': ';
         my $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start,'','',$context);          $result = &Apache::lonnet::assignrole($udom,$uname,$url,$three,$end,$start,
                                                 '','',$context,$othdomby,$requester);
         if ($context eq 'auto') {          if ($context eq 'auto') {
             $output .= $result.$linefeed;              $output .= $result.$linefeed;
         } else {          } else {
             $output .= '<b>'.$result.'</b>'.$linefeed;              $output .= '<b>'.$result.'</b>'.$linefeed;
         }          }
     }      }
     return $output;      if (wantarray) {
           return ($output,$result);
       } else {
           return $output;
       }
 }  }
   
 sub commit_studentrole {  sub commit_studentrole {
     my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,      my ($logmsg,$udom,$uname,$url,$three,$start,$end,$one,$two,$sec,$context,
         $credits) = @_;          $credits,$othdomby,$requester) = @_;
     my ($result,$linefeed,$oldsecurl,$newsecurl);      my ($result,$linefeed,$oldsecurl,$newsecurl);
     if ($context eq 'auto') {      if ($context eq 'auto') {
         $linefeed = "\n";          $linefeed = "\n";
Line 16352  sub commit_studentrole { Line 16632  sub commit_studentrole {
                 }                  }
                 $oldsecurl = $uurl;                  $oldsecurl = $uurl;
                 $expire_role_result =                   $expire_role_result = 
                     &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,'','',$context);                      &Apache::lonnet::assignrole($udom,$uname,$uurl,'st',$now,
                 if ($env{'request.course.sec'} ne '') {                                                   '','','',$context,$othdomby,$requester);
                   if ($env{'request.course.sec'} ne '') {
                     if ($expire_role_result eq 'refused') {                      if ($expire_role_result eq 'refused') {
                         my @roles = ('st');                          my @roles = ('st');
                         my @statuses = ('previous');                          my @statuses = ('previous');
Line 16379  sub commit_studentrole { Line 16660  sub commit_studentrole {
                 &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,                  &Apache::lonnet::modify_student_enrollment($udom,$uname,undef,undef,
                                                            undef,undef,undef,$sec,                                                             undef,undef,undef,$sec,
                                                            $end,$start,'','',$cid,                                                             $end,$start,'','',$cid,
                                                            '',$context,$credits);                                                             '',$context,$credits,'',
                                                              $othdomby,$requester);
             if ($modify_section_result =~ /^ok/) {              if ($modify_section_result =~ /^ok/) {
                 if ($secchange == 1) {                  if ($secchange == 1) {
                     if ($sec eq '') {                      if ($sec eq '') {
Line 16772  sub construct_course { Line 17054  sub construct_course {
         $cenv{'internal.defaultcredits'} = $args->{'defaultcredits'};          $cenv{'internal.defaultcredits'} = $args->{'defaultcredits'};
     }      }
     my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.      my @badclasses = (); # Used to accumulate sections/crosslistings that did not pass classlist access check for course owner.
       my @oklcsecs = (); # Used to accumulate LON-CAPA sections for validated institutional sections.
     if ($args->{'crssections'}) {      if ($args->{'crssections'}) {
         $cenv{'internal.sectionnums'} = '';          $cenv{'internal.sectionnums'} = '';
         if ($args->{'crssections'} =~ m/,/) {          if ($args->{'crssections'} =~ m/,/) {
Line 16785  sub construct_course { Line 17068  sub construct_course {
                 my $class = $args->{'crscode'}.$sec;                  my $class = $args->{'crscode'}.$sec;
                 my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});                  my $addcheck = &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$class,$cenv{'internal.courseowner'});
                 $cenv{'internal.sectionnums'} .= $item.',';                  $cenv{'internal.sectionnums'} .= $item.',';
                 unless ($addcheck eq 'ok') {                  if ($addcheck eq 'ok') {
                       unless (grep(/^\Q$gp\E$/,@oklcsecs)) {
                           push(@oklcsecs,$gp);
                       }
                   } else {
                     push(@badclasses,$class);                      push(@badclasses,$class);
                 }                  }
             }              }
Line 16813  sub construct_course { Line 17100  sub construct_course {
                 my ($xl,$gp) = split/:/,$item;                  my ($xl,$gp) = split/:/,$item;
                 my $addcheck =  &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});                  my $addcheck =  &Apache::lonnet::auto_new_course($$crsunum,$$crsudom,$xl,$cenv{'internal.courseowner'});
                 $cenv{'internal.crosslistings'} .= $item.',';                  $cenv{'internal.crosslistings'} .= $item.',';
                 unless ($addcheck eq 'ok') {                  if ($addcheck eq 'ok') {
                       unless (grep(/^\Q$gp\E$/,@oklcsecs)) {
                           push(@oklcsecs,$gp);
                       }
                   } else {
                     push(@badclasses,$xl);                      push(@badclasses,$xl);
                 }                  }
             }              }
Line 16876  sub construct_course { Line 17167  sub construct_course {
     if ($args->{'no_end_date'}) {      if ($args->{'no_end_date'}) {
         $args->{'endaccess'} = 0;          $args->{'endaccess'} = 0;
     }      }
   #  If an official course with institutional sections is created by cloning 
   #  an existing course, section-specific hiding of course totals in student's
   #  view of grades as copied from cloned course, will be checked for valid 
   #  sections.
       if (($can_clone && $cloneid) &&
           ($cenv{'internal.coursecode'} ne '') &&
           ($cenv{'grading'} eq 'standard') &&
           ($cenv{'hidetotals'} ne '') &&
           ($cenv{'hidetotals'} ne 'all')) {
           my @hidesecs;
           my $deletehidetotals;
           if (@oklcsecs) {
               foreach my $sec (split(/,/,$cenv{'hidetotals'})) {
                   if (grep(/^\Q$sec$/,@oklcsecs)) {
                       push(@hidesecs,$sec);
                   }
               }
               if (@hidesecs) {
                   $cenv{'hidetotals'} = join(',',@hidesecs);
               } else {
                   $deletehidetotals = 1;
               }
           } else {
               $deletehidetotals = 1;
           }
           if ($deletehidetotals) {
               delete($cenv{'hidetotals'});
               &Apache::lonnet::del('environment',['hidetotals'],$$crsudom,$$crsunum);
           }
       }
     $cenv{'internal.autostart'}=$args->{'enrollstart'};      $cenv{'internal.autostart'}=$args->{'enrollstart'};
     $cenv{'internal.autoend'}=$args->{'enrollend'};      $cenv{'internal.autoend'}=$args->{'enrollend'};
     $cenv{'default_enrollment_start_date'}=$args->{'startaccess'};      $cenv{'default_enrollment_start_date'}=$args->{'startaccess'};
Line 16994  sub construct_course { Line 17315  sub construct_course {
 #  #
     unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')      unless (($args->{'nonstandard'}) || ($args->{'firstres'} eq 'blank')
     || ($cloneid)) {      || ($cloneid)) {
  use LONCAPA::map;  
  $outcome .= &mt('Setting first resource').': ';   $outcome .= &mt('Setting first resource').': ';
   
  my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';   my $map = '/uploaded/'.$$crsudom.'/'.$$crsunum.'/default.sequence';
Line 17381  sub init_user_environment { Line 17701  sub init_user_environment {
             my %is_adv = ( is_adv => $env{'user.adv'} );              my %is_adv = ( is_adv => $env{'user.adv'} );
             my %domdef = &Apache::lonnet::get_domain_defaults($domain);              my %domdef = &Apache::lonnet::get_domain_defaults($domain);
   
             foreach my $tool ('aboutme','blog','webdav','portfolio') {              foreach my $tool ('aboutme','blog','webdav','portfolio','timezone') {
                 $userenv{'availabletools.'.$tool} =                   $userenv{'availabletools.'.$tool} = 
                     &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',                      &Apache::lonnet::usertools_access($username,$domain,$tool,'reload',
                                                       undef,\%userenv,\%domdef,\%is_adv);                                                        undef,\%userenv,\%domdef,\%is_adv);
Line 18254  sub needs_coursereinit { Line 18574  sub needs_coursereinit {
         if ($blocked) {          if ($blocked) {
             return ();              return ();
         }          }
         my $lastchange = &Apache::lonnet::get_coursechange($cdom,$cnum);          my $update;
         if ($lastchange > $env{'request.course.tied'}) {          my $lastmainchange = &Apache::lonnet::get_coursechange($cdom,$cnum);
             my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');          my $lastsuppchange = &Apache::lonnet::get_suppchange($cdom,$cnum);
             if ($curr_reqd_hash{'internal.releaserequired'} ne '') {          if ($lastmainchange > $env{'request.course.tied'}) {
                 my $required = $env{'course.'.$cdom.'_'.$cnum.'.internal.releaserequired'};              my ($needswitch,$switchwarning,$switchserver) = &switch_for_update($loncaparev,$cdom,$cnum);
                 if ($curr_reqd_hash{'internal.releaserequired'} ne $required) {              if ($needswitch) {
                     &Apache::lonnet::appenv({'course.'.$cdom.'_'.$cnum.'.internal.releaserequired' =>                  return ('switch',$switchwarning,$switchserver);
                                              $curr_reqd_hash{'internal.releaserequired'}});              }
                     my ($switchserver,$switchwarning) =              $update = 'main';
                         &check_release_required($loncaparev,$cdom.'_'.$cnum,$env{'request.role'},          }
                                                 $curr_reqd_hash{'internal.releaserequired'});          if ($lastsuppchange > $env{'request.course.suppupdated'}) {
                     if ($switchwarning ne '' || $switchserver ne '') {              if ($update) {
                         return ('switch',$switchwarning,$switchserver);                  $update = 'both';
                     }              } else {
                   my ($needswitch,$switchwarning,$switchserver) = &switch_for_update($loncaparev,$cdom,$cnum);
                   if ($needswitch) {
                       return ('switch',$switchwarning,$switchserver);
                   } else {
                       $update = 'supp';
                 }                  }
             }              }
             return ('update');              return ($update);
           }
       }
       return ();
   }
   
   sub switch_for_update {
       my ($loncaparev,$cdom,$cnum) = @_;
       my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
       if ($curr_reqd_hash{'internal.releaserequired'} ne '') {
           my $required = $env{'course.'.$cdom.'_'.$cnum.'.internal.releaserequired'};
           if ($curr_reqd_hash{'internal.releaserequired'} ne $required) {
               &Apache::lonnet::appenv({'course.'.$cdom.'_'.$cnum.'.internal.releaserequired' =>
                                       $curr_reqd_hash{'internal.releaserequired'}});
               my ($switchserver,$switchwarning) =
                   &check_release_required($loncaparev,$cdom.'_'.$cnum,$env{'request.role'},
                                           $curr_reqd_hash{'internal.releaserequired'});
               if ($switchwarning ne '' || $switchserver ne '') {
                   return ('switch',$switchwarning,$switchserver);
               }
         }          }
     }      }
     return ();      return ();
 }  }
   
 sub update_content_constraints {  sub update_content_constraints {
     my ($cdom,$cnum,$chome,$cid,$keeporder) = @_;      my ($cdom,$cnum,$chome,$cid) = @_;
     my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');      my %curr_reqd_hash = &Apache::lonnet::userenvironment($cdom,$cnum,'internal.releaserequired');
     my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'});      my ($reqdmajor,$reqdminor) = split(/\./,$curr_reqd_hash{'internal.releaserequired'});
     my (%checkresponsetypes,%checkcrsrestypes);      my (%checkresponsetypes,%checkcrsrestypes);
Line 18325  sub update_content_constraints { Line 18669  sub update_content_constraints {
         }          }
         undef($navmap);          undef($navmap);
     }      }
     my (@resources,@order,@resparms,@zombies);      if (&Apache::lonnet::count_supptools($cnum,$cdom,1)) {
     if ($keeporder) {  
         use LONCAPA::map;  
         @resources = @LONCAPA::map::resources;  
         @order = @LONCAPA::map::order;  
         @resparms = @LONCAPA::map::resparms;  
         @zombies = @LONCAPA::map::zombies;  
     }  
     my $suppmap = 'supplemental.sequence';  
     my ($suppcount,$supptools,$errors) = (0,0,0);  
     ($suppcount,$supptools,$errors) = &recurse_supplemental($cnum,$cdom,$suppmap,  
                                                             $suppcount,$supptools,$errors);  
     if ($keeporder) {  
         @LONCAPA::map::resources = @resources;  
         @LONCAPA::map::order = @order;  
         @LONCAPA::map::resparms = @resparms;  
         @LONCAPA::map::zombies = @zombies;  
     }  
     if ($supptools) {  
         my ($major,$minor) = split(/\./,$checkcrsrestypes{'exttool'});          my ($major,$minor) = split(/\./,$checkcrsrestypes{'exttool'});
         if (($major > $reqdmajor) || ($major == $reqdmajor && $minor > $reqdminor)) {          if (($major > $reqdmajor) || ($major == $reqdmajor && $minor > $reqdminor)) {
             ($reqdmajor,$reqdminor) = ($major,$minor);              ($reqdmajor,$reqdminor) = ($major,$minor);
Line 18369  sub allmaps_incourse { Line 18695  sub allmaps_incourse {
     if ($lastchange > $env{'request.course.tied'}) {      if ($lastchange > $env{'request.course.tied'}) {
         my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum");          my ($furl,$ferr) = &Apache::lonuserstate::readmap("$cdom/$cnum");
         unless ($ferr) {          unless ($ferr) {
             &update_content_constraints($cdom,$cnum,$chome,$cid,1);              &update_content_constraints($cdom,$cnum,$chome,$cid);
         }          }
     }      }
     my $navmap = Apache::lonnavmaps::navmap->new();      my $navmap = Apache::lonnavmaps::navmap->new();
Line 18395  sub parse_supplemental_title { Line 18721  sub parse_supplemental_title {
         my $name =  &plainname($uname,$udom);          my $name =  &plainname($uname,$udom);
         $name = &HTML::Entities::encode($name,'"<>&\'');          $name = &HTML::Entities::encode($name,'"<>&\'');
         $renametitle = &HTML::Entities::encode($renametitle,'"<>&\'');          $renametitle = &HTML::Entities::encode($renametitle,'"<>&\'');
         $title='<i>'.&Apache::lonlocal::locallocaltime($time).'</i> '.          $title='<i>'.&Apache::lonlocal::locallocaltime($time).'</i> '.$name;
             $name.': <br />'.$foldertitle;          if ($foldertitle ne '') {
               $title .= ': <br />'.$foldertitle;
           }
     }      }
     if (wantarray) {      if (wantarray) {
         return ($title,$foldertitle,$renametitle);          return ($title,$foldertitle,$renametitle);
Line 18404  sub parse_supplemental_title { Line 18732  sub parse_supplemental_title {
     return $title;      return $title;
 }  }
   
   sub get_supplemental {
       my ($cnum,$cdom,$ignorecache,$possdel)=@_;
       my $hashid=$cnum.':'.$cdom;
       my ($supplemental,$cached,$set_httprefs);
       unless ($ignorecache) {
           ($supplemental,$cached) = &Apache::lonnet::is_cached_new('supplemental',$hashid);
       }
       unless (defined($cached)) {
           my $chome=&Apache::lonnet::homeserver($cnum,$cdom);
           unless ($chome eq 'no_host') {
               my @order = @LONCAPA::map::order;
               my @resources = @LONCAPA::map::resources;
               my @resparms = @LONCAPA::map::resparms;
               my @zombies = @LONCAPA::map::zombies;
               my ($errors,%ids,%hidden);
               $errors =
                   &recurse_supplemental($cnum,$cdom,'supplemental.sequence',
                                         $errors,$possdel,\%ids,\%hidden);
               @LONCAPA::map::order = @order;
               @LONCAPA::map::resources = @resources;
               @LONCAPA::map::resparms = @resparms;
               @LONCAPA::map::zombies = @zombies;
               $set_httprefs = 1;
               if ($env{'request.course.id'} eq $cdom.'_'.$cnum) {
                   &Apache::lonnet::appenv({'request.course.suppupdated' => time});
               }
               $supplemental = {
                                  ids => \%ids,
                                  hidden => \%hidden,
                               };
               &Apache::lonnet::do_cache_new('supplemental',$hashid,$supplemental,600);
           }
       }
       return ($supplemental,$set_httprefs);
   }
   
 sub recurse_supplemental {  sub recurse_supplemental {
     my ($cnum,$cdom,$suppmap,$numfiles,$numexttools,$errors) = @_;      my ($cnum,$cdom,$suppmap,$errors,$possdel,$suppids,$hiddensupp,$hidden) = @_;
     if ($suppmap) {      if (($suppmap) && (ref($suppids) eq 'HASH') && (ref($hiddensupp) eq 'HASH')) {
           my $mapnum;
           if ($suppmap eq 'supplemental.sequence') {
               $mapnum = 0;
           } else {
               ($mapnum) = ($suppmap =~ /^supplemental_(\d+)\.sequence$/);
           }
         my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap);          my ($errtext,$fatal) = &LONCAPA::map::mapread('/uploaded/'.$cdom.'/'.$cnum.'/'.$suppmap);
         if ($fatal) {          if ($fatal) {
             $errors ++;              $errors ++;
         } else {          } else {
             if ($#LONCAPA::map::resources > 0) {              my @order = @LONCAPA::map::order;
                 foreach my $res (@LONCAPA::map::resources) {              if (@order > 0) {
                     my ($title,$src,$ext,$type,$status)=split(/\:/,$res);                  my @resources = @LONCAPA::map::resources;
                   my @resparms = @LONCAPA::map::resparms;
                   foreach my $idx (@order) {
                       my ($title,$src,$ext,$type,$status)=split(/\:/,$resources[$idx]);
                     if (($src ne '') && ($status eq 'res')) {                      if (($src ne '') && ($status eq 'res')) {
                           my $id = $mapnum.':'.$idx;
                           push(@{$suppids->{$src}},$id);
                           if (($hidden) || (&get_supp_parameter($resparms[$idx],'parameter_hiddenresource') =~ /^yes/i)) {
                               $hiddensupp->{$id} = 1;
                           }
                         if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) {                          if ($src =~ m{^\Q/uploaded/$cdom/$cnum/\E(supplemental_\d+\.sequence)$}) {
                             ($numfiles,$numexttools,$errors) = &recurse_supplemental($cnum,$cdom,$1,                              $errors = &recurse_supplemental($cnum,$cdom,$1,$errors,$possdel,$suppids,
                                                                    $numfiles,$numexttools,$errors);                                                              $hiddensupp,$hiddensupp->{$id});
                         } else {                          } else {
                             if ($src =~ m{^/adm/$cdom/$cnum/\d+/ext\.tool$}) {                              my $allowed;
                                 $numexttools ++;                              if (($env{'request.role.adv'}) || (!$hiddensupp->{$id})) {
                                   $allowed = 1;
                               } elsif ($possdel) {
                                   foreach my $item (@{$suppids->{$src}}) {
                                       next if ($item eq $id);
                                       unless ($hiddensupp->{$item}) {
                                          $allowed = 1;
                                          last;
                                       }
                                   }
                                   if ((!$allowed) && (exists($env{'httpref.'.$src}))) {
                                       &Apache::lonnet::delenv('httpref.'.$src);
                                   }
                               }
                               if ($allowed && (!exists($env{'httpref.'.$src}))) {
                                   &Apache::lonnet::allowuploaded('/adm/coursedoc',$src);
                               }
                           }
                       }
                   }
               }
           }
       }
       return $errors;
   }
   
   sub set_supp_httprefs {
       my ($cnum,$cdom,$supplemental,$possdel) = @_;
       if (ref($supplemental) eq 'HASH') {
           if ((ref($supplemental->{'ids'}) eq 'HASH') && (ref($supplemental->{'hidden'}) eq 'HASH')) {
               foreach my $src (keys(%{$supplemental->{'ids'}})) {
                   next if ($src =~ /\.sequence$/);
                   if (ref($supplemental->{'ids'}->{$src}) eq 'ARRAY') {
                       my $allowed;
                       if ($env{'request.role.adv'}) {
                           $allowed = 1;
                       } else {
                           foreach my $id (@{$supplemental->{'ids'}->{$src}}) {
                               unless ($supplemental->{'hidden'}->{$id}) {
                                   $allowed = 1;
                                   last;
                             }                              }
                             $numfiles ++;  
                         }                          }
                     }                      }
                       if (exists($env{'httpref.'.$src})) {
                           if ($possdel) {
                               unless ($allowed) {
                                   &Apache::lonnet::delenv('httpref.'.$src);
                               }
                           }
                       } elsif ($allowed) {
                           &Apache::lonnet::allowuploaded('/adm/coursedoc',$src);
                       }
                 }                  }
             }              }
               if ($env{'request.course.id'} eq $cdom.'_'.$cnum) {
                   &Apache::lonnet::appenv({'request.course.suppupdated' => time});
               }
         }          }
     }      }
     return ($numfiles,$numexttools,$errors);  }
   
   sub get_supp_parameter {
       my ($resparm,$name)=@_;
       return if ($resparm eq '');
       my $value=undef;
       my $ptype=undef;
       foreach (split('&&&',$resparm)) {
           my ($thistype,$thisname,$thisvalue)=split('___',$_);
           if ($thisname eq $name) {
               $value=$thisvalue;
               $ptype=$thistype;
           }
       }
       return $value;
 }  }
   
 sub symb_to_docspath {  sub symb_to_docspath {
Line 18502  sub symb_to_docspath { Line 18945  sub symb_to_docspath {
     return $path;      return $path;
 }  }
   
   sub validate_folderpath {
       my ($supplementalflag,$allowed,$coursenum,$coursedom) = @_;
       if ($env{'form.folderpath'} ne '') {
           my @items = split(/\&/,$env{'form.folderpath'});
           my ($badpath,$changed,$got_supp,$supppath,%supphidden,%suppids);
           for (my $i=0; $i<@items; $i++) {
               my $odd = $i%2;
               if (($odd) && (!$supplementalflag) && ($items[$i] !~ /^[^:]*:(|\d+):(|1):(|1):(|1):(|1)$/)) {
                   $badpath = 1;
               } elsif ($odd && $supplementalflag) {
                   my $idx = $i-1;
                   if ($items[$i] =~ /^([^:]*)::(|1):::$/) {
                       my $esc_name = $1;
                       if ((!$allowed) || ($items[$idx] eq 'supplemental')) {
                           $supppath .= '&'.$esc_name;
                           $changed = 1;
                       } else {
                           $supppath .= '&'.$items[$i];
                       }
                   } elsif (($allowed) && ($items[$idx] ne 'supplemental')) {
                       $changed = 1;
                       my $is_hidden;
                       unless ($got_supp) {
                           my ($supplemental) = &get_supplemental($coursenum,$coursedom);
                           if (ref($supplemental) eq 'HASH') {
                               if (ref($supplemental->{'hidden'}) eq 'HASH') {
                                   %supphidden = %{$supplemental->{'hidden'}};
                               }
                               if (ref($supplemental->{'ids'}) eq 'HASH') {
                                   %suppids = %{$supplemental->{'ids'}};
                               }
                           }
                           $got_supp = 1;
                       }
                       if (ref($suppids{"/uploaded/$coursedom/$coursenum/$items[$idx].sequence"}) eq 'ARRAY') {
                           my $mapid = $suppids{"/uploaded/$coursedom/$coursenum/$items[$idx].sequence"}->[0];
                           if ($supphidden{$mapid}) {
                               $is_hidden = 1;
                           }
                       }
                       $supppath .= '&'.$items[$i].'::'.$is_hidden.':::';
                   } else {
                       $supppath .= '&'.$items[$i];
                   }
               } elsif ((!$odd) && ($items[$i] !~ /^(default|supplemental)(|_\d+)$/)) {
                   $badpath = 1;
               } elsif ($supplementalflag) {
                   $supppath .= '&'.$items[$i];
               }
               last if ($badpath);
           }
           if ($badpath) {
               delete($env{'form.folderpath'});
           } elsif ($changed && $supplementalflag) {
               $supppath =~ s/^\&//;
               $env{'form.folderpath'} = $supppath;
           }
       }
       return;
   }
   
 sub captcha_display {  sub captcha_display {
     my ($context,$lonhost,$defdom) = @_;      my ($context,$lonhost,$defdom) = @_;
     my ($output,$error);      my ($output,$error);
Line 18624  sub create_captcha { Line 19128  sub create_captcha {
             $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".              $output = '<input type="hidden" name="crypt" value="'.$md5sum.'" />'."\n".
                       '<span class="LC_nobreak">'.                        '<span class="LC_nobreak">'.
                       &mt('Type in the letters/numbers shown below').'&nbsp;'.                        &mt('Type in the letters/numbers shown below').'&nbsp;'.
                       '<input type="text" size="5" name="code" value="" autocomplete="off" />'.                        '<input type="text" size="5" name="code" value="" autocomplete="new-password" />'.
                       '</span><br />'.                        '</span><br />'.
                       '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />';                        '<img src="'.$captcha_params{'www_output_dir'}.'/'.$md5sum.'.png" alt="captcha" />';
             last;              last;

Removed from v.1.1385  
changed lines
  Added in v.1.1412


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