--- loncom/interface/domainprefs.pm 2023/06/03 19:26:31 1.426 +++ loncom/interface/domainprefs.pm 2024/03/03 00:08:37 1.437 @@ -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.437 2024/03/03 00:08:37 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, }, @@ -568,7 +568,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 +669,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 +686,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 +894,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 +950,8 @@ sub print_config_box { $output .= &saml_javascript(); } elsif ($action eq 'ipaccess') { $output .= &ipaccess_javascript($settings); + } elsif ($action eq 'authordefaults') { + $output .= &authordefaults_javascript(); } $output .= ' @@ -978,7 +994,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); @@ -1023,6 +1039,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).' +
+ + + + + + + + + '."\n". + $item->{'print'}->('middle',$dom,$settings,\$rowtotal); } else { $output .= $item->{'print'}->('middle',$dom,$settings,\$rowtotal); } @@ -1055,6 +1084,10 @@ sub print_config_box { '. $item->{'print'}->('bottom',$dom,$settings,\$rowtotal); } else { + my $hdridx = 2; + if ($action eq 'lti') { + $hdridx = 3; + } $output .= '
'.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).'
'.&mt($item->{'header'}->[8]->{'col2'}).'
@@ -1063,8 +1096,8 @@ sub print_config_box { - - + + '."\n"; if ($action eq 'coursecategories') { $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal); @@ -1075,6 +1108,7 @@ sub print_config_box { } else { $output .= $item->{'print'}->('lower',$dom,$settings,\$rowtotal); } + $hdridx ++; $output .= '
'.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).''.&mt($item->{'header'}->[$hdridx]->{'col1'}).''.&mt($item->{'header'}->[$hdridx]->{'col2'}).'
@@ -1084,8 +1118,8 @@ sub print_config_box { - - '."\n"; + + '."\n"; if ($action eq 'passwords') { $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal); } else { @@ -1103,7 +1137,7 @@ sub print_config_box { $rowtotal ++; } elsif (($action eq 'usermodification') || ($action eq 'coursedefaults') || ($action eq 'directorysrch') || ($action eq 'helpsettings') || - ($action eq 'wafproxy')) { + ($action eq 'wafproxy') || ($action eq 'authordefaults')) { $output .= $item->{'print'}->('bottom',$dom,$settings,\$rowtotal); } elsif ($action eq 'scantron') { $output .= $item->{'print'}->($r,'bottom',$dom,$confname,$settings,\$rowtotal); @@ -2397,7 +2431,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 +2445,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 +2459,6 @@ sub print_quotas { } else { $currdefquota = $settings->{$type}; } - if (ref($settings->{authorquota}) eq 'HASH') { - $currauthorquota = $settings->{authorquota}->{$type}; - } } } if (defined($usertypes->{$type})) { @@ -2545,13 +2576,9 @@ sub print_quotas { ($context eq 'requestauthor')) { $datatable .= ''; } $datatable .= ''; @@ -2560,16 +2587,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 +2704,9 @@ sub print_quotas { $datatable .= ''; unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) { $datatable .= ''; + $defaultquota.'" size="5" />'; } $datatable .= ''; $typecount ++; @@ -3942,6 +3962,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"; + + +ENDSCRIPT +} + sub print_autoenroll { my ($dom,$settings,$rowtotal) = @_; my $autorun = &Apache::lonnet::auto_run(undef,$dom), @@ -6143,7 +6196,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 +6219,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 +6241,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 +6250,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 +6844,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 .= + ''."\n"; + $$itemcount ++; + } + } + $css_class = $$itemcount%2?' class="LC_odd_row"':''; + $datatable .= ''."\n". + ''."\n"; + return $datatable; +} + sub print_coursedefaults { my ($position,$dom,$settings,$rowtotal) = @_; my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles); @@ -6789,6 +6903,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 +6916,17 @@ 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)', ); my %staticdefaults = ( anonsurvey_threshold => 10, uploadquota => 500, + coursequota => 20, postsubmit => 60, mysqltables => 172800, domexttool => 1, exttool => 0, + crsauthor => 1, ); if ($position eq 'top') { %defaultchecked = ( @@ -6922,12 +7040,14 @@ 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 @types = ('official','unofficial','community','textbook','placement'); if (ref($settings) eq 'HASH') { if ($settings->{'ltiauth'}) { @@ -6953,12 +7073,30 @@ 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"'; + } + } + } $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 +7145,9 @@ sub print_coursedefaults { if ($staticdefaults{'domexttool'}) { $domexttool{$type} = ' checked="checked"'; } + if ($staticdefaults{'crsauthor'}) { + $crsauthor{$type} = ' checked="checked"'; + } } } if (!$currdefresponder) { @@ -7018,6 +7159,9 @@ sub print_coursedefaults { if ($curruploadquota{$type} eq '') { $curruploadquota{$type} = $staticdefaults{'uploadquota'}; } + if ($currcoursequota{$type} eq '') { + $currcoursequota{$type} = $staticdefaults{'coursequota'}; + } } $datatable .= '
'.&mt($item->{'header'}->[3]->{'col1'}).''.&mt($item->{'header'}->[3]->{'col2'}).'
'.&mt($item->{'header'}->[$hdridx]->{'col1'}).''.&mt($item->{'header'}->[$hdridx]->{'col2'}).'
'. - ''.&mt('Portfolio').': '. + ''. ''.(' ' x 2). - ''.&mt('Authoring').': '. - '
'. - ''.&mt('Portfolio').': '. + ''. ''.(' ' x2). - ''.&mt('Authoring').': '. - '
'."\n". + ''."\n". + '
'.$lt{'name'}.''."\n". + ''."\n". + '
'. + '
'.$lt{'info'}.''."\n". + ''. + '
'. + '
'."\n". + '
'."\n". + ''."\n". + ''.&mt('Add').''."\n". + '
'.$lt{'name'}.''."\n". + ''."\n". + '
'. + '
'.$lt{'info'}.''."\n". + ''. + '
'. + '
'."\n". + '
'. @@ -7041,6 +7185,19 @@ sub print_coursedefaults { } $datatable .= '
'."\n"; $itemcount ++; + $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; + $datatable .= ''. + $choices{'coursequota'}. + ''. + ''. + ''; + foreach my $type (@types) { + $datatable .= ''; + } + $datatable .= '
'.&mt($type).'
'. + '
'."\n"; + $itemcount ++; my $onclick = "toggleDisplay(this.form,'credits');"; my $display = 'none'; if ($currusecredits) { @@ -7139,11 +7296,236 @@ sub print_coursedefaults { &mt($type).''."\n"; } $datatable .= ''."\n"; + $itemcount ++; + $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; + $datatable .= ''. + $choices{'crsauthor'}. + ''. + ''. + ''; + foreach my $type (@types) { + $datatable .= ''."\n"; + } + $datatable .= '
'. + ''. + ''. + &mt($type).'
'."\n"; + } + $$rowtotal += $itemcount; + return $datatable; +} + +sub print_authordefaults { + my ($position,$dom,$settings,$rowtotal) = @_; + my ($css_class,$datatable,%checkedon,%checkedoff); + my $itemcount = 1; + my %titles = &authordefaults_titles(); + if ($position eq 'top') { + my %defaultchecked = ( + 'nocodemirror' => 'off', + 'daxecollapse' => 'off', + 'domcoordacc' => 'on', + ); + my @toggles = ('nocodemirror','daxecollapse','domcoordacc'); + ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked, + \%titles,$itemcount); + my %staticdefaults = ( + 'copyright' => 'default', + 'sourceavail' => 'closed', + ); + $css_class = $itemcount%2?' class="LC_odd_row"':''; + my %currrights; + foreach my $item ('copyright','sourceavail') { + $currrights{$item} = $staticdefaults{$item}; + if (ref($settings) eq 'HASH') { + if (exists($settings->{$item})) { + $currrights{$item} = $settings->{$item}; + } + } + } + $datatable .= ''. + ''.$titles{'copyright'}. + ''. + &selectbox('copyright',$currrights{'copyright'},'', + \&Apache::loncommon::copyrightdescription, + (grep !/^priv|custom$/,(&Apache::loncommon::copyrightids))). + ''."\n"; + $itemcount ++; + $css_class = $itemcount%2?' class="LC_odd_row"':''; + $datatable .= ''. + ''.$titles{'sourceavail'}. + ''. + &selectbox('sourceavail',$currrights{'sourceavail'},'', + \&Apache::loncommon::source_copyrightdescription, + (&Apache::loncommon::source_copyrightids)). + ''."\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 = ''."\n". + ''.$titles{'editors'}.''."\n". + ''."\n". + ''; + foreach my $editor (@editors) { + my $checked; + if (grep(/^\Q$editor\E$/,@{$curreditors})) { + $checked = ' checked="checked"'; + } + $datatable .= ' '; + } + $datatable .= ''."\n".''."\n".''."\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 .= ''. + ''.$titles{'webdav_LC_adv'}.'
'. + $titles{'webdav_LC_adv_over'}. + ''. + ''; + 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 .= '  '; + } + $datatable .= ''; + $itemcount ++; } $$rowtotal += $itemcount; return $datatable; } +sub authordefaults_titles { + return &Apache::lonlocal::texthash( + copyright => 'Copyright/Distribution', + sourceavail => ' Source Available', + editors => 'Available Editors', + webdav => 'WebDAV', + authorquota => 'Authoring Space quotas (MB)', + nocodemirror => 'Deactivate CodeMirror for EditXML editor', + daxecollapse => 'Daxe editor: LON-CAPA standard menus start collapsed', + domcoordacc => 'Dom. Coords. can enter Authoring Spaces in domain', + edit => 'Standard editor (Edit)', + xml => 'Text editor (EditXML)', + daxe => 'Daxe editor (Daxe)', + webdav_LC_adv => 'WebDAV access for LON-CAPA "advanced" users', + webdav_LC_adv_over => '(overrides access based on affiliation, if set)', + none => 'No override set', + overon => 'Override -- webDAV on', + overoff => 'Override -- webDAV off', + ); +} + +sub selectbox { + my ($name,$value,$readonly,$functionref,@idlist)=@_; + my $selout = ''; + return $selout; +} + sub print_selfenrollment { my ($position,$dom,$settings,$rowtotal) = @_; my ($css_class,$datatable); @@ -8070,8 +8452,10 @@ sub print_wafproxy { my $dom_in_effect; my $aliasrows = ''. ''. - &mt('Hostname').': '. - ''.&Apache::lonnet::hostname($server).' '; + &mt('Hostname').': '. + ''. + &Apache::lonnet::hostname($server). + ' '; if ($othercontrol{$server}) { $dom_in_effect = $othercontrol{$server}; my ($current,$forsaml); @@ -9386,8 +9770,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', @@ -11824,15 +12208,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 +12257,44 @@ sub insttypes_row { } $output .= ''; } - 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 .= ''."\n". + ''; + } 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 .= ''. + ''; } - $output .= ''. - ''; } } $rem = @{$types}%($numinrow); @@ -11909,20 +12316,41 @@ sub insttypes_row { } else { $output .= ''; } - 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 .= ''; + } 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 .= ''; } - $output .= ''; } $output .= ''; return $output; @@ -12936,6 +13364,240 @@ 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, + ); + my %titles = &authordefaults_titles(); + foreach my $item ('nocodemirror','daxecollapse','domcoordacc') { + if ($env{'form.'.$item} =~ /^(0|1)$/) { + $confhash{$item} = $env{'form.'.$item}; + } + } + if ($env{'form.copyright'} =~ /^(default|domain|public)$/) { + $confhash{'copyright'} = $1; + } + if ($env{'form.sourceavail'} =~ /^(closed|open)$/) { + $confhash{'sourceavail'} = $1; + } + my @posseditors = &Apache::loncommon::get_env_multiple('form.author_editors'); + my @okeditors = ('edit','xml','daxe'); + my @editors; + foreach my $item (@posseditors) { + if (grep(/^\Q$item\E$/,@okeditors)) { + push(@editors,$item); + } + } + $confhash{'editors'} = \@editors; + + my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); + my @insttypes; + if (ref($types) eq 'ARRAY') { + @insttypes = @{$types}; + } + my @webdavon = &Apache::loncommon::get_env_multiple('form.webdav'); + my %webdav; + map { $webdav{$_} = 1; } @webdavon; + foreach my $type (@insttypes,'default') { + my $possquota = $env{'form.authorquota_'.$type}; + if ($possquota =~ /^\d+$/) { + $save_quotas{'authorquota'}{$type} = $possquota; + } + if ($webdav{$type}) { + $save_quotas{'webdav'}{$type} = 1; + } else { + $save_quotas{'webdav'}{$type} = 0; + } + } + if ($env{'form.webdav_LC_adv'} =~ /^(0|1)$/) { + $save_quotas{'webdav'}{'_LC_adv'} = $env{'form.webdav_LC_adv'}; + } + if (ref($domconfig{'authordefaults'}) eq 'HASH') { + foreach my $item ('nocodemirror','daxecollapse','domcoordacc','copyright','sourceavail') { + if ($domconfig{'authordefaults'}{$item} ne $confhash{$item}) { + $changes{$item} = 1; + } + } + if (ref($domconfig{'authordefaults'}{'editors'}) eq 'ARRAY') { + my @diffs = + &Apache::loncommon::compare_arrays($confhash{'editors'}, + $domconfig{'authordefaults'}{'editors'}); + unless (@diffs == 0) { + $changes{'editors'} = 1; + } + } else { + my @diffs = + &Apache::loncommon::compare_arrays($confhash{'editors'}, + $staticdefaults{'editors'}); + unless (@diffs == 0) { + $changes{'editors'} = 1; + } + } + } else { + my @offon = ('off','on'); + foreach my $item ('nocodemirror','daxecollapse','domcoordacc') { + if ($offon[$confhash{$item}] ne $staticdefaults{$item}) { + $changes{$item} = 1; + } + } + foreach my $item ('copyright','sourceavail') { + if ($confhash{$item} ne $staticdefaults{$item}) { + $changes{$item} = 1; + } + } + } + foreach my $key ('authorquota','webdav') { + if (ref($curr_quotas{$key}) eq 'HASH') { + foreach my $type (@insttypes,'default') { + if (exists($save_quotas{$key}{$type})) { + if ($save_quotas{$key}{$type} ne $curr_quotas{$key}{$type}) { + $changes{$key}{$type} = 1; + } + } elsif (exists($curr_quotas{$key}{$type})) { + $save_quotas{$key}{$type} = $curr_quotas{$key}{$type}; + } else { + $save_quotas{$key}{$type} = $staticdefaults{$key}; + } + } + } else { + foreach my $type (@insttypes,'default') { + if (exists($save_quotas{$key}{$type})) { + unless ($save_quotas{$key}{$type} eq $staticdefaults{$key}) { + $changes{$key}{$type} = 1; + } + } else { + $save_quotas{$key}{$type} = $staticdefaults{$key}; + } + } + } + } + if (ref($curr_quotas{'webdav'}) eq 'HASH') { + if (exists($save_quotas{'webdav'}{'_LC_adv'})) { + if ($save_quotas{'webdav'}{'_LC_adv'} ne $curr_quotas{'webdav'}{'_LC_adv'}) { + $changes{'webdav_LC_adv'} = 1; + } + } elsif (exists($curr_quotas{'webdav'}{'_LC_adv'})) { + $changes{'webdav_LC_adv'} = 1; + } + } elsif (exists($save_quotas{'webdav'}{'_LC_adv'})) { + $changes{'webdav_LC_adv'} = 1; + } + my %confighash = ( + quotas => \%save_quotas, + authordefaults => \%confhash, + ); + my $putresult = &Apache::lonnet::put_dom('configuration',\%confighash, + $dom); + my $resulttext; + if ($putresult eq 'ok') { + if (keys(%changes)) { + my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); + if ((exists($changes{'authorquota'})) || (exists($changes{'webdav'})) || + ($changes{'webdav_LC_adv'})) { + if ((exists($changes{'authorquota'})) && (ref($save_quotas{'authorquota'}) eq 'HASH')) { + $domdefaults{'authorquota'} = $save_quotas{'authorquota'}; + } + if (((exists($changes{'webdav'})) || ($changes{'webdav_LC_adv'})) && + (ref($save_quotas{'webdav'}) eq 'HASH')) { + $domdefaults{'webdav'} = $save_quotas{'webdav'}; + } + } + $resulttext = &mt('Changes made:').'
    '; + my $authoroverride; + foreach my $key ('nocodemirror','daxecollapse','domcoordacc','copyright','sourceavail') { + if (exists($changes{$key})) { + $domdefaults{$key} = $confhash{$key}; + my $shown; + unless ($authoroverride) { + $resulttext .= '
  • '.&mt('Defaults which can be overridden by Author').'
      '; + $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 .= '
    • '.&mt('[_1] set to: [_2]',$titles{$key},$shown).'
    • '; + } + } + if ($authoroverride) { + $resulttext .= '
  • '; + } + my $domcoordoverride; + foreach my $key ('editors','authorquota','webdav','webdav_LC_adv') { + if (exists($changes{$key})) { + my $shown; + unless ($domcoordoverride) { + $resulttext .= '
  • '.&mt('Defaults which can be overridden by a Domain Coodinator').'
      '; + $domcoordoverride = 1; + } + if ($key eq 'editors') { + if (ref($confhash{'editors'}) eq 'ARRAY') { + $domdefaults{'editors'} = join(',',@{$confhash{'editors'}}); + if (@{$confhash{'editors'}}) { + $shown = join(', ', map { $titles{$_} } @{$confhash{'editors'}}); + } else { + $shown = &mt('None'); + } + } + } elsif ($key eq 'authorquota') { + foreach my $type (@insttypes) { + $shown .= $usertypes->{$type}.' -- '.$save_quotas{$key}{$type}.', '; + } + $shown .= $othertitle.' -- '.$save_quotas{$key}{'default'}; + } elsif ($key eq 'webdav') { + foreach my $type (@insttypes) { + $shown .= $usertypes->{$type}.' -- '. ($save_quotas{$key}{$type} ? &mt('Yes') : &mt('No')).', '; + } + $shown .= $othertitle.' -- '. ($save_quotas{$key}{'default'} ? &mt('Yes') : &mt('No')); + } elsif ($key eq 'webdav_LC_adv') { + if (exists($save_quotas{'webdav'}{'_LC_adv'})) { + $shown = ($save_quotas{'webdav'}{'_LC_adv'} ? $titles{'overon'} : $titles{'overoff'}); + } else { + $shown = $titles{'none'}; + } + } + $resulttext .= '
    • '.&mt('[_1] set to: [_2]',$titles{$key},$shown).'
    • '; + } + } + if ($domcoordoverride) { + $resulttext .= '
  • '; + } + 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); @@ -13489,7 +14151,7 @@ sub modify_quotas { $author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref, $validationfieldsref); if ($action eq 'quotas') { - $context = 'tools'; + $context = 'tools'; } else { $context = $action; } @@ -13509,7 +14171,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 +14194,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 +14487,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 +14575,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 +14598,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 +14638,6 @@ sub modify_quotas { } $resulttext .= '
'; } - if (ref($changes{'authorquota'}) eq 'HASH') { - $resulttext .= '
  • '.&mt('Authoring Space default quotas').'
      '; - foreach my $type (@{$types},'default') { - if (defined($changes{'authorquota'}{$type})) { - my $typetitle = $usertypes->{$type}; - if ($type eq 'default') { - $typetitle = $othertitle; - } - $resulttext .= '
    • '.&mt('[_1] set to [_2] MB',$typetitle,$confhash{'authorquota'}{$type}).'
    • '; - } - } - $resulttext .= '
  • '; - } } my %newenv; foreach my $item (@usertools) { @@ -14474,7 +15100,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 +15195,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 .= '
  • '.&mt('Launcher: [_1]',$name).'
    '. + &mt('Recommend: [_1]','
    '.$info.'
    '). + '
  • '; + } else { + $suggestions .= '
  • '.&mt('Recommendations deleted for Launcher: [_1]', + $newsec->{'suggested'}->{$id}).'
  • '; + } + } + if ($suggestions) { + $output .= '
  • '.&mt('Hints in Courses for Link Protector Configuration'). + '
      '.$suggestions.'
    '. + '
  • '; + } + } } } if ($needs_update) { @@ -15174,7 +15821,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 +15843,75 @@ sub modify_lti { if ($proterror) { $errors .= '
  • '.$proterror.'
  • '; } + + 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 .= '
  • '.$error.'
  • '; + } + } 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 .= '
  • '.$error.'
  • '; } } @@ -15800,7 +16505,8 @@ sub modify_lti { } $resulttext .= ''; 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 +16545,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 +16576,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 +17805,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 +18041,28 @@ sub modify_privacy { } } $resulttext .= ''; + 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'); } @@ -20469,15 +21200,19 @@ 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, ); my %texoptions = ( MathJax => 'MathJax', @@ -20522,7 +21257,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 +21269,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 +21404,10 @@ sub modify_coursedefaults { $changes{'postsubmit'} = 1; } } - my (%newdomexttool,%newexttool,%olddomexttool,%oldexttool); + my (%newdomexttool,%newexttool,%newcrsauthor,%olddomexttool,%oldexttool,%oldcrsauthor); 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'); if (ref($domconfig{'coursedefaults'}{'domexttool'}) eq 'HASH') { %olddomexttool = %{$domconfig{'coursedefaults'}{'domexttool'}}; } else { @@ -20694,6 +21430,17 @@ 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; + } + } + } foreach my $type (@types) { unless ($newdomexttool{$type}) { $newdomexttool{$type} = 0; @@ -20701,15 +21448,22 @@ 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; } my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, $dom); @@ -20720,7 +21474,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 +21507,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 +21540,13 @@ sub modify_coursedefaults { } } } + if ($changes{'crsauthor'}) { + if (ref($defaultshash{'coursedefaults'}{'crsauthor'}) eq 'HASH') { + foreach my $type (@types) { + $domdefaults{$type.'crsauthor'}=$defaultshash{'coursedefaults'}{'crsauthor'}{$type}; + } + } + } my $cachetime = 24*60*60; &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); if (ref($lastactref) eq 'HASH') { @@ -20831,6 +21599,19 @@ sub modify_coursedefaults { } else { $resulttext .= '
  • '.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'
  • '; } + } elsif ($item eq 'coursequota') { + if (ref($defaultshash{'coursedefaults'}{'coursequota'}) eq 'HASH') { + $resulttext .= '
  • '.&mt('Default cumulative quota for all group portfolio spaces in course set as follows:').'
      '. + '
    • '.&mt('Official courses: [_1] MB',''.$defaultshash{'coursedefaults'}{'coursequota'}{'official'}.'').'
    • '. + '
    • '.&mt('Unofficial courses: [_1] MB',''.$defaultshash{'coursedefaults'}{'coursequota'}{'unofficial'}.'').'
    • '. + '
    • '.&mt('Textbook courses: [_1] MB',''.$defaultshash{'coursedefaults'}{'coursequota'}{'textbook'}.'').'
    • '. + '
    • '.&mt('Placement tests: [_1] MB',''.$defaultshash{'coursedefaults'}{'coursequota'}{'placement'}.'').'
    • '. + '
    • '.&mt('Communities: [_1] MB',''.$defaultshash{'coursedefaults'}{'coursequota'}{'community'}.'').'
    • '. + '
    '. + '
  • '; + } else { + $resulttext .= '
  • '.&mt('Default cumulative quota for all group portfolio spaces in course remains default: [_1] MB',$staticdefaults{'coursequota'}).'
  • '; + } } elsif ($item eq 'mysqltables') { if (ref($defaultshash{'coursedefaults'}{'mysqltables'}) eq 'HASH') { $resulttext .= '
  • '.&mt('Lifetime of "Temporary" MySQL tables (student performance data) on homeserver').'
      '. @@ -20916,33 +21697,34 @@ sub modify_coursedefaults { } else { $resulttext .= '
    • '.&mt('LTI launch of deep-linked URL will require re-authentication').'
    • '; } - } 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 .= '
    • '.&mt('External Tools defined in the domain may be used as follows:').'
        '. - '
      • '.&mt('Official courses: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'official'}].'').'
      • '. - '
      • '.&mt('Unofficial courses: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'unofficial'}].'').'
      • '. - '
      • '.&mt('Textbook courses: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'textbook'}].'').'
      • '. - '
      • '.&mt('Placement tests: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'placement'}].'').'
      • '. - '
      • '.&mt('Communities: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{'domexttool'}{'community'}].'').'
      • '. - '
      '. - '
    • '; - } else { - $resulttext .= '
    • '.&mt('External Tools defined in the domain may be used in all course types, by default').'
    • '; - } - } elsif ($item eq 'exttool') { - my @noyes = (&mt('no'),&mt('yes')); - if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') { - $resulttext .= '
    • '.&mt('External Tools can be defined and configured in course containers as follows:').'
        '. - '
      • '.&mt('Official courses: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'official'}].'').'
      • '. - '
      • '.&mt('Unofficial courses: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'unofficial'}].'').'
      • '. - '
      • '.&mt('Textbook courses: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'textbook'}].'').'
      • '. - '
      • '.&mt('Placement tests: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'placement'}].'').'
      • '. - '
      • '.&mt('Communities: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{'exttool'}{'community'}].'').'
      • '. + 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 .= '
      • '.$status{$item}{'ishash'}.'
          '. + '
        • '.&mt('Official courses: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{$item}{'official'}].'').'
        • '. + '
        • '.&mt('Unofficial courses: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{$item}{'unofficial'}].'').'
        • '. + '
        • '.&mt('Textbook courses: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{$item}{'textbook'}].'').'
        • '. + '
        • '.&mt('Placement tests: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{$item}{'placement'}].'').'
        • '. + '
        • '.&mt('Communities: [_1]',''.$noyes[$defaultshash{'coursedefaults'}{$item}{'community'}].'').'
        • '. '
        '. '
      • '; } else { - $resulttext .= '
      • '.&mt('External Tools can not be defined in any course types, by default').'
      • '; + $resulttext .= '
      • '.$status{$item}{'default'}.'
      • '; } } }