--- loncom/interface/domainprefs.pm 2008/05/01 00:01:16 1.47 +++ loncom/interface/domainprefs.pm 2009/08/23 17:36:53 1.102.2.3 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set domain-wide configuration settings # -# $Id: domainprefs.pm,v 1.47 2008/05/01 00:01:16 raeburn Exp $ +# $Id: domainprefs.pm,v 1.102.2.3 2009/08/23 17:36:53 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -28,6 +28,131 @@ ############################################################### ############################################################## +=pod + +=head1 NAME + +Apache::domainprefs.pm + +=head1 SYNOPSIS + +Handles configuration of a LON-CAPA domain. + +This is part of the LearningOnline Network with CAPA project +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 +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. + +LON-CAPA provides a mechanism to display and modify these defaults, as well as a +host of other domain-wide settings which determine the types of functionality +available to users and courses in the domain. + +There is also a mechanism to configure cataloging of courses in the domain, and +controls on the operation of automated processes which govern such things as +roster updates, user directory updates and processing of course requests. + +The domain coordination manual which is built dynamically on install/update of +LON-CAPA from the relevant help items provides more information about domain +configuration. + +Most of the domain settings are stored in the configuration.db GDBM file which is +housed on the primary library server for the domain in /home/httpd/lonUsers/$dom, +where $dom is the domain. The configuration.db stores settings in a number of +frozen hashes of hashes. In a few cases, domain information must be uploaded to +the domain as files (e.g., image files for logos etc., or plain text files for +bubblesheet formats). In this case the domainprefs.pm must be running in a user +session hosted on the primary library server in the domain, as these files are +stored in author space belonging to a special $dom-domainconfig user. + +domainprefs.pm in combination with lonconfigsettings.pm will retrieve and display +the current settings, and provides an interface to make modifications. + +=head1 SUBROUTINES + +=over + +=item print_quotas() + +Inputs: 4 + +$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). + +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. + +Outputs: 1 + +$datatable - HTML containing form elements which allow settings to be changed. + +In the case of course requests, radio buttons are displayed for each institutional +affiliate type (and also default, and _LC_adv) for each of the course types +(official, unofficial and community). In each case the radio buttons allow the +selection of one of four values: + +0, approval, validate, autolimit=N (where N is blank, or a positive integer). +which have the following effects: + +0 + +=over + +- course requests are not allowed for this course types/affiliation + +=back + +approval + +=over + +- course requests must be approved by a Doman Coordinator in the +course's domain + +=back + +validate + +=over + +- an institutional validation (e.g., check requestor is instructor +of record) needs to be passed before the course will be created. The required +validation is in localenroll.pm on the primary library server for the course +domain. + +=back + +autolimit + +=over + +- course requests will be processed autoatically 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. + +=back + +=item modify_quotas() + +=back + +=cut + package Apache::domainprefs; use strict; @@ -37,10 +162,14 @@ use Apache::loncommon(); use Apache::lonhtmlcommon(); use Apache::lonlocal; use Apache::lonmsg(); -use LONCAPA(); +use Apache::lonconfigsettings; +use LONCAPA qw(:DEFAULT :match); use LONCAPA::Enrollment; +use LONCAPA::lonauthcgi(); use File::Copy; use Locale::Language; +use DateTime::TimeZone; +use DateTime::Locale; sub handler { my $r=shift; @@ -50,6 +179,7 @@ sub handler { return OK; } + my $context = 'domain'; my $dom = $env{'request.role.domain'}; my $domdesc = &Apache::lonnet::domain($dom,'description'); if (&Apache::lonnet::allowed('mau',$dom)) { @@ -62,7 +192,7 @@ sub handler { } &Apache::lonhtmlcommon::clear_breadcrumbs(); &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, - ['phase']); + ['phase','actions']); my $phase = 'pickactions'; if ( exists($env{'form.phase'}) ) { $phase = $env{'form.phase'}; @@ -70,15 +200,17 @@ sub handler { my %domconfig = &Apache::lonnet::get_dom('configuration',['login','rolecolors', 'quotas','autoenroll','autoupdate','directorysrch', - 'usercreation','usermodification','contacts','defaults','scantron'], - $dom); + 'usercreation','usermodification','contacts','defaults', + 'scantron','coursecategories','serverstatuses', + 'requestcourses'],$dom); my @prefs_order = ('rolecolors','login','defaults','quotas','autoenroll', 'autoupdate','directorysrch','contacts', - 'usercreation','usermodification','scantron'); + 'usercreation','usermodification','scantron', + 'requestcourses','coursecategories','serverstatuses'); my %prefs = ( 'rolecolors' => { text => 'Default color schemes', - help => 'Default_Color_Schemes', + help => 'Domain_Configuration_Color_Schemes', header => [{col1 => 'Student Settings', col2 => '',}, {col1 => 'Coordinator Settings', @@ -90,31 +222,32 @@ sub handler { }, 'login' => { text => 'Log-in page options', - help => 'Domain_Log-in_Page', + help => 'Domain_Configuration_Login_Page', header => [{col1 => 'Item', col2 => '',}], }, 'defaults' => - { text => 'Default authentication/language', - help => '', + { text => 'Default authentication/language/timezone', + help => 'Domain_Configuration_LangTZAuth', header => [{col1 => 'Setting', col2 => 'Value'}], }, 'quotas' => - { text => 'Default quotas for user portfolios', - help => 'Default_User_Quota', - header => [{col1 => 'User type', - col2 => 'Default quota'}], + { text => 'User blogs, personal information pages and portfolios', + help => 'Domain_Configuration_Quotas', + header => [{col1 => 'User affiliation', + col2 => 'Available tools', + col3 => 'Portfolio quota',}], }, 'autoenroll' => { text => 'Auto-enrollment settings', - help => 'Domain_Auto_Enrollment', + help => 'Domain_Configuration_Auto_Enrollment', header => [{col1 => 'Configuration setting', col2 => 'Value(s)'}], }, 'autoupdate' => { text => 'Auto-update settings', - help => 'Domain_Auto_Update', + help => 'Domain_Configuration_Auto_Updates', header => [{col1 => 'Setting', col2 => 'Value',}, {col1 => 'User population', @@ -122,20 +255,20 @@ sub handler { }, 'directorysrch' => { text => 'Institutional directory searches', - help => 'Domain_Directory_Search', + help => 'Domain_Configuration_InstDirectory_Search', header => [{col1 => 'Setting', col2 => 'Value',}], }, 'contacts' => { text => 'Contact Information', - help => 'Domain_Contact_Information', + help => 'Domain_Configuration_Contact_Info', header => [{col1 => 'Setting', col2 => 'Value',}], }, 'usercreation' => { text => 'User creation', - help => 'Domain_User_Creation', + help => 'Domain_Configuration_User_Creation', header => [{col1 => 'Format rule type', col2 => 'Format rules in force'}, {col1 => 'User account creation', @@ -143,21 +276,48 @@ sub handler { {col1 => 'Context', col2 => 'Assignable authentication types'}], }, - 'usermodification' => + 'usermodification' => { text => 'User modification', - help => 'Domain_User_Modification', + help => 'Domain_Configuration_User_Modification', header => [{col1 => 'Target user has role', col2 => 'User information updateable in author context'}, {col1 => 'Target user has role', - col2 => 'User information updateable in course context'}], + col2 => 'User information updateable in course context'}, + {col1 => "Status of user", + col2 => 'Information settable when self-creating account (if directory data blank)'}], }, - 'scantron' => - { text => 'Scantron format file', - help => 'Domain_Scantron_Formats', + 'scantron' => + { text => 'Bubblesheet format file', + help => 'Domain_Configuration_Scantron_Format', header => [ {col1 => 'Item', col2 => '', }], }, + 'requestcourses' => + {text => 'Request creation of courses', + help => 'Domain_Configuration_Request_Courses', + header => [{col1 => 'User affiliation', + col2 => 'Availability/Processing of requests',}, + {col1 => 'Setting', + col2 => 'Value'}], + }, + 'coursecategories' => + { text => 'Cataloging of courses', + help => 'Domain_Configuration_Cataloging_Courses', + header => [{col1 => 'Category settings', + col2 => '',}, + {col1 => 'Categories', + col2 => '', + }], + }, + 'serverstatuses' => + {text => 'Access to server status pages', + help => 'Domain_Configuration_Server_Status', + header => [{col1 => 'Status Page', + col2 => 'Other named users', + col3 => 'Specific IPs', + }], + }, ); my @roles = ('student','coordinator','author','admin'); my @actions = &Apache::loncommon::get_env_multiple('form.actions'); @@ -166,98 +326,10 @@ sub handler { text=>"Pick functionality"}); my $confname = $dom.'-domainconfig'; if ($phase eq 'process') { - &Apache::lonhtmlcommon::add_breadcrumb - ({href=>"javascript:changePage(document.$phase,'display')", - text=>"Domain Configuration"}, - {href=>"javascript:changePage(document.$phase,'$phase')", - text=>"Updated"}); - &print_header($r,$phase); - foreach my $item (@prefs_order) { - if (grep(/^\Q$item\E$/,@actions)) { - $r->print('

'.&mt($prefs{$item}{'text'}).'

'. - &process_changes($r,$dom,$confname,$item, - \@roles,%domconfig)); - } - } - $r->print('

'); - &print_footer($r,$phase,'display','Back to configuration display', - \@actions); - $r->print('

'); + &Apache::lonconfigsettings::make_changes($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname,\@roles); } elsif ($phase eq 'display') { - &Apache::lonhtmlcommon::add_breadcrumb - ({href=>"javascript:changePage(document.$phase,'display')", - text=>"Domain Configuration"}); - &print_header($r,$phase); - if (@actions > 0) { - my $rowsum = 0; - my (%output,%rowtotal,@items); - my $halfway = @actions/2; - foreach my $item (@prefs_order) { - if (grep(/^\Q$item\E$/,@actions)) { - push(@items,$item); - ($output{$item},$rowtotal{$item}) = - &print_config_box($r,$dom,$confname,$phase, - $item,$prefs{$item}, - $domconfig{$item}); - $rowsum += $rowtotal{$item}; - } - } - my $colend; - my $halfway = $rowsum/2; - my $aggregate = 0; - my $sumleft = 0; - my $sumright = 0; - my $crossover; - for (my $i=0; $i<@items; $i++) { - $aggregate += $rowtotal{$items[$i]}; - if ($aggregate > $halfway) { - $crossover = $i; - last; - } - } - for (my $i=0; $i<$crossover; $i++) { - $sumleft += $rowtotal{$items[$i]}; - } - for (my $i=$crossover+1; $i<@items; $i++) { - $sumright += $rowtotal{$items[$i]}; - } - if ((@items > 1) && ($env{'form.numcols'} == 2)) { - my $sumdiff = $sumright - $sumleft; - if ($sumdiff > 0) { - $colend = $crossover + 1; - } else { - $colend = $crossover; - } - } else { - $colend = @items; - } - $r->print('

'); - for (my $i=0; $i<$colend; $i++) { - $r->print($output{$items[$i]}); - } - $r->print(''); - if ($colend < @items) { - for (my $i=$colend; $i<@items; $i++) { - $r->print($output{$items[$i]}); - } - } - $r->print('

'); - $r->print(&print_footer($r,$phase,'process','Save',\@actions)); - } else { - $r->print(''. - ''."\n". - ''.&mt('No settings chosen'). - ''); - } - $r->print(''); - $r->print(&Apache::loncommon::end_page()); + &Apache::lonconfigsettings::display_settings($r,$dom,$phase,$context,\@prefs_order,\%prefs,\%domconfig,$confname); } else { - if ($phase eq '') { - $phase = 'pickactions'; - } - my %helphash; - &print_header($r,$phase); if (keys(%domconfig) == 0) { my $primarylibserv = &Apache::lonnet::domain($dom,'primary'); my @ids=&Apache::lonnet::current_machine_ids(); @@ -276,6 +348,7 @@ sub handler { } } if ($custom_img_count > 0) { + &Apache::lonconfigsettings::print_header($r,$phase,$context); my $switch_server = &check_switchserver($dom,$confname); $r->print( &mt('Domain configuration settings have yet to be saved for this domain via the web-based domain preferences interface.').'
'. @@ -285,50 +358,22 @@ sub handler { if ($switch_server) { $r->print($switch_server.' '.&mt('to primary library server for domain: [_1]',$dom)); } + $r->print(&Apache::loncommon::end_page()); return OK; } } } - $r->print('

'.&mt('Functionality to display/modify').'

'); - $r->print(''."\n".'

  '. - '

'); - my ($numitems,$midpoint,$seconddiv,$count); - $numitems = @prefs_order; - $midpoint = int($numitems/2); - if ($numitems%2) { - $midpoint ++; - } - $count = 0; - foreach my $item (@prefs_order) { - $r->print('

'); - $count ++; - if ((!$seconddiv) && ($count >= $midpoint)) { - $r->print('
'."\n".'
'."\n"); - $seconddiv = 1; - } - } - $r->print('

'. - &mt('Display options').'

'."\n". - '

'.&mt('Display using: ')."\n". - '  '. - ''. - &mt('two columns').'

'); - $r->print(&print_footer($r,$phase,'display','Go')); - $r->print(''); - $r->print(&Apache::loncommon::end_page()); + &Apache::lonconfigsettings::display_choices($r,$phase,$context,\@prefs_order,\%prefs); } return OK; } sub process_changes { - my ($r,$dom,$confname,$action,$roles,%domconfig) = @_; + my ($r,$dom,$confname,$action,$roles,$values) = @_; + my %domconfig; + if (ref($values) eq 'HASH') { + %domconfig = %{$values}; + } my $output; if ($action eq 'login') { $output = &modify_login($r,$dom,$confname,%domconfig); @@ -336,7 +381,7 @@ sub process_changes { $output = &modify_rolecolors($r,$dom,$confname,$roles, %domconfig); } elsif ($action eq 'quotas') { - $output = &modify_quotas($dom,%domconfig); + $output = &modify_quotas($dom,$action,%domconfig); } elsif ($action eq 'autoenroll') { $output = &modify_autoenroll($dom,%domconfig); } elsif ($action eq 'autoupdate') { @@ -352,7 +397,13 @@ sub process_changes { } elsif ($action eq 'defaults') { $output = &modify_defaults($dom,$r); } elsif ($action eq 'scantron') { - $output = &modify_scantron($r,$dom,$confname,\%domconfig); + $output = &modify_scantron($r,$dom,$confname,%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); } return $output; } @@ -360,35 +411,44 @@ sub process_changes { sub print_config_box { my ($r,$dom,$confname,$phase,$action,$item,$settings) = @_; my $rowtotal = 0; - my $output = + my $output; + if ($action eq 'coursecategories') { + $output = &coursecategories_javascript($settings); + } + $output .= ' - '; -# -# FIXME - put the help link back in when the help files exist -# -# '); + '."\n". + ''; $rowtotal ++; if (($action eq 'autoupdate') || ($action eq 'rolecolors') || - ($action eq 'usercreation') || ($action eq 'usermodification')) { - my $colspan = ($action eq 'rolecolors')?' colspan="2"':''; + ($action eq 'usercreation') || ($action eq 'usermodification') || + ($action eq 'coursecategories') || ($action eq 'requestcourses')) { + my $colspan = ''; + if (($action eq 'rolecolors') || ($action eq 'coursecategories')) { + $colspan = ' colspan="2"'; + } $output .= '
'.&mt($item->{text}). - ' 
'.&mt($item->{text}).' '. -# &Apache::loncommon::help_open_topic($item->{'help'}).'
'. + &mt($item->{text}).' '. + &Apache::loncommon::help_open_topic($item->{'help'}).'
- - + + '; - $rowtotal ++; + $rowtotal ++; if ($action eq 'autoupdate') { $output .= &print_autoupdate('top',$dom,$settings,\$rowtotal); } elsif ($action eq 'usercreation') { $output .= &print_usercreation('top',$dom,$settings,\$rowtotal); } elsif ($action eq 'usermodification') { $output .= &print_usermodification('top',$dom,$settings,\$rowtotal); + } elsif ($action eq 'coursecategories') { + $output .= &print_coursecategories('top',$dom,$item,$settings,\$rowtotal); + } elsif ($action eq 'requestcourses') { + $output .= &print_quotas($dom,$settings,\$rowtotal,$action); } else { $output .= &print_rolecolors($phase,'student',$dom,$confname,$settings,\$rowtotal); } @@ -400,8 +460,9 @@ sub print_config_box {
'.$item->{'header'}->[0]->{'col1'}.''.$item->{'header'}->[0]->{'col2'}.''.&mt($item->{'header'}->[0]->{'col1'}).''.&mt($item->{'header'}->[0]->{'col2'}).'
- - + '; + $output .= ' + '; $rowtotal ++; if ($action eq 'autoupdate') { @@ -415,12 +476,28 @@ sub print_config_box { + + +
'.$item->{'header'}->[1]->{'col1'}.''.$item->{'header'}->[1]->{'col2'}.''.&mt($item->{'header'}->[1]->{'col1'}).''.&mt($item->{'header'}->[1]->{'col2'}).'
- - '. + + '. &print_usercreation('bottom',$dom,$settings,\$rowtotal); $rowtotal ++; } elsif ($action eq 'usermodification') { - $output .= &print_usermodification('bottom',$dom,$settings,\$rowtotal); + $output .= &print_usermodification('middle',$dom,$settings,\$rowtotal).' +
'.$item->{'header'}->[2]->{'col1'}.''.$item->{'header'}->[2]->{'col2'}.'
'.&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 'requestcourses') { + $output .= &print_courserequestmail($dom,$settings,\$rowtotal); } else { $output .= &print_rolecolors($phase,'coordinator',$dom,$confname,$settings,\$rowtotal).'
'.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).'
@@ -430,8 +507,10 @@ sub print_config_box {
- - + + '. &print_rolecolors($phase,'author',$dom,$confname,$settings,\$rowtotal).'
'.$item->{'header'}->[2]->{'col1'}.''.$item->{'header'}->[2]->{'col2'}.''. + &mt($item->{'header'}->[2]->{'col1'}).''. + &mt($item->{'header'}->[2]->{'col2'}).'
@@ -441,8 +520,8 @@ sub print_config_box {
- - + + '. &print_rolecolors($phase,'admin',$dom,$confname,$settings,\$rowtotal); $rowtotal += 2; @@ -455,19 +534,41 @@ sub print_config_box { '; if (($action eq 'login') || ($action eq 'directorysrch')) { $output .= ' - '; + '; + } elsif ($action eq 'serverstatuses') { + $output .= ' + '; + } else { $output .= ' - '; + '; } - $output .= ' - - '; - $rowtotal ++; + if (defined($item->{'header'}->[0]->{'col3'})) { + $output .= ''; + if ($item->{'header'}->[0]->{'col3'}) { + $output .= ''; + } + $output .= ''; + $rowtotal ++; if ($action eq 'login') { $output .= &print_login($dom,$confname,$phase,$settings,\$rowtotal); } elsif ($action eq 'quotas') { - $output .= &print_quotas($dom,$settings,\$rowtotal); + $output .= &print_quotas($dom,$settings,\$rowtotal,$action); } elsif ($action eq 'autoenroll') { $output .= &print_autoenroll($dom,$settings,\$rowtotal); } elsif ($action eq 'directorysrch') { @@ -478,6 +579,8 @@ sub print_config_box { $output .= &print_defaults($dom,\$rowtotal); } elsif ($action eq 'scantron') { $output .= &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal); + } elsif ($action eq 'serverstatuses') { + $output .= &print_serverstatuses($dom,$settings,\$rowtotal); } } $output .= ' @@ -488,107 +591,6 @@ sub print_config_box { return ($output,$rowtotal); } -sub print_header { - my ($r,$phase) = @_; - my $alert = &mt('You must select at least one functionality type to display.'); - my $js = ' - -'; - my $additem; - if ($phase eq 'pickactions') { - my %loaditems = ( - 'onload' => "javascript:getViewportDims(document.$phase.width,document.$phase.height);setDisplayColumns();setFormElements(document.pickactions);", - ); - $additem = {'add_entries' => \%loaditems,}; - } else { - my %loaditems = ( - 'onload' => "javascript:getViewportDims(document.$phase.width,document.$phase.height);", - ); - $additem = {'add_entries' => \%loaditems,}; - } - $r->print(&Apache::loncommon::start_page('View/Modify Domain Settings', - $js,$additem)); - $r->print(&Apache::lonhtmlcommon::breadcrumbs('Domain Settings')); - $r->print(' - - - - - -'); - $r->print(''); - return; -} - -sub print_footer { - my ($r,$phase,$newphase,$button_text,$actions) = @_; - $button_text = &mt($button_text); - $r->print(''. - ''. - ''); - if (($phase eq 'display') || ($phase eq 'process')) { - if (ref($actions) eq 'ARRAY') { - foreach my $item (@{$actions}) { - $r->print('')."\n"; - } - } - $r->print(''); - } - my $dest='"javascript:changePage(document.'.$phase.','."'$newphase'".')"'; - if ($phase eq 'process') { - $r->print('

'.$button_text.'

'); - } else { - my $onclick; - if ($phase eq 'display') { - $onclick = '"javascript:changePage(document.'.$phase.','."'$newphase'".')"'; - } else { - $onclick = '"javascript:changePage(document.'.$phase.','."'$newphase'".')"'; - } - $r->print('

'); - } - if ($phase eq 'process') { - $r->print(''.&Apache::loncommon::end_page()); - } - return; -} - sub print_login { my ($dom,$confname,$phase,$settings,$rowtotal) = @_; my %choices = &login_choices(); @@ -621,6 +623,7 @@ sub print_login { ); foreach my $item (@images) { $defaults{$item} = $defaultdesign{'login.'.$item}; + $defaults{'showlogo'}{$item} = 1; } foreach my $item (@bgs) { $defaults{'bgs'}{$item} = $defaultdesign{'login.'.$item}; @@ -642,10 +645,13 @@ sub print_login { } } foreach my $item (@images) { - if ($settings->{$item} ne '') { + if (defined($settings->{$item})) { $designs{$item} = $settings->{$item}; $is_custom{$item} = 1; } + if (defined($settings->{'showlogo'}{$item})) { + $designs{'showlogo'}{$item} = $settings->{'showlogo'}{$item}; + } } foreach my $item (@logintext) { if ($settings->{$item} ne '') { @@ -734,9 +740,9 @@ sub login_choices { bgs => "Background colors", links => "Link colors", font => "Font color", - pgbg => "Page", - mainbg => "Main panel", - sidebg => "Side panel", + pgbg => "Header", + mainbg => "Page", + sidebg => "Login box", link => "Link", alink => "Active link", vlink => "Visited link", @@ -839,20 +845,27 @@ sub display_color_options { $itemcount ++; $css_class = $itemcount%2?' class="LC_odd_row"':''; $datatable .= ''. - ''; + ''; if ($designs->{$img} ne '') { $imgfile = $designs->{$img}; $img_import = ($imgfile =~ m{^/adm/}); } else { $imgfile = $defaults->{$img}; } - if ($img eq 'login') { - $login_hdr_pick = &login_header_options($img,$role,$defaults,$is_custom,$choices, - $loginheader); - $logincolors = - &login_text_colors($img,$role,$logintext,$phase,$choices,$designs); - } if ($imgfile) { my ($showfile,$fullsize); if ($imgfile =~ m-^(/res/\Q$dom\E/\Q$confname\E/\Q$img\E)/([^/]+)$-) { @@ -941,7 +954,7 @@ sub display_color_options { my $bgs_def; foreach my $item (@{$bgs}) { if (!$is_custom->{$item}) { - $bgs_def .= ''; + $bgs_def .= ''; } } if ($bgs_def) { @@ -992,6 +1005,32 @@ sub display_color_options { return $datatable; } +sub logo_display_options { + my ($img,$defaults,$designs) = @_; + my $checkedon; + if (ref($defaults) eq 'HASH') { + if (ref($defaults->{'showlogo'}) eq 'HASH') { + if ($defaults->{'showlogo'}{$img}) { + $checkedon = 'checked="checked" '; + } + } + } + if (ref($designs) eq 'HASH') { + if (ref($designs->{'showlogo'}) eq 'HASH') { + if (defined($designs->{'showlogo'}{$img})) { + if ($designs->{'showlogo'}{$img} == 0) { + $checkedon = ''; + } elsif ($designs->{'showlogo'}{$img} == 1) { + $checkedon = 'checked="checked" '; + } + } + } + } + return '
'."\n"; +} + sub login_header_options { my ($img,$role,$defaults,$is_custom,$choices,$loginheader) = @_; my $image_checked = ' checked="checked" '; @@ -1043,7 +1082,7 @@ 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') { + if ($img ne 'domlogo') { $output .= &mt('Default image:').'
'; } else { $output .= &mt('Default in use:').'
'; @@ -1073,89 +1112,419 @@ sub color_pick { return $link; } -sub color_pick_js { - my $pjump_def = &Apache::lonhtmlcommon::pjump_javascript_definition(); - my $output = <<"ENDCOL"; - function pclose() { - parmwin=window.open("/adm/rat/empty.html","LONCAPAparms","height=350,width=350,scrollbars=no,menubar=no"); - parmwin.close(); - } - - $pjump_def - - function psub() { - pclose(); - if (document.parmform.pres_marker.value!='') { - if (document.parmform.pres_type.value!='') { - eval('document.display.'+ - document.parmform.pres_marker.value+ - '.value=document.parmform.pres_value.value;'); - } - } else { - document.parmform.pres_value.value=''; - document.parmform.pres_marker.value=''; - } - } - - function get_id (span_id) { - if (document.getElementById) { - return document.getElementById(span_id); - } - if (document.all) { - return document.all[span_id]; - } - return false; - } - - function colchg_span (span_id_str,new_color_item) { - var span_ref = get_id(span_id_str); - if (span_ref.style) { span_ref = span_ref.style; } - span_ref.background = new_color_item.value; - span_ref.backgroundColor = new_color_item.value; - span_ref.bgColor = new_color_item.value; - } - -ENDCOL - return $output; -} - sub print_quotas { - my ($dom,$settings,$rowtotal) = @_; - my $datatable; + my ($dom,$settings,$rowtotal,$action) = @_; + my $context; + if ($action eq 'quotas') { + $context = 'tools'; + } else { + $context = $action; + } + my ($datatable,$defaultquota,@usertools,@options,%validations); my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); my $typecount = 0; - my $css_class; + my ($css_class,%titles); + if ($context eq 'requestcourses') { + @usertools = ('official','unofficial','community'); + @options =('norequest','approval','autolimit','validate'); + %validations = &Apache::lonnet::auto_courserequest_checks($dom); + %titles = &courserequest_titles(); + } else { + @usertools = ('aboutme','blog','portfolio'); + %titles = &tool_titles(); + } if (ref($types) eq 'ARRAY') { foreach my $type (@{$types}) { + my $currdefquota; + unless ($context eq 'requestcourses') { + if (ref($settings) eq 'HASH') { + if (ref($settings->{defaultquota}) eq 'HASH') { + $currdefquota = $settings->{defaultquota}->{$type}; + } else { + $currdefquota = $settings->{$type}; + } + } + } if (defined($usertypes->{$type})) { $typecount ++; $css_class = $typecount%2?' class="LC_odd_row"':''; - $datatable .= ''. + $datatable .= ''. ''. + ''; + unless ($context eq 'requestcourses') { + $datatable .= ''; + '" value="'.$currdefquota. + '" size="5" /> Mb'; + } + $datatable .= ''; } } } - my $defaultquota = '20'; - if (ref($settings) eq 'HASH') { - if (defined($settings->{'default'})) { - $defaultquota = $settings->{'default'}; + unless ($context eq 'requestcourses') { + $defaultquota = '20'; + if (ref($settings) eq 'HASH') { + if (ref($settings->{'defaultquota'}) eq 'HASH') { + $defaultquota = $settings->{'defaultquota'}->{'default'}; + } elsif (defined($settings->{'default'})) { + $defaultquota = $settings->{'default'}; + } } } $typecount ++; $css_class = $typecount%2?' class="LC_odd_row"':''; $datatable .= ''. ''. - ''; + ''; + unless ($context eq 'requestcourses') { + $datatable .= ''; + } + $datatable .= ''; + $typecount ++; + $css_class = $typecount%2?' class="LC_odd_row"':''; + $datatable .= ''. + ''. + ''; $$rowtotal += $typecount; return $datatable; } +sub print_courserequestmail { + my ($dom,$settings,$rowtotal) = @_; + my ($now,$datatable,%dompersonnel,@domcoord,@currapproval,$rows); + $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); + } + } + } + @domcoord = sort(@domcoord); + my $numinrow = 4; + my $numdc = @domcoord; + my $css_class = 'class="LC_odd_row"'; + $datatable = ''. + ' '. + ' '; + $$rowtotal += $rows; + return $datatable; +} + sub print_autoenroll { my ($dom,$settings,$rowtotal) = @_; my $autorun = &Apache::lonnet::auto_run(undef,$dom), @@ -1334,8 +1703,8 @@ sub print_directorysrch { $$rowtotal += 2; if (ref($usertypes) eq 'HASH') { if (keys(%{$usertypes}) > 0) { - $datatable .= &users_cansearch_row($settings,$types,$usertypes,$dom, - $numinrow,$othertitle); + $datatable .= &insttypes_row($settings,$types,$usertypes,$dom, + $numinrow,$othertitle,'cansearch'); $cansrchrow = 1; } } @@ -1350,7 +1719,7 @@ sub print_directorysrch { foreach my $title (@{$titleorder}) { if (defined($searchtitles->{$title})) { my $check = ' '; - if (ref($settings) eq 'HASH') { + if (ref($settings) eq 'HASH') { if (ref($settings->{'searchby'}) eq 'ARRAY') { if (grep(/^\Q$title\E$/,@{$settings->{'searchby'}})) { $check = ' checked="checked" '; @@ -1392,7 +1761,8 @@ sub print_contacts { my $datatable; my @contacts = ('adminemail','supportemail'); my (%checked,%to,%otheremails); - my @mailings = ('errormail','packagesmail','helpdeskmail'); + my @mailings = ('errormail','packagesmail','lonstatusmail','helpdeskmail', + 'requestsmail'); foreach my $type (@mailings) { $otheremails{$type} = ''; } @@ -1412,6 +1782,8 @@ sub print_contacts { } $otheremails{$type} = $settings->{$type}{'others'}; } + } elsif ($type eq 'lonstatusmail') { + $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" '; } } } else { @@ -1419,30 +1791,25 @@ sub print_contacts { $to{'adminemail'} = $Apache::lonnet::perlvar{'lonAdmEMail'}; $checked{'errormail'}{'adminemail'} = ' checked="checked" '; $checked{'packagesmail'}{'adminemail'} = ' checked="checked" '; - $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" '; + $checked{'helpdeskmail'}{'supportemail'} = ' checked="checked" '; + $checked{'lonstatusmail'}{'adminemail'} = ' checked="checked" '; + $checked{'requestsmail'}{'adminemail'} = ' checked="checked" '; } my ($titles,$short_titles) = &contact_titles(); my $rownum = 0; my $css_class; foreach my $item (@contacts) { - if ($rownum%2) { - $css_class = ''; - } else { - $css_class = ' class="LC_odd_row" '; - } + $rownum ++; + $css_class = $rownum%2?' class="LC_odd_row"':''; $datatable .= ''. ''; - $rownum ++; } foreach my $type (@mailings) { - if ($rownum%2) { - $css_class = ''; - } else { - $css_class = ' class="LC_odd_row" '; - } + $rownum ++; + $css_class = $rownum%2?' class="LC_odd_row"':''; $datatable .= ''. ''. @@ -1459,7 +1826,6 @@ sub print_contacts { ''. ''."\n"; - $rownum ++; } $$rowtotal += $rownum; return $datatable; @@ -1468,10 +1834,12 @@ sub print_contacts { sub contact_titles { my %titles = &Apache::lonlocal::texthash ( 'supportemail' => 'Support E-mail address', - 'adminemail' => 'Default Server Admin E-mail address', + 'adminemail' => 'Default Server Admin E-mail address', 'errormail' => 'Error reports to be e-mailed to', 'packagesmail' => 'Package update alerts to be e-mailed to', - 'helpdeskmail' => 'Helpdesk requests to be e-mailed to' + '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', ); my %short_titles = &Apache::lonlocal::texthash ( adminemail => 'Admin E-mail address', @@ -1480,6 +1848,41 @@ sub contact_titles { return (\%titles,\%short_titles); } +sub tool_titles { + my %titles = &Apache::lonlocal::texthash ( + aboutme => 'Personal Information Page', + blog => 'Blog', + portfolio => 'Portfolio', + official => 'Official courses (with institutional codes)', + unofficial => 'Unofficial courses', + community => 'Communities', + ); + return %titles; +} + +sub courserequest_titles { + my %titles = &Apache::lonlocal::texthash ( + official => 'Official', + unofficial => 'Unofficial', + community => 'Communities', + norequest => 'Not allowed', + approval => 'Approval by Dom. Coord.', + validate => 'With validation', + autolimit => 'Numerical limit', + unlimited => '(blank for unlimited)', + ); + 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).', + ); + return %conditions; +} + + sub print_usercreation { my ($position,$dom,$settings,$rowtotal) = @_; my $numinrow = 4; @@ -1521,16 +1924,26 @@ sub print_usercreation { $rowcount ++; } } elsif ($position eq 'middle') { - my @creators = ('author','course','selfcreate'); + my @creators = ('author','course','requestcrs','selfcreate'); my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($dom,'username'); my %lt = &usercreation_types(); my %checked; + my @selfcreate; if (ref($settings) eq 'HASH') { if (ref($settings->{'cancreate'}) eq 'HASH') { foreach my $item (@creators) { $checked{$item} = $settings->{'cancreate'}{$item}; } + if (ref($settings->{'cancreate'}{'selfcreate'}) eq 'ARRAY') { + @selfcreate = @{$settings->{'cancreate'}{'selfcreate'}}; + } elsif ($settings->{'cancreate'}{'selfcreate'} ne '') { + if ($settings->{'cancreate'}{'selfcreate'} eq 'any') { + @selfcreate = ('email','login','sso'); + } elsif ($settings->{'cancreate'}{'selfcreate'} ne 'none') { + @selfcreate = ($settings->{'cancreate'}{'selfcreate'}); + } + } } elsif (ref($settings->{'cancreate'}) eq 'ARRAY') { foreach my $item (@creators) { if (grep(/^\Q$item\E$/,@{$settings->{'cancreate'}})) { @@ -1542,10 +1955,8 @@ sub print_usercreation { my $rownum = 0; foreach my $item (@creators) { $rownum ++; - if ($checked{$item} eq '') { - if ($item eq 'selfcreate') { - $checked{$item} = 'none'; - } else { + if ($item ne 'selfcreate') { + if ($checked{$item} eq '') { $checked{$item} = 'any'; } } @@ -1558,29 +1969,52 @@ sub print_usercreation { $datatable .= ''. ''; } + my ($othertitle,$usertypes,$types) = + &Apache::loncommon::sorted_inst_types($dom); + 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 ++; + } + } } else { my @contexts = ('author','course','domain'); my @authtypes = ('int','krb4','krb5','loc'); @@ -1642,10 +2076,14 @@ sub user_formats_row { ); my $css_class = $rowcount%2?' class="LC_odd_row"':''; $output = ''. - ''. - '
'.$item->{'header'}->[3]->{'col1'}.''.$item->{'header'}->[3]->{'col2'}.''.&mt($item->{'header'}->[3]->{'col1'}).''.&mt($item->{'header'}->[3]->{'col2'}).'
'.$item->{'header'}->[0]->{'col1'}.''.&mt($item->{'header'}->[0]->{'col1'}).''.&mt($item->{'header'}->[0]->{'col1'}). + '
('.&mt('Automatic access for Dom. Coords.').')
'.$item->{'header'}->[0]->{'col1'}.''.&mt($item->{'header'}->[0]->{'col1'}).''.$item->{'header'}->[0]->{'col2'}.'
'. + &mt($item->{'header'}->[0]->{'col2'}); + if ($action eq 'serverstatuses') { + $output .= '
('.&mt('user1:domain1,user2:domain2 etc.').')'; + } + } else { + $output .= '
'. + &mt($item->{'header'}->[0]->{'col2'}); + } + $output .= ''. + &mt($item->{'header'}->[0]->{'col3'}); + if ($action eq 'serverstatuses') { + $output .= '
('.&mt('IP1,IP2 etc.').')'; + } + $output .= '
'.$choices->{$img}.''.$choices->{$img}; my ($imgfile,$img_import,$login_hdr_pick,$logincolors); + if ($role eq 'login') { + if ($img eq 'login') { + $login_hdr_pick = + &login_header_options($img,$role,$defaults,$is_custom,$choices, + $loginheader); + $logincolors = + &login_text_colors($img,$role,$logintext,$phase,$choices, + $designs); + } elsif ($img ne 'domlogo') { + $datatable.= &logo_display_options($img,$defaults,$designs); + } + } + $datatable .= ''.$choices->{$item}.'    
'.$defaults->{'bgs'}{$item}.'
'.$choices->{$item}.'    
'.$defaults->{'bgs'}{$item}.'
'.$usertypes->{$type}.''; + if ($context eq 'requestcourses') { + $datatable .= ''; + } + my %cell; + foreach my $item (@usertools) { + if ($context eq 'requestcourses') { + my ($curroption,$currlimit); + if (ref($settings) eq 'HASH') { + if (ref($settings->{$item}) eq 'HASH') { + $curroption = $settings->{$item}->{$type}; + if ($curroption =~ /^autolimit=(\d*)$/) { + $currlimit = $1; + } + } + } + if (!$curroption) { + $curroption = 'norequest'; + } + $datatable .= ''; + foreach my $option (@options) { + my $val = $option; + if ($option eq 'norequest') { + $val = 0; + } + if ($option eq 'validate') { + my $canvalidate = 0; + if (ref($validations{$item}) eq 'HASH') { + if ($validations{$item}{$type}) { + $canvalidate = 1; + } + } + next if (!$canvalidate); + } + my $checked = ''; + if ($option eq $curroption) { + $checked = ' checked="checked"'; + } elsif ($option eq 'autolimit') { + if ($curroption =~ /^autolimit/) { + $checked = ' checked="checked"'; + } + } + $cell{$item} .= ' '; + if ($option eq 'autolimit') { + $cell{$item} .= ''; + } + if ($option eq 'autolimit') { + $cell{$item} .= $titles{'unlimited'}; + } + $cell{$item} .= '  '; + } + } else { + my $checked = 'checked="checked" '; + if (ref($settings) eq 'HASH') { + if (ref($settings->{$item}) eq 'HASH') { + if ($settings->{$item}->{$type} == 0) { + $checked = ''; + } elsif ($settings->{$item}->{$type} == 1) { + $checked = 'checked="checked" '; + } + } + } + $datatable .= '  '; + } + } + if ($context eq 'requestcourses') { + $datatable .= ''; + foreach my $item (@usertools) { + $datatable .= ''; + } + $datatable .= '
'.$titles{$item}.'
'.$cell{$item}.'
'; + } + $datatable .= '
'. ' Mb
'.$othertitle.''. - ' Mb
'; + if ($context eq 'requestcourses') { + $datatable .= ''; + } + my %defcell; + foreach my $item (@usertools) { + if ($context eq 'requestcourses') { + my ($curroption,$currlimit); + if (ref($settings) eq 'HASH') { + if (ref($settings->{$item}) eq 'HASH') { + $curroption = $settings->{$item}->{'default'}; + if ($curroption =~ /^autolimit=(\d*)$/) { + $currlimit = $1; + } + } + } + if (!$curroption) { + $curroption = 'norequest'; + } + $datatable .= ''; + foreach my $option (@options) { + my $val = $option; + if ($option eq 'norequest') { + $val = 0; + } + if ($option eq 'validate') { + my $canvalidate = 0; + if (ref($validations{$item}) eq 'HASH') { + if ($validations{$item}{'default'}) { + $canvalidate = 1; + } + } + next if (!$canvalidate); + } + my $checked = ''; + if ($option eq $curroption) { + $checked = ' checked="checked"'; + } elsif ($option eq 'autolimit') { + if ($curroption =~ /^autolimit/) { + $checked = ' checked="checked"'; + } + } + $defcell{$item} .= ''; + if ($option eq 'autolimit') { + $defcell{$item} .= ''; + } + $defcell{$item} .= '  '; + if ($option eq 'autolimit') { + $defcell{$item} .= $titles{'unlimited'}; + } + } + } else { + my $checked = 'checked="checked" '; + if (ref($settings) eq 'HASH') { + if (ref($settings->{$item}) eq 'HASH') { + if ($settings->{$item}->{'default'} == 0) { + $checked = ''; + } elsif ($settings->{$item}->{'default'} == 1) { + $checked = 'checked="checked" '; + } + } + } + $datatable .= '  '; + } + } + if ($context eq 'requestcourses') { + $datatable .= ''; + foreach my $item (@usertools) { + $datatable .= ''; + } + $datatable .= '
'.$titles{$item}.'
'.$defcell{$item}.'
'; + } + $datatable .= '
'. + ' Mb
'.&mt('LON-CAPA Advanced Users').' '; + if ($context eq 'requestcourses') { + $datatable .= &mt('(overrides affiliation, if set)'). + ''. + ''; + } else { + $datatable .= &mt('(overrides affiliation, if checked)'). + ''. + ''; + my $checked = ''; + if ($curroption eq '') { + $checked = ' checked="checked"'; + } + $advcell{$item} .= '  '; + foreach my $option (@options) { + my $val = $option; + if ($option eq 'norequest') { + $val = 0; + } + if ($option eq 'validate') { + my $canvalidate = 0; + if (ref($validations{$item}) eq 'HASH') { + if ($validations{$item}{'_LC_adv'}) { + $canvalidate = 1; + } + } + next if (!$canvalidate); + } + my $checked = ''; + if ($val eq $curroption) { + $checked = ' checked="checked"'; + } elsif ($option eq 'autolimit') { + if ($curroption =~ /^autolimit/) { + $checked = ' checked="checked"'; + } + } + $advcell{$item} .= ''; + if ($option eq 'autolimit') { + $advcell{$item} .= ''; + } + $advcell{$item} .= '  '; + if ($option eq 'autolimit') { + $advcell{$item} .= $titles{'unlimited'}; + } + } + } else { + my $checked = 'checked="checked" '; + if (ref($settings) eq 'HASH') { + if (ref($settings->{$item}) eq 'HASH') { + if ($settings->{$item}->{'_LC_adv'} == 0) { + $checked = ''; + } elsif ($settings->{$item}->{'_LC_adv'} == 1) { + $checked = 'checked="checked" '; + } + } + } + $datatable .= '  '; + } + } + if ($context eq 'requestcourses') { + $datatable .= ''; + foreach my $item (@usertools) { + $datatable .= ''; + } + $datatable .= '
'. + '
'; + } + my %advcell; + foreach my $item (@usertools) { + if ($context eq 'requestcourses') { + my ($curroption,$currlimit); + if (ref($settings) eq 'HASH') { + if (ref($settings->{$item}) eq 'HASH') { + $curroption = $settings->{$item}->{'_LC_adv'}; + if ($curroption =~ /^autolimit=(\d*)$/) { + $currlimit = $1; + } + } + } + if (!$curroption) { + $curroption = 'norequest'; + } + $datatable .= '
'.$titles{$item}.'
'.$advcell{$item}.'
'; + } + $datatable .= '
'.&mt('Receive notification of course requests requiring approval.'). + ' '; + 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 .= '
'; + } else { + $datatable .= &mt('There are no active Domain Coordinators'); + $rows ++; + } + $datatable .='
'.$titles->{$item}. ''. '
'. $titles->{$type}.':
'.$lt{$item}. ''; - my @options = ('any'); + my @options; if ($item eq 'selfcreate') { push(@options,('email','login','sso')); } else { + @options = ('any'); if (ref($rules) eq 'HASH') { if (keys(%{$rules}) > 0) { push(@options,('official','unofficial')); } } + push(@options,'none'); } - push(@options,'none'); foreach my $option (@options) { + my $type = 'radio'; my $check = ' '; - if ($checked{$item} eq $option) { - $check = ' checked="checked" '; + if ($item eq 'selfcreate') { + $type = 'checkbox'; + if (grep(/^\Q$option\E$/,@selfcreate)) { + $check = ' checked="checked" '; + } + } else { + if ($checked{$item} eq $option) { + $check = ' checked="checked" '; + } } $datatable .= '  '; } $datatable .= '
'. - &mt("Format rules to check for $text{$type}: "). - ''; + ''. + '
'; + if ($type eq 'email') { + $output .= &mt("Formats disallowed for $text{$type}: "); + } else { + $output .= &mt("Format rules to check for $text{$type}: "); + } + $output .= ''; my $rem; if (ref($ruleorder) eq 'ARRAY') { for (my $i=0; $i<@{$ruleorder}; $i++) { @@ -1689,17 +2127,18 @@ sub usercreation_types { my %lt = &Apache::lonlocal::texthash ( author => 'When adding a co-author', course => 'When adding a user to a course', + requestcrs => 'When requesting a course', selfcreate => 'User creates own account', any => 'Any', official => 'Institutional only ', unofficial => 'Non-institutional only', - email => 'Email address', + email => 'E-mail address', login => 'Institutional Login', sso => 'SSO', none => 'None', ); return %lt; -} +} sub authtype_names { my %lt = &Apache::lonlocal::texthash( @@ -1733,7 +2172,7 @@ sub print_usermodification { $$rowtotal ++; $rowcount ++; } - } else { + } elsif ($position eq 'middle') { $context = 'course'; $rowcount = 0; foreach my $role ('st','ep','ta','in','cr') { @@ -1742,13 +2181,28 @@ sub print_usermodification { $$rowtotal ++; $rowcount ++; } + } elsif ($position eq 'bottom') { + $context = 'selfcreate'; + my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); + $usertypes->{'default'} = $othertitle; + if (ref($types) eq 'ARRAY') { + push(@{$types},'default'); + $usertypes->{'default'} = $othertitle; + foreach my $status (@{$types}) { + $datatable .= &modifiable_userdata_row($context,$status,$settings, + $numinrow,$rowcount,$usertypes); + $$rowtotal ++; + $rowcount ++; + } + } } return $datatable; } sub print_defaults { my ($dom,$rowtotal) = @_; - my @items = ('auth_def','auth_arg_def','lang_def'); + my @items = ('auth_def','auth_arg_def','lang_def','timezone_def', + 'datelocale_def'); my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); my $titles = &defaults_titles(); my $rownum = 0; @@ -1780,6 +2234,12 @@ sub print_defaults { '" value="'.$auth.'"'.$checked.'/>'. $authnames{$shortauth{$auth}}.'  '; } + } elsif ($item eq 'timezone_def') { + my $includeempty = 1; + $datatable .= &Apache::loncommon::select_timezone($item,$domdefaults{$item},undef,$includeempty); + } elsif ($item eq 'datelocale_def') { + my $includeempty = 1; + $datatable .= &Apache::loncommon::select_datelocale($item,$domdefaults{$item},undef,$includeempty); } else { $datatable .= ''; @@ -1796,6 +2256,8 @@ sub defaults_titles { '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', ); return (\%titles); } @@ -1803,11 +2265,12 @@ sub defaults_titles { sub print_scantronformat { my ($r,$dom,$confname,$settings,$rowtotal) = @_; my $itemcount = 1; - my ($datatable,$css_class,$scantronurl,$is_custom,%error,%scantronurls); + my ($datatable,$css_class,$scantronurl,$is_custom,%error,%scantronurls, + %confhash); my $switchserver = &check_switchserver($dom,$confname); my %lt = &Apache::lonlocal::texthash ( - default => 'Default scantron format file error', - custom => 'Custom scantron format file error', + default => 'Default bubblesheet format file error', + custom => 'Custom bubblesheet format file error', ); my %scantronfiles = ( default => 'default.tab', @@ -1830,28 +2293,57 @@ sub print_scantronformat { ); my %md5chk; foreach my $type (keys(%legacyfile)) { - $md5chk{$type} = split(/ /,`md5sum $legacyfile{$type}`); - chop($md5chk{$type}); + ($md5chk{$type}) = split(/ /,`md5sum $legacyfile{$type}`); + chomp($md5chk{$type}); } if ($md5chk{'default'} ne $md5chk{'custom'}) { foreach my $type (keys(%legacyfile)) { - ($scantronurls{$type},$error{$type}) = + ($scantronurls{$type},my $error) = &legacy_scantronformat($r,$dom,$confname, $type,$legacyfile{$type}, $scantronurls{$type}, $scantronfiles{$type}); + if ($error ne '') { + $error{$type} = $error; + } + } + if (keys(%error) == 0) { + $is_custom = 1; + $confhash{'scantron'}{'scantronformat'} = + $scantronurls{'custom'}; + my $putresult = + &Apache::lonnet::put_dom('configuration', + \%confhash,$dom); + if ($putresult ne 'ok') { + $error{'custom'} = + ''. + &mt('An error occurred updating the domain configuration: [_1]',$putresult).''; + } } } else { - ($scantronurls{'default'},$error{'default'}) = + ($scantronurls{'default'},my $error) = &legacy_scantronformat($r,$dom,$confname, 'default',$legacyfile{'default'}, $scantronurls{'default'}, $scantronfiles{'default'}); + if ($error eq '') { + $confhash{'scantron'}{'scantronformat'} = ''; + my $putresult = + &Apache::lonnet::put_dom('configuration', + \%confhash,$dom); + if ($putresult ne 'ok') { + $error{'default'} = + ''. + &mt('An error occurred updating the domain configuration: [_1]',$putresult).''; + } + } else { + $error{'default'} = $error; + } } } } } else { - $error{'default'} = &mt("Unable to copy default scantron formatfile to domain's RES space: [_1]",$switchserver); + $error{'default'} = &mt("Unable to copy default bubblesheet formatfile to domain's RES space: [_1]",$switchserver); } } if (ref($settings) eq 'HASH') { @@ -1867,39 +2359,59 @@ sub print_scantronformat { $scantronurl = $scantronurls{'default'}; } } else { - $scantronurl = $scantronurls{'default'}; + if ($is_custom) { + $scantronurl = $scantronurls{'custom'}; + } else { + $scantronurl = $scantronurls{'default'}; + } } $css_class = $itemcount%2?' class="LC_odd_row"':''; $datatable .= ''; if (!$is_custom) { - $datatable .= ''; + if (keys(%error) == 0) { + $datatable .= '' - .''. + ''; @@ -1922,13 +2434,422 @@ sub legacy_scantronformat { return ($url,$error); } +sub print_coursecategories { + my ($position,$dom,$hdritem,$settings,$rowtotal) = @_; + my $datatable; + if ($position eq 'top') { + my $toggle_cats_crs = ' '; + my $toggle_cats_dom = ' checked="checked" '; + my $can_cat_crs = ' '; + my $can_cat_dom = ' checked="checked" '; + if (ref($settings) eq 'HASH') { + if ($settings->{'togglecats'} eq 'crs') { + $toggle_cats_crs = $toggle_cats_dom; + $toggle_cats_dom = ' '; + } + if ($settings->{'categorize'} eq 'crs') { + $can_cat_crs = $can_cat_dom; + $can_cat_dom = ' '; + } + } + my %title = &Apache::lonlocal::texthash ( + togglecats => 'Show/Hide a course in the catalog', + categorize => 'Assign a category to a course', + ); + my %level = &Apache::lonlocal::texthash ( + dom => 'Set in "Modify Course" (Domain)', + crs => 'Set in "Modify Parameters" (Course)', + ); + $datatable = ''. + ''. + ''. + ''. + ''. + ''. + ''; + $$rowtotal += 2; + } else { + my $css_class; + my $itemcount = 1; + my $cathash; + if (ref($settings) eq 'HASH') { + $cathash = $settings->{'cats'}; + } + if (ref($cathash) eq 'HASH') { + my (@cats,@trails,%allitems,%idx,@jsarray); + &Apache::loncommon::extract_categories($cathash,\@cats,\@trails, + \%allitems,\%idx,\@jsarray); + my $maxdepth = scalar(@cats); + my $colattrib = ''; + if ($maxdepth > 2) { + $colattrib = ' colspan="2" '; + } + my @path; + if (@cats > 0) { + if (ref($cats[0]) eq 'ARRAY') { + my $numtop = @{$cats[0]}; + my $maxnum = $numtop; + if ((!grep(/^instcode$/,@{$cats[0]})) || ($cathash->{'instcode::0'} eq '')) { + $maxnum ++; + } + my $lastidx; + for (my $i=0; $i<$numtop; $i++) { + my $parent = $cats[0][$i]; + $css_class = $itemcount%2?' class="LC_odd_row"':''; + my $item = &escape($parent).'::0'; + my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','$item','$idx{$item}'".');"'; + $lastidx = $idx{$item}; + $datatable .= '' + .' ' + .''; + } else { + $datatable .= $parent + .' '; + } + my $depth = 1; + push(@path,$parent); + $datatable .= &build_category_rows($itemcount,\@cats,$depth,$parent,\@path,\%idx); + pop(@path); + $datatable .= ''; + $itemcount ++; + } + $css_class = $itemcount%2?' class="LC_odd_row"':''; + my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','addcategory_pos','$lastidx'".');"'; + $datatable .= '' + .''."\n"; + $itemcount ++; + if ((!grep(/^instcode$/,@{$cats[0]})) || ($cathash->{'instcode::0'} eq '')) { + $css_class = $itemcount%2?' class="LC_odd_row"':''; + my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','instcode_pos','$lastidx'".');"'; + $datatable .= '' + .''; + } + } + } else { + $datatable .= &initialize_categories($itemcount); + } + } else { + $datatable .= '' + .&initialize_categories($itemcount); + } + $$rowtotal += $itemcount; + } + return $datatable; +} + +sub print_serverstatuses { + my ($dom,$settings,$rowtotal) = @_; + my $datatable; + my @pages = &serverstatus_pages(); + my (%namedaccess,%machineaccess); + foreach my $type (@pages) { + $namedaccess{$type} = ''; + $machineaccess{$type}= ''; + } + if (ref($settings) eq 'HASH') { + foreach my $type (@pages) { + if (exists($settings->{$type})) { + if (ref($settings->{$type}) eq 'HASH') { + foreach my $key (keys(%{$settings->{$type}})) { + if ($key eq 'namedusers') { + $namedaccess{$type} = $settings->{$type}->{$key}; + } elsif ($key eq 'machines') { + $machineaccess{$type} = $settings->{$type}->{$key}; + } + } + } + } + } + } + my $titles= &LONCAPA::lonauthcgi::serverstatus_titles(); + my $rownum = 0; + my $css_class; + foreach my $type (@pages) { + $rownum ++; + $css_class = $rownum%2?' class="LC_odd_row"':''; + $datatable .= ''. + ''. + ''. + ''."\n"; + } + $$rowtotal += $rownum; + return $datatable; +} + +sub serverstatus_pages { + return ('userstatus','lonstatus','loncron','server-status','codeversions', + 'clusterstatus','metadata_keywords','metadata_harvest', + 'takeoffline','takeonline','showenv'); +} + +sub coursecategories_javascript { + my ($settings) = @_; + my ($output,$jstext,$cathash); + if (ref($settings) eq 'HASH') { + $cathash = $settings->{'cats'}; + } + if (ref($cathash) eq 'HASH') { + my (@cats,@jsarray,%idx); + &Apache::loncommon::gather_categories($cathash,\@cats,\%idx,\@jsarray); + if (@jsarray > 0) { + $jstext = ' var categories = Array('.scalar(@jsarray).');'."\n"; + for (my $i=0; $i<@jsarray; $i++) { + if (ref($jsarray[$i]) eq 'ARRAY') { + my $catstr = join('","',@{$jsarray[$i]}); + $jstext .= ' categories['.$i.'] = Array("'.$catstr.'");'."\n"; + } + } + } + } else { + $jstext = ' var categories = Array(1);'."\n". + ' categories[0] = Array("instcode_pos");'."\n"; + } + $output = <<"ENDSCRIPT"; + + +ENDSCRIPT + return $output; +} + +sub initialize_categories { + my ($itemcount) = @_; + my $datatable; + my $css_class = $itemcount%2?' class="LC_odd_row"':''; + my $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','instcode_pos','0'".');"'; + + $datatable = ''; + $itemcount ++; + $css_class = $itemcount%2?' class="LC_odd_row"':''; + $chgstr = ' onchange="javascript:reorderCats(this.form,'."'','addcategory_pos','0'".');"'; + $datatable .= ''; + return $datatable; +} + +sub build_category_rows { + my ($itemcount,$cats,$depth,$parent,$path,$idx) = @_; + my ($text,$name,$item,$chgstr); + if (ref($cats) eq 'ARRAY') { + my $maxdepth = scalar(@{$cats}); + if (ref($cats->[$depth]) eq 'HASH') { + if (ref($cats->[$depth]{$parent}) eq 'ARRAY') { + my $numchildren = @{$cats->[$depth]{$parent}}; + my $css_class = $itemcount%2?' class="LC_odd_row"':''; + $text .= ''; + } else { + my $higher = $depth-1; + if ($higher == 0) { + $name = &escape($parent).'::'.$higher; + } else { + if (ref($path) eq 'ARRAY') { + $name = &escape($parent).':'.&escape($path->[-2]).':'.$higher; + } + } + my $colspan; + if ($parent ne 'instcode') { + $colspan = $maxdepth - $depth - 1; + $text .= ''; + } + } + } + } + return $text; +} + sub modifiable_userdata_row { - my ($context,$role,$settings,$numinrow,$rowcount) = @_; + my ($context,$role,$settings,$numinrow,$rowcount,$usertypes) = @_; my $rolename; - if ($role eq 'cr') { - $rolename = &mt('Custom role'); + if ($context eq 'selfcreate') { + if (ref($usertypes) eq 'HASH') { + $rolename = $usertypes->{$role}; + } else { + $rolename = $role; + } } else { - $rolename = &Apache::lonnet::plaintext($role); + if ($role eq 'cr') { + $rolename = &mt('Custom role'); + } else { + $rolename = &Apache::lonnet::plaintext($role); + } } my @fields = ('lastname','firstname','middlename','generation', 'permanentemail','id'); @@ -1987,10 +2908,18 @@ sub modifiable_userdata_row { return $output; } -sub users_cansearch_row { - my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle) = @_; +sub insttypes_row { + my ($settings,$types,$usertypes,$dom,$numinrow,$othertitle,$context) = @_; + my %lt = &Apache::lonlocal::texthash ( + cansearch => 'Users allowed to search', + statustocreate => 'Institutional affiliation(s) able to create own account (login/SSO)', + ); + my $showdom; + if ($context eq 'cansearch') { + $showdom = ' ('.$dom.')'; + } my $output = ''. - ''; @@ -2138,34 +3075,36 @@ sub modify_login { 'adminmail' => 'off', 'newuser' => 'off', ); - foreach my $item (@toggles) { - if ($defaultchecked{$item} eq 'on') { - if (($domconfig{'login'}{$item} eq '0') && - ($env{'form.'.$item} eq '1')) { - $changes{$item} = 1; - } elsif (($domconfig{'login'}{$item} eq '' || - $domconfig{'login'}{$item} eq '1') && - ($env{'form.'.$item} eq '0')) { - $changes{$item} = 1; - } - } elsif ($defaultchecked{$item} eq 'off') { - if (($domconfig{'login'}{$item} eq '1') && - ($env{'form.'.$item} eq '0')) { - $changes{$item} = 1; - } elsif (($domconfig{'login'}{$item} eq '' || - $domconfig{'login'}{$item} eq '0') && - ($env{'form.'.$item} eq '1')) { - $changes{$item} = 1; + if (ref($domconfig{'login'}) eq 'HASH') { + foreach my $item (@toggles) { + if ($defaultchecked{$item} eq 'on') { + if (($domconfig{'login'}{$item} eq '0') && + ($env{'form.'.$item} eq '1')) { + $changes{$item} = 1; + } elsif (($domconfig{'login'}{$item} eq '' || + $domconfig{'login'}{$item} eq '1') && + ($env{'form.'.$item} eq '0')) { + $changes{$item} = 1; + } + } elsif ($defaultchecked{$item} eq 'off') { + if (($domconfig{'login'}{$item} eq '1') && + ($env{'form.'.$item} eq '0')) { + $changes{$item} = 1; + } elsif (($domconfig{'login'}{$item} eq '' || + $domconfig{'login'}{$item} eq '0') && + ($env{'form.'.$item} eq '1')) { + $changes{$item} = 1; + } } } - } - 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 (($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); @@ -2198,6 +3137,7 @@ sub color_font_choices { img => "Header", bgs => "Background colors", links => "Link colors", + images => "Images", font => "Font color", pgbg => "Page", tabbg => "Header", @@ -2213,6 +3153,11 @@ sub modify_rolecolors { my ($r,$dom,$confname,$roles,%domconfig) = @_; my ($resulttext,%rolehash); $rolehash{'rolecolors'} = {}; + if (ref($domconfig{'rolecolors'}) ne 'HASH') { + if ($domconfig{'rolecolors'} eq '') { + $domconfig{'rolecolors'} = {}; + } + } my ($errors,%changes) = &modify_colors($r,$dom,$confname,$roles, $domconfig{'rolecolors'},$rolehash{'rolecolors'}); my $putresult = &Apache::lonnet::put_dom('configuration',\%rolehash, @@ -2239,7 +3184,7 @@ sub modify_rolecolors { sub modify_colors { my ($r,$dom,$confname,$roles,$domconfig,$confhash) = @_; my (%changes,%choices); - my @bgs = ('pgbg','mainbg','sidebg'); + my @bgs; my @links = ('link','alink','vlink'); my @logintext; my @images; @@ -2254,8 +3199,10 @@ sub modify_colors { } if ($role eq 'login') { @images = ('img','logo','domlogo','login'); + @bgs = ('pgbg','mainbg','sidebg'); } else { @images = ('img'); + @bgs = ('pgbg','tabbg','sidebg'); } $confhash->{$role}{'font'} = $env{'form.'.$role.'_font'}; foreach my $item (@bgs,@links,@logintext) { @@ -2268,6 +3215,13 @@ sub modify_colors { $domconfig->{$role} = {}; } foreach my $img (@images) { + if (($role eq 'login') && (($img eq 'img') || ($img eq 'logo'))) { + if (defined($env{'form.login_showlogo_'.$img})) { + $confhash->{$role}{'showlogo'}{$img} = 1; + } else { + $confhash->{$role}{'showlogo'}{$img} = 0; + } + } if ( ! $env{'form.'.$role.'_'.$img.'.filename'} && !defined($domconfig->{$role}{$img}) && !$env{'form.'.$role.'_del_'.$img} @@ -2342,7 +3296,19 @@ sub modify_colors { $changes{$role}{'images'}{$img} = 1; } } - } + if (($role eq 'login') && (($img eq 'logo') || ($img eq 'img'))) { + if (ref($domconfig->{'login'}{'showlogo'}) eq 'HASH') { + if ($confhash->{$role}{'showlogo'}{$img} ne + $domconfig->{$role}{'showlogo'}{$img}) { + $changes{$role}{'showlogo'}{$img} = 1; + } + } else { + if ($confhash->{$role}{'showlogo'}{$img} == 0) { + $changes{$role}{'showlogo'}{$img} = 1; + } + } + } + } if ($domconfig->{$role}{'font'} ne '') { if ($confhash->{$role}{'font'} ne $domconfig->{$role}{'font'}) { $changes{$role}{'font'} = 1; @@ -2434,11 +3400,16 @@ sub default_change_checker { $confhash->{$role}{$img} = ''; $changes->{$role}{'images'}{$img} = 1; } + if ($role eq 'login') { + if ($confhash->{$role}{'showlogo'}{$img} == 0) { + $changes->{$role}{'showlogo'}{$img} = 1; + } + } } if ($confhash->{$role}{'font'}) { $changes->{$role}{'font'} = 1; } -} +} sub display_colorchgs { my ($dom,$changes,$roles,$confhash) = @_; @@ -2465,7 +3436,13 @@ sub display_colorchgs { $resulttext .= '
  • '.&mt($choices{$key}).':
      '; } foreach my $item (sort(keys(%{$changes->{$role}{$key}}))) { - if ($confhash->{$role}{$item} eq '') { + if (($role eq 'login') && ($key eq 'showlogo')) { + if ($confhash->{$role}{$key}{$item}) { + $resulttext .= '
    • '.&mt("$choices{$item} set to be displayed").'
    • '; + } else { + $resulttext .= '
    • '.&mt("$choices{$item} set to not be displayed").'
    • '; + } + } elsif ($confhash->{$role}{$item} eq '') { $resulttext .= '
    • '.&mt("$choices{$item} set to default").'
    • '; } else { my $newitem = $confhash->{$role}{$item}; @@ -2770,67 +3747,273 @@ sub check_switchserver { return $switchserver; } -sub javascript_set_colnums { - return < 1100) { - document.pickactions.numcols[1].checked = true; +sub modify_quotas { + my ($dom,$action,%domconfig) = @_; + my ($context,@usertools,@options,%validations,%titles,%confhash,%toolshash, + %limithash,$toolregexp,%conditions,$resulttext,%changes); + if ($action eq 'quotas') { + $context = 'tools'; + } else { + $context = $action; + } + if ($context eq 'requestcourses') { + @usertools = ('official','unofficial','community'); + @options =('norequest','approval','autolimit','validate'); + %validations = &Apache::lonnet::auto_courserequest_checks($dom); + %titles = &courserequest_titles(); + $toolregexp = join('|',@usertools); + %conditions = &courserequest_conditions(); } else { - document.pickactions.numcols[0].checked = true; + @usertools = ('aboutme','blog','portfolio'); + %titles = &tool_titles(); } -} -END -} - -sub modify_quotas { - my ($dom,%domconfig) = @_; - my ($resulttext,%changes); + my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); - my %formhash; foreach my $key (keys(%env)) { - if ($key =~ /^form\.quota_(.+)$/) { - $formhash{$1} = $env{$key}; + if ($context eq 'requestcourses') { + if ($key =~ /^form\.crsreq_($toolregexp)_(.+)$/) { + my $item = $1; + my $type = $2; + if ($type =~ /^limit_(.+)/) { + $limithash{$item}{$1} = $env{$key}; + } else { + $confhash{$item}{$type} = $env{$key}; + } + } + } else { + if ($key =~ /^form\.quota_(.+)$/) { + $confhash{'defaultquota'}{$1} = $env{$key}; + } + if ($key =~ /^form\.\Q$context\E_(.+)$/) { + @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key); + } } } - $formhash{'default'} = $env{'form.defaultquota'}; - if (ref($domconfig{'quotas'}) eq 'HASH') { - foreach my $key (keys(%{$domconfig{'quotas'}})) { - if (exists($formhash{$key})) { - if ($formhash{$key} ne $domconfig{'quotas'}{$key}) { - $changes{$key} = 1; + if ($context eq 'requestcourses') { + my @approvalnotify = &Apache::loncommon::get_env_multiple('form.reqapprovalnotify'); + @approvalnotify = sort(@approvalnotify); + $confhash{'notify'}{'approval'} = join(',',@approvalnotify); + if (ref($domconfig{$action}) eq 'HASH') { + if (ref($domconfig{$action}{'notify'}) eq 'HASH') { + if ($domconfig{$action}{'notify'}{'approval'} ne $confhash{'notify'}{'approval'}) { + $changes{'notify'}{'approval'} = 1; } } else { - $formhash{$key} = $domconfig{'quotas'}{$key}; + if ($domconfig{$action}{'notify'}{'approval'}) { + $changes{'notify'}{'approval'} = 1; + } + } + } else { + if ($domconfig{$action}{'notify'}{'approval'}) { + $changes{'notify'}{'approval'} = 1; } } + } else { + $confhash{'defaultquota'}{'default'} = $env{'form.defaultquota'}; } - foreach my $key (keys(%formhash)) { - if ($formhash{$key} ne '') { - if (!exists($domconfig{'quotas'}{$key})) { - $changes{$key} = 1; + foreach my $item (@usertools) { + foreach my $type (@{$types},'default','_LC_adv') { + my $unset; + if ($context eq 'requestcourses') { + $unset = '0'; + if ($type eq '_LC_adv') { + $unset = ''; + } + if ($confhash{$item}{$type} eq 'autolimit') { + $confhash{$item}{$type} .= '='; + unless ($limithash{$item}{$type} =~ /\D/) { + $confhash{$item}{$type} .= $limithash{$item}{$type}; + } + } + } else { + if (grep(/^\Q$type\E$/,@{$toolshash{$item}})) { + $confhash{$item}{$type} = 1; + } else { + $confhash{$item}{$type} = 0; + } + } + if (ref($domconfig{$action}) eq 'HASH') { + if (ref($domconfig{$action}{$item}) eq 'HASH') { + if ($domconfig{$action}{$item}{$type} ne $confhash{$item}{$type}) { + $changes{$item}{$type} = 1; + } + } else { + if ($context eq 'requestcourses') { + if ($confhash{$item}{$type} ne $unset) { + $changes{$item}{$type} = 1; + } + } else { + if (!$confhash{$item}{$type}) { + $changes{$item}{$type} = 1; + } + } + } + } else { + if ($context eq 'requestcourses') { + if ($confhash{$item}{$type} ne $unset) { + $changes{$item}{$type} = 1; + } + } else { + if (!$confhash{$item}{$type}) { + $changes{$item}{$type} = 1; + } + } + } + } + } + unless ($context eq 'requestcourses') { + if (ref($domconfig{'quotas'}) eq 'HASH') { + if (ref($domconfig{'quotas'}{'defaultquota'}) eq 'HASH') { + foreach my $key (keys(%{$domconfig{'quotas'}{'defaultquota'}})) { + if (exists($confhash{'defaultquota'}{$key})) { + if ($confhash{'defaultquota'}{$key} ne $domconfig{'quotas'}{'defaultquota'}{$key}) { + $changes{'defaultquota'}{$key} = 1; + } + } else { + $confhash{'defaultquota'}{$key} = $domconfig{'quotas'}{'defaultquota'}{$key}; + } + } + } else { + foreach my $key (keys(%{$domconfig{'quotas'}})) { + if (exists($confhash{'defaultquota'}{$key})) { + if ($confhash{'defaultquota'}{$key} ne $domconfig{'quotas'}{$key}) { + $changes{'defaultquota'}{$key} = 1; + } + } else { + $confhash{'defaultquota'}{$key} = $domconfig{'quotas'}{$key}; + } + } + } + } + if (ref($confhash{'defaultquota'}) eq 'HASH') { + foreach my $key (keys(%{$confhash{'defaultquota'}})) { + if (ref($domconfig{'quotas'}) eq 'HASH') { + if (ref($domconfig{'quotas'}{'defaultquota'}) eq 'HASH') { + if (!exists($domconfig{'quotas'}{'defaultquota'}{$key})) { + $changes{'defaultquota'}{$key} = 1; + } + } else { + if (!exists($domconfig{'quotas'}{$key})) { + $changes{'defaultquota'}{$key} = 1; + } + } + } else { + $changes{'defaultquota'}{$key} = 1; + } } } } + + foreach my $key (keys(%confhash)) { + $domdefaults{$key} = $confhash{$key}; + } + my %quotahash = ( - quotas => {%formhash}, + $action => { %confhash } ); my $putresult = &Apache::lonnet::put_dom('configuration',\%quotahash, $dom); if ($putresult eq 'ok') { if (keys(%changes) > 0) { + my $cachetime = 24*60*60; + &Apache::lonnet::do_cache_new('domdefaults',$dom,\%domdefaults,$cachetime); + $resulttext = &mt('Changes made:').'
        '; - foreach my $type (@{$types},'default') { - if (defined($changes{$type})) { - my $typetitle = $usertypes->{$type}; - if ($type eq 'default') { - $typetitle = $othertitle; + unless ($context eq 'requestcourses') { + if (ref($changes{'defaultquota'}) eq 'HASH') { + $resulttext .= '
      • '.&mt('Portfolio default quotas').'
          '; + foreach my $type (@{$types},'default') { + if (defined($changes{'defaultquota'}{$type})) { + my $typetitle = $usertypes->{$type}; + if ($type eq 'default') { + $typetitle = $othertitle; + } + $resulttext .= '
        • '.&mt('[_1] set to [_2] Mb',$typetitle,$confhash{'defaultquota'}{$type}).'
        • '; + } + } + $resulttext .= '
      • '; + } + } + my %newenv; + foreach my $item (@usertools) { + if (ref($changes{$item}) eq 'HASH') { + my $newacc = + &Apache::lonnet::usertools_access($env{'user.name'}, + $env{'user.domain'}, + $item,'reload',$context); + if ($context eq 'requestcourses') { + if ($env{'environment.canrequest.'.$item} ne $newacc) { + $newenv{'environment.canrequest.'.$item} = $newacc; + } + } else { + if ($env{'environment.availabletools.'.$item} ne $newacc) { + $newenv{'environment.availabletools.'.$item} = $newacc; + } + } + $resulttext .= '
      • '.$titles{$item}.'
          '; + foreach my $type (@{$types},'default','_LC_adv') { + if ($changes{$item}{$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 ($context eq 'requestcourses') { + my $cond; + if ($confhash{$item}{$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}}; + } + $resulttext .= '
        • '.&mt('Set to be available to [_1].',$typetitle).' '.$cond.'
        • '; + } else { + $resulttext .= '
        • '.&mt('Set to be available to [_1]',$typetitle).'
        • '; + } + } else { + if ($type eq '_LC_adv') { + if ($confhash{$item}{$type} eq '0') { + $resulttext .= '
        • '.&mt('Set to be unavailable to [_1]',$typetitle).'
        • '; + } else { + $resulttext .= '
        • '.&mt('No override set for [_1]',$typetitle).'
        • '; + } + } else { + $resulttext .= '
        • '.&mt('Set to be unavailable to [_1]',$typetitle).'
        • '; + } + } + } + } + $resulttext .= '
      • '; + } + } + if ($action eq 'requestcourses') { + 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('[_1] set to [_2] Mb',$typetitle,$formhash{$type}).'
      • '; } } $resulttext .= '
      '; + if (keys(%newenv)) { + &Apache::lonnet::appenv(\%newenv); + } } else { - $resulttext = &mt('No changes made to default quotas'); + if ($context eq 'requestcourses') { + $resulttext = &mt('No changes made to rights to request creation of courses.'); + } else { + $resulttext = &mt('No changes made to availability of personal information pages, blogs, portfolios or default quotas'); + } } } else { $resulttext = ''. @@ -3213,7 +4396,8 @@ sub modify_contacts { } my (%others,%to); my @contacts = ('supportemail','adminemail'); - my @mailings = ('errormail','packagesmail','helpdeskmail'); + my @mailings = ('errormail','packagesmail','helpdeskmail','lonstatusmail', + 'requestsmail'); foreach my $type (@mailings) { @{$newsetting{$type}} = &Apache::loncommon::get_env_multiple('form.'.$type); @@ -3258,6 +4442,8 @@ sub modify_contacts { $default{'errormail'} = 'adminemail'; $default{'packagesmail'} = 'adminemail'; $default{'helpdeskmail'} = 'supportemail'; + $default{'lonstatusmail'} = 'adminemail'; + $default{'requestsmail'} = 'adminemail'; foreach my $item (@contacts) { if ($to{$item} ne $default{$item}) { $changes{$item} = 1; @@ -3324,23 +4510,96 @@ sub modify_usercreation { my @username_rule = &Apache::loncommon::get_env_multiple('form.username_rule'); my @id_rule = &Apache::loncommon::get_env_multiple('form.id_rule'); my @email_rule = &Apache::loncommon::get_env_multiple('form.email_rule'); - my @contexts = ('author','course','selfcreate'); + my @contexts = ('author','course','requestcrs','selfcreate'); foreach my $item(@contexts) { - $cancreate{$item} = $env{'form.can_createuser_'.$item}; if ($item eq 'selfcreate') { + @{$cancreate{$item}} = &Apache::loncommon::get_env_multiple('form.can_createuser_'.$item); my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); if (!((($domdefaults{'auth_def'} =~/^krb/) && ($domdefaults{'auth_arg_def'} ne '')) || ($domdefaults{'auth_def'} eq 'localauth'))) { - if (($cancreate{$item} eq 'any') || ($cancreate{$item} eq 'login')) { - $warningmsg = &mt('Although account creation has been set to be available for institutional logins, currently default authentication in this domain has not been set to support this.').' '.&mt('You need to set the default authentication type to Kerberos 4 or 5 (with a Kerberos domain specified), or to Local authentication, if the localauth module has been customized in your domain to authenticate institutional logins.'); + if (ref($cancreate{$item}) eq 'ARRAY') { + if (grep(/^login$/,@{$cancreate{$item}})) { + $warningmsg = &mt('Although account creation has been set to be available for institutional logins, currently default authentication in this domain has not been set to support this.').' '.&mt('You need to set the default authentication type to Kerberos 4 or 5 (with a Kerberos domain specified), or to Local authentication, if the localauth module has been customized in your domain to authenticate institutional logins.'); + } } } + } else { + $cancreate{$item} = $env{'form.can_createuser_'.$item}; } } + my ($othertitle,$usertypes,$types) = + &Apache::loncommon::sorted_inst_types($dom); + if (ref($types) eq 'ARRAY') { + if (@{$types} > 0) { + @{$cancreate{'statustocreate'}} = + &Apache::loncommon::get_env_multiple('form.statustocreate'); + } else { + @{$cancreate{'statustocreate'}} = (); + } + push(@contexts,'statustocreate'); + } if (ref($curr_usercreation{'cancreate'}) eq 'HASH') { foreach my $item (@contexts) { - if ($curr_usercreation{'cancreate'}{$item} ne $cancreate{$item}) { - push(@{$changes{'cancreate'}},$item); - } + if (($item eq 'selfcreate') || ($item eq 'statustocreate')) { + if (ref($curr_usercreation{'cancreate'}{$item}) eq 'ARRAY') { + foreach my $curr (@{$curr_usercreation{'cancreate'}{$item}}) { + if (ref($cancreate{$item}) eq 'ARRAY') { + if (!grep(/^$curr$/,@{$cancreate{$item}})) { + if (!grep(/^$item$/,@{$changes{'cancreate'}})) { + push(@{$changes{'cancreate'}},$item); + } + } + } + } + } else { + if ($curr_usercreation{'cancreate'}{$item} eq '') { + if (@{$cancreate{$item}} > 0) { + if (!grep(/^$item$/,@{$changes{'cancreate'}})) { + push(@{$changes{'cancreate'}},$item); + } + } + } else { + if ($curr_usercreation{'cancreate'}{$item} eq 'any') { + if (@{$cancreate{$item}} < 3) { + if (!grep(/^$item$/,@{$changes{'cancreate'}})) { + push(@{$changes{'cancreate'}},$item); + } + } + } elsif ($curr_usercreation{'cancreate'}{$item} eq 'none') { + if (@{$cancreate{$item}} > 0) { + if (!grep(/^$item$/,@{$changes{'cancreate'}})) { + push(@{$changes{'cancreate'}},$item); + } + } + } elsif (!grep(/^$curr_usercreation{'cancreate'}{$item}$/,@{$cancreate{$item}})) { + if (!grep(/^$item$/,@{$changes{'cancreate'}})) { + push(@{$changes{'cancreate'}},$item); + } + } + } + } + if (!grep(/^$item$/,@{$changes{'cancreate'}})) { + foreach my $type (@{$cancreate{$item}}) { + if (ref($curr_usercreation{'cancreate'}{$item}) eq 'ARRAY') { + if (!grep(/^$type$/,@{$curr_usercreation{'cancreate'}{$item}})) { + if (!grep(/^$item$/,@{$changes{'cancreate'}})) { + push(@{$changes{'cancreate'}},$item); + } + } + } elsif (($curr_usercreation{'cancreate'}{$item} ne 'any') && + ($curr_usercreation{'cancreate'}{$item} ne 'none')) { + if ($curr_usercreation{'cancreate'}{$item} ne $type) { + if (!grep(/^$item$/,@{$changes{'cancreate'}})) { + push(@{$changes{'cancreate'}},$item); + } + } + } + } + } + } else { + if ($curr_usercreation{'cancreate'}{$item} ne $cancreate{$item}) { + push(@{$changes{'cancreate'}},$item); + } + } } } elsif (ref($curr_usercreation{'cancreate'}) eq 'ARRAY') { foreach my $item (@contexts) { @@ -3447,24 +4706,77 @@ sub modify_usercreation { my $putresult = &Apache::lonnet::put_dom('configuration',\%usercreation_hash, $dom); + + my %selfcreatetypes = ( + sso => 'users authenticated by institutional single sign on', + login => 'users authenticated by institutional log-in', + email => 'users who provide a valid e-mail address for use as the username', + ); if ($putresult eq 'ok') { if (keys(%changes) > 0) { $resulttext = &mt('Changes made:').'
        '; if (ref($changes{'cancreate'}) eq 'ARRAY') { my %lt = &usercreation_types(); foreach my $type (@{$changes{'cancreate'}}) { - my $chgtext = $lt{$type}.', '; + my $chgtext; + unless ($type eq 'statustocreate') { + $chgtext = $lt{$type}.', '; + } if ($type eq 'selfcreate') { - if ($cancreate{$type} eq 'none') { + if (@{$cancreate{$type}} == 0) { $chgtext .= &mt('creation of a new user account is not permitted.'); - } elsif ($cancreate{$type} eq 'any') { - $chgtext .= &mt('creation of a new account is permitted for users authenticated by institutional log-in and SSO, and also for e-mail addresses used as usernames.'); - } elsif ($cancreate{$type} eq 'login') { - $chgtext .= &mt('creation of a new account is only permitted for users authenticated by institutional log-in.'); - } elsif ($cancreate{$type} eq 'sso') { - $chgtext .= &mt('creation of a new account is only permitted for users authenticated by institutional single sign on.'); - } elsif ($cancreate{$type} eq 'email') { - $chgtext .= &mt('creation of a new account is only permitted for users who provide a valid e-mail address for use as the username.'); + } else { + $chgtext .= &mt('creation of a new account is permitted for:').'
          '; + foreach my $case (@{$cancreate{$type}}) { + $chgtext .= '
        • '.$selfcreatetypes{$case}.'
        • '; + } + $chgtext .= '
        '; + if (ref($cancreate{$type}) eq 'ARRAY') { + if (grep(/^(login|sso)$/,@{$cancreate{$type}})) { + if (ref($cancreate{'statustocreate'}) eq 'ARRAY') { + if (@{$cancreate{'statustocreate'}} == 0) { + $chgtext .= '
        '.&mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts.").''; + } + } + } + } + } + } elsif ($type eq 'statustocreate') { + if ((ref($cancreate{'selfcreate'}) eq 'ARRAY') && + (ref($cancreate{'statustocreate'}) eq 'ARRAY')) { + if (@{$cancreate{'selfcreate'}} > 0) { + if (@{$cancreate{'statustocreate'}} == 0) { + + $chgtext .= &mt("Institutional affiliations permitted to create accounts set to 'None'."); + if (!grep(/^email$/,@{$cancreate{'selfcreate'}})) { + $chgtext .= '
        '.&mt("However, no institutional affiliations (including 'other') are currently permitted to create accounts.").''; + } + } elsif (ref($usertypes) eq 'HASH') { + if (grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) { + $chgtext .= &mt('Creation of a new account for an institutional user is restricted to the following institutional affiliation(s):'); + } else { + $chgtext .= &mt('Institutional affiliations permitted to create accounts with institutional authentication were set as follows:'); + } + $chgtext .= '
          '; + foreach my $case (@{$cancreate{$type}}) { + if ($case eq 'default') { + $chgtext .= '
        • '.$othertitle.'
        • '; + } else { + $chgtext .= '
        • '.$usertypes->{$case}.'
        • '; + } + } + $chgtext .= '
        '; + if (!grep(/^(login|sso)$/,@{$cancreate{'selfcreate'}})) { + $chgtext .= '
        '.&mt('However, users authenticated by institutional login/single sign on are not currently permitted to create accounts.').''; + } + } + } else { + if (@{$cancreate{$type}} == 0) { + $chgtext .= &mt("Institutional affiliations permitted to create accounts were set to 'none'."); + } else { + $chgtext .= &mt('Although institutional affiliations permitted to create accounts were changed, self creation of accounts is not currently permitted for any authentication types.'); + } + } } } else { if ($cancreate{$type} eq 'none') { @@ -3573,10 +4885,11 @@ sub modify_usermodification { $curr_usermodification{$key} = $domconfig{'usermodification'}{$key}; } } - my @contexts = ('author','course'); + my @contexts = ('author','course','selfcreate'); my %context_title = ( author => 'In author context', course => 'In course context', + selfcreate => 'When self creating account', ); my @fields = ('lastname','firstname','middlename','generation', 'permanentemail','id'); @@ -3584,6 +4897,12 @@ sub modify_usermodification { author => ['ca','aa'], course => ['st','ep','ta','in','cr'], ); + my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); + if (ref($types) eq 'ARRAY') { + push(@{$types},'default'); + $usertypes->{'default'} = $othertitle; + } + $roles{'selfcreate'} = $types; my %fieldtitles = &Apache::loncommon::personal_data_fieldtitles(); my %modifyhash; foreach my $context (@contexts) { @@ -3631,13 +4950,26 @@ sub modify_usermodification { if (ref($changes{$context}) eq 'ARRAY') { foreach my $role (@{$changes{$context}}) { my $rolename; - if ($role eq 'cr') { - $rolename = &mt('Custom'); + if ($context eq 'selfcreate') { + $rolename = $role; + if (ref($usertypes) eq 'HASH') { + if ($usertypes->{$role} ne '') { + $rolename = $usertypes->{$role}; + } + } } else { - $rolename = &Apache::lonnet::plaintext($role); + if ($role eq 'cr') { + $rolename = &mt('Custom'); + } else { + $rolename = &Apache::lonnet::plaintext($role); + } } my @modifiable; - $resulttext .= '
      • '.&mt('Target user with [_1] role',$rolename).' - '.&mt('modifiable fields: '); + if ($context eq 'selfcreate') { + $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: '); + } foreach my $field (@fields) { if ($modifyhash{$context}{$role}{$field}) { push(@modifiable,$fieldtitles{$field}); @@ -3669,7 +5001,7 @@ sub modify_defaults { my ($dom,$r) = @_; my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors); my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); - my @items = ('auth_def','auth_arg_def','lang_def'); + my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def'); my @authtypes = ('internal','krb4','krb5','localauth'); foreach my $item (@items) { $newvalues{$item} = $env{'form.'.$item}; @@ -3683,26 +5015,39 @@ sub modify_defaults { if ($newvalues{$item} ne '') { if ($newvalues{$item} =~ /^(\w+)/) { my $langcode = $1; - if (code2language($langcode) eq '') { - push(@errors,$item); + if ($langcode ne 'x_chef') { + if (code2language($langcode) eq '') { + push(@errors,$item); + } } } else { push(@errors,$item); } } + } elsif ($item eq 'timezone_def') { + if ($newvalues{$item} ne '') { + if (!DateTime::TimeZone->is_valid_name($newvalues{$item})) { + push(@errors,$item); + } + } + } elsif ($item eq 'datelocale_def') { + if ($newvalues{$item} ne '') { + my @datelocale_ids = DateTime::Locale->ids(); + if (!grep(/^\Q$newvalues{$item}\E$/,@datelocale_ids)) { + push(@errors,$item); + } + } } if (grep(/^\Q$item\E$/,@errors)) { $newvalues{$item} = $domdefaults{$item}; } elsif ($domdefaults{$item} ne $newvalues{$item}) { $changes{$item} = 1; } + $domdefaults{$item} = $newvalues{$item}; } my %defaults_hash = ( - defaults => { auth_def => $newvalues{'auth_def'}, - auth_arg_def => $newvalues{'auth_arg_def'}, - lang_def => $newvalues{'lang_def'}, - } - ); + defaults => \%newvalues, + ); my $title = &defaults_titles(); my $putresult = &Apache::lonnet::put_dom('configuration',\%defaults_hash, $dom); @@ -3731,12 +5076,13 @@ sub modify_defaults { $resulttext .= '
      '; $mailmsgtext .= "\n"; my $cachetime = 24*60*60; - &Apache::lonnet::do_cache_new('domdefaults',$dom, - $defaults_hash{'defaults'},$cachetime); - my $sysmail = $r->dir_config('lonSysEMail'); - &Apache::lonmsg::sendemail($sysmail,"LON-CAPA Domain Settings Change - $dom",$mailmsgtext); + &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); + } } else { - $resulttext = &mt('No changes made to default authentication/language settings'); + $resulttext = &mt('No changes made to default authentication/language/timezone settings'); } } else { $resulttext = ''. @@ -3753,7 +5099,7 @@ sub modify_defaults { } sub modify_scantron { - my ($r,$dom,$confname,$domconfig) = @_; + my ($r,$dom,$confname,%domconfig) = @_; my ($resulttext,%confhash,%changes,$errors); my $custom = 'custom.tab'; my $default = 'default.tab'; @@ -3772,7 +5118,7 @@ sub modify_scantron { $confname,'scantron','','',$custom); if ($result eq 'ok') { $confhash{'scantron'}{'scantronformat'} = $scantronurl; - $changes{'scantron'}{'scantronformat'} = 1; + $changes{'scantronformat'} = 1; } else { $error = &mt("Upload of [_1] failed because an error occurred publishing the file in RES space. Error was: [_2].",$custom,$result); } @@ -3788,13 +5134,11 @@ sub modify_scantron { $errors .= '
    • '.$error.'
    • '; } } - if (ref($domconfig) eq 'HASH') { - if (ref($domconfig->{'scantron'}) eq 'HASH') { - if ($domconfig->{'scantron'}{'scantronformat'} ne '') { - if ($env{'form.scantronformat_del'}) { - $confhash{'scantron'}{'scantronformat'} = ''; - $changes{'scantron'}{'scantronformat'} = 1; - } + if (ref($domconfig{'scantron'}) eq 'HASH') { + if ($domconfig{'scantron'}{'scantronformat'} ne '') { + if ($env{'form.scantronformat_del'}) { + $confhash{'scantron'}{'scantronformat'} = ''; + $changes{'scantronformat'} = 1; } } } @@ -3803,15 +5147,16 @@ sub modify_scantron { $dom); if ($putresult eq 'ok') { if (keys(%changes) > 0) { - $resulttext = &mt('Changes made:').'
        '; - if (ref($changes{'scantron'}) eq 'HASH') { - if ($changes{'scantron'}{'scantronformat'}) { - if ($confhash{'scantron'}{'scantronformat'} eq '') { - $resulttext .= '
      • '.&mt('[_1] scantron 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).'
      • '; - } + 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).'
        • '; + } else { + $resulttext .= '
        • '.&mt('Custom scantron format file ([_1]) uploaded for use with courses in this domain.',$custom).'
        • '; } + $resulttext .= '
        '; + } else { + $resulttext = &mt('Changes made to scantron format file.'); } $resulttext .= '
      '; &Apache::loncommon::devalidate_domconfig_cache($dom); @@ -3832,4 +5177,353 @@ sub modify_scantron { return $resulttext; } +sub modify_coursecategories { + my ($dom,%domconfig) = @_; + my ($resulttext,%deletions,%reorderings,%needreordering,%adds,%changes,$errors, + $cathash); + my @deletecategory = &Apache::loncommon::get_env_multiple('form.deletecategory'); + if (ref($domconfig{'coursecategories'}) eq 'HASH') { + $cathash = $domconfig{'coursecategories'}{'cats'}; + if ($domconfig{'coursecategories'}{'togglecats'} ne $env{'form.togglecats'}) { + $changes{'togglecats'} = 1; + $domconfig{'coursecategories'}{'togglecats'} = $env{'form.togglecats'}; + } + if ($domconfig{'coursecategories'}{'categorize'} ne $env{'form.categorize'}) { + $changes{'categorize'} = 1; + $domconfig{'coursecategories'}{'categorize'} = $env{'form.categorize'}; + } + } else { + $changes{'togglecats'} = 1; + $changes{'categorize'} = 1; + $domconfig{'coursecategories'} = { + togglecats => $env{'form.togglecats'}, + categorize => $env{'form.categorize'}, + }; + } + if (ref($cathash) eq 'HASH') { + if (($domconfig{'coursecategories'}{'cats'}{'instcode::0'} ne '') && ($env{'form.instcode'} == 0)) { + push (@deletecategory,'instcode::0'); + } + } + my (@predelcats,@predeltrails,%predelallitems,%sort_by_deltrail); + if (ref($cathash) eq 'HASH') { + if (@deletecategory > 0) { + #FIXME Need to remove category from all courses using a deleted category + &Apache::loncommon::extract_categories($cathash,\@predelcats,\@predeltrails,\%predelallitems); + foreach my $item (@deletecategory) { + if ($domconfig{'coursecategories'}{'cats'}{$item} ne '') { + delete($domconfig{'coursecategories'}{'cats'}{$item}); + $deletions{$item} = 1; + &recurse_cat_deletes($item,$cathash,\%deletions); + } + } + } + foreach my $item (keys(%{$cathash})) { + my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item); + if ($cathash->{$item} ne $env{'form.'.$item}) { + $reorderings{$item} = 1; + $domconfig{'coursecategories'}{'cats'}{$item} = $env{'form.'.$item}; + } + if ($env{'form.addcategory_name_'.$item} ne '') { + my $newcat = $env{'form.addcategory_name_'.$item}; + my $newdepth = $depth+1; + my $newitem = &escape($newcat).':'.&escape($cat).':'.$newdepth; + $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos_'.$item}; + $adds{$newitem} = 1; + } + if ($env{'form.subcat_'.$item} ne '') { + my $newcat = $env{'form.subcat_'.$item}; + my $newdepth = $depth+1; + my $newitem = &escape($newcat).':'.&escape($cat).':'.$newdepth; + $domconfig{'coursecategories'}{'cats'}{$newitem} = 0; + $adds{$newitem} = 1; + } + } + } + if ($env{'form.instcode'} eq '1') { + if (ref($cathash) eq 'HASH') { + my $newitem = 'instcode::0'; + if ($cathash->{$newitem} eq '') { + $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.instcode_pos'}; + $adds{$newitem} = 1; + } + } else { + my $newitem = 'instcode::0'; + $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.instcode_pos'}; + $adds{$newitem} = 1; + } + } + if ($env{'form.addcategory_name'} ne '') { + my $newitem = &escape($env{'form.addcategory_name'}).'::0'; + $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'}; + $adds{$newitem} = 1; + } + my $putresult; + if ((keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) { + if (keys(%deletions) > 0) { + foreach my $key (keys(%deletions)) { + if ($predelallitems{$key} ne '') { + $sort_by_deltrail{$predelallitems{$key}} = $predeltrails[$predelallitems{$key}]; + } + } + } + my (@chkcats,@chktrails,%chkallitems); + &Apache::loncommon::extract_categories($domconfig{'coursecategories'}{'cats'},\@chkcats,\@chktrails,\%chkallitems); + if (ref($chkcats[0]) eq 'ARRAY') { + my $depth = 0; + my $chg = 0; + for (my $i=0; $i<@{$chkcats[0]}; $i++) { + my $name = $chkcats[0][$i]; + my $item; + if ($name eq '') { + $chg ++; + } else { + $item = &escape($name).'::0'; + if ($chg) { + $domconfig{'coursecategories'}{'cats'}{$item} -= $chg; + } + $depth ++; + &recurse_check(\@chkcats,$domconfig{'coursecategories'}{'cats'},$depth,$name); + $depth --; + } + } + } + } + if ((keys(%changes) > 0) || (keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) { + $putresult = &Apache::lonnet::put_dom('configuration',\%domconfig,$dom); + if ($putresult eq 'ok') { + my %title = ( + togglecats => 'Show/Hide a course in the catalog', + categorize => 'Category assigned to course', + ); + my %level = ( + dom => 'set from "Modify Course" (Domain)', + crs => 'set from "Parameters" (Course)', + ); + $resulttext = &mt('Changes made:').'
        '; + if ($changes{'togglecats'}) { + $resulttext .= '
      • '.&mt("$title{'togglecats'} $level{$env{'form.togglecats'}}").'
      • '; + } + if ($changes{'categorize'}) { + $resulttext .= '
      • '.&mt("$title{'categorize'} $level{$env{'form.categorize'}}").'
      • '; + } + if ((keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) { + my $cathash; + if (ref($domconfig{'coursecategories'}) eq 'HASH') { + $cathash = $domconfig{'coursecategories'}{'cats'}; + } else { + $cathash = {}; + } + my (@cats,@trails,%allitems); + &Apache::loncommon::extract_categories($cathash,\@cats,\@trails,\%allitems); + if (keys(%deletions) > 0) { + $resulttext .= '
      • '.&mt('Deleted categories:').'
          '; + foreach my $predeltrail (sort {$a <=> $b } (keys(%sort_by_deltrail))) { + $resulttext .= '
        • '.$predeltrails[$predeltrail].'
        • '; + } + $resulttext .= '
      • '; + } + if (keys(%reorderings) > 0) { + my %sort_by_trail; + $resulttext .= '
      • '.&mt('Reordered categories:').'
          '; + foreach my $key (keys(%reorderings)) { + if ($allitems{$key} ne '') { + $sort_by_trail{$allitems{$key}} = $trails[$allitems{$key}]; + } + } + foreach my $trail (sort {$a <=> $b } (keys(%sort_by_trail))) { + $resulttext .= '
        • '.$trails[$trail].'
        • '; + } + $resulttext .= '
      • '; + } + if (keys(%adds) > 0) { + my %sort_by_trail; + $resulttext .= '
      • '.&mt('Added categories:').'
          '; + foreach my $key (keys(%adds)) { + if ($allitems{$key} ne '') { + $sort_by_trail{$allitems{$key}} = $trails[$allitems{$key}]; + } + } + foreach my $trail (sort {$a <=> $b } (keys(%sort_by_trail))) { + $resulttext .= '
        • '.$trails[$trail].'
        • '; + } + $resulttext .= '
      • '; + } + } + $resulttext .= '
      '; + } else { + $resulttext = ''. + &mt('An error occurred: [_1]',$putresult).''; + } + } else { + $resulttext = &mt('No changes made to course categories'); + } + return $resulttext; +} + +sub modify_serverstatuses { + my ($dom,%domconfig) = @_; + my ($resulttext,%changes,%currserverstatus,%newserverstatus); + if (ref($domconfig{'serverstatuses'}) eq 'HASH') { + %currserverstatus = %{$domconfig{'serverstatuses'}}; + } + my @pages = &serverstatus_pages(); + foreach my $type (@pages) { + $newserverstatus{$type}{'namedusers'} = ''; + $newserverstatus{$type}{'machines'} = ''; + if (defined($env{'form.'.$type.'_namedusers'})) { + my @users = split(/,/,$env{'form.'.$type.'_namedusers'}); + my @okusers; + foreach my $user (@users) { + my ($uname,$udom) = split(/:/,$user); + if (($udom =~ /^$match_domain$/) && + (&Apache::lonnet::domain($udom)) && + ($uname =~ /^$match_username$/)) { + if (!grep(/^\Q$user\E/,@okusers)) { + push(@okusers,$user); + } + } + } + if (@okusers > 0) { + @okusers = sort(@okusers); + $newserverstatus{$type}{'namedusers'} = join(',',@okusers); + } + } + if (defined($env{'form.'.$type.'_machines'})) { + my @machines = split(/,/,$env{'form.'.$type.'_machines'}); + my @okmachines; + foreach my $ip (@machines) { + my @parts = split(/\./,$ip); + next if (@parts < 4); + my $badip = 0; + for (my $i=0; $i<4; $i++) { + if (!(($parts[$i] >= 0) && ($parts[$i] <= 255))) { + $badip = 1; + last; + } + } + if (!$badip) { + push(@okmachines,$ip); + } + } + @okmachines = sort(@okmachines); + $newserverstatus{$type}{'machines'} = join(',',@okmachines); + } + } + my %serverstatushash = ( + serverstatuses => \%newserverstatus, + ); + my %changes; + foreach my $type (@pages) { + foreach my $setting ('namedusers','machines') { + my (@current,@new); + if (ref($currserverstatus{$type}) eq 'HASH') { + if ($currserverstatus{$type}{$setting} ne '') { + @current = split(/,/,$currserverstatus{$type}{$setting}); + } + } + if ($newserverstatus{$type}{$setting} ne '') { + @new = split(/,/,$newserverstatus{$type}{$setting}); + } + if (@current > 0) { + if (@new > 0) { + foreach my $item (@current) { + if (!grep(/^\Q$item\E$/,@new)) { + $changes{$type}{$setting} = 1; + last; + } + } + foreach my $item (@new) { + if (!grep(/^\Q$item\E$/,@current)) { + $changes{$type}{$setting} = 1; + last; + } + } + } else { + $changes{$type}{$setting} = 1; + } + } elsif (@new > 0) { + $changes{$type}{$setting} = 1; + } + } + } + if (keys(%changes) > 0) { + my $titles= &LONCAPA::lonauthcgi::serverstatus_titles(); + my $putresult = &Apache::lonnet::put_dom('configuration', + \%serverstatushash,$dom); + if ($putresult eq 'ok') { + $resulttext .= &mt('Changes made:').'
        '; + foreach my $type (@pages) { + if (ref($changes{$type}) eq 'HASH') { + $resulttext .= '
      • '.$titles->{$type}.'
          '; + if ($changes{$type}{'namedusers'}) { + if ($newserverstatus{$type}{'namedusers'} eq '') { + $resulttext .= '
        • '.&mt("Access terminated for all specific (named) users").'
        • '."\n"; + } else { + $resulttext .= '
        • '.&mt("Access available for the following specified users: ").$newserverstatus{$type}{'namedusers'}.'
        • '."\n"; + } + } + if ($changes{$type}{'machines'}) { + if ($newserverstatus{$type}{'machines'} eq '') { + $resulttext .= '
        • '.&mt("Access terminated for all specific IP addresses").'
        • '."\n"; + } else { + $resulttext .= '
        • '.&mt("Access available for the following specified IP addresses: ").$newserverstatus{$type}{'machines'}.'
        • '."\n"; + } + + } + $resulttext .= '
      • '; + } + } + $resulttext .= '
      '; + } else { + $resulttext = ''. + &mt('An error occurred saving access settings for server status pages: [_1].',$putresult).''; + + } + } else { + $resulttext = &mt('No changes made to access to server status pages'); + } + return $resulttext; +} + +sub recurse_check { + my ($chkcats,$categories,$depth,$name) = @_; + if (ref($chkcats->[$depth]{$name}) eq 'ARRAY') { + my $chg = 0; + for (my $j=0; $j<@{$chkcats->[$depth]{$name}}; $j++) { + my $category = $chkcats->[$depth]{$name}[$j]; + my $item; + if ($category eq '') { + $chg ++; + } else { + my $deeper = $depth + 1; + $item = &escape($category).':'.&escape($name).':'.$depth; + if ($chg) { + $categories->{$item} -= $chg; + } + &recurse_check($chkcats,$categories,$deeper,$category); + $deeper --; + } + } + } + return; +} + +sub recurse_cat_deletes { + my ($item,$coursecategories,$deletions) = @_; + my ($deleted,$container,$depth) = map { &unescape($_); } split(/:/,$item); + my $subdepth = $depth + 1; + if (ref($coursecategories) eq 'HASH') { + foreach my $subitem (keys(%{$coursecategories})) { + my ($child,$parent,$itemdepth) = map { &unescape($_); } split(/:/,$subitem); + if (($parent eq $deleted) && ($itemdepth == $subdepth)) { + delete($coursecategories->{$subitem}); + $deletions->{$subitem} = 1; + &recurse_cat_deletes($subitem,$coursecategories,$deletions); + } + } + } + return; +} + 1;
  • '.&mt('Default in use:').'
    '; + $datatable .= '
    '.&mt('Default in use:').'
    '. + ''; if ($scantronurl) { $datatable .= ''. &mt('Default scantron format file').''; } else { $datatable = &mt('File unavailable for display'); } - $datatable .= '
    '.&mt('Upload:').'
    '; + $datatable .= '
    '; + if (!$switchserver) { + $datatable .= &mt('Upload:').'
    '; + } + } else { + my $errorstr; + foreach my $key (sort(keys(%error))) { + $errorstr .= $lt{$key}.': '.$error{$key}.'
    '; + } + $datatable .= '
    '.$errorstr; + } } else { if (keys(%error) > 0) { my $errorstr; foreach my $key (sort(keys(%error))) { $errorstr .= $lt{$key}.': '.$error{$key}.'
    '; } - $datatable .= '
    '.$errorstr.''; + $datatable .= ''.$errorstr.' '; } elsif ($scantronurl) { - $datatable .= '' .&mt('Custom scantron format file').'' - .''.&mt('Replace:').'
    '; + $datatable .= '
    '. + ''. + &mt('Custom scantron format file').' '. + &mt('Replace:').'
    '; } } if (keys(%error) == 0) { if ($switchserver) { $datatable .= &mt('Upload to library server: [_1]',$switchserver); } else { - $datatable .=' '; + $datatable .=' '. + ''; } } $datatable .= '
    '.$title{'togglecats'}.' '. + '
    '.$title{'categorize'}.''. + ' '. + '
    ' + .''; + if ($parent eq 'instcode') { + $datatable .= ''.&mt('Official courses') + .'
    (' + .&mt('with institutional codes').')
    '.&mt('Add category:').' ' + .'
    '. + '' + .&mt('Official courses').''.'
    (' + .&mt('with institutional codes').')
     ' + .'
    '.$hdritem->{'header'}->[0]->{'col2'}.''. + $titles->{$type}.''. + ''. + ''. + ''. + '
    ' + .' ' + .&mt('Official courses (with institutional codes)') + .'' + .' 
    ' + .' ' + .&mt('Add category').''.&mt('Name:') + .' 
    '; + my ($idxnum,$parent_name,$parent_item); + my $higher = $depth - 1; + if ($higher == 0) { + $parent_name = &escape($parent).'::'.$higher; + } else { + if (ref($path) eq 'ARRAY') { + $parent_name = &escape($parent).':'.&escape($path->[-2]).':'.$higher; + } + } + $parent_item = 'addcategory_pos_'.$parent_name; + for (my $j=0; $j<=$numchildren; $j++) { + if ($j < $numchildren) { + $name = $cats->[$depth]{$parent}[$j]; + $item = &escape($name).':'.&escape($parent).':'.$depth; + $idxnum = $idx->{$item}; + } else { + $name = $parent_name; + $item = $parent_item; + } + $chgstr = ' onchange="javascript:reorderCats(this.form,'."'$parent_name','$item','$idxnum'".');"'; + $text .= ''; + } + $text .= '
     '; + if ($j < $numchildren) { + my $deeper = $depth+1; + $text .= $name.' ' + .''; + if(ref($path) eq 'ARRAY') { + push(@{$path},$name); + $text .= &build_category_rows($itemcount,$cats,$deeper,$name,$path,$idx); + pop(@{$path}); + } + } else { + $text .= &mt('Add subcategory:').' '; + } + $text .= '
    '.&mt('Add subcategory:').'
    '.&mt('Users allowed to search').' ('.$dom.')'. + ''.$lt{$context}.$showdom. ''; my $rem; if (ref($types) eq 'ARRAY') { @@ -2004,14 +2933,18 @@ sub users_cansearch_row { $output .= ''; } my $check = ' '; - if (ref($settings->{'cansearch'}) eq 'ARRAY') { - if (grep(/^\Q$types->[$i]\E$/,@{$settings->{'cansearch'}})) { + if (ref($settings) eq 'HASH') { + if (ref($settings->{$context}) eq 'ARRAY') { + if (grep(/^\Q$types->[$i]\E$/,@{$settings->{$context}})) { + $check = ' checked="checked" '; + } + } elsif ($context eq 'statustocreate') { $check = ' checked="checked" '; } } $output .= ''; } @@ -2026,13 +2959,17 @@ sub users_cansearch_row { $output .= ''. '
    '. ''; } my $defcheck = ' '; - if (ref($settings->{'cansearch'}) eq 'ARRAY') { - if (grep(/^default$/,@{$settings->{'cansearch'}})) { + if (ref($settings) eq 'HASH') { + if (ref($settings->{$context}) eq 'ARRAY') { + if (grep(/^default$/,@{$settings->{$context}})) { + $defcheck = ' checked="checked" '; + } + } elsif ($context eq 'statustocreate') { $defcheck = ' checked="checked" '; } } $output .= '