--- loncom/interface/domainprefs.pm 2009/11/23 21:45:18 1.120 +++ loncom/interface/domainprefs.pm 2013/09/29 06:53:35 1.210 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set domain-wide configuration settings # -# $Id: domainprefs.pm,v 1.120 2009/11/23 21:45:18 raeburn Exp $ +# $Id: domainprefs.pm,v 1.210 2013/09/29 06:53:35 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -45,7 +45,7 @@ described at http://www.lon-capa.org. =head1 OVERVIEW Each institution using LON-CAPA will typically have a single domain designated -for use by individuals affliated with the institution. Accordingly, each domain +for use by individuals affiliated with the institution. Accordingly, each domain may define a default set of logos and a color scheme which can be used to "brand" the LON-CAPA instance. In addition, an institution will typically have a language and timezone which are used for the majority of courses. @@ -86,15 +86,16 @@ $dom,$settings,$rowtotal,$action. $dom is the domain, $settings is a reference to a hash of current settings for the current context, $rowtotal is a reference to the scalar used to record the -number of rows displayed on the page, and $action is the context (either quotas -or requestcourses). +number of rows displayed on the page, and $action is the context (quotas, +requestcourses or requestauthor). The print_quotas routine was orginally created to display/store information about default quota sizes for portfolio spaces for the different types of 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. +used by course owners to request creation of a course, and to display/store +default quota sizes for authoring spaces. Outputs: 1 @@ -140,7 +141,7 @@ autolimit =over -- course requests will be processed autoatically up to a limit of +- course requests will be processed automatically up to a limit of N requests for the course type for the particular requestor. If N is undefined, there is no limit to the number of course requests which a course owner may submit and have processed automatically. @@ -171,6 +172,9 @@ use Locale::Language; use DateTime::TimeZone; use DateTime::Locale; +my $registered_cleanup; +my $modified_urls; + sub handler { my $r=shift; if ($r->header_only) { @@ -190,6 +194,10 @@ sub handler { "/adm/domainprefs:mau:0:0:Cannot modify domain settings"; return HTTP_NOT_ACCEPTABLE; } + + $registered_cleanup=0; + @{$modified_urls}=(); + &Apache::lonhtmlcommon::clear_breadcrumbs(); &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['phase','actions']); @@ -197,16 +205,28 @@ sub handler { if ( exists($env{'form.phase'}) ) { $phase = $env{'form.phase'}; } + my %servers = &Apache::lonnet::internet_dom_servers($dom); my %domconfig = &Apache::lonnet::get_dom('configuration',['login','rolecolors', - 'quotas','autoenroll','autoupdate','directorysrch', - 'usercreation','usermodification','contacts','defaults', - 'scantron','coursecategories','serverstatuses', - 'requestcourses','helpsettings'],$dom); + 'quotas','autoenroll','autoupdate','autocreate', + 'directorysrch','usercreation','usermodification', + 'contacts','defaults','scantron','coursecategories', + 'serverstatuses','requestcourses','helpsettings', + 'coursedefaults','usersessions','loadbalancing', + 'requestauthor'],$dom); my @prefs_order = ('rolecolors','login','defaults','quotas','autoenroll', - 'autoupdate','directorysrch','contacts', + 'autoupdate','autocreate','directorysrch','contacts', 'usercreation','usermodification','scantron', - 'requestcourses','coursecategories','serverstatuses','helpsettings'); + 'requestcourses','requestauthor','coursecategories', + 'serverstatuses','helpsettings', + 'coursedefaults','usersessions'); + my %existing; + if (ref($domconfig{'loadbalancing'}) eq 'HASH') { + %existing = %{$domconfig{'loadbalancing'}}; + } + if ((keys(%servers) > 1) || (keys(%existing) > 0)) { + push(@prefs_order,'loadbalancing'); + } my %prefs = ( 'rolecolors' => { text => 'Default color schemes', @@ -223,22 +243,23 @@ sub handler { 'login' => { text => 'Log-in page options', help => 'Domain_Configuration_Login_Page', - header => [{col1 => 'Item', - col2 => '',}], + header => [{col1 => 'Log-in Page Items', + col2 => '',}, + {col1 => 'Log-in Help', + col2 => 'Value'}], }, - 'defaults' => - { text => 'Default authentication/language/timezone', + { text => 'Default authentication/language/timezone/portal', help => 'Domain_Configuration_LangTZAuth', header => [{col1 => 'Setting', col2 => 'Value'}], }, 'quotas' => - { text => 'User blogs, personal information pages and portfolios', + { text => 'Blogs, personal web pages, webDAV/quotas, portfolios', help => 'Domain_Configuration_Quotas', header => [{col1 => 'User affiliation', col2 => 'Available tools', - col3 => 'Portfolio quota',}], + col3 => 'Quotas, Mb; (Authoring requires role)',}], }, 'autoenroll' => { text => 'Auto-enrollment settings', @@ -251,8 +272,16 @@ sub handler { help => 'Domain_Configuration_Auto_Updates', header => [{col1 => 'Setting', col2 => 'Value',}, + {col1 => 'Setting', + col2 => 'Affiliation'}, {col1 => 'User population', - col2 => 'Updataeable user data'}], + col2 => 'Updateable user data'}], + }, + 'autocreate' => + { text => 'Auto-course creation settings', + help => 'Domain_Configuration_Auto_Creation', + header => [{col1 => 'Configuration Setting', + col2 => 'Value',}], }, 'directorysrch' => { text => 'Institutional directory searches', @@ -302,6 +331,14 @@ sub handler { {col1 => 'Setting', col2 => 'Value'}], }, + 'requestauthor' => + {text => 'Request authoring space', + help => 'Domain_Configuration_Request_Author', + header => [{col1 => 'User affiliation', + col2 => 'Availability/Processing of requests',}, + {col1 => 'Setting', + col2 => 'Value'}], + }, 'coursecategories' => { text => 'Cataloging of courses/communities', help => 'Domain_Configuration_Cataloging_Courses', @@ -322,8 +359,16 @@ sub handler { 'helpsettings' => {text => 'Help page settings', help => 'Domain_Configuration_Help_Settings', - header => [{col1 => 'Setting', - col2 => 'Value',}], + header => [{col1 => 'Help Settings (logged-in users)', + col2 => 'Value'}], + }, + 'coursedefaults' => + {text => 'Course/Community defaults', + help => 'Domain_Configuration_Course_Defaults', + header => [{col1 => 'Defaults which can be overridden in each course by a CC', + col2 => 'Value',}, + {col1 => 'Defaults which can be overridden for each course by a DC', + col2 => 'Value',},], }, 'privacy' => {text => 'User Privacy', @@ -331,28 +376,93 @@ sub handler { header => [{col1 => 'Setting', col2 => 'Value',}], }, + 'usersessions' => + {text => 'User session hosting/offloading', + help => 'Domain_Configuration_User_Sessions', + header => [{col1 => 'Domain server', + col2 => 'Servers to offload sessions to when busy'}, + {col1 => 'Hosting of users from other domains', + col2 => 'Rules'}, + {col1 => "Hosting domain's own users elsewhere", + col2 => 'Rules'}], + }, + 'loadbalancing' => + {text => 'Dedicated Load Balancer(s)', + help => 'Domain_Configuration_Load_Balancing', + header => [{col1 => 'Balancers', + col2 => 'Default destinations', + col3 => 'User affiliation', + col4 => 'Overrides'}, + ], + }, ); - my %servers = &dom_servers($dom); if (keys(%servers) > 1) { $prefs{'login'} = { text => 'Log-in page options', help => 'Domain_Configuration_Login_Page', header => [{col1 => 'Log-in Service', col2 => 'Server Setting',}, {col1 => 'Log-in Page Items', - col2 => ''}], + col2 => ''}, + {col1 => 'Log-in Help', + col2 => 'Value'}], }; } + my @roles = ('student','coordinator','author','admin'); my @actions = &Apache::loncommon::get_env_multiple('form.actions'); &Apache::lonhtmlcommon::add_breadcrumb ({href=>"javascript:changePage(document.$phase,'pickactions')", - text=>"Pick functionality"}); + text=>"Settings to display/modify"}); my $confname = $dom.'-domainconfig'; + if ($phase eq 'process') { - &Apache::lonconfigsettings::make_changes($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,\@roles); + if (&Apache::lonconfigsettings::make_changes($r,$dom,$phase,$context,\@prefs_order, + \%prefs,\%domconfig,$confname,\@roles) eq 'update') { + $r->rflush(); + &devalidate_remote_domconfs($dom); + } } elsif ($phase eq 'display') { - &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname); - } else { + my $js = &recaptcha_js(). + &credits_js(); + if ((keys(%servers) > 1) || (keys(%existing) > 0)) { + my ($othertitle,$usertypes,$types) = + &Apache::loncommon::sorted_inst_types($dom); + $js .= &lonbalance_targets_js($dom,$types,\%servers, + $domconfig{'loadbalancing'}). + &new_spares_js(). + &common_domprefs_js(). + &Apache::loncommon::javascript_array_indexof(); + } + &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,$js); + } else { +# check if domconfig user exists for the domain. + my $servadm = $r->dir_config('lonAdmEMail'); + my ($configuserok,$author_ok,$switchserver) = + &config_check($dom,$confname,$servadm); + unless ($configuserok eq 'ok') { + &Apache::lonconfigsettings::print_header($r,$phase,$context); + $r->print(&mt('The domain configuration user "[_1]" has yet to be created.', + $confname). + '
' + ); + if ($switchserver) { + $r->print(&mt('Ordinarily, that domain configuration user is created when the ./UPDATE script is run to install LON-CAPA for the first time.'). + '
'. + &mt('However, that does not apply when new domains are added to a multi-domain server, and ./UPDATE has not been run recently.'). + '
'. + &mt('The "[_1]" user can be created automatically when a Domain Coordinator visits the web-based "Set domain configuration" screen, in a session hosted on the primary library server.',$confname). + '
'. + &mt('To do that now, use the following link: [_1]',$switchserver) + ); + } else { + $r->print(&mt('To create that user from the command line run the ./UPDATE script found in the top level directory of the extracted LON-CAPA tarball.'). + '
'. + &mt('Once that is done, you will be able to use the web-based "Set domain configuration" to configure the domain') + ); + } + $r->print(&Apache::loncommon::end_page()); + return OK; + } if (keys(%domconfig) == 0) { my $primarylibserv = &Apache::lonnet::domain($dom,'primary'); my @ids=&Apache::lonnet::current_machine_ids(); @@ -392,23 +502,25 @@ sub handler { } sub process_changes { - my ($r,$dom,$confname,$action,$roles,$values) = @_; + my ($r,$dom,$confname,$action,$roles,$values,$lastactref) = @_; my %domconfig; if (ref($values) eq 'HASH') { %domconfig = %{$values}; } my $output; if ($action eq 'login') { - $output = &modify_login($r,$dom,$confname,%domconfig); + $output = &modify_login($r,$dom,$confname,$lastactref,%domconfig); } elsif ($action eq 'rolecolors') { $output = &modify_rolecolors($r,$dom,$confname,$roles, - %domconfig); + $lastactref,%domconfig); } elsif ($action eq 'quotas') { $output = &modify_quotas($dom,$action,%domconfig); } elsif ($action eq 'autoenroll') { - $output = &modify_autoenroll($dom,%domconfig); + $output = &modify_autoenroll($dom,$lastactref,%domconfig); } elsif ($action eq 'autoupdate') { $output = &modify_autoupdate($dom,%domconfig); + } elsif ($action eq 'autocreate') { + $output = &modify_autocreate($dom,%domconfig); } elsif ($action eq 'directorysrch') { $output = &modify_directorysrch($dom,%domconfig); } elsif ($action eq 'usercreation') { @@ -416,19 +528,27 @@ sub process_changes { } elsif ($action eq 'usermodification') { $output = &modify_usermodification($dom,%domconfig); } elsif ($action eq 'contacts') { - $output = &modify_contacts($dom,%domconfig); + $output = &modify_contacts($dom,$lastactref,%domconfig); } elsif ($action eq 'defaults') { - $output = &modify_defaults($dom,$r); + $output = &modify_defaults($dom,$r,%domconfig); } elsif ($action eq 'scantron') { - $output = &modify_scantron($r,$dom,$confname,%domconfig); + $output = &modify_scantron($r,$dom,$confname,$lastactref,%domconfig); } elsif ($action eq 'coursecategories') { $output = &modify_coursecategories($dom,%domconfig); } elsif ($action eq 'serverstatuses') { $output = &modify_serverstatuses($dom,%domconfig); } elsif ($action eq 'requestcourses') { $output = &modify_quotas($dom,$action,%domconfig); + } elsif ($action eq 'requestauthor') { + $output = &modify_quotas($dom,$action,%domconfig); } elsif ($action eq 'helpsettings') { - $output = &modify_helpsettings($dom,%domconfig); + $output = &modify_helpsettings($r,$dom,$confname,%domconfig); + } elsif ($action eq 'coursedefaults') { + $output = &modify_coursedefaults($dom,%domconfig); + } elsif ($action eq 'usersessions') { + $output = &modify_usersessions($dom,%domconfig); + } elsif ($action eq 'loadbalancing') { + $output = &modify_loadbalancing($dom,%domconfig); } return $output; } @@ -454,16 +574,21 @@ sub print_config_box { } if ($numheaders > 1) { my $colspan = ''; - if (($action eq 'rolecolors') || ($action eq 'coursecategories')) { + my $rightcolspan = ''; + if (($action eq 'rolecolors') || ($action eq 'coursecategories') || + (($action eq 'login') && ($numheaders < 3))) { $colspan = ' colspan="2"'; } + if ($action eq 'usersessions') { + $rightcolspan = ' colspan="3"'; + } $output .= ' - + '; $rowtotal ++; if ($action eq 'autoupdate') { @@ -475,14 +600,22 @@ sub print_config_box { } elsif ($action eq 'coursecategories') { $output .= &print_coursecategories('top',$dom,$item,$settings,\$rowtotal); } elsif ($action eq 'login') { - $output .= &print_login('top',$dom,$confname,$phase,$settings,\$rowtotal); - $colspan = ' colspan="2"'; + if ($numheaders == 3) { + $colspan = ' colspan="2"'; + $output .= &print_login('service',$dom,$confname,$phase,$settings,\$rowtotal); + } else { + $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal); + } } elsif ($action eq 'requestcourses') { $output .= &print_quotas($dom,$settings,\$rowtotal,$action); - } elsif ($action eq 'helpsettings') { - $output .= &print_helpsettings($dom,$settings,\$rowtotal); - } else { + } elsif ($action eq 'requestauthor') { + $output .= &print_quotas($dom,$settings,\$rowtotal,$action); + } elsif ($action eq 'usersessions') { + $output .= &print_usersessions('top',$dom,$settings,\$rowtotal); + } elsif ($action eq 'rolecolors') { $output .= &print_rolecolors($phase,'student',$dom,$confname,$settings,\$rowtotal); + } elsif ($action eq 'coursedefaults') { + $output .= &print_coursedefaults('top',$dom,$settings,\$rowtotal); } $output .= '
'.&mt($item->{'header'}->[0]->{'col1'}).''.&mt($item->{'header'}->[0]->{'col2'}).''.&mt($item->{'header'}->[0]->{'col2'}).'
@@ -498,7 +631,18 @@ sub print_config_box { '; $rowtotal ++; if ($action eq 'autoupdate') { - $output .= &print_autoupdate('bottom',$dom,$settings,\$rowtotal); + $output .= &print_autoupdate('middle',$dom,$settings,\$rowtotal).' + + + + + + + + + '. + &print_autoupdate('bottom',$dom,$settings,\$rowtotal); + $rowtotal ++; } elsif ($action eq 'usercreation') { $output .= &print_usercreation('middle',$dom,$settings,\$rowtotal).'
'.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).'
@@ -523,16 +667,47 @@ sub print_config_box { '.&mt($item->{'header'}->[2]->{'col1'}).' '.&mt($item->{'header'}->[2]->{'col2'}).' '. - &print_usermodification('bottom',$dom,$settings,\$rowtotal); $rowtotal ++; } elsif ($action eq 'coursecategories') { $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal); } elsif ($action eq 'login') { - $output .= &print_login('bottom',$dom,$confname,$phase,$settings,\$rowtotal); + if ($numheaders == 3) { + $output .= &print_login('page',$dom,$confname,$phase,$settings,\$rowtotal).' + + + + + + + + + '. + &print_login('help',$dom,$confname,$phase,$settings,\$rowtotal); + $rowtotal ++; + } else { + $output .= &print_login('help',$dom,$confname,$phase,$settings,\$rowtotal); + } } elsif ($action eq 'requestcourses') { - $output .= &print_courserequestmail($dom,$settings,\$rowtotal); - } else { + $output .= &print_requestmail($dom,$action,$settings,\$rowtotal); + } elsif ($action eq 'requestauthor') { + $output .= &print_requestmail($dom,$action,$settings,\$rowtotal); + } elsif ($action eq 'usersessions') { + $output .= &print_usersessions('middle',$dom,$settings,\$rowtotal).' +
'.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).'
+ + + + + + + + '. + &print_usersessions('bottom',$dom,$settings,\$rowtotal); + $rowtotal ++; + } elsif ($action eq 'coursedefaults') { + $output .= &print_coursedefaults('bottom',$dom,$settings,\$rowtotal); + } elsif ($action eq 'rolecolors') { $output .= &print_rolecolors($phase,'coordinator',$dom,$confname,$settings,\$rowtotal).'
'.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).'
@@ -590,22 +765,30 @@ sub print_config_box { } $output .= ''; if ($item->{'header'}->[0]->{'col3'}) { - $output .= ''. - &mt($item->{'header'}->[0]->{'col3'}); + if (defined($item->{'header'}->[0]->{'col4'})) { + $output .= ''. + &mt($item->{'header'}->[0]->{'col3'}); + } else { + $output .= ''. + &mt($item->{'header'}->[0]->{'col3'}); + } if ($action eq 'serverstatuses') { $output .= '
('.&mt('IP1,IP2 etc.').')'; } $output .= ''; } + if ($item->{'header'}->[0]->{'col4'}) { + $output .= ''. + &mt($item->{'header'}->[0]->{'col4'}); + } $output .= ''; $rowtotal ++; - if ($action eq 'login') { - $output .= &print_login('bottom',$dom,$confname,$phase,$settings, - \$rowtotal); - } elsif ($action eq 'quotas') { + if ($action eq 'quotas') { $output .= &print_quotas($dom,$settings,\$rowtotal,$action); } elsif ($action eq 'autoenroll') { $output .= &print_autoenroll($dom,$settings,\$rowtotal); + } elsif ($action eq 'autocreate') { + $output .= &print_autocreate($dom,$settings,\$rowtotal); } elsif ($action eq 'directorysrch') { $output .= &print_directorysrch($dom,$settings,\$rowtotal); } elsif ($action eq 'contacts') { @@ -617,8 +800,10 @@ sub print_config_box { } elsif ($action eq 'serverstatuses') { $output .= &print_serverstatuses($dom,$settings,\$rowtotal); } elsif ($action eq 'helpsettings') { - $output .= &print_helpsettings($dom,$settings,\$rowtotal); - } + $output .= &print_helpsettings($dom,$confname,$settings,\$rowtotal); + } elsif ($action eq 'loadbalancing') { + $output .= &print_loadbalancing($dom,$settings,\$rowtotal); + } } $output .= ' @@ -629,18 +814,20 @@ sub print_config_box { } sub print_login { - my ($position,$dom,$confname,$phase,$settings,$rowtotal) = @_; + my ($caller,$dom,$confname,$phase,$settings,$rowtotal) = @_; my ($css_class,$datatable); my %choices = &login_choices(); - my $itemcount = 1; - if ($position eq 'top') { - my %servers = &dom_servers($dom); + if ($caller eq 'service') { + my %servers = &Apache::lonnet::internet_dom_servers($dom); my $choice = $choices{'disallowlogin'}; $css_class = ' class="LC_odd_row"'; - $datatable .= ''.$choices{'disallowlogin'}.''. + $datatable .= ''.$choice.''. ''. - ''."\n"; + ''. + ''. + ''. + ''."\n"; my %disallowed; if (ref($settings) eq 'HASH') { if (ref($settings->{'loginvia'}) eq 'HASH') { @@ -649,156 +836,270 @@ sub print_login { } foreach my $lonhost (sort(keys(%servers))) { my $direct = 'selected="selected"'; - if ($disallowed{$lonhost} eq '') { - $direct = ''; + if (ref($disallowed{$lonhost}) eq 'HASH') { + if ($disallowed{$lonhost}{'server'} ne '') { + $direct = ''; + } } $datatable .= ''. - ''; + $datatable .= ''. + ''; + my ($custom,$exempt); + if (ref($disallowed{$lonhost}) eq 'HASH') { + $custom = $disallowed{$lonhost}{'custompath'}; + $exempt = $disallowed{$lonhost}{'exempt'}; + } + $datatable .= ''. + ''. + ''; } $datatable .= '
'.$choices{'hostid'}.''.$choices{'serverurl'}.'
'.$choices{'server'}.''.$choices{'serverpath'}.''.$choices{'custompath'}.''.$choices{'exempt'}.'
'.$servers{$lonhost}.'
'; return $datatable; - } - - my %defaultchecked = ( - 'coursecatalog' => 'on', - 'adminmail' => 'off', - 'newuser' => 'off', - ); - my @toggles = ('coursecatalog','adminmail','newuser'); - my (%checkedon,%checkedoff); - foreach my $item (@toggles) { - if ($defaultchecked{$item} eq 'on') { - $checkedon{$item} = ' checked="checked" '; - $checkedoff{$item} = ' '; - } elsif ($defaultchecked{$item} eq 'off') { - $checkedoff{$item} = ' checked="checked" '; - $checkedon{$item} = ' '; - } - } - my $loginheader = 'image'; - my @images = ('img','logo','domlogo','login'); - my @logintext = ('textcol','bgcol'); - my @bgs = ('pgbg','mainbg','sidebg'); - my @links = ('link','alink','vlink'); - my %designhash = &Apache::loncommon::get_domainconf($dom); - my %defaultdesign = %Apache::loncommon::defaultdesign; - my (%is_custom,%designs); - my %defaults = ( - font => $defaultdesign{'login.font'}, - ); - foreach my $item (@images) { - $defaults{$item} = $defaultdesign{'login.'.$item}; - $defaults{'showlogo'}{$item} = 1; - } - foreach my $item (@bgs) { - $defaults{'bgs'}{$item} = $defaultdesign{'login.'.$item}; - } - foreach my $item (@logintext) { - $defaults{'logintext'}{$item} = $defaultdesign{'login.'.$item}; - } - foreach my $item (@links) { - $defaults{'links'}{$item} = $defaultdesign{'login.'.$item}; - } - if (ref($settings) eq 'HASH') { + } elsif ($caller eq 'page') { + my %defaultchecked = ( + 'coursecatalog' => 'on', + 'helpdesk' => 'on', + 'adminmail' => 'off', + 'newuser' => 'off', + ); + my @toggles = ('coursecatalog','adminmail','helpdesk','newuser'); + my (%checkedon,%checkedoff); foreach my $item (@toggles) { - if ($settings->{$item} eq '1') { - $checkedon{$item} = ' checked="checked" '; + if ($defaultchecked{$item} eq 'on') { + $checkedon{$item} = ' checked="checked" '; $checkedoff{$item} = ' '; - } elsif ($settings->{$item} eq '0') { - $checkedoff{$item} = ' checked="checked" '; + } elsif ($defaultchecked{$item} eq 'off') { + $checkedoff{$item} = ' checked="checked" '; $checkedon{$item} = ' '; } } + my @images = ('img','logo','domlogo','login'); + my @logintext = ('textcol','bgcol'); + my @bgs = ('pgbg','mainbg','sidebg'); + my @links = ('link','alink','vlink'); + my %designhash = &Apache::loncommon::get_domainconf($dom); + my %defaultdesign = %Apache::loncommon::defaultdesign; + my (%is_custom,%designs); + my %defaults = ( + font => $defaultdesign{'login.font'}, + ); foreach my $item (@images) { - if (defined($settings->{$item})) { - $designs{$item} = $settings->{$item}; - $is_custom{$item} = 1; - } - if (defined($settings->{'showlogo'}{$item})) { - $designs{'showlogo'}{$item} = $settings->{'showlogo'}{$item}; - } + $defaults{$item} = $defaultdesign{'login.'.$item}; + $defaults{'showlogo'}{$item} = 1; } - foreach my $item (@logintext) { - if ($settings->{$item} ne '') { - $designs{'logintext'}{$item} = $settings->{$item}; - $is_custom{$item} = 1; - } + foreach my $item (@bgs) { + $defaults{'bgs'}{$item} = $defaultdesign{'login.'.$item}; } - if ($settings->{'loginheader'} ne '') { - $loginheader = $settings->{'loginheader'}; + foreach my $item (@logintext) { + $defaults{'logintext'}{$item} = $defaultdesign{'login.'.$item}; } - if ($settings->{'font'} ne '') { - $designs{'font'} = $settings->{'font'}; - $is_custom{'font'} = 1; + foreach my $item (@links) { + $defaults{'links'}{$item} = $defaultdesign{'login.'.$item}; } - foreach my $item (@bgs) { - if ($settings->{$item} ne '') { - $designs{'bgs'}{$item} = $settings->{$item}; - $is_custom{$item} = 1; + if (ref($settings) eq 'HASH') { + foreach my $item (@toggles) { + if ($settings->{$item} eq '1') { + $checkedon{$item} = ' checked="checked" '; + $checkedoff{$item} = ' '; + } elsif ($settings->{$item} eq '0') { + $checkedoff{$item} = ' checked="checked" '; + $checkedon{$item} = ' '; + } } - } - foreach my $item (@links) { - if ($settings->{$item} ne '') { - $designs{'links'}{$item} = $settings->{$item}; - $is_custom{$item} = 1; + foreach my $item (@images) { + if (defined($settings->{$item})) { + $designs{$item} = $settings->{$item}; + $is_custom{$item} = 1; + } + if (defined($settings->{'showlogo'}{$item})) { + $designs{'showlogo'}{$item} = $settings->{'showlogo'}{$item}; + } } - } - } else { - if ($designhash{$dom.'.login.font'} ne '') { - $designs{'font'} = $designhash{$dom.'.login.font'}; - $is_custom{'font'} = 1; - } - foreach my $item (@images) { - if ($designhash{$dom.'.login.'.$item} ne '') { - $designs{$item} = $designhash{$dom.'.login.'.$item}; - $is_custom{$item} = 1; + foreach my $item (@logintext) { + if ($settings->{$item} ne '') { + $designs{'logintext'}{$item} = $settings->{$item}; + $is_custom{$item} = 1; + } + } + if ($settings->{'font'} ne '') { + $designs{'font'} = $settings->{'font'}; + $is_custom{'font'} = 1; + } + foreach my $item (@bgs) { + if ($settings->{$item} ne '') { + $designs{'bgs'}{$item} = $settings->{$item}; + $is_custom{$item} = 1; + } + } + foreach my $item (@links) { + if ($settings->{$item} ne '') { + $designs{'links'}{$item} = $settings->{$item}; + $is_custom{$item} = 1; + } + } + } else { + if ($designhash{$dom.'.login.font'} ne '') { + $designs{'font'} = $designhash{$dom.'.login.font'}; + $is_custom{'font'} = 1; + } + foreach my $item (@images) { + if ($designhash{$dom.'.login.'.$item} ne '') { + $designs{$item} = $designhash{$dom.'.login.'.$item}; + $is_custom{$item} = 1; + } + } + foreach my $item (@bgs) { + if ($designhash{$dom.'.login.'.$item} ne '') { + $designs{'bgs'}{$item} = $designhash{$dom.'.login.'.$item}; + $is_custom{$item} = 1; + } + } + foreach my $item (@links) { + if ($designhash{$dom.'.login.'.$item} ne '') { + $designs{'links'}{$item} = $designhash{$dom.'.login.'.$item}; + $is_custom{$item} = 1; + } } } - foreach my $item (@bgs) { - if ($designhash{$dom.'.login.'.$item} ne '') { - $designs{'bgs'}{$item} = $designhash{$dom.'.login.'.$item}; - $is_custom{$item} = 1; + my %alt_text = &Apache::lonlocal::texthash ( img => 'Log-in banner', + logo => 'Institution Logo', + domlogo => 'Domain Logo', + login => 'Login box'); + my $itemcount = 1; + foreach my $item (@toggles) { + $css_class = $itemcount%2?' class="LC_odd_row"':''; + $datatable .= + ''.$choices{$item}. + ''. + ' '. + ''; + $itemcount ++; + } + $datatable .= &display_color_options($dom,$confname,$phase,'login',$itemcount,\%choices,\%is_custom,\%defaults,\%designs,\@images,\@bgs,\@links,\%alt_text,$rowtotal,\@logintext); + $datatable .= ''; + } elsif ($caller eq 'help') { + my ($defaulturl,$defaulttype,%url,%type,%lt,%langchoices); + my $switchserver = &check_switchserver($dom,$confname); + my $itemcount = 1; + $defaulturl = '/adm/loginproblems.html'; + $defaulttype = 'default'; + %lt = &Apache::lonlocal::texthash ( + del => 'Delete?', + rep => 'Replace:', + upl => 'Upload:', + default => 'Default', + custom => 'Custom', + ); + %langchoices = &Apache::lonlocal::texthash(&get_languages_hash()); + my @currlangs; + if (ref($settings) eq 'HASH') { + if (ref($settings->{'helpurl'}) eq 'HASH') { + foreach my $key (sort(keys(%{$settings->{'helpurl'}}))) { + next if ($settings->{'helpurl'}{$key} eq ''); + $url{$key} = $settings->{'helpurl'}{$key}.'?inhibitmenu=yes'; + $type{$key} = 'custom'; + unless ($key eq 'nolang') { + push(@currlangs,$key); + } + } + } elsif ($settings->{'helpurl'} ne '') { + $type{'nolang'} = 'custom'; + $url{'nolang'} = $settings->{'helpurl'}.'?inhibitmenu=yes'; + } + } + foreach my $lang ('nolang',sort(@currlangs)) { + $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; + $datatable .= ''; + if ($url{$lang} eq '') { + $url{$lang} = $defaulturl; + } + if ($type{$lang} eq '') { + $type{$lang} = $defaulttype; + } + $datatable .= ''; + if ($lang eq 'nolang') { + $datatable .= &mt('Log-in help page if no specific language file: [_1]', + &Apache::loncommon::modal_link($url{$lang},$lt{$type{$lang}},600,500)); + } else { + $datatable .= &mt('Log-in help page for language: [_1] is [_2]', + $langchoices{$lang}, + &Apache::loncommon::modal_link($url{$lang},$lt{$type{$lang}},600,500)); + } + $datatable .= ''."\n". + ''; + if ($type{$lang} eq 'custom') { + $datatable .= ' '.$lt{'rep'}.''; + } else { + $datatable .= $lt{'upl'}; } + $datatable .='
'; + if ($switchserver) { + $datatable .= &mt('Upload to library server: [_1]',$switchserver); + } else { + $datatable .= ''; + } + $datatable .= ''; + $itemcount ++; } - foreach my $item (@links) { - if ($designhash{$dom.'.login.'.$item} ne '') { - $designs{'links'}{$item} = $designhash{$dom.'.login.'.$item}; - $is_custom{$item} = 1; + my @addlangs; + foreach my $lang (sort(keys(%langchoices))) { + next if ((grep(/^\Q$lang\E$/,@currlangs)) || ($lang eq 'x_chef')); + push(@addlangs,$lang); + } + if (@addlangs > 0) { + my %toadd; + map { $toadd{$_} = $langchoices{$_} ; } @addlangs; + $toadd{''} = &mt('Select'); + $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; + $datatable .= ''. + &mt('Add log-in help page for a specific language:').' '. + &Apache::loncommon::select_form('','loginhelpurl_add_lang',\%toadd). + ''.$lt{'upl'}.'
'; + if ($switchserver) { + $datatable .= &mt('Upload to library server: [_1]',$switchserver); + } else { + $datatable .= ''; } + $datatable .= ''; + $itemcount ++; } + $datatable .= &captcha_choice('login',$settings,$itemcount); } - my %alt_text = &Apache::lonlocal::texthash ( img => 'Log-in banner', - logo => 'Institution Logo', - domlogo => 'Domain Logo', - login => 'Login box'); - my $itemcount = 1; - my ($css_class,$datatable); - foreach my $item (@toggles) { - $css_class = $itemcount%2?' class="LC_odd_row"':''; - $datatable .= - ''.$choices{$item}. - ''. - ' '. - ''; - $itemcount ++; - } - $datatable .= &display_color_options($dom,$confname,$phase,'login',$itemcount,\%choices,\%is_custom,\%defaults,\%designs,\@images,\@bgs,\@links,\%alt_text,$rowtotal,\@logintext,$loginheader); - $datatable .= ''; return $datatable; } @@ -807,9 +1108,13 @@ sub login_choices { &Apache::lonlocal::texthash ( coursecatalog => 'Display Course/Community Catalog link?', adminmail => "Display Administrator's E-mail Address?", + helpdesk => 'Display "Contact Helpdesk" link', disallowlogin => "Login page requests redirected", hostid => "Server", - serverurl => "Redirect to log-in via:", + server => "Redirect to:", + serverpath => "Path", + custompath => "Custom", + exempt => "Exempt IP(s)", directlogin => "No redirect", newuser => "Link to create a user account", img => "Header", @@ -841,17 +1146,7 @@ sub print_rolecolors { my %designhash = &Apache::loncommon::get_domainconf($dom); my %defaultdesign = %Apache::loncommon::defaultdesign; my (%is_custom,%designs); - my %defaults = ( - img => $defaultdesign{$role.'.img'}, - font => $defaultdesign{$role.'.font'}, - fontmenu => $defaultdesign{$role.'.fontmenu'}, - ); - foreach my $item (@bgs) { - $defaults{'bgs'}{$item} = $defaultdesign{$role.'.'.$item}; - } - foreach my $item (@links) { - $defaults{'links'}{$item} = $defaultdesign{$role.'.'.$item}; - } + my %defaults = &role_defaults($role,\@bgs,\@links,\@images); if (ref($settings) eq 'HASH') { if (ref($settings->{$role}) eq 'HASH') { if ($settings->{$role}->{'img'} ne '') { @@ -912,24 +1207,62 @@ sub print_rolecolors { return $datatable; } +sub role_defaults { + my ($role,$bgs,$links,$images,$logintext) = @_; + my %defaults; + unless ((ref($bgs) eq 'ARRAY') && (ref($links) eq 'ARRAY') && (ref($images) eq 'ARRAY')) { + return %defaults; + } + my %defaultdesign = %Apache::loncommon::defaultdesign; + if ($role eq 'login') { + %defaults = ( + font => $defaultdesign{$role.'.font'}, + ); + if (ref($logintext) eq 'ARRAY') { + foreach my $item (@{$logintext}) { + $defaults{'logintext'}{$item} = $defaultdesign{$role.'.'.$item}; + } + } + foreach my $item (@{$images}) { + $defaults{'showlogo'}{$item} = 1; + } + } else { + %defaults = ( + img => $defaultdesign{$role.'.img'}, + font => $defaultdesign{$role.'.font'}, + fontmenu => $defaultdesign{$role.'.fontmenu'}, + ); + } + foreach my $item (@{$bgs}) { + $defaults{'bgs'}{$item} = $defaultdesign{$role.'.'.$item}; + } + foreach my $item (@{$links}) { + $defaults{'links'}{$item} = $defaultdesign{$role.'.'.$item}; + } + foreach my $item (@{$images}) { + $defaults{$item} = $defaultdesign{$role.'.'.$item}; + } + return %defaults; +} + sub display_color_options { my ($dom,$confname,$phase,$role,$itemcount,$choices,$is_custom,$defaults,$designs, - $images,$bgs,$links,$alt_text,$rowtotal,$logintext,$loginheader) = @_; + $images,$bgs,$links,$alt_text,$rowtotal,$logintext) = @_; + my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'}; my $css_class = $itemcount%2?' class="LC_odd_row"':''; - my $datatable = ''. + my $datatable = ''. ''.$choices->{'font'}.''; if (!$is_custom->{'font'}) { $datatable .= ''.&mt('Default in use:').' '.$defaults->{'font'}.''; } else { $datatable .= ' '; } - my $fontlink = &color_pick($phase,$role,'font',$choices->{'font'},$designs->{'font'}); + my $current_color = $designs->{'font'} ? $designs->{'font'} : $defaults->{'font'}; + $datatable .= ''. - ' '.$fontlink. - '    '. - ''; + ' '. + ' '; unless ($role eq 'login') { $datatable .= ''. ''.$choices->{'fontmenu'}.''; @@ -938,13 +1271,13 @@ sub display_color_options { } else { $datatable .= ' '; } - $fontlink = &color_pick($phase,$role,'fontmenu',$choices->{'fontmenu'},$designs->{'fontmenu'}); + $current_color = $designs->{'fontmenu'} ? + $designs->{'fontmenu'} : $defaults->{'fontmenu'}; $datatable .= ''. - ' '.$fontlink. - '    '. - ''; + ' '. + ' '; } my $switchserver = &check_switchserver($dom,$confname); foreach my $img (@{$images}) { @@ -956,11 +1289,10 @@ sub display_color_options { if ($role eq 'login') { if ($img eq 'login') { $login_hdr_pick = - &login_header_options($img,$role,$defaults,$is_custom,$choices, - $loginheader); + &login_header_options($img,$role,$defaults,$is_custom,$choices); $logincolors = &login_text_colors($img,$role,$logintext,$phase,$choices, - $designs); + $designs,$defaults); } elsif ($img ne 'domlogo') { $datatable.= &logo_display_options($img,$defaults,$designs); } @@ -993,11 +1325,11 @@ sub display_color_options { $showfile = $imgfile; my $imgdir = $1; my $filename = $2; - if (-e "/home/httpd/html/$imgdir/tn-".$filename) { + if (-e "$londocroot/$imgdir/tn-".$filename) { $showfile = "/$imgdir/tn-".$filename; } else { - my $input = "/home/httpd/html".$imgfile; - my $output = '/home/httpd/html/'.$imgdir.'/tn-'.$filename; + my $input = $londocroot.$imgfile; + my $output = "$londocroot/$imgdir/tn-".$filename; if (!-e $output) { my ($width,$height) = &thumb_dimensions(); my ($fullwidth,$fullheight) = &check_dimensions($input); @@ -1005,7 +1337,7 @@ sub display_color_options { if ($fullwidth > $width && $fullheight > $height) { my $size = $width.'x'.$height; system("convert -sample $size $input $output"); - $showfile = '/'.$imgdir.'/tn-'.$filename; + $showfile = "/$imgdir/tn-".$filename; } } } @@ -1034,22 +1366,24 @@ sub display_color_options { } $datatable .= ''; if ($img eq 'login') { - $datatable .= $login_hdr_pick; - } + $datatable .= $login_hdr_pick; + } $datatable .= &image_changes($is_custom->{$img},$alt_text->{$img},$img_import, $showfile,$fullsize,$role,$img,$imgfile,$logincolors); } else { - $datatable .= '
'. - &mt('Upload:'); + $datatable .= ' '. + &mt('Upload:').'
'; } } else { - $datatable .= '
'. - &mt('Upload:'); + $datatable .= ' '. + &mt('Upload:').'
'; } if ($switchserver) { $datatable .= &mt('Upload to library server: [_1]',$switchserver); } else { - $datatable .=' '; + if ($img ne 'login') { # suppress file selection for Log-in header + $datatable .=' '; + } } $datatable .= ''; } @@ -1070,13 +1404,14 @@ sub display_color_options { } $datatable .= ''. ''; + foreach my $item (@{$bgs}) { - my $link = &color_pick($phase,$role,$item,$choices->{$item},$designs->{'bgs'}{$item}); - $datatable .= ''; } $datatable .= '
'.$link; + $datatable .= ''.$choices->{$item}; + my $color = $designs->{'bgs'}{$item} ? $designs->{'bgs'}{$item} : $defaults->{'bgs'}{$item}; if ($designs->{'bgs'}{$item}) { - $datatable .= '    '; + $datatable .= ' '; } - $datatable .= '
'; @@ -1098,13 +1433,12 @@ sub display_color_options { $datatable .= ''. ''; foreach my $item (@{$links}) { - $datatable .= ''; } $$rowtotal += $itemcount; @@ -1138,20 +1472,10 @@ sub logo_display_options { } sub login_header_options { - my ($img,$role,$defaults,$is_custom,$choices,$loginheader) = @_; - my $image_checked = ' checked="checked" '; - my $text_checked = ' '; - if ($loginheader eq 'text') { - $image_checked = ' '; - $text_checked = ' checked="checked" '; - } - my $output = '   '. - '
'."\n"; + my ($img,$role,$defaults,$is_custom,$choices) = @_; + my $output = ''; if ((!$is_custom->{'textcol'}) || (!$is_custom->{'bgcol'})) { - $output .= &mt('Text default(s)').':
'; + $output .= &mt('Text default(s):').'
'; if (!$is_custom->{'textcol'}) { $output .= $choices->{'textcol'}.': '.$defaults->{'logintext'}{'textcol'}. '   '; @@ -1168,17 +1492,13 @@ sub login_header_options { } sub login_text_colors { - my ($img,$role,$logintext,$phase,$choices,$designs) = @_; + my ($img,$role,$logintext,$phase,$choices,$designs,$defaults) = @_; my $color_menu = '
'."\n". - &color_pick($phase,$role,$item,$choices->{$item}, - $designs->{'links'}{$item}); + my $color = $designs->{'link'}{$item} ? $designs->{'link'}{$item} : $defaults->{'links'}{$item}; + $datatable .= ''.$choices->{$item}."\n"; if ($designs->{'links'}{$item}) { - $datatable.='    '; + $datatable.=' '; } - $datatable .= '
'; foreach my $item (@{$logintext}) { - my $link = &color_pick($phase,$role,$item,$choices->{$item},$designs->{'logintext'}{$item}); - $color_menu .= ''. - ''; + $color_menu .= ''; } $color_menu .= '
'.$link; - if ($designs->{'logintext'}{$item}) { - $color_menu .= '    '; - } - $color_menu .= '
 '.$choices->{$item}; + my $color = $designs->{'logintext'}{$item} ? $designs->{'logintext'}{$item} : $defaults->{'logintext'}{$item}; + $color_menu .= '

'; return $color_menu; @@ -1187,37 +1507,35 @@ sub login_text_colors { sub image_changes { my ($is_custom,$alt_text,$img_import,$showfile,$fullsize,$role,$img,$imgfile,$logincolors) = @_; my $output; - if (!$is_custom) { + if ($img eq 'login') { + # suppress image for Log-in header + } elsif (!$is_custom) { if ($img ne 'domlogo') { $output .= &mt('Default image:').'
'; } else { $output .= &mt('Default in use:').'
'; } } - if ($img_import) { - $output .= ''; - } - $output .= ''.$alt_text.''; - if ($is_custom) { - $output .= ''.$logincolors.' '.&mt('Replace:').'
'; + if ($img eq 'login') { # suppress image for Log-in header + $output .= ''.$logincolors; } else { - $output .= ''.$logincolors.&mt('Upload:').'
'; + if ($img_import) { + $output .= ''; + } + $output .= ''.$alt_text.''; + if ($is_custom) { + $output .= ''.$logincolors.' '.&mt('Replace:').'
'; + } else { + $output .= ''.$logincolors.&mt('Upload:').'
'; + } } return $output; } -sub color_pick { - my ($phase,$role,$item,$desc,$curcol) = @_; - my $link = ''.$desc.''; - return $link; -} - sub print_quotas { my ($dom,$settings,$rowtotal,$action) = @_; my $context; @@ -1226,7 +1544,7 @@ sub print_quotas { } else { $context = $action; } - my ($datatable,$defaultquota,@usertools,@options,%validations); + my ($datatable,$defaultquota,$authorquota,@usertools,@options,%validations); my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); my $typecount = 0; my ($css_class,%titles); @@ -1235,20 +1553,28 @@ sub print_quotas { @options =('norequest','approval','validate','autolimit'); %validations = &Apache::lonnet::auto_courserequest_checks($dom); %titles = &courserequest_titles(); + } elsif ($context eq 'requestauthor') { + @usertools = ('author'); + @options = ('norequest','approval','automatic'); + %titles = &authorrequest_titles(); } else { - @usertools = ('aboutme','blog','portfolio'); + @usertools = ('aboutme','blog','webdav','portfolio'); %titles = &tool_titles(); } if (ref($types) eq 'ARRAY') { foreach my $type (@{$types}) { - my $currdefquota; - unless ($context eq 'requestcourses') { + my ($currdefquota,$currauthorquota); + unless (($context eq 'requestcourses') || + ($context eq 'requestauthor')) { if (ref($settings) eq 'HASH') { if (ref($settings->{defaultquota}) eq 'HASH') { - $currdefquota = $settings->{defaultquota}->{$type}; + $currdefquota = $settings->{defaultquota}->{$type}; } else { $currdefquota = $settings->{$type}; } + if (ref($settings->{authorquota}) eq 'HASH') { + $currauthorquota = $settings->{authorquota}->{$type}; + } } } if (defined($usertypes->{$type})) { @@ -1301,17 +1627,39 @@ sub print_quotas { $cell{$item} .= ' '; + $titles{$option}.''; if ($option eq 'autolimit') { - $cell{$item} .= ''; } - $cell{$item} .= '  '; + $cell{$item} .= ' '; if ($option eq 'autolimit') { - $cell{$item} .= $titles{'unlimited'} + $cell{$item} .= $titles{'unlimited'}; } } + } elsif ($context eq 'requestauthor') { + my $curroption; + if (ref($settings) eq 'HASH') { + $curroption = $settings->{$type}; + } + if (!$curroption) { + $curroption = 'norequest'; + } + foreach my $option (@options) { + my $val = $option; + if ($option eq 'norequest') { + $val = 0; + } + my $checked = ''; + if ($option eq $curroption) { + $checked = ' checked="checked"'; + } + $datatable .= '  '; + } } else { my $checked = 'checked="checked" '; if (ref($settings) eq 'HASH') { @@ -1337,25 +1685,35 @@ sub print_quotas { $datatable .= ''; } $datatable .= ''; - unless ($context eq 'requestcourses') { + unless (($context eq 'requestcourses') || + ($context eq 'requestauthor')) { $datatable .= - ''. + ''. + ''.&mt('Portfolio').': '. ' Mb'; + '" size="5" />'.(' ' x 2). + ''.&mt('Authoring').': '. + ''; } $datatable .= ''; } } } - unless ($context eq 'requestcourses') { + 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 ++; @@ -1409,14 +1767,36 @@ sub print_quotas { '_default" value="'.$val.'"'.$checked.' />'. $titles{$option}.''; if ($option eq 'autolimit') { - $defcell{$item} .= ''; } - $defcell{$item} .= '  '; + $defcell{$item} .= ' '; if ($option eq 'autolimit') { - $defcell{$item} .= $titles{'unlimited'} + $defcell{$item} .= $titles{'unlimited'}; + } + } + } elsif ($context eq 'requestauthor') { + my $curroption; + if (ref($settings) eq 'HASH') { + $curroption = $settings->{'default'}; + } + if (!$curroption) { + $curroption = 'norequest'; + } + foreach my $option (@options) { + my $val = $option; + if ($option eq 'norequest') { + $val = 0; } + my $checked = ''; + if ($option eq $curroption) { + $checked = ' checked="checked"'; + } + $datatable .= '  '; } } else { my $checked = 'checked="checked" '; @@ -1443,16 +1823,20 @@ sub print_quotas { $datatable .= ''; } $datatable .= ''; - unless ($context eq 'requestcourses') { - $datatable .= ''. + unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) { + $datatable .= ''. + ''.&mt('Portfolio').': '. ' Mb'; + $defaultquota.'" size="5" />'.(' ' x2). + ''.&mt('Authoring').': '. + ''; } $datatable .= ''; $typecount ++; $css_class = $typecount%2?' class="LC_odd_row"':''; $datatable .= ''. - ''.&mt('LON-CAPA Advanced Users').' '; + ''.&mt('LON-CAPA Advanced Users').'
'; if ($context eq 'requestcourses') { $datatable .= &mt('(overrides affiliation, if set)'). ''. @@ -1512,14 +1896,41 @@ sub print_quotas { '__LC_adv" value="'.$val.'"'.$checked.' />'. $titles{$option}.''; if ($option eq 'autolimit') { - $advcell{$item} .= ''; } - $advcell{$item} .= '  '; + $advcell{$item} .= ' '; if ($option eq 'autolimit') { - $advcell{$item} .= $titles{'unlimited'} + $advcell{$item} .= $titles{'unlimited'}; + } + } + } elsif ($context eq 'requestauthor') { + my $curroption; + if (ref($settings) eq 'HASH') { + $curroption = $settings->{'_LC_adv'}; + } + my $checked = ''; + if ($curroption eq '') { + $checked = ' checked="checked"'; + } + $datatable .= '  '; + foreach my $option (@options) { + my $val = $option; + if ($option eq 'norequest') { + $val = 0; + } + my $checked = ''; + if ($val eq $curroption) { + $checked = ' checked="checked"'; } + $datatable .= '  '; } } else { my $checked = 'checked="checked" '; @@ -1550,78 +1961,34 @@ sub print_quotas { return $datatable; } -sub print_courserequestmail { - my ($dom,$settings,$rowtotal) = @_; - my ($now,$datatable,%dompersonnel,@domcoord,@currapproval,$rows); +sub print_requestmail { + my ($dom,$action,$settings,$rowtotal) = @_; + my ($now,$datatable,%currapp); $now = time; - $rows = 0; - %dompersonnel = &Apache::lonnet::get_domain_roles($dom,['dc'],$now,$now); - foreach my $server (keys(%dompersonnel)) { - foreach my $user (sort(keys(%{$dompersonnel{$server}}))) { - my ($trole,$uname,$udom,$runame,$rudom,$rsec) = split(/:/,$user); - if (!grep(/^$uname:$udom$/,@domcoord)) { - push(@domcoord,$uname.':'.$udom); - } - } - } if (ref($settings) eq 'HASH') { if (ref($settings->{'notify'}) eq 'HASH') { if ($settings->{'notify'}{'approval'} ne '') { - @currapproval = split(',',$settings->{'notify'}{'approval'}); - } - } - } - if (@currapproval) { - foreach my $dc (@currapproval) { - unless (grep(/^\Q$dc\E$/,@domcoord)) { - push(@domcoord,$dc); + map {$currapp{$_}=1;} split(/,/,$settings->{'notify'}{'approval'}); } } } - @domcoord = sort(@domcoord); - my $numinrow = 4; - my $numdc = @domcoord; + my $numinrow = 2; my $css_class = 'class="LC_odd_row"'; - $datatable = ''. - ' '.&mt('Receive notification of course requests requiring approval.'). - ' '. + my $text; + if ($action eq 'requestcourses') { + $text = &mt('Receive notification of course requests requiring approval'); + } else { + $text = &mt('Receive notification of authoring space requests requiring approval') + } + $datatable = ''. + ' '.$text.''. ' '; - if (@domcoord > 0) { - $datatable .= ''; - for (my $i=0; $i<$numdc; $i++) { - my $rem = $i%($numinrow); - if ($rem == 0) { - if ($i > 0) { - $datatable .= ''; - } - $datatable .= ''; - $rows ++; - } - my $check = ' '; - if (grep(/^\Q$domcoord[$i]\E$/,@currapproval)) { - $check = ' checked="checked" '; - } - my ($uname,$udom) = split(':',$domcoord[$i]); - my $fullname = &Apache::loncommon::plainname($uname,$udom); - if ($i == $numdc-1) { - my $colsleft = $numinrow-$rem; - if ($colsleft > 1) { - $datatable .= ''; - } - $datatable .= '
'; - } else { - $datatable .= ''; - } - } else { - $datatable .= ''; - } - $datatable .= '
'; + my ($numdc,$table,$rows) = &active_dc_picker($dom,$numinrow,'checkbox', + 'reqapprovalnotify',%currapp); + if ($numdc > 0) { + $datatable .= $table; } else { $datatable .= &mt('There are no active Domain Coordinators'); - $rows ++; } $datatable .=''; $$rowtotal += $rows; @@ -1631,7 +1998,7 @@ sub print_courserequestmail { sub print_autoenroll { my ($dom,$settings,$rowtotal) = @_; my $autorun = &Apache::lonnet::auto_run(undef,$dom), - my ($defdom,$runon,$runoff); + my ($defdom,$runon,$runoff,$coownerson,$coownersoff); if (ref($settings) eq 'HASH') { if (exists($settings->{'run'})) { if ($settings->{'run'} eq '0') { @@ -1650,6 +2017,18 @@ sub print_autoenroll { $runon = ' '; } } + if (exists($settings->{'co-owners'})) { + if ($settings->{'co-owners'} eq '0') { + $coownersoff = ' checked="checked" '; + $coownerson = ' '; + } else { + $coownerson = ' checked="checked" '; + $coownersoff = ' '; + } + } else { + $coownersoff = ' checked="checked" '; + $coownerson = ' '; + } if (exists($settings->{'sender_domain'})) { $defdom = $settings->{'sender_domain'}; } @@ -1680,8 +2059,16 @@ sub print_autoenroll { &mt('username').': '. '  '.&mt('domain'). - ': '.$domform.''; - $$rowtotal += 2; + ': '.$domform.''. + ''. + ''.&mt('Automatically assign co-ownership').''. + ' '. + ''. + ''; + $$rowtotal += 3; return $datatable; } @@ -1723,9 +2110,17 @@ sub print_autoupdate { $classlistsoff.'value="0" />'.&mt('No').''. ''; $$rowtotal += 2; + } elsif ($position eq 'middle') { + my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); + my $numinrow = 3; + my $locknamesettings; + $datatable .= &insttypes_row($settings,$types,$usertypes, + $dom,$numinrow,$othertitle, + 'lockablenames'); + $$rowtotal ++; } else { my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); - my @fields = ('lastname','firstname','middlename','gen', + my @fields = ('lastname','firstname','middlename','generation', 'permanentemail','id'); my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); my $numrows = 0; @@ -1746,6 +2141,59 @@ sub print_autoupdate { return $datatable; } +sub print_autocreate { + my ($dom,$settings,$rowtotal) = @_; + my (%createon,%createoff,%currhash); + my @types = ('xml','req'); + if (ref($settings) eq 'HASH') { + foreach my $item (@types) { + $createoff{$item} = ' checked="checked" '; + $createon{$item} = ' '; + if (exists($settings->{$item})) { + if ($settings->{$item}) { + $createon{$item} = ' checked="checked" '; + $createoff{$item} = ' '; + } + } + } + if ($settings->{'xmldc'} ne '') { + $currhash{$settings->{'xmldc'}} = 1; + } + } else { + foreach my $item (@types) { + $createoff{$item} = ' checked="checked" '; + $createon{$item} = ' '; + } + } + $$rowtotal += 2; + my $numinrow = 2; + my $datatable=''. + ''.&mt('Create pending official courses from XML files').''. + ' '. + ''. + ''. + ''.&mt('Create pending requests for official courses (if validated)').''. + ' '. + ''; + my ($numdc,$dctable,$rows) = &active_dc_picker($dom,$numinrow,'radio', + 'autocreate_xmldc',%currhash); + if ($numdc > 1) { + $datatable .= ''. + &mt('Course creation processed as: (choose Dom. Coord.)'). + ''.$dctable.''; + } else { + $datatable .= $dctable.''; + } + $$rowtotal += $rows; + return $datatable; +} + sub print_directorysrch { my ($dom,$settings,$rowtotal) = @_; my $srchon = ' '; @@ -1863,12 +2311,13 @@ sub print_contacts { my ($dom,$settings,$rowtotal) = @_; my $datatable; my @contacts = ('adminemail','supportemail'); - my (%checked,%to,%otheremails); + my (%checked,%to,%otheremails,%bccemails); my @mailings = ('errormail','packagesmail','lonstatusmail','helpdeskmail', - 'requestsmail'); + 'requestsmail','updatesmail','idconflictsmail'); foreach my $type (@mailings) { $otheremails{$type} = ''; } + $bccemails{'helpdeskmail'} = ''; if (ref($settings) eq 'HASH') { foreach my $item (@contacts) { if (exists($settings->{$item})) { @@ -1884,6 +2333,9 @@ sub print_contacts { } } $otheremails{$type} = $settings->{$type}{'others'}; + if ($type eq 'helpdeskmail') { + $bccemails{$type} = $settings->{$type}{'bcc'}; + } } } elsif ($type eq 'lonstatusmail') { $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" '; @@ -1897,21 +2349,22 @@ sub print_contacts { $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" '; $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" '; $checked{'requestsmail'}{'adminemail'} = ' checked="checked" '; + $checked{'updatesmail'}{'adminemail'} = ' checked="checked" '; + $checked{'idconflictsmail'}{'adminemail'} = ' checked="checked" '; } my ($titles,$short_titles) = &contact_titles(); my $rownum = 0; my $css_class; foreach my $item (@contacts) { - $rownum ++; $css_class = $rownum%2?' class="LC_odd_row"':''; $datatable .= ''. ''.$titles->{$item}. ''. ''; + $rownum ++; } foreach my $type (@mailings) { - $rownum ++; $css_class = $rownum%2?' class="LC_odd_row"':''; $datatable .= ''. ''. @@ -1927,41 +2380,67 @@ sub print_contacts { } $datatable .= '
'.&mt('Others').':  '. ''. - ''."\n"; + 'value="'.$otheremails{$type}.'" />'; + if ($type eq 'helpdeskmail') { + $datatable .= '
'.&mt('Bcc:').(' 'x6). + ''; + } + $datatable .= ''."\n"; + $rownum ++; } + my %choices; + $choices{'reporterrors'} = &mt('E-mail error reports to [_1]', + &Apache::loncommon::modal_link('http://loncapa.org/core.html', + &mt('LON-CAPA core group - MSU'),600,500)); + $choices{'reportupdates'} = &mt('E-mail record of completed LON-CAPA updates to [_1]', + &Apache::loncommon::modal_link('http://loncapa.org/core.html', + &mt('LON-CAPA core group - MSU'),600,500)); + my @toggles = ('reporterrors','reportupdates'); + my %defaultchecked = ('reporterrors' => 'on', + 'reportupdates' => 'on'); + (my $reports,$rownum) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked, + \%choices,$rownum); + $datatable .= $reports; $$rowtotal += $rownum; return $datatable; } sub print_helpsettings { + my ($dom,$confname,$settings,$rowtotal) = @_; + my ($datatable,$itemcount); + $itemcount = 1; + my (%choices,%defaultchecked,@toggles); + $choices{'submitbugs'} = &mt('Display link to: [_1]?', + &Apache::loncommon::modal_link('http://bugs.loncapa.org', + &mt('LON-CAPA bug tracker'),600,500)); + %defaultchecked = ('submitbugs' => 'on'); + @toggles = ('submitbugs',); - my ($dom,$settings,$rowtotal) = @_; - my ($css_class,$datatable); - my $itemcount = 1; - my (%checkedon,%checkedoff,%choices,%defaultchecked,@toggles); - - %choices = - &Apache::lonlocal::texthash ( - submitbugs => 'Display "Submit a bug" link?', - ); - - %defaultchecked = ('submitbugs' => 'on'); - - @toggles = ('submitbugs',); - - foreach my $item (@toggles) { - if ($defaultchecked{$item} eq 'on') { + ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked, + \%choices,$itemcount); + return $datatable; +} + +sub radiobutton_prefs { + my ($settings,$toggles,$defaultchecked,$choices,$itemcount,$onclick, + $additional) = @_; + return unless ((ref($toggles) eq 'ARRAY') && (ref($defaultchecked) eq 'HASH') && + (ref($choices) eq 'HASH')); + + my (%checkedon,%checkedoff,$datatable,$css_class); + + foreach my $item (@{$toggles}) { + if ($defaultchecked->{$item} eq 'on') { $checkedon{$item} = ' checked="checked" '; $checkedoff{$item} = ' '; - } elsif ($defaultchecked{$item} eq 'off') { + } elsif ($defaultchecked->{$item} eq 'off') { $checkedoff{$item} = ' checked="checked" '; $checkedon{$item} = ' '; } } - if (ref($settings) eq 'HASH') { - foreach my $item (@toggles) { + foreach my $item (@{$toggles}) { if ($settings->{$item} eq '1') { $checkedon{$item} = ' checked="checked" '; $checkedoff{$item} = ' '; @@ -1970,24 +2449,873 @@ sub print_helpsettings { $checkedon{$item} = ' '; } } - } - - foreach my $item (@toggles) { + } + if ($onclick) { + $onclick = ' onclick="'.$onclick.'"'; + } + foreach my $item (@{$toggles}) { $css_class = $itemcount%2?' class="LC_odd_row"':''; - $datatable .= - ''.$choices{$item}. + $datatable .= + ''. + ''.$choices->{$item}. ''. ''. ' '. - ''. + $checkedoff{$item}.' value="0"'.$onclick.' />'.&mt('No').''. + ''.$additional. + ''. ''; $itemcount ++; - } - return $datatable; - + } + return ($datatable,$itemcount); +} + +sub print_coursedefaults { + my ($position,$dom,$settings,$rowtotal) = @_; + my ($css_class,$datatable,%checkedon,%checkedoff,%defaultchecked,@toggles); + my $itemcount = 1; + 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)', + anonsurvey_threshold => 'Responder count needed before showing submissions for anonymous surveys', + coursecredits => 'Credits can be specified for courses', + ); + my %staticdefaults = ( + anonsurvey_threshold => 10, + uploadquota => 500, + ); + if ($position eq 'top') { + %defaultchecked = ('canuse_pdfforms' => 'off'); + @toggles = ('canuse_pdfforms'); + ($datatable,$itemcount) = &radiobutton_prefs($settings,\@toggles,\%defaultchecked, + \%choices,$itemcount); + } else { + $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; + my ($currdefresponder,$def_official_credits,$def_unofficial_credits,%curruploadquota); + my $currusecredits = 0; + my @types = ('official','unofficial','community'); + if (ref($settings) eq 'HASH') { + $currdefresponder = $settings->{'anonsurvey_threshold'}; + if (ref($settings->{'uploadquota'}) eq 'HASH') { + foreach my $type (keys(%{$settings->{'uploadquota'}})) { + $curruploadquota{$type} = $settings->{'uploadquota'}{$type}; + } + } + if (ref($settings->{'coursecredits'}) eq 'HASH') { + $def_official_credits = $settings->{'coursecredits'}->{'official'}; + $def_unofficial_credits = $settings->{'coursecredits'}->{'unofficial'}; + if (($def_official_credits ne '') || ($def_unofficial_credits ne '')) { + $currusecredits = 1; + } + } + } + if (!$currdefresponder) { + $currdefresponder = $staticdefaults{'anonsurvey_threshold'}; + } elsif ($currdefresponder < 1) { + $currdefresponder = 1; + } + foreach my $type (@types) { + if ($curruploadquota{$type} eq '') { + $curruploadquota{$type} = $staticdefaults{'uploadquota'}; + } + } + $datatable .= + ''. + $choices{'anonsurvey_threshold'}. + ''. + ''. + ''. + ''."\n". + ''. + $choices{'uploadquota'}. + ''. + ''. + ''; + foreach my $type (@types) { + $datatable .= ''; + } + $datatable .= '
'.&mt($type).'
'. + '
'."\n"; + $itemcount += 2; + my $onclick = 'toggleCredits(this.form);'; + my $display = 'none'; + if ($currusecredits) { + $display = 'block'; + } + my $additional = '
'. + ''. + &mt('Default credits for official courses [_1]', + ''). + '
'. + ''. + &mt('Default credits for unofficial courses [_1]', + ''). + '
'."\n"; + %defaultchecked = ('coursecredits' => 'off'); + @toggles = ('coursecredits'); + my $current = { + 'coursecredits' => $currusecredits, + }; + (my $table,$itemcount) = + &radiobutton_prefs($current,\@toggles,\%defaultchecked, + \%choices,$itemcount,$onclick,$additional); + $datatable .= $table; + } + $$rowtotal += $itemcount; + return $datatable; +} + +sub print_usersessions { + my ($position,$dom,$settings,$rowtotal) = @_; + my ($css_class,$datatable,%checked,%choices); + my (%by_ip,%by_location,@intdoms); + &build_location_hashes(\@intdoms,\%by_ip,\%by_location); + + my @alldoms = &Apache::lonnet::all_domains(); + my %serverhomes = %Apache::lonnet::serverhomeIDs; + my %servers = &Apache::lonnet::internet_dom_servers($dom); + my %altids = &id_for_thisdom(%servers); + my $itemcount = 1; + if ($position eq 'top') { + if (keys(%serverhomes) > 1) { + my %spareid = ¤t_offloads_to($dom,$settings,\%servers); + $datatable .= &spares_row($dom,\%servers,\%spareid,\%serverhomes,\%altids,$rowtotal); + } else { + $datatable .= ''. + &mt('Nothing to set here, as the cluster to which this domain belongs only contains one server.'); + } + } else { + if (keys(%by_location) == 0) { + $datatable .= ''. + &mt('Nothing to set here, as the cluster to which this domain belongs only contains one institution.'); + } else { + my %lt = &usersession_titles(); + my $numinrow = 5; + my $prefix; + my @types; + if ($position eq 'bottom') { + $prefix = 'remote'; + @types = ('version','excludedomain','includedomain'); + } else { + $prefix = 'hosted'; + @types = ('excludedomain','includedomain'); + } + my (%current,%checkedon,%checkedoff); + my @lcversions = &Apache::lonnet::all_loncaparevs(); + my @locations = sort(keys(%by_location)); + foreach my $type (@types) { + $checkedon{$type} = ''; + $checkedoff{$type} = ' checked="checked"'; + } + if (ref($settings) eq 'HASH') { + if (ref($settings->{$prefix}) eq 'HASH') { + foreach my $key (keys(%{$settings->{$prefix}})) { + $current{$key} = $settings->{$prefix}{$key}; + if ($key eq 'version') { + if ($current{$key} ne '') { + $checkedon{$key} = ' checked="checked"'; + $checkedoff{$key} = ''; + } + } elsif (ref($current{$key}) eq 'ARRAY') { + $checkedon{$key} = ' checked="checked"'; + $checkedoff{$key} = ''; + } + } + } + } + foreach my $type (@types) { + next if ($type ne 'version' && !@locations); + $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; + $datatable .= ' + '.$lt{$type}.'
+   +   + '; + if ($type eq 'version') { + my $selector = ' '; + $datatable .= &mt('remote server must be version: [_1] or later',$selector); + } else { + $datatable.= '
'.(' 'x2). + ''. + "\n". + '
'; + my $rem; + for (my $i=0; $i<@locations; $i++) { + my ($showloc,$value,$checkedtype); + if (ref($by_location{$locations[$i]}) eq 'ARRAY') { + my $ip = $by_location{$locations[$i]}->[0]; + if (ref($by_ip{$ip}) eq 'ARRAY') { + $value = join(':',@{$by_ip{$ip}}); + $showloc = join(', ',@{$by_ip{$ip}}); + if (ref($current{$type}) eq 'ARRAY') { + foreach my $loc (@{$by_ip{$ip}}) { + if (grep(/^\Q$loc\E$/,@{$current{$type}})) { + $checkedtype = ' checked="checked"'; + last; + } + } + } + } + } + $rem = $i%($numinrow); + if ($rem == 0) { + if ($i > 0) { + $datatable .= ''; + } + $datatable .= ''; + } + $datatable .= ''; + } + $rem = @locations%($numinrow); + my $colsleft = $numinrow - $rem; + if ($colsleft > 1 ) { + $datatable .= ''; + } elsif ($colsleft == 1) { + $datatable .= ''; + } + $datatable .= '
'. + ''. + '  
'; + } + $datatable .= ''; + $itemcount ++; + } + } + } + $$rowtotal += $itemcount; + return $datatable; +} + +sub build_location_hashes { + my ($intdoms,$by_ip,$by_location) = @_; + return unless((ref($intdoms) eq 'ARRAY') && (ref($by_ip) eq 'HASH') && + (ref($by_location) eq 'HASH')); + my %iphost = &Apache::lonnet::get_iphost(); + my $primary_id = &Apache::lonnet::domain($env{'request.role.domain'},'primary'); + my $primary_ip = &Apache::lonnet::get_host_ip($primary_id); + if (ref($iphost{$primary_ip}) eq 'ARRAY') { + foreach my $id (@{$iphost{$primary_ip}}) { + my $intdom = &Apache::lonnet::internet_dom($id); + unless(grep(/^\Q$intdom\E$/,@{$intdoms})) { + push(@{$intdoms},$intdom); + } + } + } + foreach my $ip (keys(%iphost)) { + if (ref($iphost{$ip}) eq 'ARRAY') { + foreach my $id (@{$iphost{$ip}}) { + my $location = &Apache::lonnet::internet_dom($id); + if ($location) { + next if (grep(/^\Q$location\E$/,@{$intdoms})); + if (ref($by_ip->{$ip}) eq 'ARRAY') { + unless(grep(/^\Q$location\E$/,@{$by_ip->{$ip}})) { + push(@{$by_ip->{$ip}},$location); + } + } else { + $by_ip->{$ip} = [$location]; + } + } + } + } + } + foreach my $ip (sort(keys(%{$by_ip}))) { + if (ref($by_ip->{$ip}) eq 'ARRAY') { + @{$by_ip->{$ip}} = sort(@{$by_ip->{$ip}}); + my $first = $by_ip->{$ip}->[0]; + if (ref($by_location->{$first}) eq 'ARRAY') { + unless (grep(/^\Q$ip\E$/,@{$by_location->{$first}})) { + push(@{$by_location->{$first}},$ip); + } + } else { + $by_location->{$first} = [$ip]; + } + } + } + return; +} + +sub current_offloads_to { + my ($dom,$settings,$servers) = @_; + my (%spareid,%otherdomconfigs); + if (ref($servers) eq 'HASH') { + foreach my $lonhost (sort(keys(%{$servers}))) { + my $gotspares; + if (ref($settings) eq 'HASH') { + if (ref($settings->{'spares'}) eq 'HASH') { + if (ref($settings->{'spares'}{$lonhost}) eq 'HASH') { + $spareid{$lonhost}{'primary'} = $settings->{'spares'}{$lonhost}{'primary'}; + $spareid{$lonhost}{'default'} = $settings->{'spares'}{$lonhost}{'default'}; + $gotspares = 1; + } + } + } + unless ($gotspares) { + my $gotspares; + my $serverhomeID = + &Apache::lonnet::get_server_homeID($servers->{$lonhost}); + my $serverhomedom = + &Apache::lonnet::host_domain($serverhomeID); + if ($serverhomedom ne $dom) { + if (ref($otherdomconfigs{$serverhomedom} eq 'HASH')) { + if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}) eq 'HASH') { + if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}) eq 'HASH') { + $spareid{$lonhost}{'primary'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'primary'}; + $spareid{$lonhost}{'default'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'default'}; + $gotspares = 1; + } + } + } else { + $otherdomconfigs{$serverhomedom} = + &Apache::lonnet::get_dom('configuration',['usersessions'],$serverhomedom); + if (ref($otherdomconfigs{$serverhomedom}) eq 'HASH') { + if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}) eq 'HASH') { + if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}) eq 'HASH') { + if (ref($otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{$lonhost}) eq 'HASH') { + $spareid{$lonhost}{'primary'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'primary'}; + $spareid{$lonhost}{'default'} = $otherdomconfigs{$serverhomedom}{'usersessions'}{'spares'}{'default'}; + $gotspares = 1; + } + } + } + } + } + } + } + unless ($gotspares) { + if ($lonhost eq $Apache::lonnet::perlvar{'lonHostID'}) { + $spareid{$lonhost}{'primary'} = $Apache::lonnet::spareid{'primary'}; + $spareid{$lonhost}{'default'} = $Apache::lonnet::spareid{'default'}; + } else { + my $server_hostname = &Apache::lonnet::hostname($lonhost); + my $server_homeID = &Apache::lonnet::get_server_homeID($server_hostname); + if ($server_homeID eq $Apache::lonnet::perlvar{'lonHostID'}) { + $spareid{$lonhost}{'primary'} = $Apache::lonnet::spareid{'primary'}; + $spareid{$lonhost}{'default'} = $Apache::lonnet::spareid{'default'}; + } else { + my %what = ( + spareid => 1, + ); + my ($result,$returnhash) = + &Apache::lonnet::get_remote_globals($lonhost,\%what); + if ($result eq 'ok') { + if (ref($returnhash) eq 'HASH') { + if (ref($returnhash->{'spareid'}) eq 'HASH') { + $spareid{$lonhost}{'primary'} = $returnhash->{'spareid'}->{'primary'}; + $spareid{$lonhost}{'default'} = $returnhash->{'spareid'}->{'default'}; + } + } + } + } + } + } + } + } + return %spareid; +} + +sub spares_row { + my ($dom,$servers,$spareid,$serverhomes,$altids,$rowtotal) = @_; + my $css_class; + my $numinrow = 4; + my $itemcount = 1; + my $datatable; + my %typetitles = &sparestype_titles(); + if ((ref($servers) eq 'HASH') && (ref($spareid) eq 'HASH') && (ref($altids) eq 'HASH')) { + foreach my $server (sort(keys(%{$servers}))) { + my $serverhome = &Apache::lonnet::get_server_homeID($servers->{$server}); + my ($othercontrol,$serverdom); + if ($serverhome ne $server) { + $serverdom = &Apache::lonnet::host_domain($serverhome); + $othercontrol = &mt('Session offloading controlled by domain: [_1]',''.$serverdom.''); + } else { + $serverdom = &Apache::lonnet::host_domain($server); + if ($serverdom ne $dom) { + $othercontrol = &mt('Session offloading controlled by domain: [_1]',''.$serverdom.''); + } + } + next unless (ref($spareid->{$server}) eq 'HASH'); + $css_class = $itemcount%2 ? ' class="LC_odd_row"' : ''; + $datatable .= ' + + '. + &mt('[_1] when busy, offloads to:' + ,''.$server.''). + "\n"; + my (%current,%canselect); + my @choices = + &possible_newspares($server,$spareid->{$server},$serverhomes,$altids); + foreach my $type ('primary','default') { + if (ref($spareid->{$server}) eq 'HASH') { + if (ref($spareid->{$server}{$type}) eq 'ARRAY') { + my @spares = @{$spareid->{$server}{$type}}; + if (@spares > 0) { + if ($othercontrol) { + $current{$type} = join(', ',@spares); + } else { + $current{$type} .= ''; + my $numspares = scalar(@spares); + for (my $i=0; $i<@spares; $i++) { + my $rem = $i%($numinrow); + if ($rem == 0) { + if ($i > 0) { + $current{$type} .= ''; + } + $current{$type} .= ''; + } + $current{$type} .= ''."\n"; + } + my $rem = @spares%($numinrow); + my $colsleft = $numinrow - $rem; + if ($colsleft > 1 ) { + $current{$type} .= ''; + } elsif ($colsleft == 1) { + $current{$type} .= ''."\n"; + } + $current{$type} .= '
'. + '  
'; + } + } + } + if ($current{$type} eq '') { + $current{$type} = &mt('None specified'); + } + if ($othercontrol) { + if ($type eq 'primary') { + $canselect{$type} = $othercontrol; + } + } else { + $canselect{$type} = + &mt('Add new [_1]'.$type.'[_2]:','','').' '. + ''."\n"; + } + } else { + $current{$type} = &mt('Could not be determined'); + if ($type eq 'primary') { + $canselect{$type} = $othercontrol; + } + } + if ($type eq 'default') { + $datatable .= ''; + } + $datatable .= ''.$typetitles{$type}.''."\n". + ''.$current{$type}.''."\n". + ''.$canselect{$type}.''."\n"; + } + $itemcount ++; + } + } + $$rowtotal += $itemcount; + return $datatable; +} + +sub possible_newspares { + my ($server,$currspares,$serverhomes,$altids) = @_; + my $serverhostname = &Apache::lonnet::hostname($server); + my %excluded; + if ($serverhostname ne '') { + %excluded = ( + $serverhostname => 1, + ); + } + if (ref($currspares) eq 'HASH') { + foreach my $type (keys(%{$currspares})) { + if (ref($currspares->{$type}) eq 'ARRAY') { + if (@{$currspares->{$type}} > 0) { + foreach my $curr (@{$currspares->{$type}}) { + my $hostname = &Apache::lonnet::hostname($curr); + $excluded{$hostname} = 1; + } + } + } + } + } + my @choices; + if ((ref($serverhomes) eq 'HASH') && (ref($altids) eq 'HASH')) { + if (keys(%{$serverhomes}) > 1) { + foreach my $name (sort(keys(%{$serverhomes}))) { + unless ($excluded{$name}) { + if (exists($altids->{$serverhomes->{$name}})) { + push(@choices,$altids->{$serverhomes->{$name}}); + } else { + push(@choices,$serverhomes->{$name}); + } + } + } + } + } + return sort(@choices); +} + +sub print_loadbalancing { + my ($dom,$settings,$rowtotal) = @_; + my $primary_id = &Apache::lonnet::domain($dom,'primary'); + my $intdom = &Apache::lonnet::internet_dom($primary_id); + my $numinrow = 1; + my $datatable; + my %servers = &Apache::lonnet::internet_dom_servers($dom); + my (%currbalancer,%currtargets,%currrules,%existing); + if (ref($settings) eq 'HASH') { + %existing = %{$settings}; + } + if ((keys(%servers) > 1) || (keys(%existing) > 0)) { + &get_loadbalancers_config(\%servers,\%existing,\%currbalancer, + \%currtargets,\%currrules); + } else { + return; + } + my ($othertitle,$usertypes,$types) = + &Apache::loncommon::sorted_inst_types($dom); + my $rownum = 8; + if (ref($types) eq 'ARRAY') { + $rownum += scalar(@{$types}); + } + my @css_class = ('LC_odd_row','LC_even_row'); + my $balnum = 0; + my $islast; + my (@toshow,$disabledtext); + if (keys(%currbalancer) > 0) { + @toshow = sort(keys(%currbalancer)); + if (scalar(@toshow) < scalar(keys(%servers)) + 1) { + push(@toshow,''); + } + } else { + @toshow = (''); + $disabledtext = &mt('No existing load balancer'); + } + foreach my $lonhost (@toshow) { + if ($balnum == scalar(@toshow)-1) { + $islast = 1; + } else { + $islast = 0; + } + my $cssidx = $balnum%2; + my $targets_div_style = 'display: none'; + my $disabled_div_style = 'display: block'; + my $homedom_div_style = 'display: none'; + $datatable .= ''. + ''. + '

'; + if ($lonhost eq '') { + $datatable .= ''; + if (keys(%currbalancer) > 0) { + $datatable .= &mt('Add balancer:'); + } else { + $datatable .= &mt('Enable balancer:'); + } + $datatable .= ' '. + ''."\n". + ' '."\n"; + } else { + $datatable .= ''.$lonhost.'
'. + ''. + ''; + $targets_div_style = 'display: block'; + $disabled_div_style = 'display: none'; + if ($dom eq &Apache::lonnet::host_domain($lonhost)) { + $homedom_div_style = 'display: block'; + } + } + $datatable .= '

'. + '
'.$disabledtext.'
'."\n". + '
'.&mt('Offloads to:').'
'; + my ($numspares,@spares) = &count_servers($lonhost,%servers); + my @sparestypes = ('primary','default'); + my %typetitles = &sparestype_titles(); + foreach my $sparetype (@sparestypes) { + my $targettable; + for (my $i=0; $i<$numspares; $i++) { + my $checked; + if (ref($currtargets{$lonhost}) eq 'HASH') { + if (ref($currtargets{$lonhost}{$sparetype}) eq 'ARRAY') { + if (grep(/^\Q$spares[$i]\E$/,@{$currtargets{$lonhost}{$sparetype}})) { + $checked = ' checked="checked"'; + } + } + } + my ($chkboxval,$disabled); + if (($lonhost ne '') && (exists($servers{$lonhost}))) { + $chkboxval = $spares[$i]; + } + if (exists($currbalancer{$spares[$i]})) { + $disabled = ' disabled="disabled"'; + } + $targettable .= + ''; + my $rem = $i%($numinrow); + if ($rem == 0) { + if (($i > 0) && ($i < $numspares-1)) { + $targettable .= ''; + } + if ($i < $numspares-1) { + $targettable .= ''; + } + } + } + if ($targettable ne '') { + my $rem = $numspares%($numinrow); + my $colsleft = $numinrow - $rem; + if ($colsleft > 1 ) { + $targettable .= ''. + ' '; + } elsif ($colsleft == 1) { + $targettable .= ' '; + } + $datatable .= ''.$typetitles{$sparetype}.'
'. + ''.$targettable.'

'; + } + } + $datatable .= '
'. + &loadbalancing_rules($dom,$intdom,$currrules{$lonhost}, + $othertitle,$usertypes,$types,\%servers, + \%currbalancer,$lonhost, + $targets_div_style,$homedom_div_style, + $css_class[$cssidx],$balnum,$islast); + $$rowtotal += $rownum; + $balnum ++; + } + $datatable .= ''; + return $datatable; +} + +sub get_loadbalancers_config { + my ($servers,$existing,$currbalancer,$currtargets,$currrules) = @_; + return unless ((ref($servers) eq 'HASH') && + (ref($existing) eq 'HASH') && (ref($currbalancer) eq 'HASH') && + (ref($currtargets) eq 'HASH') && (ref($currrules) eq 'HASH')); + if (keys(%{$existing}) > 0) { + my $oldlonhost; + foreach my $key (sort(keys(%{$existing}))) { + if ($key eq 'lonhost') { + $oldlonhost = $existing->{'lonhost'}; + $currbalancer->{$oldlonhost} = 1; + } elsif ($key eq 'targets') { + if ($oldlonhost) { + $currtargets->{$oldlonhost} = $existing->{'targets'}; + } + } elsif ($key eq 'rules') { + if ($oldlonhost) { + $currrules->{$oldlonhost} = $existing->{'rules'}; + } + } elsif (ref($existing->{$key}) eq 'HASH') { + $currbalancer->{$key} = 1; + $currtargets->{$key} = $existing->{$key}{'targets'}; + $currrules->{$key} = $existing->{$key}{'rules'}; + } + } + } else { + my ($balancerref,$targetsref) = + &Apache::lonnet::get_lonbalancer_config($servers); + if ((ref($balancerref) eq 'HASH') && (ref($targetsref) eq 'HASH')) { + foreach my $server (sort(keys(%{$balancerref}))) { + $currbalancer->{$server} = 1; + $currtargets->{$server} = $targetsref->{$server}; + } + } + } + return; +} + +sub loadbalancing_rules { + my ($dom,$intdom,$currrules,$othertitle,$usertypes,$types,$servers, + $currbalancer,$lonhost,$targets_div_style,$homedom_div_style, + $css_class,$balnum,$islast) = @_; + my $output; + my $num = 0; + my ($alltypes,$othertypes,$titles) = + &loadbalancing_titles($dom,$intdom,$usertypes,$types); + if ((ref($alltypes) eq 'ARRAY') && (ref($titles) eq 'HASH')) { + foreach my $type (@{$alltypes}) { + $num ++; + my $current; + if (ref($currrules) eq 'HASH') { + $current = $currrules->{$type}; + } + if (($type eq '_LC_external') || ($type eq '_LC_internetdom') || ($type eq '_LC_ipchange')) { + if ($dom ne &Apache::lonnet::host_domain($lonhost)) { + $current = ''; + } + } + $output .= &loadbalance_rule_row($type,$titles->{$type},$current, + $servers,$currbalancer,$lonhost,$dom, + $targets_div_style,$homedom_div_style, + $css_class,$balnum,$num,$islast); + } + } + return $output; +} + +sub loadbalancing_titles { + my ($dom,$intdom,$usertypes,$types) = @_; + my %othertypes = ( + '_LC_adv' => &mt('Advanced users from [_1]',$dom), + '_LC_author' => &mt('Users from [_1] with author role',$dom), + '_LC_internetdom' => &mt('Users not from [_1], but from [_2]',$dom,$intdom), + '_LC_external' => &mt('Users not from [_1]',$intdom), + '_LC_ipchangesso' => &mt('SSO users from [_1], with IP mismatch',$dom), + '_LC_ipchange' => &mt('Non-SSO users with IP mismatch'), + ); + my @alltypes = ('_LC_adv','_LC_author','_LC_internetdom','_LC_external','_LC_ipchangesso','_LC_ipchange'); + if (ref($types) eq 'ARRAY') { + unshift(@alltypes,@{$types},'default'); + } + my %titles; + foreach my $type (@alltypes) { + if ($type =~ /^_LC_/) { + $titles{$type} = $othertypes{$type}; + } elsif ($type eq 'default') { + $titles{$type} = &mt('All users from [_1]',$dom); + if (ref($types) eq 'ARRAY') { + if (@{$types} > 0) { + $titles{$type} = &mt('Other users from [_1]',$dom); + } + } + } elsif (ref($usertypes) eq 'HASH') { + $titles{$type} = $usertypes->{$type}; + } + } + return (\@alltypes,\%othertypes,\%titles); +} + +sub loadbalance_rule_row { + my ($type,$title,$current,$servers,$currbalancer,$lonhost,$dom, + $targets_div_style,$homedom_div_style,$css_class,$balnum,$num,$islast) = @_; + my @rulenames; + my %ruletitles = &offloadtype_text(); + if (($type eq '_LC_ipchangesso') || ($type eq '_LC_ipchange')) { + @rulenames = ('balancer','offloadedto'); + } else { + @rulenames = ('default','homeserver'); + if ($type eq '_LC_external') { + push(@rulenames,'externalbalancer'); + } else { + push(@rulenames,'specific'); + } + push(@rulenames,'none'); + } + my $style = $targets_div_style; + if (($type eq '_LC_external') || ($type eq '_LC_internetdom') || ($type eq '_LC_ipchange')) { + $style = $homedom_div_style; + } + my $space; + if ($islast && $num == 1) { + $space = '
 
'; + } + my $output = + ''.$space. + '
'.$title.'
'."\n". + ''.$space. + '
'."\n"; + for (my $i=0; $i<@rulenames; $i++) { + my $rule = $rulenames[$i]; + my ($checked,$extra); + if ($rulenames[$i] eq 'default') { + $rule = ''; + } + if ($rulenames[$i] eq 'specific') { + if (ref($servers) eq 'HASH') { + my $default; + if (($current ne '') && (exists($servers->{$current}))) { + $checked = ' checked="checked"'; + } + unless ($checked) { + $default = ' selected="selected"'; + } + $extra = + ': '; + } + } elsif ($rule eq $current) { + $checked = ' checked="checked"'; + } + $output .= ''.$extra.'
'."\n"; + } + $output .= '
'."\n"; + return $output; +} + +sub offloadtype_text { + my %ruletitles = &Apache::lonlocal::texthash ( + 'default' => 'Offloads to default destinations', + 'homeserver' => "Offloads to user's home server", + 'externalbalancer' => "Offloads to Load Balancer in user's domain", + 'specific' => 'Offloads to specific server', + 'none' => 'No offload', + 'balancer' => 'Session hosted on Load Balancer, after re-authentication', + 'offloadedto' => 'Session hosted on offload server, after re-authentication', + ); + return %ruletitles; +} + +sub sparestype_titles { + my %typestitles = &Apache::lonlocal::texthash ( + 'primary' => 'primary', + 'default' => 'default', + ); + return %typestitles; } sub contact_titles { @@ -1999,6 +3327,8 @@ sub contact_titles { 'helpdeskmail' => 'Helpdesk requests to be e-mailed to', 'lonstatusmail' => 'E-mail from nightly status check (warnings/errors)', 'requestsmail' => 'E-mail from course requests requiring approval', + 'updatesmail' => 'E-mail from nightly check of LON-CAPA module integrity/updates', + 'idconflictsmail' => 'E-mail from bi-nightly check for multiple users sharing same student/employee ID', ); my %short_titles = &Apache::lonlocal::texthash ( adminemail => 'Admin E-mail address', @@ -2009,8 +3339,9 @@ sub contact_titles { sub tool_titles { my %titles = &Apache::lonlocal::texthash ( - aboutme => 'Personal Information Page', + aboutme => 'Personal web page', blog => 'Blog', + webdav => 'WebDAV', portfolio => 'Portfolio', official => 'Official courses (with institutional codes)', unofficial => 'Unofficial courses', @@ -2033,10 +3364,19 @@ sub courserequest_titles { return %titles; } +sub authorrequest_titles { + my %titles = &Apache::lonlocal::texthash ( + norequest => 'Not allowed', + approval => 'Approval by Dom. Coord.', + automatic => 'Automatic approval', + ); + return %titles; +} + sub courserequest_conditions { my %conditions = &Apache::lonlocal::texthash ( approval => '(Processing of request subject to approval by Domain Coordinator).', - validate => '(Processing of request subject to instittutional validation).', + validate => '(Processing of request subject to institutional validation).', ); return %conditions; } @@ -2162,18 +3502,20 @@ sub print_usercreation { } my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); + my $createsettings; + if (ref($settings) eq 'HASH') { + $createsettings = $settings->{cancreate}; + } if (ref($usertypes) eq 'HASH') { if (keys(%{$usertypes}) > 0) { - my $createsettings; - if (ref($settings) eq 'HASH') { - $createsettings = $settings->{cancreate}; - } $datatable .= &insttypes_row($createsettings,$types,$usertypes, $dom,$numinrow,$othertitle, 'statustocreate'); $$rowtotal ++; + $rownum ++; } } + $datatable .= &captcha_choice('cancreate',$createsettings,$rownum); } else { my @contexts = ('author','course','domain'); my @authtypes = ('int','krb4','krb5','loc'); @@ -2225,6 +3567,64 @@ sub print_usercreation { return $datatable; } +sub captcha_choice { + my ($context,$settings,$itemcount) = @_; + my ($keyentry,$currpub,$currpriv,%checked,$rowname,$pubtext,$privtext); + my %lt = &captcha_phrases(); + $keyentry = 'hidden'; + if ($context eq 'cancreate') { + $rowname = &mt('CAPTCHA validation (e-mail as username)'); + } elsif ($context eq 'login') { + $rowname = &mt('"Contact helpdesk" CAPTCHA validation'); + } + if (ref($settings) eq 'HASH') { + if ($settings->{'captcha'}) { + $checked{$settings->{'captcha'}} = ' checked="checked"'; + } else { + $checked{'original'} = ' checked="checked"'; + } + if ($settings->{'captcha'} eq 'recaptcha') { + $pubtext = $lt{'pub'}; + $privtext = $lt{'priv'}; + $keyentry = 'text'; + } + if (ref($settings->{'recaptchakeys'}) eq 'HASH') { + $currpub = $settings->{'recaptchakeys'}{'public'}; + $currpriv = $settings->{'recaptchakeys'}{'private'}; + } + } else { + $checked{'original'} = ' checked="checked"'; + } + my $css_class = $itemcount%2?' class="LC_odd_row"':''; + my $output = ''. + ''.$rowname.''."\n". + ''."\n". + '
'."\n"; + foreach my $option ('original','recaptcha','notused') { + $output .= ''; + unless ($option eq 'notused') { + $output .= (' 'x2)."\n"; + } + } +# +# Note: If reCAPTCHA is to be used for LON-CAPA servers in a domain, a domain coordinator should visit: +# https://www.google.com/recaptcha and generate a Public and Private key. For domains with multiple +# servers a single key pair will be used for all servers, so the internet domain (e.g., yourcollege.edu) +# specified for use with the key should be broad enough to accommodate all servers in the LON-CAPA domain. +# + $output .= '
'."\n". + ''.$pubtext.' '."\n". + '
'."\n". + ''.$privtext.' '."\n". + '
'."\n". + ''; + return $output; +} + sub user_formats_row { my ($type,$settings,$rules,$ruleorder,$numinrow,$rowcount) = @_; my $output; @@ -2361,9 +3761,9 @@ sub print_usermodification { sub print_defaults { my ($dom,$rowtotal) = @_; my @items = ('auth_def','auth_arg_def','lang_def','timezone_def', - 'datelocale_def'); + 'datelocale_def','portal_def'); my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); - my $titles = &defaults_titles(); + my $titles = &defaults_titles($dom); my $rownum = 0; my ($datatable,$css_class); foreach my $item (@items) { @@ -2399,9 +3799,19 @@ sub print_defaults { } elsif ($item eq 'datelocale_def') { my $includeempty = 1; $datatable .= &Apache::loncommon::select_datelocale($item,$domdefaults{$item},undef,$includeempty); - } else { + } elsif ($item eq 'lang_def') { + my %langchoices = &get_languages_hash(); + $langchoices{''} = 'No language preference'; + %langchoices = &Apache::lonlocal::texthash(%langchoices); + $datatable .= &Apache::loncommon::select_form($domdefaults{$item},$item, + \%langchoices); + } else { + my $size; + if ($item eq 'portal_def') { + $size = ' size="25"'; + } $datatable .= ''; + $domdefaults{$item}.'"'.$size.' />'; } $datatable .= ''; $rownum ++; @@ -2410,14 +3820,37 @@ sub print_defaults { return $datatable; } +sub get_languages_hash { + my %langchoices; + foreach my $id (&Apache::loncommon::languageids()) { + my $code = &Apache::loncommon::supportedlanguagecode($id); + if ($code ne '') { + $langchoices{$code} = &Apache::loncommon::plainlanguagedescription($id); + } + } + return %langchoices; +} + sub defaults_titles { + my ($dom) = @_; my %titles = &Apache::lonlocal::texthash ( 'auth_def' => 'Default authentication type', 'auth_arg_def' => 'Default authentication argument', 'lang_def' => 'Default language', 'timezone_def' => 'Default timezone', 'datelocale_def' => 'Default locale for dates', + 'portal_def' => 'Portal/Default URL', ); + if ($dom) { + my $uprimary_id = &Apache::lonnet::domain($dom,'primary'); + my $uint_dom = &Apache::lonnet::internet_dom($uprimary_id); + my $protocol = $Apache::lonnet::protocol{$uprimary_id}; + $protocol = 'http' if ($protocol ne 'https'); + if ($uint_dom) { + $titles{'portal_def'} .= ' '.&mt('(for example: [_1])',$protocol.'://loncapa.'. + $uint_dom); + } + } return (\%titles); } @@ -2530,8 +3963,8 @@ sub print_scantronformat { $datatable .= ''.&mt('Default in use:').'
'. ''; if ($scantronurl) { - $datatable .= ''. - &mt('Default scantron format file').''; + $datatable .= &Apache::loncommon::modal_link($scantronurl,&mt('Default bubblesheet format file'),600,500, + undef,undef,undef,undef,'background-color:#ffffff'); } else { $datatable = &mt('File unavailable for display'); } @@ -2556,11 +3989,12 @@ sub print_scantronformat { } $datatable .= ''.$errorstr.' '; } elsif ($scantronurl) { + my $link = &Apache::loncommon::modal_link($scantronurl,&mt('Custom bubblesheet format file'),600,500, + undef,undef,undef,undef,'background-color:#ffffff'); $datatable .= ''. - ''. - &mt('Custom scantron format file').''. + $link. + ''. ' '. &mt('Replace:').'
'; } @@ -2587,7 +4021,7 @@ sub legacy_scantronformat { &publishlogo($r,'copy',$legacyfile,$dom,$confname,'scantron', '','',$newfile); if ($result ne 'ok') { - $error = &mt("An error occurred publishing the [_1] scantron format file in RES space. Error was: [_2].",$newfile,$result); + $error = &mt("An error occurred publishing the [_1] bubblesheet format file in RES space. Error was: [_2].",$newfile,$result); } } return ($url,$error); @@ -2858,8 +4292,8 @@ sub print_serverstatuses { sub serverstatus_pages { return ('userstatus','lonstatus','loncron','server-status','codeversions', - 'clusterstatus','metadata_keywords','metadata_harvest', - 'takeoffline','takeonline','showenv','toggledebug'); + 'checksums','clusterstatus','metadata_keywords','metadata_harvest', + 'takeoffline','takeonline','showenv','toggledebug','ping','domconf'); } sub coursecategories_javascript { @@ -3016,7 +4450,7 @@ sub build_category_rows { if (ref($cats->[$depth]{$parent}) eq 'ARRAY') { my $numchildren = @{$cats->[$depth]{$parent}}; my $css_class = $itemcount%2?' class="LC_odd_row"':''; - $text .= ''; + $text .= '
'; my ($idxnum,$parent_name,$parent_item); my $higher = $depth - 1; if ($higher == 0) { @@ -3167,14 +4601,19 @@ sub insttypes_row { my %lt = &Apache::lonlocal::texthash ( cansearch => 'Users allowed to search', statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)', + lockablenames => 'User preference to lock name', ); my $showdom; if ($context eq 'cansearch') { $showdom = ' ('.$dom.')'; } + my $class = 'LC_left_item'; + if ($context eq 'statustocreate') { + $class = 'LC_right_item'; + } my $output = ''. '
'.$lt{$context}.$showdom. - ''; + '
'; my $rem; if (ref($types) eq 'ARRAY') { for (my $i=0; $i<@{$types}; $i++) { @@ -3203,10 +4642,12 @@ sub insttypes_row { $usertypes->{$types->[$i]}.''; } } - $rem = @{$types}%($numinrow); } my $colsleft = $numinrow - $rem; + if (($rem == 0) && (@{$types} > 0)) { + $output .= ''; + } if ($colsleft > 1) { $output .= '
'; } else { @@ -3301,14 +4742,15 @@ sub usertype_update_row { } sub modify_login { - my ($r,$dom,$confname,%domconfig) = @_; - my ($resulttext,$errors,$colchgtext,%changes,%colchanges); - my %title = ( coursecatalog => 'Display course catalog', - adminmail => 'Display administrator E-mail address', - newuser => 'Link for visitors to create a user account', - loginheader => 'Log-in box header'); - my @offon = ('off','on'); - my %curr_loginvia; + my ($r,$dom,$confname,$lastactref,%domconfig) = @_; + my ($resulttext,$errors,$colchgtext,%changes,%colchanges,%newfile,%newurl, + %curr_loginvia,%loginhash,@currlangs,@newlangs,$addedfile,%title,@offon); + %title = ( coursecatalog => 'Display course catalog', + adminmail => 'Display administrator E-mail address', + helpdesk => 'Display "Contact Helpdesk" link', + newuser => 'Link for visitors to create a user account', + loginheader => 'Log-in box header'); + @offon = ('off','on'); if (ref($domconfig{login}) eq 'HASH') { if (ref($domconfig{login}{loginvia}) eq 'HASH') { foreach my $lonhost (keys(%{$domconfig{login}{loginvia}})) { @@ -3316,10 +4758,9 @@ sub modify_login { } } } - my %loginhash; ($errors,%colchanges) = &modify_colors($r,$dom,$confname,['login'], \%domconfig,\%loginhash); - my @toggles = ('coursecatalog','adminmail','newuser'); + my @toggles = ('coursecatalog','adminmail','helpdesk','newuser'); foreach my $item (@toggles) { $loginhash{login}{$item} = $env{'form.'.$item}; } @@ -3329,31 +4770,188 @@ sub modify_login { \%loginhash); } - my %servers = &dom_servers($dom); + my %servers = &Apache::lonnet::internet_dom_servers($dom); + my @loginvia_attribs = ('serverpath','custompath','exempt'); if (keys(%servers) > 1) { foreach my $lonhost (keys(%servers)) { - next if ($env{'form.'.$lonhost.'_serverurl'} eq $lonhost); - if ($env{'form.'.$lonhost.'_serverurl'} eq $curr_loginvia{$lonhost}) { - $loginhash{login}{loginvia}{$lonhost} = $curr_loginvia{$lonhost}; next; - } - if ($curr_loginvia{$lonhost} ne '') { - $loginhash{login}{loginvia}{$lonhost} = $env{'form.'.$lonhost.'_serverurl'}; - $changes{'loginvia'}{$lonhost} = 1; + next if ($env{'form.'.$lonhost.'_server'} eq $lonhost); + if (ref($curr_loginvia{$lonhost}) eq 'HASH') { + if ($env{'form.'.$lonhost.'_server'} eq $curr_loginvia{$lonhost}{'server'}) { + $loginhash{login}{loginvia}{$lonhost}{'server'} = $curr_loginvia{$lonhost}{'server'}; + } elsif ($curr_loginvia{$lonhost}{'server'} ne '') { + if (defined($servers{$env{'form.'.$lonhost.'_server'}})) { + $loginhash{login}{loginvia}{$lonhost}{'server'} = $env{'form.'.$lonhost.'_server'}; + $changes{'loginvia'}{$lonhost} = 1; + } else { + $loginhash{login}{loginvia}{$lonhost}{'server'} = ''; + $changes{'loginvia'}{$lonhost} = 1; + } + } else { + if (defined($servers{$env{'form.'.$lonhost.'_server'}})) { + $loginhash{login}{loginvia}{$lonhost}{'server'} = $env{'form.'.$lonhost.'_server'}; + $changes{'loginvia'}{$lonhost} = 1; + } + } + if ($loginhash{login}{loginvia}{$lonhost}{'server'} eq '') { + foreach my $item (@loginvia_attribs) { + $loginhash{login}{loginvia}{$lonhost}{$item} = ''; + } + } else { + foreach my $item (@loginvia_attribs) { + my $new = $env{'form.'.$lonhost.'_'.$item}; + if (($item eq 'serverpath') && ($new eq 'custom')) { + $env{'form.'.$lonhost.'_custompath'} =~ s/\s+//g; + if ($env{'form.'.$lonhost.'_custompath'} eq '') { + $new = '/'; + } + } + if (($item eq 'custompath') && + ($env{'form.'.$lonhost.'_serverpath'} ne 'custom')) { + $new = ''; + } + if ($new ne $curr_loginvia{$lonhost}{$item}) { + $changes{'loginvia'}{$lonhost} = 1; + } + if ($item eq 'exempt') { + $new =~ s/^\s+//; + $new =~ s/\s+$//; + my @poss_ips = split(/\s*[,:]\s*/,$new); + my @okips; + foreach my $ip (@poss_ips) { + if ($ip =~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) { + if (($1 <= 255) && ($2 <= 255) && ($3 <= 255) && ($4 <= 255)) { + push(@okips,$ip); + } + } + } + if (@okips > 0) { + $new = join(',',@okips); + } else { + $new = ''; + } + } + $loginhash{login}{loginvia}{$lonhost}{$item} = $new; + } + } } else { - if (defined($servers{$env{'form.'.$lonhost.'_serverurl'}})) { - $loginhash{login}{loginvia}{$lonhost} = $env{'form.'.$lonhost.'_serverurl'}; + if (defined($servers{$env{'form.'.$lonhost.'_server'}})) { + $loginhash{login}{loginvia}{$lonhost}{'server'} = $env{'form.'.$lonhost.'_server'}; $changes{'loginvia'}{$lonhost} = 1; + foreach my $item (@loginvia_attribs) { + my $new = $env{'form.'.$lonhost.'_'.$item}; + if (($item eq 'serverpath') && ($new eq 'custom')) { + if ($env{'form.'.$lonhost.'_custompath'} eq '') { + $new = '/'; + } + } + if (($item eq 'custompath') && + ($env{'form.'.$lonhost.'_serverpath'} ne 'custom')) { + $new = ''; + } + $loginhash{login}{loginvia}{$lonhost}{$item} = $new; + } + } + } + } + } + + my $servadm = $r->dir_config('lonAdmEMail'); + my %langchoices = &Apache::lonlocal::texthash(&get_languages_hash()); + if (ref($domconfig{'login'}) eq 'HASH') { + if (ref($domconfig{'login'}{'helpurl'}) eq 'HASH') { + foreach my $lang (sort(keys(%{$domconfig{'login'}{'helpurl'}}))) { + if ($lang eq 'nolang') { + push(@currlangs,$lang); + } elsif (defined($langchoices{$lang})) { + push(@currlangs,$lang); + } else { + next; + } + } + } + } + my @delurls = &Apache::loncommon::get_env_multiple('form.loginhelpurl_del'); + if (@currlangs > 0) { + foreach my $lang (@currlangs) { + if (grep(/^\Q$lang\E$/,@delurls)) { + $changes{'helpurl'}{$lang} = 1; + } elsif ($env{'form.loginhelpurl_'.$lang.'.filename'}) { + $changes{'helpurl'}{$lang} = 1; + $newfile{$lang} = $env{'form.loginhelpurl_'.$lang.'.filename'}; + push(@newlangs,$lang); + } else { + $loginhash{'login'}{'helpurl'}{$lang} = $domconfig{'login'}{'helpurl'}{$lang}; + } + } + } + unless (grep(/^nolang$/,@currlangs)) { + if ($env{'form.loginhelpurl_nolang.filename'}) { + $changes{'helpurl'}{'nolang'} = 1; + $newfile{'nolang'} = $env{'form.loginhelpurl_nolang.filename'}; + push(@newlangs,'nolang'); + } + } + if ($env{'form.loginhelpurl_add_lang'}) { + if ((defined($langchoices{$env{'form.loginhelpurl_add_lang'}})) && + ($env{'form.loginhelpurl_add_file.filename'})) { + $newfile{$env{'form.loginhelpurl_add_lang'}} = $env{'form.loginhelpurl_add_file.filename'}; + $addedfile = $env{'form.loginhelpurl_add_lang'}; + } + } + if ((@newlangs > 0) || ($addedfile)) { + my $error; + my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm); + if ($configuserok eq 'ok') { + if ($switchserver) { + $error = &mt("Upload of custom help file is not permitted to this server: [_1]",$switchserver); + } elsif ($author_ok eq 'ok') { + my @allnew = @newlangs; + if ($addedfile ne '') { + push(@allnew,$addedfile); + } + foreach my $lang (@allnew) { + my $formelem = 'loginhelpurl_'.$lang; + if ($lang eq $env{'form.loginhelpurl_add_lang'}) { + $formelem = 'loginhelpurl_add_file'; + } + (my $result,$newurl{$lang}) = &publishlogo($r,'upload',$formelem,$dom,$confname, + "help/$lang",'','',$newfile{$lang}); + if ($result eq 'ok') { + $loginhash{'login'}{'helpurl'}{$lang} = $newurl{$lang}; + $changes{'helpurl'}{$lang} = 1; + } else { + my $puberror = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$newfile{$lang},$result); + $errors .= '
  • '.$puberror.'
  • '; + if ((grep(/^\Q$lang\E$/,@currlangs)) && + (!grep(/^\Q$lang\E$/,@delurls))) { + + $loginhash{'login'}{'helpurl'}{$lang} = $domconfig{'login'}{'helpurl'}{$lang}; + } + } } + } else { + $error = &mt("Upload of custom log-in help file(s) failed because an author role could not be assigned to a Domain Configuration user ([_1]) in domain: [_2]. Error was: [_3].",$confname,$dom,$author_ok); } + } else { + $error = &mt("Upload of custom log-in help file(s) failed because a Domain Configuration user ([_1]) could not be created in domain: [_2]. Error was: [_3].",$confname,$dom,$configuserok); + } + if ($error) { + &Apache::lonnet::logthis($error); + $errors .= '
  • '.$error.'
  • '; } } + &process_captcha('login',\%changes,$loginhash{'login'},$domconfig{'login'}); + + my $defaulthelpfile = '/adm/loginproblems.html'; + my $defaulttext = &mt('Default in use'); my $putresult = &Apache::lonnet::put_dom('configuration',\%loginhash, $dom); if ($putresult eq 'ok') { - my @toggles = ('coursecatalog','adminmail','newuser'); + my @toggles = ('coursecatalog','adminmail','helpdesk','newuser'); my %defaultchecked = ( 'coursecatalog' => 'on', + 'helpdesk' => 'on', 'adminmail' => 'off', 'newuser' => 'off', ); @@ -3379,32 +4977,102 @@ sub modify_login { } } } - if (($domconfig{'login'}{'loginheader'} eq 'text') && - ($env{'form.loginheader'} eq 'image')) { - $changes{'loginheader'} = 1; - } elsif (($domconfig{'login'}{'loginheader'} eq '' || - $domconfig{'login'}{'loginheader'} eq 'image') && - ($env{'form.loginheader'} eq 'text')) { - $changes{'loginheader'} = 1; - } } if (keys(%changes) > 0 || $colchgtext) { &Apache::loncommon::devalidate_domconfig_cache($dom); + $$lastactref = 'update'; $resulttext = &mt('Changes made:').'
      '; foreach my $item (sort(keys(%changes))) { - if ($item eq 'loginheader') { - $resulttext .= '
    • '.&mt("$title{$item} set to $env{'form.loginheader'}").'
    • '; - } elsif ($item eq 'loginvia') { + if ($item eq 'loginvia') { if (ref($changes{$item}) eq 'HASH') { $resulttext .= '
    • '.&mt('Log-in page availability:').'
        '; foreach my $lonhost (sort(keys(%{$changes{$item}}))) { - if ($servers{$env{'form.'.$lonhost.'_serverurl'}} ne '') { - $resulttext .= '
      • '.&mt('Server: [_1] log-in page now redirects to [_2]',$lonhost,$servers{$env{'form.'.$lonhost.'_serverurl'}}).'
      • '; + if (defined($servers{$loginhash{login}{loginvia}{$lonhost}{'server'}})) { + if (ref($loginhash{login}{loginvia}{$lonhost}) eq 'HASH') { + my $protocol = $Apache::lonnet::protocol{$env{'form.'.$lonhost.'_server'}}; + $protocol = 'http' if ($protocol ne 'https'); + my $target = $protocol.'://'.$servers{$env{'form.'.$lonhost.'_server'}}; + + if ($loginhash{login}{loginvia}{$lonhost}{'serverpath'} eq 'custom') { + $target .= $loginhash{login}{loginvia}{$lonhost}{'custompath'}; + } else { + $target .= $loginhash{login}{loginvia}{$lonhost}{'serverpath'}; + } + $resulttext .= '
      • '.&mt('Server: [_1] log-in page redirects to [_2].',$servers{$lonhost},''.$target.''); + if ($loginhash{login}{loginvia}{$lonhost}{'exempt'} ne '') { + $resulttext .= ' '.&mt('No redirection for clients from following IPs:').' '.$loginhash{login}{loginvia}{$lonhost}{'exempt'}; + } + $resulttext .= '
      • '; + } else { + $resulttext .= '
      • '.&mt('Server: [_1] has standard log-in page.',$lonhost).'
      • '; + } + } else { + $resulttext .= '
      • '.&mt('Server: [_1] has standard log-in page.',$servers{$lonhost}).'
      • '; + } + } + $resulttext .= '
    • '; + } + } elsif ($item eq 'helpurl') { + if (ref($changes{$item}) eq 'HASH') { + foreach my $lang (sort(keys(%{$changes{$item}}))) { + if (grep(/^\Q$lang\E$/,@delurls)) { + my ($chg,$link); + $link = &Apache::loncommon::modal_link($defaulthelpfile,$defaulttext,600,500); + if ($lang eq 'nolang') { + $chg = &mt('custom log-in help file removed for no preferred language; [_1]',$link); + } else { + $chg = &mt('custom log-in help file removed for specific language: [_1]; [_2]',$langchoices{$lang},$link); + } + $resulttext .= '
    • '.$chg.'
    • '; + } else { + my $chg; + if ($lang eq 'nolang') { + $chg = &mt('custom log-in help file for no preferred language'); + } else { + $chg = &mt('custom log-in help file for specific language: [_1]',$langchoices{$lang}); + } + $resulttext .= '
    • '.&Apache::loncommon::modal_link( + $loginhash{'login'}{'helpurl'}{$lang}. + '?inhibitmenu=yes',$chg,600,500). + '
    • '; + } + } + } + } elsif ($item eq 'captcha') { + if (ref($loginhash{'login'}) eq 'HASH') { + my $chgtxt; + if ($loginhash{'login'}{$item} eq 'notused') { + $chgtxt .= &mt('No CAPTCHA validation in use for helpdesk form.'); + } else { + my %captchas = &captcha_phrases(); + if ($captchas{$loginhash{'login'}{$item}}) { + $chgtxt .= &mt("Validation for helpdesk form set to $captchas{$loginhash{'login'}{$item}}."); } else { - $resulttext .= '
    • '.&mt('Server: [_1] now has standard log-in page.',$lonhost).'
    • '; + $chgtxt .= &mt('Validation for helpdesk form set to unknown type.'); } } - $resulttext .= '
    '; + $resulttext .= '
  • '.$chgtxt.'
  • '; + } + } elsif ($item eq 'recaptchakeys') { + if (ref($loginhash{'login'}) eq 'HASH') { + my ($privkey,$pubkey); + if (ref($loginhash{'login'}{$item}) eq 'HASH') { + $pubkey = $loginhash{'login'}{$item}{'public'}; + $privkey = $loginhash{'login'}{$item}{'private'}; + } + my $chgtxt .= &mt('ReCAPTCHA keys changes').'
      '; + if (!$pubkey) { + $chgtxt .= '
    • '.&mt('Public key deleted').'
    • '; + } else { + $chgtxt .= '
    • '.&mt('Public key set to [_1]',$pubkey).'
    • '; + } + if (!$privkey) { + $chgtxt .= '
    • '.&mt('Private key deleted').'
    • '; + } else { + $chgtxt .= '
    • '.&mt('Private key set to [_1]',$pubkey).'
    • '; + } + $chgtxt .= '
    '; + $resulttext .= '
  • '.$chgtxt.'
  • '; } } else { $resulttext .= '
  • '.&mt("$title{$item} set to $offon[$env{'form.'.$item}]").'
  • '; @@ -3433,7 +5101,7 @@ sub color_font_choices { links => "Link colors", images => "Images", font => "Font color", - fontmenu => "Font Menu", + fontmenu => "Font menu", pgbg => "Page", tabbg => "Header", sidebg => "Border", @@ -3445,7 +5113,7 @@ sub color_font_choices { } sub modify_rolecolors { - my ($r,$dom,$confname,$roles,%domconfig) = @_; + my ($r,$dom,$confname,$roles,$lastactref,%domconfig) = @_; my ($resulttext,%rolehash); $rolehash{'rolecolors'} = {}; if (ref($domconfig{'rolecolors'}) ne 'HASH') { @@ -3460,6 +5128,7 @@ sub modify_rolecolors { if ($putresult eq 'ok') { if (keys(%changes) > 0) { &Apache::loncommon::devalidate_domconfig_cache($dom); + $$lastactref = 'update'; $resulttext = &display_colorchgs($dom,\%changes,$roles, $rolehash{'rolecolors'}); } else { @@ -3485,24 +5154,45 @@ sub modify_colors { my @images; my $servadm = $r->dir_config('lonAdmEMail'); my $errors; + my %defaults; foreach my $role (@{$roles}) { if ($role eq 'login') { %choices = &login_choices(); @logintext = ('textcol','bgcol'); } else { %choices = &color_font_choices(); - $confhash->{$role}{'fontmenu'} = $env{'form.'.$role.'_fontmenu'}; } if ($role eq 'login') { @images = ('img','logo','domlogo','login'); @bgs = ('pgbg','mainbg','sidebg'); } else { @images = ('img'); - @bgs = ('pgbg','tabbg','sidebg'); + @bgs = ('pgbg','tabbg','sidebg'); } - $confhash->{$role}{'font'} = $env{'form.'.$role.'_font'}; - foreach my $item (@bgs,@links,@logintext) { - $confhash->{$role}{$item} = $env{'form.'.$role.'_'.$item}; + my %defaults = &role_defaults($role,\@bgs,\@links,\@images,\@logintext); + unless ($env{'form.'.$role.'_font'} eq $defaults{'font'}) { + $confhash->{$role}{'font'} = $env{'form.'.$role.'_font'}; + } + if ($role eq 'login') { + foreach my $item (@logintext) { + unless ($env{'form.'.$role.'_'.$item} eq $defaults{'logintext'}{$item}) { + $confhash->{$role}{$item} = $env{'form.'.$role.'_'.$item}; + } + } + } else { + unless($env{'form.'.$role.'_fontmenu'} eq $defaults{'fontmenu'}) { + $confhash->{$role}{'fontmenu'} = $env{'form.'.$role.'_fontmenu'}; + } + } + foreach my $item (@bgs) { + unless ($env{'form.'.$role.'_'.$item} eq $defaults{'bgs'}{$item} ) { + $confhash->{$role}{$item} = $env{'form.'.$role.'_'.$item}; + } + } + foreach my $item (@links) { + unless ($env{'form.'.$role.'_'.$item} eq $defaults{'links'}{$item}) { + $confhash->{$role}{$item} = $env{'form.'.$role.'_'.$item}; + } } my ($configuserok,$author_ok,$switchserver) = &config_check($dom,$confname,$servadm); @@ -3850,15 +5540,17 @@ sub publishlogo { # See if there is anything left unless ($fname) { return ('error: no uploaded file'); } $fname="$subdir/$fname"; - my $filepath='/home/'.$confname.'/public_html'; + my $docroot=$r->dir_config('lonDocRoot'); + my $filepath="$docroot/priv"; + my $relpath = "$dom/$confname"; my ($fnamepath,$file,$fetchthumb); $file=$fname; if ($fname=~m|/|) { ($fnamepath,$file) = ($fname =~ m|^(.*)/([^/]+)$|); } - my @parts=split(/\//,$filepath.'/'.$fnamepath); + my @parts=split(/\//,"$filepath/$relpath/$fnamepath"); my $count; - for ($count=4;$count<=$#parts;$count++) { + for ($count=5;$count<=$#parts;$count++) { $filepath.="/$parts[$count]"; if ((-e $filepath)!=1) { mkdir($filepath,02770); @@ -3868,19 +5560,19 @@ sub publishlogo { if ($file=~/\.(\w+)$/ && (&Apache::loncommon::fileembstyle($1) eq 'hdn')) { $output = - &mt('Invalid file extension ([_1]) - reserved for LONCAPA use.',$1); + &mt('Invalid file extension ([_1]) - reserved for internal use.',$1); } elsif ($file=~/\.(\w+)$/ && !defined(&Apache::loncommon::fileembstyle($1))) { $output = &mt('Unrecognized file extension ([_1]) - rename the file with a proper extension and re-upload.',$1); } elsif ($file=~/\.(\d+)\.(\w+)$/) { - $output = &mt('File name not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2); + $output = &mt('Filename not allowed - rename the file to remove the number immediately before the file extension([_1]) and re-upload.',$2); } elsif (-d "$filepath/$file") { - $output = &mt('File name is a directory name - rename the file and re-upload'); + $output = &mt('Filename is a directory name - rename the file and re-upload'); } else { my $source = $filepath.'/'.$file; my $logfile; if (!open($logfile,">>$source".'.log')) { - return (&mt('No write permission to Construction Space')); + return (&mt('No write permission to Authoring Space')); } print $logfile "\n================= Publish ".localtime()." ================\n". @@ -3905,7 +5597,6 @@ $env{'user.name'}.':'.$env{'user.domain' close(FH); chmod(0660, $source); # Permissions to rw-rw---. - my $docroot=$r->dir_config('lonDocRoot'); my $targetdir=$docroot.'/res/'.$dom.'/'.$confname .'/'.$fnamepath; my $copyfile=$targetdir.'/'.$file; @@ -3928,8 +5619,15 @@ $env{'user.name'}.':'.$env{'user.domain' if (copy($source,$copyfile)) { print $logfile "\nCopied original source to ".$copyfile."\n"; $output = 'ok'; - &write_metadata($dom,$confname,$formname,$targetdir,$file,$logfile); $logourl = '/res/'.$dom.'/'.$confname.'/'.$fname; + push(@{$modified_urls},[$copyfile,$source]); + my $metaoutput = + &write_metadata($dom,$confname,$formname,$targetdir,$file,$logfile); + unless ($registered_cleanup) { + my $handlers = $r->get_handlers('PerlCleanupHandler'); + $r->set_handlers('PerlCleanupHandler' => [\¬ifysubscribed,@{$handlers}]); + $registered_cleanup=1; + } } else { print $logfile "\nUnable to write ".$copyfile.':'.$!."\n"; $output = &mt('Failed to copy file to RES space').", $!"; @@ -3947,8 +5645,15 @@ $env{'user.name'}.':'.$env{'user.domain' my $copyfile=$targetdir.'/tn-'.$file; if (copy($outfile,$copyfile)) { print $logfile "\nCopied source to ".$copyfile."\n"; - &write_metadata($dom,$confname,$formname, - $targetdir,'tn-'.$file,$logfile); + my $thumb_metaoutput = + &write_metadata($dom,$confname,$formname, + $targetdir,'tn-'.$file,$logfile); + push(@{$modified_urls},[$copyfile,$outfile]); + unless ($registered_cleanup) { + my $handlers = $r->get_handlers('PerlCleanupHandler'); + $r->set_handlers('PerlCleanupHandler' => [\¬ifysubscribed,@{$handlers}]); + $registered_cleanup=1; + } } else { print $logfile "\nUnable to write ".$copyfile. ':'.$!."\n"; @@ -4013,30 +5718,79 @@ sub write_metadata { { print $logfile "\nWrite metadata file for ".$targetdir.'/'.$file; my $mfh; - unless (open($mfh,'>'.$targetdir.'/'.$file.'.meta')) { + if (open($mfh,'>'.$targetdir.'/'.$file.'.meta')) { + foreach (sort(keys(%metadatafields))) { + unless ($_=~/\./) { + my $unikey=$_; + $unikey=~/^([A-Za-z]+)/; + my $tag=$1; + $tag=~tr/A-Z/a-z/; + print $mfh "\n\<$tag"; + foreach (split(/\,/,$metadatakeys{$unikey})) { + my $value=$metadatafields{$unikey.'.'.$_}; + $value=~s/\"/\'\'/g; + print $mfh ' '.$_.'="'.$value.'"'; + } + print $mfh '>'. + &HTML::Entities::encode($metadatafields{$unikey},'<>&"') + .''; + } + } + $output = 'ok'; + print $logfile "\nWrote metadata"; + close($mfh); + } else { + print $logfile "\nFailed to open metadata file"; $output = &mt('Could not write metadata'); } - foreach (sort keys %metadatafields) { - unless ($_=~/\./) { - my $unikey=$_; - $unikey=~/^([A-Za-z]+)/; - my $tag=$1; - $tag=~tr/A-Z/a-z/; - print $mfh "\n\<$tag"; - foreach (split(/\,/,$metadatakeys{$unikey})) { - my $value=$metadatafields{$unikey.'.'.$_}; - $value=~s/\"/\'\'/g; - print $mfh ' '.$_.'="'.$value.'"'; - } - print $mfh '>'. - &HTML::Entities::encode($metadatafields{$unikey},'<>&"') - .''; - } - } - $output = 'ok'; - print $logfile "\nWrote metadata"; - close($mfh); } + return $output; +} + +sub notifysubscribed { + foreach my $targetsource (@{$modified_urls}){ + next unless (ref($targetsource) eq 'ARRAY'); + my ($target,$source)=@{$targetsource}; + if ($source ne '') { + if (open(my $logfh,'>>'.$source.'.log')) { + print $logfh "\nCleanup phase: Notifications\n"; + my @subscribed=&subscribed_hosts($target); + foreach my $subhost (@subscribed) { + print $logfh "\nNotifying host ".$subhost.':'; + my $reply=&Apache::lonnet::critical('update:'.$target,$subhost); + print $logfh $reply; + } + my @subscribedmeta=&subscribed_hosts("$target.meta"); + foreach my $subhost (@subscribedmeta) { + print $logfh "\nNotifying host for metadata only ".$subhost.':'; + my $reply=&Apache::lonnet::critical('update:'.$target.'.meta', + $subhost); + print $logfh $reply; + } + print $logfh "\n============ Done ============\n"; + close($logfh); + } + } + } + return OK; +} + +sub subscribed_hosts { + my ($target) = @_; + my @subscribed; + if (open(my $fh,"<$target.subscription")) { + while (my $subline=<$fh>) { + if ($subline =~ /^($match_lonid):/) { + my $host = $1; + if ($host ne $Apache::lonnet::perlvar{'lonHostID'}) { + unless (grep(/^\Q$host\E$/,@subscribed)) { + push(@subscribed,$host); + } + } + } + } + } + return @subscribed; } sub check_switchserver { @@ -4049,7 +5803,7 @@ sub check_switchserver { 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; } @@ -4060,7 +5814,7 @@ sub modify_quotas { %limithash,$toolregexp,%conditions,$resulttext,%changes); if ($action eq 'quotas') { $context = 'tools'; - } else { + } else { $context = $action; } if ($context eq 'requestcourses') { @@ -4070,8 +5824,11 @@ sub modify_quotas { %titles = &courserequest_titles(); $toolregexp = join('|',@usertools); %conditions = &courserequest_conditions(); + } elsif ($context eq 'requestauthor') { + @usertools = ('author'); + %titles = &authorrequest_titles(); } else { - @usertools = ('aboutme','blog','portfolio'); + @usertools = ('aboutme','blog','webdav','portfolio'); %titles = &tool_titles(); } my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); @@ -4087,16 +5844,21 @@ sub modify_quotas { $confhash{$item}{$type} = $env{$key}; } } + } elsif ($context eq 'requestauthor') { + if ($key =~ /^\Qform.authorreq_\E(.+)$/) { + $confhash{$1} = $env{$key}; + } } else { if ($key =~ /^form\.quota_(.+)$/) { $confhash{'defaultquota'}{$1} = $env{$key}; - } - if ($key =~ /^form\.\Q$context\E_(.+)$/) { + } elsif ($key =~ /^form\.authorquota_(.+)$/) { + $confhash{'authorquota'}{$1} = $env{$key}; + } elsif ($key =~ /^form\.\Q$context\E_(.+)$/) { @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key); } } } - if ($context eq 'requestcourses') { + if (($context eq 'requestcourses') || ($context eq 'requestauthor')) { my @approvalnotify = &Apache::loncommon::get_env_multiple('form.reqapprovalnotify'); @approvalnotify = sort(@approvalnotify); $confhash{'notify'}{'approval'} = join(',',@approvalnotify); @@ -4106,17 +5868,18 @@ sub modify_quotas { $changes{'notify'}{'approval'} = 1; } } else { - if ($domconfig{$action}{'notify'}{'approval'}) { + if ($confhash{'notify'}{'approval'}) { $changes{'notify'}{'approval'} = 1; } } } else { - if ($domconfig{$action}{'notify'}{'approval'}) { + if ($confhash{'notify'}{'approval'}) { $changes{'notify'}{'approval'} = 1; } } } else { $confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'}; + $confhash{'authorquota'}{'default'} = $env{'form.authorquota'}; } foreach my $item (@usertools) { foreach my $type (@{$types},'default','_LC_adv') { @@ -4132,6 +5895,11 @@ sub modify_quotas { $confhash{$item}{$type} .= $limithash{$item}{$type}; } } + } elsif ($context eq 'requestauthor') { + $unset = '0'; + if ($type eq '_LC_adv') { + $unset = ''; + } } else { if (grep(/^\Q$type\E$/,@{$toolshash{$item}})) { $confhash{$item}{$type} = 1; @@ -4140,7 +5908,11 @@ sub modify_quotas { } } if (ref($domconfig{$action}) eq 'HASH') { - if (ref($domconfig{$action}{$item}) eq 'HASH') { + if ($action eq 'requestauthor') { + if ($domconfig{$action}{$type} ne $confhash{$type}) { + $changes{$type} = 1; + } + } elsif (ref($domconfig{$action}{$item}) eq 'HASH') { if ($domconfig{$action}{$item}{$type} ne $confhash{$item}{$type}) { $changes{$item}{$type} = 1; } @@ -4160,6 +5932,10 @@ sub modify_quotas { if ($confhash{$item}{$type} ne $unset) { $changes{$item}{$type} = 1; } + } elsif ($context eq 'requestauthor') { + if ($confhash{$type} ne $unset) { + $changes{$type} = 1; + } } else { if (!$confhash{$item}{$type}) { $changes{$item}{$type} = 1; @@ -4168,7 +5944,7 @@ sub modify_quotas { } } } - unless ($context eq 'requestcourses') { + unless (($context eq 'requestcourses') || ($context eq 'requestauthor')) { if (ref($domconfig{'quotas'}) eq 'HASH') { if (ref($domconfig{'quotas'}{'defaultquota'}) eq 'HASH') { foreach my $key (keys(%{$domconfig{'quotas'}{'defaultquota'}})) { @@ -4191,6 +5967,17 @@ 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}; + } + } + } } if (ref($confhash{'defaultquota'}) eq 'HASH') { foreach my $key (keys(%{$confhash{'defaultquota'}})) { @@ -4209,12 +5996,31 @@ 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; + } + } + } } - foreach my $key (keys(%confhash)) { - $domdefaults{$key} = $confhash{$key}; + if ($context eq 'requestauthor') { + $domdefaults{'requestauthor'} = \%confhash; + } else { + foreach my $key (keys(%confhash)) { + $domdefaults{$key} = $confhash{$key}; + } } - + my %quotahash = ( $action => { %confhash } ); @@ -4226,7 +6032,8 @@ sub modify_quotas { &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); $resulttext = &mt('Changes made:').'
      '; - unless ($context eq 'requestcourses') { + unless (($context eq 'requestcourses') || + ($context eq 'requestauthor')) { if (ref($changes{'defaultquota'}) eq 'HASH') { $resulttext .= '
    • '.&mt('Portfolio default quotas').'
        '; foreach my $type (@{$types},'default') { @@ -4240,15 +6047,41 @@ 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) { - if (ref($changes{$item}) eq 'HASH') { + my (%haschgs,%inconf); + if ($context eq 'requestauthor') { + %haschgs = %changes; + %inconf = %confhash; + } else { + if (ref($changes{$item}) eq 'HASH') { + %haschgs = %{$changes{$item}}; + } + if (ref($confhash{$item}) eq 'HASH') { + %inconf = %{$confhash{$item}}; + } + } + if (keys(%haschgs) > 0) { my $newacc = &Apache::lonnet::usertools_access($env{'user.name'}, $env{'user.domain'}, $item,'reload',$context); - if ($context eq 'requestcourses') { + if (($context eq 'requestcourses') || + ($context eq 'requestauthor')) { if ($env{'environment.canrequest.'.$item} ne $newacc) { $newenv{'environment.canrequest.'.$item} = $newacc; } @@ -4257,34 +6090,40 @@ sub modify_quotas { $newenv{'environment.availabletools.'.$item} = $newacc; } } - $resulttext .= '
    • '.$titles{$item}.'
        '; + unless ($context eq 'requestauthor') { + $resulttext .= '
      • '.$titles{$item}.'
          '; + } foreach my $type (@{$types},'default','_LC_adv') { - if ($changes{$item}{$type}) { + if ($haschgs{$type}) { my $typetitle = $usertypes->{$type}; if ($type eq 'default') { $typetitle = $othertitle; } elsif ($type eq '_LC_adv') { $typetitle = 'LON-CAPA Advanced Users'; } - if ($confhash{$item}{$type}) { + if ($inconf{$type}) { if ($context eq 'requestcourses') { my $cond; - if ($confhash{$item}{$type} =~ /^autolimit=(\d*)$/) { + if ($inconf{$type} =~ /^autolimit=(\d*)$/) { if ($1 eq '') { $cond = &mt('(Automatic processing of any request).'); } else { $cond = &mt('(Automatic processing of requests up to limit of [quant,_1,request] per user).',$1); } } else { - $cond = $conditions{$confhash{$item}{$type}}; + $cond = $conditions{$inconf{$type}}; } $resulttext .= '
        • '.&mt('Set to be available to [_1].',$typetitle).' '.$cond.'
        • '; + } elsif ($context eq 'requestauthor') { + $resulttext .= '
        • '.&mt('Set to "[_1]" for "[_2]".', + $titles{$inconf{$type}},$typetitle); + } else { $resulttext .= '
        • '.&mt('Set to be available to [_1]',$typetitle).'
        • '; } } else { if ($type eq '_LC_adv') { - if ($confhash{$item}{$type} eq '0') { + if ($inconf{$type} eq '0') { $resulttext .= '
        • '.&mt('Set to be unavailable to [_1]',$typetitle).'
        • '; } else { $resulttext .= '
        • '.&mt('No override set for [_1]',$typetitle).'
        • '; @@ -4295,17 +6134,19 @@ sub modify_quotas { } } } - $resulttext .= '
      • '; + unless ($context eq 'requestauthor') { + $resulttext .= '
    • '; + } } } - if ($action eq 'requestcourses') { + if (($action eq 'requestcourses') || ($action eq 'requestauthor')) { if (ref($changes{'notify'}) eq 'HASH') { if ($changes{'notify'}{'approval'}) { if (ref($confhash{'notify'}) eq 'HASH') { if ($confhash{'notify'}{'approval'}) { $resulttext .= '
    • '.&mt('Notification of requests requiring approval will be sent to: ').$confhash{'notify'}{'approval'}.'
    • '; } else { - $resulttext .= '
    • '.&mt('No Domain Coordinators will receive notification of course requests requiring approval.').'
    • '; + $resulttext .= '
    • '.&mt('No Domain Coordinators will receive notification of requests requiring approval.').'
    • '; } } } @@ -4318,6 +6159,8 @@ sub modify_quotas { } else { if ($context eq 'requestcourses') { $resulttext = &mt('No changes made to rights to request creation of courses.'); + } elsif ($context eq 'requestauthor') { + $resulttext = &mt('No changes made to rights to request author space.'); } else { $resulttext = &mt('No changes made to availability of personal information pages, blogs, portfolios or default quotas'); } @@ -4330,7 +6173,7 @@ sub modify_quotas { } sub modify_autoenroll { - my ($dom,%domconfig) = @_; + my ($dom,$lastactref,%domconfig) = @_; my ($resulttext,%changes); my %currautoenroll; if (ref($domconfig{'autoenroll'}) eq 'HASH') { @@ -4340,7 +6183,8 @@ sub modify_autoenroll { } my $autorun = &Apache::lonnet::auto_run(undef,$dom), my %title = ( run => 'Auto-enrollment active', - sender => 'Sender for notification messages'); + sender => 'Sender for notification messages', + coowners => 'Automatic assignment of co-ownership to instructors of record (institutional data)'); my @offon = ('off','on'); my $sender_uname = $env{'form.sender_uname'}; my $sender_domain = $env{'form.sender_domain'}; @@ -4349,11 +6193,12 @@ sub modify_autoenroll { } elsif ($sender_uname eq '') { $sender_domain = ''; } + my $coowners = $env{'form.autoassign_coowners'}; my %autoenrollhash = ( - autoenroll => { run => $env{'form.autoenroll_run'}, - sender_uname => $sender_uname, - sender_domain => $sender_domain, - + autoenroll => { 'run' => $env{'form.autoenroll_run'}, + 'sender_uname' => $sender_uname, + 'sender_domain' => $sender_domain, + 'co-owners' => $coowners, } ); my $putresult = &Apache::lonnet::put_dom('configuration',\%autoenrollhash, @@ -4374,6 +6219,13 @@ sub modify_autoenroll { if ($currautoenroll{'sender_domain'} ne $sender_domain) { $changes{'sender'} = 1; } + if ($currautoenroll{'co-owners'} ne '') { + if ($currautoenroll{'co-owners'} ne $coowners) { + $changes{'coowners'} = 1; + } + } elsif ($coowners) { + $changes{'coowners'} = 1; + } if (keys(%changes) > 0) { $resulttext = &mt('Changes made:').'
        '; if ($changes{'run'}) { @@ -4386,6 +6238,11 @@ sub modify_autoenroll { $resulttext .= '
      • '.&mt("$title{'sender'} set to [_1]",$sender_uname.':'.$sender_domain).'
      • '; } } + if ($changes{'coowners'}) { + $resulttext .= '
      • '.&mt("$title{'coowners'} set to $offon[$env{'form.autoassign_coowners'}]").'
      • '; + &Apache::loncommon::devalidate_domconfig_cache($dom); + $$lastactref = 'update'; + } $resulttext .= '
      '; } else { $resulttext = &mt('No changes made to auto-enrollment settings'); @@ -4417,21 +6274,43 @@ sub modify_autoupdate { lastname => 'Last Name', firstname => 'First Name', middlename => 'Middle Name', - gen => 'Generation', + generation => 'Generation', ); - my $othertitle = &mt('All users'); + $othertitle = &mt('All users'); if (keys(%{$usertypes}) > 0) { $othertitle = &mt('Other users'); } foreach my $key (keys(%env)) { if ($key =~ /^form\.updateable_(.+)_([^_]+)$/) { - push(@{$fields{$1}},$2); + my ($usertype,$item) = ($1,$2); + if (grep(/^\Q$item\E$/,keys(%fieldtitles))) { + if ($usertype eq 'default') { + push(@{$fields{$1}},$2); + } elsif (ref($types) eq 'ARRAY') { + if (grep(/^\Q$usertype\E$/,@{$types})) { + push(@{$fields{$1}},$2); + } + } + } + } + } + my @lockablenames = &Apache::loncommon::get_env_multiple('form.lockablenames'); + @lockablenames = sort(@lockablenames); + if (ref($currautoupdate{'lockablenames'}) eq 'ARRAY') { + my @changed = &Apache::loncommon::compare_arrays($currautoupdate{'lockablenames'},\@lockablenames); + if (@changed) { + $changes{'lockablenames'} = 1; + } + } else { + if (@lockablenames) { + $changes{'lockablenames'} = 1; } } my %updatehash = ( autoupdate => { run => $env{'form.autoupdate_run'}, classlists => $env{'form.classlists'}, fields => {%fields}, + lockablenames => \@lockablenames, } ); foreach my $key (keys(%currautoupdate)) { @@ -4449,9 +6328,11 @@ sub modify_autoupdate { foreach my $type (@{$currautoupdate{$key}{$item}}) { if (!exists($fields{$item})) { $change = 1; + last; } elsif (ref($fields{$item}) eq 'ARRAY') { if (!grep(/^\Q$type\E$/,@{$fields{$item}})) { $change = 1; + last; } } } @@ -4461,12 +6342,41 @@ sub modify_autoupdate { } } } + } elsif ($key eq 'lockablenames') { + if (ref($currautoupdate{$key}) eq 'ARRAY') { + my @changed = &Apache::loncommon::compare_arrays($currautoupdate{'lockablenames'},\@lockablenames); + if (@changed) { + $changes{'lockablenames'} = 1; + } + } else { + if (@lockablenames) { + $changes{'lockablenames'} = 1; + } + } + } + } + unless (grep(/^\Qlockablenames\E$/,keys(%currautoupdate))) { + if (@lockablenames) { + $changes{'lockablenames'} = 1; } } foreach my $item (@{$types},'default') { if (defined($fields{$item})) { if (ref($currautoupdate{'fields'}) eq 'HASH') { - if (!exists($currautoupdate{'fields'}{$item})) { + if (ref($currautoupdate{'fields'}{$item}) eq 'ARRAY') { + my $change = 0; + if (ref($fields{$item}) eq 'ARRAY') { + foreach my $type (@{$fields{$item}}) { + if (!grep(/^\Q$type\E$/,@{$currautoupdate{'fields'}{$item}})) { + $change = 1; + last; + } + } + } + if ($change) { + push(@{$changes{'fields'}},$item); + } + } else { push(@{$changes{'fields'}},$item); } } else { @@ -4480,7 +6390,17 @@ sub modify_autoupdate { if (keys(%changes) > 0) { $resulttext = &mt('Changes made:').'
        '; foreach my $key (sort(keys(%changes))) { - if (ref($changes{$key}) eq 'ARRAY') { + if ($key eq 'lockablenames') { + $resulttext .= '
      • '; + if (@lockablenames) { + $usertypes->{'default'} = $othertitle; + $resulttext .= &mt("User preference to disable replacement of user's name with institutional data (by auto-update), available for the following affiliations:").' '. + join(', ', map { $usertypes->{$_}; } @lockablenames).'
      • '; + } else { + $resulttext .= &mt("User preference to disable replacement of user's name with institutional data (by auto-update) is unavailable."); + } + $resulttext .= ''; + } elsif (ref($changes{$key}) eq 'ARRAY') { foreach my $item (@{$changes{$key}}) { my @newvalues; foreach my $type (@{$fields{$item}}) { @@ -4519,6 +6439,81 @@ sub modify_autoupdate { return $resulttext; } +sub modify_autocreate { + my ($dom,%domconfig) = @_; + my ($resulttext,%changes,%currautocreate,%newvals,%autocreatehash); + if (ref($domconfig{'autocreate'}) eq 'HASH') { + foreach my $key (keys(%{$domconfig{'autocreate'}})) { + $currautocreate{$key} = $domconfig{'autocreate'}{$key}; + } + } + my %title= ( xml => 'Auto-creation of courses in XML course description files', + req => 'Auto-creation of validated requests for official courses', + xmldc => 'Identity of course creator of courses from XML files', + ); + my @types = ('xml','req'); + foreach my $item (@types) { + $newvals{$item} = $env{'form.autocreate_'.$item}; + $newvals{$item} =~ s/\D//g; + $newvals{$item} = 0 if ($newvals{$item} eq ''); + } + $newvals{'xmldc'} = $env{'form.autocreate_xmldc'}; + my %domcoords = &get_active_dcs($dom); + unless (exists($domcoords{$newvals{'xmldc'}})) { + $newvals{'xmldc'} = ''; + } + %autocreatehash = ( + autocreate => { xml => $newvals{'xml'}, + req => $newvals{'req'}, + } + ); + if ($newvals{'xmldc'} ne '') { + $autocreatehash{'autocreate'}{'xmldc'} = $newvals{'xmldc'}; + } + my $putresult = &Apache::lonnet::put_dom('configuration',\%autocreatehash, + $dom); + if ($putresult eq 'ok') { + my @items = @types; + if ($newvals{'xml'}) { + push(@items,'xmldc'); + } + foreach my $item (@items) { + if (exists($currautocreate{$item})) { + if ($currautocreate{$item} ne $newvals{$item}) { + $changes{$item} = 1; + } + } elsif ($newvals{$item}) { + $changes{$item} = 1; + } + } + if (keys(%changes) > 0) { + my @offon = ('off','on'); + $resulttext = &mt('Changes made:').'
          '; + foreach my $item (@types) { + if ($changes{$item}) { + my $newtxt = $offon[$newvals{$item}]; + $resulttext .= '
        • '. + &mt("$title{$item} set to [_1]$newtxt [_2]", + '',''). + '
        • '; + } + } + if ($changes{'xmldc'}) { + my ($dcname,$dcdom) = split(':',$newvals{'xmldc'}); + my $newtxt = &Apache::loncommon::plainname($dcname,$dcdom); + $resulttext .= '
        • '.&mt("$title{'xmldc'} set to [_1]",''.$newtxt.'').'
        • '; + } + $resulttext .= '
        '; + } else { + $resulttext = &mt('No changes made to auto-creation settings'); + } + } else { + $resulttext = ''. + &mt('An error occurred: [_1]',$putresult).''; + } + return $resulttext; +} + sub modify_directorysrch { my ($dom,%domconfig) = @_; my ($resulttext,%changes); @@ -4652,7 +6647,11 @@ sub modify_directorysrch { } else { $chgtext =~ s/\; $//; } - $resulttext .= '
      • '.&mt("Users from domain '[_1]' permitted to search the institutional directory set to: [_2]",$dom,$chgtext).'
      • '; + $resulttext .= + '
      • '. + &mt("Users from domain '[_1]' permitted to search the institutional directory set to: [_2]", + ''.$dom.'',$chgtext). + '
      • '; } } } @@ -4680,7 +6679,7 @@ sub modify_directorysrch { } } $chgtext =~ s/\; $//; - $resulttext .= '
      • '.&mt("$title{'searchtypes'} set to: \"[_1]\"",$chgtext).'
      • '; + $resulttext .= '
      • '.&mt($title{'searchtypes'}.' set to: "[_1]"',$chgtext).'
      • '; } $resulttext .= '
      '; } else { @@ -4694,17 +6693,18 @@ sub modify_directorysrch { } sub modify_contacts { - my ($dom,%domconfig) = @_; + my ($dom,$lastactref,%domconfig) = @_; my ($resulttext,%currsetting,%newsetting,%changes,%contacts_hash); if (ref($domconfig{'contacts'}) eq 'HASH') { foreach my $key (keys(%{$domconfig{'contacts'}})) { $currsetting{$key} = $domconfig{'contacts'}{$key}; } } - my (%others,%to); + my (%others,%to,%bcc); my @contacts = ('supportemail','adminemail'); my @mailings = ('errormail','packagesmail','helpdeskmail','lonstatusmail', - 'requestsmail'); + 'requestsmail','updatesmail','idconflictsmail'); + my @toggles = ('reporterrors','reportupdates'); foreach my $type (@mailings) { @{$newsetting{$type}} = &Apache::loncommon::get_env_multiple('form.'.$type); @@ -4717,11 +6717,20 @@ sub modify_contacts { } $others{$type} = $env{'form.'.$type.'_others'}; $contacts_hash{contacts}{$type}{'others'} = $others{$type}; + if ($type eq 'helpdeskmail') { + $bcc{$type} = $env{'form.'.$type.'_bcc'}; + $contacts_hash{contacts}{$type}{'bcc'} = $bcc{$type}; + } } foreach my $item (@contacts) { $to{$item} = $env{'form.'.$item}; $contacts_hash{'contacts'}{$item} = $to{$item}; } + foreach my $item (@toggles) { + if ($env{'form.'.$item} =~ /^(0|1)$/) { + $contacts_hash{'contacts'}{$item} = $env{'form.'.$item}; + } + } if (keys(%currsetting) > 0) { foreach my $item (@contacts) { if ($to{$item} ne $currsetting{$item}) { @@ -4741,6 +6750,11 @@ sub modify_contacts { if ($others{$type} ne $currsetting{$type}{'others'}) { push(@{$changes{$type}},'others'); } + if ($type eq 'helpdeskmail') { + if ($bcc{$type} ne $currsetting{$type}{'bcc'}) { + push(@{$changes{$type}},'bcc'); + } + } } } else { my %default; @@ -4751,10 +6765,11 @@ sub modify_contacts { $default{'helpdeskmail'} = 'supportemail'; $default{'lonstatusmail'} = 'adminemail'; $default{'requestsmail'} = 'adminemail'; + $default{'updatesmail'} = 'adminemail'; foreach my $item (@contacts) { if ($to{$item} ne $default{$item}) { $changes{$item} = 1; - } + } } foreach my $type (@mailings) { if ((@{$newsetting{$type}} != 1) || ($newsetting{$type}[0] ne $default{$type})) { @@ -4763,13 +6778,28 @@ sub modify_contacts { } if ($others{$type} ne '') { push(@{$changes{$type}},'others'); - } + } + if ($type eq 'helpdeskmail') { + if ($bcc{$type} ne '') { + push(@{$changes{$type}},'bcc'); + } + } + } + } + foreach my $item (@toggles) { + if (($env{'form.'.$item} == 1) && ($currsetting{$item} == 0)) { + $changes{$item} = 1; + } elsif ((!$env{'form.'.$item}) && + (($currsetting{$item} eq '') || ($currsetting{$item} == 1))) { + $changes{$item} = 1; } } my $putresult = &Apache::lonnet::put_dom('configuration',\%contacts_hash, $dom); if ($putresult eq 'ok') { if (keys(%changes) > 0) { + &Apache::loncommon::devalidate_domconfig_cache($dom); + $$lastactref = 'update'; my ($titles,$short_titles) = &contact_titles(); $resulttext = &mt('Changes made:').'
        '; foreach my $item (@contacts) { @@ -4791,8 +6821,31 @@ sub modify_contacts { push(@text,$others{$type}); } $resulttext .= ''. - join(', ',@text).''; - } + join(', ',@text).''; + if ($type eq 'helpdeskmail') { + if ($bcc{$type} ne '') { + $resulttext .= ' '.&mt('with Bcc to').': '.$bcc{$type}.''; + } + } + $resulttext .= ''; + } + } + my @offon = ('off','on'); + if ($changes{'reporterrors'}) { + $resulttext .= '
      • '. + &mt('E-mail error reports to [_1] set to "'. + $offon[$env{'form.reporterrors'}].'".', + &Apache::loncommon::modal_link('http://loncapa.org/core.html', + &mt('LON-CAPA core group - MSU'),600,500)). + '
      • '; + } + if ($changes{'reportupdates'}) { + $resulttext .= '
      • '. + &mt('E-mail record of completed LON-CAPA updates to [_1] set to "'. + $offon[$env{'form.reportupdates'}].'".', + &Apache::loncommon::modal_link('http://loncapa.org/core.html', + &mt('LON-CAPA core group - MSU'),600,500)). + '
      • '; } $resulttext .= '
      '; } else { @@ -4844,6 +6897,7 @@ sub modify_usercreation { } push(@contexts,'statustocreate'); } + &process_captcha('cancreate',\%changes,\%cancreate,\%curr_usercreation); if (ref($curr_usercreation{'cancreate'}) eq 'HASH') { foreach my $item (@contexts) { if (($item eq 'selfcreate') || ($item eq 'statustocreate')) { @@ -5026,7 +7080,7 @@ sub modify_usercreation { my %lt = &usercreation_types(); foreach my $type (@{$changes{'cancreate'}}) { my $chgtext; - unless ($type eq 'statustocreate') { + unless (($type eq 'statustocreate') || ($type eq 'captcha') || ($type eq 'recaptchakeys')) { $chgtext = $lt{$type}.', '; } if ($type eq 'selfcreate') { @@ -5085,6 +7139,35 @@ sub modify_usercreation { } } } + } elsif ($type eq 'captcha') { + if ($cancreate{$type} eq 'notused') { + $chgtext .= &mt('No CAPTCHA validation in use for self-creation screen.'); + } else { + my %captchas = &captcha_phrases(); + if ($captchas{$cancreate{$type}}) { + $chgtext .= &mt("Validation for self-creation screen set to $captchas{$cancreate{$type}}."); + } else { + $chgtext .= &mt('Validation for self-creation screen set to unknown type.'); + } + } + } elsif ($type eq 'recaptchakeys') { + my ($privkey,$pubkey); + if (ref($cancreate{$type}) eq 'HASH') { + $pubkey = $cancreate{$type}{'public'}; + $privkey = $cancreate{$type}{'private'}; + } + $chgtext .= &mt('ReCAPTCHA keys changes').'
        '; + if (!$pubkey) { + $chgtext .= '
      • '.&mt('Public key deleted').'
      • '; + } else { + $chgtext .= '
      • '.&mt('Public key set to [_1]',$pubkey).'
      • '; + } + if (!$privkey) { + $chgtext .= '
      • '.&mt('Private key deleted').'
      • '; + } else { + $chgtext .= '
      • '.&mt('Private key set to [_1]',$pubkey).'
      • '; + } + $chgtext .= '
      '; } else { if ($cancreate{$type} eq 'none') { $chgtext .= &mt('creation of new users is not permitted, except by a Domain Coordinator.'); @@ -5184,6 +7267,59 @@ sub modify_usercreation { return $resulttext; } +sub process_captcha { + my ($container,$changes,$newsettings,$current) = @_; + return unless ((ref($changes) eq 'HASH') && (ref($newsettings) eq 'HASH') || (ref($current) eq 'HASH')); + $newsettings->{'captcha'} = $env{'form.'.$container.'_captcha'}; + unless ($newsettings->{'captcha'} eq 'recaptcha' || $newsettings->{'captcha'} eq 'notused') { + $newsettings->{'captcha'} = 'original'; + } + if ($current->{'captcha'} ne $newsettings->{'captcha'}) { + if ($container eq 'cancreate') { + if (ref($changes->{'cancreate'}) eq 'ARRAY') { + push(@{$changes->{'cancreate'}},'captcha'); + } elsif (!defined($changes->{'cancreate'})) { + $changes->{'cancreate'} = ['captcha']; + } + } else { + $changes->{'captcha'} = 1; + } + } + my ($newpub,$newpriv,$currpub,$currpriv); + if ($newsettings->{'captcha'} eq 'recaptcha') { + $newpub = $env{'form.'.$container.'_recaptchapub'}; + $newpriv = $env{'form.'.$container.'_recaptchapriv'}; + $newpub =~ s/\W//g; + $newpriv =~ s/\W//g; + $newsettings->{'recaptchakeys'} = { + public => $newpub, + private => $newpriv, + }; + } + if (ref($current->{'recaptchakeys'}) eq 'HASH') { + $currpub = $current->{'recaptchakeys'}{'public'}; + $currpriv = $current->{'recaptchakeys'}{'private'}; + unless ($newsettings->{'captcha'} eq 'recaptcha') { + $newsettings->{'recaptchakeys'} = { + public => '', + private => '', + } + } + } + if (($newpub ne $currpub) || ($newpriv ne $currpriv)) { + if ($container eq 'cancreate') { + if (ref($changes->{'cancreate'}) eq 'ARRAY') { + push(@{$changes->{'cancreate'}},'recaptchakeys'); + } elsif (!defined($changes->{'cancreate'})) { + $changes->{'cancreate'} = ['recaptchakeys']; + } + } else { + $changes->{'recaptchakeys'} = 1; + } + } + return; +} + sub modify_usermodification { my ($dom,%domconfig) = @_; my ($resulttext,%curr_usermodification,%changes); @@ -5273,7 +7409,7 @@ sub modify_usermodification { } my @modifiable; if ($context eq 'selfcreate') { - $resulttext .= '
    • '.&mt('Self-creation of account by users with status: [_1] ',$rolename).' - '.&mt('modifiable fields (if institutional data blank): '); + $resulttext .= '
    • '.&mt('Self-creation of account by users with status: [_1]',$rolename).' - '.&mt('modifiable fields (if institutional data blank): '); } else { $resulttext .= '
    • '.&mt('Target user with [_1] role',$rolename).' - '.&mt('modifiable fields: '); } @@ -5305,10 +7441,10 @@ sub modify_usermodification { } sub modify_defaults { - my ($dom,$r) = @_; + my ($dom,$r,%domconfig) = @_; my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors); my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); - my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def'); + my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def','portal_def'); my @authtypes = ('internal','krb4','krb5','localauth'); foreach my $item (@items) { $newvalues{$item} = $env{'form.'.$item}; @@ -5344,6 +7480,12 @@ sub modify_defaults { push(@errors,$item); } } + } elsif ($item eq 'portal_def') { + if ($newvalues{$item} ne '') { + unless ($newvalues{$item} =~ /^https?\:\/\/(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])\/?$/) { + push(@errors,$item); + } + } } if (grep(/^\Q$item\E$/,@errors)) { $newvalues{$item} = $domdefaults{$item}; @@ -5385,8 +7527,17 @@ sub modify_defaults { my $cachetime = 24*60*60; &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); if ($changes{'auth_def'} || $changes{'auth_arg_def'} || $changes{'lang_def'} || $changes{'datelocale_def'}) { - my $sysmail = $r->dir_config('lonSysEMail'); - &Apache::lonmsg::sendemail($sysmail,"LON-CAPA Domain Settings Change - $dom",$mailmsgtext); + my $notify = 1; + if (ref($domconfig{'contacts'}) eq 'HASH') { + if ($domconfig{'contacts'}{'reportupdates'} == 0) { + $notify = 0; + } + } + if ($notify) { + &Apache::lonmsg::sendemail('installrecord@loncapa.org', + "LON-CAPA Domain Settings Change - $dom", + $mailmsgtext); + } } } else { $resulttext = &mt('No changes made to default authentication/language/timezone settings'); @@ -5406,7 +7557,7 @@ sub modify_defaults { } sub modify_scantron { - my ($r,$dom,$confname,%domconfig) = @_; + my ($r,$dom,$confname,$lastactref,%domconfig) = @_; my ($resulttext,%confhash,%changes,$errors); my $custom = 'custom.tab'; my $default = 'default.tab'; @@ -5417,7 +7568,7 @@ sub modify_scantron { my $error; if ($configuserok eq 'ok') { if ($switchserver) { - $error = &mt("Upload of scantron format file is not permitted to this server: [_1]",$switchserver); + $error = &mt("Upload of bubblesheet format file is not permitted to this server: [_1]",$switchserver); } else { if ($author_ok eq 'ok') { my ($result,$scantronurl) = @@ -5457,25 +7608,26 @@ sub modify_scantron { if (ref($confhash{'scantron'}) eq 'HASH') { $resulttext = &mt('Changes made:').'
        '; if ($confhash{'scantron'}{'scantronformat'} eq '') { - $resulttext .= '
      • '.&mt('[_1] scantron format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'
      • '; + $resulttext .= '
      • '.&mt('[_1] bubblesheet format file removed; [_2] file will be used for courses in this domain.',$custom,$default).'
      • '; } else { - $resulttext .= '
      • '.&mt('Custom scantron format file ([_1]) uploaded for use with courses in this domain.',$custom).'
      • '; + $resulttext .= '
      • '.&mt('Custom bubblesheet format file ([_1]) uploaded for use with courses in this domain.',$custom).'
      • '; } $resulttext .= '
      '; } else { - $resulttext = &mt('Changes made to scantron format file.'); + $resulttext = &mt('Changes made to bubblesheet format file.'); } $resulttext .= '
    '; &Apache::loncommon::devalidate_domconfig_cache($dom); + $$lastactref = 'update'; } else { - $resulttext = &mt('No changes made to scantron format file'); + $resulttext = &mt('No changes made to bubblesheet format file'); } } else { $resulttext = ''. &mt('An error occurred: [_1]',$putresult).''; } } else { - $resulttext = &mt('No changes made to scantron format file'); + $resulttext = &mt('No changes made to bubblesheet format file'); } if ($errors) { $resulttext .= &mt('The following errors occurred: ').'
      '. @@ -5510,15 +7662,13 @@ sub modify_coursecategories { } else { $changes{'togglecats'} = 1; $changes{'categorize'} = 1; - $domconfig{'coursecategories'} = { - togglecats => $env{'form.togglecats'}, - categorize => $env{'form.categorize'}, - }; $changes{'togglecatscomm'} = 1; $changes{'categorizecomm'} = 1; $domconfig{'coursecategories'} = { - togglecats => $env{'form.togglecatscomm'}, - categorize => $env{'form.categorizecomm'}, + togglecats => $env{'form.togglecats'}, + categorize => $env{'form.categorize'}, + togglecatscomm => $env{'form.togglecatscomm'}, + categorizecomm => $env{'form.categorizecomm'}, }; } if (ref($cathash) eq 'HASH') { @@ -5762,7 +7912,6 @@ sub modify_serverstatuses { my %serverstatushash = ( serverstatuses => \%newserverstatus, ); - my %changes; foreach my $type (@pages) { foreach my $setting ('namedusers','machines') { my (@current,@new); @@ -5836,67 +7985,693 @@ sub modify_serverstatuses { } sub modify_helpsettings { - my ($dom,%domconfig) = @_; - my ($resulttext,$errors,%changes,%helphash); - - my %defaultchecked = ('submitbugs' => 'on'); - my @offon = ('off','on'); - my %title = ( submitbugs => 'Display link for users to submit a bug'); + my ($r,$dom,$confname,%domconfig) = @_; + my ($resulttext,$errors,%changes,%helphash); + my %defaultchecked = ('submitbugs' => 'on'); + my @offon = ('off','on'); my @toggles = ('submitbugs'); + if (ref($domconfig{'helpsettings'}) eq 'HASH') { + foreach my $item (@toggles) { + if ($defaultchecked{$item} eq 'on') { + if ($domconfig{'helpsettings'}{$item} eq '') { + if ($env{'form.'.$item} eq '0') { + $changes{$item} = 1; + } + } elsif ($domconfig{'helpsettings'}{$item} ne $env{'form.'.$item}) { + $changes{$item} = 1; + } + } elsif ($defaultchecked{$item} eq 'off') { + if ($domconfig{'helpsettings'}{$item} eq '') { + if ($env{'form.'.$item} eq '1') { + $changes{$item} = 1; + } + } elsif ($domconfig{'helpsettings'}{$item} ne $env{'form.'.$item}) { + $changes{$item} = 1; + } + } + if (($env{'form.'.$item} eq '0') || ($env{'form.'.$item} eq '1')) { + $helphash{'helpsettings'}{$item} = $env{'form.'.$item}; + } + } + } + my $putresult; + if (keys(%changes) > 0) { + $putresult = &Apache::lonnet::put_dom('configuration',\%helphash,$dom); + if ($putresult eq 'ok') { + $resulttext = &mt('Changes made:').'
        '; + foreach my $item (sort(keys(%changes))) { + if ($item eq 'submitbugs') { + $resulttext .= '
      • '.&mt('Display link to: [_1] set to "'.$offon[$env{'form.'.$item}].'".', + &Apache::loncommon::modal_link('http://bugs.loncapa.org', + &mt('LON-CAPA bug tracker'),600,500)).'
      • '; + } + } + $resulttext .= '
      '; + } else { + $resulttext = &mt('No changes made to help settings'); + $errors .= '
    • '. + &mt('An error occurred storing the settings: [_1]', + $putresult).'
    • '; + } + } + if ($errors) { + $resulttext .= '
      '.&mt('The following errors occurred: ').'
        '. + $errors.'
      '; + } + return $resulttext; +} - $helphash{'helpsettings'} = {}; - - if (ref($domconfig{'helpsettings'}) ne 'HASH') { - if ($domconfig{'helpsettings'} eq '') { - $domconfig{'helpsettings'} = {}; +sub modify_coursedefaults { + my ($dom,%domconfig) = @_; + my ($resulttext,$errors,%changes,%defaultshash); + my %defaultchecked = ('canuse_pdfforms' => 'off'); + my @toggles = ('canuse_pdfforms'); + my @numbers = ('anonsurvey_threshold','uploadquota_official','uploadquota_unofficial', + 'uploadquota_community'); + my @types = ('official','unofficial','community'); + my %staticdefaults = ( + anonsurvey_threshold => 10, + uploadquota => 500, + ); + + $defaultshash{'coursedefaults'} = {}; + + if (ref($domconfig{'coursedefaults'}) ne 'HASH') { + if ($domconfig{'coursedefaults'} eq '') { + $domconfig{'coursedefaults'} = {}; } } - - if (ref($domconfig{'helpsettings'}) eq 'HASH') { - + + if (ref($domconfig{'coursedefaults'}) eq 'HASH') { foreach my $item (@toggles) { - - if ($defaultchecked{$item} eq 'on') { - if (($domconfig{'helpsettings'}{$item} eq '') && - ($env{'form.'.$item} eq '0')) { - $changes{$item} = 1; - } elsif ($domconfig{'helpsettings'}{$item} ne $env{'form.'.$item}) { - $changes{$item} = 1; - } - } elsif ($defaultchecked{$item} eq 'off') { - if (($domconfig{'helpsettings'}{$item} eq '') && - ($env{'form.'.$item} eq '1')) { - $changes{$item} = 1; - } elsif ($domconfig{'helpsettings'}{$item} ne $env{'form.'.$item}) { - $changes{$item} = 1; - } - } - $helphash{'helpsettings'}{$item} = $env{'form.'.$item}; - } + if ($defaultchecked{$item} eq 'on') { + if (($domconfig{'coursedefaults'}{$item} eq '') && + ($env{'form.'.$item} eq '0')) { + $changes{$item} = 1; + } elsif ($domconfig{'coursedefaults'}{$item} ne $env{'form.'.$item}) { + $changes{$item} = 1; + } + } elsif ($defaultchecked{$item} eq 'off') { + if (($domconfig{'coursedefaults'}{$item} eq '') && + ($env{'form.'.$item} eq '1')) { + $changes{$item} = 1; + } elsif ($domconfig{'coursedefaults'}{$item} ne $env{'form.'.$item}) { + $changes{$item} = 1; + } + } + $defaultshash{'coursedefaults'}{$item} = $env{'form.'.$item}; + } + foreach my $item (@numbers) { + my ($currdef,$newdef); + $newdef = $env{'form.'.$item}; + if ($item eq 'anonsurvey_threshold') { + $currdef = $domconfig{'coursedefaults'}{$item}; + $newdef =~ s/\D//g; + if ($newdef eq '' || $newdef < 1) { + $newdef = 1; + } + $defaultshash{'coursedefaults'}{$item} = $newdef; + } else { + my ($type) = ($item =~ /^\Quploadquota_\E(\w+)$/); + if (ref($domconfig{'coursedefaults'}{'uploadquota'}) eq 'HASH') { + $currdef = $domconfig{'coursedefaults'}{'uploadquota'}{$type}; + } + $newdef =~ s/[^\w.\-]//g; + $defaultshash{'coursedefaults'}{'uploadquota'}{$type} = $newdef; + } + if ($currdef ne $newdef) { + my $staticdef; + if ($item eq 'anonsurvey_threshold') { + unless (($currdef eq '') && ($newdef == $staticdefaults{$item})) { + $changes{$item} = 1; + } + } else { + unless (($currdef eq '') && ($newdef == $staticdefaults{'uploadquota'})) { + $changes{'uploadquota'} = 1; + } + } + } + } + my $officialcreds = $env{'form.official_credits'}; + $officialcreds =~ s/^[^\d\.]//g; + my $unofficialcreds = $env{'form.unofficial_credits'}; + $unofficialcreds =~ s/^[^\d\.]//g; + if (ref($domconfig{'coursedefaults'}{'coursecredits'} ne 'HASH') && + ($env{'form.coursecredits'} eq '1')) { + $changes{'coursecredits'} = 1; + } else { + if (($domconfig{'coursedefaults'}{'coursecredits'}{'official'} ne $officialcreds) || + ($domconfig{'coursedefaults'}{'coursecredits'}{'unofficial'} ne $unofficialcreds)) { + $changes{'coursecredits'} = 1; + } + } + $defaultshash{'coursedefaults'}{'coursecredits'} = { + official => $officialcreds, + unofficial => $unofficialcreds, + } } - - my $putresult = &Apache::lonnet::put_dom('configuration',\%helphash, + my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, $dom); - if ($putresult eq 'ok') { + my %domdefaults; if (keys(%changes) > 0) { - $resulttext = &mt('Changes made:').'
        '; - foreach my $item (sort(keys(%changes))) { - if ($item eq 'submitbugs') { - $resulttext .= '
      • '.&mt("$title{$item} set to $offon[$env{'form.'.$item}]").'
      • '; - } - } - $resulttext .= '
      '; - } else { - $resulttext = &mt('No changes made to help settings'); - } + if (($changes{'canuse_pdfforms'}) || ($changes{'coursecredits'}) || ($changes{'uploadquota'})) { + %domdefaults = &Apache::lonnet::get_domain_defaults($dom); + if ($changes{'canuse_pdfforms'}) { + $domdefaults{'canuse_pdfforms'}=$defaultshash{'coursedefaults'}{'canuse_pdfforms'}; + } + if ($changes{'coursecredits'}) { + if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') { + $domdefaults{'officialcredits'} = + $defaultshash{'coursedefaults'}{'coursecredits'}{'official'}; + $domdefaults{'unofficialcredits'} = + $defaultshash{'coursedefaults'}{'coursecredits'}{'unofficial'}; + } + } + if ($changes{'uploadquota'}) { + if (ref($defaultshash{'coursedefaults'}{'uploadquota'}) eq 'HASH') { + foreach my $type (@types) { + $domdefaults{$type.'quota'}=$defaultshash{'coursedefaults'}{'uploadquota'}{$type}; + } + } + } + my $cachetime = 24*60*60; + &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); + } + $resulttext = &mt('Changes made:').'
        '; + foreach my $item (sort(keys(%changes))) { + if ($item eq 'canuse_pdfforms') { + if ($env{'form.'.$item} eq '1') { + $resulttext .= '
      • '.&mt("Course/Community users can create/upload PDF forms set to 'on'").'
      • '; + } else { + $resulttext .= '
      • '.&mt('Course/Community users can create/upload PDF forms set to "off"').'
      • '; + } + } elsif ($item eq 'anonsurvey_threshold') { + $resulttext .= '
      • '.&mt('Responder count required for display of anonymous survey submissions set to [_1].',$defaultshash{'coursedefaults'}{'anonsurvey_threshold'}).'
      • '; + } elsif ($item eq 'uploadquota') { + if (ref($defaultshash{'coursedefaults'}{'uploadquota'}) eq 'HASH') { + $resulttext .= '
      • '.&mt('Default quota for content uploaded to a course/community via Course Editor set as follows:').'
          '. + '
        • '.&mt('Official courses: [_1] MB',''.$defaultshash{'coursedefaults'}{'uploadquota'}{'official'}.'').'
        • '. + '
        • '.&mt('Unofficial courses: [_1] MB',''.$defaultshash{'coursedefaults'}{'uploadquota'}{'unofficial'}.'').'
        • '. + '
        • '.&mt('Communities: [_1] MB',''.$defaultshash{'coursedefaults'}{'uploadquota'}{'community'}.'').'
        • '. + '
        '. + '
      • '; + } else { + $resulttext .= '
      • '.&mt('Default quota for content uploaded via Course Editor remains default: [_1] MB',$staticdefaults{'uploadquota'}).'
      • '; + } + } elsif ($item eq 'coursecredits') { + if (ref($defaultshash{'coursedefaults'}{'coursecredits'}) eq 'HASH') { + if (($domdefaults{'officialcredits'} eq '') && + ($domdefaults{'unofficialcredits'} eq '')) { + $resulttext .= '
      • '.&mt('Student credits not in use for courses in this domain').'
      • '; + } else { + $resulttext .= '
      • '.&mt('Student credits can be set per course by a Domain Coordinator, with the following defaults applying:').'
          '. + '
        • '.&mt('Official courses: [_1]',$defaultshash{'coursedefaults'}{'coursecredits'}{'official'}).'
        • '. + '
        • '.&mt('Unofficial courses: [_1]',$defaultshash{'coursedefaults'}{'coursecredits'}{'unofficial'}).'
        • '. + '
        '. + '
      • '; + } + } else { + $resulttext .= '
      • '.&mt('Student credits not in use for courses in this domain').'
      • '; + } + } + } + $resulttext .= '
      '; + } else { + $resulttext = &mt('No changes made to course defaults'); + } } else { $resulttext = ''. - &mt('An error occurred: [_1]',$putresult).''; + &mt('An error occurred: [_1]',$putresult).''; } - if ($errors) { - $resulttext .= &mt('The following errors occurred: ').'
        '. - $errors.'
      '; + return $resulttext; +} + +sub modify_usersessions { + my ($dom,%domconfig) = @_; + my @hostingtypes = ('version','excludedomain','includedomain'); + my @offloadtypes = ('primary','default'); + my %types = ( + remote => \@hostingtypes, + hosted => \@hostingtypes, + spares => \@offloadtypes, + ); + my @prefixes = ('remote','hosted','spares'); + my @lcversions = &Apache::lonnet::all_loncaparevs(); + my (%by_ip,%by_location,@intdoms); + &build_location_hashes(\@intdoms,\%by_ip,\%by_location); + my @locations = sort(keys(%by_location)); + my (%defaultshash,%changes); + foreach my $prefix (@prefixes) { + $defaultshash{'usersessions'}{$prefix} = {}; + } + my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); + my $resulttext; + my %iphost = &Apache::lonnet::get_iphost(); + foreach my $prefix (@prefixes) { + next if ($prefix eq 'spares'); + foreach my $type (@{$types{$prefix}}) { + my $inuse = $env{'form.'.$prefix.'_'.$type.'_inuse'}; + if ($type eq 'version') { + my $value = $env{'form.'.$prefix.'_'.$type}; + my $okvalue; + if ($value ne '') { + if (grep(/^\Q$value\E$/,@lcversions)) { + $okvalue = $value; + } + } + if (ref($domconfig{'usersessions'}) eq 'HASH') { + if (ref($domconfig{'usersessions'}{$prefix}) eq 'HASH') { + if ($domconfig{'usersessions'}{$prefix}{$type} ne '') { + if ($inuse == 0) { + $changes{$prefix}{$type} = 1; + } else { + if ($okvalue ne $domconfig{'usersessions'}{$prefix}{$type}) { + $changes{$prefix}{$type} = 1; + } + if ($okvalue ne '') { + $defaultshash{'usersessions'}{$prefix}{$type} = $okvalue; + } + } + } else { + if (($inuse == 1) && ($okvalue ne '')) { + $defaultshash{'usersessions'}{$prefix}{$type} = $okvalue; + $changes{$prefix}{$type} = 1; + } + } + } else { + if (($inuse == 1) && ($okvalue ne '')) { + $defaultshash{'usersessions'}{$prefix}{$type} = $okvalue; + $changes{$prefix}{$type} = 1; + } + } + } else { + if (($inuse == 1) && ($okvalue ne '')) { + $defaultshash{'usersessions'}{$prefix}{$type} = $okvalue; + $changes{$prefix}{$type} = 1; + } + } + } else { + my @vals = &Apache::loncommon::get_env_multiple('form.'.$prefix.'_'.$type); + my @okvals; + foreach my $val (@vals) { + if ($val =~ /:/) { + my @items = split(/:/,$val); + foreach my $item (@items) { + if (ref($by_location{$item}) eq 'ARRAY') { + push(@okvals,$item); + } + } + } else { + if (ref($by_location{$val}) eq 'ARRAY') { + push(@okvals,$val); + } + } + } + @okvals = sort(@okvals); + if (ref($domconfig{'usersessions'}) eq 'HASH') { + if (ref($domconfig{'usersessions'}{$prefix}) eq 'HASH') { + if (ref($domconfig{'usersessions'}{$prefix}{$type}) eq 'ARRAY') { + if ($inuse == 0) { + $changes{$prefix}{$type} = 1; + } else { + $defaultshash{'usersessions'}{$prefix}{$type} = \@okvals; + my @changed = &Apache::loncommon::compare_arrays($domconfig{'usersessions'}{$prefix}{$type},$defaultshash{'usersessions'}{$prefix}{$type}); + if (@changed > 0) { + $changes{$prefix}{$type} = 1; + } + } + } else { + if ($inuse == 1) { + $defaultshash{'usersessions'}{$prefix}{$type} = \@okvals; + $changes{$prefix}{$type} = 1; + } + } + } else { + if ($inuse == 1) { + $defaultshash{'usersessions'}{$prefix}{$type} = \@okvals; + $changes{$prefix}{$type} = 1; + } + } + } else { + if ($inuse == 1) { + $defaultshash{'usersessions'}{$prefix}{$type} = \@okvals; + $changes{$prefix}{$type} = 1; + } + } + } + } + } + + my @alldoms = &Apache::lonnet::all_domains(); + my %servers = &Apache::lonnet::internet_dom_servers($dom); + my %spareid = ¤t_offloads_to($dom,$domconfig{'usersessions'},\%servers); + my $savespares; + + foreach my $lonhost (sort(keys(%servers))) { + my $serverhomeID = + &Apache::lonnet::get_server_homeID($servers{$lonhost}); + my $serverhostname = &Apache::lonnet::hostname($lonhost); + $defaultshash{'usersessions'}{'spares'}{$lonhost} = {}; + my %spareschg; + foreach my $type (@{$types{'spares'}}) { + my @okspares; + my @checked = &Apache::loncommon::get_env_multiple('form.spare_'.$type.'_'.$lonhost); + foreach my $server (@checked) { + if (&Apache::lonnet::hostname($server) ne '') { + unless (&Apache::lonnet::hostname($server) eq $serverhostname) { + unless (grep(/^\Q$server\E$/,@okspares)) { + push(@okspares,$server); + } + } + } + } + my $new = $env{'form.newspare_'.$type.'_'.$lonhost}; + my $newspare; + if (($new ne '') && (&Apache::lonnet::hostname($new))) { + unless (&Apache::lonnet::hostname($new) eq $serverhostname) { + $newspare = $new; + } + } + my @spares; + if (($newspare ne '') && (!grep(/^\Q$newspare\E$/,@okspares))) { + @spares = sort(@okspares,$newspare); + } else { + @spares = sort(@okspares); + } + $defaultshash{'usersessions'}{'spares'}{$lonhost}{$type} = \@spares; + if (ref($spareid{$lonhost}) eq 'HASH') { + if (ref($spareid{$lonhost}{$type}) eq 'ARRAY') { + my @diffs = &Apache::loncommon::compare_arrays($spareid{$lonhost}{$type},\@spares); + if (@diffs > 0) { + $spareschg{$type} = 1; + } + } + } + } + if (keys(%spareschg) > 0) { + $changes{'spares'}{$lonhost} = \%spareschg; + } + } + + if (ref($domconfig{'usersessions'}) eq 'HASH') { + if (ref($domconfig{'usersessions'}{'spares'}) eq 'HASH') { + if (ref($changes{'spares'}) eq 'HASH') { + if (keys(%{$changes{'spares'}}) > 0) { + $savespares = 1; + } + } + } else { + $savespares = 1; + } + } + + my $nochgmsg = &mt('No changes made to settings for user session hosting/offloading.'); + if ((keys(%changes) > 0) || ($savespares)) { + my $putresult = &Apache::lonnet::put_dom('configuration',\%defaultshash, + $dom); + if ($putresult eq 'ok') { + if (ref($defaultshash{'usersessions'}) eq 'HASH') { + if (ref($defaultshash{'usersessions'}{'remote'}) eq 'HASH') { + $domdefaults{'remotesessions'} = $defaultshash{'usersessions'}{'remote'}; + } + if (ref($defaultshash{'usersessions'}{'hosted'}) eq 'HASH') { + $domdefaults{'hostedsessions'} = $defaultshash{'usersessions'}{'hosted'}; + } + } + my $cachetime = 24*60*60; + &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); + if (keys(%changes) > 0) { + my %lt = &usersession_titles(); + $resulttext = &mt('Changes made:').'
        '; + foreach my $prefix (@prefixes) { + if (ref($changes{$prefix}) eq 'HASH') { + $resulttext .= '
      • '.$lt{$prefix}.'
          '; + if ($prefix eq 'spares') { + if (ref($changes{$prefix}) eq 'HASH') { + foreach my $lonhost (sort(keys(%{$changes{$prefix}}))) { + $resulttext .= '
        • '.$lonhost.' '; + my $lonhostdom = &Apache::lonnet::host_domain($lonhost); + &Apache::lonnet::remote_devalidate_cache($lonhost,'spares',$lonhostdom); + if (ref($changes{$prefix}{$lonhost}) eq 'HASH') { + foreach my $type (@{$types{$prefix}}) { + if ($changes{$prefix}{$lonhost}{$type}) { + my $offloadto = &mt('None'); + if (ref($defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}) eq 'ARRAY') { + if (@{$defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}} > 0) { + $offloadto = join(', ',@{$defaultshash{'usersessions'}{'spares'}{$lonhost}{$type}}); + } + } + $resulttext .= &mt('[_1] set to: [_2].',''.$lt{$type}.'',$offloadto).(' 'x3); + } + } + } + $resulttext .= '
        • '; + } + } + } else { + foreach my $type (@{$types{$prefix}}) { + if (defined($changes{$prefix}{$type})) { + my $newvalue; + if (ref($defaultshash{'usersessions'}) eq 'HASH') { + if (ref($defaultshash{'usersessions'}{$prefix})) { + if ($type eq 'version') { + $newvalue = $defaultshash{'usersessions'}{$prefix}{$type}; + } elsif (ref($defaultshash{'usersessions'}{$prefix}{$type}) eq 'ARRAY') { + if (@{$defaultshash{'usersessions'}{$prefix}{$type}} > 0) { + $newvalue = join(', ',@{$defaultshash{'usersessions'}{$prefix}{$type}}); + } + } + } + } + if ($newvalue eq '') { + if ($type eq 'version') { + $resulttext .= '
        • '.&mt('[_1] set to: off',$lt{$type}).'
        • '; + } else { + $resulttext .= '
        • '.&mt('[_1] set to: none',$lt{$type}).'
        • '; + } + } else { + if ($type eq 'version') { + $newvalue .= ' '.&mt('(or later)'); + } + $resulttext .= '
        • '.&mt('[_1] set to: [_2].',$lt{$type},$newvalue).'
        • '; + } + } + } + } + $resulttext .= '
        '; + } + } + $resulttext .= '
      '; + } else { + $resulttext = $nochgmsg; + } + } else { + $resulttext = ''. + &mt('An error occurred: [_1]',$putresult).''; + } + } else { + $resulttext = $nochgmsg; + } + return $resulttext; +} + +sub modify_loadbalancing { + my ($dom,%domconfig) = @_; + my $primary_id = &Apache::lonnet::domain($dom,'primary'); + my $intdom = &Apache::lonnet::internet_dom($primary_id); + my ($othertitle,$usertypes,$types) = + &Apache::loncommon::sorted_inst_types($dom); + my %servers = &Apache::lonnet::internet_dom_servers($dom); + my @sparestypes = ('primary','default'); + my %typetitles = &sparestype_titles(); + my $resulttext; + my (%currbalancer,%currtargets,%currrules,%existing); + if (ref($domconfig{'loadbalancing'}) eq 'HASH') { + %existing = %{$domconfig{'loadbalancing'}}; + } + &get_loadbalancers_config(\%servers,\%existing,\%currbalancer, + \%currtargets,\%currrules); + my ($saveloadbalancing,%defaultshash,%changes); + my ($alltypes,$othertypes,$titles) = + &loadbalancing_titles($dom,$intdom,$usertypes,$types); + my %ruletitles = &offloadtype_text(); + my @deletions = &Apache::loncommon::get_env_multiple('form.loadbalancing_delete'); + for (my $i=0; $i<$env{'form.loadbalancing_total'}; $i++) { + my $balancer = $env{'form.loadbalancing_lonhost_'.$i}; + if ($balancer eq '') { + next; + } + if (!exists($servers{$balancer})) { + if (exists($currbalancer{$balancer})) { + push(@{$changes{'delete'}},$balancer); + } + next; + } + if ((@deletions > 0) && (grep(/^\Q$i\E$/,@deletions))) { + push(@{$changes{'delete'}},$balancer); + next; + } + if (!exists($currbalancer{$balancer})) { + push(@{$changes{'add'}},$balancer); + } + $defaultshash{'loadbalancing'}{$balancer}{'targets'}{'primary'} = []; + $defaultshash{'loadbalancing'}{$balancer}{'targets'}{'default'} = []; + $defaultshash{'loadbalancing'}{$balancer}{'rules'} = {}; + unless (ref($domconfig{'loadbalancing'}) eq 'HASH') { + $saveloadbalancing = 1; + } + foreach my $sparetype (@sparestypes) { + my @targets = &Apache::loncommon::get_env_multiple('form.loadbalancing_target_'.$i.'_'.$sparetype); + my @offloadto; + foreach my $target (@targets) { + if (($servers{$target}) && ($target ne $balancer)) { + if ($sparetype eq 'default') { + if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{'primary'}) eq 'ARRAY') { + next if (grep(/^\Q$target\E$/,@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{'primary'}})); + } + } + unless(grep(/^\Q$target\E$/,@offloadto)) { + push(@offloadto,$target); + } + } + $defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype} = \@offloadto; + } + } + if (ref($currtargets{$balancer}) eq 'HASH') { + foreach my $sparetype (@sparestypes) { + if (ref($currtargets{$balancer}{$sparetype}) eq 'ARRAY') { + my @targetdiffs = &Apache::loncommon::compare_arrays($currtargets{$balancer}{$sparetype},$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}); + if (@targetdiffs > 0) { + $changes{'curr'}{$balancer}{'targets'} = 1; + } + } elsif (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') { + if (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}} > 0) { + $changes{'curr'}{$balancer}{'targets'} = 1; + } + } + } + } else { + if (ref($defaultshash{'loadbalancing'}{$balancer}) eq 'HASH') { + foreach my $sparetype (@sparestypes) { + if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') { + if (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}} > 0) { + $changes{'curr'}{$balancer}{'targets'} = 1; + } + } + } + } + } + my $ishomedom; + if (&Apache::lonnet::host_domain($balancer) eq $dom) { + $ishomedom = 1; + } + if (ref($alltypes) eq 'ARRAY') { + foreach my $type (@{$alltypes}) { + my $rule; + unless ((($type eq '_LC_external') || ($type eq '_LC_internetdom')) && + (!$ishomedom)) { + $rule = $env{'form.loadbalancing_rules_'.$i.'_'.$type}; + } + if ($rule eq 'specific') { + $rule = $env{'form.loadbalancing_singleserver_'.$i.'_'.$type}; + } + $defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type} = $rule; + if (ref($currrules{$balancer}) eq 'HASH') { + if ($rule ne $currrules{$balancer}{$type}) { + $changes{'curr'}{$balancer}{'rules'}{$type} = 1; + } + } elsif ($rule ne '') { + $changes{'curr'}{$balancer}{'rules'}{$type} = 1; + } + } + } + } + my $nochgmsg = &mt('No changes made to Load Balancer settings.'); + if ((keys(%changes) > 0) || ($saveloadbalancing)) { + unless (ref($defaultshash{'loadbalancing'}) eq 'HASH') { + $defaultshash{'loadbalancing'} = {}; + } + my $putresult = &Apache::lonnet::put_dom('configuration', + \%defaultshash,$dom); + if ($putresult eq 'ok') { + if (keys(%changes) > 0) { + if (ref($changes{'delete'}) eq 'ARRAY') { + foreach my $balancer (sort(@{$changes{'delete'}})) { + $resulttext .= '
    • '.&mt('Load Balancing discontinued for: [_1]',$balancer).'
    • '; + &Apache::lonnet::remote_devalidate_cache($balancer,'loadbalancing',$dom); + } + } + if (ref($changes{'add'}) eq 'ARRAY') { + foreach my $balancer (sort(@{$changes{'add'}})) { + $resulttext .= '
    • '.&mt('Load Balancing enabled for: [_1]',$balancer); + } + } + if (ref($changes{'curr'}) eq 'HASH') { + foreach my $balancer (sort(keys(%{$changes{'curr'}}))) { + if (ref($changes{'curr'}{$balancer}) eq 'HASH') { + if ($changes{'curr'}{$balancer}{'targets'}) { + my %offloadstr; + foreach my $sparetype (@sparestypes) { + if (ref($defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}) eq 'ARRAY') { + if (@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}} > 0) { + $offloadstr{$sparetype} = join(', ',@{$defaultshash{'loadbalancing'}{$balancer}{'targets'}{$sparetype}}); + } + } + } + if (keys(%offloadstr) == 0) { + $resulttext .= '
    • '.&mt("Servers to which Load Balance server offloads set to 'None', by default").'
    • '; + } else { + my $showoffload; + foreach my $sparetype (@sparestypes) { + $showoffload .= ''.$typetitles{$sparetype}.': '; + if (defined($offloadstr{$sparetype})) { + $showoffload .= $offloadstr{$sparetype}; + } else { + $showoffload .= &mt('None'); + } + $showoffload .= (' 'x3); + } + $resulttext .= '
    • '.&mt('By default, Load Balancer: [_1] set to offload to - [_2]',$balancer,$showoffload).'
    • '; + } + } + } + if (ref($changes{'curr'}{$balancer}{'rules'}) eq 'HASH') { + if ((ref($alltypes) eq 'ARRAY') && (ref($titles) eq 'HASH')) { + foreach my $type (@{$alltypes}) { + if ($changes{'curr'}{$balancer}{'rules'}{$type}) { + my $rule = $defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type}; + my $balancetext; + if ($rule eq '') { + $balancetext = $ruletitles{'default'}; + } elsif (($rule eq 'homeserver') || ($rule eq 'externalbalancer') || + ($rule eq 'balancer') || ($rule eq 'offloadedto')) { + $balancetext = $ruletitles{$rule}; + } else { + $balancetext = &mt('offload to [_1]',$defaultshash{'loadbalancing'}{$balancer}{'rules'}{$type}); + } + $resulttext .= '
    • '.&mt('Load Balancer: [_1] -- balancing for [_2] set to - "[_3]"',$balancer,$titles->{$type},$balancetext).'
    • '; + } + } + } + } + &Apache::lonnet::remote_devalidate_cache($balancer,'loadbalancing',$dom); + } + } + if ($resulttext ne '') { + $resulttext = &mt('Changes made:').'
        '.$resulttext.'
      '; + } else { + $resulttext = $nochgmsg; + } + } else { + $resulttext = $nochgmsg; + } + } else { + $resulttext = ''. + &mt('An error occurred: [_1]',$putresult).''; + } + } else { + $resulttext = $nochgmsg; } return $resulttext; } @@ -5935,43 +8710,686 @@ sub recurse_cat_deletes { delete($coursecategories->{$subitem}); $deletions->{$subitem} = 1; &recurse_cat_deletes($subitem,$coursecategories,$deletions); - } + } } } return; } -sub dom_servers { +sub get_active_dcs { my ($dom) = @_; - my (%uniqservers,%servers); - my $primaryserver = &Apache::lonnet::hostname(&Apache::lonnet::domain($dom,'primary')); - my @machinedoms = &Apache::lonnet::machine_domains($primaryserver); - foreach my $mdom (@machinedoms) { - my %currservers = %servers; - my %server = &Apache::lonnet::get_servers($mdom); - %servers = (%currservers,%server); + my $now = time; + my %dompersonnel = &Apache::lonnet::get_domain_roles($dom,['dc'],$now,$now); + my %domcoords; + my $numdcs = 0; + foreach my $server (keys(%dompersonnel)) { + foreach my $user (sort(keys(%{$dompersonnel{$server}}))) { + my ($trole,$uname,$udom,$runame,$rudom,$rsec) = split(/:/,$user); + $domcoords{$uname.':'.$udom} = $dompersonnel{$server}{$user}; + } } - my %by_hostname; - foreach my $id (keys(%servers)) { - push(@{$by_hostname{$servers{$id}}},$id); + return %domcoords; +} + +sub active_dc_picker { + my ($dom,$numinrow,$inputtype,$name,%currhash) = @_; + my %domcoords = &get_active_dcs($dom); + my @domcoord = keys(%domcoords); + if (keys(%currhash)) { + foreach my $dc (keys(%currhash)) { + unless (exists($domcoords{$dc})) { + push(@domcoord,$dc); + } + } } - foreach my $hostname (sort(keys(%by_hostname))) { - if (@{$by_hostname{$hostname}} > 1) { - my $match = 0; - foreach my $id (@{$by_hostname{$hostname}}) { - if (&Apache::lonnet::host_domain($id) eq $dom) { - $uniqservers{$id} = $hostname; - $match = 1; + @domcoord = sort(@domcoord); + my $numdcs = scalar(@domcoord); + my $rows = 0; + my $table; + if ($numdcs > 1) { + $table = ''; + for (my $i=0; $i<@domcoord; $i++) { + my $rem = $i%($numinrow); + if ($rem == 0) { + if ($i > 0) { + $table .= ''; } + $table .= ''; + $rows ++; } - unless ($match) { - $uniqservers{$by_hostname{$hostname}[0]} = $hostname; + my $check = ''; + if ($inputtype eq 'radio') { + if (keys(%currhash) == 0) { + if (!$i) { + $check = ' checked="checked"'; + } + } elsif (exists($currhash{$domcoord[$i]})) { + $check = ' checked="checked"'; + } + } else { + if (exists($currhash{$domcoord[$i]})) { + $check = ' checked="checked"'; + } + } + if ($i == @domcoord - 1) { + my $colsleft = $numinrow - $rem; + if ($colsleft > 1) { + $table .= ''; } + } + $table .= '
      '; + } else { + $table .= ''; + } + } else { + $table .= ''; + } + my ($dcname,$dcdom) = split(':',$domcoord[$i]); + my $user = &Apache::loncommon::plainname($dcname,$dcdom); + $table .= '
      '; + } elsif ($numdcs == 1) { + if ($inputtype eq 'radio') { + $table .= ''; } else { - $uniqservers{$by_hostname{$hostname}[0]} = $hostname; + my $check; + if (exists($currhash{$domcoord[0]})) { + $check = ' checked="checked"'; + } + $table .= ''; + $rows ++; } } - return %uniqservers; + return ($numdcs,$table,$rows); +} + +sub usersession_titles { + return &Apache::lonlocal::texthash( + hosted => 'Hosting of sessions for users from other domains on servers in this domain', + remote => 'Hosting of sessions for users in this domain on servers in other domains', + spares => 'Servers offloaded to, when busy', + version => 'LON-CAPA version requirement', + excludedomain => 'Allow all, but exclude specific domains', + includedomain => 'Deny all, but include specific domains', + primary => 'Primary (checked first)', + default => 'Default', + ); +} + +sub id_for_thisdom { + my (%servers) = @_; + my %altids; + foreach my $server (keys(%servers)) { + my $serverhome = &Apache::lonnet::get_server_homeID($servers{$server}); + if ($serverhome ne $server) { + $altids{$serverhome} = $server; + } + } + return %altids; +} + +sub count_servers { + my ($currbalancer,%servers) = @_; + my (@spares,$numspares); + foreach my $lonhost (sort(keys(%servers))) { + next if ($currbalancer eq $lonhost); + push(@spares,$lonhost); + } + if ($currbalancer) { + $numspares = scalar(@spares); + } else { + $numspares = scalar(@spares) - 1; + } + return ($numspares,@spares); +} + +sub lonbalance_targets_js { + my ($dom,$types,$servers,$settings) = @_; + my $select = &mt('Select'); + my ($alltargets,$allishome,$allinsttypes,@alltypes); + if (ref($servers) eq 'HASH') { + $alltargets = join("','",sort(keys(%{$servers}))); + my @homedoms; + foreach my $server (sort(keys(%{$servers}))) { + if (&Apache::lonnet::host_domain($server) eq $dom) { + push(@homedoms,'1'); + } else { + push(@homedoms,'0'); + } + } + $allishome = join("','",@homedoms); + } + if (ref($types) eq 'ARRAY') { + if (@{$types} > 0) { + @alltypes = @{$types}; + } + } + push(@alltypes,'default','_LC_adv','_LC_author','_LC_internetdom','_LC_external'); + $allinsttypes = join("','",@alltypes); + my (%currbalancer,%currtargets,%currrules,%existing); + if (ref($settings) eq 'HASH') { + %existing = %{$settings}; + } + &get_loadbalancers_config($servers,\%existing,\%currbalancer, + \%currtargets,\%currrules); + my $balancers = join("','",sort(keys(%currbalancer))); + return <<"END"; + + + +END +} + +sub new_spares_js { + my @sparestypes = ('primary','default'); + my $types = join("','",@sparestypes); + my $select = &mt('Select'); + return <<"END"; + + + +END + +} + +sub common_domprefs_js { + return <<"END"; + + + +END + +} + +sub recaptcha_js { + my %lt = &captcha_phrases(); + return <<"END"; + + + +END + +} + +sub credits_js { + return <<"END"; + + + +END + +} + +sub captcha_phrases { + return &Apache::lonlocal::texthash ( + priv => 'Private key', + pub => 'Public key', + original => 'original (CAPTCHA)', + recaptcha => 'successor (ReCAPTCHA)', + notused => 'unused', + ); +} + +sub devalidate_remote_domconfs { + my ($dom) = @_; + my $primary_id = &Apache::lonnet::domain($dom,'primary'); + my $intdom = &Apache::lonnet::internet_dom($primary_id); + my %servers = &Apache::lonnet::internet_dom_servers($dom); + my %thismachine; + map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids(); + if (keys(%servers) > 1) { + foreach my $server (keys(%servers)) { + next if ($thismachine{$server}); + &Apache::lonnet::remote_devalidate_cache($server,'domainconfig',$dom); + } + } + return; } 1;