--- loncom/interface/domainprefs.pm 2008/05/07 23:01:50 1.48 +++ loncom/interface/domainprefs.pm 2008/07/09 21:34:27 1.62 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set domain-wide configuration settings # -# $Id: domainprefs.pm,v 1.48 2008/05/07 23:01:50 raeburn Exp $ +# $Id: domainprefs.pm,v 1.62 2008/07/09 21:34:27 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -41,6 +41,7 @@ use LONCAPA; use LONCAPA::Enrollment; use File::Copy; use Locale::Language; +use DateTime::TimeZone; sub handler { my $r=shift; @@ -62,7 +63,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'}; @@ -96,7 +97,7 @@ sub handler { col2 => '',}], }, 'defaults' => - { text => 'Default authentication/language', + { text => 'Default authentication/language/timezone', help => '', header => [{col1 => 'Setting', col2 => 'Value'}], @@ -162,9 +163,11 @@ sub handler { 'coursecategories' => { text => 'Cataloging of courses', help => 'Domain_Course_Catalog', - header => [ {col1 => 'Categories', - col2 => '', - }], + header => [{col1 => 'Category settings', + col2 => '',}, + {col1 => 'Categories', + col2 => '', + }], } ); my @roles = ('student','coordinator','author','admin'); @@ -300,10 +303,10 @@ sub handler { $r->print('

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

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

'."\n".'

  '. - '

'); my ($numitems,$midpoint,$seconddiv,$count); @@ -314,7 +317,7 @@ sub handler { } $count = 0; foreach my $item (@prefs_order) { - $r->print('

'); + $r->print('

'); $count ++; if ((!$seconddiv) && ($count >= $midpoint)) { $r->print('
'."\n".'
'."\n"); @@ -370,7 +373,11 @@ 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 .= ''); $rowtotal ++; if (($action eq 'autoupdate') || ($action eq 'rolecolors') || - ($action eq 'usercreation') || ($action eq 'usermodification')) { + ($action eq 'usercreation') || ($action eq 'usermodification') || + ($action eq 'coursecategories')) { my $colspan = ($action eq 'rolecolors')?' colspan="2"':''; $output .= '
'.&mt($item->{text}). @@ -382,15 +389,16 @@ sub print_config_box { #
- - + + '; $rowtotal ++; if ($action eq 'autoupdate') { @@ -399,6 +407,8 @@ sub print_config_box { $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); } else { $output .= &print_rolecolors($phase,'student',$dom,$confname,$settings,\$rowtotal); } @@ -410,8 +420,10 @@ sub print_config_box {
'.$item->{'header'}->[0]->{'col1'}.''.$item->{'header'}->[0]->{'col2'}.''.&mt($item->{'header'}->[0]->{'col1'}).''.&mt($item->{'header'}->[0]->{'col2'}).'
- - + '; + my $colspan = ($action eq 'coursecategories')?' colspan="2"':''; + $output .= ' + '; $rowtotal ++; if ($action eq 'autoupdate') { @@ -425,12 +437,14 @@ 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); + } elsif ($action eq 'coursecategories') { + $output .= &print_coursecategories('bottom',$dom,$item,$settings,\$rowtotal); } else { $output .= &print_rolecolors($phase,'coordinator',$dom,$confname,$settings,\$rowtotal).'
'.$item->{'header'}->[2]->{'col1'}.''.$item->{'header'}->[2]->{'col2'}.'
'.&mt($item->{'header'}->[2]->{'col1'}).''.&mt($item->{'header'}->[2]->{'col2'}).'
@@ -440,8 +454,8 @@ 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'}).'
@@ -451,8 +465,8 @@ sub print_config_box {
- - + + '. &print_rolecolors($phase,'admin',$dom,$confname,$settings,\$rowtotal); $rowtotal += 2; @@ -465,14 +479,13 @@ sub print_config_box { '; if (($action eq 'login') || ($action eq 'directorysrch')) { $output .= ' - '; + '; } else { $output .= ' - '; + '; } - my $colspan = ($action eq 'coursecategories')?' colspan="2"':''; $output .= ' - + '; $rowtotal ++; if ($action eq 'login') { @@ -489,8 +502,6 @@ sub print_config_box { $output .= &print_defaults($dom,\$rowtotal); } elsif ($action eq 'scantron') { $output .= &print_scantronformat($r,$dom,$confname,$settings,\$rowtotal); - } elsif ($action eq 'coursecategories'){ - $output .= &print_coursecategories($dom,$item,$settings,\$rowtotal); } } $output .= ' @@ -1539,11 +1550,21 @@ sub print_usercreation { &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'}})) { @@ -1555,10 +1576,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'; } } @@ -1571,24 +1590,33 @@ sub print_usercreation { $datatable .= ''. ''; + if (keys(%error) == 0) { + $datatable .= '' @@ -1935,112 +2014,251 @@ sub legacy_scantronformat { return ($url,$error); } -sub print_coursecategories { - my ($dom,$item,$settings,$rowtotal) = @_; - my ($datatable,$css_class); - my $itemcount = 1; - # FIXME Need to add javascrpt to update other select boxes when one is changed. - if (ref($settings) eq 'HASH') { - my (@cats,@trails,%allitems); - &extract_categories($settings,\@cats,\@trails,\%allitems); - 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]})) || ($settings->{'instcode::0'} eq '')) { - $maxnum ++; - } - for (my $i=0; $i<$numtop; $i++) { - my $parent = $cats[0][$i]; +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 $item = &escape($parent).'::0'; - $datatable .= '' - .' ' - .''; - } else { - $datatable .= $parent - .' '; - } - my $depth = 1; - push(@path,$parent); - $datatable .= &build_category_rows($itemcount,\@cats,$depth,$parent,\@path); - pop(@path); - $datatable .= ''; + $datatable .= '' + .''."\n"; $itemcount ++; - } - $css_class = $itemcount%2?' class="LC_odd_row"':''; - $datatable .= '' - .''."\n"; - $itemcount ++; - if ((!grep(/^instcode$/,@{$cats[0]})) || ($settings->{'instcode::0'} eq '')) { - $css_class = $itemcount%2?' class="LC_odd_row"':''; - $datatable .= '' + .''; } - $datatable .= '' - .''; } + } else { + $datatable .= &initialize_categories($itemcount); } } else { - $datatable .= &initialize_categories($itemcount); + $datatable .= '' + .&initialize_categories($itemcount); } - } else { - $datatable .= '' - .&initialize_categories($itemcount); + $$rowtotal += $itemcount; } - $$rowtotal += $itemcount; return $datatable; } +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 .= ''; @@ -2061,8 +2280,8 @@ sub initialize_categories { } sub build_category_rows { - my ($itemcount,$cats,$depth,$parent,$path) = @_; - my ($text,$name,$item); + 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') { @@ -2070,22 +2289,27 @@ sub build_category_rows { my $numchildren = @{$cats->[$depth]{$parent}}; my $css_class = $itemcount%2?' class="LC_odd_row"':''; $text .= '
'.$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'}).''.$item->{'header'}->[0]->{'col1'}.''.&mt($item->{'header'}->[0]->{'col1'}).''.$item->{'header'}->[0]->{'col2'}.''.&mt($item->{'header'}->[0]->{'col2'}).'
'.$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 .= '  '; } @@ -1761,7 +1789,7 @@ sub print_usermodification { 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'); my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); my $titles = &defaults_titles(); my $rownum = 0; @@ -1793,6 +1821,9 @@ 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); } else { $datatable .= ''; @@ -1809,6 +1840,7 @@ sub defaults_titles { 'auth_def' => 'Default authentication type', 'auth_arg_def' => 'Default authentication argument', 'lang_def' => 'Default language', + 'timezone_def' => 'Default timezone', ); return (\%titles); } @@ -1816,7 +1848,8 @@ 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', @@ -1843,23 +1876,52 @@ 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; + } } } } @@ -1880,7 +1942,11 @@ 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 .= ''; @@ -1892,16 +1958,29 @@ sub print_scantronformat { } 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').'' + $datatable .= '' + .&mt('Custom scantron format file').'' .'
'.$title{'togglecats'}.' '. + '
'.$title{'categorize'}.''. + ' '. + '
' + .''; + if ($parent eq 'instcode') { + $datatable .= ''.&mt('Official courses') + .'
(' + .&mt('with institutional codes').')
' - .'
'; - if ($parent eq 'instcode') { - $datatable .= ''.&mt('Official courses') - .'
(' - .&mt('with institutional codes').')
'.&mt('Add category:').' ' + .'
'.&mt('New:').' ' - .'
'. - '
'. + '' + .&mt('Official courses').''.'
(' + .&mt('with institutional codes').')
 ' + .'
' - .&mt('Official courses').''.'
(' - .&mt('with institutional codes').')
 ' - .'
'.$hdritem->{'header'}->[0]->{'col2'}.''.$item->{'header'}->[0]->{'col2'}.'
' .' ' @@ -2052,8 +2270,9 @@ sub initialize_categories { .'
' - .'' .' ' .&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) { - my $higher = $depth-1; - if ($higher == 0) { - $name = &escape($parent).'::'.$higher; - } else { - if (ref($path) eq 'ARRAY') { - $name = &escape($parent).':'.&escape($path->[-2]).':'.$higher; - } - } - $item = 'addcategory_pos_'.$name; - } else { + if ($j < $numchildren) { $name = $cats->[$depth]{$parent}[$j]; $item = &escape($name).':'.&escape($parent).':'.$depth; + $idxnum = $idx->{$item}; + } else { + $name = $parent_name; + $item = $parent_item; } - $text .= '
'; if(ref($path) eq 'ARRAY') { push(@{$path},$name); - $text .= &build_category_rows($itemcount,$cats,$deeper,$name,$path); + $text .= &build_category_rows($itemcount,$cats,$deeper,$name,$path,$idx); pop(@{$path}); } } else { - $text .= &mt('New:').'  "Background colors", links => "Link colors", + images => "Images", font => "Font color", pgbg => "Page", tabbg => "Header", @@ -2428,6 +2655,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, @@ -2454,7 +2686,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; @@ -2469,8 +2701,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) { @@ -3021,7 +3255,11 @@ sub modify_quotas { } foreach my $key (keys(%formhash)) { if ($formhash{$key} ne '') { - if (!exists($domconfig{'quotas'}{$key})) { + if (ref($domconfig{'quotas'}) eq 'HASH') { + if (!exists($domconfig{'quotas'}{$key})) { + $changes{$key} = 1; + } + } else { $changes{$key} = 1; } } @@ -3541,21 +3779,81 @@ sub modify_usercreation { my @email_rule = &Apache::loncommon::get_env_multiple('form.email_rule'); my @contexts = ('author','course','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}; } } 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') { + if (ref($curr_usercreation{'cancreate'}{$item}) eq 'ARRAY') { + foreach my $curr (@{$curr_usercreation{'cancreate'}{$item}}) { + 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) { @@ -3662,6 +3960,12 @@ 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:').'
    '; @@ -3670,16 +3974,14 @@ sub modify_usercreation { foreach my $type (@{$changes{'cancreate'}}) { my $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 .= '
    '; } } else { if ($cancreate{$type} eq 'none') { @@ -3884,7 +4186,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'); my @authtypes = ('internal','krb4','krb5','localauth'); foreach my $item (@items) { $newvalues{$item} = $env{'form.'.$item}; @@ -3905,6 +4207,12 @@ sub modify_defaults { push(@errors,$item); } } + } elsif ($item eq 'timezone_def') { + if ($newvalues{$item} ne '') { + if (!DateTime::TimeZone->is_valid_name($newvalues{$item})) { + push(@errors,$item); + } + } } if (grep(/^\Q$item\E$/,@errors)) { $newvalues{$item} = $domdefaults{$item}; @@ -3916,6 +4224,7 @@ sub modify_defaults { defaults => { auth_def => $newvalues{'auth_def'}, auth_arg_def => $newvalues{'auth_arg_def'}, lang_def => $newvalues{'lang_def'}, + timezone_def => $newvalues{'timezone_def'}, } ); my $title = &defaults_titles(); @@ -3948,10 +4257,12 @@ sub modify_defaults { 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); + if ($changes{'auth_def'} || $changes{'auth_arg_def'} || $changes{'lang_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 = ''. @@ -4048,67 +4359,85 @@ sub modify_scantron { sub modify_coursecategories { my ($dom,%domconfig) = @_; - my ($resulttext,%deletions,%reorderings,%needreordering,%adds,$errors); + my ($resulttext,%deletions,%reorderings,%needreordering,%adds,%changes,$errors, + $cathash); my @deletecategory = &Apache::loncommon::get_env_multiple('form.deletecategory'); - if (($domconfig{'coursecategories'}{'instcode::0'} ne '') && ($env{'form.instcode'} == 0)) { - push (@deletecategory,'instcode::0'); - } - my (@predelcats,@predeltrails,%predelallitems); 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'}; + $domconfig{'coursecategories'}{'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 - &extract_categories($domconfig{'coursecategories'},\@predelcats,\@predeltrails,\%predelallitems); + &Apache::loncommon::extract_categories($cathash,\@predelcats,\@predeltrails,\%predelallitems); foreach my $item (@deletecategory) { - if ($domconfig{'coursecategories'}{$item} ne '') { - delete($domconfig{'coursecategories'}{$item}); + if ($domconfig{'coursecategories'}{'cats'}{$item} ne '') { + delete($domconfig{'coursecategories'}{'cats'}{$item}); $deletions{$item} = 1; - &recurse_cat_deletes($item,$domconfig{'coursecategories'}, - \%deletions); + &recurse_cat_deletes($item,$cathash,\%deletions); } } } - foreach my $item (keys(%{$domconfig{'coursecategories'}})) { + foreach my $item (keys(%{$cathash})) { my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item); - if ($domconfig{'coursecategories'}{$item} ne $env{'form.'.$item}) { + if ($cathash->{$item} ne $env{'form.'.$item}) { $reorderings{$item} = 1; - $domconfig{'coursecategories'}{$item} = $env{'form.'.$item}; + $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'}{$newitem} = $env{'form.addcategory_pos_'.$item}; + $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'}{$newitem} = 0; + $domconfig{'coursecategories'}{'cats'}{$newitem} = 0; $adds{$newitem} = 1; } } } if ($env{'form.instcode'} eq '1') { - if (ref($domconfig{'coursecategories'}) eq 'HASH') { + if (ref($cathash) eq 'HASH') { my $newitem = 'instcode::0'; - if ($domconfig{'coursecategories'}{$newitem} eq '') { - $domconfig{'coursecategories'}{$newitem} = $env{'form.instcode_pos'}; + if ($cathash->{$newitem} eq '') { + $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.instcode_pos'}; $adds{$newitem} = 1; } } else { my $newitem = 'instcode::0'; - $domconfig{'coursecategories'}{$newitem} = $env{'form.instcode_pos'}; + $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'}{$newitem} = $env{'form.addcategory_pos'}; + $domconfig{'coursecategories'}{'cats'}{$newitem} = $env{'form.addcategory_pos'}; $adds{$newitem} = 1; } + my $putresult; if ((keys(%deletions) > 0) || (keys(%reorderings) > 0) || (keys(%adds) > 0)) { - my %sort_by_deltrail; if (keys(%deletions) > 0) { foreach my $key (keys(%deletions)) { if ($predelallitems{$key} ne '') { @@ -4117,7 +4446,7 @@ sub modify_coursecategories { } } my (@chkcats,@chktrails,%chkallitems); - &extract_categories($domconfig{'coursecategories'},\@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; @@ -4129,56 +4458,80 @@ sub modify_coursecategories { } else { $item = &escape($name).'::0'; if ($chg) { - $domconfig{'coursecategories'}{$item} -= $chg; + $domconfig{'coursecategories'}{'cats'}{$item} -= $chg; } $depth ++; - &recurse_check(\@chkcats,$domconfig{'coursecategories'},$depth,$name); + &recurse_check(\@chkcats,$domconfig{'coursecategories'}{'cats'},$depth,$name); $depth --; } } } - my $putresult = &Apache::lonnet::put_dom('configuration',\%domconfig,$dom); - my (@cats,@trails,%allitems); - &extract_categories($domconfig{'coursecategories'},\@cats,\@trails,\%allitems); + } + 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 (keys(%deletions) > 0) { - $resulttext .= '
    • '.&mt('Deleted categories:').'
        '; - foreach my $predeltrail (sort {$a <=> $b } (keys(%sort_by_deltrail))) { - $resulttext .= '
      • '.$predeltrails[$predeltrail].'
      • '; - } - $resulttext .= '
    • '; + if ($changes{'togglecats'}) { + $resulttext .= '
    • '.&mt("$title{'togglecats'} $level{$env{'form.togglecats'}}").'
    • '; } - 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 ($changes{'categorize'}) { + $resulttext .= '
    • '.&mt("$title{'categorize'} $level{$env{'form.categorize'}}").'
    • '; } - 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}]; + 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 .= '
      • '; } - foreach my $trail (sort {$a <=> $b } (keys(%sort_by_trail))) { - $resulttext .= '
      • '.$trails[$trail].'
      • '; + 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 .= '
    • '; } $resulttext .= '
    '; } else { $resulttext = ''. - &mt('An error occurred: [_1]',$putresult).''; + &mt('An error occurred: [_1]',$putresult).'
    '; } } else { $resulttext = &mt('No changes made to course categories'); @@ -4224,73 +4577,6 @@ sub recurse_cat_deletes { } } return; -} - -sub extract_categories { - my ($categories,$cats,$trails,$allitems) = @_; - if (ref($categories) eq 'HASH') { - foreach my $item (keys(%{$categories})) { - my ($cat,$container,$depth) = map { &unescape($_); } split(/:/,$item); - if ($container eq '' && $depth == 0) { - $cats->[$depth][$categories->{$item}] = $cat; - } else { - $cats->[$depth]{$container}[$categories->{$item}] = $cat; - } - } - if (ref($cats->[0]) eq 'ARRAY') { - for (my $i=0; $i<@{$cats->[0]}; $i++) { - my $name = $cats->[0][$i]; - my $item = &escape($name).'::0'; - my $trailstr; - if ($name eq 'instcode') { - $trailstr = &mt('Official courses (with institutional codes)'); - } else { - $trailstr = $name; - } - if ($allitems->{$item} eq '') { - push(@{$trails},$trailstr); - $allitems->{$item} = scalar(@{$trails})-1; - } - my @parents = ($name); - if (ref($cats->[1]{$name}) eq 'ARRAY') { - for (my $j=0; $j<@{$cats->[1]{$name}}; $j++) { - my $category = $cats->[1]{$name}[$j]; - &recurse_categories($cats,2,$category,$trails,$allitems,\@parents); - } - } - } - } - } - return; -} - -sub recurse_categories { - my ($cats,$depth,$category,$trails,$allitems,$parents) = @_; - if (ref($cats->[$depth]{$category}) eq 'ARRAY') { - for (my $k=0; $k<@{$cats->[$depth]{$category}}; $k++) { - my $shallower = $depth - 1; - my $name = $cats->[$depth]{$category}[$k]; - my $item = &escape($category).':'.&escape($parents->[-1]).':'.$shallower; - my $trailstr = join(' -> ',(@{$parents},$category)); - if ($allitems->{$item} eq '') { - push(@{$trails},$trailstr); - $allitems->{$item} = scalar(@{$trails})-1; - } - my $deeper = $depth+1; - push(@{$parents},$category); - &recurse_categories($cats,$deeper,$name,$trails,$allitems,$parents); - pop(@{$parents}); - } - } else { - $depth --; - my $item = &escape($category).':'.&escape($parents->[-1]).':'.$depth; - my $trailstr = join(' -> ',(@{$parents},$category)); - if ($allitems->{$item} eq '') { - push(@{$trails},$trailstr); - $allitems->{$item} = scalar(@{$trails})-1; - } - } - return; } 1;