--- loncom/interface/domainprefs.pm 2023/03/19 16:05:48 1.421 +++ loncom/interface/domainprefs.pm 2024/02/27 15:46:42 1.435 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set domain-wide configuration settings # -# $Id: domainprefs.pm,v 1.421 2023/03/19 16:05:48 raeburn Exp $ +# $Id: domainprefs.pm,v 1.435 2024/02/27 15:46:42 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 @@ -105,7 +104,7 @@ $datatable - HTML containing form eleme In the case of course requests, radio buttons are displayed for each institutional affiliate type (and also default, and _LC_adv) for each of the course types (official, unofficial, community, textbook, placement, and lti). -In each case the radio buttons allow the selection of one of four values: +In each case the radio buttons allow the selection of one of four values: 0, approval, validate, autolimit=N (where N is blank, or a positive integer). which have the following effects: @@ -178,6 +177,7 @@ use DateTime::TimeZone; use DateTime::Locale; use Time::HiRes qw( sleep ); use Net::CIDR; +use Crypt::CBC; my $registered_cleanup; my $modified_urls; @@ -222,26 +222,50 @@ 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); if (ref($domconfig{'ltitools'}) eq 'HASH') { if (ref($encconfig{'ltitools'}) eq 'HASH') { + my $home = &Apache::lonnet::domain($dom,'primary'); + unless (($home eq 'no_host') || ($home eq '')) { + my @ids=&Apache::lonnet::current_machine_ids(); + if (grep(/^\Q$home\E$/,@ids)) { + $is_home = 1; + } + } + $checked_is_home = 1; foreach my $id (keys(%{$domconfig{'ltitools'}})) { if ((ref($domconfig{'ltitools'}{$id}) eq 'HASH') && (ref($encconfig{'ltitools'}{$id}) eq 'HASH')) { $domconfig{'ltitools'}{$id}{'key'} = $encconfig{'ltitools'}{$id}{'key'}; + if (($is_home) && ($phase eq 'process')) { + $domconfig{'ltitools'}{$id}{'secret'} = $encconfig{'ltitools'}{$id}{'secret'}; + } } } } } if (ref($domconfig{'lti'}) eq 'HASH') { if (ref($encconfig{'lti'}) eq 'HASH') { + unless ($checked_is_home) { + my $home = &Apache::lonnet::domain($dom,'primary'); + unless (($home eq 'no_host') || ($home eq '')) { + my @ids=&Apache::lonnet::current_machine_ids(); + if (grep(/^\Q$home\E$/,@ids)) { + $is_home = 1; + } + } + $checked_is_home = 1; + } foreach my $id (keys(%{$domconfig{'lti'}})) { if ((ref($domconfig{'lti'}{$id}) eq 'HASH') && (ref($encconfig{'lti'}{$id}) eq 'HASH')) { - foreach my $item ('key','secret') { - $domconfig{'lti'}{$id}{$item} = $encconfig{'lti'}{$id}{$item}; + $domconfig{'lti'}{$id}{'key'} = $encconfig{'lti'}{$id}{'key'}; + if (($is_home) && ($phase eq 'process')) { + $domconfig{'lti'}{$id}{'secret'} = $encconfig{'lti'}{$id}{'secret'}; } } } @@ -281,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'}}; @@ -358,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, }, @@ -544,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'}, @@ -580,7 +604,7 @@ sub handler { print => \&print_loadbalancing, modify => \&modify_loadbalancing, }, - 'ltitools' => + 'ltitools' => {text => 'External Tools (LTI)', help => 'Domain_Configuration_LTI_Tools', header => [{col1 => 'Encryption of shared secrets', @@ -638,13 +662,15 @@ sub handler { print => \&print_trust, modify => \&modify_trust, }, - 'lti' => + 'lti' => {text => 'LTI Link Protection and LTI Consumers', help => 'Domain_Configuration_LTI_Provider', header => [{col1 => 'Encryption of shared secrets', col2 => 'Settings'}, - {col1 => 'Rules for shared secrets', + {col1 => 'Rules for shared secrets', col2 => 'Settings'}, + {col1 => 'Link Protectors in Courses', + col2 => 'Values'}, {col1 => 'Link Protectors', col2 => 'Settings'}, {col1 => 'Consumers', @@ -652,7 +678,7 @@ sub handler { print => \&print_lti, modify => \&modify_lti, }, - 'ipaccess' => + 'ipaccess' => {text => 'IP-based access control', help => 'Domain_Configuration_IP_Access', header => [{col1 => 'Setting', @@ -660,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', @@ -858,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; } @@ -893,7 +931,7 @@ sub print_config_box { &Apache::lonuserutils::custom_role_privs(\%privs,\%full,\%levels,\%levelscurrent); my @templateroles = &Apache::lonuserutils::custom_template_roles($context,$crstype); $output = - &Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full, + &Apache::lonuserutils::custom_roledefs_js($context,$crstype,$formname,\%full, \@templateroles); } elsif ($action eq 'ltitools') { $output .= &Apache::lonconfigsettings::ltitools_javascript($settings); @@ -912,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 .= ' @@ -954,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); @@ -999,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); } @@ -1031,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'}).'
@@ -1039,8 +1096,8 @@ sub print_config_box { - - + + '."\n"; if ($action eq 'coursecategories') { $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal); @@ -1051,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'}).'
@@ -1060,8 +1118,8 @@ sub print_config_box { - - '."\n"; + + '."\n"; if ($action eq 'passwords') { $output .= $item->{'print'}->('bottom',$dom,$confname,$settings,\$rowtotal); } else { @@ -1079,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); @@ -2373,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); @@ -2387,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') { @@ -2401,9 +2459,6 @@ sub print_quotas { } else { $currdefquota = $settings->{$type}; } - if (ref($settings->{authorquota}) eq 'HASH') { - $currauthorquota = $settings->{authorquota}->{$type}; - } } } if (defined($usertypes->{$type})) { @@ -2521,13 +2576,9 @@ sub print_quotas { ($context eq 'requestauthor')) { $datatable .= ''; } $datatable .= ''; @@ -2536,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 ++; @@ -2657,12 +2704,9 @@ sub print_quotas { $datatable .= ''; unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) { $datatable .= ''; + $defaultquota.'" size="5" />'; } $datatable .= ''; $typecount ++; @@ -3529,7 +3573,6 @@ sub lti_toggle_js { my %servers = &Apache::lonnet::get_servers($dom,'library'); my $primary = &Apache::lonnet::domain($dom,'primary'); my $course_servers = "'".join("','",keys(%servers))."'"; - return <<"ENDSCRIPT"; + +ENDSCRIPT +} + sub print_autoenroll { my ($dom,$settings,$rowtotal) = @_; my $autorun = &Apache::lonnet::auto_run(undef,$dom), @@ -4590,7 +4666,7 @@ sub print_contacts { map {$excluded{$_} = 1; } @{$lonstatus{'excluded'}}; } } - foreach my $item ('errorthreshold','errorsysmail') { + foreach my $item ('errorthreshold','errorsysmail') { $css_class = $rownum%2?' class="LC_odd_row"':''; $datatable .= ''. ''; $itemcount ++; @@ -6291,8 +6419,16 @@ sub print_lti { ''.$lt{'version'}.': '."\n". (' 'x2). - ''.$lt{'lifetime'}.': '."\n". - (' 'x2). + ''.$lt{'lifetime'}.':

'."\n"; + if ($switchserver) { + $datatable .= ''.&mt('Key and Secret are required').' - '.$switchmessage.''."\n"; + } else { + $datatable .= ''.$lt{'key'}.': '."\n". + (' 'x2). + ''.$lt{'secret'}.':'. + ' '."\n"; + } + $datatable .= '

'. ''.$lt{'requser'}.':'. ' '."\n". ''."\n". @@ -6300,11 +6436,6 @@ sub print_lti { ''.$lt{'crsinc'}.':'. ' '."\n". ''."\n". - (' 'x4). - ''.$lt{'key'}.': '."\n". - (' 'x2). - ''.$lt{'secret'}.':'. - ' '."\n". ''.<i_options('add',undef,$itemcount,%lt). ''."\n". ''."\n"; @@ -6377,7 +6508,7 @@ sub lti_options { if (($current->{'mapuser'} ne '') && ($current->{'mapuser'} ne 'lis_person_sourcedid')) { $checked{'mapuser'}{'sourcedid'} = ''; if ($current->{'mapuser'} eq 'lis_person_contact_email_primary') { - $checked{'mapuser'}{'email'} = ' checked="checked"'; + $checked{'mapuser'}{'email'} = ' checked="checked"'; } else { $checked{'mapuser'}{'other'} = ' checked="checked"'; $userfield = $current->{'mapuser'}; @@ -6387,7 +6518,7 @@ sub lti_options { if (($current->{'mapcrs'} ne '') && ($current->{'mapcrs'} ne 'course_offering_sourcedid')) { $checked{'mapcrs'}{'course_offering_sourcedid'} = ''; if ($current->{'mapcrs'} eq 'context_id') { - $checked{'mapcrs'}{'context_id'} = ' checked="checked"'; + $checked{'mapcrs'}{'context_id'} = ' checked="checked"'; } else { $checked{'mapcrs'}{'other'} = ' checked="checked"'; $cidfield = $current->{'mapcrs'}; @@ -6415,7 +6546,7 @@ sub lti_options { $checked{'lcauth'}{$1} = ' checked="checked"'; unless (($current->{'lcauth'} eq 'lti') || ($current->{'lcauth'} eq 'internal')) { $lcauthparm = $current->{'lcauthparm'}; - $lcauthparmstyle = 'display:table-row'; + $lcauthparmstyle = 'display:table-row'; if ($current->{'lcauth'} eq 'localauth') { $lcauthparmtext = &mt('Local auth argument'); } else { @@ -6432,7 +6563,7 @@ sub lti_options { %rolemaps = %{$current->{'maproles'}}; } if ($current->{'section'} ne '') { - $checked{'crssec'}{'Y'} = ' checked="checked"'; + $checked{'crssec'}{'Y'} = ' checked="checked"'; $crssecfieldsty = 'inline-block'; if ($current->{'section'} eq 'course_section_sourcedid') { $checked{'crssecsrc'}{'sourcedid'} = ' checked="checked"'; @@ -6478,9 +6609,9 @@ sub lti_options { $checked{'crssec'}{'N'} = ' checked="checked"'; $checked{'callback'}{'N'} = ' checked="checked"'; $checked{'topmenu'}{'N'} = ' checked="checked"'; - $checked{'inlinemenu'}{'Y'} = ' checked="checked"'; + $checked{'inlinemenu'}{'Y'} = ' checked="checked"'; $checked{'menuitem'}{'grades'} = ' checked="checked"'; - $menusty = 'inline-block'; + $menusty = 'inline-block'; } my @coursetypes = ('official','unofficial','community','textbook','placement','lti'); my %coursetypetitles = &Apache::lonlocal::texthash ( @@ -6533,7 +6664,7 @@ sub lti_options { '
'.&mt('Roles which may create user accounts').''; foreach my $ltirole (@ltiroles) { $output .= '  '; + $checked{'makeuser'}{$ltirole}.' />'.$ltirole.'  '; } $output .= '
'. '
'.&mt('New user accounts created for LTI users').''. @@ -6665,9 +6796,9 @@ sub lti_options { if ($extra eq 'passback') { $pb1p1chk = ' checked="checked"'; $pb1p0chk = ''; - $onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"'; + $onclickpb = ' onclick="toggleLTI(this.form,'."'passback','$num'".');"'; } else { - $onclickpb = ''; + $onclickpb = ''; } if (ref($current) eq 'HASH') { if (($current->{$extra})) { @@ -6713,20 +6844,56 @@ sub ltimenu_titles { ); } -sub check_switchserver { - my ($home) = @_; - my $switchserver; - if ($home ne '') { - my $allowed; - my @ids=&Apache::lonnet::current_machine_ids(); - foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } } - if (!$allowed) { - $switchserver=''.&mt('Switch Server').''; +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 ++; } } - return $switchserver; + $css_class = $$itemcount%2?' class="LC_odd_row"':''; + $datatable .= ''."\n". + ''."\n"; + return $datatable; } sub print_coursedefaults { @@ -6736,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)', @@ -6746,12 +6914,19 @@ sub print_coursedefaults { canclone => "People who may clone a course (besides course's owner and coordinators)", mysqltables => 'Lifetime (s) of "Temporary" MySQL tables (student performance data) on homeserver', 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 = ( @@ -6865,21 +7040,63 @@ 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'}) { $ltiauth = 1; } + if (ref($settings->{'domexttool'}) eq 'HASH') { + foreach my $type (@types) { + if ($settings->{'domexttool'}->{$type}) { + $domexttool{$type} = ' checked="checked"'; + } + } + } else { + foreach my $type (@types) { + if ($staticdefaults{'domexttool'}) { + $domexttool{$type} = ' checked="checked"'; + } + } + } + if (ref($settings->{'exttool'}) eq 'HASH') { + foreach my $type (@types) { + if ($settings->{'exttool'}->{$type}) { + $exttool{$type} = ' checked="checked"'; + } + } + } + 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'); @@ -6925,6 +7142,12 @@ sub print_coursedefaults { } else { foreach my $type (@types) { $deftimeout{$type} = $staticdefaults{'postsubmit'}; + if ($staticdefaults{'domexttool'}) { + $domexttool{$type} = ' checked="checked"'; + } + if ($staticdefaults{'crsauthor'}) { + $crsauthor{$type} = ' checked="checked"'; + } } } if (!$currdefresponder) { @@ -6936,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').': '. - '
'. @@ -4672,7 +4748,7 @@ sub print_contacts { $includeloc{'override_'.$key} = ''; $includestr{'override_'.$key} = ''; if ($settings->{'overrides'}{$key}{'include'} ne '') { - ($includeloc{'override_'.$key},$includestr{'override_'.$key}) = + ($includeloc{'override_'.$key},$includestr{'override_'.$key}) = split(/:/,$settings->{'overrides'}{$key}{'include'},2); $includestr{'override_'.$key} = &unescape($includestr{'override_'.$key}); } @@ -4684,7 +4760,6 @@ sub print_contacts { my $optionsprefix = 'LC_options_helpdesk_'; my $onclicktypes = "toggleHelpdeskRow(this.form,'overrides','$customclass','$optionsprefix');"; - $datatable .= &insttypes_row($settings,$types,$usertypes,$dom, $numinrow,$othertitle,'overrides', \$rownum,$onclicktypes,$customclass); @@ -4751,7 +4826,7 @@ sub overridden_helpdesk { } my $title; if (ref($short_titles) eq 'HASH') { - $title = $short_titles->{$item}; + $title = $short_titles->{$item}; } $output .= ' '. (' 'x2). ''.$lt{'lifetime'}.':'. - (' 'x2). + 'value="'.$lifetime.'" size="3" />

'; + if ($key ne '') { + $datatable .= ''.$lt{'key'}; + if ($switchserver) { + $datatable .= ': ['.&mt('[_1] to view/edit',$switchserver).']'; + } else { + $datatable .= ':'; + } + $datatable .= ' '.(' 'x2); + } elsif (!$switchserver) { + $datatable .= ''.$lt{'key'}.':'. + ''. + ' '.(' 'x2); + } + if ($switchserver) { + if ($usable ne '') { + $datatable .= '
'. + $lt{'secret'}.': ['.&mt('not shown').'] '.(' 'x2).'
'. + ''.&mt('Change secret?'). + ''. + (' 'x2). + ''.(' 'x2). + ''; + } elsif ($key eq '') { + $datatable .= ''.&mt('Key and Secret are required').' - '.$switchmessage.''."\n"; + } else { + $datatable .= ''.&mt('Secret required').' - '.$switchmessage.''."\n"; + } + } else { + if ($usable ne '') { + $datatable .= '
'. + $lt{'secret'}.': ['.&mt('not shown').'] '.(' 'x2).'
'. + ''.&mt('Change?'). + ''. + (' 'x2). + '  '; + } else { + $datatable .= + ''.$lt{'secret'}.':'. + ''. + ''; + } + } + $datatable .= '

'. ''.$lt{'requser'}.':'. ' '."\n". ''."\n". @@ -6257,12 +6391,6 @@ sub print_lti { ' '."\n". '
'."\n". (' 'x4). - ''.$lt{'key'}. - ': '. - (' 'x2). - ''.$lt{'secret'}.':'. - ''. - ''. ''. ''.<i_options($i,$current,$itemcount,%lt).'
'."\n". + ''."\n". + '
'.$lt{'name'}.''."\n". + ''."\n". + '
'. + '
'.$lt{'info'}.''."\n". + ''. + '
'. + '
'."\n". + '
'."\n". + ''."\n". + ''.&mt('Add').''."\n". + '
'.$lt{'name'}.''."\n". + ''."\n". + '
'. + '
'.$lt{'info'}.''."\n". + ''. + '
'. + '
'."\n". + '
'. @@ -6959,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) { @@ -7028,12 +7267,263 @@ sub print_coursedefaults { &radiobutton_prefs($current,\@toggles,\%defaultchecked, \%choices,$itemcount,undef,undef,'left'); $datatable .= $table; + $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; + $datatable .= ''. + $choices{'domexttool'}. + ''. + ''. + ''; + foreach my $type (@types) { + $datatable .= ''."\n"; + } + $datatable .= '
'. + ''. + ''. + &mt($type).'
'."\n"; + $itemcount ++; + $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; + $datatable .= ''. + $choices{'exttool'}. + ''. + ''. + ''; + foreach my $type (@types) { + $datatable .= ''."\n"; + } + $datatable .= '
'. + ''. + ''. + &mt($type).'
'."\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', + 'domcoordacc' => 'on', + ); + my @toggles = ('nocodemirror','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', + 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); @@ -7800,7 +8290,7 @@ sub password_rules { if (ref($settings->{chars}) eq 'ARRAY') { map { $chars{$_} = 1; } (@{$settings->{chars}}); } - if ($prefix eq 'passwords') { + if ($prefix eq 'passwords') { if ($settings->{expire}) { $expire = $settings->{expire}; } @@ -7943,7 +8433,7 @@ sub print_wafproxy { my %config = &Apache::lonnet::get_dom('configuration',['wafproxy'],$domain); if (ref($config{'wafproxy'}) eq 'HASH') { $aliases{$domain} = $config{'wafproxy'}{'alias'}; - if (exists($config{'wafproxy'}{'saml'})) { + if (exists($config{'wafproxy'}{'saml'})) { $saml{$domain} = $config{'wafproxy'}{'saml'}; } foreach my $item ('remoteip','ipheader','trusted','vpnint','vpnext') { @@ -7960,8 +8450,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); @@ -8008,10 +8500,10 @@ sub print_wafproxy { (' 'x2).''. &mt('Alias used for SSO Auth').':   '. - ''; + ''; } $aliasrows .= ''; $aliasinfo{$dom_in_effect} .= $aliasrows; @@ -8921,7 +9413,7 @@ sub print_loadbalancing { no => ' checked="checked"', ); my %balcookiechecked = ( - no => ' checked="checked"', + no => ' checked="checked"', ); foreach my $sparetype (@sparestypes) { my $targettable; @@ -9276,8 +9768,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', @@ -9508,7 +10000,7 @@ sub print_selfcreation { ($datatable,$itemcount) = &radiobutton_prefs(\%radiohash,\@toggles,\%defaultchecked, \%choices,$itemcount,$onclick); $$rowtotal += $itemcount; - + if (ref($usertypes) eq 'HASH') { if (keys(%{$usertypes}) > 0) { $datatable .= &insttypes_row($createsettings,$types,$usertypes, @@ -9645,7 +10137,7 @@ sub print_selfcreation { my $currstyle = 'display:none'; if (grep(/^\Q$status\E$/,@ordered)) { $currstyle = $rowstyle; - $hidden = 0; + $hidden = 0; } $datatable .= &noninst_users($processing,$emailverified,$emailoptions,$emaildomain, $emailrules,$emailruleorder,$settings,$status,$rowid, @@ -9672,8 +10164,8 @@ sub print_selfcreation { foreach my $status (@posstypes) { my $rowid = $classprefix.$status; my $datarowstyle = 'display:none'; - if (grep(/^\Q$status\E$/,@ordered)) { - $datarowstyle = $rowstyle; + if (grep(/^\Q$status\E$/,@ordered)) { + $datarowstyle = $rowstyle; } $datatable .= &modifiable_userdata_row('cancreate','emailusername_'.$status,$settings, $numinrow,$$rowtotal,\%usertypeshash,$infofields, @@ -9775,7 +10267,7 @@ function toggleEmailOptions(form,radio,p document.getElementById(altprefix+'_inst_'+status).style.display = 'none'; document.getElementById(altprefix+'_noninst_'+status).style.display = 'none'; if (curr == 'custom') { - if (prefix) { + if (prefix) { document.getElementById(prefix+'_'+status).style.display = 'inline'; } } else if (curr == 'inst') { @@ -9798,10 +10290,10 @@ ENDSCRIPT sub noninst_users { my ($processing,$emailverified,$emailoptions,$emaildomain,$emailrules, - $emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_; + $emailruleorder,$settings,$type,$rowid,$typetitle,$css_class,$rowstyle,$intdom) = @_; my $class = 'LC_left_item'; if ($css_class) { - $css_class = ' class="'.$css_class.'"'; + $css_class = ' class="'.$css_class.'"'; } if ($rowid) { $rowid = ' id="'.$rowid.'"'; @@ -9816,10 +10308,10 @@ sub noninst_users { $description = &mt('Requests for: [_1] (status self-reported)',$typetitle); } $output = ''. - "$description\n". + "$description\n". ''. ''; - my %headers = &Apache::lonlocal::texthash( + my %headers = &Apache::lonlocal::texthash( approve => 'Processing', email => 'E-mail', username => 'Username', @@ -9944,7 +10436,7 @@ sub noninst_users { my $value; if (ref($emaildomain) eq 'HASH') { if (ref($emaildomain->{$type}) eq 'HASH') { - $value = $emaildomain->{$type}->{$option}; + $value = $emaildomain->{$type}->{$option}; } } if ($value eq '') { @@ -10262,7 +10754,7 @@ sub print_defaults { if ($defaults{$item.'_'.$field}) { $checkedon = $checkedoff; $checkedoff = ''; - } + } $datatable .= '
'. ''.$titles->{$field}.' '. ''. @@ -11091,7 +11583,7 @@ sub defaults_javascript { function portalExtras(caller) { var x = caller.value; var y = new Array('email','web'); - for (var i=0; i 0) { @@ -11195,7 +11687,7 @@ sub passwords_javascript { } &js_escape(\%intalert); my $defmin = $Apache::lonnet::passwdmin; - my $intauthjs; + my $intauthjs; if ($prefix eq 'passwords') { $intauthjs = <<"ENDSCRIPT"; function warnIntAuth(field) { @@ -11589,7 +12081,6 @@ sub modifiable_userdata_row { '
'; return $output; @@ -12067,7 +12601,7 @@ sub modify_login { if ($lang eq $env{'form.loginhelpurl_add_lang'}) { $formelem = 'loginhelpurl_add_file'; } - (my $result,$newurl{$lang}) = + (my $result,$newurl{$lang}) = &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname, "help/$lang",'','',$newfile{$lang}, $modified); @@ -12144,7 +12678,7 @@ sub modify_login { my $modified = []; foreach my $lonhost (@newhosts) { my $formelem = 'loginheadtag_'.$lonhost; - (my $result,$newheadtagurls{$lonhost}) = + (my $result,$newheadtagurls{$lonhost}) = &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname, "login/headtag/$lonhost",'','', $env{'form.loginheadtag_'.$lonhost.'.filename'}, @@ -12221,15 +12755,15 @@ sub modify_login { $currsaml{$lonhost}{$item} = $env{'form.saml_'.$item.'_'.$lonhost}; } } else { - if ($saml{$lonhost}) { + if ($saml{$lonhost}) { $changes{'saml'}{$lonhost} = 1; delete($currsaml{$lonhost}); } } } foreach my $posshost (keys(%currsaml)) { - unless (exists($domservers{$posshost})) { - delete($currsaml{$posshost}); + unless (exists($domservers{$posshost})) { + delete($currsaml{$posshost}); } } %{$loginhash{'login'}{'saml'}} = %currsaml; @@ -12243,7 +12777,7 @@ sub modify_login { my $modified = []; foreach my $lonhost (@newsamlimgs) { my $formelem = 'saml_img_'.$lonhost; - my ($result,$imgurl) = + my ($result,$imgurl) = &Apache::lonconfigsettings::publishlogo($r,'upload',$formelem,$dom,$confname, "login/saml/$lonhost",'','', $env{'form.saml_img_'.$lonhost.'.filename'}, @@ -12613,7 +13147,7 @@ sub modify_ipaccess { $possrange =~ s/,+/,/g; if ($possrange ne '') { my (@ok,$count); - $count = 0; + $count = 0; foreach my $poss (split(/\,/,$possrange)) { $count ++; $poss = &validate_ip_pattern($poss); @@ -12646,9 +13180,9 @@ sub modify_ipaccess { } } $confhash{$itemid}{'commblocks'} = {}; - + my %commblocks; - map { $commblocks{$_} = 1; } &Apache::loncommon::get_env_multiple('form.ipaccess_block_'.$idx); + map { $commblocks{$_} = 1; } &Apache::loncommon::get_env_multiple('form.ipaccess_block_'.$idx); foreach my $type (@{$typeorder}) { if ($commblocks{$type}) { $confhash{$itemid}{'commblocks'}{$type} = 'on'; @@ -12680,7 +13214,7 @@ sub modify_ipaccess { } $env{'form.ipaccess_cnum_'.$idx} =~ s/^\s+|\s+$//g; $env{'form.ipaccess_cdom_'.$idx} =~ s/^\s+|\s+$//g; - if (($env{'form.ipaccess_cnum_'.$idx} =~ /^$match_courseid$/) && + if (($env{'form.ipaccess_cnum_'.$idx} =~ /^$match_courseid$/) && ($env{'form.ipaccess_cdom_'.$idx} =~ /^$match_domain$/)) { if (&Apache::lonnet::homeserver($env{'form.ipaccess_cnum_'.$idx}, $env{'form.ipaccess_cdom_'.$idx}) eq 'no_host') { @@ -12760,7 +13294,7 @@ sub modify_ipaccess { if (keys(%{$confhash{$itemid}{'courses'}})) { my @courses; foreach my $cid (sort(keys(%{$confhash{$itemid}{'courses'}}))) { - my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1}); + my %courseinfo = &Apache::lonnet::coursedescription($cid,{'one_time' => 1}); push(@courses,$courseinfo{'description'}.' ('.$cid.')'); } $resulttext .= '
  • '.&mt('Courses/Communities allowed').':
    • '. @@ -12828,6 +13362,239 @@ 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', + 'domcoordacc' => 'on', + 'editors' => ['edit','xml']. + 'authorquota' => 500, + 'webdav' => 0, + ); + my %titles = &authordefaults_titles(); + foreach my $item ('nocodemirror','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','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','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','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 '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); @@ -13355,15 +14122,21 @@ sub subscribed_hosts { sub check_switchserver { my ($dom,$confname) = @_; - my ($allowed,$switchserver); - my $home = &Apache::lonnet::homeserver($confname,$dom); - if ($home eq 'no_host') { + my ($allowed,$switchserver,$home); + if ($confname eq '') { $home = &Apache::lonnet::domain($dom,'primary'); + } else { + $home = &Apache::lonnet::homeserver($confname,$dom); + if ($home eq 'no_host') { + $home = &Apache::lonnet::domain($dom,'primary'); + } } my @ids=&Apache::lonnet::current_machine_ids(); foreach my $id (@ids) { if ($id eq $home) { $allowed=1; } } if (!$allowed) { - $switchserver=''.&mt('Switch Server').''; + $switchserver=''.&mt('Switch Server').''; } return $switchserver; } @@ -13375,7 +14148,7 @@ sub modify_quotas { $author_ok,$switchserver,$errors,$validationitemsref,$validationnamesref, $validationfieldsref); if ($action eq 'quotas') { - $context = 'tools'; + $context = 'tools'; } else { $context = $action; } @@ -13395,7 +14168,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); @@ -13418,8 +14191,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); } @@ -13713,7 +14484,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') { @@ -13802,15 +14572,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') { @@ -13830,21 +14595,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') { @@ -13885,19 +14635,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) { @@ -14188,15 +14925,22 @@ sub modify_ltitools { $action => { %newtoolsenc } ); &Apache::lonnet::put_dom('encconfig',\%toolsenchash,$dom,undef,1); + my $cachetime = 24*60*60; + &Apache::lonnet::do_cache_new('ltitoolsenc',$dom,\%newtoolsenc,$cachetime); &store_security($dom,'ltitools',\%secchanges,\%newkeyset,\%keystore,$lastactref); } $resulttext = &mt('Changes made:').'
        '; if (keys(%secchanges) > 0) { - $resulttext .= <i_security_results('ltitools',\%secchanges,\%newtoolsec,\%newkeyset,\%keystore); + $resulttext .= <i_security_results($dom,'ltitools',\%secchanges,\%newtoolsec,\%newkeyset,\%keystore); } if (keys(%ltitoolschg) > 0) { $resulttext .= $ltitoolsoutput; } + my $cachetime = 24*60*60; + &Apache::lonnet::do_cache_new('ltitools',$dom,\%newltitools,$cachetime); + if (ref($lastactref) eq 'HASH') { + $lastactref->{'ltitools'} = 1; + } } else { $errors .= '
      • '.&mt('Failed to save changes').'
      • '; } @@ -14277,7 +15021,6 @@ sub fetch_secrets { foreach my $hostid (keys(%servers)) { if (($hostid ne '') && (grep(/^\Q$hostid\E$/,@ids))) { - my $newkey; my $keyitem = 'form.'.$context.'_privkey_'.$hostid; if (exists($env{$keyitem})) { $env{$keyitem} =~ s/(`)/'/g; @@ -14301,7 +15044,7 @@ sub fetch_secrets { } sub store_security { - my ($dom,$context,$secchanges,$newkeyset,$keystore,$lastactref) = @_; + my ($dom,$context,$secchanges,$newkeyset,$keystore) = @_; return unless ((ref($secchanges) eq 'HASH') && (ref($newkeyset) eq 'HASH') && (ref($keystore) eq 'HASH')); if (keys(%{$secchanges})) { @@ -14316,19 +15059,17 @@ sub store_security { $dom,$hostid); } } - if (ref($lastactref) eq 'HASH') { - if (($secchanges->{'encrypt'}) || ($secchanges->{'private'})) { - $lastactref->{'domdefaults'} = 1; - } - } } } sub lti_security_results { - my ($context,$secchanges,$newsec,$newkeyset,$keystore) = @_; + my ($dom,$context,$secchanges,$newsec,$newkeyset,$keystore) = @_; my $output; + my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); + my $needs_update; foreach my $item (keys(%{$secchanges})) { if ($item eq 'encrypt') { + $needs_update = 1; my %encrypted; if ($context eq 'lti') { %encrypted = ( @@ -14356,16 +15097,32 @@ sub lti_security_results { off => &mt('Encryption of stored external tool secrets defined in domain disabled'), }, ); - } my @types= ('crs','dom'); if ($context eq 'lti') { + foreach my $type (@types) { + undef($domdefaults{'linkprotenc_'.$type}); + } push(@types,'consumers'); + undef($domdefaults{'ltienc_consumers'}); + } elsif ($context eq 'ltitools') { + foreach my $type (@types) { + undef($domdefaults{'toolenc_'.$type}); + } } foreach my $type (@types) { my $shown = $encrypted{$type}{'off'}; if (ref($newsec->{$item}) eq 'HASH') { if ($newsec->{$item}{$type}) { + if ($context eq 'lti') { + if ($type eq 'consumers') { + $domdefaults{'ltienc_consumers'} = 1; + } else { + $domdefaults{'linkprotenc_'.$type} = 1; + } + } elsif ($context eq 'ltitools') { + $domdefaults{'toolenc_'.$type} = 1; + } $shown = $encrypted{$type}{'on'}; } } @@ -14409,17 +15166,60 @@ sub lti_security_results { $output .= '
      • '.&mt('[_1] set to none',$titles{'chars'}).'
      • '; } } elsif ($item eq 'private') { + $needs_update = 1; + if ($context eq 'lti') { + undef($domdefaults{'ltiprivhosts'}); + } elsif ($context eq 'ltitools') { + undef($domdefaults{'toolprivhosts'}); + } if (keys(%{$newkeyset})) { + my @privhosts; foreach my $hostid (sort(keys(%{$newkeyset}))) { if ($keystore->{$hostid} eq 'ok') { $output .= '
      • '.&mt('Encryption key for storage of shared secrets saved for [_1]',$hostid).'
      • '; + unless (grep(/^\Q$hostid\E$/,@privhosts)) { + push(@privhosts,$hostid); + } + } + } + if (@privhosts) { + if ($context eq 'lti') { + $domdefaults{'ltiprivhosts'} = \@privhosts; + } elsif ($context eq 'ltitools') { + $domdefaults{'toolprivhosts'} = \@privhosts; } } } } 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) { + my $cachetime = 24*60*60; + &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); + } return $output; } @@ -14959,7 +15759,7 @@ sub process_proctoring_image { sub modify_lti { my ($r,$dom,$action,$lastactref,%domconfig) = @_; my %domdefaults = &Apache::lonnet::get_domain_defaults($dom,1); - my ($newid,@allpos,%changes,%confhash,%encconfig,$errors,$resulttext); + my ($newid,@allpos,%changes,%confhash,%ltienc,$errors,$resulttext); my (%posslti,%posslticrs,%posscrstype); my @courseroles = ('cc','in','ta','ep','st'); my @ltiroles = qw(Learner Instructor ContentDeveloper TeachingAssistant Mentor Member Manager Administrator); @@ -15018,7 +15818,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') { @@ -15040,17 +15840,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.'
      • '; } } @@ -15073,29 +15931,43 @@ sub modify_lti { } } } + my (%keystore,$secstored); + if ($is_home) { + &store_security($dom,'lti',\%secchanges,\%newkeyset,\%keystore); + } + + my ($cipher,$privnum); + if ((@items > 0) && ($is_home)) { + ($cipher,$privnum) = &get_priv_creds($dom,$home,$secchanges{'encrypt'}, + $newltisec{'encrypt'},$keystore{$home}); + } foreach my $idx (@items) { my $itemid = $itemids{$idx}; next unless ($itemid); + my %currlti; + unless ($idx eq 'add') { + if (ref($domconfig{$action}) eq 'HASH') { + if (ref($domconfig{$action}{$itemid}) eq 'HASH') { + %currlti = %{$domconfig{$action}{$itemid}}; + } + } + } my $position = $env{'form.lti_pos_'.$itemid}; $position =~ s/\D+//g; if ($position ne '') { $allpos[$position] = $itemid; } - foreach my $item ('consumer','key','secret','lifetime','requser','crsinc') { + foreach my $item ('consumer','lifetime','requser','crsinc') { my $formitem = 'form.lti_'.$item.'_'.$idx; $env{$formitem} =~ s/(`)/'/g; if ($item eq 'lifetime') { $env{$formitem} =~ s/[^\d.]//g; } if ($env{$formitem} ne '') { - if (($item eq 'key') || ($item eq 'secret')) { - $encconfig{$itemid}{$item} = $env{$formitem}; - } else { - $confhash{$itemid}{$item} = $env{$formitem}; - unless (($idx eq 'add') || ($changes{$itemid})) { - if ($domconfig{$action}{$itemid}{$item} ne $confhash{$itemid}{$item}) { - $changes{$itemid} = 1; - } + $confhash{$itemid}{$item} = $env{$formitem}; + unless (($idx eq 'add') || ($changes{$itemid})) { + if ($currlti{$item} ne $confhash{$itemid}{$item}) { + $changes{$itemid} = 1; } } } @@ -15236,27 +16108,27 @@ sub modify_lti { unless (($idx eq 'add') || ($changes{$itemid})) { if ($confhash{$itemid}{'crsinc'}) { foreach my $field ('mapcrs','storecrs','makecrs','section','passback','roster') { - if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) { + if ($currlti{$field} ne $confhash{$itemid}{$field}) { $changes{$itemid} = 1; } } unless ($changes{$itemid}) { - if ($domconfig{$action}{$itemid}{'passback'} eq $confhash{$itemid}{'passback'}) { - if ($domconfig{$action}{$itemid}{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) { + if ($currlti{'passback'} eq $confhash{$itemid}{'passback'}) { + if ($currlti{'passbackformat'} ne $confhash{$itemid}{'passbackformat'}) { $changes{$itemid} = 1; } } } foreach my $field ('mapcrstype','selfenroll') { unless ($changes{$itemid}) { - if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') { + if (ref($currlti{$field}) eq 'ARRAY') { if (ref($confhash{$itemid}{$field}) eq 'ARRAY') { - my @diffs = &Apache::loncommon::compare_arrays($domconfig{$action}{$itemid}{$field}, + my @diffs = &Apache::loncommon::compare_arrays($currlti{$field}, $confhash{$itemid}{$field}); if (@diffs) { $changes{$itemid} = 1; } - } elsif (@{$domconfig{$action}{$itemid}{$field}} > 0) { + } elsif (@{$currlti{$field}} > 0) { $changes{$itemid} = 1; } } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') { @@ -15267,10 +16139,10 @@ sub modify_lti { } } unless ($changes{$itemid}) { - if (ref($domconfig{$action}{$itemid}{'maproles'}) eq 'HASH') { + if (ref($currlti{'maproles'}) eq 'HASH') { if (ref($confhash{$itemid}{'maproles'}) eq 'HASH') { - foreach my $ltirole (keys(%{$domconfig{$action}{$itemid}{'maproles'}})) { - if ($domconfig{$action}{$itemid}{'maproles'}{$ltirole} ne + foreach my $ltirole (keys(%{$currlti{'maproles'}})) { + if ($currlti{'maproles'}{$ltirole} ne $confhash{$itemid}{'maproles'}{$ltirole}) { $changes{$itemid} = 1; last; @@ -15279,13 +16151,13 @@ sub modify_lti { unless ($changes{$itemid}) { foreach my $ltirole (keys(%{$confhash{$itemid}{'maproles'}})) { if ($confhash{$itemid}{'maproles'}{$ltirole} ne - $domconfig{$action}{$itemid}{'maproles'}{$ltirole}) { + $currlti{'maproles'}{$ltirole}) { $changes{$itemid} = 1; last; } } } - } elsif (keys(%{$domconfig{$action}{$itemid}{'maproles'}}) > 0) { + } elsif (keys(%{$currlti{'maproles'}}) > 0) { $changes{$itemid} = 1; } } elsif (ref($confhash{$itemid}{'maproles'}) eq 'HASH') { @@ -15299,20 +16171,20 @@ sub modify_lti { } unless ($changes{$itemid}) { foreach my $field ('mapuser','lcauth','lcauthparm','topmenu','inlinemenu','callback') { - if ($domconfig{$action}{$itemid}{$field} ne $confhash{$itemid}{$field}) { + if ($currlti{$field} ne $confhash{$itemid}{$field}) { $changes{$itemid} = 1; } } unless ($changes{$itemid}) { foreach my $field ('makeuser','lcmenu') { - if (ref($domconfig{$action}{$itemid}{$field}) eq 'ARRAY') { + if (ref($currlti{$field}) eq 'ARRAY') { if (ref($confhash{$itemid}{$field}) eq 'ARRAY') { - my @diffs = &Apache::loncommon::compare_arrays($domconfig{$action}{$itemid}{$field}, + my @diffs = &Apache::loncommon::compare_arrays($currlti{$field}, $confhash{$itemid}{$field}); if (@diffs) { $changes{$itemid} = 1; } - } elsif (@{$domconfig{$action}{$itemid}{$field}} > 0) { + } elsif (@{$currlti{$field}} > 0) { $changes{$itemid} = 1; } } elsif (ref($confhash{$itemid}{$field}) eq 'ARRAY') { @@ -15325,6 +16197,71 @@ sub modify_lti { } } } + if ($is_home) { + my $keyitem = 'form.lti_key_'.$idx; + $env{$keyitem} =~ s/(`)/'/g; + if ($env{$keyitem} ne '') { + $ltienc{$itemid}{'key'} = $env{$keyitem}; + unless ($changes{$itemid}) { + if ($currlti{'key'} ne $env{$keyitem}) { + $changes{$itemid} = 1; + } + } + } + my $secretitem = 'form.lti_secret_'.$idx; + $env{$secretitem} =~ s/(`)/'/g; + if ($currlti{'usable'}) { + if ($env{'form.lti_changesecret_'.$idx}) { + if ($env{$secretitem} ne '') { + if ($privnum && $cipher) { + $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem}); + $confhash{$itemid}{'cipher'} = $privnum; + } else { + $ltienc{$itemid}{'secret'} = $env{$secretitem}; + } + $changes{$itemid} = 1; + } + } else { + $ltienc{$itemid}{'secret'} = $currlti{'secret'}; + $confhash{$itemid}{'cipher'} = $currlti{'cipher'}; + } + if (ref($ltienc{$itemid}) eq 'HASH') { + if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'secret'} ne '')) { + $confhash{$itemid}{'usable'} = 1; + } + } + } elsif ($env{$secretitem} ne '') { + if ($privnum && $cipher) { + $ltienc{$itemid}{'secret'} = $cipher->encrypt_hex($env{$secretitem}); + $confhash{$itemid}{'cipher'} = $privnum; + } else { + $ltienc{$itemid}{'secret'} = $env{$secretitem}; + } + if (ref($ltienc{$itemid}) eq 'HASH') { + if (($ltienc{$itemid}{'key'} ne '') && ($ltienc{$itemid}{'key'} ne '')) { + $confhash{$itemid}{'usable'} = 1; + } + } + $changes{$itemid} = 1; + } + } + unless ($changes{$itemid}) { + foreach my $key (keys(%currlti)) { + if (ref($currlti{$key}) eq 'HASH') { + if (ref($confhash{$itemid}{$key}) eq 'HASH') { + foreach my $innerkey (keys(%{$currlti{$key}})) { + unless (exists($confhash{$itemid}{$key}{$innerkey})) { + $changes{$itemid} = 1; + last; + } + } + } elsif (keys(%{$currlti{$key}}) > 0) { + $changes{$itemid} = 1; + } + } + last if ($changes{$itemid}); + } + } } if (@allpos > 0) { my $idx = 0; @@ -15342,12 +16279,21 @@ sub modify_lti { } } } + + if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) { + return &mt('No changes made.'); + } + my %ltihash = ( $action => { %confhash } ); - my %ltienchash = ( - $action => { %encconfig } - ); + my %ltienchash; + + if ($is_home) { + %ltienchash = ( + $action => { %ltienc } + ); + } if (keys(%secchanges)) { $ltihash{'ltisec'} = \%newltisec; if ($secchanges{'linkprot'}) { @@ -15358,43 +16304,32 @@ sub modify_lti { } my $putresult = &Apache::lonnet::put_dom('configuration',\%ltihash,$dom); if ($putresult eq 'ok') { - my %keystore; - &store_security($dom,'lti',\%secchanges,\%newkeyset,\%keystore,$lastactref); - &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1); - if ((keys(%changes) == 0) && (keys(%secchanges) == 0)) { - return &mt('No changes made.'); + if (keys(%ltienchash)) { + &Apache::lonnet::put_dom('encconfig',\%ltienchash,$dom,undef,1); } $resulttext = &mt('Changes made:').'
          '; if (keys(%secchanges) > 0) { - $resulttext .= <i_security_results('lti',\%secchanges,\%newltisec,\%newkeyset,\%keystore); + $resulttext .= <i_security_results($dom,'lti',\%secchanges,\%newltisec,\%newkeyset,\%keystore); if (exists($secchanges{'linkprot'})) { $resulttext .= $linkprotoutput; } } if (keys(%changes) > 0) { my $cachetime = 24*60*60; - my %ltiall = %confhash; - foreach my $id (keys(%ltiall)) { - if (ref($encconfig{$id}) eq 'HASH') { - foreach my $item ('key','secret') { - $ltiall{$id}{$item} = $encconfig{$id}{$item}; - } - } - } - &Apache::lonnet::do_cache_new('lti',$dom,\%ltiall,$cachetime); + &Apache::lonnet::do_cache_new('lti',$dom,\%confhash,$cachetime); if (ref($lastactref) eq 'HASH') { $lastactref->{'lti'} = 1; } my %bynum; foreach my $itemid (sort(keys(%changes))) { - my $position = $confhash{$itemid}{'order'}; - $bynum{$position} = $itemid; + if (ref($confhash{$itemid}) eq 'HASH') { + my $position = $confhash{$itemid}{'order'}; + $bynum{$position} = $itemid; + } } foreach my $pos (sort { $a <=> $b } keys(%bynum)) { my $itemid = $bynum{$pos}; - if (ref($confhash{$itemid}) ne 'HASH') { - $resulttext .= '
        • '.&mt('Deleted: [_1]',$changes{$itemid}).'
        • '; - } else { + if (ref($confhash{$itemid}) eq 'HASH') { $resulttext .= '
        • '.$confhash{$itemid}{'consumer'}.'
            '; my $position = $pos + 1; $resulttext .= '
          • '.&mt('Order: [_1]',$position).'
          • '; @@ -15403,13 +16338,11 @@ sub modify_lti { $resulttext .= '
          • '.$lt{$item}.': '.$confhash{$itemid}{$item}.'
          • '; } } - if ($encconfig{$itemid}{'key'} ne '') { - $resulttext .= '
          • '.$lt{'key'}.': '.$encconfig{$itemid}{'key'}.'
          • '; + if ($ltienc{$itemid}{'key'} ne '') { + $resulttext .= '
          • '.$lt{'key'}.': '.$ltienc{$itemid}{'key'}.'
          • '; } - if ($encconfig{$itemid}{'secret'} ne '') { - $resulttext .= '
          • '.$lt{'secret'}.': '; - my $num = length($encconfig{$itemid}{'secret'}); - $resulttext .= ('*'x$num).'
          • '; + if ($ltienc{$itemid}{'secret'} ne '') { + $resulttext .= '
          • '.$lt{'secret'}.': ['.&mt('not shown').']
          • '; } if ($confhash{$itemid}{'requser'}) { if ($confhash{$itemid}{'callback'}) { @@ -15561,8 +16494,19 @@ sub modify_lti { $resulttext .= '
        • '; } } + if (keys(%deletions)) { + foreach my $itemid (sort { $a <=> $b } keys(%deletions)) { + $resulttext .= '
        • '.&mt('Deleted: [_1]',$changes{$itemid}).'
        • '; + } + } } $resulttext .= '
        '; + if (ref($lastactref) eq 'HASH') { + if (($secchanges{'encrypt'}) || ($secchanges{'private'}) || (exists($secchanges{'suggested'}))) { + &Apache::lonnet::get_domain_defaults($dom,1); + $lastactref->{'domdefaults'} = 1; + } + } } else { $errors .= '
      • '.&mt('Failed to save changes').'
      • '; } @@ -15573,24 +16517,51 @@ sub modify_lti { return $resulttext; } +sub get_priv_creds { + my ($dom,$home,$encchg,$encrypt,$storedsec) = @_; + my ($needenc,$cipher,$privnum); + my %domdefs = &Apache::lonnet::get_domain_defaults($dom); + if (($encchg) && (ref($encrypt) eq 'HASH')) { + $needenc = $encrypt->{'consumers'} + } else { + $needenc = $domdefs{'ltienc_consumers'}; + } + if ($needenc) { + if (($storedsec eq 'ok') || ((ref($domdefs{'ltiprivhosts'}) eq 'ARRAY') && + (grep(/^\Q$home\E$/,@{$domdefs{'ltiprivhosts'}})))) { + my %privhash = &Apache::lonnet::restore_dom('lti','private',$dom,$home,1); + my $privkey = $privhash{'key'}; + $privnum = $privhash{'version'}; + if (($privnum) && ($privkey ne '')) { + $cipher = Crypt::CBC->new({'key' => $privkey, + 'cipher' => 'DES'}); + } + } + } + return ($cipher,$privnum); +} + 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)) { @@ -15602,14 +16573,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'; } @@ -16375,7 +17346,7 @@ sub modify_contacts { $contacts_hash{'contacts'}{'overrides'}{$type}{'include'} = $includeloc{$type}.':'.&escape($includestr{$type}); $newsetting{'override_'.$type}{'include'} = $contacts_hash{'contacts'}{'overrides'}{$type}{'include'}; } - } + } } } if (keys(%currsetting) > 0) { @@ -16433,12 +17404,12 @@ sub modify_contacts { } } if (@statuses) { - if (ref($currsetting{'overrides'}) eq 'HASH') { + if (ref($currsetting{'overrides'}) eq 'HASH') { foreach my $key (keys(%{$currsetting{'overrides'}})) { if (ref($currsetting{'overrides'}{$key}) eq 'HASH') { if (ref($newsetting{'override_'.$key}) eq 'HASH') { foreach my $item (@contacts,'bcc','others','include') { - if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) { + if ($currsetting{'overrides'}{$key}{$item} ne $newsetting{'override_'.$key}{$item}) { push(@{$changes{'overrides'}},$key); last; } @@ -16455,7 +17426,7 @@ sub modify_contacts { } } else { foreach my $key (@overrides) { - push(@{$changes{'overrides'}},$key); + push(@{$changes{'overrides'}},$key); } } } @@ -16637,7 +17608,7 @@ sub modify_contacts { $resulttext .= $bcctext.': '.$bcc{$type}.''; } elsif (!@text) { $resulttext .= &mt('No one'); - } + } if ($includestr{$type} ne '') { if ($includeloc{$type} eq 'b') { $resulttext .= '
        '.&mt('Text automatically added to e-mail body:').' '.$includestr{$type}; @@ -16661,14 +17632,14 @@ sub modify_contacts { if (ref($newsetting{'override_'.$type}) eq 'HASH') { my @text; foreach my $item (@contacts) { - if ($newsetting{'override_'.$type}{$item}) { + if ($newsetting{'override_'.$type}{$item}) { push(@text,$short_titles->{$item}); } } if ($newsetting{'override_'.$type}{'others'} ne '') { push(@text,$newsetting{'override_'.$type}{'others'}); } - + if (@text) { $resulttext .= &mt('Helpdesk e-mail sent to: [_1]', ''.join(', ',@text).''); @@ -16831,7 +17802,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'}}; @@ -17067,6 +18038,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'); } @@ -17509,7 +18502,7 @@ sub modify_passwords { ); my $needed = '
      • '. join('
      • ',map {$rulenames{$_} } @{$confighash{'passwords'}{'chars'}}). - '
      '; + '
    '; $resulttext .= '
  • '.&mt('[_1] set to: [_2]',$titles{'chars'},$needed).'
  • '; } else { $resulttext .= '
  • '.&mt('[_1] set to none',$titles{'chars'}).'
  • '; @@ -17992,7 +18985,7 @@ sub modify_selfcreation { if (($chosen eq 'inst') || ($chosen eq 'noninst')) { my $emaildom; if ($env{'form.cancreate_emaildomain_'.$chosen.'_'.$type} =~ /^\@[^\@]+$/) { - $emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type}; + $emaildom = $env{'form.cancreate_emaildomain_'.$chosen.'_'.$type}; $cancreate{'emaildomain'}{$type}{$chosen} = $emaildom; if (ref($curremaildom{$type}) eq 'HASH') { if (exists($curremaildom{$type}{$chosen})) { @@ -18004,7 +18997,7 @@ sub modify_selfcreation { } } elsif ($emaildom ne '') { push(@{$changes{'cancreate'}},'emaildomain'); - } + } } $cancreate{'emailoptions'}{$type} = $env{'form.cancreate_emailoptions_'.$type}; } elsif ($chosen eq 'custom') { @@ -18431,7 +19424,7 @@ sub modify_selfcreation { ); if (@types) { if (@statuses) { - $chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:'). + $chgtext .= &mt('Processing of requests to create account with e-mail verification set as follows:'). '
      '; foreach my $status (@statuses) { if ($status eq 'default') { @@ -18639,7 +19632,7 @@ sub modify_selfcreation { $typename = $othertitle; } else { $typename = $usertypes{$type}; - } + } $chgtext .= &mt('(Affiliation: [_1])',$typename); } if (@{$email_rule{$type}} > 0) { @@ -18984,7 +19977,7 @@ sub modify_defaults { } if ($item eq 'portal_def') { unless (grep(/^\Q$item\E$/,@errors)) { - if ($newvalues{$item} eq '') { + if ($newvalues{$item} eq '') { foreach my $field ('email','web') { if (exists($domdefaults{$item.'_'.$field})) { delete($domdefaults{$item.'_'.$field}); @@ -19169,7 +20162,7 @@ sub modify_defaults { $resulttext =~ s/, $//; $resulttext .= ''; } else { - $resulttext .= '
    • '.&mt('Institutional user status types deleted').'
    • '; + $resulttext .= '
    • '.&mt('Institutional user status types deleted').'
    • '; } } } elsif ($item eq 'unamemap_rule') { @@ -20204,14 +21197,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', @@ -20256,7 +21254,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}; } @@ -20268,7 +21266,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; @@ -20403,6 +21401,66 @@ sub modify_coursedefaults { $changes{'postsubmit'} = 1; } } + 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 { + foreach my $type (@types) { + if ($staticdefaults{'domexttool'}) { + $olddomexttool{$type} = 1; + } else { + $olddomexttool{$type} = 0; + } + } + } + if (ref($domconfig{'coursedefaults'}{'exttool'}) eq 'HASH') { + %oldexttool = %{$domconfig{'coursedefaults'}{'exttool'}}; + } else { + foreach my $type (@types) { + if ($staticdefaults{'exttool'}) { + $oldexttool{$type} = 1; + } else { + $oldexttool{$type} = 0; + } + } + } + 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; + } + 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); @@ -20412,8 +21470,10 @@ sub modify_coursedefaults { if (($changes{'canuse_pdfforms'}) || ($changes{'uploadquota'}) || ($changes{'postsubmit'}) || ($changes{'coursecredits'}) || ($changes{'uselcmath'}) || ($changes{'usejsme'}) || ($changes{'canclone'}) || ($changes{'mysqltables'}) || ($changes{'texengine'}) || - ($changes{'inline_chem'}) || ($changes{'ltiauth'})) { - foreach my $item ('canuse_pdfforms','uselcmath','usejsme','inline_chem','texengine','ltiauth') { + ($changes{'inline_chem'}) || ($changes{'ltiauth'}) || ($changes{'domexttool'}) || + ($changes{'exttool'}) || ($changes{'coursequota'}) || ($changes{'crsauthor'})) { + foreach my $item ('canuse_pdfforms','uselcmath','usejsme','inline_chem','texengine', + 'ltiauth') { if ($changes{$item}) { $domdefaults{$item}=$defaultshash{'coursedefaults'}{$item}; } @@ -20444,6 +21504,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') { @@ -20456,6 +21523,27 @@ sub modify_coursedefaults { $domdefaults{'canclone'}=$defaultshash{'coursedefaults'}{'canclone'}; } } + if ($changes{'domexttool'}) { + if (ref($defaultshash{'coursedefaults'}{'domexttool'}) eq 'HASH') { + foreach my $type (@types) { + $domdefaults{$type.'domexttool'}=$defaultshash{'coursedefaults'}{'domexttool'}{$type}; + } + } + } + if ($changes{'exttool'}) { + if (ref($defaultshash{'coursedefaults'}{'exttool'}) eq 'HASH') { + foreach my $type (@types) { + $domdefaults{$type.'exttool'}=$defaultshash{'coursedefaults'}{'exttool'}{$type}; + } + } + } + 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') { @@ -20508,6 +21596,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').'
        '. @@ -20593,6 +21694,35 @@ sub modify_coursedefaults { } else { $resulttext .= '
      • '.&mt('LTI launch of deep-linked URL will require re-authentication').'
      • '; } + } elsif (($item eq 'domexttool') || ($item eq 'exttool') || ($item eq 'crsauthor')) { + my @noyes = (&mt('no'),&mt('yes')); + 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 .= '
      • '.$status{$item}{'default'}.'
      • '; + } } } $resulttext .= '
      '; @@ -20986,7 +22116,7 @@ sub modify_wafproxy { } } elsif ($currvalue{$item}) { $changes{$item} = 1; - } + } } } else { if (keys(%curralias)) { @@ -20994,7 +22124,7 @@ sub modify_wafproxy { } if (keys(%currsaml)) { $changes{'saml'} = 1; - } + } if (keys(%currvalue)) { foreach my $key (keys(%currvalue)) { $changes{$key} = 1; @@ -21004,7 +22134,7 @@ sub modify_wafproxy { if (keys(%changes)) { my %defaultshash = ( wafproxy => \%wafproxy, - ); + ); my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, $dom); if ($putresult eq 'ok') { @@ -21020,7 +22150,7 @@ sub modify_wafproxy { $domdefaults{'waf_'.$item} = $wafproxy{$item}; } elsif (exists($domdefaults{'waf_'.$item})) { delete($domdefaults{'waf_'.$item}); - } + } } } if ($updatedomdefs) { @@ -21087,7 +22217,7 @@ sub modify_wafproxy { $output .= '
    • '.&mt('Aliases deleted for hostnames').'
    • '; } } elsif ($item eq 'saml') { - my $shown; + my $shown; if (ref($wafproxy{'saml'}) eq 'HASH') { if (keys(%{$wafproxy{'saml'}})) { $shown = join(', ',sort(keys(%{$wafproxy{'saml'}}))); @@ -21417,7 +22547,7 @@ sub modify_usersessions { if (($offload eq 'offloadoth') && (@okoffloadoth)) { $changes{'offloadoth'} = 1; } - } + } } } else { if (@okoffload) { @@ -21955,7 +23085,7 @@ sub modify_loadbalancing { } if ($env{'form.loadbalancing_cookie_'.$i}) { $defaultshash{'loadbalancing'}{$balancer}{'cookie'} = 1; - if (exists($currbalancer{$balancer})) { + if (exists($currbalancer{$balancer})) { unless ($currcookies{$balancer}) { $changes{'curr'}{$balancer}{'cookie'} = 1; } @@ -22641,7 +23771,6 @@ function balancerChange(balnum,baltotal, END } - sub new_spares_js { my @sparestypes = ('primary','default'); my $types = join("','",@sparestypes);
    '; my $rem; my %checks; - my %current; if (ref($settings) eq 'HASH') { my $hashref; if ($context eq 'lti') { @@ -11615,7 +12106,7 @@ sub modifiable_userdata_row { } } } - if (ref($hashref) eq 'HASH') { + if (ref($hashref) eq 'HASH') { foreach my $field (@fields) { if ($hashref->{$field}) { if ($role eq 'emailusername') { @@ -11627,7 +12118,6 @@ sub modifiable_userdata_row { } } } - my $total = scalar(@fields); for (my $i=0; $i<$total; $i++) { $rem = $i%($numinrow); @@ -11716,15 +12206,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') { @@ -11761,25 +12255,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 .= ''; + } 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); @@ -11791,7 +12304,7 @@ sub insttypes_row { } else { $output .= ''; @@ -11801,20 +12314,41 @@ sub insttypes_row { } else { $output .= '
    '."\n". + ''. + ''. - ''; } - $output .= ' '; + $output .= ' '; } else { if ($rem == 0) { $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 .= '