--- loncom/interface/domainprefs.pm	2023/06/03 19:26:31	1.426
+++ loncom/interface/domainprefs.pm	2024/10/11 23:29:34	1.444
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: domainprefs.pm,v 1.426 2023/06/03 19:26:31 raeburn Exp $
+# $Id: domainprefs.pm,v 1.444 2024/10/11 23:29:34 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -95,8 +95,7 @@ about default quota sizes for portfolio
 institutional affiliation in the domain (e.g., Faculty, Staff, Student etc.), 
 but is now also used to manage availability of user tools: 
 i.e., blogs, aboutme page, and portfolios, and the course request tool,
-used by course owners to request creation of a course, and to display/store
-default quota sizes for Authoring Spaces.
+used by course owners to request creation of a course.
 
 Outputs: 1
 
@@ -223,7 +222,8 @@ sub handler {
                 'coursedefaults','usersessions','loadbalancing',
                 'requestauthor','selfenrollment','inststatus',
                 'ltitools','toolsec','ssl','trust','lti','ltisec',
-                'privacy','passwords','proctoring','wafproxy','ipaccess'],$dom);
+                'privacy','passwords','proctoring','wafproxy',
+                'ipaccess','authordefaults'],$dom);
     my %encconfig =
         &Apache::lonnet::get_dom('encconfig',['ltitools','lti','proctoring','linkprot'],$dom,undef,1);
     my ($checked_is_home,$is_home);
@@ -305,8 +305,8 @@ sub handler {
                        'contacts','privacy','usercreation','selfcreation',
                        'usermodification','scantron','requestcourses','requestauthor',
                        'coursecategories','serverstatuses','helpsettings','coursedefaults',
-                       'ltitools','proctoring','selfenrollment','usersessions','ssl',
-                       'trust','lti');
+                       'authordefaults','ltitools','proctoring','selfenrollment',
+                       'usersessions','ssl','trust','lti');
     my %existing;
     if (ref($domconfig{'loadbalancing'}) eq 'HASH') {
         %existing = %{$domconfig{'loadbalancing'}};
@@ -382,11 +382,11 @@ sub handler {
                       modify => \&modify_passwords,
                     },
         'quotas' => 
-                    { text => 'Blogs, personal pages/timezones, webDAV/quotas, portfolio',
+                    { text => 'Blogs, personal pages/timezones, portfolio/quotas',
                       help => 'Domain_Configuration_Quotas',
                       header => [{col1 => 'User affiliation',
                                   col2 => 'Available tools',
-                                  col3 => 'Quotas, MB; (Authoring requires role)',}],
+                                  col3 => 'Portfolio quota (MB)',}],
                       print => \&print_quotas,
                       modify => \&modify_quotas,
                     },
@@ -472,6 +472,8 @@ sub handler {
                     header => [{col1 => 'Target user has role',
                                 col2 => 'User information updatable in author context'},
                                {col1 => 'Target user has role',
+                                col2 => 'User information updatable by co-author manager'},
+                               {col1 => 'Target user has role',
                                 col2 => 'User information updatable in course context'}],
                     print => \&print_usermodification,
                     modify => \&modify_usermodification,
@@ -568,7 +570,7 @@ sub handler {
                   modify => \&modify_selfenrollment,
                  },
         'privacy' => 
-                 {text   => 'Availability of User Information',
+                 {text   => 'Role assignments and user privacy',
                   help   => 'Domain_Configuration_User_Privacy',
                   header => [{col1 => 'Role assigned in different domain',
                               col2 => 'Approval options'},
@@ -669,6 +671,8 @@ sub handler {
                               col2 => 'Settings'},
                              {col1 => 'Rules for shared secrets',
                               col2 => 'Settings'},
+                             {col1 => 'Link Protectors in Courses',
+                              col2 => 'Values'},
                              {col1 => 'Link Protectors',
                               col2 => 'Settings'},
                              {col1 => 'Consumers',
@@ -684,6 +688,16 @@ sub handler {
                         print  => \&print_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) {
         $prefs{'login'}  = { text   => 'Log-in page options',
@@ -882,13 +896,15 @@ sub process_changes {
     } elsif ($action eq 'lti') {
         $output = &modify_lti($r,$dom,$action,$lastactref,%domconfig);
     } elsif ($action eq 'privacy') {
-        $output = &modify_privacy($dom,%domconfig);
+        $output = &modify_privacy($dom,$lastactref,%domconfig);
     } elsif ($action eq 'passwords') {
         $output = &modify_passwords($r,$dom,$confname,$lastactref,%domconfig);
     } elsif ($action eq 'wafproxy') {
         $output = &modify_wafproxy($dom,$action,$lastactref,%domconfig);
     } elsif ($action eq 'ipaccess') {
         $output = &modify_ipaccess($dom,$lastactref,%domconfig);
+    } elsif ($action eq 'authordefaults') {
+        $output = &modify_authordefaults($dom,$lastactref,%domconfig);
     }
     return $output;
 }
@@ -936,6 +952,8 @@ sub print_config_box {
         $output .= &saml_javascript();
     } elsif ($action eq 'ipaccess') {
         $output .= &ipaccess_javascript($settings);
+    } elsif ($action eq 'authordefaults') {
+        $output .= &authordefaults_javascript();
     }
     $output .=
          '<table class="LC_nested_outer">
@@ -978,7 +996,7 @@ sub print_config_box {
             ($action eq 'selfenrollment') || ($action eq 'usersessions') || ($action eq 'ssl') ||
             ($action eq 'directorysrch') || ($action eq 'trust') || ($action eq 'helpsettings') ||
             ($action eq 'contacts') || ($action eq 'privacy') || ($action eq 'wafproxy') ||
-            ($action eq 'lti') || ($action eq 'ltitools')) {
+            ($action eq 'lti') || ($action eq 'ltitools') || ($action eq 'authordefaults')) {
             $output .= $item->{'print'}->('top',$dom,$settings,\$rowtotal);
         } elsif ($action eq 'passwords') {
             $output .= $item->{'print'}->('top',$dom,$confname,$settings,\$rowtotal);
@@ -1015,7 +1033,7 @@ sub print_config_box {
             ($action eq 'usersessions') || ($action eq 'coursecategories') || 
             ($action eq 'trust') || ($action eq 'contacts') || ($action eq 'defaults') ||
             ($action eq 'privacy') || ($action eq 'passwords') || ($action eq 'lti') ||
-            ($action eq 'ltitools')) {
+            ($action eq 'ltitools') || ($action eq 'usermodification')) {
             if ($action eq 'coursecategories') {
                 $output .= &print_coursecategories('middle',$dom,$item,$settings,\$rowtotal);
                 $colspan = ' colspan="2"';
@@ -1023,6 +1041,19 @@ sub print_config_box {
                 $output .= $item->{'print'}->('shared',$dom,$settings,\$rowtotal);
             } elsif ($action eq 'passwords') {
                 $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 {
                 $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal);
             }
@@ -1055,6 +1086,10 @@ sub print_config_box {
               <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[8]->{'col2'}).'</td></tr>'.
                            $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
             } else {
+                my $hdridx = 2;
+                if ($action eq 'lti') {
+                    $hdridx = 3;
+                }
                 $output .= '
            </table>
           </td>
@@ -1063,8 +1098,8 @@ sub print_config_box {
            <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>
+              <td class="LC_left_item"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col1'}).'</td>
+              <td class="LC_right_item">'.&mt($item->{'header'}->[$hdridx]->{'col2'}).'</td>
              </tr>'."\n";
                 if ($action eq 'coursecategories') {
                     $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal);
@@ -1075,6 +1110,7 @@ sub print_config_box {
                     } else {
                         $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal);
                     }
+                    $hdridx ++;
                     $output .= '
              </tr>
             </table>
@@ -1084,8 +1120,8 @@ sub print_config_box {
            <td>
             <table class="LC_nested">
              <tr class="LC_info_row">
-              <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col1'}).'</td>
-              <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[3]->{'col2'}).'</td></tr>'."\n";
+              <td class="LC_left_item'.$leftnobr.'"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col1'}).'</td>
+              <td class="LC_right_item"'.$colspan.'>'.&mt($item->{'header'}->[$hdridx]->{'col2'}).'</td></tr>'."\n";
                     if ($action eq 'passwords') {
                         $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal);
                     } else {
@@ -1101,7 +1137,7 @@ sub print_config_box {
                 }
             }
             $rowtotal ++;
-        } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') ||
+        } elsif (($action eq 'coursedefaults') || ($action eq 'authordefaults') ||
                  ($action eq 'directorysrch') || ($action eq 'helpsettings') ||
                  ($action eq 'wafproxy')) {
             $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal);
@@ -2397,7 +2433,7 @@ sub print_quotas {
     } else {
         $context = $action;
     }
-    my ($datatable,$defaultquota,$authorquota,@usertools,@options,%validations);
+    my ($datatable,$defaultquota,@usertools,@options,%validations);
     my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom);
     my $typecount = 0;
     my ($css_class,%titles);
@@ -2411,12 +2447,12 @@ sub print_quotas {
         @options = ('norequest','approval','automatic');
         %titles = &authorrequest_titles();
     } else {
-        @usertools = ('aboutme','blog','webdav','portfolio','timezone');
+        @usertools = ('aboutme','blog','portfolio','portaccess','timezone');
         %titles = &tool_titles();
     }
     if (ref($types) eq 'ARRAY') {
         foreach my $type (@{$types}) {
-            my ($currdefquota,$currauthorquota);
+            my $currdefquota;
             unless (($context eq 'requestcourses') ||
                     ($context eq 'requestauthor')) {
                 if (ref($settings) eq 'HASH') {
@@ -2425,9 +2461,6 @@ sub print_quotas {
                     } else {
                         $currdefquota = $settings->{$type};
                     }
-                    if (ref($settings->{authorquota}) eq 'HASH') {
-                        $currauthorquota = $settings->{authorquota}->{$type};
-                    }
                 }
             }
             if (defined($usertypes->{$type})) {
@@ -2545,13 +2578,9 @@ sub print_quotas {
                         ($context eq 'requestauthor')) {
                     $datatable .= 
                               '<td class="LC_right_item">'.
-                              '<span class="LC_nobreak">'.&mt('Portfolio').':&nbsp;'.
+                              '<span class="LC_nobreak">'.
                               '<input type="text" name="quota_'.$type.
                               '" 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>';
                 }
                 $datatable .= '</tr>';
@@ -2560,16 +2589,12 @@ sub print_quotas {
     }
     unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         $defaultquota = '20';
-        $authorquota = '500';
         if (ref($settings) eq 'HASH') {
             if (ref($settings->{'defaultquota'}) eq 'HASH') {
                 $defaultquota = $settings->{'defaultquota'}->{'default'};
             } elsif (defined($settings->{'default'})) {
                 $defaultquota = $settings->{'default'};
             }
-            if (ref($settings->{'authorquota'}) eq 'HASH') {
-                $authorquota = $settings->{'authorquota'}->{'default'};
-            }
         }
     }
     $typecount ++;
@@ -2681,12 +2706,9 @@ sub print_quotas {
     $datatable .= '</td>';
     unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) {
         $datatable .= '<td class="LC_right_item">'.
-                      '<span class="LC_nobreak">'.&mt('Portfolio').':&nbsp;'.
+                      '<span class="LC_nobreak">'.
                       '<input type="text" name="defaultquota" value="'.
-                      $defaultquota.'" size="5" /></span>'.('&nbsp;' x2).
-                      '<span class="LC_nobreak">'.&mt('Authoring').':&nbsp;'.
-                      '<input type="text" name="authorquota" value="'.
-                      $authorquota.'" size="5" /></span></td>';
+                      $defaultquota.'" size="5" /></span></td>';
     }
     $datatable .= '</tr>';
     $typecount ++;
@@ -3942,6 +3964,39 @@ $jstext
 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 {
     my ($dom,$settings,$rowtotal) = @_;
     my $autorun = &Apache::lonnet::auto_run(undef,$dom),
@@ -6143,7 +6198,7 @@ sub print_lti {
     my ($position,$dom,$settings,$rowtotal) = @_;
     my $itemcount = 1;
     my ($datatable,$css_class);
-    my (%rules,%encrypt,%privkeys,%linkprot);
+    my (%rules,%encrypt,%privkeys,%linkprot,%suggestions);
     if (ref($settings) eq 'HASH') {
         if ($position eq 'top') {
             if (exists($settings->{'encrypt'})) {
@@ -6166,12 +6221,18 @@ sub print_lti {
                     }
                 }
             }
-        } elsif ($position eq 'middle') {
+        } elsif ($position eq 'upper') {
             if (exists($settings->{'rules'})) {
                 if (ref($settings->{'rules'}) eq 'HASH') {
                     %rules = %{$settings->{'rules'}};
                 }
             }
+        } elsif ($position eq 'middle') {
+            if (exists($settings->{'suggested'})) {
+                if (ref($settings->{'suggested'}) eq 'HASH') {
+                    %suggestions = %{$settings->{'suggested'}};
+                }
+            }
         } elsif ($position eq 'lower') {
             if (exists($settings->{'linkprot'})) {
                 if (ref($settings->{'linkprot'}) eq 'HASH') {
@@ -6182,7 +6243,7 @@ sub print_lti {
                 }
             }
         } else {
-            foreach my $key ('encrypt','private','rules','linkprot') {
+            foreach my $key ('encrypt','private','rules','linkprot','suggestions') {
                 if (exists($settings->{$key})) {
                     delete($settings->{$key});
                 }
@@ -6191,11 +6252,14 @@ sub print_lti {
     }
     if ($position eq 'top') {
         $datatable = &secrets_form($dom,'ltisec',\%encrypt,\%privkeys,$rowtotal);
-    } elsif ($position eq 'middle') {
+    } elsif ($position eq 'upper') {
         $datatable = &password_rules('ltisecrets',\$itemcount,\%rules);
         $$rowtotal += $itemcount;
+    } elsif ($position eq 'middle') {
+        $datatable = &linkprot_suggestions(\%suggestions,\$itemcount);
+        $$rowtotal += $itemcount;
     } elsif ($position eq 'lower') {
-         $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');
+        $datatable .= &Apache::courseprefs::print_linkprotection($dom,'',$settings,$rowtotal,'','','domain');
     } else {
         my ($switchserver,$switchmessage);
         $switchserver = &check_switchserver($dom);
@@ -6782,6 +6846,58 @@ sub ltimenu_titles {
     );
 }
 
+sub linkprot_suggestions {
+    my ($suggested,$itemcount) = @_;
+    my $count = 0;
+    my $next = 1;
+    my %lt = &Apache::lonlocal::texthash(
+                                          'name' => 'Suggested Launcher',
+                                          'info' => 'Recommendations',
+                                        );
+    my ($datatable,$css_class,$dest);
+    if (ref($suggested) eq 'HASH') {
+        my @current = sort { $a <=> $b } keys(%{$suggested});
+        $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"':'';
+    $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 {
     my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles);
@@ -6789,6 +6905,7 @@ sub print_coursedefaults {
     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)',
+        coursequota          => 'Default cumulative quota for all group portfolio spaces in course (MB)',
         anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys',
         coursecredits        => 'Credits can be specified for courses',
         uselcmath            => 'Math preview uses LON-CAPA previewer (javascript) in place of DragMath (Java)',
@@ -6801,14 +6918,19 @@ sub print_coursedefaults {
         ltiauth              => 'Student username in LTI launch of deep-linked URL can be accepted without re-authentication',
         domexttool           => 'External Tools defined in the domain may be used in courses/communities (by type)',
         exttool              => 'External Tools can be defined and configured in courses/communities (by type)',
+        crsauthor            => 'Standard LON-CAPA problems can be created within a course/community (by type)',
+        crseditors           => 'Available editors for web pages and/or problems created in a course/community',
     );
     my %staticdefaults = (
                            anonsurvey_threshold => 10,
                            uploadquota          => 500,
+                           coursequota          => 20,
                            postsubmit           => 60,
                            mysqltables          => 172800,
                            domexttool           => 1,
                            exttool              => 0,
+                           crsauthor            => 1,
+                           crseditors           => ['edit','xml'],  
                          );
     if ($position eq 'top') {
         %defaultchecked = (
@@ -6922,12 +7044,15 @@ sub print_coursedefaults {
         $itemcount ++;
     } else {
         $css_class = $itemcount%2 ? ' class="LC_odd_row"' : '';
-        my ($currdefresponder,%defcredits,%curruploadquota,%deftimeout,%currmysql);
+        my ($currdefresponder,%defcredits,%curruploadquota,%currcoursequota,
+            %deftimeout,%currmysql);
         my $currusecredits = 0;
         my $postsubmitclient = 1;
         my $ltiauth = 0;
         my %domexttool;
         my %exttool;
+        my %crsauthor;
+        my %crseditors;
         my @types = ('official','unofficial','community','textbook','placement');
         if (ref($settings) eq 'HASH') {
             if ($settings->{'ltiauth'}) {
@@ -6953,12 +7078,39 @@ sub print_coursedefaults {
                     }
                 }
             }
+            if (ref($settings->{'crsauthor'}) eq 'HASH') {
+                foreach my $type (@types) {
+                    if ($settings->{'crsauthor'}->{$type}) {
+                        $crsauthor{$type} = ' checked="checked"';
+                    }
+                }
+            } else {
+                foreach my $type (@types) {
+                    if ($staticdefaults{'crsauthor'}) {
+                        $crsauthor{$type} = ' checked="checked"';
+                    }
+                }
+            }
+            if (ref($settings->{'crseditors'}) eq 'ARRAY') {
+                foreach my $editor (@{$settings->{'crseditors'}}) {
+                    $crseditors{$editor} = ' checked="checked"';
+                }
+            } else {
+                foreach my $editor (@{$staticdefaults{'crseditors'}}) {
+                    $crseditors{$editor} = ' checked="checked"';
+                }
+            }
             $currdefresponder = $settings->{'anonsurvey_threshold'};
             if (ref($settings->{'uploadquota'}) eq 'HASH') {
                 foreach my $type (keys(%{$settings->{'uploadquota'}})) {
                     $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') {
                 foreach my $type (@types) {
                     next if ($type eq 'community');
@@ -7007,6 +7159,12 @@ sub print_coursedefaults {
                 if ($staticdefaults{'domexttool'}) {
                     $domexttool{$type} = ' checked="checked"';
                 }
+                if ($staticdefaults{'crsauthor'}) {
+                    $crsauthor{$type} = ' checked="checked"';
+                }
+            }
+            foreach my $editor (@{$staticdefaults{'crseditors'}}) {
+                $crseditors{$editor} = ' checked="checked"';
             }
         }
         if (!$currdefresponder) {
@@ -7018,6 +7176,9 @@ sub print_coursedefaults {
             if ($curruploadquota{$type} eq '') {
                 $curruploadquota{$type} = $staticdefaults{'uploadquota'};
             }
+            if ($currcoursequota{$type} eq '') {
+                $currcoursequota{$type} = $staticdefaults{'coursequota'};
+            }
         }
         $datatable .=
                 '<tr'.$css_class.'><td><span class="LC_nobreak">'.
@@ -7041,6 +7202,19 @@ sub print_coursedefaults {
         }
         $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">'.
+                      '<table><tr>';
+        foreach my $type (@types) {
+            $datatable .= '<td style="text-align: center">'.&mt($type).'<br />'.
+                           '<input type="text" name="coursequota_'.$type.'"'.
+                           ' value="'.$currcoursequota{$type}.'" size="5" /></td>';
+        }
+        $datatable .= '</tr></table></td></tr>'."\n";
+        $itemcount ++;
         my $onclick = "toggleDisplay(this.form,'credits');";
         my $display = 'none';
         if ($currusecredits) {
@@ -7119,9 +7293,9 @@ sub print_coursedefaults {
         foreach my $type (@types) {
             $datatable .= '<td style="text-align: left">'.
                           '<span class="LC_nobreak">'.
-                          '<input type="checkbox" name="domexttool"'.
+                          '<label><input type="checkbox" name="domexttool"'.
                           ' value="'.$type.'"'.$domexttool{$type}.' />'.
-                          &mt($type).'</span></td>'."\n";
+                          &mt($type).'</label></span></td>'."\n";
         }
         $datatable .= '</tr></table></td></tr>'."\n";
         $itemcount ++;
@@ -7134,9 +7308,41 @@ sub print_coursedefaults {
         foreach my $type (@types) {
             $datatable .= '<td style="text-align: left">'.
                           '<span class="LC_nobreak">'.
-                          '<input type="checkbox" name="exttool"'.
+                          '<label><input type="checkbox" name="exttool"'.
                           ' value="'.$type.'"'.$exttool{$type}.' />'.
-                          &mt($type).'</span></td>'."\n";
+                          &mt($type).'</label></span></td>'."\n";
+        }
+        $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{'crsauthor'}.
+                      '</span></td>'.
+                      '<td style="text-align: right" class="LC_right_item">'.
+                      '<table><tr>';
+        foreach my $type (@types) {
+            $datatable .= '<td style="text-align: left">'.
+                          '<span class="LC_nobreak">'.
+                          '<label><input type="checkbox" name="crsauthor"'.
+                          ' value="'.$type.'"'.$crsauthor{$type}.' />'.
+                          &mt($type).'</label></span></td>'."\n";
+        }
+        $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{'crseditors'}.
+                      '</span></td>'.
+                      '<td style="text-align: right" class="LC_right_item">'.
+                      '<table><tr>';
+        my @editors = ('edit','xml','daxe');
+        my %editornames = &crseditor_titles();
+        foreach my $editor (@editors) {
+            $datatable .= '<td style="text-align: left">'.
+                          '<span class="LC_nobreak">'.
+                          '<label><input type="checkbox" name="crseditors"'.
+                          ' value="'.$editor.'"'.$crseditors{$editor}.' />'.
+                          $editornames{$editor}.'</label></span></td>'."\n";
         }
         $datatable .= '</tr></table></td></tr>'."\n";
     }
@@ -7144,6 +7350,234 @@ sub print_coursedefaults {
     return $datatable;
 }
 
+sub crseditor_titles {
+    return &Apache::lonlocal::texthash(
+               edit  => 'Standard editor (Edit)',
+               xml   => 'Text editor (EditXML)',
+               daxe  => 'Daxe editor (Daxe)',
+           );
+}
+
+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 ++;
+        my %defchecked = (
+                                'archive' => 'off',
+                             );
+        my @toggles = ('archive');
+        (my $archive,$itemcount) = &radiobutton_prefs($settings,['archive'],
+                                                      {'archive' => 'off'},
+                                                      \%titles,$itemcount);
+        $datatable .= $archive."\n";
+        $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',
+               archive => 'Authors can download tar.gz file of Authoring Space',
+    );
+}
+
+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 {
     my ($position,$dom,$settings,$rowtotal) = @_;
     my ($css_class,$datatable);
@@ -8070,8 +8504,10 @@ sub print_wafproxy {
             my $dom_in_effect;
             my $aliasrows = '<tr>'.
                             '<td class="LC_left_item" style="vertical-align: baseline;">'.
-                            &mt('Hostname').':&nbsp;'.
-                            '<i>'.&Apache::lonnet::hostname($server).'</i></td><td>&nbsp;</td>';
+                            &mt('Hostname').': '.
+                            '<span class="LC_nobreak LC_cusr_emph">'.
+                            &Apache::lonnet::hostname($server).
+                            '</span></td><td>&nbsp;</td>';
             if ($othercontrol{$server}) {
                 $dom_in_effect = $othercontrol{$server};
                 my ($current,$forsaml);
@@ -9386,8 +9822,8 @@ sub tool_titles {
     my %titles = &Apache::lonlocal::texthash (
                      aboutme    => 'Personal web page',
                      blog       => 'Blog',
-                     webdav     => 'WebDAV',
                      portfolio  => 'Portfolio',
+                     portaccess => 'Share portfolio files',
                      timezone   => 'Can set time zone',
                      official   => 'Official courses (with institutional codes)',
                      unofficial => 'Unofficial courses',
@@ -10290,6 +10726,15 @@ sub print_usermodification {
             $$rowtotal ++;
             $rowcount ++;
         }
+    } elsif ($position eq 'middle') {
+        $rowcount = 0;
+        $context = 'coauthor';
+        foreach my $role ('ca','aa') {
+            $datatable .= &modifiable_userdata_row($context,$role,$settings,
+                                                   $numinrow,$rowcount);
+            $$rowtotal ++;
+            $rowcount ++;
+        }
     } elsif ($position eq 'bottom') {
         $context = 'course';
         $rowcount = 0;
@@ -11795,6 +12240,8 @@ sub modifiable_userdata_row {
         } else {
             if ($context eq 'lti') {
                 $prefix = 'lti';
+            } elsif ($context eq 'coauthor') {
+                $prefix = 'cacanmodify';
             } elsif ($context eq 'privacy') {
                 $prefix = 'privacy';
             }
@@ -11824,15 +12271,19 @@ sub insttypes_row {
     my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context,$rowtotal,$onclick,
         $customcss,$rowstyle) = @_;
     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)',
-                      lockablenames => 'User preference to lock name',
-                      selfassign    => 'Self-reportable affiliations',
-                      overrides     => "Override domain's helpdesk settings based on requester's affiliation",
+                      lockablenames  => 'User preference to lock name',
+                      selfassign     => 'Self-reportable affiliations',
+                      overrides      => "Override domain's helpdesk settings based on requester's affiliation",
+                      webdav         => 'WebDAV access available',
+                      authorquota    => 'Authoring Space quota (MB)',
              );
-    my $showdom;
+    my ($showdom,$defaultquota);
     if ($context eq 'cansearch') {
         $showdom = ' ('.$dom.')';
+    } elsif ($context eq 'authorquota') {
+        $defaultquota = 500;
     }
     my $class = 'LC_left_item';
     if ($context eq 'statustocreate') {
@@ -11869,25 +12320,44 @@ sub insttypes_row {
                     }
                     $output .= '<tr>';
                 }
-                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') {
+                if ($context eq 'authorquota') {
+                    my $currquota;
+                    if ($settings->{$context}->{$types->[$i]} =~ /^\d+$/) {
+                        $currquota = $settings->{$context}->{$types->[$i]};
+                    } 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" ';
                         }
-                    } 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);
@@ -11909,20 +12379,41 @@ sub insttypes_row {
         } else {
             $output .= '<td class="LC_left_item">';
         }
-        my $defcheck = ' ';
-        if (ref($settings) eq 'HASH') {  
-            if (ref($settings->{$context}) eq 'ARRAY') {
-                if (grep(/^default$/,@{$settings->{$context}})) {
+        if ($context eq 'authorquota') {
+            my $currquota = 500;
+            if ((ref($settings) eq 'HASH') && (ref($settings->{$context}) eq 'HASH')) {
+                if ($settings->{$context}{'default'} =~ /^\d+$/) {
+                    $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" ';
                 }
-            } 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>';
     return $output;
@@ -12936,6 +13427,251 @@ sub get_ipaccess_id {
     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,
+                           'archive'      => 'off',
+                         );
+    my %titles = &authordefaults_titles();
+    foreach my $item ('nocodemirror','daxecollapse','domcoordacc','archive') {
+        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','archive') {
+            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','archive') {
+            if ($offon[$confhash{$item}] ne $staticdefaults{$item}) {
+                $changes{$item} = 1; 
+            }
+        }
+        foreach my $item ('copyright','sourceavail') {
+            if ($confhash{$item} ne $staticdefaults{$item}) {
+                $changes{$item} = 1;
+            }
+        }
+        my @diffs =
+            &Apache::loncommon::compare_arrays($confhash{'editors'},
+                                               $staticdefaults{'editors'});
+        unless (@diffs == 0) {
+            $changes{'editors'} = 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','archive') {
+                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'};
+                        }
+                    } elsif ($key eq 'archive') {
+                        $domdefaults{$key} = $confhash{$key};
+                        $shown = ($confhash{$key} ? &mt('Yes') : &mt('No'));
+                    }
+                    $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';
+                }
+            }
+            if ($domcoordoverride) {
+                $resulttext .= '</ul></li>';
+            }
+            $resulttext .= '</ul>';
+            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 {
     my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_;
     my ($resulttext,%rolehash);
@@ -12996,7 +13732,11 @@ sub modify_colors {
             @bgs = ('pgbg','tabbg','sidebg');
         }
         my %defaults = &role_defaults($role,\@bgs,\@links,\@images,\@logintext);
-        unless ($env{'form.'.$role.'_font'} eq $defaults{'font'}) {
+        $env{'form.'.$role.'_font'} = lc($env{'form.'.$role.'_font'});
+        if ($env{'form.'.$role.'_font'} =~ /^\w+/) {
+            $env{'form.'.$role.'_font'} = '#'.$env{'form.'.$role.'_font'};
+        }
+        unless ($env{'form.'.$role.'_font'} eq lc($defaults{'font'})) {
             $confhash->{$role}{'font'} = $env{'form.'.$role.'_font'};
         }
         if ($role eq 'login') {
@@ -13489,7 +14229,7 @@ sub modify_quotas {
         $author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref,
         $validationfieldsref);
     if ($action eq 'quotas') {
-        $context = 'tools'; 
+        $context = 'tools';
     } else {
         $context = $action;
     }
@@ -13509,7 +14249,7 @@ sub modify_quotas {
         @usertools = ('author');
         %titles = &authorrequest_titles();
     } else {
-        @usertools = ('aboutme','blog','webdav','portfolio','timezone');
+        @usertools = ('aboutme','blog','portfolio','portaccess','timezone');
         %titles = &tool_titles();
     }
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1);
@@ -13532,8 +14272,6 @@ sub modify_quotas {
         } else {
             if ($key =~ /^form\.quota_(.+)$/) {
                 $confhash{'defaultquota'}{$1} = $env{$key};
-            } elsif ($key =~ /^form\.authorquota_(.+)$/) {
-                $confhash{'authorquota'}{$1} = $env{$key};
             } elsif ($key =~ /^form\.\Q$context\E_(.+)$/) {
                 @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key);
             }
@@ -13827,7 +14565,6 @@ sub modify_quotas {
         }
     } else {
         $confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'};
-        $confhash{'authorquota'}{'default'} = $env{'form.authorquota'};
     }
     foreach my $item (@usertools) {
         foreach my $type (@{$types},'default','_LC_adv') {
@@ -13916,15 +14653,10 @@ sub modify_quotas {
                 }
             }
             if (ref($domconfig{'quotas'}{'authorquota'}) eq 'HASH') {
-                foreach my $key (keys(%{$domconfig{'quotas'}{'authorquota'}})) {
-                    if (exists($confhash{'authorquota'}{$key})) {
-                        if ($confhash{'authorquota'}{$key} ne $domconfig{'quotas'}{'authorquota'}{$key}) {
-                            $changes{'authorquota'}{$key} = 1;
-                        }
-                    } else {
-                        $confhash{'authorquota'}{$key} = $domconfig{'quotas'}{'authorquota'}{$key};
-                    }
-                }
+                $confhash{'authorquota'} = $domconfig{'quotas'}{'authorquota'};
+            }
+            if (ref($domconfig{'quotas'}{'webdav'}) eq 'HASH') {
+                $confhash{'webdav'} = $domconfig{'quotas'}{'webdav'};
             }
         }
         if (ref($confhash{'defaultquota'}) eq 'HASH') {
@@ -13944,21 +14676,6 @@ 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') {
@@ -13999,19 +14716,6 @@ sub modify_quotas {
                     }
                     $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;
             foreach my $item (@usertools) {
@@ -14163,6 +14867,7 @@ sub modify_quotas {
                             $resulttext .= '<li>'.&mt('Validated course requests identified as processed by: [_1]',
                                                      '<b>'.$changes{'validation'}{'dc'}.'</b>').'</li>';
                         }
+                        $resulttext .= '</ul></li>';
                     }
                 }
             }
@@ -14474,7 +15179,6 @@ sub lti_security_results {
                                        off => &mt('Encryption of stored external tool secrets defined in domain disabled'),
                                      },
                              );
-
             }
             my @types= ('crs','dom');
             if ($context eq 'lti') {
@@ -14570,6 +15274,28 @@ sub lti_security_results {
             }
         } elsif ($item eq 'linkprot') {
             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) {
@@ -15174,7 +15900,7 @@ sub modify_lti {
         }
     }
     if (ref($currltisec{'linkprot'}) eq 'HASH') {
-        foreach my $id (%{$currltisec{'linkprot'}}) {
+        foreach my $id (keys(%{$currltisec{'linkprot'}})) {
             next if ($id !~ /^\d+$/);
             unless (exists($linkprotchg{$id})) {
                 if (ref($currltisec{'linkprot'}{$id}) eq 'HASH') {
@@ -15196,17 +15922,75 @@ sub modify_lti {
     if ($proterror) {
         $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);
     if ($env{'form.lti_add'}) {
         my $consumer = $env{'form.lti_consumer_add'};
         $consumer =~ s/(`)/'/g;
-        ($newid,my $error) = &get_lti_id($dom,$consumer);
+        ($newid,my $errormsg) = &get_lti_id($dom,$consumer,'lti');
         if ($newid) {
             $itemids{'add'} = $newid;
             push(@items,'add');
             $changes{$newid} = 1;
         } else {
             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>';
         }
     }
@@ -15800,7 +16584,8 @@ sub modify_lti {
         }
         $resulttext .= '</ul>';
         if (ref($lastactref) eq 'HASH') {
-            if (($secchanges{'encrypt'}) || ($secchanges{'private'})) {
+            if (($secchanges{'encrypt'}) || ($secchanges{'private'}) || (exists($secchanges{'suggested'}))) {
+                &Apache::lonnet::get_domain_defaults($dom,1);
                 $lastactref->{'domdefaults'} = 1;
             }
         }
@@ -15839,23 +16624,26 @@ sub get_priv_creds {
 }
 
 sub get_lti_id {
-    my ($domain,$consumer) = @_;
-    # get lock on lti db
+    my ($domain,$consumer,$dbname) = @_;
+    unless (($dbname eq 'lti') || ($dbname eq 'suggested')) {
+        return ('','invalid db');
+    }
+    # get lock on db
     my $lockhash = {
                       lock => $env{'user.name'}.
                               ':'.$env{'user.domain'},
                    };
     my $tries = 0;
-    my $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);
+    my $gotlock = &Apache::lonnet::newput_dom($dbname,$lockhash,$domain);
     my ($id,$error);
 
     while (($gotlock ne 'ok') && ($tries<10)) {
         $tries ++;
         sleep (0.1);
-        $gotlock = &Apache::lonnet::newput_dom('lti',$lockhash,$domain);
+        $gotlock = &Apache::lonnet::newput_dom($dbname,$lockhash,$domain);
     }
     if ($gotlock eq 'ok') {
-        my %currids = &Apache::lonnet::dump_dom('lti',$domain);
+        my %currids = &Apache::lonnet::dump_dom($dbname,$domain);
         if ($currids{'lock'}) {
             delete($currids{'lock'});
             if (keys(%currids)) {
@@ -15867,14 +16655,14 @@ sub get_lti_id {
                 $id = 1;
             }
             if ($id) {
-                unless (&Apache::lonnet::newput_dom('lti',{ $id => $consumer },$domain) eq 'ok') {
+                unless (&Apache::lonnet::newput_dom($dbname,{ $id => $consumer },$domain) eq 'ok') {
                     $error = 'nostore';
                 }
             } else {
                 $error = 'nonumber';
             }
         }
-        my $dellockoutcome = &Apache::lonnet::del_dom('lti',['lock'],$domain);
+        my $dellockoutcome = &Apache::lonnet::del_dom($dbname,['lock'],$domain);
     } else {
         $error = 'nolock';
     }
@@ -17096,7 +17884,7 @@ sub modify_contacts {
 }
 
 sub modify_privacy {
-    my ($dom,%domconfig) = @_;
+    my ($dom,$lastactref,%domconfig) = @_;
     my ($resulttext,%current,%changes);
     if (ref($domconfig{'privacy'}) eq 'HASH') {
         %current = %{$domconfig{'privacy'}};
@@ -17332,6 +18120,28 @@ sub modify_privacy {
                 }
             }
             $resulttext .= '</ul>';
+            if ($changes{'approval'}) {
+                my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
+                delete($domdefaults{'userapprovals'});
+                if (ref($privacyhash{'approval'}) eq 'HASH') {
+                    foreach my $domtype ('instdom','extdom') {
+                        if (ref($privacyhash{'approval'}{$domtype}) eq 'HASH') {
+                            foreach my $roletype ('domain','author','course','community') {
+                                if ($privacyhash{'approval'}{$domtype}{$roletype} eq 'user') {
+                                    $domdefaults{'userapprovals'} = 1;
+                                    last;
+                                }
+                            }
+                        }
+                        last if ($domdefaults{'userapprovals'});               
+                    }
+                }
+                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 user information settings');
         }
@@ -19088,21 +19898,27 @@ sub modify_usermodification {
             }
         }
     }
-    my @contexts = ('author','course');
+    my @contexts = ('author','coauthor','course');
     my %context_title = (
                            author => 'In author context',
+                           coauthor => 'As co-author manager',
                            course => 'In course context',
                         );
     my @fields = ('lastname','firstname','middlename','generation',
                   'permanentemail','id');
     my %roles = (
                   author => ['ca','aa'],
+                  coauthor => ['ca','aa'],
                   course => ['st','ep','ta','in','cr'],
                 );
     my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles();
     foreach my $context (@contexts) {
+        my $prefix = 'canmodify';
+        if ($context eq 'coauthor') {
+            $prefix = 'cacanmodify';
+        }
         foreach my $role (@{$roles{$context}}) {
-            my @modifiable =  &Apache::loncommon::get_env_multiple('form.canmodify_'.$role);
+            my @modifiable =  &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$role);
             foreach my $item (@fields) {
                 if (grep(/^\Q$item\E$/,@modifiable)) {
                     $modifyhash{$context}{$role}{$item} = 1;
@@ -20469,21 +21285,30 @@ sub modify_coursedefaults {
     my @toggles = ('canuse_pdfforms','uselcmath','usejsme','inline_chem','ltiauth');
     my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial',
                    'uploadquota_community','uploadquota_textbook','uploadquota_placement',
-                   'mysqltables_official','mysqltables_unofficial','mysqltables_community',
-                   'mysqltables_textbook','mysqltables_placement');
+                   'coursequota_official','coursequota_unofficial','coursequota_community',
+                   'coursequota_textbook','coursequota_placement','mysqltables_official',
+                   'mysqltables_unofficial','mysqltables_community','mysqltables_textbook',
+                   'mysqltables_placement');
     my @types = ('official','unofficial','community','textbook','placement');
     my %staticdefaults = (
                            anonsurvey_threshold => 10,
                            uploadquota          => 500,
+                           coursequota          => 20,
                            postsubmit           => 60,
                            mysqltables          => 172800,
                            domexttool           => 1,
+                           crsauthor            => 1,
+                           crseditors           => ['edit','xml'],
                          );
     my %texoptions = (
                         MathJax  => 'MathJax',
                         mimetex  => &mt('Convert to Images'),
                         tth      => &mt('TeX to HTML'),
                      );
+
+    my @editors = ('edit','xml','daxe');
+    my %editornames = &crseditor_titles();
+
     $defaultshash{'coursedefaults'} = {};
 
     if (ref($domconfig{'coursedefaults'}) ne 'HASH') {
@@ -20522,7 +21347,7 @@ sub modify_coursedefaults {
                 }
                 $defaultshash{'coursedefaults'}{$item} = $newdef;
             } else {
-                my ($setting,$type) = ($item =~ /^(uploadquota|mysqltables)_(\w+)$/);
+                my ($setting,$type) = ($item =~ /^(uploadquota|coursequota|mysqltables)_(\w+)$/);
                 if (ref($domconfig{'coursedefaults'}{$setting}) eq 'HASH') {
                     $currdef = $domconfig{'coursedefaults'}{$setting}{$type};
                 }
@@ -20534,7 +21359,7 @@ sub modify_coursedefaults {
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) {
                         $changes{$item} = 1;
                     }
-                } elsif ($item =~ /^(uploadquota|mysqltables)_/) {
+                } elsif ($item =~ /^(uploadquota|coursequota|mysqltables)_/) {
                     my $setting = $1;
                     unless (($currdef eq '') && ($newdef == $staticdefaults{$setting})) {
                         $changes{$setting} = 1;
@@ -20669,9 +21494,12 @@ sub modify_coursedefaults {
                 $changes{'postsubmit'} = 1;
             }
         }
-        my (%newdomexttool,%newexttool,%olddomexttool,%oldexttool);
+        my (%newdomexttool,%newexttool,%newcrsauthor,%olddomexttool,%oldexttool,%oldcrsauthor,
+            %posscrseditors);
         map { $newdomexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.domexttool');
         map { $newexttool{$_} = 1; } &Apache::loncommon::get_env_multiple('form.exttool');
+        map { $newcrsauthor{$_} = 1; } &Apache::loncommon::get_env_multiple('form.crsauthor');
+        map { $posscrseditors{$_} = 1; } &Apache::loncommon::get_env_multiple('form.crseditors');
         if (ref($domconfig{'coursedefaults'}{'domexttool'}) eq 'HASH') {
             %olddomexttool = %{$domconfig{'coursedefaults'}{'domexttool'}};
         } else {
@@ -20694,6 +21522,38 @@ sub modify_coursedefaults {
                }
             }
         }
+        if (ref($domconfig{'coursedefaults'}{'crsauthor'}) eq 'HASH') {
+            %oldcrsauthor = %{$domconfig{'coursedefaults'}{'crsauthor'}};
+        } else {
+            foreach my $type (@types) {
+               if ($staticdefaults{'crsauthor'}) {
+                   $oldcrsauthor{$type} = 1;
+               } else {
+                   $oldcrsauthor{$type} = 0;
+               }
+            }
+        }
+        my @newcrseditors = ();
+        foreach my $editor (@editors) {
+            if ($posscrseditors{$editor}) {
+                push(@newcrseditors,$editor);
+            }
+        }
+        if (ref($domconfig{'coursedefaults'}{'crseditors'}) eq 'ARRAY') {
+            my @diffs =
+                &Apache::loncommon::compare_arrays($domconfig{'coursedefaults'}{'crseditors'},
+                                                   \@newcrseditors);
+            if (@diffs) {
+                $changes{'crseditors'} = 1; 
+            }
+        } else {
+            my @diffs =
+                &Apache::loncommon::compare_arrays($staticdefaults{'crseditors'},
+                                                   \@newcrseditors);
+            unless (@diffs == 0) {
+                $changes{'crseditors'} = 1;
+            }       
+        }
         foreach my $type (@types) {
             unless ($newdomexttool{$type}) {
                 $newdomexttool{$type} = 0;
@@ -20701,15 +21561,23 @@ sub modify_coursedefaults {
             unless ($newexttool{$type}) {
                 $newexttool{$type} = 0;
             }
+            unless ($newcrsauthor{$type}) {
+                $newcrsauthor{$type} = 0;
+            }
             if ($newdomexttool{$type} != $olddomexttool{$type}) {
                 $changes{'domexttool'} = 1;
             }
             if ($newexttool{$type} != $oldexttool{$type}) {
                 $changes{'exttool'} = 1;
             }
+            if ($newcrsauthor{$type} != $oldcrsauthor{$type}) {
+                $changes{'crsauthor'} = 1;
+            }
         }
         $defaultshash{'coursedefaults'}{'domexttool'} = \%newdomexttool;
         $defaultshash{'coursedefaults'}{'exttool'} = \%newexttool;
+        $defaultshash{'coursedefaults'}{'crsauthor'} = \%newcrsauthor;
+        $defaultshash{'coursedefaults'}{'crseditors'} = \@newcrseditors;
     }
     my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash,
                                              $dom);
@@ -20720,7 +21588,7 @@ sub modify_coursedefaults {
                 ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) ||
                 ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'}) ||
                 ($changes{'inline_chem'}) || ($changes{'ltiauth'}) || ($changes{'domexttool'}) ||
-                ($changes{'exttool'}) ) {
+                ($changes{'exttool'}) || ($changes{'coursequota'}) || ($changes{'crsauthor'})) {
                 foreach my $item ('canuse_pdfforms','uselcmath','usejsme','inline_chem','texengine',
                                   'ltiauth') {
                     if ($changes{$item}) {
@@ -20753,6 +21621,13 @@ 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 (ref($defaultshash{'coursedefaults'}{'canclone'}) eq 'HASH') {
                         if (ref($defaultshash{'coursedefaults'}{'canclone'}{'instcode'}) eq 'ARRAY') {
@@ -20779,6 +21654,18 @@ sub modify_coursedefaults {
                         }
                     }
                 }
+                if ($changes{'crsauthor'}) {
+                    if (ref($defaultshash{'coursedefaults'}{'crsauthor'}) eq 'HASH') {
+                        foreach my $type (@types) {
+                            $domdefaults{$type.'crsauthor'}=$defaultshash{'coursedefaults'}{'crsauthor'}{$type};
+                        }
+                    }
+                }
+                if ($changes{'crseditors'}) {
+                    if (ref($defaultshash{'coursedefaults'}{'crseditors'}) eq 'ARRAY') {
+                        $domdefaults{'crseditors'}=join(',',@{$defaultshash{'coursedefaults'}{'crseditors'}});
+                    }
+                }
                 my $cachetime = 24*60*60;
                 &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime);
                 if (ref($lastactref) eq 'HASH') {
@@ -20831,6 +21718,19 @@ sub modify_coursedefaults {
                     } else {
                         $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('Placement tests: [_1] MB','<b>'.$defaultshash{'coursedefaults'}{'coursequota'}{'placement'}.'</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') {
                     if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') {
                         $resulttext .= '<li>'.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'<ul>'.
@@ -20916,33 +21816,44 @@ sub modify_coursedefaults {
                     } else {
                         $resulttext .= '<li>'.&mt('LTI launch of deep-linked URL will require re-authentication').'</li>';
                     }
-                } elsif ($item eq 'domexttool') {
+                } elsif (($item eq 'domexttool') || ($item eq 'exttool') || ($item eq 'crsauthor')) {
                     my @noyes = (&mt('no'),&mt('yes'));
-                    if (ref($defaultshash{'coursedefaults'}{'domexttool'}) eq 'HASH') {
-                        $resulttext .= '<li>'.&mt('External Tools defined in the domain may be used as follows:').'<ul>'.
-                                       '<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'official'}].'</b>').'</li>'.
-                                       '<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'unofficial'}].'</b>').'</li>'.
-                                       '<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'textbook'}].'</b>').'</li>'.
-                                       '<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'placement'}].'</b>').'</li>'.
-                                       '<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'community'}].'</b>').'</li>'.
+                    my %status = (
+                                   domexttool => {
+                                                  ishash => &mt('External Tools defined in the domain may be used as follows:'), 
+                                                  default => &mt('External Tools defined in the domain may be used in all course types, by default'),
+                                                 },
+                                   exttool => {
+                                                  ishash => &mt('External Tools can be defined and configured in course containers as follows:'),
+                                                  default => &mt('External Tools can not be defined in any course types, by default'),
+                                              },
+                                   crsauthor => {
+                                                  ishash => &mt('Standard Problems can be created within course containers as follows:'),
+                                                  default => &mt('Standard Problems can be created within any course type, by default'),
+                                                },
+                                 );
+                                   
+                    if (ref($defaultshash{'coursedefaults'}{$item}) eq 'HASH') {
+                        $resulttext .= '<li>'.$status{$item}{'ishash'}.'<ul>'.
+                                       '<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'official'}].'</b>').'</li>'.
+                                       '<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'unofficial'}].'</b>').'</li>'.
+                                       '<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'textbook'}].'</b>').'</li>'.
+                                       '<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'placement'}].'</b>').'</li>'.
+                                       '<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{$item}{'community'}].'</b>').'</li>'.
                                        '</ul>'.
                                        '</li>';
                     } else {
-                        $resulttext .= '<li>'.&mt('External Tools defined in the domain may be used in all course types, by default').'</li>';
+                        $resulttext .= '<li>'.$status{$item}{'default'}.'</li>';
                     }
-                } elsif ($item eq 'exttool') {
-                    my @noyes = (&mt('no'),&mt('yes'));
-                    if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') {
-                        $resulttext .= '<li>'.&mt('External Tools can be defined and configured in course containers as follows:').'<ul>'.
-                                       '<li>'.&mt('Official courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'official'}].'</b>').'</li>'.
-                                       '<li>'.&mt('Unofficial courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'unofficial'}].'</b>').'</li>'.
-                                       '<li>'.&mt('Textbook courses: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'textbook'}].'</b>').'</li>'.
-                                       '<li>'.&mt('Placement tests: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'placement'}].'</b>').'</li>'.
-                                       '<li>'.&mt('Communities: [_1]','<b>'.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'community'}].'</b>').'</li>'.
-                                       '</ul>'.
-                                       '</li>';
-                    } else {
-                        $resulttext .= '<li>'.&mt('External Tools can not be defined in any course types, by default').'</li>';
+                } elsif ($item eq 'crseditors') {
+                    if (ref($defaultshash{'coursedefaults'}{$item}) eq 'ARRAY') {
+                        my $shown;
+                        if (@{$defaultshash{'coursedefaults'}{$item}}) {
+                            $shown = join(', ', map { $editornames{$_} } @{$defaultshash{'coursedefaults'}{$item}});
+                        } else {
+                            $shown = &mt('None');
+                        }
+                        $resulttext .= '<li>'.&mt('Available editors for course/community resources: [_1]',$shown).'</li>';
                     }
                 }
             }