[LON-CAPA-cvs] cvs: loncom /interface domainprefs.pm loncreateuser.pm /lonnet/perl lonnet.pm

raeburn raeburn@source.lon-capa.org
Sat, 08 Aug 2009 00:36:10 -0000


This is a MIME encoded message

--raeburn1249691770
Content-Type: text/plain

raeburn		Sat Aug  8 00:36:10 2009 EDT

  Modified files:              
    /loncom/interface	domainprefs.pm loncreateuser.pm 
    /loncom/lonnet/perl	lonnet.pm 
  Log:
  Course Requests within LON-CAPA.
  
  - Start on documentation for domainprefs.pm
  
  - Domain setting for course requests for each instituional affiliate type (and 
  also default, and _LC_adv) for each course type (official, unofficial and 
  community) can now be one of:  
    0, approve, validate, autolimit=N (where N is blank, or a positive integer.
  
  - Custom course request settings set for an individual user in the user's domain 
  can also be one of: approve, validate, autolimit=N for the three course types
  
  - A user's environment setting for course requests in external domains (modifiable
  by a DC in a domain other than the user's home domain) can also be one of the 
  three.
   
  0: course requests not allowed for the specific affiliation/course type.
  approve - requests queued and must be approved by DC in course's domain before 
  processing.
  
  validate: institutional validation (e.g., check requestor is instructor
  of record) before course will be created.
  
  autolimit: requests will be processed autoatically up to a limit of N requests
  for the course type for that requestor.
  - If N is undefined, there is no limit to the number of course requests which a
  course owner may submit for automatic processing.
  
  lonnet.pm
  - auto_courserequest_checks() placeholder.
  
  Work in progress.
  
  
--raeburn1249691770
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20090808003610.txt"

Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.100 loncom/interface/domainprefs.pm:1.101
--- loncom/interface/domainprefs.pm:1.100	Thu Aug  6 15:14:08 2009
+++ loncom/interface/domainprefs.pm	Sat Aug  8 00:36:00 2009
@@ -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 @@
                  {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 @@
     } 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 @@
                 $datatable .= '<tr'.$css_class.'>'.
                               '<td>'.$usertypes->{$type}.'</td>'.
                               '<td class="LC_left_item">';
+                if ($context eq 'requestcourses') {
+                    $datatable .= '<table><tr>';
+                }
+                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 .= '<th>'.$titles{$item}.'</th>';
+                        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} .= '<span class="LC_nobreak"><label>'.
+                                  '<input type="radio" name="crsreq_'.$item.
+                                  '_'.$type.'" value="'.$val.'"'.$checked.' />'.
+                                  $titles{$option}.'</label>&nbsp;';
+                            if ($option eq 'autolimit') {
+                                $cell{$item} .= '<input type="text" name="crsreq_'.
+                                                $item.'_limit_'.$type.'" size="1" '.
+                                                'value="'.$currlimit.'" />'; 
+                            }
+                            $cell{$item} .= '</span>&nbsp; ';
+                        }
+                    } 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 .= '<span class="LC_nobreak"><label>'.
+                                      '<input type="checkbox" name="'.$context.'_'.$item.
+                                      '" value="'.$type.'" '.$checked.'/>'.$titles{$item}.
+                                      '</label></span>&nbsp; ';
                     }
-                    $datatable .= '<span class="LC_nobreak"><label>'.
-                                  '<input type="checkbox" name="'.$context.'_'.$item.
-                                  '" value="'.$type.'" '.$checked.'/>'.$titles{$item}.
-                                  '</label></span>&nbsp; ';
+                }
+                if ($context eq 'requestcourses') {
+                    $datatable .= '</tr><tr>';
+                    foreach my $item (@usertools) {
+                        $datatable .= '<td>'.$cell{$item}.'</td>';  
+                    }
+                    $datatable .= '</tr></table>';
                 }
                 $datatable .= '</td>';
                 unless ($context eq 'requestcourses') {
@@ -1088,24 +1273,81 @@
     $datatable .= '<tr'.$css_class.'>'.
                   '<td>'.$othertitle.'</td>'.
                   '<td class="LC_left_item">';
+    if ($context eq 'requestcourses') {
+        $datatable .= '<table><tr>';
+    }
+    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 .= '<th>'.$titles{$item}.'</th>';
+            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} .= '<span class="LC_nobreak"><label>'.
+                                  '<input type="radio" name="crsreq_'.$item.
+                                  '_default" value="'.$val.'"'.$checked.' />'.
+                                  $titles{$option}.'</label>';
+                if ($option eq 'autolimit') {
+                    $defcell{$item} .= '<input type="text" name="crsreq_'.
+                                       $item.'_limit_default" size="1" '.
+                                       'value="'.$currlimit.'" />';
+                }
+                $defcell{$item} .= '</span>&nbsp; ';
+            }
+        } 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 .= '<span class="LC_nobreak"><label>'.
+                          '<input type="checkbox" name="'.$context.'_'.$item.
+                          '" value="default" '.$checked.'/>'.$titles{$item}.
+                          '</label></span>&nbsp; ';
+        }
+    }
+    if ($context eq 'requestcourses') {
+        $datatable .= '</tr><tr>';
+        foreach my $item (@usertools) {
+            $datatable .= '<td>'.$defcell{$item}.'</td>';
         }
-        $datatable .= '<span class="LC_nobreak"><label>'.
-                      '<input type="checkbox" name="'.$context.'_'.$item.
-                      '" value="default" '.$checked.'/>'.$titles{$item}.
-                      '</label></span>&nbsp; ';
+        $datatable .= '</tr></table>';
     }
     $datatable .= '</td>';
     unless ($context eq 'requestcourses') {
@@ -1120,25 +1362,84 @@
                   '<td>'.&mt('LON-CAPA Advanced Users').
                   ' <span class="LC_nobreak">('.
                   &mt('overrides affiliation').')</span></td>'.
-                  '<td class="LC_left_item" colspan="2"><br />';
+                  '<td class="LC_left_item" colspan="2">';
+    if ($context eq 'requestcourses') {
+        $datatable .= '<table><tr>';
+    } else {
+        $datatable .= '<br />';
+    }
+    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 .= '<th>'.$titles{$item}.'</th>';
+            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} .= '<span class="LC_nobreak"><label>'.
+                                  '<input type="radio" name="crsreq_'.$item.
+                                  '__LC_adv" value="'.$val.'"'.$checked.' />'.
+                                  $titles{$option}.'</label>';
+                if ($option eq 'autolimit') {
+                    $advcell{$item} .= '<input type="text" name="crsreq_'.
+                                       $item.'_limit__LC_adv" size="1" '.
+                                       'value="'.$currlimit.'" />';
                 }
+                $advcell{$item} .= '</span>&nbsp; ';
             }
+        } 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 .= '<span class="LC_nobreak"><label>'.
+                          '<input type="checkbox" name="'.$context.'_'.$item.
+                          '" value="_LC_adv" '.$checked.'/>'.$titles{$item}.
+                          '</label></span>&nbsp; ';
+        }
+    }
+    if ($context eq 'requestcourses') {
+        $datatable .= '</tr><tr>';
+        foreach my $item (@usertools) {
+            $datatable .= '<td>'.$advcell{$item}.'</td>';
         }
-        $datatable .= '<span class="LC_nobreak"><label>'.
-                      '<input type="checkbox" name="'.$context.'_'.$item.
-                      '" value="_LC_adv" '.$checked.'/>'.$titles{$item}.
-                      '</label></span>&nbsp; ';
+        $datatable .= '</tr></table>';
     }
     $datatable .= '</td></tr>';
     $$rowtotal += $typecount;
@@ -1477,6 +1778,28 @@
     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 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 @@
     }
     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 @@
     }
     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 @@
                     }
                 } else {
                     if ($context eq 'requestcourses') {
-                        if ($confhash{$item}{$type}) {
+                        if ($confhash{$item}{$type} ne 'norequest') {
                             $changes{$item}{$type} = 1;
                         }
                     } else {
@@ -3406,7 +3752,7 @@
                 }
             } else {
                 if ($context eq 'requestcourses') {
-                    if ($confhash{$item}{$type}) {
+                    if ($confhash{$item}{$type} eq 'norequest') {
                         $changes{$item}{$type} = 1;
                     }
                 } else {
@@ -3498,8 +3844,8 @@
                                                           $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 @@
                                 $typetitle = 'LON-CAPA Advanced Users'; 
                             }
                             if ($confhash{$item}{$type}) {
-                                $resulttext .= '<li>'.&mt('Set to be available to [_1]',$typetitle).'</li>';
+                                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 .= '<li>'.&mt('Set to be available to [_1].',$typetitle).' '.$cond.'</li>';
+                                } else {
+                                    $resulttext .= '<li>'.&mt('Set to be available to [_1]',$typetitle).'</li>';
+                                }
                             } else {
                                 $resulttext .= '<li>'.&mt('Set to be unavailable to [_1]',$typetitle).'</li>';
                             }
Index: loncom/interface/loncreateuser.pm
diff -u loncom/interface/loncreateuser.pm:1.305 loncom/interface/loncreateuser.pm:1.306
--- loncom/interface/loncreateuser.pm:1.305	Thu Aug  6 20:40:59 2009
+++ loncom/interface/loncreateuser.pm	Sat Aug  8 00:36:00 2009
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Create a user
 #
-# $Id: loncreateuser.pm,v 1.305 2009/08/06 20:40:59 raeburn Exp $
+# $Id: loncreateuser.pm,v 1.306 2009/08/08 00:36:00 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -216,7 +216,8 @@
 
 sub build_tools_display {
     my ($ccuname,$ccdomain,$context) = @_;
-    my (@usertools,%userenv,$output);
+    my (@usertools,%userenv,$output,@options,%validations,%reqtitles,%reqdisplay,
+        $colspan);
     my %lt = &Apache::lonlocal::texthash (
                    'blog'       => "Personal User Blog",
                    'aboutme'    => "Personal Information Page",
@@ -235,53 +236,123 @@
                       'requestcourses.official','requestcourses.unofficial',
                       'requestcourses.community');
         @usertools = ('official','unofficial','community');
+        @options =('norequest','approve','autolimit','validate');
+        %validations = &Apache::lonnet::auto_courserequest_checks($ccdomain);
+        %reqtitles = &courserequest_titles();
+        %reqdisplay = &courserequest_display();
+        $colspan = ' colspan="2"';
     } else {
         %userenv = &Apache::lonnet::userenvironment($ccdomain,$ccuname,
                           'tools.aboutme','tools.portfolio','tools.blog');
         @usertools = ('aboutme','blog','portfolio');
     }
     foreach my $item (@usertools) {
-        my ($custom_access,$curr_access,$cust_on,$cust_off,$tool_on,$tool_off);
+        my ($custom_access,$curr_access,$cust_on,$cust_off,$tool_on,$tool_off,
+            $currdisp,$custdisp,$custradio);
         $cust_off = 'checked="checked" ';
         $tool_on = 'checked="checked" ';
         $curr_access =  
             &Apache::lonnet::usertools_access($ccuname,$ccdomain,$item,undef,
                                               $context);
-        if ($userenv{$context.'.'.$item} eq '') {
-            $custom_access = 
-                &mt('Availability determined currently from default setting.');
-            if (!$curr_access) {
-                $tool_off = 'checked="checked" ';
-                $tool_on = '';
-            }
-        } else {
-            $custom_access = 
-                &mt('Availability determined currently from custom setting.');
+        if ($userenv{$context.'.'.$item} ne '') {
             $cust_on = ' checked="checked" ';
             $cust_off = '';
-            if ($userenv{$context.'.'.$item} == 0) {
-                $tool_off = 'checked="checked" ';
-                $tool_on = '';
+        }
+        if ($context eq 'requestcourses') {
+            if ($userenv{$context.'.'.$item} eq '') {
+                $custom_access = &mt('Currently from default setting.'); 
+            } else {
+                $custom_access = &mt('Currently from custom setting.');
+            }
+        } else {
+            if ($userenv{$context.'.'.$item} eq '') {
+                $custom_access = 
+                    &mt('Availability determined currently from default setting.');
+                if (!$curr_access) {
+                    $tool_off = 'checked="checked" ';
+                    $tool_on = '';
+                }
+            } else {
+                $custom_access = 
+                    &mt('Availability determined currently from custom setting.');
+                if ($userenv{$context.'.'.$item} == 0) {
+                    $tool_off = 'checked="checked" ';
+                    $tool_on = '';
+                }
             }
         }
         $output .= '  <tr class="LC_info_row">'."\n".
-                   '   <td>'.$lt{$item}.'</td>'."\n".
+                   '   <td'.$colspan.'>'.$lt{$item}.'</td>'."\n".
                    '  </tr>'."\n".
-                   &Apache::loncommon::start_data_table_row()."\n".
-                   '  <td>'.$custom_access.('&nbsp;'x5).$lt{'avai'}.': '.
-                   ($curr_access?&mt('Yes'):&mt('No')).'</td>'."\n".
+                   &Apache::loncommon::start_data_table_row()."\n";
+        if ($context eq 'requestcourses') {
+            my ($curroption,$currlimit);
+            $curroption = $userenv{$context.'.'.$item};
+            if (!$curroption) {
+                $curroption = 'norequest';
+            }
+            if ($curroption =~ /^autolimit=(\d*)$/) {
+                $currlimit = $1;
+                $currdisp = &mt('Yes, up to [quant,_1,request]/user',$currlimit); 
+            } else {
+                $currdisp = $reqdisplay{$curroption};
+            }
+            $custdisp = '<table>';
+            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}{'_custom_'}) {
+                            $canvalidate = 1;
+                        }
+                    }
+                    next if (!$canvalidate);
+                }
+                my $checked = '';
+                if ($option eq $curroption) {
+                    $checked = ' checked="checked"';
+                } elsif ($option eq 'autolimit') {
+                    if ($curroption =~ /^autolimit/) {
+                        $checked = ' checked="checked"';
+                    }
+                }
+                $custdisp .= '<tr><td><span class="LC_nobreak"><label>'.
+                             '<input type="radio" name="crsreq_'.$item.
+                             '" value="'.$val.'"'.$checked.' />'.
+                             $reqtitles{$option}.'</label>&nbsp;';
+                if ($option eq 'autolimit') {
+                    $custdisp .= '<input type="text" name="crsreq_'.
+                                 $item.'_limit" size="1" '.
+                                 'value="'.$currlimit.'" />';
+                 }
+                 $custdisp .= '</span></td></tr>';
+            }
+            $custdisp .= '</table>';
+            $custradio = '</span></td><td>'.&mt('Custom setting').'<br />'.$custdisp;
+        } else {
+            $currdisp = ($curr_access?&mt('Yes'):&mt('No'));
+            $custdisp = '<span class="LC_nobreak"><label>'.
+                        '<input type="radio" name="'.$context.'_'.$item.'"'. 
+                        ' value="1"'. $tool_on.'/>'.&mt('On').'</label>&nbsp;<label>'.
+                        '<input type="radio" name="'.$context.'_'.$item.'" value="0" '.
+                        $tool_off.'/>'.&mt('Off').'</label></span>';
+            $custradio = ('&nbsp;'x2).'--'.$lt{'cusa'}.':&nbsp;'.$custdisp.
+                          '</span>';
+        }
+        $output .= '  <td'.$colspan.'>'.$custom_access.('&nbsp;'x4).
+                   $lt{'avai'}.': '.$currdisp.'</td>'."\n".
                    &Apache::loncommon::end_data_table_row()."\n".
                    &Apache::loncommon::start_data_table_row()."\n".
-                   '  <td><span class="LC_nobreak">'.$lt{'chse'}.': <label>'.
+                   '  <td style="vertical-align:top;"><span class="LC_nobreak">'.
+                   $lt{'chse'}.': <label>'.
                    '<input type="radio" name="custom'.$item.'" value="0" '.
-                   $cust_off.'/>'.$lt{'usde'}.'</label>&nbsp;&nbsp;&nbsp;'.
-                    '<label><input type="radio" name="custom'.$item.'" value="1" '.
-                   $cust_on.'/>'.$lt{'uscu'}.'</label>&nbsp;&nbsp;--&nbsp;&nbsp;'.
-                   $lt{'cusa'}.':&nbsp;<label>'.
-                   '<input type="radio" name="'.$context.'_'.$item.'" value="1" '.
-                   $tool_on.'/>'.&mt('On').'</label>&nbsp;<label>'.
-                   '<input type="radio" name="'.$context.'_'.$item.'" value="0" '.
-                   $tool_off.'/>'.&mt('Off').'</label></span></td>'."\n".
+                   $cust_off.'/>'.$lt{'usde'}.'</label>'.('&nbsp;' x3).
+                   '<label><input type="radio" name="custom'.$item.'" value="1" '.
+                   $cust_on.'/>'.$lt{'uscu'}.'</label>'.$custradio.'</td>'.
                    &Apache::loncommon::end_data_table_row()."\n";
     }
     return $output;
@@ -289,7 +360,7 @@
 
 sub coursereq_externaluser {
     my ($ccuname,$ccdomain,$cdom) = @_;
-    my (@usertools,%userenv,$output);
+    my (@usertools,@options,%validations,%userenv,$output);
     my %lt = &Apache::lonlocal::texthash (
                    'official'   => 'Can request creation of official courses',
                    'unofficial' => 'Can request creation of unofficial courses',
@@ -300,27 +371,83 @@
                       'reqcrsotherdom.official','reqcrsotherdom.unofficial',
                       'reqcrsotherdom.community');
     @usertools = ('official','unofficial','community');
+    @options = ('approve','validate','autolimit');
+    %validations = &Apache::lonnet::auto_courserequest_checks($cdom);
+    my $optregex = join('|',@options);
+    my %reqtitles = &courserequest_titles();
     foreach my $item (@usertools) {
-        my ($tool_on,$tool_off);
-        $tool_off = 'checked="checked" ';
+        my ($curroption,$currlimit,$tooloff);
         if ($userenv{'reqcrsotherdom.'.$item} ne '') {
             my @curr = split(',',$userenv{'reqcrsotherdom.'.$item});
-            if (grep(/^\Q$cdom\E$/,@curr)) {
-                $tool_on = 'checked="checked" ';
-                $tool_off = '';
+            if (grep(/^\Q$cdom\E:($optregex)=?(\d*)$/,@curr)) {
+                $curroption = $1;
+                $currlimit = $2;
+                if (!$curroption) {
+                    $curroption = 'norequest';
+                }
+            }
+        } else {
+            $curroption = 'norequest';
+            $tooloff = ' checked="checked"';
+        }
+        $output.= &Apache::loncommon::start_data_table_row()."\n".
+                  '  <td><span class="LC_nobreak">'.$lt{$item}.': '.
+                  '<label><input type="radio" name="reqcrsotherdom_'.$item.
+                  '" value="0"'.$tooloff.' />'.$reqtitles{'norequest'}.
+                  '</label>&nbsp;';
+        foreach my $option (@options) {
+            if ($option eq 'validate') {
+                my $canvalidate = 0;
+                if (ref($validations{$item}) eq 'HASH') {
+                    if ($validations{$item}{'_external_'}) {
+                        $canvalidate = 1;
+                    }
+                }
+                next if (!$canvalidate);
+            }
+            my $checked = '';
+            if ($option eq $curroption) {
+                $checked = ' checked="checked"';
+            }
+            $output .= '<span class="LC_nobreak"><label>'.
+                       '<input type="radio" name="reqcrsotherdom_'.$item.
+                       '" value="'.$option.'"'.$checked.' />'.
+                       $reqtitles{$option}.'</label>&nbsp;';
+            if ($option eq 'autolimit') {
+                $output .= '<input type="text" name="reqcrsotherdom_'.
+                           $item.'_limit" size="1" '.
+                           'value="'.$currlimit.'" />';
             }
+            $output .= '&nbsp;'
         }
-        $output .= &Apache::loncommon::start_data_table_row()."\n".
-                   '  <td><span class="LC_nobreak">'.$lt{$item}.': <label>'.
-                   '<input type="radio" name="reqcrsotherdom_'.$item.'" value="1" '.
-                   $tool_on.'/>'.&mt('Yes').'</label>&nbsp;<label>'.
-                   '<input type="radio" name="reqcrsotherdom_'.$item.'" value="0" '.
-                   $tool_off.'/>'.&mt('No').'</label></span></td>'."\n".
+        $output .= '</span></td>'."\n".
                    &Apache::loncommon::end_data_table_row()."\n";
     }
     return $output;
 }
 
+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_display {
+    my %titles = &Apache::lonlocal::texthash (
+                                   approve    => 'Yes, need approval',
+                                   validate   => 'Yes, with validation',
+                                   norequest  => 'No',
+   );
+   return %titles;
+}
+
 # =================================================================== Phase one
 
 sub print_username_entry_form {
@@ -2031,7 +2158,13 @@
                 }
             }
             foreach my $item (@requestcourses) {
-                $newcustom{$item} = $env{'form.requestcourses_'.$item};
+                $newcustom{$item} = $env{'form.crsreq_'.$item};
+                if ($env{'form.crsreq_'.$item} eq 'autolimit') {
+                    $newcustom{$item} .= '=';
+                    unless ($env{'form.crsreq_'.$item.'_limit'} =~ /\D/) {
+                        $newcustom{$item} .= $env{'form.crsreq_'.$item.'_limit'};
+                    }
+                }
                 $changed{$item} = &tool_admin($item,$newcustom{$item},
                                               \%changeHash,'requestcourses');
             }
@@ -2677,6 +2810,9 @@
         return;
     }
     if ($context eq 'reqcrsotherdom') {
+        my @options = ('approve','validate','autolimit');
+        my $optregex = join('|',@options);
+        my %reqdisplay = &courserequest_display();
         my $cdom = $env{'request.role.domain'};
         foreach my $tool (@{$usertools}) {
             $oldaccesstext->{$tool} = &mt('no');
@@ -2695,19 +2831,31 @@
                 my @curr = split(',',$userenv->{$context.'.'.$tool});
                 my @new;
                 my $changedoms;
-                if (grep(/^\Q$cdom\E$/,@curr)) {
+                my $newop = $env{'form.'.$context.'_'.$tool};
+                if ($newop eq 'autolimit') {
+                    $newop .= '=';
+                    unless ($env{'form.'.$context.'_'.$tool.'_limit'} =~ /\D/) {
+                        $newop .= $env{'form.'.$context.'_'.$tool.'_limit'};
+                    }
+                }  
+                if (grep(/^\Q$cdom:($optregex\=?\d*)\E$/,@curr)) {
                     $oldaccesstext->{$tool} = &mt('yes');
-                    unless ($env{'form.'.$context.'_'.$tool}) {
+                    my $oldop = $1;
+                    if ($oldop ne $newop) {
                         $changedoms = 1;
                         foreach my $dom (@curr) {
                             unless ($dom eq $cdom) {
                                 push(@new,$dom);
                             }
                         }
+                        if ($newop) {
+                            push(@new,$cdom.':'.$newop);
+                        }
+                        @new = sort(@new);
                     }
                 } elsif ($env{'form.'.$context.'_'.$tool}) {
                     $changedoms = 1;
-                    @new = sort(@curr,$cdom);
+                    @new = sort(@curr,$cdom.':'.$newop);
                 }
                 $newaccesstext->{$tool} = $oldaccesstext->{$tool};
                 if ($changedoms) {
@@ -2719,9 +2867,17 @@
                                                   $context);
                     if ($changed->{$tool}) {
                         if ($env{'form.'.$context.'_'.$tool}) {
-                            $newaccesstext->{$tool} = &mt('yes'); 
+                            if ($env{'form.'.$context.'_'.$tool} eq 'autolimit') {
+                                if ($env{'form.'.$context.'_'.$tool.'_limit'} =~ /\D/) {
+                                    $newaccesstext->{$tool} = &mt('Yes, processed automatically');
+                                } else {
+                                    $newaccesstext->{$tool} = &mt('Yes, up to limit of [quant,_1,request] per user).',$env{'form.'.$context.'_'.$tool.'_limit'});
+                                }
+                            } else {  
+                                $newaccesstext->{$tool} = $reqdisplay{$env{'form.'.$context.'_'.$tool}};
+                            }
                         } else {
-                            $newaccesstext->{$tool} = &mt('no');
+                            $newaccesstext->{$tool} = &mt('No');
                         }
                     }
                 }
@@ -2730,6 +2886,15 @@
         return;
     }
     foreach my $tool (@{$usertools}) {
+        my $newval;
+        if ($context eq 'requestcourses') {
+            $newval = $env{'form.crsreq_'.$tool};
+            if ($newval eq 'autolimit') {
+                $newval .= '='.$env{'form.crsreq_'.$tool.'_limit'};
+            }
+        } else {  
+            $newval = $env{'form.'.$context.'_'.$tool};
+        }
         if ($userenv->{$context.'.'.$tool} ne '') {
             $oldaccess->{$tool} = &mt('custom');
             if ($userenv->{$context.'.'.$tool}) {
@@ -2739,12 +2904,12 @@
             }
             $changeHash->{$context.'.'.$tool} = $userenv->{$context.'.'.$tool};
             if ($env{'form.custom'.$tool} == 1) {
-                if ($env{'form.'.$context.'_'.$tool} ne $userenv->{$context.'.'.$tool}) {
-                    $changed->{$tool} = &tool_admin($tool,$env{'form.'.$context.'_'.$tool},
-                                                  $changeHash,$context);
+                if ($newval ne $userenv->{$context.'.'.$tool}) {
+                    $changed->{$tool} = &tool_admin($tool,$newval,$changeHash,
+                                                    $context);
                     if ($changed->{$tool}) {
                         $newaccess->{$tool} = &mt('custom');
-                        if ($env{'form.'.$context.'_'.$tool}) {
+                        if ($newval) {
                             $newaccesstext->{$tool} = &mt("availability set to 'on'");
                         } else {
                             $newaccesstext->{$tool} = &mt("availability set to 'off'");
@@ -2777,11 +2942,11 @@
         } else {
             $oldaccess->{$tool} = &mt('default');
             if ($env{'form.custom'.$tool} == 1) {
-                $changed->{$tool} = &tool_admin($tool,$env{'form.'.$context.'_'.$tool},
-                                                $changeHash,$context);
+                $changed->{$tool} = &tool_admin($tool,$newval,$changeHash,
+                                                $context);
                 if ($changed->{$tool}) {
                     $newaccess->{$tool} = &mt('custom');
-                    if ($env{'form.'.$context.'_'.$tool}) {
+                    if ($newval) {
                         $newaccesstext->{$tool} = &mt("availability set to 'on'");
                     } else {
                         $newaccesstext->{$tool} = &mt("availability set to 'off'");
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1009 loncom/lonnet/perl/lonnet.pm:1.1010
--- loncom/lonnet/perl/lonnet.pm:1.1009	Thu Aug  6 04:54:23 2009
+++ loncom/lonnet/perl/lonnet.pm	Sat Aug  8 00:36:10 2009
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1009 2009/08/06 04:54:23 raeburn Exp $
+# $Id: lonnet.pm,v 1.1010 2009/08/08 00:36:10 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -5771,6 +5771,12 @@
     return $response;
 }
 
+sub auto_courserequest_checks {
+    my ($dom) = @_;
+    my %validations;
+    return %validations; 
+}
+
 sub auto_validate_class_sec {
     my ($cdom,$cnum,$owners,$inst_class) = @_;
     my $homeserver = &homeserver($cnum,$cdom);

--raeburn1249691770--