Diff for /loncom/interface/domainprefs.pm between versions 1.160.6.118.2.21 and 1.425

version 1.160.6.118.2.21, 2024/03/03 02:21:32 version 1.425, 2023/06/03 19:18:11
Line 95  about default quota sizes for portfolio Line 95  about default quota sizes for portfolio
 institutional affiliation in the domain (e.g., Faculty, Staff, Student etc.),   institutional affiliation in the domain (e.g., Faculty, Staff, Student etc.), 
 but is now also used to manage availability of user tools:   but is now also used to manage availability of user tools: 
 i.e., blogs, aboutme page, and portfolios, and the course request tool,  i.e., blogs, aboutme page, and portfolios, and the course request tool,
 used by course owners to request creation of a course.  used by course owners to request creation of a course, and to display/store
   default quota sizes for Authoring Spaces.
   
 Outputs: 1  Outputs: 1
   
Line 103  $datatable  - HTML containing form eleme Line 104  $datatable  - HTML containing form eleme
   
 In the case of course requests, radio buttons are displayed for each institutional  In the case of course requests, radio buttons are displayed for each institutional
 affiliate type (and also default, and _LC_adv) for each of the course types   affiliate type (and also default, and _LC_adv) for each of the course types 
 (official, unofficial, community, textbook, and lti).  (official, unofficial, community, textbook, placement, and lti).  
 In each case the radio buttons allow the selection of one of four values:  In each case the radio buttons allow the selection of one of four values:
   
 0, approval, validate, autolimit=N (where N is blank, or a positive integer).  0, approval, validate, autolimit=N (where N is blank, or a positive integer).
Line 170  use Apache::courseprefs(); Line 171  use Apache::courseprefs();
 use LONCAPA qw(:DEFAULT :match);  use LONCAPA qw(:DEFAULT :match);
 use LONCAPA::Enrollment;  use LONCAPA::Enrollment;
 use LONCAPA::lonauthcgi();  use LONCAPA::lonauthcgi();
   use LONCAPA::SSL;
 use File::Copy;  use File::Copy;
 use Locale::Language;  use Locale::Language;
 use DateTime::TimeZone;  use DateTime::TimeZone;
Line 220  sub handler { Line 222  sub handler {
                 'serverstatuses','requestcourses','helpsettings',                  'serverstatuses','requestcourses','helpsettings',
                 'coursedefaults','usersessions','loadbalancing',                  'coursedefaults','usersessions','loadbalancing',
                 'requestauthor','selfenrollment','inststatus',                  'requestauthor','selfenrollment','inststatus',
                 'passwords','ltitools','toolsec','lti','ltisec',                  'ltitools','toolsec','ssl','trust','lti','ltisec',
                 'wafproxy','ipaccess','authordefaults'],$dom);                  'privacy','passwords','proctoring','wafproxy','ipaccess'],$dom);
     my %encconfig =      my %encconfig =
         &Apache::lonnet::get_dom('encconfig',['ltitools','lti','linkprot'],$dom,undef,1);          &Apache::lonnet::get_dom('encconfig',['ltitools','lti','proctoring','linkprot'],$dom,undef,1);
     my ($checked_is_home,$is_home);      my ($checked_is_home,$is_home);
     if (ref($domconfig{'ltitools'}) eq 'HASH') {      if (ref($domconfig{'ltitools'}) eq 'HASH') {
         if (ref($encconfig{'ltitools'}) eq 'HASH') {          if (ref($encconfig{'ltitools'}) eq 'HASH') {
Line 286  sub handler { Line 288  sub handler {
             }              }
         }          }
     }      }
       if (ref($domconfig{'proctoring'}) eq 'HASH') {
           if (ref($encconfig{'proctoring'}) eq 'HASH') {
               foreach my $provider (keys(%{$domconfig{'proctoring'}})) {
                   if ((ref($domconfig{'proctoring'}{$provider}) eq 'HASH') &&
                       (ref($encconfig{'proctoring'}{$provider}) eq 'HASH')) {
                       foreach my $item ('key','secret') {
                           $domconfig{'proctoring'}{$provider}{$item} = $encconfig{'proctoring'}{$provider}{$item};
                       }
                   }
               }
           }
       }
     my @prefs_order = ('rolecolors','login','ipaccess','defaults','wafproxy','passwords',      my @prefs_order = ('rolecolors','login','ipaccess','defaults','wafproxy','passwords',
                        'quotas','autoenroll','autoupdate','autocreate','directorysrch',                         'quotas','autoenroll','autoupdate','autocreate','directorysrch',
                        'contacts','usercreation','selfcreation','usermodification',                         'contacts','privacy','usercreation','selfcreation',
                        'scantron','requestcourses','requestauthor','coursecategories',                         'usermodification','scantron','requestcourses','requestauthor',
                        'serverstatuses','helpsettings','coursedefaults',                         'coursecategories','serverstatuses','helpsettings','coursedefaults',
                        'authordefaults','ltitools','selfenrollment','usersessions','lti');                         'ltitools','proctoring','selfenrollment','usersessions','ssl',
                          'trust','lti');
     my %existing;      my %existing;
     if (ref($domconfig{'loadbalancing'}) eq 'HASH') {      if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
         %existing = %{$domconfig{'loadbalancing'}};          %existing = %{$domconfig{'loadbalancing'}};
Line 367  sub handler { Line 382  sub handler {
                       modify => \&modify_passwords,                        modify => \&modify_passwords,
                     },                      },
         'quotas' =>           'quotas' => 
                     { text => 'Blogs, personal pages/timezones, portfolio/quotas',                      { text => 'Blogs, personal pages/timezones, webDAV/quotas, portfolio',
                       help => 'Domain_Configuration_Quotas',                        help => 'Domain_Configuration_Quotas',
                       header => [{col1 => 'User affiliation',                        header => [{col1 => 'User affiliation',
                                   col2 => 'Available tools',                                    col2 => 'Available tools',
                                   col3 => 'Portfolio quota (MB)',}],                                    col3 => 'Quotas, MB; (Authoring requires role)',}],
                       print => \&print_quotas,                        print => \&print_quotas,
                       modify => \&modify_quotas,                        modify => \&modify_quotas,
                     },                      },
Line 552  sub handler { Line 567  sub handler {
                   print => \&print_selfenrollment,                    print => \&print_selfenrollment,
                   modify => \&modify_selfenrollment,                    modify => \&modify_selfenrollment,
                  },                   },
           'privacy' => 
                    {text   => 'Availability of User Information',
                     help   => 'Domain_Configuration_User_Privacy',
                     header => [{col1 => 'Role assigned in different domain',
                                 col2 => 'Approval options'},
                                {col1 => 'Role assigned in different domain to user of type',
                                 col2 => 'User information available in that domain'},
                                {col1 => "Role assigned in user's domain",
                                 col2 => 'Information viewable by privileged user'},
                                {col1 => "Role assigned in user's domain",
                                 col2 => 'Information viewable by unprivileged user'}],
                     print => \&print_privacy,
                     modify => \&modify_privacy,
                    },
         'usersessions' =>          'usersessions' =>
                  {text  => 'User session hosting/offloading',                   {text  => 'User session hosting/offloading',
                   help  => 'Domain_Configuration_User_Sessions',                    help  => 'Domain_Configuration_User_Sessions',
Line 587  sub handler { Line 616  sub handler {
                   print => \&print_ltitools,                    print => \&print_ltitools,
                   modify => \&modify_ltitools,                    modify => \&modify_ltitools,
                  },                   },
           'proctoring' =>
                    {text => 'Remote Proctoring Integration',
                     help => 'Domain_Configuration_Proctoring',
                     header => [{col1 => 'Name',
                                 col2 => 'Configuration'}],
                     print => \&print_proctoring,
                     modify => \&modify_proctoring,
                    },
           'ssl' =>
                    {text  => 'LON-CAPA Network (SSL)',
                     help  => 'Domain_Configuration_Network_SSL',
                     header => [{col1 => 'Server',
                                 col2 => 'Certificate Status'},
                                {col1 => 'Connections to other servers',
                                 col2 => 'Rules'},
                                {col1 => 'Connections from other servers',
                                 col2 => 'Rules'},
                                {col1 => "Replicating domain's published content",
                                 col2 => 'Rules'}],
                     print => \&print_ssl,
                     modify => \&modify_ssl,
                    },
           'trust' =>
                    {text   => 'Trust Settings',
                     help   => 'Domain_Configuration_Trust',
                     header => [{col1 => "Access to this domain's content by others",
                                 col2 => 'Rules'},
                                {col1 => "Access to other domain's content by this domain",
                                 col2 => 'Rules'},
                                {col1 => "Enrollment in this domain's courses by others",
                                 col2 => 'Rules',},
                                {col1 => "Co-author roles in this domain for others",
                                 col2 => 'Rules',},
                                {col1 => "Co-author roles for this domain's users elsewhere",
                                 col2 => 'Rules',},
                                {col1 => "Domain roles in this domain assignable to others",
                                 col2 => 'Rules'},
                                {col1 => "Course catalog for this domain displayed elsewhere",
                                 col2 => 'Rules'},
                                {col1 => "Requests for creation of courses in this domain by others",
                                 col2 => 'Rules'},
                                {col1 => "Users in other domains can send messages to this domain",
                                 col2 => 'Rules'},],
                     print => \&print_trust,
                     modify => \&modify_trust,
                    },
         'lti' =>          'lti' =>
                  {text => 'LTI Link Protection and LTI Consumers',                   {text => 'LTI Link Protection and LTI Consumers',
                   help => 'Domain_Configuration_LTI_Provider',                    help => 'Domain_Configuration_LTI_Provider',
Line 594  sub handler { Line 669  sub handler {
                               col2 => 'Settings'},                                col2 => 'Settings'},
                              {col1 => 'Rules for shared secrets',                               {col1 => 'Rules for shared secrets',
                               col2 => 'Settings'},                                col2 => 'Settings'},
                              {col1 => 'Link Protectors in Courses',  
                               col2 => 'Values'},  
                              {col1 => 'Link Protectors',                               {col1 => 'Link Protectors',
                               col2 => 'Settings'},                                col2 => 'Settings'},
                              {col1 => 'Consumers',                               {col1 => 'Consumers',
Line 611  sub handler { Line 684  sub handler {
                         print  => \&print_ipaccess,                          print  => \&print_ipaccess,
                         modify => \&modify_ipaccess,                          modify => \&modify_ipaccess,
                        },                         },
         'authordefaults' =>  
                             {text => 'Authoring Space defaults',  
                              help => 'Domain_Configuration_Author_Defaults',  
                              header => [{col1 => 'Defaults which can be overridden by Author',  
                                          col2 => 'Settings',},  
                                         {col1 => 'Defaults which can be overridden by a Dom. Coord.',  
                                          col2 => 'Settings',},],  
                              print => \&print_authordefaults,  
                              modify => \&modify_authordefaults,  
                             },  
     );      );
     if (keys(%servers) > 1) {      if (keys(%servers) > 1) {
         $prefs{'login'}  = { text   => 'Log-in page options',          $prefs{'login'}  = { text   => 'Log-in page options',
Line 810  sub process_changes { Line 873  sub process_changes {
         $output = &modify_loadbalancing($dom,%domconfig);          $output = &modify_loadbalancing($dom,%domconfig);
     } elsif ($action eq 'ltitools') {      } elsif ($action eq 'ltitools') {
         $output = &modify_ltitools($r,$dom,$action,$lastactref,%domconfig);          $output = &modify_ltitools($r,$dom,$action,$lastactref,%domconfig);
       } elsif ($action eq 'proctoring') {
           $output = &modify_proctoring($r,$dom,$action,$lastactref,%domconfig);
       } elsif ($action eq 'ssl') {
           $output = &modify_ssl($dom,$lastactref,%domconfig);
       } elsif ($action eq 'trust') {
           $output = &modify_trust($dom,$lastactref,%domconfig);
     } elsif ($action eq 'lti') {      } elsif ($action eq 'lti') {
         $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);          $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);
       } elsif ($action eq 'privacy') {
           $output = &modify_privacy($dom,%domconfig);
     } elsif ($action eq 'passwords') {      } elsif ($action eq 'passwords') {
         $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);          $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);
     } elsif ($action eq 'wafproxy') {      } elsif ($action eq 'wafproxy') {
         $output = &modify_wafproxy($dom,$action,$lastactref,%domconfig);          $output = &modify_wafproxy($dom,$action,$lastactref,%domconfig);
     } elsif ($action eq 'ipaccess') {      } elsif ($action eq 'ipaccess') {
         $output = &modify_ipaccess($dom,$lastactref,%domconfig);          $output = &modify_ipaccess($dom,$lastactref,%domconfig);
     } elsif ($action eq 'authordefaults') {  
         $output = &modify_authordefaults($dom,$lastactref,%domconfig);  
     }      }
     return $output;      return $output;
 }  }
Line 855  sub print_config_box { Line 924  sub print_config_box {
     } elsif ($action eq 'lti') {      } elsif ($action eq 'lti') {
         $output .= &passwords_javascript('ltisecrets')."\n".          $output .= &passwords_javascript('ltisecrets')."\n".
                    &lti_javascript($dom,$settings);                     &lti_javascript($dom,$settings);
       } elsif ($action eq 'proctoring') {
           $output .= &proctoring_javascript($settings);
     } elsif ($action eq 'wafproxy') {      } elsif ($action eq 'wafproxy') {
         $output .= &wafproxy_javascript($dom);          $output .= &wafproxy_javascript($dom);
     } elsif ($action eq 'autoupdate') {      } elsif ($action eq 'autoupdate') {
Line 865  sub print_config_box { Line 936  sub print_config_box {
         $output .= &saml_javascript();          $output .= &saml_javascript();
     } elsif ($action eq 'ipaccess') {      } elsif ($action eq 'ipaccess') {
         $output .= &ipaccess_javascript($settings);          $output .= &ipaccess_javascript($settings);
     } elsif ($action eq 'authordefaults') {  
         $output .= &authordefaults_javascript();  
     }      }
     $output .=      $output .=
          '<table class="LC_nested_outer">           '<table class="LC_nested_outer">
Line 906  sub print_config_box { Line 975  sub print_config_box {
         $rowtotal ++;          $rowtotal ++;
         if (($action eq 'autoupdate') || ($action eq 'usercreation') || ($action eq 'selfcreation') ||          if (($action eq 'autoupdate') || ($action eq 'usercreation') || ($action eq 'selfcreation') ||
             ($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||              ($action eq 'usermodification') || ($action eq 'defaults') || ($action eq 'coursedefaults') ||
             ($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'directorysrch') ||              ($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'ssl') ||
             ($action eq 'helpsettings') || ($action eq 'contacts') || ($action eq 'wafproxy') ||              ($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
             ($action eq 'lti') || ($action eq 'ltitools') || ($action eq 'authordefaults')) {              ($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'wafproxy') ||
               ($action eq 'lti') || ($action eq 'ltitools')) {
             $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'passwords') {          } elsif ($action eq 'passwords') {
             $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);              $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);
Line 942  sub print_config_box { Line 1012  sub print_config_box {
             $rowtotal ++;              $rowtotal ++;
         if (($action eq 'autoupdate') || ($action eq 'usercreation') ||          if (($action eq 'autoupdate') || ($action eq 'usercreation') ||
             ($action eq 'selfcreation') || ($action eq 'selfenrollment') ||              ($action eq 'selfcreation') || ($action eq 'selfenrollment') ||
             ($action eq 'usersessions') || ($action eq 'coursecategories') ||              ($action eq 'usersessions') || ($action eq 'coursecategories') || 
             ($action eq 'contacts') || ($action eq 'passwords') ||               ($action eq 'trust') || ($action eq 'contacts') || ($action eq 'defaults') ||
             ($action eq 'defaults') || ($action eq 'lti') ||              ($action eq 'privacy') || ($action eq 'passwords') || ($action eq 'lti') ||
             ($action eq 'ltitools')) {              ($action eq 'ltitools')) {
             if ($action eq 'coursecategories') {              if ($action eq 'coursecategories') {
                 $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);                  $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);
                 $colspan = ' colspan="2"';                  $colspan = ' colspan="2"';
               } elsif ($action eq 'trust') {
                   $output .= $item->{'print'}->('shared',$dom,$settings,\$rowtotal);
             } elsif ($action eq 'passwords') {              } elsif ($action eq 'passwords') {
                 $output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal);                  $output .= $item->{'print'}->('middle',$dom,$confname,$settings,\$rowtotal);
             } elsif ($action eq 'lti') {  
                 $output .= $item->{'print'}->('upper',$dom,$settings,\$rowtotal).'  
                            </table>  
                           </td>  
                          </tr>  
                          <tr>  
                           <td>  
                           <table class="LC_nested">  
                            <tr class="LC_info_row">  
                             <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>  
                             <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>  
                            </tr>'."\n".  
                            $item->{'print'}->('middle',$dom,$settings,\$rowtotal);  
             } else {              } else {
                 $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);                  $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
             }              }
             my $hdridx = 2;              if ($action eq 'trust') {
             if ($action eq 'lti') {                  $output .= '
                 $hdridx = 3;              </table>
             }            </td>
             $output .= '           </tr>';
                   my @trusthdrs = qw(2 3 4 5 6 7);
                   my @prefixes = qw(enroll othcoau coaurem domroles catalog reqcrs);
                   for (my $i=0; $i<@trusthdrs; $i++) {
                       $output .= '
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$trusthdrs[$i]]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->($prefixes[$i],$dom,$settings,\$rowtotal).'
               </table>
             </td>
            </tr>';
                   }
                   $output .= '
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
               } else {
                   $output .= '
            </table>             </table>
           </td>            </td>
          </tr>           </tr>
Line 979  sub print_config_box { Line 1063  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item">'.&mt($item->{'header'}->[$hdridx]->{'col2'}).'</td>                <td class="LC_right_item">'.&mt($item->{'header'}->[2]->{'col2'}).'</td>
              </tr>'."\n";               </tr>'."\n";
             if ($action eq 'coursecategories') {                  if ($action eq 'coursecategories') {
                 $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);                      $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);
             } elsif (($action eq 'contacts') || ($action eq 'passwords')) {                  } elsif (($action eq 'contacts') || ($action eq 'privacy') || 
                 if ($action eq 'passwords') {                           ($action eq 'passwords') || ($action eq 'lti')) {
                     $output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal);                      if ($action eq 'passwords') {
                 } else {                          $output .= $item->{'print'}->('lower',$dom,$confname,$settings,\$rowtotal);
                     $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal);                      } else {
                 }                          $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal);
                 $hdridx ++;                      }
                 $output .= '                      $output .= '
              </tr>               </tr>
             </table>              </table>
            </td>             </td>
Line 1000  sub print_config_box { Line 1084  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col1'}).'</td>                <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col2'}).'</td></tr>'."\n";                <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'."\n";
                 if ($action eq 'passwords') {                      if ($action eq 'passwords') {
                     $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal);                          $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal);
                 } else {                      } else {
                     $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);                          $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
                 }                      }
                 $output .= '                      $output .= '
             </table>              </table>
           </td>            </td>
          </tr>           </tr>
          <tr>';           <tr>';
             } else {                  } else {
                 $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);                      $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
                   }
             }              }
             $rowtotal ++;              $rowtotal ++;
         } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||          } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||
                  ($action eq 'directorysrch') || ($action eq 'helpsettings') ||                   ($action eq 'directorysrch') || ($action eq 'helpsettings') ||
                  ($action eq 'wafproxy') || ($action eq 'authordefaults')) {                   ($action eq 'wafproxy')) {
             $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);              $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'scantron') {          } elsif ($action eq 'scantron') {
             $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);              $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal);
           } elsif ($action eq 'ssl') {
               $output .= $item->{'print'}->('connto',$dom,$settings,\$rowtotal).'
               </table>
             </td>
            </tr>
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[2]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->('connfrom',$dom,$settings,\$rowtotal).'
               </table>
             </td>
            </tr>
            <tr>
              <td>
               <table class="LC_nested">
                <tr class="LC_info_row">
                 <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
                 <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'.
                              $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'login') {          } elsif ($action eq 'login') {
             if ($numheaders == 5) {              if ($numheaders == 5) {
                 $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'                  $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).'
Line 1112  sub print_config_box { Line 1219  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item"'.$colspan.' valign="top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td>                <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col1'}).'</td>
               <td class="LC_right_item" valign="top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td>                <td class="LC_right_item" style="vertical-align: top">'.&mt($item->{'header'}->[4]->{'col2'}).'</td>
              </tr>'.               </tr>'.
             &print_validation_rows('requestcourses',$dom,$settings,\$rowtotal);              &print_validation_rows('requestcourses',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'requestauthor') {          } elsif ($action eq 'requestauthor') {
Line 1128  sub print_config_box { Line 1235  sub print_config_box {
            <td>             <td>
             <table class="LC_nested">              <table class="LC_nested">
              <tr class="LC_info_row">               <tr class="LC_info_row">
               <td class="LC_left_item"'.$colspan.' valign="top">'.                <td class="LC_left_item"'.$colspan.' style="vertical-align: top">'.
                &mt($item->{'header'}->[2]->{'col1'}).'</td>                 &mt($item->{'header'}->[2]->{'col1'}).'</td>
               <td class="LC_right_item" valign="top">'.                <td class="LC_right_item" style="vertical-align: top">'.
                &mt($item->{'header'}->[2]->{'col2'}).'</td>                 &mt($item->{'header'}->[2]->{'col2'}).'</td>
              </tr>'.               </tr>'.
             &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).'              &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).'
Line 1158  sub print_config_box { Line 1265  sub print_config_box {
               <td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';                <td class="LC_left_item" colspan="2">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';
         } elsif ($action eq 'serverstatuses') {          } elsif ($action eq 'serverstatuses') {
             $output .= '              $output .= '
               <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).                <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).
               '<br />('.&mt('Automatic access for Dom. Coords.').')</td>';                '<br />('.&mt('Automatic access for Dom. Coords.').')</td>';
   
         } else {          } else {
             $output .= '              $output .= '
               <td class="LC_left_item" valign="top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';                <td class="LC_left_item" style="vertical-align: top">'.&mt($item->{'header'}->[0]->{'col1'}).'</td>';
         }          }
         if (defined($item->{'header'}->[0]->{'col3'})) {          if (defined($item->{'header'}->[0]->{'col3'})) {
             $output .= '<td class="LC_left_item" valign="top">'.              $output .= '<td class="LC_left_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col2'});                         &mt($item->{'header'}->[0]->{'col2'});
             if ($action eq 'serverstatuses') {              if ($action eq 'serverstatuses') {
                 $output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)';                  $output .= '<br />(<tt>'.&mt('user1:domain1,user2:domain2 etc.').'</tt>)';
             }               } 
         } else {          } else {
             $output .= '<td class="LC_right_item" valign="top">'.              $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col2'});                         &mt($item->{'header'}->[0]->{'col2'});
         }          }
         $output .= '</td>';          $output .= '</td>';
         if ($item->{'header'}->[0]->{'col3'}) {          if ($item->{'header'}->[0]->{'col3'}) {
             if (defined($item->{'header'}->[0]->{'col4'})) {              if (defined($item->{'header'}->[0]->{'col4'})) {
                 $output .= '<td class="LC_left_item" valign="top">'.                  $output .= '<td class="LC_left_item" style="vertical-align: top">'.
                             &mt($item->{'header'}->[0]->{'col3'});                              &mt($item->{'header'}->[0]->{'col3'});
             } else {              } else {
                 $output .= '<td class="LC_right_item" valign="top">'.                  $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                            &mt($item->{'header'}->[0]->{'col3'});                             &mt($item->{'header'}->[0]->{'col3'});
             }              }
             if ($action eq 'serverstatuses') {              if ($action eq 'serverstatuses') {
Line 1190  sub print_config_box { Line 1297  sub print_config_box {
             $output .= '</td>';              $output .= '</td>';
         }          }
         if ($item->{'header'}->[0]->{'col4'}) {          if ($item->{'header'}->[0]->{'col4'}) {
             $output .= '<td class="LC_right_item" valign="top">'.              $output .= '<td class="LC_right_item" style="vertical-align: top">'.
                        &mt($item->{'header'}->[0]->{'col4'});                         &mt($item->{'header'}->[0]->{'col4'});
         }          }
         $output .= '</tr>';          $output .= '</tr>';
Line 1198  sub print_config_box { Line 1305  sub print_config_box {
         if ($action eq 'quotas') {          if ($action eq 'quotas') {
             $output .= &print_quotas($dom,$settings,\$rowtotal,$action);              $output .= &print_quotas($dom,$settings,\$rowtotal,$action);
         } elsif (($action eq 'autoenroll') || ($action eq 'autocreate') ||           } elsif (($action eq 'autoenroll') || ($action eq 'autocreate') || 
                  ($action eq 'serverstatuses') || ($action eq 'loadbalancing') ||                   ($action eq 'serverstatuses') || ($action eq 'loadbalancing') || 
                  ($action eq 'ipaccess')) {                   ($action eq 'proctoring') || ($action eq 'ipaccess')) {
             $output .= $item->{'print'}->($dom,$settings,\$rowtotal);              $output .= $item->{'print'}->($dom,$settings,\$rowtotal);
         }          }
     }      }
Line 1224  sub print_login { Line 1331  sub print_login {
         my $choice = $choices{'disallowlogin'};          my $choice = $choices{'disallowlogin'};
         $css_class = ' class="LC_odd_row"';          $css_class = ' class="LC_odd_row"';
         $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'.          $datatable .= '<tr'.$css_class.'><td>'.$choice.'</td>'.
                       '<td align="right"><table><tr><th>'.$choices{'hostid'}.'</th>'.                        '<td style="text-align: right"><table><tr><th>'.$choices{'hostid'}.'</th>'.
                       '<th>'.$choices{'server'}.'</th>'.                        '<th>'.$choices{'server'}.'</th>'.
                       '<th>'.$choices{'serverpath'}.'</th>'.                        '<th>'.$choices{'serverpath'}.'</th>'.
                       '<th>'.$choices{'custompath'}.'</th>'.                        '<th>'.$choices{'custompath'}.'</th>'.
Line 1505  sub print_login { Line 1612  sub print_login {
         my $choice = $choices{'headtag'};          my $choice = $choices{'headtag'};
         $css_class = ' class="LC_odd_row"';          $css_class = ' class="LC_odd_row"';
         $datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'.          $datatable .= '<tr'.$css_class.'><td colspan="2">'.$choice.'</td>'.
                       '<td align="left"><table><tr><th>'.$choices{'hostid'}.'</th>'.                        '<td style="text-align: left"><table><tr><th>'.$choices{'hostid'}.'</th>'.
                       '<th>'.$choices{'current'}.'</th>'.                        '<th>'.$choices{'current'}.'</th>'.
                       '<th>'.$choices{'action'}.'</th>'.                        '<th>'.$choices{'action'}.'</th>'.
                       '<th>'.$choices{'exempt'}.'</th></tr>'."\n";                        '<th>'.$choices{'exempt'}.'</th></tr>'."\n";
Line 2154  sub display_color_options { Line 2261  sub display_color_options {
                   '<table border="0"><tr>';                    '<table border="0"><tr>';
   
     foreach my $item (@{$bgs}) {      foreach my $item (@{$bgs}) {
         $datatable .= '<td align="center">'.$choices->{$item};          $datatable .= '<td style="text-align: center">'.$choices->{$item};
  my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item};   my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item};
         if ($designs->{'bgs'}{$item}) {          if ($designs->{'bgs'}{$item}) {
             $datatable .= '&nbsp;';              $datatable .= '&nbsp;';
Line 2182  sub display_color_options { Line 2289  sub display_color_options {
                   '<table border="0"><tr>';                    '<table border="0"><tr>';
     foreach my $item (@{$links}) {      foreach my $item (@{$links}) {
  my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item};   my $color = $designs->{'links'}{$item} ? $designs->{'links'}{$item} : $defaults->{'links'}{$item};
         $datatable .= '<td align="center">'.$choices->{$item}."\n";          $datatable .= '<td style="text-align: center">'.$choices->{$item}."\n";
         if ($designs->{'links'}{$item}) {          if ($designs->{'links'}{$item}) {
             $datatable.='&nbsp;';              $datatable.='&nbsp;';
         }          }
Line 2243  sub login_text_colors { Line 2350  sub login_text_colors {
     my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_;      my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_;
     my $color_menu = '<table border="0"><tr>';      my $color_menu = '<table border="0"><tr>';
     foreach my $item (@{$logintext}) {      foreach my $item (@{$logintext}) {
         $color_menu .= '<td align="center">'.$choices->{$item};          $color_menu .= '<td style="text-align: center">'.$choices->{$item};
         my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item};          my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item};
         $color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color.          $color_menu .= '<br /><input type="text" class="colorchooser" size="8" name="'.$role.'_'.$item.'" value="'.$color.
                       '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>';                        '" onblur = "javascript:colchg_span('."'css_".$role.'_'.$item."'".',this);" /></td>';
Line 2276  sub image_changes { Line 2383  sub image_changes {
                        $role.'_del_'.$img.'" value="1" />'.&mt('Delete?').                         $role.'_del_'.$img.'" value="1" />'.&mt('Delete?').
                        '</label>&nbsp;'.&mt('Replace:').'</span><br />';                         '</label>&nbsp;'.&mt('Replace:').'</span><br />';
         } else {          } else {
             $output .= '<td valign="middle">'.$logincolors.&mt('Upload:').'<br />';              $output .= '<td class="LC_middle">'.$logincolors.&mt('Upload:').'<br />';
         }          }
     }      }
     return $output;      return $output;
Line 2290  sub print_quotas { Line 2397  sub print_quotas {
     } else {      } else {
         $context = $action;          $context = $action;
     }      }
     my ($datatable,$defaultquota,@usertools,@options,%validations);      my ($datatable,$defaultquota,$authorquota,@usertools,@options,%validations);
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);      my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
     my $typecount = 0;      my $typecount = 0;
     my ($css_class,%titles);      my ($css_class,%titles);
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook','lti');          @usertools = ('official','unofficial','community','textbook','placement','lti');
         @options =('norequest','approval','validate','autolimit');          @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);          %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();          %titles = &courserequest_titles();
Line 2304  sub print_quotas { Line 2411  sub print_quotas {
         @options = ('norequest','approval','automatic');          @options = ('norequest','approval','automatic');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','portfolio','timezone');          @usertools = ('aboutme','blog','webdav','portfolio','timezone');
         %titles = &tool_titles();          %titles = &tool_titles();
     }      }
     if (ref($types) eq 'ARRAY') {      if (ref($types) eq 'ARRAY') {
         foreach my $type (@{$types}) {          foreach my $type (@{$types}) {
             my $currdefquota;              my ($currdefquota,$currauthorquota);
             unless (($context eq 'requestcourses') ||              unless (($context eq 'requestcourses') ||
                     ($context eq 'requestauthor')) {                      ($context eq 'requestauthor')) {
                 if (ref($settings) eq 'HASH') {                  if (ref($settings) eq 'HASH') {
Line 2318  sub print_quotas { Line 2425  sub print_quotas {
                     } else {                      } else {
                         $currdefquota = $settings->{$type};                          $currdefquota = $settings->{$type};
                     }                      }
                       if (ref($settings->{authorquota}) eq 'HASH') {
                           $currauthorquota = $settings->{authorquota}->{$type};
                       }
                 }                  }
             }              }
             if (defined($usertypes->{$type})) {              if (defined($usertypes->{$type})) {
Line 2435  sub print_quotas { Line 2545  sub print_quotas {
                         ($context eq 'requestauthor')) {                          ($context eq 'requestauthor')) {
                     $datatable .=                       $datatable .= 
                               '<td class="LC_right_item">'.                                '<td class="LC_right_item">'.
                               '<span class="LC_nobreak">'.                                '<span class="LC_nobreak">'.&mt('Portfolio').':&nbsp;'.
                               '<input type="text" name="quota_'.$type.                                '<input type="text" name="quota_'.$type.
                               '" value="'.$currdefquota.                                '" value="'.$currdefquota.
                                 '" size="5" /></span>'.('&nbsp;' x 2).
                                 '<span class="LC_nobreak">'.&mt('Authoring').':&nbsp;'.
                                 '<input type="text" name="authorquota_'.$type.
                                 '" value="'.$currauthorquota.
                               '" size="5" /></span></td>';                                '" size="5" /></span></td>';
                 }                  }
                 $datatable .= '</tr>';                  $datatable .= '</tr>';
Line 2446  sub print_quotas { Line 2560  sub print_quotas {
     }      }
     unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {      unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         $defaultquota = '20';          $defaultquota = '20';
           $authorquota = '500';
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if (ref($settings->{'defaultquota'}) eq 'HASH') {              if (ref($settings->{'defaultquota'}) eq 'HASH') {
                 $defaultquota = $settings->{'defaultquota'}->{'default'};                  $defaultquota = $settings->{'defaultquota'}->{'default'};
             } elsif (defined($settings->{'default'})) {              } elsif (defined($settings->{'default'})) {
                 $defaultquota = $settings->{'default'};                  $defaultquota = $settings->{'default'};
             }              }
               if (ref($settings->{'authorquota'}) eq 'HASH') {
                   $authorquota = $settings->{'authorquota'}->{'default'};
               }
         }          }
     }      }
     $typecount ++;      $typecount ++;
Line 2563  sub print_quotas { Line 2681  sub print_quotas {
     $datatable .= '</td>';      $datatable .= '</td>';
     unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {      unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         $datatable .= '<td class="LC_right_item">'.          $datatable .= '<td class="LC_right_item">'.
                       '<span class="LC_nobreak">'.                        '<span class="LC_nobreak">'.&mt('Portfolio').':&nbsp;'.
                       '<input type="text" name="defaultquota" value="'.                        '<input type="text" name="defaultquota" value="'.
                       $defaultquota.'" size="5" /></span></td>';                        $defaultquota.'" size="5" /></span>'.('&nbsp;' x2).
                         '<span class="LC_nobreak">'.&mt('Authoring').':&nbsp;'.
                         '<input type="text" name="authorquota" value="'.
                         $authorquota.'" size="5" /></span></td>';
     }      }
     $datatable .= '</tr>';      $datatable .= '</tr>';
     $typecount ++;      $typecount ++;
Line 2748  sub print_studentcode { Line 2869  sub print_studentcode {
     my ($settings,$rowtotal) = @_;      my ($settings,$rowtotal) = @_;
     my $rownum = 0;       my $rownum = 0; 
     my ($output,%current);      my ($output,%current);
     my @crstypes = ('official','unofficial','community','textbook','lti');      my @crstypes = ('official','unofficial','community','textbook','placement','lti');
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if (ref($settings->{'uniquecode'}) eq 'HASH') {          if (ref($settings->{'uniquecode'}) eq 'HASH') {
             foreach my $type (@crstypes) {              foreach my $type (@crstypes) {
Line 3239  function toggleWAF() { Line 3360  function toggleWAF() {
 ENDSCRIPT  ENDSCRIPT
 }  }
   
   sub proctoring_javascript {
       my ($settings) = @_;
       my (%ordered,$total,%jstext);
       $total = 0;
       if (ref($settings) eq 'HASH') {
           foreach my $item (keys(%{$settings})) {
               if (ref($settings->{$item}) eq 'HASH') {
                   my $num = $settings->{$item}{'order'};
                   $ordered{$num} = $item;
               }
           }
           $total = scalar(keys(%{$settings}));
       } else {
           %ordered = (
                          0 => 'proctorio',
                          1 => 'examity',
                      );
           $total = 2; 
       }
       my @jsarray = ();
       foreach my $item (sort {$a <=> $b } (keys(%ordered))) {
           push(@jsarray,$ordered{$item});
       }
       my $jstext = '    var proctors = Array('."'".join("','",@jsarray)."'".');'."\n";
       return <<"ENDSCRIPT";
   <script type="text/javascript">
   // <![CDATA[
   function reorderProctoring(form,item) {
       var changedVal;
   $jstext
       var maxh = $total;
       var current = new Array;
       var changedVal = form.elements[item].options[form.elements[item].selectedIndex].value;
       for (var i=0; i<proctors.length; i++) {
           var elementName = 'proctoring_pos_'+proctors[i];
           if (elementName != item) {
               if (form.elements[elementName]) {
                   var currVal = form.elements[elementName].options[form.elements[elementName].selectedIndex].value;
                   current[currVal] = elementName;
               }
           }
       }
       var oldVal;
       for (var j=0; j<maxh; j++) {
           if (current[j] == undefined) {
               oldVal = j;
           }
       }
       if (oldVal < changedVal) {
           for (var k=oldVal+1; k<=changedVal ; k++) {
              var elementName = current[k];
              form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex - 1;
           }
       } else {
           for (var k=changedVal; k<oldVal; k++) {
               var elementName = current[k];
               form.elements[elementName].selectedIndex = form.elements[elementName].selectedIndex + 1;
           }
       }
       return;
   }
   
   function toggleProctoring(form,item) {
       var fieldsets = document.getElementsByClassName('proctoring_'+item);
       if (fieldsets.length) {
           var radioname = 'proctoring_available_'+item;
           var num = form.elements[radioname].length;
           if (num) {
               var setvis = '';
               for (var i=0; i<num; i++) {
                   if (form.elements[radioname][i].checked) {
                       if (form.elements[radioname][i].value == '1') {
                          setvis = 1;
                          break;
                       }
                   }
               }
               for (var j=0; j<fieldsets.length; j++) {
                   if (setvis) {
                       fieldsets[j].style.display = 'block';
                   } else {
                       fieldsets[j].style.display = 'none';
                   }
               }
           }
       }
       return;
   }
   
   // ]]>
   </script>
   
   ENDSCRIPT
   }
   
   
 sub lti_javascript {  sub lti_javascript {
     my ($dom,$settings) = @_;      my ($dom,$settings) = @_;
     my $togglejs = &lti_toggle_js($dom);      my $togglejs = &lti_toggle_js($dom);
Line 3725  $jstext Line 3942  $jstext
 ENDSCRIPT  ENDSCRIPT
 }  }
   
 sub authordefaults_javascript {  
     my %alert = &Apache::lonlocal::texthash (  
                     reqd => 'Warning: at least one editor needs to be available.',  
                     rest => 'Unchecking this editor disallowed while others unchecked.',  
     );  
     &js_escape(\%alert);  
     return <<"ENDSCRIPT";  
 <script type="text/javascript">  
 // <![CDATA[  
   
 function checkEditors(form,checkbox,current) {  
     if (form.elements[checkbox].length != undefined) {  
         var count = 0;  
         for (var i=0; i<form.elements[checkbox].length; i++) {  
             if (form.elements[checkbox][i].checked) {  
                 count ++;  
             }  
         }  
         if (count == 0) {  
             if (current.type =='radio') {  
                 current.checked = true;  
                 alert('$alert{reqd}\\n$alert{rest}');  
             }  
         }  
     }  
     return;  
 }  
 // ]]>  
 </script>  
   
 ENDSCRIPT  
 }  
   
 sub print_autoenroll {  sub print_autoenroll {
     my ($dom,$settings,$rowtotal) = @_;      my ($dom,$settings,$rowtotal) = @_;
     my $autorun = &Apache::lonnet::auto_run(undef,$dom),      my $autorun = &Apache::lonnet::auto_run(undef,$dom),
Line 4772  sub print_helpsettings { Line 4956  sub print_helpsettings {
             my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);              my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
             $css_class = $itemcount%2?' class="LC_odd_row"':'';              $css_class = $itemcount%2?' class="LC_odd_row"':'';
             my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"';              my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$num."_pos'".');"';
             $datatable .= '<tr '.$css_class.'><td valign="top"><b>'.$role.'</b><br />'.              $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><b>'.$role.'</b><br />'.
                           '<select name="helproles_'.$num.'_pos"'.$chgstr.'>';                            '<select name="helproles_'.$num.'_pos"'.$chgstr.'>';
             for (my $k=0; $k<=$maxnum; $k++) {              for (my $k=0; $k<=$maxnum; $k++) {
                 my $vpos = $k+1;                  my $vpos = $k+1;
Line 4811  sub print_helpsettings { Line 4995  sub print_helpsettings {
         &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);          &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent);
         my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);          my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype);
         my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"';          my $chgstr = ' onchange="javascript:reorderHelpRoles(this.form,'."'helproles_".$count."_pos'".');"';
         $datatable .= '<tr '.$css_class.'><td valign="top"><span class="LC_nobreak"><label>'.          $datatable .= '<tr '.$css_class.'><td style="vertical-align: top"><span class="LC_nobreak"><label>'.
                       '<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n".                        '<input type="hidden" name="helproles_maxnum" value="'.$maxnum.'" />'."\n".
                       '<select name="helproles_'.$count.'_pos"'.$chgstr.'>';                        '<select name="helproles_'.$count.'_pos"'.$chgstr.'>';
         for (my $k=0; $k<$maxnum+1; $k++) {          for (my $k=0; $k<$maxnum+1; $k++) {
Line 5092  sub radiobutton_prefs { Line 5276  sub radiobutton_prefs {
     foreach my $item (@{$toggles}) {      foreach my $item (@{$toggles}) {
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $datatable .=          $datatable .=
             '<tr'.$css_class.'><td valign="top">'.              '<tr'.$css_class.'><td style="vertical-align: top">'.
             '<span class="LC_nobreak">'.$choices->{$item}.              '<span class="LC_nobreak">'.$choices->{$item}.
             '</span></td>';              '</span></td>';
         if ($align eq 'left') {          if ($align eq 'left') {
Line 5321  sub secrets_form { Line 5505  sub secrets_form {
     return $output;      return $output;
 }  }
   
   sub print_proctoring {
       my ($dom,$settings,$rowtotal) = @_;
       my $itemcount = 1;
       my (%ordered,%providernames,%current,%currentdef);
       my $confname = $dom.'-domainconfig';
       my $switchserver = &check_switchserver($dom,$confname);
       if (ref($settings) eq 'HASH') {
           foreach my $item (keys(%{$settings})) {
               if (ref($settings->{$item}) eq 'HASH') {
                   my $num = $settings->{$item}{'order'};
                   $ordered{$num} = $item;
               }
           }
       } else {
           %ordered = (
                        1 => 'proctorio',
                        2 => 'examity',
                      );
       }
       %providernames = &proctoring_providernames();
       my $maxnum = scalar(keys(%ordered));
       my (%requserfields,%optuserfields,%defaults,%extended,%crsconf,@courseroles,@ltiroles);
       my ($requref,$opturef,$defref,$extref,$crsref,$rolesref,$ltiref) = &proctoring_data();
       if (ref($requref) eq 'HASH') {
           %requserfields = %{$requref};
       }
       if (ref($opturef) eq 'HASH') {
           %optuserfields = %{$opturef};
       }
       if (ref($defref) eq 'HASH') {
           %defaults = %{$defref};
       }
       if (ref($extref) eq 'HASH') {
           %extended = %{$extref};
       }
       if (ref($crsref) eq 'HASH') {
           %crsconf = %{$crsref};
       }
       if (ref($rolesref) eq 'ARRAY') {
           @courseroles = @{$rolesref};
       }
       if (ref($ltiref) eq 'ARRAY') {
           @ltiroles = @{$ltiref};
       }
       my $datatable;
       my $css_class;
       if (keys(%ordered)) {
           my @items = sort { $a <=> $b } keys(%ordered);
           for (my $i=0; $i<@items; $i++) {
               $css_class = $itemcount%2?' class="LC_odd_row"':'';
               my $provider = $ordered{$items[$i]};
               my $optionsty = 'none';
               my ($available,$version,$lifetime,$imgsrc,$userincdom,$showroles,
                   %checkedfields,%rolemaps,%inuse,%crsconfig,%current);
               if (ref($settings) eq 'HASH') {
                   if (ref($settings->{$provider}) eq 'HASH') {
                       %current = %{$settings->{$provider}};
                       if ($current{'available'}) {
                           $optionsty = 'block';
                           $available = 1;
                       }
                       if ($current{'lifetime'} =~ /^\d+$/) {
                           $lifetime = $current{'lifetime'};
                       }
                       if ($current{'version'} =~ /^\d+\.\d+$/) {
                           $version = $current{'version'};
                       }
                       if ($current{'image'} ne '') {
                           $imgsrc = '<img src="'.$current{'image'}.'" alt="'.&mt('Proctoring service icon').'" />';
                       }
                       if (ref($current{'fields'}) eq 'ARRAY') {
                           map { $checkedfields{$_} = 1; } @{$current{'fields'}};
                       }
                       $userincdom = $current{'incdom'};
                       if (ref($current{'roles'}) eq 'HASH') {
                           %rolemaps = %{$current{'roles'}};
                           $checkedfields{'roles'} = 1;
                       }
                       if (ref($current{'defaults'}) eq 'ARRAY') {
                           foreach my $val (@{$current{'defaults'}}) {
                               if (grep(/^\Q$val\E$/,@{$defaults{$provider}})) {
                                   $inuse{$val} = 1;
                               } else {
                                   foreach my $poss (keys(%{$extended{$provider}})) {
                                       if (ref($extended{$provider}{$poss}) eq 'ARRAY') {
                                           if (grep(/^\Q$val\E$/,@{$extended{$provider}{$poss}})) {
                                               $inuse{$poss} = $val;
                                               last;
                                           }
                                       }
                                   }
                               }
                           }
                       } elsif (ref($current{'defaults'}) eq 'HASH') {
                           foreach my $key (keys(%{$current{'defaults'}})) {
                               my $currval = $current{'defaults'}{$key}; 
                               if (grep(/^\Q$key\E$/,@{$defaults{$provider}})) {
                                   $inuse{$key} = 1;
                               } else {
                                   my $match;
                                   foreach my $poss (keys(%{$extended{$provider}})) {
                                       if (ref($extended{$provider}{$poss}) eq 'ARRAY') {
                                           if (grep(/^\Q$key\E$/,@{$extended{$provider}{$poss}})) {
                                               $inuse{$poss} = $key;
                                               last;
                                           }
                                       } elsif (ref($extended{$provider}{$poss}) eq 'HASH') {
                                           foreach my $inner (sort(keys(%{$extended{$provider}{$poss}}))) {
                                               if (ref($extended{$provider}{$poss}{$inner}) eq 'ARRAY') {
                                                   if (grep(/^\Q$currval\E$/,@{$extended{$provider}{$poss}{$inner}})) {
                                                       $currentdef{$inner} = $currval;
                                                       $match = 1;
                                                       last;
                                                   }
                                               } elsif ($inner eq $key) {
                                                   $currentdef{$key} = $currval;
                                                   $match = 1;
                                                   last;
                                               }
                                           }
                                       }
                                       last if ($match);
                                   }
                               }
                           }
                       }
                       if (ref($current{'crsconf'}) eq 'ARRAY') {
                           map { $crsconfig{$_} = 1; } @{$current{'crsconf'}};
                       }
                   }
               }
               my %lt = &proctoring_titles($provider);
               my %fieldtitles = &proctoring_fieldtitles($provider);
               my $onclickavailable = ' onclick="toggleProctoring(this.form,'."'$provider'".');"';
               my %checkedavailable = (
                                      yes => '',
                                      no  => ' checked="checked"',
                                    );
               if ($available) {
                   $checkedavailable{'yes'} = $checkedavailable{'no'};
                   $checkedavailable{'no'} = '';
               }
               my $chgstr = ' onchange="javascript:reorderProctoring(this.form,'."'proctoring_pos_".$provider."'".');"';
               $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
                            .'<select name="proctoring_pos_'.$provider.'"'.$chgstr.'>';
               for (my $k=0; $k<$maxnum; $k++) {
                   my $vpos = $k+1;
                   my $selstr;
                   if ($k == $i) {
                       $selstr = ' selected="selected" ';
                   }
                   $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
               }
               if ($version eq '') {
                   if ($provider eq 'proctorio') {
                       $version = '1.0';
                   } elsif ($provider eq 'examity') {
                       $version = '1.1';
                   }
               }
               if ($lifetime eq '') {
                   $lifetime = '300';
               }
               $datatable .=
                   '</select>'.('&nbsp;'x2).'<b>'.$providernames{$provider}.'</b></span><br />'.
                   '<span class="LC_nobreak">'.$lt{'avai'}.'&nbsp;'.
                   '<label><input type="radio" name="proctoring_available_'.$provider.'" value="1"'.$onclickavailable.$checkedavailable{yes}.' />'.&mt('Yes').'</label>&nbsp;'."\n".
                   '<label><input type="radio" name="proctoring_available_'.$provider.'" value="0"'.$onclickavailable.$checkedavailable{no}.' />'.&mt('No').'</label></span>'."\n".
                   '</td>'.
                   '<td colspan="2">'.
                   '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'base'}.'</legend>'.
                   '<span class="LC_nobreak">'.$lt{'version'}.':<select name="proctoring_'.$provider.'_version">'.
                   '<option value="'.$version.'" selected="selected">'.$version.'</option></select></span> '."\n".
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'sigmethod'}.':<select name="proctoring_'.$provider.'_sigmethod">'.
                   '<option value="HMAC-SHA1" selected="selected">HMAC-SHA1</option>'.
                   '<option value="HMAC-SHA256">HMAC-SHA256</option></select></span>'.
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'lifetime'}.':<input type="text" size="5" name="proctoring_'.$provider.'_lifetime" value="'.$lifetime.'" /></span> '."\n".
                   '<br />'.
                   '<span class="LC_nobreak">'.$lt{'url'}.':<input type="text" size="40" name="proctoring_'.$provider.'_url" value="'.$current{'url'}.'" /></span> '."\n".
                   '<br />'.
                   '<span class="LC_nobreak">'.$lt{'key'}.':<input type="text" size="25" name="proctoring_'.$provider.'_key" value="'.$current{'key'}.'" /></span> '."\n".
                   ('&nbsp;'x2).
                   '<span class="LC_nobreak">'.$lt{'secret'}.':<input type="password" size="20" name="proctoring_'.$provider.'_secret" value="'.$current{'secret'}.'" />'.
                   '<label><input type="checkbox" name="visible" onclick="if (this.checked) { this.form.proctoring_'.$provider.'_secret.type='."'text'".' } else { this.form.proctoring_'.$provider.'_secret.type='."'password'".' }" />'.$lt{'visible'}.'</label></span><br />'."\n";
               $datatable .= '<span class="LC_nobreak">'.$lt{'icon'}.':&nbsp;';
               if ($imgsrc) {
                   $datatable .= $imgsrc.
                                 '<label><input type="checkbox" name="proctoring_image_del"'.
                                 ' value="'.$provider.'" />'.&mt('Delete?').'</label></span> '.
                                 '<span class="LC_nobreak">&nbsp;'.&mt('Replace:');
               }
               $datatable .= '&nbsp;';
               if ($switchserver) {
                   $datatable .= &mt('Upload to library server: [_1]',$switchserver);
               } else {
                   $datatable .= '<input type="file" name="proctoring_image_'.$provider.'" value="" />';
               }
               unless ($imgsrc) {
                   $datatable .= '<br />('.&mt('if larger than 21x21 pixels, image will be scaled').')';
               }
               $datatable .= '</fieldset>'."\n";
               if (ref($requserfields{$provider}) eq 'ARRAY') {
                   if (@{$requserfields{$provider}} > 0) {
                       $datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'requ'}.'</legend>';
                       foreach my $field (@{$requserfields{$provider}}) {
                           $datatable .= '<span class="LC_nobreak">'.
                                         '<label><input type="checkbox" name="proctoring_reqd_'.$provider.'" value="'.$field.'" checked="checked" disabled="disabled" />'.
                                         $lt{$field}.'</label>';
                           if ($field eq 'user') {
                               my $seluserdom = '';
                               my $unseluserdom = ' selected="selected"';
                               if ($userincdom) {
                                   $seluserdom = $unseluserdom;
                                   $unseluserdom = '';
                               }
                               $datatable .= ':&nbsp;'.
                                   '<select name="proctoring_userincdom_'.$provider.'">'.
                                   '<option value="0"'.$unseluserdom.'>'.$lt{'username'}.'</option>'.
                                   '<option value="1"'.$seluserdom.'>'.$lt{'uname:dom'}.'</option>'.
                                   '</select>&nbsp;';
                           } else {
                               $datatable .= '&nbsp;';
                               if ($field eq 'roles') {
                                   $showroles = 1; 
                               } 
                           }
                           $datatable .= '</span> ';
                       }
                   }
                   $datatable .= '</fieldset>'."\n";
               }
               if (ref($optuserfields{$provider}) eq 'ARRAY') {
                   if (@{$optuserfields{$provider}} > 0) {
                       $datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'optu'}.'</legend>'; 
                       foreach my $field (@{$optuserfields{$provider}}) {
                           my $checked;
                           if ($checkedfields{$field}) {
                               $checked = ' checked="checked"';
                           }
                           $datatable .= '<span class="LC_nobreak">'.
                                         '<label><input type="checkbox" name="proctoring_optional_'.$provider.'" value="'.$field.'"'.$checked.' />'.$lt{$field}.'</label></span>&nbsp; ';
                       }
                       $datatable .= '</fieldset>'."\n";
                   }
               }
               if (ref($defaults{$provider}) eq 'ARRAY') {
                   if (@{$defaults{$provider}}) {
                       my (%options,@selectboxes);
                       if (ref($extended{$provider}) eq 'HASH') {
                           %options = %{$extended{$provider}};
                       }
                       $datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'"><legend>'.$lt{'defa'}.'</legend>';
                       my ($rem,$numinrow,$dropdowns);
                       if ($provider eq 'proctorio') { 
                           $datatable .= '<table>';
                           $numinrow = 4;
                       }
                       my $i = 0;
                       foreach my $field (@{$defaults{$provider}}) {
                           my $checked;
                           if ($inuse{$field}) {
                               $checked = ' checked="checked"';
                           }
                           if ($provider eq 'examity') {
                               if ($field eq 'display') {
                                   $datatable .= '<span class="LC_nobreak">'.&mt('Display target:');
                                   foreach my $option ('iframe','tab','window') {
                                       my $checkdisp;
                                       if ($currentdef{'target'} eq $option) {
                                           $checkdisp = ' checked="checked"';
                                       }
                                       $datatable .= '<label><input type="radio" name="proctoring_target_'.$provider.'" value="'.$option.'"'.$checkdisp.' />'.
                                       $fieldtitles{$option}.'</label>'.('&nbsp;'x2);
                                   }
                                   $datatable .= ('&nbsp;'x4);
                                   foreach my $dimen ('width','height') {
                                       $datatable .= '<label>'.$fieldtitles{$dimen}.'&nbsp;'.
                                                     '<input type="text" name="proctoring_'.$dimen.'_'.$provider.'" size="5" '.
                                                     'value="'.$currentdef{$dimen}.'" /></label>'.
                                                     ('&nbsp;'x2);
                                   }
                                   $datatable .= '</span><br />'.
                                                 '<div class="LC_left_float">'.$fieldtitles{'linktext'}.'<br />'.
                                                 '<input type="text" name="proctoring_linktext_'.$provider.'" '.
                                                 'size="25" value="'.$currentdef{'linktext'}.'" /></div>'.
                                                 '<div class="LC_left_float">'.$fieldtitles{'explanation'}.'<br />'.
                                                 '<textarea name="proctoring_explanation_'.$provider.'" rows="5" cols="40">'.
                                                 $currentdef{'explanation'}.
                                                 '</textarea></div><div style=""></div><br />';
                               }
                           } else {
                               if ((exists($options{$field})) && (ref($options{$field}) eq 'ARRAY')) {
                                   my ($output,$selnone);
                                   unless ($checked) {
                                       $selnone = ' selected="selected"';
                                   }
                                   $output .= '<span class="LC_nobreak">'.$fieldtitles{$field}.': '.
                                              '<select name="proctoring_defaults_'.$field.'_'.$provider.'">'.
                                              '<option value=""'.$selnone.'>'.&mt('Not in use').'</option>'; 
                                   foreach my $option (@{$options{$field}}) {
                                       my $sel; 
                                       if ($inuse{$field} eq $option) {
                                           $sel = ' selected="selected"';
                                       }
                                       $output .= '<option value="'.$option.'"'.$sel.'>'.$fieldtitles{$option}.'</option>';
                                   }
                                   $output .= '</select></span>';
                                   push(@selectboxes,$output);
                               } else {
                                   $rem = $i%($numinrow);
                                   if ($rem == 0) {
                                       if ($i > 0) {
                                           $datatable .= '</tr>';
                                       }
                                       $datatable .= '<tr>';
                                   }
                                   $datatable .= '<td class="LC_left_item">'.
                                                 '<span class="LC_nobreak">'.
                                                 '<label><input type="checkbox" name="proctoring_defaults_'.$provider.'" value="'.$field.'"'.$checked.' />'.
                                                 $fieldtitles{$field}.'</label></span></td>';
                                   $i++;
                               }
                           }
                       }
                       if ($provider eq 'proctorio') {
                           if ($numinrow) {
                               $rem = $i%$numinrow;
                           }
                           my $colsleft = $numinrow - $rem;
                           if ($colsleft > 1) {
                               $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
                           } else {
                               $datatable .= '<td class="LC_left_item">';
                           }
                           $datatable .= '&nbsp;'.
                                         '</td></tr></table>';
                           if (@selectboxes) {
                               $datatable .= '<hr /><table>';
                               $numinrow = 2;
                               for (my $i=0; $i<@selectboxes; $i++) {
                                   $rem = $i%($numinrow);
                                   if ($rem == 0) {
                                       if ($i > 0) {
                                           $datatable .= '</tr>';
                                       }
                                       $datatable .= '<tr>';
                                   }
                                   $datatable .= '<td class="LC_left_item">'.
                                                 $selectboxes[$i].'</td>';
                               }
                               if ($numinrow) {
                                   $rem = $i%$numinrow;
                               }
                               $colsleft = $numinrow - $rem;
                               if ($colsleft > 1) {
                                   $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
                               } else {
                                   $datatable .= '<td class="LC_left_item">';
                               }
                               $datatable .= '&nbsp;'.
                                             '</td></tr></table>';
                           }
                       }
                       $datatable .= '</fieldset>';
                   }
                   if (ref($crsconf{$provider}) eq 'ARRAY') {
                       $datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'">'.
                                     '<legend>'.&mt('Configurable in course').'</legend>';
                       my ($rem,$numinrow);
                       if ($provider eq 'proctorio') {
                           $datatable .= '<table>';
                           $numinrow = 4;
                       }
                       my $i = 0;
                       foreach my $item (@{$crsconf{$provider}}) {
                           my $name;
                           if ($provider eq 'examity') {
                               $name = $lt{'crs'.$item};
                           } elsif ($provider eq 'proctorio') {
                               $name = $fieldtitles{$item};
                               $rem = $i%($numinrow);
                               if ($rem == 0) {
                                   if ($i > 0) {
                                       $datatable .= '</tr>';
                                   }
                                   $datatable .= '<tr>';
                               }
                               $datatable .= '<td class="LC_left_item>';
                           }
                           my $checked;
                           if ($crsconfig{$item}) {
                               $checked = ' checked="checked"';
                           }
                           $datatable .= '<span class="LC_nobreak"><label>'.
                                         '<input type="checkbox" name="proctoring_crsconf_'.$provider.'" value="'.$item.'"'.$checked.' />'.
                                         $name.'</label></span>';
                           if ($provider eq 'examity') {
                               $datatable .= '&nbsp; ';
                           }
                           $datatable .= "\n";
                           $i++;
                       }
                       if ($provider eq 'proctorio') {
                           if ($numinrow) {
                               $rem = $i%$numinrow;
                           }
                           my $colsleft = $numinrow - $rem;
                           if ($colsleft > 1) {
                               $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">';
                           } else {
                               $datatable .= '<td class="LC_left_item">';
                           }
                           $datatable .= '&nbsp;'.
                                         '</td></tr></table>';
                       }
                       $datatable .= '</fieldset>';
                   }
                   if ($showroles) {
                       $datatable .= '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'">'.
                                     '<legend>'.&mt('Role mapping').'</legend><table><tr>';
                       foreach my $role (@courseroles) {
                           my ($selected,$selectnone);
                           if (!$rolemaps{$role}) {
                               $selectnone = ' selected="selected"';
                           }
                           $datatable .= '<td style="text-align: center">'.
                                         &Apache::lonnet::plaintext($role,'Course').'<br />'.
                                         '<select name="proctoring_roles_'.$role.'_'.$provider.'">'.
                                         '<option value=""'.$selectnone.'>'.&mt('Select').'</option>';
                           foreach my $ltirole (@ltiroles) {
                               unless ($selectnone) {
                                   if ($rolemaps{$role} eq $ltirole) {
                                       $selected = ' selected="selected"';
                                   } else {
                                       $selected = '';
                                   }
                               }
                               $datatable .= '<option value="'.$ltirole.'"'.$selected.'>'.$ltirole.'</option>';
                           }
                           $datatable .= '</select></td>';
                       }
                       $datatable .= '</tr></table></fieldset>'.
                                     '<fieldset class="proctoring_'.$provider.'" style="display:'.$optionsty.'">'.
                                     '<legend>'.&mt('Custom items sent on launch').'</legend>'.
                                     '<table><tr><th>'.&mt('Action').'</th><th>'.&mt('Name').'</th><th>'.&mt('Value').'</th></tr>'.
                                     '<tr><td></td><td>lms</td>'.
                                     '<td><input type="text" name="proctoring_customval_lms_'.$provider.'"'.
                                     ' value="Loncapa" disabled="disabled"/></td></tr>';
                       if ((ref($settings) eq 'HASH') && (ref($settings->{$provider}) eq 'HASH') &&
                           (ref($settings->{$provider}->{'custom'}) eq 'HASH')) {
                           my %custom = %{$settings->{$provider}->{'custom'}};
                           if (keys(%custom) > 0) {
                               foreach my $key (sort(keys(%custom))) {
                                   next if ($key eq 'lms');
                                   $datatable .= '<tr><td><span class="LC_nobreak">'.
                                                 '<label><input type="checkbox" name="proctoring_customdel_'.$provider.'" value="'.
                                                 $key.'" />'.&mt('Delete').'</label></span></td><td>'.$key.'</td>'.
                                                 '<td><input type="text" name="proctoring_customval_'.$key.'_'.$provider.'"'.
                                                 ' value="'.$custom{$key}.'" /></td></tr>';
                               }
                           }
                       }
                       $datatable .= '<tr><td><span class="LC_nobreak">'.
                                     '<label><input type="checkbox" name="proctoring_customadd" value="'.$provider.'" />'.
                                     &mt('Add more').'</label></span></td><td><input type="text" name="proctoring_custom_name_'.$provider.'" />'.
                                     '</td><td><input type="text" name="proctoring_custom_value_'.$provider.'" /></td></tr>'.
                                     '</table></fieldset></td></tr>'."\n";
                   }
                   $datatable .= '</td></tr>';
               }
               $itemcount ++;
           }
       }
       return $datatable;
   }
   
   sub proctoring_data {
       my $requserfields = {
                         proctorio => ['user'],
                         examity   => ['roles','user'],
                        };
       my $optuserfields = {
                           proctorio => ['fullname'],
                           examity   => ['fullname','firstname','lastname','email'],
                        };
       my $defaults = {
                     proctorio => ['recordvideo','recordaudio','recordscreen','recordwebtraffic',
                                   'recordroomstart','verifyvideo','verifyaudio','verifydesktop',
                                   'verifyid','verifysignature','fullscreen','clipboard','tabslinks',
                                   'closetabs','onescreen','print','downloads','cache','rightclick',
                                   'reentry','calculator','whiteboard'],
                     examity   => ['display'],
                   };
       my $extended = { 
                     proctorio => {
                                    verifyid => ['verifyidauto','verifyidlive'],
                                    fullscreen => ['fullscreenlenient','fullscreenmoderate','fullscreensever'],
                                    tabslinks => ['notabs','linksonly'],
                                    reentry => ['noreentry','agentreentry'],
                                    calculator => ['calculatorbasic','calculatorsci'],
                                  },
                     examity => {
                                  display => {
                                              target      => ['iframe','tab','window'],
                                              width       => '',
                                              height      => '',
                                              linktext    => '',
                                              explanation => '',
                                             },
                                },
                   };
       my $crsconf = {
                    proctorio => ['recordvideo','recordaudio','recordscreen','recordwebtraffic',
                                  'recordroomstart','verifyvideo','verifyaudio','verifydesktop',
                                  'verifyid','verifysignature','fullscreen','clipboard','tabslinks',
                                  'closetabs','onescreen','print','downloads','cache','rightclick',
                                  'reentry','calculator','whiteboard'],
                    examity => ['label','title','target','linktext','explanation','append'],
                  };
       my $courseroles = ['cc','in','ta','ep','st'];
       my $ltiroles = ['Instructor','ContentDeveloper','TeachingAssistant','Learner'];
       return ($requserfields,$optuserfields,$defaults,$extended,$crsconf,$courseroles,$ltiroles);
   }
   
   sub proctoring_titles {
       my ($item) = @_;
       my (%common_lt,%custom_lt);
       %common_lt = &Apache::lonlocal::texthash (
                        'avai'      => 'Available?',
                        'base'      => 'Basic Settings',
                        'requ'      => 'User data required to be sent on launch',
                        'optu'      => 'User data optionally sent on launch',
                        'udsl'      => 'User data sent on launch',
                        'defa'      => 'Defaults for items configurable in course',
                        'sigmethod' => 'Signature Method',
                        'key'       => 'Key',
                        'lifetime'  => 'Nonce lifetime (s)',
                        'secret'    => 'Secret',
                        'icon'      => 'Icon',
                        'fullname'  => 'Full Name',
                        'visible'   => 'Visible input',
                        'username'  => 'username',
                        'user'      => 'User',
                    );
       if ($item eq 'proctorio') {
           %custom_lt = &Apache::lonlocal::texthash (
                            'version'        => 'OAuth version',
                            'url'            => 'API URL',
                            'uname:dom'      => 'username-domain',
           );
       } elsif ($item eq 'examity') {
           %custom_lt = &Apache::lonlocal::texthash (
                            'version'        => 'LTI Version',
                            'url'            => 'URL',
                            'uname:dom'      => 'username:domain',
                            'msgtype'        => 'Message Type',
                            'firstname'      => 'First Name',
                            'lastname'       => 'Last Name',
                            'email'          => 'E-mail',
                            'roles'          => 'Role',
                            'crstarget'      => 'Display target',
                            'crslabel'       => 'Course label',
                            'crstitle'       => 'Course title', 
                            'crslinktext'    => 'Link Text',
                            'crsexplanation' => 'Explanation',
                            'crsappend'      => 'Provider URL',
           );
       }
       my %lt = (%common_lt,%custom_lt);
       return %lt;
   }
   
   sub proctoring_fieldtitles {
       my ($item) = @_;
       if ($item eq 'proctorio') {
           return &Apache::lonlocal::texthash (
                     'recordvideo' => 'Record video',
                     'recordaudio' => 'Record audio',
                     'recordscreen' => 'Record screen',
                     'recordwebtraffic' => 'Record web traffic',
                     'recordroomstart' => 'Record room scan',
                     'verifyvideo' => 'Verify webcam',
                     'verifyaudio' => 'Verify microphone',
                     'verifydesktop' => 'Verify desktop recording',
                     'verifyid' => 'Photo ID verification',
                     'verifysignature' => 'Require signature',
                     'fullscreen' => 'Fullscreen',
                     'clipboard' => 'Disable copy/paste',
                     'tabslinks' => 'New tabs/windows',
                     'closetabs' => 'Close other tabs',
                     'onescreen' => 'Limit to single screen',
                     'print' => 'Disable Printing',
                     'downloads' => 'Disable Downloads',
                     'cache' => 'Empty cache after exam',
                     'rightclick' => 'Disable right click',
                     'reentry' => 'Re-entry to exam',
                     'calculator' => 'Onscreen calculator',
                     'whiteboard' => 'Onscreen whiteboard',
                     'verifyidauto' => 'Automated verification',
                     'verifyidlive' => 'Live agent verification',
                     'fullscreenlenient' => 'Forced, but can navigate away for up to 30s',
                     'fullscreenmoderate' => 'Forced, but can navigate away for up to 15s',
                     'fullscreensever' => 'Forced, navigation away ends exam',
                     'notabs' => 'Disaallowed',
                     'linksonly' => 'Allowed from links in exam',
                     'noreentry' => 'Disallowed',
                     'agentreentry' => 'Agent required for re-entry',
                     'calculatorbasic' => 'Basic',
                     'calculatorsci' => 'Scientific',
           );
       } elsif ($item eq 'examity') {
           return &Apache::lonlocal::texthash (
                   'target'         => 'Display target',   
                   'window'         => 'Window',
                   'tab'            => 'Tab',
                   'iframe'         => 'iFrame',
                   'height'         => 'Height (pixels)',
                   'width'          => 'Width (pixels)',
                   'linktext'       => 'Default Link Text',
                   'explanation'    => 'Default Explanation',
                   'append'         => 'Provider URL',
           );
       }
   }
   
   sub proctoring_providernames {
       return (
                proctorio => 'Proctorio',
                examity   => 'Examity',
              );
   }
   
 sub print_lti {  sub print_lti {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my $itemcount = 1;      my $itemcount = 1;
     my ($datatable,$css_class);      my ($datatable,$css_class);
     my (%rules,%encrypt,%privkeys,%linkprot,%suggestions);      my (%rules,%encrypt,%privkeys,%linkprot);
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         if ($position eq 'top') {          if ($position eq 'top') {
             if (exists($settings->{'encrypt'})) {              if (exists($settings->{'encrypt'})) {
Line 5348  sub print_lti { Line 6166  sub print_lti {
                     }                      }
                 }                  }
             }              }
         } elsif ($position eq 'upper') {          } elsif ($position eq 'middle') {
             if (exists($settings->{'rules'})) {              if (exists($settings->{'rules'})) {
                 if (ref($settings->{'rules'}) eq 'HASH') {                  if (ref($settings->{'rules'}) eq 'HASH') {
                     %rules = %{$settings->{'rules'}};                      %rules = %{$settings->{'rules'}};
                 }                  }
             }              }
         } elsif ($position eq 'middle') {  
             if (exists($settings->{'suggested'})) {  
                 if (ref($settings->{'suggested'}) eq 'HASH') {  
                     %suggestions = %{$settings->{'suggested'}};  
                 }  
             }  
         } elsif ($position eq 'lower') {          } elsif ($position eq 'lower') {
             if (exists($settings->{'linkprot'})) {              if (exists($settings->{'linkprot'})) {
                 if (ref($settings->{'linkprot'}) eq 'HASH') {                  if (ref($settings->{'linkprot'}) eq 'HASH') {
Line 5370  sub print_lti { Line 6182  sub print_lti {
                 }                  }
             }              }
         } else {          } else {
             foreach my $key ('encrypt','private','rules','linkprot','suggestions') {              foreach my $key ('encrypt','private','rules','linkprot') {
                 if (exists($settings->{$key})) {                  if (exists($settings->{$key})) {
                     delete($settings->{$key});                      delete($settings->{$key});
                 }                  }
Line 5379  sub print_lti { Line 6191  sub print_lti {
     }      }
     if ($position eq 'top') {      if ($position eq 'top') {
         $datatable = &secrets_form($dom,'ltisec',\%encrypt,\%privkeys,$rowtotal);          $datatable = &secrets_form($dom,'ltisec',\%encrypt,\%privkeys,$rowtotal);
     } elsif ($position eq 'upper') {  
         $datatable = &password_rules('ltisecrets',\$itemcount,\%rules);  
         $$rowtotal += $itemcount;  
     } elsif ($position eq 'middle') {      } elsif ($position eq 'middle') {
         $datatable = &linkprot_suggestions(\%suggestions,\$itemcount);          $datatable = &password_rules('ltisecrets',\$itemcount,\%rules);
         $$rowtotal += $itemcount;          $$rowtotal += $itemcount;
     } elsif ($position eq 'lower') {      } elsif ($position eq 'lower') {
         $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');           $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');
     } else {      } else {
         my ($switchserver,$switchmessage);          my ($switchserver,$switchmessage);
         $switchserver = &check_switchserver($dom);          $switchserver = &check_switchserver($dom);
Line 5742  sub lti_options { Line 6551  sub lti_options {
         $checked{'menuitem'}{'grades'} = ' checked="checked"';          $checked{'menuitem'}{'grades'} = ' checked="checked"';
         $menusty = 'inline-block';          $menusty = 'inline-block';
     }      }
     my @coursetypes = ('official','unofficial','community','textbook','lti');      my @coursetypes = ('official','unofficial','community','textbook','placement','lti');
     my %coursetypetitles = &Apache::lonlocal::texthash (      my %coursetypetitles = &Apache::lonlocal::texthash (
                                official   => 'Official',                                 official   => 'Official',
                                unofficial => 'Unofficial',                                 unofficial => 'Unofficial',
                                community  => 'Community',                                 community  => 'Community',
                                textbook   => 'Textbook',                                 textbook   => 'Textbook',
                                  placement  => 'Placement Test',
                                lti        => 'LTI Provider',                                 lti        => 'LTI Provider',
     );      );
     my @authtypes = ('internal','krb4','krb5','localauth');      my @authtypes = ('internal','krb4','krb5','localauth');
Line 5972  sub ltimenu_titles { Line 6782  sub ltimenu_titles {
     );      );
 }  }
   
 sub linkprot_suggestions {  sub check_switchserver {
     my ($suggested,$itemcount) = @_;      my ($home) = @_;
     my $count = 0;      my $switchserver;
     my $next = 1;      if ($home ne '') {
     my %lt = &Apache::lonlocal::texthash(          my $allowed;
                                           'name' => 'Suggested Launcher',          my @ids=&Apache::lonnet::current_machine_ids();
                                           'info' => 'Recommendations',          foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
                                         );          if (!$allowed) {
     my ($datatable,$css_class,$dest);              $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&amp;role='.
     if (ref($suggested) eq 'HASH') {                            &HTML::Entities::encode($env{'request.role'},'\'<>"&').
         my @current = sort { $a <=> $b } keys(%{$suggested});                            '&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';
         $next += $current[-1];  
         for (my $i=0; $i<@current; $i++) {  
             my $num = $current[$i];  
             my %values;  
             if (ref($suggested->{$num}) eq 'HASH') {  
                 %values = %{$suggested->{$num}};  
             } else {  
                 next;  
             }  
             $css_class = $$itemcount%2?' class="LC_odd_row"':'';  
             $datatable .=  
                 '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".  
                 '<label><input type="checkbox" name="linkprot_suggested_del" value="'.$i.'" />'."\n".  
                 &mt('Delete?').'</label></span></td><td>'."\n".  
                 '<div class="LC_floatleft"><fieldset><legend>'.$lt{'name'}.'</legend>'."\n".  
                 '<input type="text" size="15" name="linkprot_suggested_name_'.$i.'" value="'.$values{'name'}.'" autocomplete="off" />'."\n".  
                 '</fieldset></div>'.  
                 '<div class="LC_floatleft"><fieldset><legend>'.$lt{'info'}.'</legend>'."\n".  
                 '<textarea cols="55" rows="5" name="linkprot_suggested_info_'.$i.'">'.$values{'info'}.'</textarea>'.  
                 '</fieldset></div>'.  
                 '<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n".  
                 '<input type="hidden" name="linkprot_suggested_id_'.$i.'" value="'.$num.'" /></td></tr>'."\n";  
             $$itemcount ++;  
         }          }
     }      }
     $css_class = $$itemcount%2?' class="LC_odd_row"':'';      return $switchserver;
     $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'."\n".  
                   '<input type="hidden" name="linkprot_suggested_maxnum" value="'.$next.'" />'."\n".  
                   '<input type="checkbox" name="linkprot_suggested_add" value="1" />'.&mt('Add').'</span></td>'."\n".  
                   '<td>'."\n".  
                   '<div class="LC_floatleft"><fieldset><legend>'.$lt{'name'}.'</legend>'."\n".  
                   '<input type="text" size="15" name="linkprot_suggested_name_add" value="" autocomplete="off" />'."\n".  
                   '</fieldset></div>'.  
                   '<div class="LC_floatleft"><fieldset><legend>'.$lt{'info'}.'</legend>'."\n".  
                   '<textarea cols="55" rows="5" name="linkprot_suggested_info_add"></textarea>'.  
                   '</fieldset></div>'.  
                   '<div style="padding:0;clear:both;margin:0;border:0"></div>'."\n".  
                   '</td></tr>'."\n";  
     return $datatable;  
 }  }
   
 sub print_coursedefaults {  sub print_coursedefaults {
Line 6029  sub print_coursedefaults { Line 6803  sub print_coursedefaults {
     my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles);      my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles);
     my $itemcount = 1;      my $itemcount = 1;
     my %choices =  &Apache::lonlocal::texthash (      my %choices =  &Apache::lonlocal::texthash (
           canuse_pdfforms      => 'Course/Community users can create/upload PDF forms',
         uploadquota          => 'Default quota for files uploaded directly to course/community using Course Editor (MB)',          uploadquota          => 'Default quota for files uploaded directly to course/community using Course Editor (MB)',
         coursequota          => 'Default cumulative quota for all group portfolio spaces in course (MB)',  
         anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',          anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',
         coursecredits        => 'Credits can be specified for courses',          coursecredits        => 'Credits can be specified for courses',
         uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',          uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',
Line 6047  sub print_coursedefaults { Line 6821  sub print_coursedefaults {
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            coursequota          => 20,  
                            postsubmit           => 60,                             postsubmit           => 60,
                            mysqltables          => 172800,                             mysqltables          => 172800,
                            domexttool           => 1,                             domexttool           => 1,
Line 6055  sub print_coursedefaults { Line 6828  sub print_coursedefaults {
                          );                           );
     if ($position eq 'top') {      if ($position eq 'top') {
         %defaultchecked = (          %defaultchecked = (
                               'canuse_pdfforms' => 'off',
                             'uselcmath'       => 'on',                              'uselcmath'       => 'on',
                             'usejsme'         => 'on',                              'usejsme'         => 'on',
                             'inline_chem'     => 'on',                              'inline_chem'     => 'on',
                             'canclone'        => 'none',                              'canclone'        => 'none',
                           );                            );
         @toggles = ('uselcmath','usejsme','inline_chem');          @toggles = ('canuse_pdfforms','uselcmath','usejsme','inline_chem');
         my $deftex = $Apache::lonnet::deftex;          my $deftex = $Apache::lonnet::deftex;
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'texengine'}) {              if ($settings->{'texengine'}) {
Line 6093  sub print_coursedefaults { Line 6867  sub print_coursedefaults {
         $datatable = $mathdisp.$datatable;          $datatable = $mathdisp.$datatable;
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $datatable .=          $datatable .=
             '<tr'.$css_class.'><td valign="top">'.              '<tr'.$css_class.'><td style="vertical-align: top">'.
             '<span class="LC_nobreak">'.$choices{'canclone'}.              '<span class="LC_nobreak">'.$choices{'canclone'}.
             '</span></td><td class="LC_left_item">';              '</span></td><td class="LC_left_item">';
         my $currcanclone = 'none';          my $currcanclone = 'none';
Line 6164  sub print_coursedefaults { Line 6938  sub print_coursedefaults {
         $itemcount ++;          $itemcount ++;
     } else {      } else {
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';          $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
         my ($currdefresponder,%defcredits,%curruploadquota,%currcoursequota,          my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout,%currmysql);
             %deftimeout,%currmysql);  
         my $currusecredits = 0;          my $currusecredits = 0;
         my $postsubmitclient = 1;          my $postsubmitclient = 1;
         my $ltiauth = 0;          my $ltiauth = 0;
         my %domexttool;          my %domexttool;
         my %exttool;          my %exttool;
         my @types = ('official','unofficial','community','textbook');          my @types = ('official','unofficial','community','textbook','placement');
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'ltiauth'}) {              if ($settings->{'ltiauth'}) {
                 $ltiauth = 1;                  $ltiauth = 1;
Line 6202  sub print_coursedefaults { Line 6975  sub print_coursedefaults {
                     $curruploadquota{$type} = $settings->{'uploadquota'}{$type};                      $curruploadquota{$type} = $settings->{'uploadquota'}{$type};
                 }                  }
             }              }
             if (ref($settings->{'coursequota'}) eq 'HASH') {  
                 foreach my $type (keys(%{$settings->{'coursequota'}})) {  
                     $currcoursequota{$type} = $settings->{'coursequota'}{$type};  
                 }  
             }  
             if (ref($settings->{'coursecredits'}) eq 'HASH') {              if (ref($settings->{'coursecredits'}) eq 'HASH') {
                 foreach my $type (@types) {                  foreach my $type (@types) {
                     next if ($type eq 'community');                      next if ($type eq 'community');
Line 6266  sub print_coursedefaults { Line 7034  sub print_coursedefaults {
             if ($curruploadquota{$type} eq '') {              if ($curruploadquota{$type} eq '') {
                 $curruploadquota{$type} = $staticdefaults{'uploadquota'};                  $curruploadquota{$type} = $staticdefaults{'uploadquota'};
             }              }
             if ($currcoursequota{$type} eq '') {  
                 $currcoursequota{$type} = $staticdefaults{'coursequota'};  
             }  
         }          }
         $datatable .=          $datatable .=
                 '<tr'.$css_class.'><td><span class="LC_nobreak">'.                  '<tr'.$css_class.'><td><span class="LC_nobreak">'.
Line 6283  sub print_coursedefaults { Line 7048  sub print_coursedefaults {
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.          $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                       $choices{'uploadquota'}.                        $choices{'uploadquota'}.
                       '</span></td>'.                        '</span></td>'.
                       '<td align="right" class="LC_right_item">'.  
                       '<table><tr>';  
         foreach my $type (@types) {  
             $datatable .= '<td align="center">'.&mt($type).'<br />'.  
                            '<input type="text" name="uploadquota_'.$type.'"'.  
                            ' value="'.$curruploadquota{$type}.'" size="5" /></td>';  
         }  
         $datatable .= '</tr></table></td></tr>'."\n";  
         $itemcount ++;  
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.  
                       $choices{'coursequota'}.  
                       '</span></td>'.  
                       '<td style="text-align: right" class="LC_right_item">'.                        '<td style="text-align: right" class="LC_right_item">'.
                       '<table><tr>';                        '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.              $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="coursequota_'.$type.'"'.                             '<input type="text" name="uploadquota_'.$type.'"'.
                            ' value="'.$currcoursequota{$type}.'" size="5" /></td>';                             ' value="'.$curruploadquota{$type}.'" size="5" /></td>';
         }          }
         $datatable .= '</tr></table></td></tr>'."\n";          $datatable .= '</tr></table></td></tr>'."\n";
         $itemcount ++;          $itemcount ++;
Line 6314  sub print_coursedefaults { Line 7066  sub print_coursedefaults {
                          '<i>'.&mt('Default credits').'</i><br /><table><tr>';                           '<i>'.&mt('Default credits').'</i><br /><table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             next if ($type eq 'community');              next if ($type eq 'community');
             $additional .= '<td align="center">'.&mt($type).'<br />'.              $additional .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="'.$type.'_credits"'.                             '<input type="text" name="'.$type.'_credits"'.
                            ' value="'.$defcredits{$type}.'" size="3" /></td>';                             ' value="'.$defcredits{$type}.'" size="3" /></td>';
         }          }
Line 6338  sub print_coursedefaults { Line 7090  sub print_coursedefaults {
                       '<i>'.&mt('Enter 0 to remain disabled until page reload.').'</i><br />'.                        '<i>'.&mt('Enter 0 to remain disabled until page reload.').'</i><br />'.
                       '<table><tr>';                        '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $additional .= '<td align="center">'.&mt($type).'<br />'.              $additional .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="'.$type.'_timeout" value="'.                             '<input type="text" name="'.$type.'_timeout" value="'.
                            $deftimeout{$type}.'" size="5" /></td>';                             $deftimeout{$type}.'" size="5" /></td>';
         }          }
Line 6356  sub print_coursedefaults { Line 7108  sub print_coursedefaults {
         $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.          $datatable .= '<tr'.$css_class.'><td><span class="LC_nobreak">'.
                       $choices{'mysqltables'}.                        $choices{'mysqltables'}.
                       '</span></td>'.                        '</span></td>'.
                       '<td align="right" class="LC_right_item">'.                        '<td style="text-align: right" class="LC_right_item">'.
                       '<table><tr>';                        '<table><tr>';
         foreach my $type (@types) {          foreach my $type (@types) {
             $datatable .= '<td align="center">'.&mt($type).'<br />'.              $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
                            '<input type="text" name="mysqltables_'.$type.'"'.                             '<input type="text" name="mysqltables_'.$type.'"'.
                            ' value="'.$currmysql{$type}.'" size="8" /></td>';                             ' value="'.$currmysql{$type}.'" size="8" /></td>';
         }          }
Line 6408  sub print_coursedefaults { Line 7160  sub print_coursedefaults {
     return $datatable;      return $datatable;
 }  }
   
 sub print_authordefaults {  
     my ($position,$dom,$settings,$rowtotal) = @_;  
     my ($css_class,$datatable,%checkedon,%checkedoff);  
     my $itemcount = 1;  
     my %titles = &authordefaults_titles();  
     if ($position eq 'top') {  
         my %defaultchecked = (  
                             'nocodemirror' => 'off',  
                             'daxecollapse' => 'off',  
                             'domcoordacc'  => 'on',  
                           );  
         my @toggles = ('nocodemirror','daxecollapse','domcoordacc');  
         ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked,  
                                                      \%titles,$itemcount);  
         my %staticdefaults = (  
                                 'copyright'    => 'default',  
                                 'sourceavail'  => 'closed',  
                              );  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my %currrights;  
         foreach my $item ('copyright','sourceavail') {  
             $currrights{$item} = $staticdefaults{$item};  
             if (ref($settings) eq 'HASH') {  
                 if (exists($settings->{$item})) {  
                     $currrights{$item} = $settings->{$item};  
                 }  
             }  
         }  
         $datatable .= '<tr'.$css_class.'><td style="vertical-align: top">'.  
                       '<span class="LC_nobreak">'.$titles{'copyright'}.  
                       '</span></td><td class="LC_right_item">'.  
                       &selectbox('copyright',$currrights{'copyright'},'',  
                                  \&Apache::loncommon::copyrightdescription,  
                                  (grep !/^priv|custom$/,(&Apache::loncommon::copyrightids))).  
                       '</td></tr>'."\n";  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'><td style="vertical-align: top">'.  
                       '<span class="LC_nobreak">'.$titles{'sourceavail'}.  
                       '</span></td><td class="LC_right_item">'.  
                       &selectbox('sourceavail',$currrights{'sourceavail'},'',  
                                  \&Apache::loncommon::source_copyrightdescription,  
                                  (&Apache::loncommon::source_copyrightids)).  
                       '</td></tr>'."\n";  
     } else {  
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';  
         my $curreditors;  
         my %staticdefaults = (  
                                 editors => ['edit','xml'],  
                                 authorquota => 500,  
                                 webdav => 0,  
                              );  
         my $curreditors = $staticdefaults{'editors'};  
         if ((ref($settings) eq 'HASH') &&  
             (ref($settings->{'editors'}) eq 'ARRAY')) {  
             $curreditors = $settings->{'editors'};  
         } else {  
             $curreditors = $staticdefaults{'editors'};  
         }  
         my @editors = ('edit','xml','daxe');  
         $datatable = '<tr'.$css_class.'>'."\n".  
                      '<td>'.$titles{'editors'}.'</td>'."\n".  
                      '<td class="LC_left_item">'."\n".  
                      '<span class="LC_nobreak">';  
         foreach my $editor (@editors) {  
             my $checked;  
             if (grep(/^\Q$editor\E$/,@{$curreditors})) {  
                 $checked = ' checked="checked"';  
             }  
             $datatable .= '<label>'.  
                           '<input type="checkbox" name="author_editors" '.  
                           $checked.' value="'.$editor.'" '.  
                           'onclick="javascript:checkEditors(this.form,'."'author_editors'".',this);" />'.  
                           $titles{$editor}.'</label>&nbsp;';  
         }  
         $datatable .= '</span>'."\n".'</td>'."\n".'</tr>'."\n";  
         $itemcount ++;  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
         my @insttypes;  
         if (ref($types) eq 'ARRAY') {  
             @insttypes = @{$types};  
         }  
         my $typecount = 0;  
         my %domconf = &Apache::lonnet::get_dom('configuration',['quotas'],$dom);  
         my @items = ('webdav','authorquota');  
         my %quotas;  
         if (ref($domconf{'quotas'}) eq 'HASH') {  
             %quotas = %{$domconf{'quotas'}};  
             foreach my $item (@items) {  
                 if (ref($quotas{$item}) eq 'HASH') {  
                     foreach my $type (@insttypes,'default') {  
                         if ($item eq 'authorquota') {  
                             if ($quotas{$item}{$type} !~ /^\d+$/) {  
                                 $quotas{$item}{$type} = $staticdefaults{$item};  
                             }  
                         } elsif ($item eq 'webdav') {  
                             if ($quotas{$item}{$type} !~ /^(0|1)$/) {  
                                 $quotas{$item}{$type} = $staticdefaults{$item};  
                             }  
                         }  
                     }  
                 } else {  
                     foreach my $type (@insttypes,'default') {  
                         $quotas{$item}{$type} = $staticdefaults{$item};  
                     }  
                 }  
             }  
         } else {  
             foreach my $item (@items) {  
                 foreach my $type (@insttypes,'default') {  
                     $quotas{$item}{$type} = $staticdefaults{$item};  
                 }  
             }  
         }  
         if (ref($usertypes) eq 'HASH') {  
             my $numinrow = 4;  
             my $onclick = '';  
             $datatable .= &insttypes_row(\%quotas,$types,$usertypes,$dom,  
                                          $numinrow,$othertitle,'authorquota',  
                                          \$itemcount,$onclick);  
             $itemcount ++;  
             $datatable .= &insttypes_row(\%quotas,$types,$usertypes,$dom,  
                                          $numinrow,$othertitle,'webdav',  
                                          \$itemcount);  
             $itemcount ++;  
         }  
         my $checkedno = ' checked="checked"';  
         my ($checkedon,$checkedoff);  
         if (ref($quotas{'webdav'}) eq 'HASH') {  
             if ($quotas{'webdav'}{'_LC_adv'} =~ /^0|1$/) {  
                 if ($quotas{'webdav'}{'_LC_adv'}) {  
                     $checkedon = $checkedno;  
                 } else {  
                     $checkedoff = $checkedno;  
                 }  
                 undef($checkedno);  
             }  
         }  
         $css_class = $itemcount%2?' class="LC_odd_row"':'';  
         $datatable .= '<tr'.$css_class.'>'.  
                       '<td>'.$titles{'webdav_LC_adv'}.'<br />'.  
                              $titles{'webdav_LC_adv_over'}.  
                       '</td>'.  
                       '<td class="LC_left_item">';  
         foreach my $option ('none','off','on') {  
             my ($text,$val,$checked);  
             if ($option eq 'none') {  
                 $text = $titles{'none'};  
                 $val = '';  
                 $checked = $checkedno;  
             } elsif ($option eq 'off') {  
                 $text = $titles{'overoff'};  
                 $val = 0;  
                 $checked = $checkedoff;  
             } elsif ($option eq 'on') {  
                 $text = $titles{'overon'};  
                 $val = 1;  
                 $checked = $checkedon;  
             }  
             $datatable .= '<span class="LC_nobreak"><label>'.  
                           '<input type="radio" name="webdav_LC_adv"'.  
                           ' value="'.$val.'"'.$checked.' />'.  
                           $text.'</label></span>&nbsp; ';  
         }  
         $datatable .= '</td></tr>';  
         $itemcount ++;  
     }  
     $$rowtotal += $itemcount;  
     return $datatable;  
 }  
   
 sub authordefaults_titles {  
     return &Apache::lonlocal::texthash(  
                copyright => 'Copyright/Distribution',  
                sourceavail => ' Source Available',  
                editors => 'Available Editors',  
                webdav => 'WebDAV',  
                authorquota => 'Authoring Space quotas (MB)',  
                nocodemirror => 'Deactivate CodeMirror for EditXML editor',  
                daxecollapse => 'Daxe editor: LON-CAPA standard menus start collapsed',  
                domcoordacc => 'Dom. Coords. can enter Authoring Spaces in domain',  
                edit  => 'Standard editor (Edit)',  
                xml   => 'Text editor (EditXML)',  
                daxe  => 'Daxe editor (Daxe)',  
                webdav_LC_adv => 'WebDAV access for LON-CAPA "advanced" users',  
                webdav_LC_adv_over => '(overrides access based on affiliation, if set)',  
                none => 'No override set',  
                overon => 'Override -- webDAV on',  
                overoff => 'Override -- webDAV off',  
     );  
 }  
   
 sub selectbox {  
     my ($name,$value,$readonly,$functionref,@idlist)=@_;  
     my $selout = '<select name="'.$name.'">';  
     foreach my $id (@idlist) {  
         $selout.='<option value="'.$id.'"';  
         if ($id eq $value) {  
             $selout.=' selected="selected"';  
         }  
         if ($readonly) {  
             $selout .= ' disabled="disabled"';  
         }  
         $selout.='>'.&{$functionref}($id).'</option>';  
     }  
     $selout.='</select>';  
     return $selout;  
 }  
   
 sub print_selfenrollment {  sub print_selfenrollment {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable);      my ($css_class,$datatable);
     my $itemcount = 1;      my $itemcount = 1;
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     if (($position eq 'top') || ($position eq 'middle')) {      if (($position eq 'top') || ($position eq 'middle')) {
         my ($rowsref,$titlesref) = &Apache::lonuserutils::get_selfenroll_titles();          my ($rowsref,$titlesref) = &Apache::lonuserutils::get_selfenroll_titles();
         my %descs = &Apache::lonuserutils::selfenroll_default_descs();          my %descs = &Apache::lonuserutils::selfenroll_default_descs();
Line 6843  sub print_validation_rows { Line 7385  sub print_validation_rows {
     return $datatable;      return $datatable;
 }  }
   
   sub print_privacy {
       my ($position,$dom,$settings,$rowtotal) = @_;
       my ($datatable,$css_class,$numinrow,@items,%names,$othertitle,$usertypes,$types);
       my $itemcount = 0;
       if ($position eq 'top') {
           $numinrow = 2;
       } else {
           @items = ('domain','author','course','community');
           %names = &Apache::lonlocal::texthash (
                        domain => 'Assigned domain role(s)',
                        author => 'Assigned co-author role(s)',
                        course => 'Assigned course role(s)',
                        community => 'Assigned community role(s)',
                    );
           $numinrow = 4;
           ($othertitle,$usertypes,$types) =
               &Apache::loncommon::sorted_inst_types($dom);
       }
       if (($position eq 'top') || ($position eq 'middle')) {
           my (%by_ip,%by_location,@intdoms,@instdoms);
           &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
           if ($position eq 'top') {
               my %curr;
               my @options = ('none','user','domain','auto');
               my %titles = &Apache::lonlocal::texthash (
                   none   => 'Not allowed',
                   user   => 'User authorizes',
                   domain => 'DC authorizes',
                   auto   => 'Unrestricted',
                   instdom => 'Other domain shares institution/provider',
                   extdom => 'Other domain has different institution/provider',
                   notify => 'Notify when role needs authorization',
               );
               my %names = &Apache::lonlocal::texthash (
                   domain => 'Domain role',
                   author => 'Co-author role',
                   course => 'Course role',
                   community => 'Community role',
               );
               my $primary_id = &Apache::lonnet::domain($dom,'primary');
               my $intdom = &Apache::lonnet::internet_dom($primary_id);
               foreach my $domtype ('instdom','extdom') {
                   my (%checked,$skip);
                   $css_class = $itemcount%2?' class="LC_odd_row"':'';
                   $datatable .= '<tr'.$css_class.'><td>'.$titles{$domtype}.'</td>'.
                                 '<td class="LC_left_item">';
                   if ($domtype eq 'instdom') {
                       unless (@instdoms > 1) {
                           $datatable .= &mt('Nothing to set, as no domains besides [_1] are hosted by [_2]',$dom,$intdom);
                           $skip = 1;
                       }
                   } elsif ($domtype eq 'extdom') {
                       if (keys(%by_location) == 0) {
                           $datatable .= &mt('Nothing to set, as no other hosts besides [_1]',$intdom);
                           $skip = 1;
                       }
                   }
                   unless ($skip) {
                       foreach my $roletype ('domain','author','course','community') {
                           $checked{'auto'} = ' checked="checked"';
                           if (ref($settings) eq 'HASH') {
                               if (ref($settings->{approval}) eq 'HASH') {
                                   if (ref($settings->{approval}->{$domtype}) eq 'HASH') {
                                       if ($settings->{approval}->{$domtype}->{$roletype}=~ /^(none|user|domain)$/) {
                                           $checked{$1} = ' checked="checked"';
                                           $checked{'auto'} = '';
                                       }
                                   }
                               }
                           }
                           $datatable .= '<fieldset><legend>'.$names{$roletype}.'</legend>';
                           foreach my $option (@options) {
                               $datatable .= '<span class="LC_nobreak"><label>'.
                                             '<input type="radio" name="privacy_approval_'.$domtype.'_'.$roletype.'" '.
                                             'value="'.$option.'"'.$checked{$option}.' />'.$titles{$option}.
                                             '</label></span>&nbsp; ';
                           }
                           $datatable .= '</fieldset>';
                       }
                   }
                   $datatable .= '</td></tr>';
                   $itemcount ++;
               }
               $css_class = $itemcount%2?' class="LC_odd_row"':'';
               $datatable .= '<tr'.$css_class.'><td>'.$titles{'notify'}.'</td>'.
                             '<td class="LC_left_item">';
               if ((@instdoms > 1) || (keys(%by_location) > 0)) {
                   my %curr;
                   if (ref($settings) eq 'HASH') {
                       if ($settings->{'notify'} ne '') {
                           map {$curr{$_}=1;} split(/,/,$settings->{'notify'});
                       }
                   }
                   $css_class = $itemcount%2?' class="LC_odd_row"':'';
                   my ($numdc,$table,$rows) = &active_dc_picker($dom,$numinrow,'checkbox',
                                                                'privacy_notify',%curr);
                   if ($numdc > 0) {
                       $datatable .= $table;
                   } else {
                       $datatable .= &mt('There are no active Domain Coordinators');
                   }
               } else {
                   $datatable .= &mt('Nothing to set here, as there are no other domains');
               }
               $datatable .='</td></tr>';
           } elsif ($position eq 'middle') {
               if ((@instdoms > 1) || (keys(%by_location) > 0)) {
                   if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
                       foreach my $item (@{$types}) {
                           $datatable .= &modifiable_userdata_row('privacy','othdom_'.$item,$settings,
                                                                  $numinrow,$itemcount,'','','','','',
                                                                  '',$usertypes->{$item});
                           $itemcount ++;
                       }
                   }
                   $datatable .= &modifiable_userdata_row('privacy','othdom_default',$settings,
                                                          $numinrow,$itemcount,'','','','','',
                                                          '',$othertitle);
                   $itemcount ++;
               } else {
                   my (@insttypes,%insttitles);
                   if ((ref($types) eq 'ARRAY') && (ref($usertypes) eq 'HASH')) {
                       @insttypes = @{$types};
                       %insttitles = %{$usertypes};
                   }
                   foreach my $item (@insttypes,'default') {
                       my $title;
                       if ($item eq 'default') {
                           $title = $othertitle;
                       } else {
                           $title = $insttitles{$item};
                       }
                       $css_class = $itemcount%2?' class="LC_odd_row"':'';
                       $datatable .= '<tr'.$css_class.'>'.
                                     '<td class="LC_left_item">'.$title.'</td>'.
                                     '<td class="LC_left_item">'.
                                     &mt('Nothing to set here, as there are no other domains').
                                     '</td></tr>';
                       $itemcount ++;
                   }
               }
           }
       } else {
           my $prefix;
           if ($position eq 'lower') {
               $prefix = 'priv';
           } else {
               $prefix = 'unpriv';
           }
           foreach my $item (@items) {
               $datatable .= &modifiable_userdata_row('privacy',$prefix.'_'.$item,$settings,
                                                      $numinrow,$itemcount,'','','','','',
                                                      '',$names{$item});
               $itemcount ++;
           }
       }
       if (ref($rowtotal)) {
           $$rowtotal += $itemcount;
       }
       return $datatable;
   }
   
 sub print_passwords {  sub print_passwords {
     my ($position,$dom,$confname,$settings,$rowtotal) = @_;      my ($position,$dom,$confname,$settings,$rowtotal) = @_;
     my ($datatable,$css_class);      my ($datatable,$css_class);
Line 6864  sub print_passwords { Line 7568  sub print_passwords {
         min            => 'Minimum password length',          min            => 'Minimum password length',
         max            => 'Maximum password length',          max            => 'Maximum password length',
         chars          => 'Required characters',          chars          => 'Required characters',
           expire         => 'Password expiration (days)',
         numsaved       => 'Number of previous passwords to save and disallow reuse',          numsaved       => 'Number of previous passwords to save and disallow reuse',
     );      );
     if ($position eq 'top') {      if ($position eq 'top') {
Line 7153  sub print_passwords { Line 7858  sub print_passwords {
         $datatable .= '<tr '.$css_class.'>'.          $datatable .= '<tr '.$css_class.'>'.
                       '<td>'.                        '<td>'.
                       &mt('Requirements').'<ul>'.                        &mt('Requirements').'<ul>'.
                       '<li>'.&mt("Course 'type' is not a Community").'</li>'.                        '<li>'.&mt("Course 'type' is not a Community or Placement Test").'</li>'.
                       '<li>'.&mt('User is Course Coordinator and also course owner').'</li>'.                        '<li>'.&mt('User is Course Coordinator and also course owner').'</li>'.
                       '<li>'.&mt("Student's only active roles are student role(s) in course(s) owned by this user").'</li>'.                        '<li>'.&mt("Student's only active roles are student role(s) in course(s) owned by this user").'</li>'.
                       '<li>'.&mt('User, course, and student share same domain').'</li>'.                        '<li>'.&mt('User, course, and student share same domain').'</li>'.
Line 7190  sub print_passwords { Line 7895  sub print_passwords {
   
 sub password_rules {  sub password_rules {
     my ($prefix,$itemcountref,$settings) = @_;      my ($prefix,$itemcountref,$settings) = @_;
     my ($min,$max,%chars,$numsaved,$numinrow);      my ($min,$max,%chars,$expire,$numsaved,$numinrow);
     my %titles;      my %titles;
     if ($prefix eq 'passwords') {      if ($prefix eq 'passwords') {
         %titles = &Apache::lonlocal::texthash (          %titles = &Apache::lonlocal::texthash (
Line 7222  sub password_rules { Line 7927  sub password_rules {
             map { $chars{$_} = 1; } (@{$settings->{chars}});              map { $chars{$_} = 1; } (@{$settings->{chars}});
         }          }
         if ($prefix eq 'passwords') {          if ($prefix eq 'passwords') {
               if ($settings->{expire}) {
                   $expire = $settings->{expire};
               }
             if ($settings->{numsaved}) {              if ($settings->{numsaved}) {
                 $numsaved = $settings->{numsaved};                  $numsaved = $settings->{numsaved};
             }              }
Line 7283  sub password_rules { Line 7991  sub password_rules {
     $datatable .='</table></td></tr>';      $datatable .='</table></td></tr>';
     $itemcount ++;      $itemcount ++;
     if ($prefix eq 'passwords') {      if ($prefix eq 'passwords') {
           $titles{'expire'} = &mt('Password expiration (days)');
         $titles{'numsaved'} = &mt('Number of previous passwords to save and disallow reuse');          $titles{'numsaved'} = &mt('Number of previous passwords to save and disallow reuse');
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable .= '<tr'.$css_class.'><td>'.$titles{'expire'}.'</td>'.
                         '<td class="LC_left_item"><span class="LC_nobreak">'.
                         '<input type="text" name="'.$prefix.'_expire" value="'.$expire.'" size="4" '.
                         'onblur="javascript:warnInt'.$prefix.'(this);" />'.
                         '<span class="LC_fontsize_small"> '.&mt('(Leave blank for no expiration)').'</span>'.
                         '</span></td></tr>';
           $itemcount ++;
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.          $datatable .= '<tr'.$css_class.'><td>'.$titles{'numsaved'}.'</td>'.
                       '<td class="LC_left_item"><span class="LC_nobreak">'.                        '<td class="LC_left_item"><span class="LC_nobreak">'.
                       '<input type="text" name="'.$prefix.'_numsaved" value="'.$numsaved.'" size="3" '.                        '<input type="text" name="'.$prefix.'_numsaved" value="'.$numsaved.'" size="3" '.
Line 7369  sub print_wafproxy { Line 8086  sub print_wafproxy {
             my $dom_in_effect;              my $dom_in_effect;
             my $aliasrows = '<tr>'.              my $aliasrows = '<tr>'.
                             '<td class="LC_left_item" style="vertical-align: baseline;">'.                              '<td class="LC_left_item" style="vertical-align: baseline;">'.
                             &mt('Hostname').': '.                              &mt('Hostname').':&nbsp;'.
                             '<span class="LC_nobreak LC_cusr_emph">'.                              '<i>'.&Apache::lonnet::hostname($server).'</i></td><td>&nbsp;</td>';
                             &Apache::lonnet::hostname($server).'</span></td><td>&nbsp;</td>';  
             if ($othercontrol{$server}) {              if ($othercontrol{$server}) {
                 $dom_in_effect = $othercontrol{$server};                  $dom_in_effect = $othercontrol{$server};
                 my ($current,$forsaml);                  my ($current,$forsaml);
Line 7609  sub remoteip_methods { Line 8325  sub remoteip_methods {
   
 sub print_usersessions {  sub print_usersessions {
     my ($position,$dom,$settings,$rowtotal) = @_;      my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,%checked,%choices);      my ($css_class,$datatable,$itemcount,%checked,%choices);
     my (%by_ip,%by_location,@intdoms);      my (%by_ip,%by_location,@intdoms,@instdoms);
     &build_location_hashes(\@intdoms,\%by_ip,\%by_location);      &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
   
     my @alldoms = &Apache::lonnet::all_domains();      my @alldoms = &Apache::lonnet::all_domains();
     my %serverhomes = %Apache::lonnet::serverhomeIDs;      my %serverhomes = %Apache::lonnet::serverhomeIDs;
     my %servers = &Apache::lonnet::internet_dom_servers($dom);      my %servers = &Apache::lonnet::internet_dom_servers($dom);
     my %altids = &id_for_thisdom(%servers);      my %altids = &id_for_thisdom(%servers);
     my $itemcount = 1;  
     if ($position eq 'top') {      if ($position eq 'top') {
         if (keys(%serverhomes) > 1) {          if (keys(%serverhomes) > 1) {
             my %spareid = &current_offloads_to($dom,$settings,\%servers);              my %spareid = &current_offloads_to($dom,$settings,\%servers);
Line 7639  sub print_usersessions { Line 8354  sub print_usersessions {
                           '</td></tr>';                            '</td></tr>';
         }          }
     } else {      } else {
         if (keys(%by_location) == 0) {          my %titles = &usersession_titles();
             $datatable .= '<tr'.$css_class.'><td colspan="2">'.          my ($prefix,@types);
                           &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.').          if ($position eq 'bottom') {
                           '</td></tr>';              $prefix = 'remote';
               @types = ('version','excludedomain','includedomain');
         } else {          } else {
             my %lt = &usersession_titles();              $prefix = 'hosted';
             my $numinrow = 5;              @types = ('excludedomain','includedomain');
             my $prefix;          }
             my @types;          ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
             if ($position eq 'bottom') {      }
                 $prefix = 'remote';      $$rowtotal += $itemcount;
                 @types = ('version','excludedomain','includedomain');      return $datatable;
             } else {  }
                 $prefix = 'hosted';  
                 @types = ('excludedomain','includedomain');  sub rules_by_location {
             }      my ($settings,$prefix,$by_location,$by_ip,$types,$titles) = @_; 
             my (%current,%checkedon,%checkedoff);      my ($datatable,$itemcount,$css_class);
             my @lcversions = &Apache::lonnet::all_loncaparevs();      if (keys(%{$by_location}) == 0) {
             my @locations = sort(keys(%by_location));          $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
             foreach my $type (@types) {          $datatable = '<tr'.$css_class.'><td colspan="2">'.
                 $checkedon{$type} = '';                       &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.').
                 $checkedoff{$type} = ' checked="checked"';                       '</td></tr>';
             }          $itemcount = 1;
             if (ref($settings) eq 'HASH') {      } else {
                 if (ref($settings->{$prefix}) eq 'HASH') {          $itemcount = 0;
                     foreach my $key (keys(%{$settings->{$prefix}})) {          my $numinrow = 5;
                         $current{$key} = $settings->{$prefix}{$key};          my (%current,%checkedon,%checkedoff);
                         if ($key eq 'version') {          my @locations = sort(keys(%{$by_location}));
                             if ($current{$key} ne '') {          foreach my $type (@{$types}) {
                                 $checkedon{$key} = ' checked="checked"';              $checkedon{$type} = '';
                                 $checkedoff{$key} = '';              $checkedoff{$type} = ' checked="checked"';
                             }          }
                         } elsif (ref($current{$key}) eq 'ARRAY') {          if (ref($settings) eq 'HASH') {
               if (ref($settings->{$prefix}) eq 'HASH') {
                   foreach my $key (keys(%{$settings->{$prefix}})) {
                       $current{$key} = $settings->{$prefix}{$key};
                       if ($key eq 'version') {
                           if ($current{$key} ne '') {
                             $checkedon{$key} = ' checked="checked"';                              $checkedon{$key} = ' checked="checked"';
                             $checkedoff{$key} = '';                              $checkedoff{$key} = '';
                         }                          }
                       } elsif (ref($current{$key}) eq 'ARRAY') {
                           $checkedon{$key} = ' checked="checked"';
                           $checkedoff{$key} = '';
                     }                      }
                 }                  }
             }              }
             foreach my $type (@types) {          }
                 next if ($type ne 'version' && !@locations);          foreach my $type (@{$types}) {
                 $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';              next if ($type ne 'version' && !@locations);
                 $datatable .= '<tr'.$css_class.'>              $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
                                <td><span class="LC_nobreak">'.$lt{$type}.'</span><br />              $datatable .= '<tr'.$css_class.'>
                                <span class="LC_nobreak">&nbsp;                             <td><span class="LC_nobreak">'.$titles->{$type}.'</span><br />
                                <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>&nbsp;                             <span class="LC_nobreak">&nbsp;
                                <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';                             <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedoff{$type}.' value="0" />'.&mt('Not in use').'</label>&nbsp;
                 if ($type eq 'version') {                             <label><input type="radio" name="'.$prefix.'_'.$type.'_inuse" '.$checkedon{$type}.' value="1" />'.&mt('In use').'</label></span></td><td>';
                     my $selector = '<select name="'.$prefix.'_version">';              if ($type eq 'version') {
                     foreach my $version (@lcversions) {                  my @lcversions = &Apache::lonnet::all_loncaparevs();
                         my $selected = '';                  my $selector = '<select name="'.$prefix.'_version">';
                         if ($current{'version'} eq $version) {                  foreach my $version (@lcversions) {
                             $selected = ' selected="selected"';                      my $selected = '';
                         }                      if ($current{'version'} eq $version) {
                         $selector .= ' <option value="'.$version.'"'.                          $selected = ' selected="selected"';
                                      $selected.'>'.$version.'</option>';                      }
                     }                      $selector .= ' <option value="'.$version.'"'.
                     $selector .= '</select> ';                                   $selected.'>'.$version.'</option>';
                     $datatable .= &mt('remote server must be version: [_1] or later',$selector);                  }
                 } else {                  $selector .= '</select> ';
                     $datatable.= '<div><input type="button" value="'.&mt('check all').'" '.                  $datatable .= &mt('remote server must be version: [_1] or later',$selector);
                                  'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.              } else {
                                  ' />'.('&nbsp;'x2).                  $datatable.= '<div><input type="button" value="'.&mt('check all').'" '.
                                  '<input type="button" value="'.&mt('uncheck all').'" '.                               'onclick="javascript:checkAll(document.display.'.$prefix.'_'.$type.')"'.
                                  'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.                               ' />'.('&nbsp;'x2).
                                  "\n".                               '<input type="button" value="'.&mt('uncheck all').'" '.
                                  '</div><div><table>';                               'onclick="javascript:uncheckAll(document.display.'.$prefix.'_'.$type.')" />'.
                     my $rem;                               "\n".
                     for (my $i=0; $i<@locations; $i++) {                               '</div><div><table>';
                         my ($showloc,$value,$checkedtype);                  my $rem;
                         if (ref($by_location{$locations[$i]}) eq 'ARRAY') {                  for (my $i=0; $i<@locations; $i++) {
                             my $ip = $by_location{$locations[$i]}->[0];                      my ($showloc,$value,$checkedtype);
                             if (ref($by_ip{$ip}) eq 'ARRAY') {                      if (ref($by_location->{$locations[$i]}) eq 'ARRAY') {
                                  $value = join(':',@{$by_ip{$ip}});                          my $ip = $by_location->{$locations[$i]}->[0];
                                 $showloc = join(', ',@{$by_ip{$ip}});                          if (ref($by_ip->{$ip}) eq 'ARRAY') {
                                 if (ref($current{$type}) eq 'ARRAY') {                              $value = join(':',@{$by_ip->{$ip}});
                                     foreach my $loc (@{$by_ip{$ip}}) {                                $showloc = join(', ',@{$by_ip->{$ip}});
                                         if (grep(/^\Q$loc\E$/,@{$current{$type}})) {                              if (ref($current{$type}) eq 'ARRAY') {
                                             $checkedtype = ' checked="checked"';                                  foreach my $loc (@{$by_ip->{$ip}}) {
                                             last;                                      if (grep(/^\Q$loc\E$/,@{$current{$type}})) {
                                         }                                          $checkedtype = ' checked="checked"';
                                           last;
                                     }                                      }
                                 }                                  }
                             }                              }
                         }                          }
                         $rem = $i%($numinrow);  
                         if ($rem == 0) {  
                             if ($i > 0) {  
                                 $datatable .= '</tr>';  
                             }  
                             $datatable .= '<tr>';  
                         }  
                         $datatable .= '<td class="LC_left_item">'.  
                                       '<span class="LC_nobreak"><label>'.  
                                       '<input type="checkbox" name="'.$prefix.'_'.$type.  
                                       '" value="'.$value.'"'.$checkedtype.' />'.$showloc.  
                                       '</label></span></td>';  
                     }                      }
                     $rem = @locations%($numinrow);                      $rem = $i%($numinrow);
                     my $colsleft = $numinrow - $rem;                      if ($rem == 0) {
                     if ($colsleft > 1 ) {                          if ($i > 0) {
                         $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.                              $datatable .= '</tr>';
                                       '&nbsp;</td>';                          }
                     } elsif ($colsleft == 1) {                          $datatable .= '<tr>';
                         $datatable .= '<td class="LC_left_item">&nbsp;</td>';                      }
                       $datatable .= '<td class="LC_left_item">'.
                                     '<span class="LC_nobreak"><label>'.
                                     '<input type="checkbox" name="'.$prefix.'_'.$type.
                                     '" value="'.$value.'"'.$checkedtype.' />'.$showloc.
                                     '</label></span></td>';
                   }
                   $rem = @locations%($numinrow);
                   my $colsleft = $numinrow - $rem;
                   if ($colsleft > 1 ) {
                       $datatable .= '<td colspan="'.$colsleft.'" class="LC_left_item">'.
                                     '&nbsp;</td>';
                   } elsif ($colsleft == 1) {
                       $datatable .= '<td class="LC_left_item">&nbsp;</td>';
                   }
                   $datatable .= '</tr></table>';
               }
               $datatable .= '</td></tr>';
               $itemcount ++;
           }
       }
       return ($datatable,$itemcount);
   }
   
   sub print_ssl {
       my ($position,$dom,$settings,$rowtotal) = @_;
       my ($css_class,$datatable);
       my $itemcount = 1;
       if ($position eq 'top') {
           my $primary_id = &Apache::lonnet::domain($dom,'primary');
           my $intdom = &Apache::lonnet::internet_dom($primary_id);
           my $same_institution;
           if ($intdom ne '') {
               my $internet_names = &Apache::lonnet::get_internet_names($Apache::lonnet::perlvar{'lonHostID'});
               if (ref($internet_names) eq 'ARRAY') {
                   if (grep(/^\Q$intdom\E$/,@{$internet_names})) {
                       $same_institution = 1;
                   }
               }
           }
           $css_class = $itemcount%2?' class="LC_odd_row"':'';
           $datatable = '<tr'.$css_class.'><td colspan="2">';
           if ($same_institution) {
               my %domservers = &Apache::lonnet::get_servers($dom);
               $datatable .= &LONCAPA::SSL::print_certstatus(\%domservers,'web','domprefs');
           } else {
               $datatable .= &mt("You need to be logged into one of your own domain's servers to display information about the status of LON-CAPA SSL certificates.");
           }
           $datatable .= '</td></tr>';
           $itemcount ++;
       } else {
           my %titles = &ssl_titles();
           my (%by_ip,%by_location,@intdoms,@instdoms);
           &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
           my @alldoms = &Apache::lonnet::all_domains();
           my %serverhomes = %Apache::lonnet::serverhomeIDs;
           my @domservers = &Apache::lonnet::get_servers($dom);
           my %servers = &Apache::lonnet::internet_dom_servers($dom);
           my %altids = &id_for_thisdom(%servers);
           if (($position eq 'connto') || ($position eq 'connfrom')) {
               my $legacy;
               unless (ref($settings) eq 'HASH') {
                   my $name;
                   if ($position eq 'connto') {
                       $name = 'loncAllowInsecure';
                   } else {
                       $name = 'londAllowInsecure';
                   }
                   my $primarylibserv = &Apache::lonnet::domain($dom,'primary');
                   my @ids=&Apache::lonnet::current_machine_ids();
                   if (($primarylibserv ne '') && (!grep(/^\Q$primarylibserv\E$/,@ids))) {
                       my %what = (
                                      $name => 1,
                                  );
                       my ($result,$returnhash) =
                           &Apache::lonnet::get_remote_globals($primarylibserv,\%what);
                       if ($result eq 'ok') {
                           if (ref($returnhash) eq 'HASH') {
                               $legacy = $returnhash->{$name};
                           }
                       }
                   } else {
                       $legacy = $Apache::lonnet::perlvar{$name};
                   }
               }
               foreach my $type ('dom','intdom','other') {
                   my %checked;
                   $css_class = $itemcount%2?' class="LC_odd_row"':'';
                   $datatable .= '<tr'.$css_class.'><td>'.$titles{$type}.'</td>'.
                                 '<td class="LC_right_item">';
                   my $skip; 
                   if ($type eq 'dom') {
                       unless (keys(%servers) > 1) {
                           $datatable .= &mt('Nothing to set here, as there are no other servers/VMs');    
                           $skip = 1;
                       }
                   }
                   if ($type eq 'intdom') {
                       unless (@instdoms > 1) {
                           $datatable .= &mt('Nothing to set here, as there are no other domains for this institution');
                           $skip = 1;
                       } 
                   } elsif ($type eq 'other') {
                       if (keys(%by_location) == 0) {
                           $datatable .= &mt('Nothing to set here, as there are no other institutions');
                           $skip = 1;
                       }
                   }
                   unless ($skip) {
                       $checked{'yes'} = ' checked="checked"'; 
                       if (ref($settings) eq 'HASH') {
                           if (ref($settings->{$position}) eq 'HASH') {
                               if ($settings->{$position}->{$type} =~ /^(no|req)$/) {
                                   $checked{$1} = $checked{'yes'};
                                   delete($checked{'yes'}); 
                               }
                           }
                       } else {
                           if ($legacy == 0) {
                               $checked{'req'} = $checked{'yes'};
                               delete($checked{'yes'});    
                           }
                       }
                       foreach my $option ('no','yes','req') {
                           $datatable .= '<span class="LC_nobreak"><label>'.
                                         '<input type="radio" name="'.$position.'_'.$type.'" '.
                                         'value="'.$option.'"'.$checked{$option}.' />'.$titles{$option}.
                                         '</label></span>'.('&nbsp;'x2);
                     }                      }
                     $datatable .= '</tr></table>';  
                 }                  }
                 $datatable .= '</td></tr>';                  $datatable .= '</td></tr>';
                   $itemcount ++; 
               }
           } else {
               my $prefix = 'replication';
               my @types = ('certreq','nocertreq');
               if (keys(%by_location) == 0) {
                   $datatable .= '<tr'.$css_class.'><td>'.
                                 &mt('Nothing to set here, as there are no other institutions').
                                 '</td></tr>';
                 $itemcount ++;                  $itemcount ++;
               } else {
                   ($datatable,$itemcount) = 
                       &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
             }              }
         }          }
     }      }
Line 7756  sub print_usersessions { Line 8607  sub print_usersessions {
     return $datatable;      return $datatable;
 }  }
   
   sub ssl_titles {
       return &Apache::lonlocal::texthash (
                  dom           => 'LON-CAPA servers/VMs from same domain',
                  intdom        => 'LON-CAPA servers/VMs from same "internet" domain',
                  other         => 'External LON-CAPA servers/VMs',
                  connto        => 'Connections to other servers',
                  connfrom      => 'Connections from other servers',
                  replication   => 'Replicating content to other institutions',
                  certreq       => 'Client certificate required, but specific domains exempt',
                  nocertreq     => 'No client certificate required, except for specific domains',
                  no            => 'SSL not used',
                  yes           => 'SSL Optional (used if available)',
                  req           => 'SSL Required',
       );
   }
   
   sub print_trust {
       my ($prefix,$dom,$settings,$rowtotal) = @_;
       my ($css_class,$datatable,%checked,%choices);
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my $itemcount = 1;
       my %titles = &trust_titles();
       my @types = ('exc','inc');
       if ($prefix eq 'top') {
           $prefix = 'content';
       } elsif ($prefix eq 'bottom') {
           $prefix = 'msg';
       }
       ($datatable,$itemcount) = &rules_by_location($settings,$prefix,\%by_location,\%by_ip,\@types,\%titles);
       $$rowtotal += $itemcount;
       return $datatable;
   }
   
   sub trust_titles {
       return &Apache::lonlocal::texthash(
                  content  => "Access to this domain's content by others",
                  shared   => "Access to other domain's content by this domain",
                  enroll   => "Enrollment in this domain's courses by others", 
                  othcoau  => "Co-author roles in this domain for others",
                  coaurem  => "Co-author roles for this domain's users elsewhere", 
                  domroles => "Domain roles in this domain assignable to others",
                  catalog  => "Course Catalog for this domain displayed elsewhere",
                  reqcrs   => "Requests for creation of courses in this domain by others",
                  msg      => "Users in other domains can send messages to this domain",
                  exc      => "Allow all, but exclude specific domains",
                  inc      => "Deny all, but include specific domains",
              );
   } 
   
 sub build_location_hashes {  sub build_location_hashes {
     my ($intdoms,$by_ip,$by_location) = @_;      my ($intdoms,$by_ip,$by_location,$instdoms) = @_;
     return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') &&      return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') &&
                   (ref($by_location) eq 'HASH'));                     (ref($by_location) eq 'HASH') && (ref($instdoms) eq 'ARRAY'));
     my %iphost = &Apache::lonnet::get_iphost();      my %iphost = &Apache::lonnet::get_iphost();
     my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary');      my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary');
     my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);      my $primary_ip = &Apache::lonnet::get_host_ip($primary_id);
Line 7776  sub build_location_hashes { Line 8677  sub build_location_hashes {
             foreach my $id (@{$iphost{$ip}}) {              foreach my $id (@{$iphost{$ip}}) {
                 my $location = &Apache::lonnet::internet_dom($id);                  my $location = &Apache::lonnet::internet_dom($id);
                 if ($location) {                  if ($location) {
                     next if (grep(/^\Q$location\E$/,@{$intdoms}));                      if (grep(/^\Q$location\E$/,@{$intdoms})) {
                           my $dom = &Apache::lonnet::host_domain($id);
                           unless (grep(/^\Q$dom\E/,@{$instdoms})) {
                               push(@{$instdoms},$dom);
                           }
                           next;
                       }
                     if (ref($by_ip->{$ip}) eq 'ARRAY') {                      if (ref($by_ip->{$ip}) eq 'ARRAY') {
                         unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) {                          unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) {
                             push(@{$by_ip->{$ip}},$location);                              push(@{$by_ip->{$ip}},$location);
Line 8096  sub print_loadbalancing { Line 9003  sub print_loadbalancing {
         my $disabled_div_style = 'display: block';          my $disabled_div_style = 'display: block';
         my $homedom_div_style = 'display: none';          my $homedom_div_style = 'display: none';
         $datatable .= '<tr class="'.$css_class[$cssidx].'">'.          $datatable .= '<tr class="'.$css_class[$cssidx].'">'.
                       '<td rowspan="'.$rownum.'" valign="top">'.                        '<td rowspan="'.$rownum.'" style="vertical-align: top">'.
                       '<p>';                        '<p>';
         if ($lonhost eq '') {          if ($lonhost eq '') {
             $datatable .= '<span class="LC_nobreak">';              $datatable .= '<span class="LC_nobreak">';
Line 8129  sub print_loadbalancing { Line 9036  sub print_loadbalancing {
                 $homedom_div_style = 'display: block';                  $homedom_div_style = 'display: block';
             }              }
         }          }
         $datatable .= '</p></td><td rowspan="'.$rownum.'" valign="top">'.          $datatable .= '</p></td><td rowspan="'.$rownum.'" style="vertical-align: top">'.
                   '<div id="loadbalancing_disabled_'.$balnum.'" style="'.                    '<div id="loadbalancing_disabled_'.$balnum.'" style="'.
                   $disabled_div_style.'">'.$disabledtext.'</div>'."\n".                    $disabled_div_style.'">'.$disabledtext.'</div>'."\n".
                   '<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />';                    '<div id="loadbalancing_targets_'.$balnum.'" style="'.$targets_div_style.'">'.&mt('Offloads to:').'<br />';
Line 8361  sub loadbalance_rule_row { Line 9268  sub loadbalance_rule_row {
         $space = '<div style="display:inline-block;">&nbsp;</div>';          $space = '<div style="display:inline-block;">&nbsp;</div>';
     }      }
     my $output =      my $output =
         '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td valign="top">'.$space.          '<tr class="'.$css_class.'" id="balanceruletr_'.$balnum.'_'.$num.'"><td style="vertical-align: top">'.$space.
         '<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n".          '<div id="balanceruletitle_'.$balnum.'_'.$type.'" style="'.$style.'">'.$title.'</div></td>'."\n".
         '<td valaign="top">'.$space.          '<td valaign="top">'.$space.
         '<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n";          '<div id="balancerule_'.$balnum.'_'.$type.'" style="'.$style.'">'."\n";
Line 8495  sub tool_titles { Line 9402  sub tool_titles {
     my %titles = &Apache::lonlocal::texthash (      my %titles = &Apache::lonlocal::texthash (
                      aboutme    => 'Personal web page',                       aboutme    => 'Personal web page',
                      blog       => 'Blog',                       blog       => 'Blog',
                        webdav     => 'WebDAV',
                      portfolio  => 'Portfolio',                       portfolio  => 'Portfolio',
                      timezone   => 'Can set time zone',                       timezone   => 'Can set time zone',
                      official   => 'Official courses (with institutional codes)',                       official   => 'Official courses (with institutional codes)',
                      unofficial => 'Unofficial courses',                       unofficial => 'Unofficial courses',
                      community  => 'Communities',                       community  => 'Communities',
                      textbook   => 'Textbook courses',                       textbook   => 'Textbook courses',
                        placement  => 'Placement tests',
                  );                   );
     return %titles;      return %titles;
 }  }
Line 8511  sub courserequest_titles { Line 9420  sub courserequest_titles {
                                    unofficial => 'Unofficial',                                     unofficial => 'Unofficial',
                                    community  => 'Communities',                                     community  => 'Communities',
                                    textbook   => 'Textbook',                                     textbook   => 'Textbook',
                                      placement  => 'Placement tests',
                                    lti        => 'LTI Provider',                                     lti        => 'LTI Provider',
                                    norequest  => 'Not allowed',                                     norequest  => 'Not allowed',
                                    approval   => 'Approval by Dom. Coord.',                                     approval   => 'Approval by DC',
                                    validate   => 'With validation',                                     validate   => 'With validation',
                                    autolimit  => 'Numerical limit',                                     autolimit  => 'Numerical limit',
                                    unlimited  => '(blank for unlimited)',                                     unlimited  => '(blank for unlimited)',
Line 8602  sub print_usercreation { Line 9512  sub print_usercreation {
             }              }
             $datatable .= '<tr'.$css_class.'>'.              $datatable .= '<tr'.$css_class.'>'.
                          '<td><span class="LC_nobreak">'.$lt{$item}.                           '<td><span class="LC_nobreak">'.$lt{$item}.
                          '</span></td><td align="right">';                           '</span></td><td style="text-align: right">';
             my @options = ('any');              my @options = ('any');
             if (ref($rules) eq 'HASH') {              if (ref($rules) eq 'HASH') {
                 if (keys(%{$rules}) > 0) {                  if (keys(%{$rules}) > 0) {
Line 9045  sub noninst_users { Line 9955  sub noninst_users {
     }      }
     $output .= '</tr><tr>';      $output .= '</tr><tr>';
     foreach my $item ('approve','email','username') {      foreach my $item ('approve','email','username') {
         $output .= '<td valign="top">';          $output .= '<td style="vertical-align: top">';
         my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom);          my (%choices,@options,$hashref,$defoption,$name,$onclick,$hascustom);
         if ($item eq 'approve') {          if ($item eq 'approve') {
             %choices = &Apache::lonlocal::texthash (              %choices = &Apache::lonlocal::texthash (
Line 9516  sub print_defaults { Line 10426  sub print_defaults {
                     $datatable .= '</select>&nbsp;'.&mt('Internal ID:').'&nbsp;<b>'.$item.'</b>&nbsp;'.                      $datatable .= '</select>&nbsp;'.&mt('Internal ID:').'&nbsp;<b>'.$item.'</b>&nbsp;'.
                                   '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.                                    '<input type="checkbox" name="inststatus_delete" value="'.$item.'" />'.
                                   &mt('delete').'</span></td>'.                                    &mt('delete').'</span></td>'.
                                   '<td class="LC_left_item"><span class="LC_nobreak">'.&mt('Name displayed').':'.                                    '<td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.&mt('Name displayed').':'.
                                   '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.                                    '<input type="text" size="20" name="inststatus_title_'.$item.'" value="'.$title.'" />'.
                                   '</span></td></tr>';                                    '</span></td></tr>';
                 }                  }
Line 9535  sub print_defaults { Line 10445  sub print_defaults {
                 $datatable .= '</select>&nbsp;'.&mt('Internal ID:').                  $datatable .= '</select>&nbsp;'.&mt('Internal ID:').
                               '<input type="text" size="10" name="addinststatus" value="" />'.                                '<input type="text" size="10" name="addinststatus" value="" />'.
                               '&nbsp;'.&mt('(new)').                                '&nbsp;'.&mt('(new)').
                               '</span></td><td class="LC_left_item"><span class="LC_nobreak">'.                                '</span></td><td class="LC_left_item" colspan="2"><span class="LC_nobreak">'.
                               &mt('Name displayed').':'.                                &mt('Name displayed').':'.
                               '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.                                '<input type="text" size="20" name="addinststatus_title" value="" /></span></td>'.
                               '</tr>'."\n";                                '</tr>'."\n";
Line 9770  sub print_scantronformat { Line 10680  sub print_scantronformat {
         }          }
         $datatable .= '</span></td>';          $datatable .= '</span></td>';
         if (keys(%error) == 0) {           if (keys(%error) == 0) { 
             $datatable .= '<td valign="bottom">';              $datatable .= '<td style="vertical-align: bottom">';
             if (!$switchserver) {              if (!$switchserver) {
                 $datatable .= &mt('Upload:').'<br />';                  $datatable .= &mt('Upload:').'<br />';
             }              }
Line 10008  sub print_coursecategories { Line 10918  sub print_coursecategories {
         my $toggle_catscomm_dom = ' checked="checked" ';          my $toggle_catscomm_dom = ' checked="checked" ';
         my $can_catcomm_comm = ' ';          my $can_catcomm_comm = ' ';
         my $can_catcomm_dom = ' checked="checked" ';          my $can_catcomm_dom = ' checked="checked" ';
           my $toggle_catsplace_place = ' ';
           my $toggle_catsplace_dom = ' checked="checked" ';
           my $can_catplace_place = ' ';
           my $can_catplace_dom = ' checked="checked" ';
   
         if (ref($settings) eq 'HASH') {          if (ref($settings) eq 'HASH') {
             if ($settings->{'togglecats'} eq 'crs') {              if ($settings->{'togglecats'} eq 'crs') {
Line 10026  sub print_coursecategories { Line 10940  sub print_coursecategories {
                 $can_catcomm_comm = $can_catcomm_dom;                  $can_catcomm_comm = $can_catcomm_dom;
                 $can_catcomm_dom = ' ';                  $can_catcomm_dom = ' ';
             }              }
               if ($settings->{'togglecatsplace'} eq 'place') {
                   $toggle_catsplace_place = $toggle_catsplace_dom;
                   $toggle_catsplace_dom = ' ';
               }
               if ($settings->{'categorizeplace'} eq 'place') {
                   $can_catplace_place = $can_catplace_dom;
                   $can_catplace_dom = ' ';
               }
         }          }
         my %title = &Apache::lonlocal::texthash (          my %title = &Apache::lonlocal::texthash (
                      togglecats     => 'Show/Hide a course in catalog',                       togglecats      => 'Show/Hide a course in catalog',
                      togglecatscomm => 'Show/Hide a community in catalog',                       togglecatscomm  => 'Show/Hide a community in catalog',
                      categorize     => 'Assign a category to a course',                       togglecatsplace => 'Show/Hide a placement test in catalog',
                      categorizecomm => 'Assign a category to a community',                       categorize      => 'Assign a category to a course',
                        categorizecomm  => 'Assign a category to a community',
                        categorizeplace => 'Assign a category to a placement test',
                     );                      );
         my %level = &Apache::lonlocal::texthash (          my %level = &Apache::lonlocal::texthash (
                      dom  => 'Set in Domain',                       dom   => 'Set in Domain',
                      crs  => 'Set in Course',                       crs   => 'Set in Course',
                      comm => 'Set in Community',                       comm  => 'Set in Community',
                        place => 'Set in Placement Test',
                     );                      );
         $datatable = '<tr class="LC_odd_row">'.          $datatable = '<tr class="LC_odd_row">'.
                   '<td>'.$title{'togglecats'}.'</td>'.                    '<td>'.$title{'togglecats'}.'</td>'.
Line 10066  sub print_coursecategories { Line 10991  sub print_coursecategories {
                   $can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.                    $can_catcomm_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                   '<label><input type="radio" name="categorizecomm"'.                    '<label><input type="radio" name="categorizecomm"'.
                   $can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'.                    $can_catcomm_comm.'value="comm" />'.$level{'comm'}.'</label></span></td>'.
                     '</tr><tr class="LC_odd_row">'.
                     '<td>'.$title{'togglecatsplace'}.'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak"><label>'.
                     '<input type="radio" name="togglecatsplace"'.
                     $toggle_catsplace_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                     '<label><input type="radio" name="togglecatscomm"'.
                     $toggle_catsplace_place.' value="comm" />'.$level{'place'}.'</label></span></td>'.
                     '</tr><tr>'.
                     '<td>'.$title{'categorizeplace'}.'</td>'.
                     '<td class="LC_right_item"><span class="LC_nobreak">'.
                     '<label><input type="radio" name="categorizeplace"'.
                     $can_catplace_dom.' value="dom" />'.$level{'dom'}.'</label>&nbsp;'.
                     '<label><input type="radio" name="categorizeplace"'.
                     $can_catplace_place.'value="place" />'.$level{'place'}.'</label></span></td>'.
                   '</tr>';                    '</tr>';
         $$rowtotal += 4;          $$rowtotal += 6;
     } else {      } else {
         my $css_class;          my $css_class;
         my $itemcount = 1;          my $itemcount = 1;
Line 10092  sub print_coursecategories { Line 11031  sub print_coursecategories {
                     my %default_names = (                      my %default_names = (
                           instcode    => &mt('Official courses'),                            instcode    => &mt('Official courses'),
                           communities => &mt('Communities'),                            communities => &mt('Communities'),
                             placement   => &mt('Placement Tests'),
                     );                      );
   
                     if ((!grep(/^instcode$/,@{$cats[0]})) ||                       if ((!grep(/^instcode$/,@{$cats[0]})) || 
                         ($cathash->{'instcode::0'} eq '') ||                          ($cathash->{'instcode::0'} eq '') ||
                         (!grep(/^communities$/,@{$cats[0]})) ||                           (!grep(/^communities$/,@{$cats[0]})) || 
                         ($cathash->{'communities::0'} eq '')) {                          ($cathash->{'communities::0'} eq '') ||
                           (!grep(/^placement$/,@{$cats[0]})) ||
                           ($cathash->{'placement::0'} eq '')) {
                         $maxnum ++;                          $maxnum ++;
                     }                      }
                     my $lastidx;                      my $lastidx;
Line 10118  sub print_coursecategories { Line 11060  sub print_coursecategories {
                             $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';                              $datatable .= '<option value="'.$k.'"'.$selstr.'>'.$vpos.'</option>';
                         }                          }
                         $datatable .= '</select></span></td><td>';                          $datatable .= '</select></span></td><td>';
                         if ($parent eq 'instcode' || $parent eq 'communities') {                          if ($parent eq 'instcode' || $parent eq 'communities' || $parent eq 'placement') {
                             $datatable .=  '<span class="LC_nobreak">'                              $datatable .=  '<span class="LC_nobreak">'
                                            .$default_names{$parent}.'</span>';                                             .$default_names{$parent}.'</span>';
                             if ($parent eq 'instcode') {                              if ($parent eq 'instcode') {
Line 10141  sub print_coursecategories { Line 11083  sub print_coursecategories {
                             $datatable .= '<label><input type="radio" name="'                              $datatable .= '<label><input type="radio" name="'
                                           .$parent.'" value="0" />'                                            .$parent.'" value="0" />'
                                           .&mt('Do not display').'</label></span>';                                            .&mt('Do not display').'</label></span>';
                             if ($parent eq 'communities') {                              if (($parent eq 'communities') || ($parent eq 'placement')) {
                                 $datatable .= '</td></tr></table>';                                  $datatable .= '</td></tr></table>';
                             }                              }
                             $datatable .= '</td>';                              $datatable .= '</td>';
Line 10173  sub print_coursecategories { Line 11115  sub print_coursecategories {
                                   .'<input type="text" size="20" name="addcategory_name" value="" /></td>'                                    .'<input type="text" size="20" name="addcategory_name" value="" /></td>'
                                   .'</tr>'."\n";                                    .'</tr>'."\n";
                     $itemcount ++;                      $itemcount ++;
                     foreach my $default ('instcode','communities') {                      foreach my $default ('instcode','communities','placement') {
                         if ((!grep(/^\Q$default\E$/,@{$cats[0]})) || ($cathash->{$default.'::0'} eq '')) {                          if ((!grep(/^\Q$default\E$/,@{$cats[0]})) || ($cathash->{$default.'::0'} eq '')) {
                             $css_class = $itemcount%2?' class="LC_odd_row"':'';                              $css_class = $itemcount%2?' class="LC_odd_row"':'';
                             my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','$lastidx'".');"';                              my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','$lastidx'".');"';
Line 10262  sub print_serverstatuses { Line 11204  sub print_serverstatuses {
   
 sub serverstatus_pages {  sub serverstatus_pages {
     return ('userstatus','lonstatus','loncron','server-status','codeversions',      return ('userstatus','lonstatus','loncron','server-status','codeversions',
             'checksums','clusterstatus','metadata_keywords','metadata_harvest',              'checksums','clusterstatus','certstatus','metadata_keywords',
             'takeoffline','takeonline','showenv','toggledebug','ping','domconf',              'metadata_harvest','takeoffline','takeonline','showenv','toggledebug',
             'uniquecodes','diskusage','coursecatalog');              'ping','domconf','uniquecodes','diskusage','coursecatalog');
 }  }
   
 sub defaults_javascript {  sub defaults_javascript {
Line 10368  sub passwords_javascript { Line 11310  sub passwords_javascript {
             authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',              authcost => 'Warning: bcrypt encryption cost for internal authentication must be an integer.',
             passmin => 'Warning: minimum password length must be a positive integer greater than 6.',              passmin => 'Warning: minimum password length must be a positive integer greater than 6.',
             passmax => 'Warning: maximum password length must be a positive integer (or blank).',              passmax => 'Warning: maximum password length must be a positive integer (or blank).',
               passexp => 'Warning: days before password expiration must be a positive integer (or blank).',
             passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',              passnum => 'Warning: number of previous passwords to save must be a positive integer (or blank).',
         );          );
     } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {      } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
Line 10429  function warnInt$prefix(field) { Line 11372  function warnInt$prefix(field) {
             field.value = '';              field.value = '';
         }          }
         if (field.value != '') {          if (field.value != '') {
             if (!regexdigit.test(field.value)) {              if (field.name == '${prefix}_expire') {
                 if (field.name == '${prefix}_max') {                  var regexpposnum=/^\\d+(|\\.\\d*)\$/; 
                     alert('$intalert{passmax}');                  if (!regexpposnum.test(field.value)) {
                       alert('$intalert{passexp}');
                       field.value = '';
                 } else {                  } else {
                     if (field.name == '${prefix}_numsaved') {                      var expval = parseFloat(field.value);
                         alert('$intalert{passnum}');                      if (expval == 0) {
                           alert('$intalert{passexp}');
                           field.value = '';
                     }                      }
                 }                  }
                 field.value = '';              } else {
                   if (!regexdigit.test(field.value)) {
                       if (field.name == '${prefix}_max') {
                           alert('$intalert{passmax}');
                       } else {
                           if (field.name == '${prefix}_numsaved') {
                               alert('$intalert{passnum}');
                           }
                       }
                       field.value = '';
                   }
             }              }
         }          }
     }      }
Line 10472  sub coursecategories_javascript { Line 11429  sub coursecategories_javascript {
     }      }
     my $instcode_reserved = &mt('The name: [_1] is a reserved category.','"instcode"');      my $instcode_reserved = &mt('The name: [_1] is a reserved category.','"instcode"');
     my $communities_reserved = &mt('The name: [_1] is a reserved category.','"communities"');      my $communities_reserved = &mt('The name: [_1] is a reserved category.','"communities"');
       my $placement_reserved = &mt('The name: [_1] is a reserved category.','"placement"');
     my $choose_again = "\n".&mt('Please use a different name for the new top level category.');       my $choose_again = "\n".&mt('Please use a different name for the new top level category.'); 
     &js_escape(\$instcode_reserved);      &js_escape(\$instcode_reserved);
     &js_escape(\$communities_reserved);      &js_escape(\$communities_reserved);
       &js_escape(\$placement_reserved);
     &js_escape(\$choose_again);      &js_escape(\$choose_again);
     $output = <<"ENDSCRIPT";      $output = <<"ENDSCRIPT";
 <script type="text/javascript">  <script type="text/javascript">
Line 10544  function categoryCheck(form) { Line 11503  function categoryCheck(form) {
         alert('$communities_reserved\\n$choose_again');          alert('$communities_reserved\\n$choose_again');
         return false;          return false;
     }      }
       if (form.elements['addcategory_name'].value == 'placement') {
           alert('$placement_reserved\\n$choose_again');
           return false;
       }
     return true;      return true;
 }  }
   
Line 10560  sub initialize_categories { Line 11523  sub initialize_categories {
     my %default_names = &Apache::lonlocal::texthash (      my %default_names = &Apache::lonlocal::texthash (
                       instcode    => 'Official courses (with institutional codes)',                        instcode    => 'Official courses (with institutional codes)',
                       communities => 'Communities',                        communities => 'Communities',
                         placement   => 'Placement Tests',
                         );                          );
     my $select0 = ' selected="selected"';      my %selnum = (
     my $select1 = '';                     instcode    => '0',
     foreach my $default ('instcode','communities') {                     communities => '1',
                      placement   => '2',
                    );
       my %selected;
       foreach my $default ('instcode','communities','placement') {
         $css_class = $itemcount%2?' class="LC_odd_row"':'';          $css_class = $itemcount%2?' class="LC_odd_row"':'';
         $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','0'".');"';          $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$default"."_pos','0'".');"';
         if ($default eq 'communities') {          map { $selected{$selnum{$_}} = '' } keys(%selnum);
             $select1 = $select0;          $selected{$selnum{$default}} = ' selected="selected"';
             $select0 = '';  
         }  
         $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'          $datatable .= '<tr '.$css_class.'><td><span class="LC_nobreak">'
                      .'<select name="'.$default.'_pos">'                       .'<select name="'.$default.'_pos"'.$chgstr.'>'
                      .'<option value="0"'.$select0.'>1</option>'                       .'<option value="0"'.$selected{'0'}.'>1</option>'
                      .'<option value="1"'.$select1.'>2</option>'                       .'<option value="1"'.$selected{'1'}.'>2</option>'
                      .'<option value="2">3</option></select>&nbsp;'                       .'<option value="2"'.$selected{'2'}.'>3</option>'
                        .'<option value="3">4</option></select>&nbsp;'
                      .$default_names{$default}                       .$default_names{$default}
                      .'</span></td><td><span class="LC_nobreak">'                       .'</span></td><td><span class="LC_nobreak">'
                      .'<label><input type="radio" name="'.$default.'" value="1" checked="checked" />'                       .'<label><input type="radio" name="'.$default.'" value="1" checked="checked" />'
Line 10589  sub initialize_categories { Line 11556  sub initialize_categories {
                   .'<select name="addcategory_pos"'.$chgstr.'>'                    .'<select name="addcategory_pos"'.$chgstr.'>'
                   .'<option value="0">1</option>'                    .'<option value="0">1</option>'
                   .'<option value="1">2</option>'                    .'<option value="1">2</option>'
                   .'<option value="2" selected="selected">3</option></select>&nbsp;'                    .'<option value="2">3</option>'
                     .'<option value="3" selected="selected">4</option></select>&nbsp;'
                   .&mt('Add category').'</span></td><td><span class="LC_nobreak">'.&mt('Name:')                    .&mt('Add category').'</span></td><td><span class="LC_nobreak">'.&mt('Name:')
                   .'&nbsp;<input type="text" size="20" name="addcategory_name" value="" /></span>'                    .'&nbsp;<input type="text" size="20" name="addcategory_name" value="" /></span>'
                   .'</td></tr>';                    .'</td></tr>';
Line 10703  sub modifiable_userdata_row { Line 11671  sub modifiable_userdata_row {
         }          }
     } elsif ($context eq 'lti') {      } elsif ($context eq 'lti') {
         $rolename = &mt('Institutional data used (if available)');          $rolename = &mt('Institutional data used (if available)');
       } elsif ($context eq 'privacy') {
           $rolename = $itemdesc;
     } else {      } else {
         if ($role eq 'cr') {          if ($role eq 'cr') {
             $rolename = &mt('Custom role');              $rolename = &mt('Custom role');
Line 10745  sub modifiable_userdata_row { Line 11715  sub modifiable_userdata_row {
               '<td class="LC_left_item" colspan="2"><table>';                '<td class="LC_left_item" colspan="2"><table>';
     my $rem;      my $rem;
     my %checks;      my %checks;
       my %current;
     if (ref($settings) eq 'HASH') {      if (ref($settings) eq 'HASH') {
         my $hashref;          my $hashref;
         if ($context eq 'lti') {          if ($context eq 'lti') {
             if (ref($settings) eq 'HASH') {              if (ref($settings) eq 'HASH') {
                 $hashref = $settings->{'instdata'};                  $hashref = $settings->{'instdata'};
             }              }
           } elsif ($context eq 'privacy') {
               my ($key,$inner) = split(/_/,$role);
               if (ref($settings) eq 'HASH') {
                   if (ref($settings->{$key}) eq 'HASH') {
                       $hashref = $settings->{$key}->{$inner};
                   }
               }
         } elsif (ref($settings->{$context}) eq 'HASH') {          } elsif (ref($settings->{$context}) eq 'HASH') {
             if (ref($settings->{$context}->{$role}) eq 'HASH') {              if (ref($settings->{$context}->{$role}) eq 'HASH') {
                 $hashref = $settings->{'lti_instdata'};                  $hashref = $settings->{'lti_instdata'};
Line 10788  sub modifiable_userdata_row { Line 11766  sub modifiable_userdata_row {
         unless ($role eq 'emailusername') {          unless ($role eq 'emailusername') {
             if (exists($checks{$fields[$i]})) {              if (exists($checks{$fields[$i]})) {
                 $check = $checks{$fields[$i]};                  $check = $checks{$fields[$i]};
               } elsif ($context eq 'privacy') {
                   if ($role =~ /^priv_(domain|course)$/) {
                       if (ref($settings) ne 'HASH') {
                           $check = ' checked="checked" ';
                       }
                   } elsif ($role =~ /^priv_(author|community)$/) {
                       if (ref($settings) ne 'HASH') {
                           unless ($fields[$i] eq 'id') {
                               $check = ' checked="checked" ';
                           }
                       }
                   } elsif ($role =~ /^(unpriv|othdom)_/) {
                       if (ref($settings) ne 'HASH') {
                           if (($fields[$i] eq 'lastname') || ($fields[$i] eq 'firstname')) {
                               $check = ' checked="checked" ';
                           }
                       }
                   }
             } elsif ($context ne 'lti') {              } elsif ($context ne 'lti') {
                 if ($role eq 'st') {                  if ($role eq 'st') {
                     if (ref($settings) ne 'HASH') {                      if (ref($settings) ne 'HASH') {
Line 10816  sub modifiable_userdata_row { Line 11812  sub modifiable_userdata_row {
         } else {          } else {
             if ($context eq 'lti') {              if ($context eq 'lti') {
                 $prefix = 'lti';                  $prefix = 'lti';
               } elsif ($context eq 'privacy') {
                   $prefix = 'privacy';
             }              }
             $output .= '<label>'.              $output .= '<label>'.
                        '<input type="checkbox" name="'.$prefix.'_'.$role.'" '.                         '<input type="checkbox" name="'.$prefix.'_'.$role.'" '.
Line 10843  sub insttypes_row { Line 11841  sub insttypes_row {
     my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick,      my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick,
         $customcss,$rowstyle) = @_;          $customcss,$rowstyle) = @_;
     my %lt = &Apache::lonlocal::texthash (      my %lt = &Apache::lonlocal::texthash (
                       cansearch      => 'Users allowed to search',                        cansearch => 'Users allowed to search',
                       statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)',                        statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)',
                       lockablenames  => 'User preference to lock name',                        lockablenames => 'User preference to lock name',
                       selfassign     => 'Self-reportable affiliations',                        selfassign    => 'Self-reportable affiliations',
                       overrides      => "Override domain's helpdesk settings based on requester's affiliation",                        overrides     => "Override domain's helpdesk settings based on requester's affiliation",
                       webdav         => 'WebDAV access available',  
                       authorquota    => 'Authoring Space quota (MB)',  
              );               );
     my ($showdom,$defaultquota);      my $showdom;
     if ($context eq 'cansearch') {      if ($context eq 'cansearch') {
         $showdom = ' ('.$dom.')';          $showdom = ' ('.$dom.')';
     } elsif ($context eq 'authorquota') {  
         $defaultquota = 500;  
     }      }
     my $class = 'LC_left_item';      my $class = 'LC_left_item';
     if ($context eq 'statustocreate') {      if ($context eq 'statustocreate') {
Line 10892  sub insttypes_row { Line 11886  sub insttypes_row {
                     }                      }
                     $output .= '<tr>';                      $output .= '<tr>';
                 }                  }
                 if ($context eq 'authorquota') {                  my $check = ' ';
                     my $currquota;                  if (ref($settings) eq 'HASH') {
                     if ($settings->{$context}->{$types->[$i]} =~ /^\d+$/) {                      if (ref($settings->{$context}) eq 'ARRAY') {
                         $currquota = $settings->{$context}->{$types->[$i]};                          if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {
                     } else {  
                         $currquota = $defaultquota;  
                     }  
                     $output .= '<td class="LC_left_item">'."\n".  
                                '<label><span class="LC_nobreak">'."\n".  
                                $usertypes->{$types->[$i]}.'</span><br />'."\n".  
                                '<input type="text" name="'.$context.'_'.$types->[$i].'" '.  
                                'value="'.$currquota.'" size="5"'.$onclick.'/>'."\n".  
                                '</label></td>';  
                 } else {  
                     my $check = ' ';  
                     if (ref($settings) eq 'HASH') {  
                         if (ref($settings->{$context}) eq 'ARRAY') {  
                             if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) {  
                                 $check = ' checked="checked" ';  
                             }  
                         } elsif (ref($settings->{$context}) eq 'HASH') {  
                             if (ref($settings->{$context}->{$types->[$i]}) eq 'HASH') {  
                                 $check = ' checked="checked" ';  
                             } elsif ($context eq 'webdav') {  
                                 if ($settings->{$context}->{$types->[$i]}) {  
                                     $check = ' checked="checked" ';  
                                 }  
                             }  
                         } elsif ($context eq 'statustocreate') {  
                             $check = ' checked="checked" ';                              $check = ' checked="checked" ';
                         }                          }
                       } elsif (ref($settings->{$context}) eq 'HASH') {
                           if (ref($settings->{$context}->{$types->[$i]}) eq 'HASH') {
                               $check = ' checked="checked" ';
                           }
                       } elsif ($context eq 'statustocreate') {
                           $check = ' checked="checked" ';
                     }                      }
                     $output .= '<td class="LC_left_item">'.  
                                '<span class="LC_nobreak"><label>'.  
                                '<input type="checkbox" name="'.$context.'" '.  
                                'value="'.$types->[$i].'"'.$check.$onclick.'/>'.  
                                $usertypes->{$types->[$i]}.'</label></span></td>';  
                 }                  }
                   $output .= '<td class="LC_left_item">'.
                              '<span class="LC_nobreak"><label>'.
                              '<input type="checkbox" name="'.$context.'" '.
                              'value="'.$types->[$i].'"'.$check.$onclick.' />'.
                              $usertypes->{$types->[$i]}.'</label></span></td>';
             }              }
         }          }
         $rem = @{$types}%($numinrow);          $rem = @{$types}%($numinrow);
Line 10951  sub insttypes_row { Line 11926  sub insttypes_row {
         } else {          } else {
             $output .= '<td class="LC_left_item">';              $output .= '<td class="LC_left_item">';
         }          }
         if ($context eq 'authorquota') {          my $defcheck = ' ';
             my $currquota = 500;          if (ref($settings) eq 'HASH') {  
             if ((ref($settings) eq 'HASH') && (ref($settings->{$context}) eq 'HASH')) {              if (ref($settings->{$context}) eq 'ARRAY') {
                 if ($settings->{$context}{'default'} =~ /^\d+$/) {                  if (grep(/^default$/,@{$settings->{$context}})) {
                     $currquota = $settings->{$context}{'default'};  
                 }  
             }  
             $output .= '<label><span class="LC_nobreak">'.$othertitle.'</span><br />'."\n".  
                        '<input type="text" name="'.$context.'_default" '.  
                        'value="'.$currquota.'" size="5"'.$onclick.'/>'."\n".  
                        '</label>';  
         } else {  
             my $defcheck = ' ';  
             if (ref($settings) eq 'HASH') {  
                 if (ref($settings->{$context}) eq 'ARRAY') {  
                     if (grep(/^default$/,@{$settings->{$context}})) {  
                         $defcheck = ' checked="checked" ';  
                     }  
                 } elsif (ref($settings->{$context}) eq 'HASH') {  
                     if (ref($settings->{$context}->{'default'}) eq 'HASH') {  
                         $defcheck = ' checked="checked" ';  
                     } elsif ($context eq 'webdav') {  
                         if ($settings->{$context}->{'default'}) {  
                             $defcheck = ' checked="checked" ';  
                         }  
                     }  
                 } elsif ($context eq 'statustocreate') {  
                     $defcheck = ' checked="checked" ';                      $defcheck = ' checked="checked" ';
                 }                  }
               } elsif ($context eq 'statustocreate') {
                   $defcheck = ' checked="checked" ';
             }              }
             $output .= '<span class="LC_nobreak"><label>'.  
                        '<input type="checkbox" name="'.$context.'" '.  
                        'value="default"'.$defcheck.$onclick.'/>'.  
                        $othertitle.'</label></span>';  
         }          }
           $output .= '<span class="LC_nobreak"><label>'.
                      '<input type="checkbox" name="'.$context.'" '.
                      'value="default"'.$defcheck.$onclick.' />'.
                      $othertitle.'</label></span>';
     }      }
     $output .= '</td></tr></table></td></tr>';      $output .= '</td></tr></table></td></tr>';
     return $output;      return $output;
Line 11999  sub get_ipaccess_id { Line 12953  sub get_ipaccess_id {
     return ($id,$error);      return ($id,$error);
 }  }
   
 sub modify_authordefaults {  
     my ($dom,$lastactref,%domconfig) = @_;  
 #  
 # Retrieve current domain configuration for webDAV and Authoring Space quotas from $domconfig{'quotas'}.  
 #  
     my (%curr_quotas,%save_quotas,%confhash,%changes,%newvalues);  
     if (ref($domconfig{'quotas'}) eq 'HASH') {  
         foreach my $key (keys(%{$domconfig{'quotas'}})) {  
             if ($key =~ /^webdav|authorquota$/) {  
                 $curr_quotas{$key} = $domconfig{'quotas'}{$key};  
             } else {  
                 $save_quotas{$key} = $domconfig{'quotas'}{$key};  
             }  
         }  
     }  
     my %staticdefaults = (  
                            'copyright'    => 'default',  
                            'sourceavail'  => 'closed',  
                            'nocodemirror' => 'off',  
                            'daxecollapse' => 'off',  
                            'domcoordacc'  => 'on',  
                            'editors'      => ['edit','xml'].  
                            'authorquota'  => 500,  
                            'webdav'       => 0,  
                          );  
     my %titles = &authordefaults_titles();  
     foreach my $item ('nocodemirror','daxecollapse','domcoordacc') {  
         if ($env{'form.'.$item} =~ /^(0|1)$/) {  
             $confhash{$item} = $env{'form.'.$item};  
         }  
     }  
     if ($env{'form.copyright'} =~ /^(default|domain|public)$/) {  
         $confhash{'copyright'} = $1;  
     }  
     if ($env{'form.sourceavail'} =~ /^(closed|open)$/) {  
         $confhash{'sourceavail'} = $1;  
     }  
     my @posseditors =  &Apache::loncommon::get_env_multiple('form.author_editors');  
     my @okeditors = ('edit','xml','daxe');  
     my @editors;  
     foreach my $item (@posseditors) {  
         if (grep(/^\Q$item\E$/,@okeditors)) {  
             push(@editors,$item);  
         }  
     }  
     $confhash{'editors'} = \@editors;  
   
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);  
     my @insttypes;  
     if (ref($types) eq 'ARRAY') {  
         @insttypes = @{$types};  
     }  
     my @webdavon = &Apache::loncommon::get_env_multiple('form.webdav');  
     my %webdav;  
     map { $webdav{$_} = 1; } @webdavon;  
     foreach my $type (@insttypes,'default') {  
         my $possquota = $env{'form.authorquota_'.$type};  
         if ($possquota =~ /^\d+$/) {  
             $save_quotas{'authorquota'}{$type} = $possquota;  
         }  
         if ($webdav{$type}) {  
             $save_quotas{'webdav'}{$type} = 1;  
         } else {  
             $save_quotas{'webdav'}{$type} = 0;  
         }  
     }  
     if ($env{'form.webdav_LC_adv'} =~ /^(0|1)$/) {  
         $save_quotas{'webdav'}{'_LC_adv'} = $env{'form.webdav_LC_adv'};  
     }  
     if (ref($domconfig{'authordefaults'}) eq 'HASH') {  
         foreach my $item ('nocodemirror','daxecollapse','domcoordacc','copyright','sourceavail') {  
             if ($domconfig{'authordefaults'}{$item} ne $confhash{$item}) {  
                 $changes{$item} = 1;  
              }  
         }  
         if (ref($domconfig{'authordefaults'}{'editors'}) eq 'ARRAY') {  
             my @diffs =  
                 &Apache::loncommon::compare_arrays($confhash{'editors'},  
                                                    $domconfig{'authordefaults'}{'editors'});  
             unless (@diffs == 0) {  
                 $changes{'editors'} = 1;  
             }  
         } else {  
             my @diffs =  
                 &Apache::loncommon::compare_arrays($confhash{'editors'},  
                                                    $staticdefaults{'editors'});  
             unless (@diffs == 0) {  
                 $changes{'editors'} = 1;  
             }  
         }  
     } else {  
         my @offon = ('off','on');  
         foreach my $item ('nocodemirror','daxecollapse','domcoordacc') {  
             if ($offon[$confhash{$item}] ne $staticdefaults{$item}) {  
                 $changes{$item} = 1;  
             }  
         }  
         foreach my $item ('copyright','sourceavail') {  
             if ($confhash{$item} ne $staticdefaults{$item}) {  
                 $changes{$item} = 1;  
             }  
         }  
     }  
     foreach my $key ('authorquota','webdav') {  
         if (ref($curr_quotas{$key}) eq 'HASH') {  
             foreach my $type (@insttypes,'default') {  
                 if (exists($save_quotas{$key}{$type})) {  
                     if ($save_quotas{$key}{$type} ne $curr_quotas{$key}{$type}) {  
                         $changes{$key}{$type} = 1;  
                     }  
                 } elsif (exists($curr_quotas{$key}{$type})) {  
                     $save_quotas{$key}{$type} = $curr_quotas{$key}{$type};  
                 } else {  
                     $save_quotas{$key}{$type} = $staticdefaults{$key};  
                 }  
             }  
         } else {  
             foreach my $type (@insttypes,'default') {  
                 if (exists($save_quotas{$key}{$type})) {  
                     unless ($save_quotas{$key}{$type} eq $staticdefaults{$key}) {  
                         $changes{$key}{$type} = 1;  
                     }  
                 } else {  
                     $save_quotas{$key}{$type} = $staticdefaults{$key};  
                 }  
             }  
         }  
     }  
     if (ref($curr_quotas{'webdav'}) eq 'HASH') {  
         if (exists($save_quotas{'webdav'}{'_LC_adv'})) {  
             if ($save_quotas{'webdav'}{'_LC_adv'} ne $curr_quotas{'webdav'}{'_LC_adv'}) {  
                 $changes{'webdav_LC_adv'} = 1;  
             }  
         } elsif (exists($curr_quotas{'webdav'}{'_LC_adv'})) {  
             $changes{'webdav_LC_adv'} = 1;  
         }  
     } elsif (exists($save_quotas{'webdav'}{'_LC_adv'})) {  
         $changes{'webdav_LC_adv'} = 1;  
     }  
     my %confighash = (  
                         quotas  => \%save_quotas,  
                         authordefaults => \%confhash,  
                      );  
     my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,  
                                              $dom);  
     my $resulttext;  
     if ($putresult eq 'ok') {  
         if (keys(%changes)) {  
             my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);  
             if ((exists($changes{'authorquota'})) || (exists($changes{'webdav'})) ||  
                 ($changes{'webdav_LC_adv'})) {  
                 if ((exists($changes{'authorquota'})) && (ref($save_quotas{'authorquota'}) eq 'HASH')) {  
                     $domdefaults{'authorquota'} = $save_quotas{'authorquota'};  
                 }  
                 if (((exists($changes{'webdav'})) || ($changes{'webdav_LC_adv'})) &&  
                     (ref($save_quotas{'webdav'}) eq 'HASH')) {  
                     $domdefaults{'webdav'} = $save_quotas{'webdav'};  
                 }  
             }  
             $resulttext = &mt('Changes made:').'<ul>';  
             my $authoroverride;  
             foreach my $key ('nocodemirror','daxecollapse','domcoordacc','copyright','sourceavail') {  
                 if (exists($changes{$key})) {  
                     $domdefaults{$key} = $confhash{$key};  
                     my $shown;  
                     unless ($authoroverride) {  
                         $resulttext .= '<li>'.&mt('Defaults which can be overridden by Author').'<ul>';  
                         $authoroverride = 1;  
                     }  
                     if (($key eq 'nocodemirror') || ($key eq 'daxecollapse') || ($key eq 'domcoordacc')) {  
                         $shown = ($confhash{$key} ? &mt('Yes') : &mt('No'));  
                     } elsif ($key eq 'copyright') {  
                         $shown = &Apache::loncommon::copyrightdescription($confhash{$key});  
                     } elsif ($key eq 'sourceavail') {  
                         $shown = &Apache::loncommon::source_copyrightdescription($confhash{$key});  
                     }  
                     $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';  
                 }  
             }  
             if ($authoroverride) {  
                 $resulttext .= '</ul></li>';  
             }  
             my $domcoordoverride;  
             foreach my $key ('editors','authorquota','webdav','webdav_LC_adv') {  
                 if (exists($changes{$key})) {  
                     my $shown;  
                     unless ($domcoordoverride) {  
                         $resulttext .= '<li>'.&mt('Defaults which can be overridden by a Domain Coodinator').'<ul>';  
                         $domcoordoverride = 1;  
                     }  
                     if ($key eq 'editors') {  
                         if (ref($confhash{'editors'}) eq 'ARRAY') {  
                             $domdefaults{'editors'} = join(',',@{$confhash{'editors'}});  
                             if (@{$confhash{'editors'}}) {  
                                 $shown = join(', ', map { $titles{$_} } @{$confhash{'editors'}});  
                             } else {  
                                 $shown = &mt('None');  
                             }  
                         }  
                     } elsif ($key eq 'authorquota') {  
                         foreach my $type (@insttypes) {  
                             $shown .= $usertypes->{$type}.' -- '.$save_quotas{$key}{$type}.', ';  
                         }  
                         $shown .= $othertitle.' -- '.$save_quotas{$key}{'default'};  
                     } elsif ($key eq 'webdav') {  
                         foreach my $type (@insttypes) {  
                             $shown .= $usertypes->{$type}.' -- '. ($save_quotas{$key}{$type} ? &mt('Yes') : &mt('No')).', ';  
                         }  
                         $shown .= $othertitle.' -- '. ($save_quotas{$key}{'default'} ? &mt('Yes') : &mt('No'));  
                     } elsif ($key eq 'webdav_LC_adv') {  
                         if (exists($save_quotas{'webdav'}{'_LC_adv'})) {  
                             $shown = ($save_quotas{'webdav'}{'_LC_adv'} ? $titles{'overon'} : $titles{'overoff'});  
                         } else {  
                             $shown = $titles{'none'};  
                         }  
                     }  
                     $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';  
                 }     
             }  
             if ($domcoordoverride) {  
                 $resulttext .= '</ul></li>';  
             }  
             my $cachetime = 24*60*60;  
             &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);  
             if (ref($lastactref) eq 'HASH') {  
                 $lastactref->{'domdefaults'} = 1;  
             }  
         } else {  
             $resulttext = &mt('No changes made to Authoring Space defaults');  
         }  
     }  
     return $resulttext;  
 }  
   
 sub modify_rolecolors {  sub modify_rolecolors {
     my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;      my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;
     my ($resulttext,%rolehash);      my ($resulttext,%rolehash);
Line 12620  sub display_colorchgs { Line 13340  sub display_colorchgs {
                         } else {                          } else {
                             my $newitem = $confhash->{$role}{$item};                              my $newitem = $confhash->{$role}{$item};
                             if ($key eq 'images') {                              if ($key eq 'images') {
                                 $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" valign="bottom" />';                                  $newitem = '<img src="'.$confhash->{$role}{$item}.'" alt="'.$choices{$item}.'" style="vertical-align: bottom" />';
                             }                              }
                             $resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>';                              $resulttext .= '<li>'.&mt("$choices{$item} set to [_1]",$newitem).'</li>';
                         }                          }
Line 12772  sub check_switchserver { Line 13492  sub check_switchserver {
     my @ids=&Apache::lonnet::current_machine_ids();      my @ids=&Apache::lonnet::current_machine_ids();
     foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }      foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } }
     if (!$allowed) {      if (!$allowed) {
  $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&amp;role='.   $switchserver='<a href="/adm/switchserver?otherserver='.$home.'&amp;role=dc./'.$dom.'/&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';
                       &HTML::Entities::encode($env{'request.role'},'\'<>"&').  
                       '&amp;destinationurl=/adm/domainprefs">'.&mt('Switch Server').'</a>';  
     }      }
     return $switchserver;      return $switchserver;
 }  }
Line 12786  sub modify_quotas { Line 13504  sub modify_quotas {
         $author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref,          $author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref,
         $validationfieldsref);          $validationfieldsref);
     if ($action eq 'quotas') {      if ($action eq 'quotas') {
         $context = 'tools';          $context = 'tools'; 
     } else {      } else {
         $context = $action;          $context = $action;
     }      }
     if ($context eq 'requestcourses') {      if ($context eq 'requestcourses') {
         @usertools = ('official','unofficial','community','textbook','lti');          @usertools = ('official','unofficial','community','textbook','placement','lti');
         @options =('norequest','approval','validate','autolimit');          @options =('norequest','approval','validate','autolimit');
         %validations = &Apache::lonnet::auto_courserequest_checks($dom);          %validations = &Apache::lonnet::auto_courserequest_checks($dom);
         %titles = &courserequest_titles();          %titles = &courserequest_titles();
Line 12806  sub modify_quotas { Line 13524  sub modify_quotas {
         @usertools = ('author');          @usertools = ('author');
         %titles = &authorrequest_titles();          %titles = &authorrequest_titles();
     } else {      } else {
         @usertools = ('aboutme','blog','portfolio','timezone');          @usertools = ('aboutme','blog','webdav','portfolio','timezone');
         %titles = &tool_titles();          %titles = &tool_titles();
     }      }
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
Line 12829  sub modify_quotas { Line 13547  sub modify_quotas {
         } else {          } else {
             if ($key =~ /^form\.quota_(.+)$/) {              if ($key =~ /^form\.quota_(.+)$/) {
                 $confhash{'defaultquota'}{$1} = $env{$key};                  $confhash{'defaultquota'}{$1} = $env{$key};
               } elsif ($key =~ /^form\.authorquota_(.+)$/) {
                   $confhash{'authorquota'}{$1} = $env{$key};
             } elsif ($key =~ /^form\.\Q$context\E_(.+)$/) {              } elsif ($key =~ /^form\.\Q$context\E_(.+)$/) {
                 @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key);                  @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key);
             }              }
Line 12838  sub modify_quotas { Line 13558  sub modify_quotas {
         my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval');          my @approvalnotify = &Apache::loncommon::get_env_multiple('form.'.$context.'notifyapproval');
         @approvalnotify = sort(@approvalnotify);          @approvalnotify = sort(@approvalnotify);
         $confhash{'notify'}{'approval'} = join(',',@approvalnotify);          $confhash{'notify'}{'approval'} = join(',',@approvalnotify);
         my @crstypes = ('official','unofficial','community','textbook','lti');          my @crstypes = ('official','unofficial','community','textbook','placement','lti');
         my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode');          my @hasuniquecode = &Apache::loncommon::get_env_multiple('form.uniquecode');
         foreach my $type (@hasuniquecode) {          foreach my $type (@hasuniquecode) {
             if (grep(/^\Q$type\E$/,@crstypes)) {              if (grep(/^\Q$type\E$/,@crstypes)) {
Line 13122  sub modify_quotas { Line 13842  sub modify_quotas {
         }          }
     } else {      } else {
         $confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'};          $confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'};
           $confhash{'authorquota'}{'default'} = $env{'form.authorquota'};
     }      }
     foreach my $item (@usertools) {      foreach my $item (@usertools) {
         foreach my $type (@{$types},'default','_LC_adv') {          foreach my $type (@{$types},'default','_LC_adv') {
Line 13210  sub modify_quotas { Line 13931  sub modify_quotas {
                 }                  }
             }              }
             if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {              if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {
                 $confhash{'authorquota'} = $domconfig{'quotas'}{'authorquota'};                  foreach my $key (keys(%{$domconfig{'quotas'}{'authorquota'}})) {
             }                      if (exists($confhash{'authorquota'}{$key})) {
             if (ref($domconfig{'quotas'}{'webdav'}) eq 'HASH') {                          if ($confhash{'authorquota'}{$key} ne $domconfig{'quotas'}{'authorquota'}{$key}) {
                 $confhash{'webdav'} = $domconfig{'quotas'}{'webdav'};                              $changes{'authorquota'}{$key} = 1;
                           }
                       } else {
                           $confhash{'authorquota'}{$key} = $domconfig{'quotas'}{'authorquota'}{$key};
                       }
                   }
             }              }
         }          }
         if (ref($confhash{'defaultquota'}) eq 'HASH') {          if (ref($confhash{'defaultquota'}) eq 'HASH') {
Line 13233  sub modify_quotas { Line 13959  sub modify_quotas {
                 }                  }
             }              }
         }          }
           if (ref($confhash{'authorquota'}) eq 'HASH') {
               foreach my $key (keys(%{$confhash{'authorquota'}})) {
                   if (ref($domconfig{'quotas'}) eq 'HASH') {
                       if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {
                           if (!exists($domconfig{'quotas'}{'authorquota'}{$key})) {
                               $changes{'authorquota'}{$key} = 1;
                           }
                       } else {
                           $changes{'authorquota'}{$key} = 1;
                       }
                   } else {
                       $changes{'authorquota'}{$key} = 1;
                   }
               }
           }
     }      }
   
     if ($context eq 'requestauthor') {      if ($context eq 'requestauthor') {
Line 13273  sub modify_quotas { Line 14014  sub modify_quotas {
                     }                      }
                     $resulttext .= '</ul></li>';                      $resulttext .= '</ul></li>';
                 }                  }
                   if (ref($changes{'authorquota'}) eq 'HASH') {
                       $resulttext .= '<li>'.&mt('Authoring Space default quotas').'<ul>';
                       foreach my $type (@{$types},'default') {
                           if (defined($changes{'authorquota'}{$type})) {
                               my $typetitle = $usertypes->{$type};
                               if ($type eq 'default') {
                                   $typetitle = $othertitle;
                               }
                               $resulttext .= '<li>'.&mt('[_1] set to [_2] MB',$typetitle,$confhash{'authorquota'}{$type}).'</li>';
                           }
                       }
                       $resulttext .= '</ul></li>';
                   }
             }              }
             my %newenv;              my %newenv;
             foreach my $item (@usertools) {              foreach my $item (@usertools) {
Line 13735  sub lti_security_results { Line 14489  sub lti_security_results {
                                        off => &mt('Encryption of stored external tool secrets defined in domain disabled'),                                         off => &mt('Encryption of stored external tool secrets defined in domain disabled'),
                                      },                                       },
                              );                               );
   
             }              }
             my @types= ('crs','dom');              my @types= ('crs','dom');
             if ($context eq 'lti') {              if ($context eq 'lti') {
Line 13830  sub lti_security_results { Line 14585  sub lti_security_results {
             }              }
         } elsif ($item eq 'linkprot') {          } elsif ($item eq 'linkprot') {
             next;              next;
         } elsif ($item eq 'suggested') {  
             if ((ref($secchanges->{'suggested'}) eq 'HASH') &&  
                 (ref($newsec->{'suggested'}) eq 'HASH')) {  
                 my $suggestions;  
                 foreach my $id (sort { $a <=> $b } keys(%{$secchanges->{'suggested'}})) {  
                     if (ref($newsec->{'suggested'}->{$id}) eq 'HASH') {  
                         my $name = $newsec->{'suggested'}->{$id}->{'name'};  
                         my $info = $newsec->{'suggested'}->{$id}->{'info'};  
                         $suggestions .= '<li>'.&mt('Launcher: [_1]',$name).'<br />'.  
                                                &mt('Recommend: [_1]','<pre>'.$info.'</pre>').  
                                         '</li>';  
                     } else {  
                         $suggestions .= '<li>'.&mt('Recommendations deleted for Launcher: [_1]',  
                                                    $newsec->{'suggested'}->{$id}).'</li>';  
                     }  
                 }  
                 if ($suggestions) {  
                     $output .= '<li>'.&mt('Hints in Courses for Link Protector Configuration').  
                                '<ul>'.$suggestions.'</ul>'.  
                                '</li>';  
                 }  
             }  
         }          }
     }      }
     if ($needs_update) {      if ($needs_update) {
Line 13861  sub lti_security_results { Line 14594  sub lti_security_results {
     return $output;      return $output;
 }  }
   
   sub modify_proctoring {
       my ($r,$dom,$action,$lastactref,%domconfig) = @_;
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my (@allpos,%changes,%confhash,%encconfhash,$errors,$resulttext,%imgdeletions);
       my $confname = $dom.'-domainconfig';
       my $servadm = $r->dir_config('lonAdmEMail');
       my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm);
       my %providernames = &proctoring_providernames();
       my $maxnum = scalar(keys(%providernames));
   
       my (%requserfields,%optuserfields,%defaults,%extended,%crsconf,@courseroles,@ltiroles);
       my ($requref,$opturef,$defref,$extref,$crsref,$rolesref,$ltiref) = &proctoring_data();
       if (ref($requref) eq 'HASH') {
           %requserfields = %{$requref};
       }
       if (ref($opturef) eq 'HASH') {
           %optuserfields = %{$opturef};
       }
       if (ref($defref) eq 'HASH') {
           %defaults = %{$defref};
       }
       if (ref($extref) eq 'HASH') {
           %extended = %{$extref};
       }
       if (ref($crsref) eq 'HASH') {
           %crsconf = %{$crsref};
       }
       if (ref($rolesref) eq 'ARRAY') {
           @courseroles = @{$rolesref};
       }
       if (ref($ltiref) eq 'ARRAY') {
           @ltiroles = @{$ltiref};
       }
   
       if (ref($domconfig{$action}) eq 'HASH') {
           my @todeleteimages = &Apache::loncommon::get_env_multiple('form.proctoring_image_del');
           if (@todeleteimages) {
               map { $imgdeletions{$_} = 1; } @todeleteimages;
           }
       }
       my %customadds;
       my @newcustom = &Apache::loncommon::get_env_multiple('form.proctoring_customadd');
       if (@newcustom) {
           map { $customadds{$_} = 1; } @newcustom;
       }
       foreach my $provider (sort(keys(%providernames))) {
           $confhash{$provider} = {};
           my $pos = $env{'form.proctoring_pos_'.$provider};
           $pos =~ s/\D+//g;
           $allpos[$pos] = $provider;
           my (%current,%currentenc);
           my $showroles = 0;
           if (ref($domconfig{$action}) eq 'HASH') {
               if (ref($domconfig{$action}{$provider}) eq 'HASH') {
                   %current = %{$domconfig{$action}{$provider}};
                   foreach my $item ('key','secret') { 
                       $currentenc{$item} = $current{$item};
                       delete($current{$item});
                   }
               }
           }
           if ($env{'form.proctoring_available_'.$provider}) {
               $confhash{$provider}{'available'} = 1;
               unless ($current{'available'}) {
                   $changes{$provider} = 1;
               }
           } else {
               %{$confhash{$provider}} = %current;
               %{$encconfhash{$provider}} = %currentenc;
               $confhash{$provider}{'available'} = 0;
               if ($current{'available'}) {
                   $changes{$provider} = 1;
               }
           }
           if ($confhash{$provider}{'available'}) {
               foreach my $field ('lifetime','version','sigmethod','url','key','secret') {
                   my $possval = $env{'form.proctoring_'.$provider.'_'.$field};
                   if ($field eq 'lifetime') {
                       if ($possval =~ /^\d+$/) {
                           $confhash{$provider}{$field} = $possval;
                       }
                   } elsif ($field eq 'version') {
                       if ($possval =~ /^\d+\.\d+$/) {
                           $confhash{$provider}{$field} = $possval;
                       }
                   } elsif ($field eq 'sigmethod') {
                       if ($possval =~ /^\QHMAC-SHA\E(1|256)$/) {
                           $confhash{$provider}{$field} = $possval;
                       }
                   } elsif ($field eq 'url') {
                       $confhash{$provider}{$field} = $possval;
                   } elsif (($field eq 'key') || ($field eq 'secret')) {
                       $encconfhash{$provider}{$field} = $possval;
                       unless ($currentenc{$field} eq $possval) {
                           $changes{$provider} = 1;
                       }
                   }
                   unless (($field eq 'key') || ($field eq 'secret')) {
                       unless ($current{$field} eq $confhash{$provider}{$field}) {
                           $changes{$provider} = 1;
                       }
                   }
               }
               if ($imgdeletions{$provider}) {
                   $changes{$provider} = 1;
               } elsif ($env{'form.proctoring_image_'.$provider.'.filename'} ne '') {
                   my ($imageurl,$error) =
                       &process_proctoring_image($r,$dom,$confname,'proctoring_image_'.$provider,$provider,
                                                 $configuserok,$switchserver,$author_ok);
                   if ($imageurl) {
                       $confhash{$provider}{'image'} = $imageurl;
                       $changes{$provider} = 1; 
                   }
                   if ($error) {
                       &Apache::lonnet::logthis($error);
                       $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
                   }
               } elsif (exists($current{'image'})) {
                   $confhash{$provider}{'image'} = $current{'image'};
               }
               if (ref($requserfields{$provider}) eq 'ARRAY') {
                   if (@{$requserfields{$provider}} > 0) {
                       if (grep(/^user$/,@{$requserfields{$provider}})) {
                           if ($env{'form.proctoring_userincdom_'.$provider}) {
                               $confhash{$provider}{'incdom'} = 1;
                           }
                           unless ($current{'incdom'} eq $confhash{$provider}{'incdom'}) {
                               $changes{$provider} = 1;
                           }
                       }
                       if (grep(/^roles$/,@{$requserfields{$provider}})) {
                           $showroles = 1;
                       }
                   }
               }
               $confhash{$provider}{'fields'} = [];
               if (ref($optuserfields{$provider}) eq 'ARRAY') {
                   if (@{$optuserfields{$provider}} > 0) {
                       my @optfields = &Apache::loncommon::get_env_multiple('form.proctoring_optional_'.$provider);
                       foreach my $field (@{$optuserfields{$provider}}) {
                           if (grep(/^\Q$field\E$/,@optfields)) {
                               push(@{$confhash{$provider}{'fields'}},$field);
                           }
                       }
                   }
                   if (ref($current{'fields'}) eq 'ARRAY') {
                       unless ($changes{$provider}) {
                           my @new = sort(@{$confhash{$provider}{'fields'}});
                           my @old = sort(@{$current{'fields'}}); 
                           my @diffs = &Apache::loncommon::compare_arrays(\@new,\@old);
                           if (@diffs) {
                               $changes{$provider} = 1;
                           }
                       }
                   } elsif (@{$confhash{$provider}{'fields'}}) {
                       $changes{$provider} = 1;
                   }
               }
               if (ref($defaults{$provider}) eq 'ARRAY') {  
                   if (@{$defaults{$provider}} > 0) {
                       my %options;
                       if (ref($extended{$provider}) eq 'HASH') {
                           %options = %{$extended{$provider}};
                       }
                       my @checked = &Apache::loncommon::get_env_multiple('form.proctoring_defaults_'.$provider);
                       foreach my $field (@{$defaults{$provider}}) {
                           if ((exists($options{$field})) && (ref($options{$field}) eq 'ARRAY')) {
                               my $poss = $env{'form.proctoring_defaults_'.$field.'_'.$provider};
                               if (grep(/^\Q$poss\E$/,@{$options{$field}})) {
                                   push(@{$confhash{$provider}{'defaults'}},$poss); 
                               }
                           } elsif ((exists($options{$field})) && (ref($options{$field}) eq 'HASH')) {
                               foreach my $inner (keys(%{$options{$field}})) {
                                   if (ref($options{$field}{$inner}) eq 'ARRAY') {
                                       my $poss = $env{'form.proctoring_'.$inner.'_'.$provider};
                                       if (grep(/^\Q$poss\E$/,@{$options{$field}{$inner}})) {
                                           $confhash{$provider}{'defaults'}{$inner} = $poss;
                                       }
                                   } else {
                                       $confhash{$provider}{'defaults'}{$inner} = $env{'form.proctoring_'.$inner.'_'.$provider};
                                   }
                               }
                           } else {
                               if (grep(/^\Q$field\E$/,@checked)) {
                                   push(@{$confhash{$provider}{'defaults'}},$field);
                               }
                           }
                       }
                       if (ref($confhash{$provider}{'defaults'}) eq 'ARRAY') {
                           if (ref($current{'defaults'}) eq 'ARRAY') {
                               unless ($changes{$provider}) {
                                   my @new = sort(@{$confhash{$provider}{'defaults'}});
                                   my @old = sort(@{$current{'defaults'}});
                                   my @diffs = &Apache::loncommon::compare_arrays(\@new,\@old);
                                   if (@diffs) {
                                       $changes{$provider} = 1; 
                                   }
                               }
                           } elsif (ref($current{'defaults'}) eq 'ARRAY') {
                               if (@{$current{'defaults'}}) {
                                   $changes{$provider} = 1;
                               }
                           }
                       } elsif (ref($confhash{$provider}{'defaults'}) eq 'HASH') {
                           if (ref($current{'defaults'}) eq 'HASH') {
                               unless ($changes{$provider}) {
                                   foreach my $key (keys(%{$confhash{$provider}{'defaults'}})) {
                                       unless ($confhash{$provider}{'defaults'}{$key} eq $current{'defaults'}{$key}) {
                                           $changes{$provider} = 1;
                                           last;
                                       }
                                   }
                               }
                               unless ($changes{$provider}) {
                                   foreach my $key (keys(%{$current{'defaults'}})) {
                                       unless ($current{'defaults'}{$key} eq $confhash{$provider}{'defaults'}{$key}) {
                                           $changes{$provider} = 1;
                                           last;
                                       }
                                   }
                               }
                           } elsif (keys(%{$confhash{$provider}{'defaults'}})) {
                               $changes{$provider} = 1;
                           }
                       }
                   }
               }
               if (ref($crsconf{$provider}) eq 'ARRAY') {
                   if (@{$crsconf{$provider}} > 0) {
                       $confhash{$provider}{'crsconf'} = [];
                       my @checked = &Apache::loncommon::get_env_multiple('form.proctoring_crsconf_'.$provider);
                       foreach my $crsfield (@{$crsconf{$provider}}) {
                           if (grep(/^\Q$crsfield\E$/,@checked)) {
                               push(@{$confhash{$provider}{'crsconf'}},$crsfield);
                           }
                       }
                       if (ref($current{'crsconf'}) eq 'ARRAY') {
                           unless ($changes{$provider}) {  
                               my @new = sort(@{$confhash{$provider}{'crsconf'}});
                               my @old = sort(@{$current{'crsconf'}});
                               my @diffs = &Apache::loncommon::compare_arrays(\@new,\@old);
                               if (@diffs) {
                                   $changes{$provider} = 1;
                               }
                           }
                       } elsif (@{$confhash{$provider}{'crsconf'}}) {
                           $changes{$provider} = 1;
                       }
                   }
               }
               if ($showroles) {
                   $confhash{$provider}{'roles'} = {};
                   foreach my $role (@courseroles) {
                       my $poss = $env{'form.proctoring_roles_'.$role.'_'.$provider};
                       if (grep(/^\Q$poss\E$/,@ltiroles)) {
                           $confhash{$provider}{'roles'}{$role} = $poss;
                       }
                   }
                   unless ($changes{$provider}) {
                       if (ref($current{'roles'}) eq 'HASH') {
                           foreach my $role (keys(%{$current{'roles'}})) {
                               unless ($current{'roles'}{$role} eq $confhash{$provider}{'roles'}{$role}) {
                                   $changes{$provider} = 1;
                                   last
                               }
                           }
                           unless ($changes{$provider}) {
                               foreach my $role (keys(%{$confhash{$provider}{'roles'}})) {
                                   unless ($confhash{$provider}{'roles'}{$role} eq $current{'roles'}{$role}) {
                                       $changes{$provider} = 1;
                                       last;
                                   }
                               }
                           }
                       } elsif (keys(%{$confhash{$provider}{'roles'}})) {
                           $changes{$provider} = 1;
                       }
                   }
               }
               if (ref($current{'custom'}) eq 'HASH') {
                   my @customdels = &Apache::loncommon::get_env_multiple('form.proctoring_customdel_'.$provider);
                   foreach my $key (keys(%{$current{'custom'}})) {
                       if (grep(/^\Q$key\E$/,@customdels)) {
                           $changes{$provider} = 1;
                       } else {
                           $confhash{$provider}{'custom'}{$key} = $env{'form.proctoring_customval_'.$key.'_'.$provider};
                           if ($confhash{$provider}{'custom'}{$key} ne $current{'custom'}{$key}) {
                               $changes{$provider} = 1;
                           }
                       }
                   }
               }
               if ($customadds{$provider}) {
                   my $name = $env{'form.proctoring_custom_name_'.$provider};
                   $name =~ s/(`)/'/g;
                   $name =~ s/^\s+//;
                   $name =~ s/\s+$//;
                   my $value = $env{'form.proctoring_custom_value_'.$provider};
                   $value =~ s/(`)/'/g;
                   $value =~ s/^\s+//;
                   $value =~ s/\s+$//;
                   if ($name ne '') {
                       $confhash{$provider}{'custom'}{$name} = $value;
                       $changes{$provider} = 1;
                   }
               }
           }
       }
       if (@allpos > 0) {
           my $idx = 0;
           foreach my $provider (@allpos) {
               if ($provider ne '') {
                   $confhash{$provider}{'order'} = $idx;
                   unless ($changes{$provider}) {
                       if (ref($domconfig{$action}) eq 'HASH') {
                           if (ref($domconfig{$action}{$provider}) eq 'HASH') {
                               if ($domconfig{$action}{$provider}{'order'} ne $idx) {
                                   $changes{$provider} = 1;
                               }
                           }
                       }
                   }
                   $idx ++;
               }
           }
       }
       my %proc_hash = (
                             $action => { %confhash }
                          );
       my $putresult = &Apache::lonnet::put_dom('configuration',\%proc_hash,
                                                $dom);
       if ($putresult eq 'ok') {
           my %proc_enchash = (
                                $action => { %encconfhash }
                            );
           &Apache::lonnet::put_dom('encconfig',\%proc_enchash,$dom,undef,1);
           if (keys(%changes) > 0) {
               my $cachetime = 24*60*60;
               my %procall = %confhash;
               foreach my $provider (keys(%procall)) {
                   if (ref($encconfhash{$provider}) eq 'HASH') {
                       foreach my $key ('key','secret') {
                           $procall{$provider}{$key} = $encconfhash{$provider}{$key};
                       }
                   }
               }
               &Apache::lonnet::do_cache_new('proctoring',$dom,\%procall,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'proctoring'} = 1;
               }
               $resulttext = &mt('Configuration for Provider(s) with changes:').'<ul>';
               my %bynum;
               foreach my $provider (sort(keys(%changes))) {
                   my $position = $confhash{$provider}{'order'};
                   $bynum{$position} = $provider;
               }
               foreach my $pos (sort { $a <=> $b } keys(%bynum)) {
                   my $provider = $bynum{$pos};
                   my %lt = &proctoring_titles($provider);
                   my %fieldtitles = &proctoring_fieldtitles($provider);
                   if (!$confhash{$provider}{'available'}) {
                       $resulttext .= '<li>'.&mt('Proctoring integration unavailable for: [_1]','<b>'.$providernames{$provider}.'</b>').'</li>';
                   } else {
                       $resulttext .= '<li>'.&mt('Proctoring integration available for: [_1]','<b>'.$providernames{$provider}.'</b>');
                       if ($confhash{$provider}{'image'}) {
                           $resulttext .= '&nbsp;'.
                                          '<img src="'.$confhash{$provider}{'image'}.'"'.
                                          ' alt="'.&mt('Proctoring icon').'" />';
                       }
                       $resulttext .= '<ul>';
                       my $position = $pos + 1;
                       $resulttext .= '<li>'.&mt('Order: [_1]',$position).'</li>';
                       foreach my $key ('version','sigmethod','url','lifetime') {
                           if ($confhash{$provider}{$key} ne '') {
                               $resulttext .= '<li>'.$lt{$key}.':&nbsp;'.$confhash{$provider}{$key}.'</li>';
                           }
                       }
                       if ($encconfhash{$provider}{'key'} ne '') {
                           $resulttext .= '<li>'.$lt{'key'}.':&nbsp;'.$encconfhash{$provider}{'key'}.'</li>';
                       }
                       if ($encconfhash{$provider}{'secret'} ne '') {
                           $resulttext .= '<li>'.$lt{'secret'}.':&nbsp;';
                           my $num = length($encconfhash{$provider}{'secret'});
                           $resulttext .= ('*'x$num).'</li>';
                       }
                       my (@fields,$showroles);
                       if (ref($requserfields{$provider}) eq 'ARRAY') {
                           push(@fields,@{$requserfields{$provider}});
                       }
                       if (ref($confhash{$provider}{'fields'}) eq 'ARRAY') {
                           push(@fields,@{$confhash{$provider}{'fields'}});
                       } elsif (ref($confhash{$provider}{'fields'}) eq 'HASH') {
                           push(@fields,(keys(%{$confhash{$provider}{'fields'}})));
                       }
                       if (@fields) {
                           if (grep(/^roles$/,@fields)) {
                               $showroles = 1;
                           }
                           $resulttext .= '<li>'.$lt{'udsl'}.':&nbsp;"'.
                                          join('", "', map { $lt{$_}; } @fields).'"</li>';
                       }
                       if (ref($requserfields{$provider}) eq 'ARRAY') {
                           if (grep(/^user$/,@{$requserfields{$provider}})) {
                               if ($confhash{$provider}{'incdom'}) {
                                   $resulttext .= '<li>'.&mt('[_1] sent as [_2]',$lt{'user'},$lt{'uname:dom'}).'</li>';
                               } else { 
                                   $resulttext .= '<li>'.&mt('[_1] sent as [_2]',$lt{'user'},$lt{'username'}).'</li>';
                               }
                           }
                       }
                       if (ref($confhash{$provider}{'defaults'}) eq 'ARRAY') {
                           if (@{$confhash{$provider}{'defaults'}} > 0) {
                               $resulttext .= '<li>'.$lt{'defa'};
                               foreach my $field (@{$confhash{$provider}{'defaults'}}) {
                                   $resulttext .= ' "'.$fieldtitles{$field}.'",';
                               }
                               $resulttext =~ s/,$//;
                               $resulttext .= '</li>';
                           }
                       } elsif (ref($confhash{$provider}{'defaults'}) eq 'HASH') {
                           if (keys(%{$confhash{$provider}{'defaults'}})) {
                               $resulttext .= '<li>'.$lt{'defa'}.':&nbsp;<ul>';
                               foreach my $key (sort(keys(%{$confhash{$provider}{'defaults'}}))) {
                                   if ($confhash{$provider}{'defaults'}{$key} ne '') {
                                       $resulttext .= '<li>'.$fieldtitles{$key}.' = '.$confhash{$provider}{'defaults'}{$key}.'</li>';
                                   }
                               }
                               $resulttext .= '</ul></li>';
                           }
                       }
                       if (ref($crsconf{$provider}) eq 'ARRAY') {
                           if (@{$crsconf{$provider}} > 0) {
                               $resulttext .= '<li>'.&mt('Configurable in course:');
                               my $numconfig = 0;
                               if (ref($confhash{$provider}{'crsconf'}) eq 'ARRAY') {
                                   if (@{$confhash{$provider}{'crsconf'}} > 0) {
                                       foreach my $field (@{$confhash{$provider}{'crsconf'}}) {
                                           $numconfig ++;
                                           if ($provider eq 'examity') {
                                               $resulttext .= ' "'.$lt{'crs'.$field}.'",';
                                           } else {
                                               $resulttext .= ' "'.$fieldtitles{$field}.'",';
                                           }
                                       }
                                       $resulttext =~ s/,$//;
                                   }
                               }
                               if (!$numconfig) {
                                   $resulttext .= '&nbsp;'.&mt('None');
                               }
                               $resulttext .= '</li>';
                           }
                       }
                       if ($showroles) {
                           if (ref($confhash{$provider}{'roles'}) eq 'HASH') {
                               my $rolemaps;
                               foreach my $role (@courseroles) {
                                   if ($confhash{$provider}{'roles'}{$role}) {
                                       $rolemaps .= ('&nbsp;'x2).&Apache::lonnet::plaintext($role,'Course').'='.
                                                    $confhash{$provider}{'roles'}{$role}.',';
                                   }
                               }
                               if ($rolemaps) {
                                   $rolemaps =~ s/,$//;
                                   $resulttext .= '<li>'.&mt('Role mapping:').$rolemaps.'</li>';
                               }
                           }
                       }
                       if (ref($confhash{$provider}{'custom'}) eq 'HASH') {
                           my $customlist;
                           if (keys(%{$confhash{$provider}{'custom'}})) {
                               foreach my $key (sort(keys(%{$confhash{$provider}{'custom'}}))) {
                                   $customlist .= $key.'='.$confhash{$provider}{'custom'}{$key}.', ';
                               }
                               $customlist =~ s/,$//;
                           }
                           if ($customlist) {
                               $resulttext .= '<li>'.&mt('Custom items').': '.$customlist.'</li>';
                           }
                       } 
                       $resulttext .= '</ul></li>';
                   }
               }
               $resulttext .= '</ul>';
           } else {
               $resulttext = &mt('No changes made.');
           }
       } else {
           $errors .= '<li><span class="LC_error">'.&mt('Failed to save changes').'</span></li>';
       }
       if ($errors) {
           $resulttext .= &mt('The following errors occurred: ').'<ul>'.
                          $errors.'</ul>';
       }
       return $resulttext;
   }
   
   sub process_proctoring_image {
       my ($r,$dom,$confname,$caller,$provider,$configuserok,$switchserver,$author_ok) = @_;
       my $filename = $env{'form.'.$caller.'.filename'};
       my ($error,$url);
       my ($width,$height) = (21,21);
       if ($configuserok eq 'ok') {
           if ($switchserver) {
               $error = &mt('Upload of Remote Proctoring Provider icon is not permitted to this server: [_1]',
                            $switchserver);
           } elsif ($author_ok eq 'ok') {
               my $modified = [];
               my ($result,$imageurl,$madethumb) =
                   &Apache::lonconfigsettings::publishlogo($r,'upload',$caller,$dom,$confname,
                                                           "proctoring/$provider/icon",$width,$height,
                                                           '',$modified);
               if ($result eq 'ok') {
                   if ($madethumb) {
                       my ($path,$imagefile) = ($imageurl =~ m{^(.+)/([^/]+)$});
                       my $imagethumb = "$path/tn-".$imagefile;
                       $url = $imagethumb;
                   } else {
                       $url = $imageurl;
                   }
                   &update_modify_urls($r,$modified);
               } else {
                   $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$filename,$result);
               }
           } else {
               $error = &mt("Upload of [_1] failed because an author role could not be assigned to a Domain Configuration user ([_2]) in domain: [_3].  Error was: [_4].",$filename,$confname,$dom,$author_ok);
           }
       } else {
           $error = &mt("Upload of [_1] failed because a Domain Configuration user ([_2]) could not be created in domain: [_3].  Error was: [_4].",$filename,$confname,$dom,$configuserok);
       }
       return ($url,$error);
   }
   
 sub modify_lti {  sub modify_lti {
     my ($r,$dom,$action,$lastactref,%domconfig) = @_;      my ($r,$dom,$action,$lastactref,%domconfig) = @_;
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);      my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
Line 13923  sub modify_lti { Line 15189  sub modify_lti {
         }          }
     }      }
     if (ref($currltisec{'linkprot'}) eq 'HASH') {      if (ref($currltisec{'linkprot'}) eq 'HASH') {
         foreach my $id (keys(%{$currltisec{'linkprot'}})) {          foreach my $id (%{$currltisec{'linkprot'}}) {
             next if ($id !~ /^\d+$/);              next if ($id !~ /^\d+$/);
             unless (exists($linkprotchg{$id})) {              unless (exists($linkprotchg{$id})) {
                 if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') {                  if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') {
Line 13945  sub modify_lti { Line 15211  sub modify_lti {
     if ($proterror) {      if ($proterror) {
         $errors .= '<li>'.$proterror.'</li>';          $errors .= '<li>'.$proterror.'</li>';
     }      }
   
     my (%delsuggested,%suggids,@suggested);;  
     if (ref($currltisec{'suggested'}) eq 'HASH') {  
         my $maxnum = $env{'form.linkprot_suggested_maxnum'};  
         my @todelete = &Apache::loncommon::get_env_multiple('form.linkprot_suggested_del');  
         for (my $i=0; $i<$maxnum; $i++) {  
             my $itemid = $env{'form.linkprot_suggested_id_'.$i};  
             $itemid =~ s/\D+//g;  
             if ($itemid) {  
                 if (ref($currltisec{'suggested'}->{$itemid}) eq 'HASH') {  
                     push(@suggested,$i);  
                     $suggids{$i} = $itemid;  
                     if ((@todelete > 0) && (grep(/^$i$/,@todelete))) {  
                         if (ref($currltisec{'suggested'}{$itemid}) eq 'HASH') {  
                             $delsuggested{$itemid} = $currltisec{'suggested'}{$itemid}{'name'};  
                         }  
                     } else {  
                         if ($env{'form.linkprot_suggested_name_'.$i} eq '') {  
                             $delsuggested{$itemid} = $currltisec{'suggested'}{$itemid}{'name'};  
                         } else {  
                             $env{'form.linkprot_suggested_name_'.$i} =~ s/(`)/'/g;  
                             $env{'form.linkprot_suggested_info_'.$i} =~ s/(`)/'/g;  
                             $newltisec{'suggested'}{$itemid}{'name'} = $env{'form.linkprot_suggested_name_'.$i};  
                             $newltisec{'suggested'}{$itemid}{'info'} = $env{'form.linkprot_suggested_info_'.$i};  
                             if (($currltisec{'suggested'}{$itemid}{'name'} ne $newltisec{'suggested'}{$itemid}{'name'}) ||  
                                 ($currltisec{'suggested'}{$itemid}{'info'} ne $newltisec{'suggested'}{$itemid}{'info'})) {  
                                 $secchanges{'suggested'}{$itemid} = 1;  
                             }  
                         }  
                     }  
                 }  
             }  
         }  
     }  
     foreach my $key (keys(%delsuggested)) {  
         $newltisec{'suggested'}{$key} = $delsuggested{$key};  
         $secchanges{'suggested'}{$key} = 1;  
     }  
     if (($env{'form.linkprot_suggested_add'}) &&  
         ($env{'form.linkprot_suggested_name_add'} ne '')) {  
         $env{'form.linkprot_suggested_name_add'} =~ s/(`)/'/g;  
         $env{'form.linkprot_suggested_info_add'} =~ s/(`)/'/g;  
         my ($newsuggid,$errormsg) = &get_lti_id($dom,$env{'form.linkprot_suggested_name_add'},'suggested');  
         if ($newsuggid) {  
             $newltisec{'suggested'}{$newsuggid}{'name'} = $env{'form.linkprot_suggested_name_add'};  
             $newltisec{'suggested'}{$newsuggid}{'info'} = $env{'form.linkprot_suggested_info_add'};  
             $secchanges{'suggested'}{$newsuggid} = 1;  
         } else {  
             my $error = &mt('Failed to acquire unique ID for new Link Protectors in Courses Suggestion');  
             if ($errormsg) {  
                 $error .= ' ('.$errormsg.')';  
             }  
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';  
         }  
     }  
     my (@items,%deletions,%itemids);      my (@items,%deletions,%itemids);
     if ($env{'form.lti_add'}) {      if ($env{'form.lti_add'}) {
         my $consumer = $env{'form.lti_consumer_add'};          my $consumer = $env{'form.lti_consumer_add'};
         $consumer =~ s/(`)/'/g;          $consumer =~ s/(`)/'/g;
         ($newid,my $errormsg) = &get_lti_id($dom,$consumer,'lti');          ($newid,my $error) = &get_lti_id($dom,$consumer);
         if ($newid) {          if ($newid) {
             $itemids{'add'} = $newid;              $itemids{'add'} = $newid;
             push(@items,'add');              push(@items,'add');
             $changes{$newid} = 1;              $changes{$newid} = 1;
         } else {          } else {
             my $error = &mt('Failed to acquire unique ID for new LTI configuration');              my $error = &mt('Failed to acquire unique ID for new LTI configuration');
             if ($errormsg) {  
                 $error .= ' ('.$errormsg.')';  
             }  
             $errors .= '<li><span class="LC_error">'.$error.'</span></li>';              $errors .= '<li><span class="LC_error">'.$error.'</span></li>';
         }          }
     }      }
Line 14152  sub modify_lti { Line 15360  sub modify_lti {
                     ($env{'form.lti_mapcrs_'.$idx} eq 'context_id'))  {                      ($env{'form.lti_mapcrs_'.$idx} eq 'context_id'))  {
                     $confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx};                      $confhash{$itemid}{'mapcrs'} = $env{'form.lti_mapcrs_'.$idx};
                 } elsif ($env{'form.lti_mapcrs_'.$idx} eq 'other') {                  } elsif ($env{'form.lti_mapcrs_'.$idx} eq 'other') {
                     my $mapcrs = $env{'form.lti_mapcrsfield_'.$idx};                      my $mapcrs = $env{'form.lti_mapcrsfield_'.$idx}; 
                     $mapcrs =~ s/(`)/'/g;                      $mapcrs =~ s/(`)/'/g;
                     $mapcrs =~ s/^\s+|\s+$//g;                      $mapcrs =~ s/^\s+|\s+$//g;
                     $confhash{$itemid}{'mapcrs'} = $mapcrs;                      $confhash{$itemid}{'mapcrs'} = $mapcrs;
Line 14167  sub modify_lti { Line 15375  sub modify_lti {
                 $confhash{$itemid}{'mapcrstype'} = \@crstypes;                  $confhash{$itemid}{'mapcrstype'} = \@crstypes;
                 if ($env{'form.lti_storecrs_'.$idx}) {                  if ($env{'form.lti_storecrs_'.$idx}) {
                     $confhash{$itemid}{'storecrs'} = 1;                      $confhash{$itemid}{'storecrs'} = 1;
                 }                  }       
                 if ($env{'form.lti_makecrs_'.$idx}) {                  if ($env{'form.lti_makecrs_'.$idx}) {
                     $confhash{$itemid}{'makecrs'} = 1;                      $confhash{$itemid}{'makecrs'} = 1;
                 }                  }
Line 14247  sub modify_lti { Line 15455  sub modify_lti {
                         if (ref($currlti{'maproles'}) eq 'HASH') {                          if (ref($currlti{'maproles'}) eq 'HASH') {
                             if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {                              if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') {
                                 foreach my $ltirole (keys(%{$currlti{'maproles'}})) {                                  foreach my $ltirole (keys(%{$currlti{'maproles'}})) {
                                     if ($currlti{'maproles'}{$ltirole} ne                                      if ($currlti{'maproles'}{$ltirole} ne 
                                         $confhash{$itemid}{'maproles'}{$ltirole}) {                                          $confhash{$itemid}{'maproles'}{$ltirole}) {
                                         $changes{$itemid} = 1;                                          $changes{$itemid} = 1;
                                         last;                                          last;
Line 14255  sub modify_lti { Line 15463  sub modify_lti {
                                 }                                  }
                                 unless ($changes{$itemid}) {                                  unless ($changes{$itemid}) {
                                     foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {                                      foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) {
                                         if ($confhash{$itemid}{'maproles'}{$ltirole} ne                                          if ($confhash{$itemid}{'maproles'}{$ltirole} ne 
                                             $currlti{'maproles'}{$ltirole}) {                                              $currlti{'maproles'}{$ltirole}) {
                                             $changes{$itemid} = 1;                                              $changes{$itemid} = 1;
                                             last;                                              last;
Line 14467  sub modify_lti { Line 15675  sub modify_lti {
                             $resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>';                              $resulttext .= '<li>'.&mt('LON-CAPA username').': '.$shownmapuser.'</li>';
                         }                          }
                         if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {                          if (ref($confhash{$itemid}{'makeuser'}) eq 'ARRAY') {
                             if (@{$confhash{$itemid}{'makeuser'}} > 0) {                              if (@{$confhash{$itemid}{'makeuser'}} > 0) { 
                                 $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',                                  $resulttext .= '<li>'.&mt('Following roles may create user accounts: [_1]',
                                                           join(', ',@{$confhash{$itemid}{'makeuser'}})).'<br />';                                                            join(', ',@{$confhash{$itemid}{'makeuser'}})).'<br />';
                                 if ($confhash{$itemid}{'lcauth'} eq 'lti') {                                  if ($confhash{$itemid}{'lcauth'} eq 'lti') {
Line 14562  sub modify_lti { Line 15770  sub modify_lti {
                             if ($confhash{$itemid}{'section'}) {                              if ($confhash{$itemid}{'section'}) {
                                 if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') {                                  if ($confhash{$itemid}{'section'} eq 'course_section_sourcedid') {
                                     $resulttext .= '<li>'.&mt('User section from standard field:').                                      $resulttext .= '<li>'.&mt('User section from standard field:').
                                                          ' (course_section_sourcedid)'.'</li>';                                                           ' (course_section_sourcedid)'.'</li>';  
                                 } else {                                  } else {
                                     $resulttext .= '<li>'.&mt('User section from:').' '.                                      $resulttext .= '<li>'.&mt('User section from:').' '.
                                                           $confhash{$itemid}{'section'}.'</li>';                                                            $confhash{$itemid}{'section'}.'</li>';
Line 14589  sub modify_lti { Line 15797  sub modify_lti {
                             if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {                              if (ref($confhash{$itemid}{'lcmenu'}) eq 'ARRAY') {
                                 if (@{$confhash{$itemid}{'lcmenu'}} > 0) {                                  if (@{$confhash{$itemid}{'lcmenu'}} > 0) {
                                     $resulttext .= '<li>'.&mt('Menu items:').' '.                                      $resulttext .= '<li>'.&mt('Menu items:').' '.
                                                    join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>';                                                     join(', ', map { $menutitles{$_}; } (@{$confhash{$itemid}{'lcmenu'}})).'</li>'; 
                                 } else {                                  } else {
                                     $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>';                                      $resulttext .= '<li>'.&mt('No menu items displayed in header or online menu').'</li>'; 
                                 }                                  }
                             }                              }
                         }                          }
Line 14607  sub modify_lti { Line 15815  sub modify_lti {
         }          }
         $resulttext .= '</ul>';          $resulttext .= '</ul>';
         if (ref($lastactref) eq 'HASH') {          if (ref($lastactref) eq 'HASH') {
             if (($secchanges{'encrypt'}) || ($secchanges{'private'}) || (exists($secchanges{'suggested'}))) {              if (($secchanges{'encrypt'}) || ($secchanges{'private'})) {
                 &Apache::lonnet::get_domain_defaults($dom,1);  
                 $lastactref->{'domdefaults'} = 1;                  $lastactref->{'domdefaults'} = 1;
             }              }
         }          }
Line 14627  sub get_priv_creds { Line 15834  sub get_priv_creds {
     my ($needenc,$cipher,$privnum);      my ($needenc,$cipher,$privnum);
     my %domdefs = &Apache::lonnet::get_domain_defaults($dom);      my %domdefs = &Apache::lonnet::get_domain_defaults($dom);
     if (($encchg) && (ref($encrypt) eq 'HASH')) {      if (($encchg) && (ref($encrypt) eq 'HASH')) {
         $needenc = $encrypt->{'consumers'}          $needenc = $encrypt->{'consumers'} 
     } else {      } else {
         $needenc = $domdefs{'ltienc_consumers'};          $needenc = $domdefs{'ltienc_consumers'};
     }      }
Line 14647  sub get_priv_creds { Line 15854  sub get_priv_creds {
 }  }
   
 sub get_lti_id {  sub get_lti_id {
     my ($domain,$consumer,$dbname) = @_;      my ($domain,$consumer) = @_;
     unless (($dbname eq 'lti') || ($dbname eq 'suggested')) {      # get lock on lti db
         return ('','invalid db');  
     }  
     # get lock on db  
     my $lockhash = {      my $lockhash = {
                       lock => $env{'user.name'}.                        lock => $env{'user.name'}.
                               ':'.$env{'user.domain'},                                ':'.$env{'user.domain'},
                    };                     };
     my $tries = 0;      my $tries = 0;
     my $gotlock = &Apache::lonnet::newput_dom($dbname,$lockhash,$domain);      my $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);
     my ($id,$error);      my ($id,$error);
   
     while (($gotlock ne 'ok') && ($tries<10)) {      while (($gotlock ne 'ok') && ($tries<10)) {
         $tries ++;          $tries ++;
         sleep (0.1);          sleep (0.1);
         $gotlock = &Apache::lonnet::newput_dom($dbname,$lockhash,$domain);          $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);
     }      }
     if ($gotlock eq 'ok') {      if ($gotlock eq 'ok') {
         my %currids = &Apache::lonnet::dump_dom($dbname,$domain);          my %currids = &Apache::lonnet::dump_dom('lti',$domain);
         if ($currids{'lock'}) {          if ($currids{'lock'}) {
             delete($currids{'lock'});              delete($currids{'lock'});
             if (keys(%currids)) {              if (keys(%currids)) {
Line 14678  sub get_lti_id { Line 15882  sub get_lti_id {
                 $id = 1;                  $id = 1;
             }              }
             if ($id) {              if ($id) {
                 unless (&Apache::lonnet::newput_dom($dbname,{ $id => $consumer },$domain) eq 'ok') {                  unless (&Apache::lonnet::newput_dom('lti',{ $id => $consumer },$domain) eq 'ok') {
                     $error = 'nostore';                      $error = 'nostore';
                 }                  }
             } else {              } else {
                 $error = 'nonumber';                  $error = 'nonumber';
             }              }
         }          }
         my $dellockoutcome = &Apache::lonnet::del_dom($dbname,['lock'],$domain);          my $dellockoutcome = &Apache::lonnet::del_dom('lti',['lock'],$domain);
     } else {      } else {
         $error = 'nolock';          $error = 'nolock';
     }      }
Line 15901  sub modify_contacts { Line 17105  sub modify_contacts {
         }          }
     } else {      } else {
         $resulttext = '<span class="LC_error">'.          $resulttext = '<span class="LC_error">'.
               &mt('An error occurred: [_1].',$putresult).'</span>';
       }
       return $resulttext;
   }
   
   sub modify_privacy {
       my ($dom,%domconfig) = @_;
       my ($resulttext,%current,%changes);
       if (ref($domconfig{'privacy'}) eq 'HASH') {
           %current = %{$domconfig{'privacy'}};
       }
       my @fields = ('lastname','firstname','middlename','generation','permanentemail','id');
       my @items = ('domain','author','course','community');
       my %names = &Apache::lonlocal::texthash (
                      domain => 'Assigned domain role(s)',
                      author => 'Assigned co-author role(s)',
                      course => 'Assigned course role(s)',
                      community => 'Assigned community role(s)',
                   );
       my %roles = &Apache::lonlocal::texthash (
                      domain => 'Domain role',
                      author => 'Co-author role',
                      course => 'Course role',
                      community => 'Community role',
                   );
       my %titles = &Apache::lonlocal::texthash (
                     approval => 'Approval for role in different domain',
                     othdom   => 'User information available in other domain',
                     priv     => 'Information viewable by privileged user in same domain',
                     unpriv   => 'Information viewable by unprivileged user in same domain',
                     instdom  => 'Other domain shares institution/provider',
                     extdom   => 'Other domain has different institution/provider',
                     none     => 'Not allowed',
                     user     => 'User authorizes',
                     domain   => 'Domain Coordinator authorizes',
                     auto     => 'Unrestricted',
                     notify   => 'Notify when role needs authorization',
       );
       my %fieldnames = &Apache::lonlocal::texthash (
                           id => 'Student/Employee ID',
                           permanentemail => 'E-mail address',
                           lastname => 'Last Name',
                           firstname => 'First Name',
                           middlename => 'Middle Name',
                           generation => 'Generation',
       );
       my ($othertitle,$usertypes,$types) =
           &Apache::loncommon::sorted_inst_types($dom);
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
   
       my %privacyhash = (
                          'approval' => {
                                          instdom => {},
                                          extdom  => {},
                                        },
                          'othdom'   => {},
                          'priv'     => {},
                          'unpriv'   => {},
                         );
       foreach my $item (@items) {
           if (@instdoms > 1) {
               if ($env{'form.privacy_approval_instdom_'.$item} =~ /^(none|user|domain|auto)$/) {
                   $privacyhash{'approval'}{'instdom'}{$item} = $env{'form.privacy_approval_instdom_'.$item};
               }
               if (ref($current{'approval'}) eq 'HASH') {
                   if (ref($current{'approval'}{'instdom'}) eq 'HASH') {
                       unless ($privacyhash{'approval'}{'instdom'}{$item} eq $current{'approval'}{'instdom'}{$item}) {
                           $changes{'approval'} = 1;
                       }
                   }
               } elsif ($privacyhash{'approval'}{'instdom'}{$item} ne 'auto') {
                   $changes{'approval'} = 1;
               }
           }
           if (keys(%by_location) > 0) {
               if ($env{'form.privacy_approval_extdom_'.$item} =~ /^(none|user|domain|auto)$/) {
                   $privacyhash{'approval'}{'extdom'}{$item} = $env{'form.privacy_approval_extdom_'.$item};
               }
               if (ref($current{'approval'}) eq 'HASH') {
                   if (ref($current{'approval'}{'extdom'}) eq 'HASH') {
                       unless ($privacyhash{'approval'}{'extdom'}{$item} eq $current{'approval'}{'extdom'}{$item}) {
                           $changes{'approval'} = 1;
                       }
                   }
               } elsif ($privacyhash{'approval'}{'extdom'}{$item} ne 'auto') {
                   $changes{'approval'} = 1;
               }
           }
           foreach my $status ('priv','unpriv') {
               my @possibles = sort(&Apache::loncommon::get_env_multiple('form.privacy_'.$status.'_'.$item));
               my @newvalues;
               foreach my $field (@possibles) {
                   if (grep(/^\Q$field\E$/,@fields)) {
                       $privacyhash{$status}{$item}{$field} = 1;
                       push(@newvalues,$field);
                   }
               }
               @newvalues = sort(@newvalues);
               if (ref($current{$status}) eq 'HASH') {
                   if (ref($current{$status}{$item}) eq 'HASH') {
                       my @currvalues = sort(keys(%{$current{$status}{$item}}));
                       my @diffs = &Apache::loncommon::compare_arrays(\@currvalues,\@newvalues);
                       if (@diffs > 0) {
                           $changes{$status} = 1;
                       }
                   }
               } else {
                   my @stdfields;
                   foreach my $field (@fields) {
                       if ($field eq 'id') {
                           next if ($status eq 'unpriv');
                           next if (($status eq 'priv') && ($item eq 'community'));
                       }
                       push(@stdfields,$field);
                   }
                   my @diffs = &Apache::loncommon::compare_arrays(\@stdfields,\@newvalues);
                   if (@diffs > 0) {
                       $changes{$status} = 1;
                   }
               }
           }
       }
       if ((@instdoms > 1) || (keys(%by_location) > 0)) {
           my @statuses;
           if (ref($types) eq 'ARRAY') {
               @statuses = @{$types};
           }
           foreach my $type (@statuses,'default') {
               my @possfields = &Apache::loncommon::get_env_multiple('form.privacy_othdom_'.$type);
               my @newvalues;
               foreach my $field (sort(@possfields)) {
                   if (grep(/^\Q$field\E$/,@fields)) {
                       $privacyhash{'othdom'}{$type}{$field} = 1;
                       push(@newvalues,$field);
                   }
               }
               @newvalues = sort(@newvalues);
               if (ref($current{'othdom'}) eq 'HASH') {
                   if (ref($current{'othdom'}{$type}) eq 'HASH') {
                       my @currvalues = sort(keys(%{$current{'othdom'}{$type}}));
                       my @diffs = &Apache::loncommon::compare_arrays(\@currvalues,\@newvalues);
                       if (@diffs > 0) {
                           $changes{'othdom'} = 1;
                       }
                   }
               } else {
                   my @stdfields = ('lastname','firstname','middlename','generation','permanentemail');
                   my @diffs = &Apache::loncommon::compare_arrays(\@stdfields,\@newvalues);
                   if (@diffs > 0) {
                       $changes{'othdom'} = 1;
                   }
               }
           }
           my %domcoords = &Apache::lonnet::get_active_domroles($dom,['dc']);
           my %notify;
           foreach my $possdc (&Apache::loncommon::get_env_multiple('form.privacy_notify')) {
               if (exists($domcoords{$possdc})) {
                   $notify{$possdc} = 1;
               }
           }
           my $notify = join(',',sort(keys(%notify)));
           if ($current{'notify'} ne $notify) {
               $changes{'notify'} = 1;
           }
           $privacyhash{'notify'} = $notify;
       }
       my %confighash = (
                           privacy => \%privacyhash,
                        );
       my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash,$dom);
       if ($putresult eq 'ok') {
           if (keys(%changes) > 0) {
               $resulttext = &mt('Changes made: ').'<ul>';
               foreach my $key ('approval','notify','othdom','priv','unpriv') {
                   if ($changes{$key}) {
                       $resulttext .= '<li>'.$titles{$key}.':<ul>';
                       if ($key eq 'approval') {
                           if (keys(%{$privacyhash{$key}{instdom}})) {
                               $resulttext .= '<li>'.$titles{'instdom'}.'<ul>';
                               foreach my $item (@items) {
                                   $resulttext .=  '<li>'.$roles{$item}.': '.$titles{$privacyhash{$key}{instdom}{$item}}.'</li>';
                               }
                               $resulttext .= '</ul></li>';
                           }
                           if (keys(%{$privacyhash{$key}{extdom}})) {
                               $resulttext .= '<li>'.$titles{'extdom'}.'<ul>';
                               foreach my $item (@items) {
                                   $resulttext .=  '<li>'.$roles{$item}.': '.$titles{$privacyhash{$key}{extdom}{$item}}.'</li>';
                               }
                               $resulttext .= '</ul></li>';
                           }
                       } elsif ($key eq 'notify') {
                           if ($privacyhash{$key}) {
                               foreach my $dc (split(/,/,$privacyhash{$key})) {
                                   my ($dcname,$dcdom) = split(/:/,$dc);
                                   $resulttext .= '<li>'.&Apache::loncommon::plainname($dcname,$dcdom).'</li>';
                               }
                           } else {
                               $resulttext .= '<li>'.&mt('No DCs to notify').'</li>';
                           }
                       } elsif ($key eq 'othdom') {
                           my @statuses;
                           if (ref($types) eq 'ARRAY') {
                               @statuses = @{$types};
                           }
                           if (ref($privacyhash{$key}) eq 'HASH') {
                               foreach my $status (@statuses,'default') {
                                   if ($status eq 'default') {
                                       $resulttext .= '<li>'.$othertitle.': ';
                                   } elsif (ref($usertypes) eq 'HASH') {
                                       $resulttext .= '<li>'.$usertypes->{$status}.': ';
                                   } else {
                                       next;
                                   }
                                   if (ref($privacyhash{$key}{$status}) eq 'HASH') {
                                       if (keys(%{$privacyhash{$key}{$status}})) {
                                           $resulttext .= join(', ', map { $fieldnames{$_}; } (sort(keys(%{$privacyhash{$key}{$status}}))));
                                       } else {
                                           $resulttext .= &mt('none');
                                       }
                                   }
                                   $resulttext .= '</li>';
                               }
                           }
                       } else {
                           foreach my $item (@items) {
                               if (ref($privacyhash{$key}{$item}) eq 'HASH') {
                                   $resulttext .= '<li>'.$names{$item}.': ';
                                   if (keys(%{$privacyhash{$key}{$item}})) {
                                       $resulttext .= join(', ', map { $fieldnames{$_}; } (sort(keys(%{$privacyhash{$key}{$item}}))));
                                   } else {
                                       $resulttext .= &mt('none');
                                   }
                                   $resulttext .= '</li>';
                               }
                           }
                       }
                       $resulttext .= '</ul></li>';
                   }
               }
               $resulttext .= '</ul>';
           } else {
               $resulttext = &mt('No changes made to user information settings');
           }
       } else {
           $resulttext = '<span class="LC_error">'.
             &mt('An error occurred: [_1]',$putresult).'</span>';              &mt('An error occurred: [_1]',$putresult).'</span>';
     }      }
     return $resulttext;      return $resulttext;
Line 15931  sub modify_passwords { Line 17382  sub modify_passwords {
         min            => 'Minimum password length',          min            => 'Minimum password length',
         max            => 'Maximum password length',          max            => 'Maximum password length',
         chars          => 'Required characters',          chars          => 'Required characters',
           expire         => 'Password expiration (days)',
         numsaved       => 'Number of previous passwords to save',          numsaved       => 'Number of previous passwords to save',
         reset          => 'Resetting Forgotten Password',          reset          => 'Resetting Forgotten Password',
         intauth        => 'Encryption of Stored Passwords (Internal Auth)',          intauth        => 'Encryption of Stored Passwords (Internal Auth)',
Line 16314  sub modify_passwords { Line 17766  sub modify_passwords {
                             $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$titles{$key.'_'.$item},$value).'</li>';                              $resulttext .= '<li>'.&mt('[_1] set to "[_2]"',$titles{$key.'_'.$item},$value).'</li>';
                         }                          }
                     } elsif ($key eq 'rules') {                      } elsif ($key eq 'rules') {
                         foreach my $rule ('min','max','numsaved') {                          foreach my $rule ('min','max','expire','numsaved') {
                             if ($confighash{'passwords'}{$rule} eq '') {                              if ($confighash{'passwords'}{$rule} eq '') {
                                 if ($rule eq 'min') {                                  if ($rule eq 'min') {
                                     $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});                                      $resulttext .= '<li>'.&mt('[_1] not set.',$titles{$rule});
Line 16409  sub password_rule_changes { Line 17861  sub password_rule_changes {
                    (ref($changes) eq 'HASH'));                     (ref($changes) eq 'HASH'));
     my (@rules,%staticdefaults);      my (@rules,%staticdefaults);
     if ($prefix eq 'passwords') {      if ($prefix eq 'passwords') {
         @rules = ('min','max','numsaved');          @rules = ('min','max','expire','numsaved');
     } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {      } elsif (($prefix eq 'ltisecrets') || ($prefix eq 'toolsecrets')) {
         @rules = ('min','max');          @rules = ('min','max');
     }      }
Line 16417  sub password_rule_changes { Line 17869  sub password_rule_changes {
     foreach my $rule (@rules) {      foreach my $rule (@rules) {
         $env{'form.'.$prefix.'_'.$rule} =~ s/^\s+|\s+$//g;          $env{'form.'.$prefix.'_'.$rule} =~ s/^\s+|\s+$//g;
         my $ruleok;          my $ruleok;
         if ($rule eq 'min') {          if ($rule eq 'expire') {
               if (($env{'form.'.$prefix.'_'.$rule} =~ /^\d+(|\.\d*)$/) &&
                   ($env{'form.'.$prefix.'_'.$rule} ne '0')) {
                   $ruleok = 1;
               }
           } elsif ($rule eq 'min') {
             if ($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) {              if ($env{'form.'.$prefix.'_'.$rule} =~ /^\d+$/) {
                 if ($env{'form.'.$prefix.'_'.$rule} >= $staticdefaults{$rule}) {                  if ($env{'form.'.$prefix.'_'.$rule} >= $staticdefaults{$rule}) {
                     $ruleok = 1;                      $ruleok = 1;
Line 17901  sub modify_defaults { Line 19358  sub modify_defaults {
     my @allpos;      my @allpos;
     my %alltypes;      my %alltypes;
     my @inststatusguest;      my @inststatusguest;
     if (ref($currinststatus) eq 'HASH') {      if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {
         if (ref($currinststatus->{'inststatusguest'}) eq 'ARRAY') {          foreach my $type (@{$currinststatus->{'inststatusguest'}}) {
             foreach my $type (@{$currinststatus->{'inststatusguest'}}) {              unless (grep(/^\Q$type\E$/,@todelete)) {
                 unless (grep(/^\Q$type\E$/,@todelete)) {                  push(@inststatusguest,$type);
                     push(@inststatusguest,$type);  
                 }  
             }              }
         }          }
     }      }
Line 18258  sub modify_scantron { Line 19713  sub modify_scantron {
                 &mt('An error occurred: [_1]',$putresult).'</span>';                  &mt('An error occurred: [_1]',$putresult).'</span>';
         }          }
     } else {      } else {
         $resulttext = &mt('No changes made to bubblesheet format settings');          $resulttext = &mt('No changes made to bubblesheet format file'); 
     }      }
     if ($errors) {      if ($errors) {
         $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.          $resulttext .= '<p>'.&mt('The following errors occurred: ').'<ul>'.
Line 18291  sub modify_coursecategories { Line 19746  sub modify_coursecategories {
         if ($domconfig{'coursecategories'}{'categorizecomm'} ne $env{'form.categorizecomm'}) {          if ($domconfig{'coursecategories'}{'categorizecomm'} ne $env{'form.categorizecomm'}) {
             $changes{'categorizecomm'} = 1;              $changes{'categorizecomm'} = 1;
             $domconfig{'coursecategories'}{'categorizecomm'} = $env{'form.categorizecomm'};              $domconfig{'coursecategories'}{'categorizecomm'} = $env{'form.categorizecomm'};
   
           }
           if ($domconfig{'coursecategories'}{'togglecatsplace'} ne $env{'form.togglecatsplace'}) {
               $changes{'togglecatsplace'} = 1;
               $domconfig{'coursecategories'}{'togglecatsplace'} = $env{'form.togglecatsplace'};
           }
           if ($domconfig{'coursecategories'}{'categorizeplace'} ne $env{'form.categorizeplace'}) {
               $changes{'categorizeplace'} = 1;
               $domconfig{'coursecategories'}{'categorizeplace'} = $env{'form.categorizeplace'};
         }          }
         foreach my $item (@catitems) {          foreach my $item (@catitems) {
             if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) {              if (grep(/^\Q$env{'form.coursecat_'.$item}\E$/,@cattypes)) {
Line 18305  sub modify_coursecategories { Line 19769  sub modify_coursecategories {
         $changes{'categorize'} = 1;          $changes{'categorize'} = 1;
         $changes{'togglecatscomm'} = 1;          $changes{'togglecatscomm'} = 1;
         $changes{'categorizecomm'} = 1;          $changes{'categorizecomm'} = 1;
           $changes{'togglecatsplace'} = 1;
           $changes{'categorizeplace'} = 1;
         $domconfig{'coursecategories'} = {          $domconfig{'coursecategories'} = {
                                              togglecats => $env{'form.togglecats'},                                               togglecats => $env{'form.togglecats'},
                                              categorize => $env{'form.categorize'},                                               categorize => $env{'form.categorize'},
                                              togglecatscomm => $env{'form.togglecatscomm'},                                               togglecatscomm => $env{'form.togglecatscomm'},
                                              categorizecomm => $env{'form.categorizecomm'},                                               categorizecomm => $env{'form.categorizecomm'},
                                                togglecatsplace => $env{'form.togglecatsplace'},
                                                categorizeplace => $env{'form.categorizeplace'},
                                          };                                           };
         foreach my $item (@catitems) {          foreach my $item (@catitems) {
             if ($env{'form.coursecat_'.$item} ne 'std') {              if ($env{'form.coursecat_'.$item} ne 'std') {
Line 18327  sub modify_coursecategories { Line 19795  sub modify_coursecategories {
         if (($domconfig{'coursecategories'}{'cats'}{'communities::0'} ne '')  && ($env{'form.communities'} == 0)) {          if (($domconfig{'coursecategories'}{'cats'}{'communities::0'} ne '')  && ($env{'form.communities'} == 0)) {
             push(@deletecategory,'communities::0');              push(@deletecategory,'communities::0');
         }          }
           if (($domconfig{'coursecategories'}{'cats'}{'placement::0'} ne '')  && ($env{'form.placement'} == 0)) {
               push(@deletecategory,'placement::0');
           }
     }      }
     my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail);      my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail);
     if (ref($cathash) eq 'HASH') {      if (ref($cathash) eq 'HASH') {
Line 18389  sub modify_coursecategories { Line 19860  sub modify_coursecategories {
             $adds{$newitem} = 1;              $adds{$newitem} = 1;
         }          }
     }      }
       if ($env{'form.placement'} eq '1') {
           if (ref($cathash) eq 'HASH') {
               my $newitem = 'placement::0';
               if ($cathash->{$newitem} eq '') {
                   $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'};
                   $adds{$newitem} = 1;
               }
           } else {
               my $newitem = 'placement::0';
               $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.placement_pos'};
               $adds{$newitem} = 1;
           }
       }
     if ($env{'form.addcategory_name'} ne '') {      if ($env{'form.addcategory_name'} ne '') {
         if (($env{'form.addcategory_name'} ne 'instcode') &&          if (($env{'form.addcategory_name'} ne 'instcode') &&
             ($env{'form.addcategory_name'} ne 'communities')) {              ($env{'form.addcategory_name'} ne 'communities') &&
               ($env{'form.addcategory_name'} ne 'placement')) {
             my $newitem = &escape($env{'form.addcategory_name'}).'::0';              my $newitem = &escape($env{'form.addcategory_name'}).'::0';
             $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'};              $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'};
             $adds{$newitem} = 1;              $adds{$newitem} = 1;
Line 18990  sub modify_coursedefaults { Line 20475  sub modify_coursedefaults {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,$errors,%changes,%defaultshash);      my ($resulttext,$errors,%changes,%defaultshash);
     my %defaultchecked = (      my %defaultchecked = (
                              'canuse_pdfforms' => 'off',
                            'uselcmath'       => 'on',                             'uselcmath'       => 'on',
                            'usejsme'         => 'on',                             'usejsme'         => 'on',
                            'inline_chem'     => 'on',                             'inline_chem'     => 'on',
                            'ltiauth'         => 'off',                             'ltiauth'         => 'off',
                          );                           );
     my @toggles = ('uselcmath','usejsme','inline_chem','ltiauth');      my @toggles = ('canuse_pdfforms','uselcmath','usejsme','inline_chem','ltiauth');
     my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',      my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',
                    'uploadquota_community','uploadquota_textbook','coursequota_official',                     'uploadquota_community','uploadquota_textbook','uploadquota_placement',
                    'coursequota_unofficial','coursequota_community','coursequota_textbook',  
                    'mysqltables_official','mysqltables_unofficial','mysqltables_community',                     'mysqltables_official','mysqltables_unofficial','mysqltables_community',
                    'mysqltables_textbook');                     'mysqltables_textbook','mysqltables_placement');
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     my %staticdefaults = (      my %staticdefaults = (
                            anonsurvey_threshold => 10,                             anonsurvey_threshold => 10,
                            uploadquota          => 500,                             uploadquota          => 500,
                            coursequota          => 20,  
                            postsubmit           => 60,                             postsubmit           => 60,
                            mysqltables          => 172800,                             mysqltables          => 172800,
                            domexttool           => 1,                             domexttool           => 1,
Line 19053  sub modify_coursedefaults { Line 20537  sub modify_coursedefaults {
                 }                  }
                 $defaultshash{'coursedefaults'}{$item} = $newdef;                  $defaultshash{'coursedefaults'}{$item} = $newdef;
             } else {              } else {
                 my ($setting,$type) = ($item =~ /^(uploadquota|coursequota|mysqltables)_(\w+)$/);                  my ($setting,$type) = ($item =~ /^(uploadquota|mysqltables)_(\w+)$/);
                 if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {                  if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {
                     $currdef = $domconfig{'coursedefaults'}{$setting}{$type};                      $currdef = $domconfig{'coursedefaults'}{$setting}{$type};
                 }                  }
Line 19065  sub modify_coursedefaults { Line 20549  sub modify_coursedefaults {
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {                      unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {
                         $changes{$item} = 1;                          $changes{$item} = 1;
                     }                      }
                 } elsif ($item =~ /^(uploadquota|coursequota|mysqltables)_/) {                  } elsif ($item =~ /^(uploadquota|mysqltables)_/) {
                     my $setting = $1;                      my $setting = $1;
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {                      unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {
                         $changes{$setting} = 1;                          $changes{$setting} = 1;
Line 19247  sub modify_coursedefaults { Line 20731  sub modify_coursedefaults {
     if ($putresult eq 'ok') {      if ($putresult eq 'ok') {
         if (keys(%changes) > 0) {          if (keys(%changes) > 0) {
             my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);              my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
             if (($changes{'uploadquota'}) || ($changes{'postsubmit'}) ||              if (($changes{'canuse_pdfforms'}) || ($changes{'uploadquota'}) || ($changes{'postsubmit'}) ||
                 ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) ||                  ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) ||
                 ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'}) ||                  ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'}) ||
                 ($changes{'inline_chem'}) || ($changes{'ltiauth'}) || ($changes{'domexttool'}) ||                  ($changes{'inline_chem'}) || ($changes{'ltiauth'}) || ($changes{'domexttool'}) ||
                 ($changes{'exttool'}) || ($changes{'coursequota'})) {                  ($changes{'exttool'}) ) {
                 foreach my $item ('uselcmath','usejsme','inline_chem','texengine','ltiauth') {                  foreach my $item ('canuse_pdfforms','uselcmath','usejsme','inline_chem','texengine',
                                     'ltiauth') {
                     if ($changes{$item}) {                      if ($changes{$item}) {
                         $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};                          $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item};
                     }                      }
Line 19283  sub modify_coursedefaults { Line 20768  sub modify_coursedefaults {
                         }                          }
                     }                      }
                 }                  }
                 if ($changes{'coursequota'}) {  
                     if (ref($defaultshash{'coursedefaults'}{'coursequota'}) eq 'HASH') {  
                         foreach my $type (@types) {  
                             $domdefaults{$type.'coursequota'}=$defaultshash{'coursedefaults'}{'coursequota'}{$type};  
                         }  
                     }  
                 }  
                 if ($changes{'canclone'}) {                  if ($changes{'canclone'}) {
                     if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {                      if (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {
                         if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {                          if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {
Line 19324  sub modify_coursedefaults { Line 20802  sub modify_coursedefaults {
             }              }
             $resulttext = &mt('Changes made:').'<ul>';              $resulttext = &mt('Changes made:').'<ul>';
             foreach my $item (sort(keys(%changes))) {              foreach my $item (sort(keys(%changes))) {
                 if ($item eq 'uselcmath') {                  if ($item eq 'canuse_pdfforms') {
                       if ($env{'form.'.$item} eq '1') {
                           $resulttext .= '<li>'.&mt("Course/Community users can create/upload PDF forms set to 'on'").'</li>';
                       } else {
                           $resulttext .= '<li>'.&mt('Course/Community users can create/upload PDF forms set to "off"').'</li>';
                       }
                   } elsif ($item eq 'uselcmath') {
                     if ($env{'form.'.$item} eq '1') {                      if ($env{'form.'.$item} eq '1') {
                         $resulttext .= '<li>'.&mt('Math preview uses LON-CAPA previewer (javascript), if supported by browser.').'</li>';                          $resulttext .= '<li>'.&mt('Math preview uses LON-CAPA previewer (javascript), if supported by browser.').'</li>';
                     } else {                      } else {
Line 19355  sub modify_coursedefaults { Line 20839  sub modify_coursedefaults {
                                        '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'</b>').'</li>'.                                         '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'</b>').'</li>'.
                                        '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'</b>').'</li>'.                                         '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'</b>').'</li>'.
                                        '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'textbook'}.'</b>').'</li>'.                                         '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'textbook'}.'</b>').'</li>'.
                                          '<li>'.&mt('Placement tests: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'placement'}.'</b>').'</li>'. 
                                        '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'</b>').'</li>'.                                         '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'</b>').'</li>'.
                                        '</ul>'.                                         '</ul>'.
                                        '</li>';                                         '</li>';
                     } else {                      } else {
                         $resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>';                          $resulttext .= '<li>'.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'</li>';
                     }                      }
                 } elsif ($item eq 'coursequota') {  
                     if (ref($defaultshash{'coursedefaults'}{'coursequota'}) eq 'HASH') {  
                         $resulttext .= '<li>'.&mt('Default cumulative quota for all group portfolio spaces in course set as follows:').'<ul>'.  
                                        '<li>'.&mt('Official courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'official'}.'</b>').'</li>'.  
                                        '<li>'.&mt('Unofficial courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'unofficial'}.'</b>').'</li>'.  
                                        '<li>'.&mt('Textbook courses: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'textbook'}.'</b>').'</li>'.  
                                        '<li>'.&mt('Communities: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'community'}.'</b>').'</li>'.  
                                        '</ul>'.  
                                        '</li>';  
                     } else {  
                         $resulttext .= '<li>'.&mt('Default cumulative quota for all group portfolio spaces in course remains default: [_1] MB',$staticdefaults{'coursequota'}).'</li>';  
                     }  
                 } elsif ($item eq 'mysqltables') {                  } elsif ($item eq 'mysqltables') {
                     if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {                      if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {
                         $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'.                          $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'.
                                        '<li>'.&mt('Official courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'official'}.'</b>').'</li>'.                                         '<li>'.&mt('Official courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'official'}.'</b>').'</li>'.
                                        '<li>'.&mt('Unofficial courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'unofficial'}.'</b>').'</li>'.                                         '<li>'.&mt('Unofficial courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'unofficial'}.'</b>').'</li>'.
                                        '<li>'.&mt('Textbook courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'textbook'}.'</b>').'</li>'.                                         '<li>'.&mt('Textbook courses: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'textbook'}.'</b>').'</li>'.
                                          '<li>'.&mt('Placement tests: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'placement'}.'</b>').'</li>'.
                                        '<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'.                                         '<li>'.&mt('Communities: [_1] s','<b>'.$defaultshash{'coursedefaults'}{'mysqltables'}{'community'}.'</b>').'</li>'.
                                        '</ul>'.                                         '</ul>'.
                                        '</li>';                                         '</li>';
Line 19414  sub modify_coursedefaults { Line 20888  sub modify_coursedefaults {
                                     $resulttext .= &mt('Unofficial courses');                                      $resulttext .= &mt('Unofficial courses');
                                 } elsif ($type eq 'textbook') {                                  } elsif ($type eq 'textbook') {
                                     $resulttext .= &mt('Textbook courses');                                      $resulttext .= &mt('Textbook courses');
                                   } elsif ($type eq 'placement') {
                                       $resulttext .= &mt('Placement tests');
                                 }                                  }
                                 $resulttext .= ' -- '.$display.'</li>';                                  $resulttext .= ' -- '.$display.'</li>';
                             }                              }
Line 19499  sub modify_coursedefaults { Line 20975  sub modify_coursedefaults {
 sub modify_selfenrollment {  sub modify_selfenrollment {
     my ($dom,$lastactref,%domconfig) = @_;      my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,$errors,%changes,%selfenrollhash,%ordered);      my ($resulttext,$errors,%changes,%selfenrollhash,%ordered);
     my @types = ('official','unofficial','community','textbook');      my @types = ('official','unofficial','community','textbook','placement');
     my %titles = &tool_titles();      my %titles = &tool_titles();
     my %descs = &Apache::lonuserutils::selfenroll_default_descs();      my %descs = &Apache::lonuserutils::selfenroll_default_descs();
     ($ordered{'admin'},my $titlesref) = &Apache::lonuserutils::get_selfenroll_titles();      ($ordered{'admin'},my $titlesref) = &Apache::lonuserutils::get_selfenroll_titles();
Line 20085  sub modify_usersessions { Line 21561  sub modify_usersessions {
                 );                  );
     my @prefixes = ('remote','hosted','spares');      my @prefixes = ('remote','hosted','spares');
     my @lcversions = &Apache::lonnet::all_loncaparevs();      my @lcversions = &Apache::lonnet::all_loncaparevs();
     my (%by_ip,%by_location,@intdoms);      my (%by_ip,%by_location,@intdoms,@instdoms);
     &build_location_hashes(\@intdoms,\%by_ip,\%by_location);      &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
     my @locations = sort(keys(%by_location));      my @locations = sort(keys(%by_location));
     my (%defaultshash,%changes);      my (%defaultshash,%changes);
     foreach my $prefix (@prefixes) {      foreach my $prefix (@prefixes) {
Line 20375  sub modify_usersessions { Line 21851  sub modify_usersessions {
                         } else {                          } else {
                             foreach my $type (@{$types{$prefix}}) {                              foreach my $type (@{$types{$prefix}}) {
                                 if (defined($changes{$prefix}{$type})) {                                  if (defined($changes{$prefix}{$type})) {
                                     my $newvalue;                                      my ($newvalue,$notinuse);
                                     if (ref($defaultshash{'usersessions'}) eq 'HASH') {                                      if (ref($defaultshash{'usersessions'}) eq 'HASH') {
                                         if (ref($defaultshash{'usersessions'}{$prefix})) {                                          if (ref($defaultshash{'usersessions'}{$prefix})) {
                                             if ($type eq 'version') {                                              if ($type eq 'version') {
                                                 $newvalue = $defaultshash{'usersessions'}{$prefix}{$type};                                                  $newvalue = $defaultshash{'usersessions'}{$prefix}{$type};
                                             } elsif (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') {                                              } else {
                                                 if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) {                                                  if (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') {
                                                     $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}});                                                      if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) {
                                                           $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}});
                                                       }
                                                   } else {
                                                       $notinuse = 1;
                                                 }                                                  }
                                             }                                              }
                                         }                                          }
Line 20390  sub modify_usersessions { Line 21870  sub modify_usersessions {
                                     if ($newvalue eq '') {                                      if ($newvalue eq '') {
                                         if ($type eq 'version') {                                          if ($type eq 'version') {
                                             $resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>';                                              $resulttext .= '<li>'.&mt('[_1] set to: off',$lt{$type}).'</li>';
                                           } elsif ($notinuse) {
                                               $resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>';
                                         } else {                                          } else {
                                             $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';                                              $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
                                         }                                          }
Line 20449  sub modify_usersessions { Line 21931  sub modify_usersessions {
     return $resulttext;      return $resulttext;
 }  }
   
   sub modify_ssl {
       my ($dom,$lastactref,%domconfig) = @_;
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my @locations = sort(keys(%by_location));
       my %servers = &Apache::lonnet::internet_dom_servers($dom);
       my (%defaultshash,%changes);
       my $action = 'ssl';
       my @prefixes = ('connto','connfrom','replication');
       foreach my $prefix (@prefixes) {
           $defaultshash{$action}{$prefix} = {};
       }
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my $resulttext;
       my %iphost = &Apache::lonnet::get_iphost();
       my @reptypes = ('certreq','nocertreq');
       my @connecttypes = ('dom','intdom','other');
       my %types = (
                     connto      => \@connecttypes,
                     connfrom    => \@connecttypes,
                     replication => \@reptypes,
                   );
       foreach my $prefix (sort(keys(%types))) {
           foreach my $type (@{$types{$prefix}}) {
               if (($prefix eq 'connto') || ($prefix eq 'connfrom')) {
                   my $value = 'yes';
                   if ($env{'form.'.$prefix.'_'.$type} =~ /^(no|req)$/) {
                       $value = $env{'form.'.$prefix.'_'.$type};
                   }
                   if (ref($domconfig{$action}) eq 'HASH') {
                       if (ref($domconfig{$action}{$prefix}) eq 'HASH') {
                           if ($domconfig{$action}{$prefix}{$type} ne '') {
                               if ($value ne $domconfig{$action}{$prefix}{$type}) {
                                   $changes{$prefix}{$type} = 1;
                               }
                               $defaultshash{$action}{$prefix}{$type} = $value;
                           } else {
                               $defaultshash{$action}{$prefix}{$type} = $value;
                               $changes{$prefix}{$type} = 1;
                           }
                       } else {
                           $defaultshash{$action}{$prefix}{$type} = $value;
                           $changes{$prefix}{$type} = 1;
                       }
                   } else {
                       $defaultshash{$action}{$prefix}{$type} = $value;
                       $changes{$prefix}{$type} = 1;
                   }
                   if (($type eq 'dom') && (keys(%servers) == 1)) {
                       delete($changes{$prefix}{$type});
                   } elsif (($type eq 'intdom') && (@instdoms == 1)) {
                       delete($changes{$prefix}{$type});
                   } elsif (($type eq 'other') && (keys(%by_location) == 0)) { 
                       delete($changes{$prefix}{$type});
                   }
               } elsif ($prefix eq 'replication') {
                   if (@locations > 0) {
                       my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
                       my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
                       my @okvals;
                       foreach my $val (@vals) {
                           if ($val =~ /:/) {
                               my @items = split(/:/,$val);
                               foreach my $item (@items) {
                                   if (ref($by_location{$item}) eq 'ARRAY') {
                                       push(@okvals,$item);
                                   }
                               }
                           } else {
                               if (ref($by_location{$val}) eq 'ARRAY') {
                                   push(@okvals,$val);
                               }
                           }
                       }
                       @okvals = sort(@okvals);
                       if (ref($domconfig{$action}) eq 'HASH') {
                           if (ref($domconfig{$action}{$prefix}) eq 'HASH') {
                               if (ref($domconfig{$action}{$prefix}{$type}) eq 'ARRAY') {
                                   if ($inuse == 0) {
                                       $changes{$prefix}{$type} = 1;
                                   } else {
                                       $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                       my @changed = &Apache::loncommon::compare_arrays($domconfig{$action}{$prefix}{$type},$defaultshash{$action}{$prefix}{$type});
                                       if (@changed > 0) {
                                           $changes{$prefix}{$type} = 1;
                                       }
                                   }
                               } else {
                                   if ($inuse == 1) {
                                       $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                       $changes{$prefix}{$type} = 1;
                                   }
                               }
                           } else {
                               if ($inuse == 1) {
                                   $defaultshash{$action}{$prefix}{$type} = \@okvals;
                                   $changes{$prefix}{$type} = 1;
                               }
                           }
                       } else {
                           if ($inuse == 1) {
                               $defaultshash{$action}{$prefix}{$type} = \@okvals;
                               $changes{$prefix}{$type} = 1;
                           }
                       }
                   }
               }
           }
       }
       if (keys(%changes)) {
           foreach my $prefix (keys(%changes)) {
               if (ref($changes{$prefix}) eq 'HASH') {
                   if (scalar(keys(%{$changes{$prefix}})) == 0) {
                       delete($changes{$prefix});
                   }
               } else {
                   delete($changes{$prefix});
               }
           }
       }
       my $nochgmsg = &mt('No changes made to LON-CAPA SSL settings');
       if (keys(%changes) > 0) {
           my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                                    $dom);
           if ($putresult eq 'ok') {
               if (ref($defaultshash{$action}) eq 'HASH') {
                   if (ref($defaultshash{$action}{'replication'}) eq 'HASH') {
                       $domdefaults{'replication'} = $defaultshash{$action}{'replication'};
                   }
                   if (ref($defaultshash{$action}{'connto'}) eq 'HASH') {
                       $domdefaults{'connto'} = $defaultshash{$action}{'connto'};
                   }
                   if (ref($defaultshash{$action}{'connfrom'}) eq 'HASH') {
                       $domdefaults{'connfrom'} = $defaultshash{$action}{'connfrom'};
                   }
               }
               my $cachetime = 24*60*60;
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
               }
               if (keys(%changes) > 0) {
                   my %titles = &ssl_titles();
                   $resulttext = &mt('Changes made:').'<ul>';
                   foreach my $prefix (@prefixes) {
                       if (ref($changes{$prefix}) eq 'HASH') {
                           $resulttext .= '<li>'.$titles{$prefix}.'<ul>';
                           foreach my $type (@{$types{$prefix}}) {
                               if (defined($changes{$prefix}{$type})) {
                                   my ($newvalue,$notinuse);
                                   if (ref($defaultshash{$action}) eq 'HASH') {
                                       if (ref($defaultshash{$action}{$prefix})) {
                                           if (($prefix eq 'connto') || ($prefix eq 'connfrom')) {
                                               $newvalue = $titles{$defaultshash{$action}{$prefix}{$type}};
                                           } else {
                                               if (ref($defaultshash{$action}{$prefix}{$type}) eq 'ARRAY') {
                                                   if (@{$defaultshash{$action}{$prefix}{$type}} > 0) {
                                                       $newvalue = join(', ',@{$defaultshash{$action}{$prefix}{$type}});
                                                   }
                                               } else {
                                                   $notinuse = 1;
                                               }
                                           }
                                       }
                                       if ($notinuse) {
                                           $resulttext .= '<li>'.&mt('[_1] set to: not in use',$titles{$type}).'</li>';
                                       } elsif ($newvalue eq '') {
                                           $resulttext .= '<li>'.&mt('[_1] set to: none',$titles{$type}).'</li>';
                                       } else {
                                           $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$titles{$type},$newvalue).'</li>';
                                       }
                                   }
                               }
                           }
                           $resulttext .= '</ul>';
                       }
                   }
               } else {
                   $resulttext = $nochgmsg;
               }
           } else {
               $resulttext = '<span class="LC_error">'.
                             &mt('An error occurred: [_1]',$putresult).'</span>';
           }
       } else {
           $resulttext = $nochgmsg;
       }
       return $resulttext;
   }
   
   sub modify_trust {
       my ($dom,$lastactref,%domconfig) = @_;
       my (%by_ip,%by_location,@intdoms,@instdoms);
       &build_location_hashes(\@intdoms,\%by_ip,\%by_location,\@instdoms);
       my @locations = sort(keys(%by_location));
       my @prefixes = qw(content shared enroll othcoau coaurem domroles catalog reqcrs msg);
       my @types = ('exc','inc');
       my (%defaultshash,%changes);
       foreach my $prefix (@prefixes) {
           $defaultshash{'trust'}{$prefix} = {};
       }
       my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
       my $resulttext;
       foreach my $prefix (@prefixes) {
           foreach my $type (@types) {
               my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'};
               my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type);
               my @okvals;
               foreach my $val (@vals) {
                   if ($val =~ /:/) {
                       my @items = split(/:/,$val);
                       foreach my $item (@items) {
                           if (ref($by_location{$item}) eq 'ARRAY') {
                               push(@okvals,$item);
                           }
                       }
                   } else {
                       if (ref($by_location{$val}) eq 'ARRAY') {
                           push(@okvals,$val);
                       }
                   }
               }
               @okvals = sort(@okvals);
               if (ref($domconfig{'trust'}) eq 'HASH') {
                   if (ref($domconfig{'trust'}{$prefix}) eq 'HASH') {
                       if (ref($domconfig{'trust'}{$prefix}{$type}) eq 'ARRAY') {
                           if ($inuse == 0) {
                               $changes{$prefix}{$type} = 1;
                           } else {
                               $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                               my @changed = &Apache::loncommon::compare_arrays($domconfig{'trust'}{$prefix}{$type},$defaultshash{'trust'}{$prefix}{$type});
                               if (@changed > 0) {
                                   $changes{$prefix}{$type} = 1;
                               }
                           }
                       } else {
                           if ($inuse == 1) {
                               $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                               $changes{$prefix}{$type} = 1;
                           }
                       }
                   } else {
                       if ($inuse == 1) {
                           $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                           $changes{$prefix}{$type} = 1;
                       }
                   }
               } else {
                   if ($inuse == 1) {
                       $defaultshash{'trust'}{$prefix}{$type} = \@okvals;
                       $changes{$prefix}{$type} = 1;
                   }
               }
           }
       }
       my $nochgmsg = &mt('No changes made to trust settings.');
       if (keys(%changes) > 0) {
           my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                                    $dom);
           if ($putresult eq 'ok') {
               if (ref($defaultshash{'trust'}) eq 'HASH') {
                   foreach my $prefix (@prefixes) {
                       if (ref($defaultshash{'trust'}{$prefix}) eq 'HASH') {
                           $domdefaults{'trust'.$prefix} = $defaultshash{'trust'}{$prefix};
                       }
                   }
               }
               my $cachetime = 24*60*60;
               &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
               &Apache::lonnet::do_cache_new('trust',$dom,$defaultshash{'trust'},3600);
               if (ref($lastactref) eq 'HASH') {
                   $lastactref->{'domdefaults'} = 1;
                   $lastactref->{'trust'} = 1;
               }
               if (keys(%changes) > 0) {
                   my %lt = &trust_titles();
                   $resulttext = &mt('Changes made:').'<ul>';
                   foreach my $prefix (@prefixes) {
                       if (ref($changes{$prefix}) eq 'HASH') {
                           $resulttext .= '<li>'.$lt{$prefix}.'<ul>';
                           foreach my $type (@types) {
                               if (defined($changes{$prefix}{$type})) {
                                   my ($newvalue,$notinuse);
                                   if (ref($defaultshash{'trust'}) eq 'HASH') {
                                       if (ref($defaultshash{'trust'}{$prefix})) {
                                           if (ref($defaultshash{'trust'}{$prefix}{$type}) eq 'ARRAY') {
                                               if (@{$defaultshash{'trust'}{$prefix}{$type}} > 0) {
                                                   $newvalue = join(', ',@{$defaultshash{'trust'}{$prefix}{$type}});
                                               }
                                           } else {
                                               $notinuse = 1;
                                           }
                                       }
                                   }
                                   if ($notinuse) {
                                       $resulttext .= '<li>'.&mt('[_1] set to: not in use',$lt{$type}).'</li>';
                                   } elsif ($newvalue eq '') {
                                       $resulttext .= '<li>'.&mt('[_1] set to: none',$lt{$type}).'</li>';
                                   } else {
                                       $resulttext .= '<li>'.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'</li>';
                                   }
                               }
                           }
                           $resulttext .= '</ul>';
                       }
                   }
                   $resulttext .= '</ul>';
               } else {
                   $resulttext = $nochgmsg;
               }
           } else {
               $resulttext = '<span class="LC_error">'.
                             &mt('An error occurred: [_1]',$putresult).'</span>';
           }
       } else {
           $resulttext = $nochgmsg;
       }
       return $resulttext;
   }
   
 sub modify_loadbalancing {  sub modify_loadbalancing {
     my ($dom,%domconfig) = @_;      my ($dom,%domconfig) = @_;
     my $primary_id = &Apache::lonnet::domain($dom,'primary');      my $primary_id = &Apache::lonnet::domain($dom,'primary');
Line 21469  sub devalidate_remote_domconfs { Line 23271  sub devalidate_remote_domconfs {
     map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();      map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids();
     my @posscached = ('domainconfig','domdefaults','ltitools','usersessions',      my @posscached = ('domainconfig','domdefaults','ltitools','usersessions',
                       'directorysrch','passwdconf','cats','proxyalias','proxysaml',                        'directorysrch','passwdconf','cats','proxyalias','proxysaml',
                       'ipaccess');                        'ipaccess','trust');
     my %cache_by_lonhost;      my %cache_by_lonhost;
     if (exists($cachekeys->{'samllanding'})) {      if (exists($cachekeys->{'samllanding'})) {
         if (ref($cachekeys->{'samllanding'}) eq 'HASH') {          if (ref($cachekeys->{'samllanding'}) eq 'HASH') {

Removed from v.1.160.6.118.2.21  
changed lines
  Added in v.1.425


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