--- loncom/interface/domainprefs.pm 2009/08/06 15:14:08 1.100 +++ loncom/interface/domainprefs.pm 2009/08/08 00:36:00 1.101 @@ -1,7 +1,7 @@ # The LearningOnline Network with CAPA # Handler to set domain-wide configuration settings # -# $Id: domainprefs.pm,v 1.100 2009/08/06 15:14:08 raeburn Exp $ +# $Id: domainprefs.pm,v 1.101 2009/08/08 00:36:00 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, approve, 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 + +approve + +=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; @@ -172,7 +297,7 @@ sub handler { {text => 'Request creation of courses', help => 'Domain_Configuration_Request_Courses', header => [{col1 => 'User affiliation', - col2 => 'Requestable course types',}], + col2 => 'Availability/Processing of requests',}], }, 'coursecategories' => { text => 'Cataloging of courses', @@ -1014,16 +1139,19 @@ sub print_quotas { } else { $context = $action; } - my ($datatable,$defaultquota,@usertools); + 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','approve','autolimit','validate'); + %validations = &Apache::lonnet::auto_courserequest_checks($dom); + %titles = &courserequest_titles(); } else { @usertools = ('aboutme','blog','portfolio'); + %titles = &tool_titles(); } - my %titles = &tool_titles(); if (ref($types) eq 'ARRAY') { foreach my $type (@{$types}) { my $currdefquota; @@ -1042,24 +1170,81 @@ sub print_quotas { $datatable .= ''. ''.$usertypes->{$type}.''. ''; + if ($context eq 'requestcourses') { + $datatable .= ''; + } + my %cell; foreach my $item (@usertools) { - my $checked; - unless ($context eq 'requestcourses') { - $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" '; + 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} .= ''; + } + $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 .= '  '; + $datatable .= '
'.$titles{$item}.'
'.$cell{$item}.'
'; } $datatable .= ''; unless ($context eq 'requestcourses') { @@ -1088,24 +1273,81 @@ sub print_quotas { $datatable .= ''. ''.$othertitle.''. ''; + if ($context eq 'requestcourses') { + $datatable .= ''; + } + my %defcell; foreach my $item (@usertools) { - my $checked; - unless ($context eq 'requestcourses') { - $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" '; + 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} .= '  '; + } + } 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 .= '  '; } - $datatable .= '  '; + } + if ($context eq 'requestcourses') { + $datatable .= ''; + foreach my $item (@usertools) { + $datatable .= ''; + } + $datatable .= '
'.$titles{$item}.'
'.$defcell{$item}.'
'; } $datatable .= ''; unless ($context eq 'requestcourses') { @@ -1120,25 +1362,84 @@ sub print_quotas { ''.&mt('LON-CAPA Advanced Users'). ' ('. &mt('overrides affiliation').')'. - '
'; + ''; + if ($context eq 'requestcourses') { + $datatable .= ''; + } else { + $datatable .= '
'; + } + my %advcell; foreach my $item (@usertools) { - my $checked; - unless ($context eq 'requestcourses') { - $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" '; + 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 .= ''; + 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 ($option 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} .= '  '; + } + } 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 .= '  '; + $datatable .= '
'.$titles{$item}.'
'.$advcell{$item}.'
'; } $datatable .= ''; $$rowtotal += $typecount; @@ -1477,6 +1778,28 @@ sub tool_titles { return %titles; } +sub courserequest_titles { + my %titles = &Apache::lonlocal::texthash ( + official => 'Official', + unofficial => 'Unofficial', + community => 'Communities', + norequest => 'Not allowed', + approve => 'Approval by Dom. Coord.', + validate => 'With validation', + autolimit => 'Numerical limit', + ); + return %titles; +} + +sub courserequest_conditions { + my %conditions = &Apache::lonlocal::texthash ( + approve => '(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; @@ -3352,7 +3675,8 @@ sub check_switchserver { sub modify_quotas { my ($dom,$action,%domconfig) = @_; - my ($context,@usertools); + my ($context,@usertools,@options,%validations,%titles,%confhash,%toolshash, + %limithash,$toolregexp,%conditions,$resulttext,%changes); if ($action eq 'quotas') { $context = 'tools'; } else { @@ -3360,22 +3684,35 @@ sub modify_quotas { } if ($context eq 'requestcourses') { @usertools = ('official','unofficial','community'); + @options =('norequest','approve','autolimit','validate'); + %validations = &Apache::lonnet::auto_courserequest_checks($dom); + %titles = &courserequest_titles(); + $toolregexp = join('|',@usertools); + %conditions = &courserequest_conditions(); } else { @usertools = ('aboutme','blog','portfolio'); + %titles = &tool_titles(); } my %domdefaults = &Apache::lonnet::get_domain_defaults($dom); - my ($resulttext,%changes); my ($othertitle,$usertypes,$types) = &Apache::loncommon::sorted_inst_types($dom); - my %titles = &tool_titles(); - my (%confhash,%toolshash); foreach my $key (keys(%env)) { - unless ($context eq 'requestcourses') { + 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); + if ($key =~ /^form\.\Q$context\E_(.+)$/) { + @{$toolshash{$1}} = &Apache::loncommon::get_env_multiple($key); + } } } unless ($context eq 'requestcourses') { @@ -3383,10 +3720,19 @@ sub modify_quotas { } foreach my $item (@usertools) { foreach my $type (@{$types},'default','_LC_adv') { - if (grep(/^\Q$type\E$/,@{$toolshash{$item}})) { - $confhash{$item}{$type} = 1; + if ($context eq 'requestcourses') { + if ($confhash{$item}{$type} eq 'autolimit') { + $confhash{$item}{$type} .= '='; + unless ($limithash{$item}{$type} =~ /\D/) { + $confhash{$item}{$type} .= $limithash{$item}{$type}; + } + } } else { - $confhash{$item}{$type} = 0; + 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') { @@ -3395,7 +3741,7 @@ sub modify_quotas { } } else { if ($context eq 'requestcourses') { - if ($confhash{$item}{$type}) { + if ($confhash{$item}{$type} ne 'norequest') { $changes{$item}{$type} = 1; } } else { @@ -3406,7 +3752,7 @@ sub modify_quotas { } } else { if ($context eq 'requestcourses') { - if ($confhash{$item}{$type}) { + if ($confhash{$item}{$type} eq 'norequest') { $changes{$item}{$type} = 1; } } else { @@ -3498,8 +3844,8 @@ sub modify_quotas { $env{'user.domain'}, $item,'reload',$context); if ($context eq 'requestcourses') { - if ($env{'environment.canrequest.'.$item} ne $newacc) { - $newenv{'environment.canrequest.'.$item} = $newacc; + if ($env{'environment.crsrequest.'.$item} ne $newacc) { + $newenv{'environment.crsrequest.'.$item} = $newacc; } } else { if ($env{'environment.availabletools.'.$item} ne $newacc) { @@ -3516,7 +3862,21 @@ sub modify_quotas { $typetitle = 'LON-CAPA Advanced Users'; } if ($confhash{$item}{$type}) { - $resulttext .= '
  • '.&mt('Set to be available to [_1]',$typetitle).'
  • '; + 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 { $resulttext .= '
  • '.&mt('Set to be unavailable to [_1]',$typetitle).'
  • '; }