[LON-CAPA-cvs] cvs: loncom / lond /enrollment Autoenroll.pl localenroll.pm /interface coursecatalog.pm loncommon.pm loncoursequeueadmin.pm lonmodifycourse.pm lonpopulate.pm selfenroll.pm /lonnet/perl lonnet.pm
raeburn
raeburn at source.lon-capa.org
Tue Jun 15 16:52:28 EDT 2021
raeburn Tue Jun 15 20:52:28 2021 EDT
Modified files:
/loncom/interface coursecatalog.pm loncommon.pm
loncoursequeueadmin.pm lonmodifycourse.pm
lonpopulate.pm selfenroll.pm
/loncom lond
/loncom/enrollment Autoenroll.pl localenroll.pm
/loncom/lonnet/perl lonnet.pm
Log:
- Support customization in localenroll.pm to eliminate ambiguity in extraction
of institutional section from institutional course section for automated
enrollment.
-------------- next part --------------
Index: loncom/interface/coursecatalog.pm
diff -u loncom/interface/coursecatalog.pm:1.104 loncom/interface/coursecatalog.pm:1.105
--- loncom/interface/coursecatalog.pm:1.104 Fri Apr 30 18:19:41 2021
+++ loncom/interface/coursecatalog.pm Tue Jun 15 20:52:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# Handler for displaying the course catalog interface
#
-# $Id: coursecatalog.pm,v 1.104 2021/04/30 18:19:41 raeburn Exp $
+# $Id: coursecatalog.pm,v 1.105 2021/06/15 20:52:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1511,6 +1511,25 @@
}
my $count = 1;
my $totalsec = 0;
+ my %clutteredxlists;
+ foreach my $course (keys(%courseinfo)) {
+ if (ref($courseinfo{$course}) eq 'HASH') {
+ if ($courseinfo{$course}{'xlist'} ne '') {
+ my $crskey = $courseinfo{$course}{'cnum'}.':'.$courseinfo{$course}{'code'};
+ my @xlists = split(/,\s/,$courseinfo{$course}{'xlist'});
+ $clutteredxlists{$crskey} = \@xlists;
+ }
+ }
+ }
+ if (keys(%clutteredxlists)) {
+ my %reformattedxlists = &Apache::lonnet::auto_instsec_reformat($domain,'declutter',\%clutteredxlists);
+ foreach my $crskey (keys(%reformattedxlists)) {
+ if (ref($reformattedxlists{$crskey}) eq 'ARRAY') {
+ my $course = $domain.'_'.(split(/:/,$crskey))[0];
+ $courseinfo{$course}{'xlist'} = join(', ',@{$reformattedxlists{$crskey}});
+ }
+ }
+ }
foreach my $item (@sorted_courses) {
foreach my $course (@{$Sortby{$item}}) {
$output.=&Apache::loncommon::start_data_table_row();
@@ -1971,13 +1990,19 @@
sub get_valid_classes {
my ($seclist,$xlist_items,$crscode,$owners,$cdom,$cnum) = @_;
my $response;
- my (@sections, at xlists,%possclasses,%okclasses,%validations);
+ my (@sections, at format_sections, at xlists,%possclasses,%okclasses,%validations);
@{$validations{'sections'}} = ();
@{$validations{'xlists'}} = ();
my $totalitems = 0;
if ($seclist) {
@sections = split(/,\s+/,$seclist);
- map { $possclasses{$crscode.$_} = 1; } @sections;
+ my $crskey = $cnum.':'.$crscode;
+ my %formattedsec = &Apache::lonnet::auto_instsec_reformat($cdom,'clutter',
+ {$crskey => \@sections});
+ if (ref($formattedsec{$crskey}) eq 'ARRAY') {
+ @format_sections = @{$formattedsec{$crskey}};
+ map { $possclasses{$crscode.$_} = 1; } @format_sections;
+ }
}
if ($xlist_items) {
@xlists = split(/,\s+/,$xlist_items);
@@ -1986,9 +2011,10 @@
my %okclasses = &Apache::lonnet::auto_validate_instclasses($cdom,$cnum,$owners,
\%possclasses);
if (keys(%okclasses)) {
- foreach my $sec (@sections) {
- if ($okclasses{$crscode.$sec}) {
- if (!grep(/^\Q$sec$\E/,@{$validations{'sections'}})) {
+ for (my $i=0; $i<@sections; $i++) {
+ if ($okclasses{$crscode.$format_sections[$i]}) {
+ my $sec = $sections[$i];
+ if (!grep(/^\Q$sec\E$/,@{$validations{'sections'}})) {
push(@{$validations{'sections'}},$sec);
$totalitems ++;
}
@@ -2009,6 +2035,13 @@
join(', ',@{$validations{'sections'}}).'<br />';
}
if (@{$validations{'xlists'}}) {
+ my $crskey = $cnum.':'.$crscode;
+ my %reformattedxlists =
+ &Apache::lonnet::auto_instsec_reformat($cdom,'declutter',
+ {$crskey => $validations{'xlists'}});
+ if (ref($reformattedxlists{$crskey}) eq 'ARRAY') {
+ $validations{'xlists'} = $reformattedxlists{$crskey};
+ }
$response .= &mt('Courses:').' '.
join(', ',@{$validations{'xlists'}});
}
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1360 loncom/interface/loncommon.pm:1.1361
--- loncom/interface/loncommon.pm:1.1360 Sat Jun 12 20:51:38 2021
+++ loncom/interface/loncommon.pm Tue Jun 15 20:52:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# a pile of common routines
#
-# $Id: loncommon.pm,v 1.1360 2021/06/12 20:51:38 raeburn Exp $
+# $Id: loncommon.pm,v 1.1361 2021/06/15 20:52:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -11156,11 +11156,15 @@
}
sub get_institutional_codes {
- my ($settings,$allcourses,$LC_code) = @_;
+ my ($cdom,$crs,$settings,$allcourses,$LC_code) = @_;
# Get complete list of course sections to update
my @currsections = ();
my @currxlists = ();
+ my (%unclutteredsec,%unclutteredlcsec);
my $coursecode = $$settings{'internal.coursecode'};
+ my $crskey = $crs.':'.$coursecode;
+ @{$unclutteredsec{$crskey}} = ();
+ @{$unclutteredlcsec{$crskey}} = ();
if ($$settings{'internal.sectionnums'} ne '') {
@currsections = split(/,/,$$settings{'internal.sectionnums'});
@@ -11171,8 +11175,8 @@
}
if (@currxlists > 0) {
- foreach (@currxlists) {
- if (m/^([^:]+):(\w*)$/) {
+ foreach my $xl (@currxlists) {
+ if ($xl =~ /^([^:]+):(\w*)$/) {
unless (grep/^$1$/,@{$allcourses}) {
push(@{$allcourses},$1);
$$LC_code{$1} = $2;
@@ -11180,15 +11184,28 @@
}
}
}
-
+
if (@currsections > 0) {
- foreach (@currsections) {
- if (m/^(\w+):(\w*)$/) {
- my $sec = $coursecode.$1;
+ foreach my $sec (@currsections) {
+ if ($sec =~ m/^(\w+):(\w*)$/ ) {
+ my $instsec = $1;
my $lc_sec = $2;
- unless (grep/^$sec$/,@{$allcourses}) {
+ unless (grep/^\Q$instsec\E$/,@{$unclutteredsec{$crskey}}) {
+ push(@{$unclutteredsec{$crskey}},$instsec);
+ push(@{$unclutteredlcsec{$crskey}},$lc_sec);
+ }
+ }
+ }
+ }
+
+ if (@{$unclutteredsec{$crskey}} > 0) {
+ my %formattedsec = &Apache::lonnet::auto_instsec_reformat($cdom,'clutter',\%unclutteredsec);
+ if ((ref($formattedsec{$crskey}) eq 'ARRAY') && (ref($unclutteredlcsec{$crskey}) eq 'ARRAY')) {
+ for (my $i=0; $i<@{$formattedsec{$crskey}}; $i++) {
+ my $sec = $coursecode.$formattedsec{$crskey}[$i];
+ unless (grep/^\Q$sec\E$/,@{$allcourses}) {
push(@{$allcourses},$sec);
- $$LC_code{$sec} = $lc_sec;
+ $$LC_code{$sec} = $unclutteredlcsec{$crskey}[$i];
}
}
}
Index: loncom/interface/loncoursequeueadmin.pm
diff -u loncom/interface/loncoursequeueadmin.pm:1.60 loncom/interface/loncoursequeueadmin.pm:1.61
--- loncom/interface/loncoursequeueadmin.pm:1.60 Fri Aug 21 21:59:20 2020
+++ loncom/interface/loncoursequeueadmin.pm Tue Jun 15 20:52:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Utilities to administer domain course requests and course self-enroll requests
#
-# $Id: loncoursequeueadmin.pm,v 1.60 2020/08/21 21:59:20 raeburn Exp $
+# $Id: loncoursequeueadmin.pm,v 1.61 2021/06/15 20:52:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -1647,7 +1647,7 @@
$owneremail = $emails{$email};
last if ($owneremail ne '');
}
- my %reqdetails = &build_batchcreatehash($dom,$context,$details,$owneremail,$domdefs);
+ my %reqdetails = &build_batchcreatehash($dom,$cnum,$context,$details,$owneremail,$domdefs);
my $cid = &LONCAPA::batchcreatecourse::build_course($dom,$cnum,'requestcourses',
\%reqdetails,$longroles,$logmsg,$clonemsg,$newusermsg,$addresult,
$enrollcount,$output,$keysmsg,$ownerdom,$ownername,$cnum,$crstype,
@@ -1669,7 +1669,7 @@
}
sub build_batchcreatehash {
- my ($dom,$context,$details,$owneremail,$domdefs) = @_;
+ my ($dom,$cnum,$context,$details,$owneremail,$domdefs) = @_;
my %batchhash;
my @items = qw{owner domain coursehome clonecrs clonedom datemode dateshift tinyurls enrollstart enrollend accessstart accessend sections users uniquecode};
if ((ref($details) eq 'HASH') && (ref($domdefs) eq 'HASH')) {
@@ -1681,7 +1681,14 @@
if (ref($details->{'crosslists'}) eq 'HASH') {
foreach my $key (keys(%{$details->{'crosslists'}})) {
if (ref($details->{'crosslists'}->{$key}) eq 'HASH') {
- $batchhash{'crosslists'}{$key}{'inst'} = $details->{crosslists}->{$key}->{instcode}.$details->{crosslists}->{$key}->{instsec};
+ my $instsec = $details->{crosslists}->{$key}->{instsec};
+ $batchhash{'crosslists'}{$key}{'inst'} = $details->{crosslists}->{$key}->{instcode};
+ my $crskey = $cnum.':'.$batchhash{'crosslists'}{$key}{'inst'};
+ my %formatted = &Apache::lonnet::auto_instsec_reformat($dom,'clutter',
+ {$crskey => [$instsec]});
+ if (ref($formatted{$crskey}) eq 'ARRAY') {
+ $batchhash{'crosslists'}{$key}{'inst'} .= $formatted{$crskey}->[0];
+ }
$batchhash{'crosslists'}{$key}{'loncapa'} = $details->{crosslists}->{$key}->{loncapa};
}
}
Index: loncom/interface/lonmodifycourse.pm
diff -u loncom/interface/lonmodifycourse.pm:1.95 loncom/interface/lonmodifycourse.pm:1.96
--- loncom/interface/lonmodifycourse.pm:1.95 Thu Jul 25 20:23:52 2019
+++ loncom/interface/lonmodifycourse.pm Tue Jun 15 20:52:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network with CAPA
# handler for DC-only modifiable course settings
#
-# $Id: lonmodifycourse.pm,v 1.95 2019/07/25 20:23:52 raeburn Exp $
+# $Id: lonmodifycourse.pm,v 1.96 2021/06/15 20:52:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -684,9 +684,34 @@
"<th>$lt{'dcon'}</th>\n".
&Apache::loncommon::end_data_table_header_row()."\n";
foreach my $item (@items) {
+ my $shown = $enrollvar{$item};
+ if ($item eq 'crosslistings') {
+ my (@xlists, at lcsecs);
+ foreach my $entry (split(/,/,$enrollvar{$item})) {
+ my ($xlist,$lc_sec) = split(/:/,$entry);
+ push(@xlists,$xlist);
+ push(@lcsecs,$lc_sec);
+ }
+ if (@xlists) {
+ my $crskey = $cnum.':'.$enrollvar{'coursecode'};
+ my %reformatted =
+ &Apache::lonnet::auto_instsec_reformat($cdom,'declutter',
+ {$crskey => \@xlists});
+ if (ref($reformatted{$crskey}) eq 'ARRAY') {
+ my @show;
+ my @xlcodes = @{$reformatted{$crskey}};
+ for (my $i=0; $i<@xlcodes; $i++) {
+ push(@show,$xlcodes[$i].':'.$lcsecs[$i]);
+ }
+ if (@show) {
+ $shown = join(',', at show);
+ }
+ }
+ }
+ }
$disp_table .= &Apache::loncommon::start_data_table_row()."\n".
"<td><b>$longtype{$item}</b></td>\n".
- "<td>$enrollvar{$item}</td>\n";
+ "<td>$shown</td>\n";
if (grep(/^\Q$item\E$/, at modifiable_params)) {
$disp_table .= '<td align="right">'.&mt('Yes').'</td>'."\n";
} else {
Index: loncom/interface/lonpopulate.pm
diff -u loncom/interface/lonpopulate.pm:1.86 loncom/interface/lonpopulate.pm:1.87
--- loncom/interface/lonpopulate.pm:1.86 Wed Mar 31 02:19:59 2021
+++ loncom/interface/lonpopulate.pm Tue Jun 15 20:52:26 2021
@@ -1,5 +1,5 @@
# automated enrollment configuration handler
-# $Id: lonpopulate.pm,v 1.86 2021/03/31 02:19:59 raeburn Exp $
+# $Id: lonpopulate.pm,v 1.87 2021/06/15 20:52:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -37,6 +37,7 @@
use Apache::Constants qw(:common :http REDIRECT);
use Time::Local;
use LONCAPA::Enrollment;
+use LONCAPA qw(:DEFAULT :match);
###############################################################
sub header {
@@ -903,10 +904,12 @@
<th>'.&mt('LON-CAPA section ID').'</th>
');
$r->print(&Apache::loncommon::end_data_table_row());
- for (my $i=0; $i<@xlists; $i++) {
+ my @showable;
+ &reformat_xlists($dom,$crs,$enrollvar{'coursecode'},\@xlists,\@showable);
+ for (my $i=0; $i<@showable; $i++) {
my $xl = ' ';
my $lc_sec = ' ';
- if ($xlists[$i] =~ /^([^:]+):?(.*)$/) {
+ if ($showable[$i] =~ /^([^:]+):?(.*)$/) {
$xl = $1;
$lc_sec = $2;
}
@@ -2063,8 +2066,10 @@
if ($crosscount > 0) {
$response .= &mt('The [quant,_1,course] listed below remain crosslisted with this LON-CAPA course, and students enrolling in these course sections will be automatically added to the class roster for the course, if you have chosen to enable a nightly automated enrollment update.',$crosscount).
'<br /><ul>'."\n";
- foreach my $xl (@xlists) {
- my ($xlist,$lc_sec) = split(/:/,$xl);
+ my @showable;
+ &reformat_xlists($dom,$crs,$coursecode,\@xlists,\@showable);
+ foreach my $item (@showable) {
+ my ($xlist,$lc_sec) = split(/:/,$item);
$response .=
'<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'."\n";
}
@@ -2074,26 +2079,86 @@
if ( exists($env{'form.numcross'}) ) {
my $numcross = $env{'form.numcross'};
if ($numcross) {
- $response .=
- &mt('You indicated that you wish to add an additional [quant,_1,crosslisting].',$numcross).' '.
- &mt('For each new crosslisting enter the institutional course section code (e.g., fs03zol101001, for section 001 of zol101 for fs03 semester), and the LON-CAPA section ID you wish to assign to students who will be enrolled in your LON-CAPA class as a result of their registration in the crosslisted course section.').' '.
- &mt('The LON-CAPA section ID can be left blank, if you do not wish to tie a section ID to this crosslisting.').' '.
- &mt("The institutional course section code should only contain letters and/or numbers, and must be consistent with the scheme adopted by your Domain Coordinator to map course codes (and section numbers) to your institution's student information system.").
- '<br /><br />
- <form name="enter" method="post" action="">'.
- &Apache::loncommon::start_data_table().
- &Apache::loncommon::start_data_table_row().'
- <th>'.&mt('Crosslisting').'</th>
- <th>'.&mt('LON-CAPA section ID').'</th>'."\n".
- &Apache::loncommon::end_data_table_row();
- for (my $i=0; $i<$numcross; $i++) {
- $response .=
- &Apache::loncommon::start_data_table_row().'
- <td><input type="text" size="15" name="newcross_'.$i.'" /></td>
- <td align="right"><input type="text" size="10" name="newlcsec_'.$i.'" /></td>'.
+ my (@codetitles,%cat_titles,%cat_order, at code_order);
+ &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles,
+ \%cat_order,\@code_order);
+ $response .=
+ &mt('You indicated that you wish to add an additional [quant,_1,crosslisting].',$numcross).' ';
+ if (@codetitles > 0) {
+ my $lastitem = pop(@codetitles);
+ $response .=
+ &mt('For each new crosslisting select [_1], and enter the [_2] and the LON-CAPA section ID.',join(', ', at codetitles),$lastitem).' '.
+ &mt('The LON-CAPA section ID can be left blank, if you do not wish to tie a section ID to this crosslisting.').' '.
+ '<br /><br />'.
+ '<form name="enter" method="post" action="">'."\n".
+ &Apache::loncommon::start_data_table()."\n".
+ &Apache::loncommon::start_data_table_header_row()."\n";
+ foreach my $title (@codetitles) {
+ if (ref($cat_order{$title}) eq 'ARRAY') {
+ if (@{$cat_order{$title}} > 0) {
+ $response .= '<th>'.$title.'</th>';
+ }
+ }
+ }
+ $response .= '<th>'.$lastitem.'</th>'."\n".
+ '<th>'.&mt('Institutional section').'</th>'."\n".
+ '<th>'.&mt('LON-CAPA section').'</th>'."\n".
+ &Apache::loncommon::end_data_table_header_row()."\n";
+ for (my $i=0; $i<$numcross; $i++) {
+ $response .=
+ &Apache::loncommon::start_data_table_row()."\n";
+ foreach my $title (@codetitles) {
+ if (ref($cat_order{$title}) eq 'ARRAY') {
+ if (@{$cat_order{$title}} > 0) {
+ $response .= '<td align="center">'.
+ '<select name="newcross_'.$i.'_'.$title.'">'."\n".
+ ' <option value="" selected="selected">'.
+ &mt('Select').'</option>'."\n";
+ foreach my $item (@{$cat_order{$title}}) {
+ my $longitem = $item;
+ if (ref($cat_titles{$title}) eq 'HASH') {
+ if ($cat_titles{$title}{$item} ne '') {
+ $longitem = $cat_titles{$title}{$item};
+ }
+ }
+ $response .= '<option value="'.$item.'">'.$longitem.
+ '</option>'."\n";
+ }
+ $response .= '</select></td>'."\n";
+ }
+ }
+ }
+ $response .= '<td align="center">'.
+ '<input type="text" size="5" name="newcross_'.$i.'_'.$lastitem.'" />'.
+ '</td>'."\n".'<td align="center">'.
+ '<input type="text" size="10" name="newcross_'.$i.'_instsec" />'.
+ '</td>'."\n".'<td align="center">'.
+ '<input type="text" size="10" name="newlcsec_'.$i.'" /></td>'.
+ &Apache::loncommon::end_data_table_row()."\n";
+ }
+ $response .= &Apache::loncommon::end_data_table()."\n";
+ } else {
+ $response .=
+ &mt('For each new crosslisting enter the institutional course section code (e.g., fs03zol101001, for section 001 of zol101 for fs03 semester), and the LON-CAPA section ID you wish to assign to students who will be enrolled in your LON-CAPA class as a result of their registration in the crosslisted course section.').' '.
+ &mt('The LON-CAPA section ID can be left blank, if you do not wish to tie a section ID to this crosslisting.').' '.
+ &mt("The institutional course section code should only contain letters and/or numbers, and must be consistent with the scheme adopted by your Domain Coordinator to map course codes (and section numbers) to your institution's student information system.").
+ '<br /><br />'.
+ '<form name="enter" method="post" action="">'."\n".
+ &Apache::loncommon::start_data_table()."\n".
+ &Apache::loncommon::start_data_table_row()."\n".
+ '<th>'.&mt('Crosslisting').'</th>'."\n".
+ '<th>'.&mt('LON-CAPA section ID').'</th>'."\n".
&Apache::loncommon::end_data_table_row();
- }
- $response .= &Apache::loncommon::end_data_table().'
+ for (my $i=0; $i<$numcross; $i++) {
+ $response .=
+ &Apache::loncommon::start_data_table_row().'
+ <td><input type="text" size="15" name="newcross_'.$i.'" /></td>
+ <td align="right"><input type="text" size="10" name="newlcsec_'.$i.'" /></td>'.
+ &Apache::loncommon::end_data_table_row();
+ }
+ $response .= &Apache::loncommon::end_data_table();
+ }
+ $response .= '
</td>
</tr>
<tr>
@@ -2134,32 +2199,64 @@
}
if ($numcross) {
my %curr_groups = &Apache::longroup::coursegroups();
+ my (@codetitles,%cat_titles,%cat_order, at code_order);
+ &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles,
+ \%cat_order,\@code_order);
+ my $lastitem = $codetitles[-1];
for (my $i=0; $i<$numcross; $i++) {
- my $xl = "newcross_".$i;
+ my $xl = '';
+ if (@code_order > 0) {
+ foreach my $item (@code_order) {
+ my $possval = $env{'form.newcross_'.$i.'_'.$item};
+ if ($item eq $lastitem) {
+ $xl .= $possval;
+ } else {
+ my $possval = $env{'form.newcross_'.$i.'_'.$item};
+ if (ref($cat_order{$item}) eq 'ARRAY') {
+ if (grep(/^\Q$possval\E$/,@{$cat_order{$item}})) {
+ $xl .= $possval;
+ }
+ }
+ }
+ }
+ if ($xl ne '') {
+ my $crskey = $crs.':'.$xl;
+ if ($env{'form.newcross_'.$i.'_instsec'} ne '') {
+ my $poss_sec = $env{'form.newcross_'.$i.'_instsec'};
+ my %formatted = &Apache::lonnet::auto_instsec_reformat($dom,'clutter',
+ {$crskey => [$poss_sec]});
+ if (ref($formatted{$crskey}) eq 'ARRAY') {
+ $xl .= $formatted{$crskey}->[0];
+ }
+ }
+ }
+ } else {
+ $xl = $env{'form.newcross_'.$i};
+ }
my $lc_sec = "newlcsec_".$i;
- if ( exists($env{"form.$xl"}) ) {
+ if ($xl ne '') {
if (exists($env{"form.$lc_sec"})) {
my $lc_sec_check = &validate_lcsec(\%curr_groups,
$env{"form.$lc_sec"});
if ($lc_sec_check eq 'reserved') {
- push(@reserved,$env{"form.$xl"}.":".$env{"form.$lc_sec"});
+ push(@reserved,$xl.':'.$env{"form.$lc_sec"});
next;
} elsif ($lc_sec_check eq 'group') {
- push(@matchgroup,$env{"form.$xl"}.":".$env{"form.$lc_sec"});
+ push(@matchgroup,$xl.':'.$env{"form.$lc_sec"});
next;
}
}
my $coursecheck =
- &Apache::lonnet::auto_validate_courseID($crs,$dom,$env{"form.$xl"});
+ &Apache::lonnet::auto_validate_courseID($crs,$dom,$xl);
if ($coursecheck eq 'ok') {
my $addcheck = '';
- $addcheck = &Apache::lonnet::auto_new_course($crs,$dom,$env{"form.$xl"},$owner,$coowners);
+ $addcheck = &Apache::lonnet::auto_new_course($crs,$dom,$xl,$owner,$coowners);
unless ($addcheck eq 'ok') {
if ($coowners) {
foreach my $user (split(/,/,$coowners)) {
if ($user =~ /^($match_username):($match_domain)$/) {
if (&Apache::lonnet::auto_validate_inst_crosslist($crs,$dom,$coursecode,
- $env{"form.$xl"},$user) eq 'valid') {
+ $xl,$user) eq 'valid') {
$addcheck = 'ok';
last;
}
@@ -2168,12 +2265,12 @@
}
}
if ($addcheck eq 'ok') {
- push(@xlists,$env{"form.$xl"}.":".$env{"form.$lc_sec"});
+ push(@xlists,$xl.':'.$env{"form.$lc_sec"});
} else {
- push(@badowner,$env{"form.$xl"}.":".$env{"form.$lc_sec"});
+ push(@badowner,$xl.':'.$env{"form.$lc_sec"});
}
} else {
- push(@badxlists,$env{"form.$xl"}.":".$env{"form.$lc_sec"}.":".$coursecheck);
+ push(@badxlists,$xl.':'.$env{"form.$lc_sec"}.":".$coursecheck);
}
}
}
@@ -2193,7 +2290,9 @@
'<br /><br />';
} else {
$response = &mt('The courses listed below are now crosslisted with this LON-CAPA course, and students enrolling in these course sections will be automatically added to the class roster for the course, if you have chosen to enable a nightly automated enrollment update.').'<br /><ul>'."\n";
- foreach my $item (@allxlists) {
+ my @showable;
+ &reformat_xlists($dom,$crs,$coursecode,\@allxlists,\@showable);
+ foreach my $item (@showable) {
my ($xlist,$lc_sec) = split(/:/,$item);
$response .= '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'.
"\n";
@@ -2205,7 +2304,9 @@
my @oldxlists = split(/,/,$xliststr);
$response .= &mt('Although no new crosslistings were added, the courses listed below continue to be crosslisted with your LON-CAPA course.').
'<br /><ul>'."\n";
- foreach my $xl (@oldxlists) {
+ my @showable;
+ &reformat_xlists($dom,$crs,$coursecode,\@oldxlists,\@showable);
+ foreach my $item (@showable) {
my ($xlist,$lc_sec) = split(/:/,$xl);
$response .= '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'.
"\n";
@@ -2216,7 +2317,9 @@
if (@badxlists > 0) {
$response .= &mt("The courses listed below could not be included in the crosslistings for this LON-CAPA course, because they are not valid courses according to your institution's official schedule of classes and sections.").
'<br /><ul>'."\n";
- foreach my $item (@badxlists) {
+ my @showable;
+ &reformat_xlists($dom,$crs,$coursecode,\@badxlists,\@showable);
+ foreach my $item (@showable) {
my ($xlist,$lc_sec,$prob) = split(/:/,$item);
$response .= '<li>'.
&mt('[_1] - ID: [_2] - Error: [_3]',
@@ -2228,7 +2331,9 @@
if (@badowner > 0) {
$response .= &mt("The courses listed below could not be included in the crosslistings for this LON-CAPA course, because the owner of this course - [_1] - does not have rights to view enrollment in those classes, as determined by your instititution's policies on access to official classlists.",$owner).
'<br /><ul>'."\n";
- foreach my $item (@badowner) {
+ my @showable;
+ &reformat_xlists($dom,$crs,$coursecode,\@badowner,\@showable);
+ foreach my $item (@showable) {
my ($xlist,$lc_sec) = split(/:/,$item);
$response .= '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'.
"\n";
@@ -2240,7 +2345,9 @@
&mt('Please [_1]go back[_2]</a> and change the section ID for each of these courses.',
'<a href="javascript:history(-1)">','>/a>').
'<br /><ul>'."\n";
- foreach my $item (@reserved) {
+ my @showable;
+ &reformat_xlists($dom,$crs,$coursecode,\@reserved,\@showable);
+ foreach my $item (@showable) {
my ($xlist,$lc_sec) = split(/:/,$item);
$response .= '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'.
"\n";
@@ -2252,7 +2359,9 @@
$response .= &mt('The courses listed below could not be included in the crosslistings for this LON-CAPA course, because the section ID associated with the crosslisted course is the name of a group in this course.').' '.
&mt('Please [_1]go back[_2] and change the section ID for each of these courses.','<a href="javascript:history(-1)">','</a>').
'<br /><ul>'."\n";
- foreach my $item (@matchgroup) {
+ my @showable;
+ &reformat_xlists($dom,$crs,$coursecode,\@matchgroup,\@showable);
+ foreach my $item (@showable) {
my ($xlist,$lc_sec) = split(/:/,$item);
$response .= '<li>'.&mt('[_1] - ID: [_2]',$xlist,$lc_sec).'</li>'.
"\n";
@@ -2272,6 +2381,33 @@
return;
}
+sub reformat_xlists {
+ my ($dom,$crs,$coursecode,$xlistsref,$showxlistsref) = @_;
+ return unless ((ref($xlistsref) eq 'ARRAY') && (ref($showxlistsref) eq 'ARRAY'));
+ my $crskey = $crs.':'.$coursecode;
+ my (@xlcodes, at lcsecs, at extras);
+ foreach my $xl (@{$xlistsref}) {
+ my ($instcodesec,$lc_sec,$extra) = split(/:/,$xl);
+ push(@xlcodes,$instcodesec);
+ push(@lcsecs,$lc_sec);
+ push(@extras,$extra);
+ }
+ my %reformatted =
+ &Apache::lonnet::auto_instsec_reformat($dom,'declutter',
+ {$crskey => \@xlcodes});
+ if (ref($reformatted{$crskey}) eq 'ARRAY') {
+ @xlcodes = @{$reformatted{$crskey}};
+ for (my $i=0; $i<@xlcodes; $i++) {
+ my $value = $xlcodes[$i].':'.$lcsecs[$i];
+ if ($extras[$i] ne '') {
+ $value .= ':'.$extras[$i];
+ }
+ push(@{$showxlistsref},$value);
+ }
+ }
+ return;
+}
+
sub print_sections_menu {
my ($r,$realm,$dom,$crs,$action,$tasktitleref) = @_;
my %settings =
@@ -2814,7 +2950,7 @@
'internal.sectionnums',
'internal.crosslistings'],
$dom,$crs);
- &Apache::loncommon::get_institutional_codes(\%settings,\@allcourses,\%LC_code);
+ &Apache::loncommon::get_institutional_codes($dom,$crs,\%settings,\@allcourses,\%LC_code);
if (@allcourses > 0) {
@{$affiliates{$crs}} = @allcourses;
$outcome = &Apache::lonnet::auto_photoupdate(\%affiliates,$dom,$crs,\%changes);
@@ -2944,7 +3080,7 @@
$response = &mt('There was a problem retrieving the course code for this LON-CAPA course.').' '.
&mt('An update of the class roster has not been carried out, and enrollment remains unchanged.');
} else {
- &Apache::loncommon::get_institutional_codes(\%settings,\@allcourses,\%LC_code);
+ &Apache::loncommon::get_institutional_codes($dom,$crs,\%settings,\@allcourses,\%LC_code);
if (@allcourses > 0) {
@{$affiliates{$crs}} = @allcourses;
my $outcome = &Apache::lonnet::fetch_enrollment_query('updatenow',\%affiliates,\%reply,$dom,$crs);
Index: loncom/interface/selfenroll.pm
diff -u loncom/interface/selfenroll.pm:1.36 loncom/interface/selfenroll.pm:1.37
--- loncom/interface/selfenroll.pm:1.36 Tue May 4 18:47:36 2021
+++ loncom/interface/selfenroll.pm Tue Jun 15 20:52:26 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network
# Allow users to self-enroll in a course
#
-# $Id: selfenroll.pm,v 1.36 2021/05/04 18:47:36 raeburn Exp $
+# $Id: selfenroll.pm,v 1.37 2021/06/15 20:52:26 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -794,7 +794,7 @@
'internal.sectionnums',
'internal.crosslistings'],$cdom,$cnum);
my (@allcourses,%LC_code,%affiliates,%reply);
- &Apache::loncommon::get_institutional_codes(\%settings,\@allcourses,\%LC_code);
+ &Apache::loncommon::get_institutional_codes($cdom,$cnum,\%settings,\@allcourses,\%LC_code);
if (@allcourses > 0) {
@{$affiliates{$cnum}} = @allcourses;
my $outcome = &Apache::lonnet::fetch_enrollment_query('updatenow',\%affiliates,\%reply,$cdom,$cnum);
Index: loncom/lond
diff -u loncom/lond:1.566 loncom/lond:1.567
--- loncom/lond:1.566 Wed Mar 31 02:19:58 2021
+++ loncom/lond Tue Jun 15 20:52:27 2021
@@ -2,7 +2,7 @@
# The LearningOnline Network
# lond "LON Daemon" Server (port "LOND" 5663)
#
-# $Id: lond,v 1.566 2021/03/31 02:19:58 raeburn Exp $
+# $Id: lond,v 1.567 2021/06/15 20:52:27 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -65,7 +65,7 @@
my $status='';
my $lastlog='';
-my $VERSION='$Revision: 1.566 $'; #' stupid emacs
+my $VERSION='$Revision: 1.567 $'; #' stupid emacs
my $remoteVERSION;
my $currenthostid="default";
my $currentdomainid;
@@ -214,6 +214,7 @@
autovalidatecourse => {remote => 1, enroll => 1},
autovalidateinstcode => {domroles => 1, remote => 1, enroll => 1},
autovalidateinstcrosslist => {remote => 1, enroll => 1},
+ autoinstsecreformat => {remote => 1, enroll => 1},
changeuserauth => {remote => 1, domroles => 1},
chatretr => {remote => 1, enroll => 1},
chatsend => {remote => 1, enroll => 1},
@@ -6106,6 +6107,62 @@
®ister_handler("autovalidateclass_sec", \&validate_class_access_handler, 0, 1, 0);
#
+# Modify institutional sections (using customized &instsec_reformat()
+# routine in localenroll.pm), to either clutter or declutter, for
+# purposes of ensuring an institutional course section (string) can
+# be unambiguously separated into institutional course and section.
+#
+# Formal Parameters:
+# $cmd - The command request that got us dispatched.
+# $tail - The tail of the command. In this case this is a colon separated
+# set of values that will be split into:
+# $cdom - The LON-CAPA domain of the course.
+# $action - Either: clutter or declutter
+# clutter adds character(s) to eliminate ambiguity
+# declutter removes the added characters (e.g., for
+# display of the institutional course section string.
+# $info - A frozen hash in which keys are:
+# LON-CAPA course number:Institutional course code
+# and values are a reference to an array of the
+# items to modify -- either institutional sections,
+# or institutional course sections (for crosslistings).
+# $client - The socket open on the client.
+# Returns:
+# 1 - continue processing.
+#
+
+sub instsec_reformat_handler {
+ my ($cmd, $tail, $client) = @_;
+ my $userinput = "$cmd:$tail";
+ my ($cdom,$action,$info) = split(/:/,$tail);
+ my $instsecref = &Apache::lonnet::thaw_unescape($info);
+ my ($outcome,$result);
+ eval {
+ local($SIG{__DIE__})='DEFAULT';
+ $outcome=&localenroll::instsec_reformat($cdom,$action,$instsecref);
+ if ($outcome eq 'ok') {
+ if (ref($instsecref) eq 'HASH') {
+ foreach my $key (keys(%{$instsecref})) {
+ $result .= &escape($key).'='.&Apache::lonnet::freeze_escape($instsecref->{$key}).'&';
+ }
+ $result =~ s/\&$//;
+ }
+ }
+ };
+ if (!$@) {
+ if ($outcome eq 'ok') {
+ &Reply( $client, \$result, $userinput);
+ } else {
+ &Reply($client,\$outcome, $userinput);
+ }
+ } else {
+ &Failure($client,"unknown_cmd\n",$userinput);
+ }
+ return 1;
+}
+®ister_handler("autoinstsecreformat",\&instsec_reformat_handler, 0, 1, 0);
+
+#
# Validate course owner or co-owners(s) access to enrollment data for all sections
# and crosslistings for a particular course.
#
Index: loncom/enrollment/Autoenroll.pl
diff -u loncom/enrollment/Autoenroll.pl:1.34 loncom/enrollment/Autoenroll.pl:1.35
--- loncom/enrollment/Autoenroll.pl:1.34 Wed Sep 14 20:58:27 2016
+++ loncom/enrollment/Autoenroll.pl Tue Jun 15 20:52:27 2021
@@ -1,7 +1,7 @@
#!/usr/bin/perl
#
#Automated Enrollment script
-# $Id: Autoenroll.pl,v 1.34 2016/09/14 20:58:27 raeburn Exp $
+# $Id: Autoenroll.pl,v 1.35 2021/06/15 20:52:27 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -74,6 +74,8 @@
# Determine the courses
my %courses = &Apache::lonnet::courseiddump($dom,'.',1,'.','.','.',1,\@hostids,'Course');
my %affiliates = ();
+ my %unclutteredsec = ();
+ my %unclutteredlcsec = ();
my %enrollvar = ();
my %reply = ();
my %LC_code = ();
@@ -120,17 +122,21 @@
$sections[0] = $enrollvar{$crs}{sectionnums};
}
if ($enrollvar{$crs}{crosslistings} =~ m/,/) {
- @crosslistings = split/,/,$enrollvar{$crs}{crosslistings}
+ @crosslistings = split/,/,$enrollvar{$crs}{crosslistings};
} else {
@crosslistings = $enrollvar{$crs}{crosslistings};
}
+ my $crscode = $enrollvar{$crs}{coursecode};
+ my $crskey = $crs.':'.$crscode;
+ @{$unclutteredsec{$crskey}} = ();
+ @{$unclutteredlcsec{$crskey}} = ();
foreach my $sec (@sections) {
if ($sec =~ m/^(\w+):(\w*)$/ ) {
- my $course_id = $enrollvar{$crs}{coursecode}.$1;
+ my $instsec = $1;
my $gp = $2;
- if (!grep/^\Q$course_id\E$/,@{$affiliates{$crs}}) {
- push @{$affiliates{$crs}}, $course_id;
- $LC_code{$crs}{$course_id} = $gp;
+ unless (grep/^\Q$instsec\E$/,@{$unclutteredsec{$crskey}}) {
+ push(@{$unclutteredsec{$crskey}},$instsec);
+ push(@{$unclutteredlcsec{$crskey}},$gp);
}
}
}
@@ -147,6 +153,19 @@
}
}
}
+ my %formattedsec = &Apache::lonnet::auto_instsec_reformat($dom,'clutter',\%unclutteredsec);
+ foreach my $crskey (keys(%formattedsec)) {
+ my ($crs,$instcode) = split(/:/,$crskey);
+ if ((ref($formattedsec{$crskey}) eq 'ARRAY') && (ref($unclutteredlcsec{$crskey}) eq 'ARRAY')) {
+ for (my $i=0; $i<@{$formattedsec{$crskey}}; $i++) {
+ my $course_id = $instcode.$formattedsec{$crskey}[$i];
+ unless (grep/^\Q$course_id\E$/,@{$affiliates{$crs}}) {
+ push(@{$affiliates{$crs}},$course_id);
+ $LC_code{$crs}{$course_id} = $unclutteredlcsec{$crskey}[$i];
+ }
+ }
+ }
+ }
my $outcome = &Apache::lonnet::fetch_enrollment_query('automated',\%affiliates,\%reply,$dom);
# Now go through classes and perform required enrollment changes.
Index: loncom/enrollment/localenroll.pm
diff -u loncom/enrollment/localenroll.pm:1.60 loncom/enrollment/localenroll.pm:1.61
--- loncom/enrollment/localenroll.pm:1.60 Wed Mar 31 02:19:58 2021
+++ loncom/enrollment/localenroll.pm Tue Jun 15 20:52:27 2021
@@ -1,6 +1,6 @@
# functions to glue school database system into Lon-CAPA for
# automated enrollment
-# $Id: localenroll.pm,v 1.60 2021/03/31 02:19:58 raeburn Exp $
+# $Id: localenroll.pm,v 1.61 2021/06/15 20:52:27 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -655,6 +655,101 @@
return 'ok';
}
+=pod
+
+=item instsec_reformat()
+
+ Inputs: $dom, $action, $instsecref
+
+ $dom is the course's domain
+ $action is either: clutter or declutter
+ $instsecref is a reference to a hash, in which each key is
+ course num:course code, and each value is either an array of
+ institutional sections, or (in the case of crosslisted courses)
+ an array of institutional course sections.
+
+ Returns: ok
+
+ Side effects: will modify the items in the array as determined by
+ code implemented for the domain. Modification will differ depending
+ on whether the action is clutter or declutter.
+
+ The idea is that "clutter" will modify the name of the section such
+ that a concatenation of institutional code then (modified) section
+ will result in a string that other customized routines in localenroll.pm
+ can separate without ambiguity into instituional code then (real)
+ institutional section using a regular expression.
+
+ Conversely, "declutter" will modify the name of an already modified
+ item such that display of the concatenated string (e.g., for a
+ crosslisting in the course catalog) does not include the "added"
+ characters used to eliminate ambiguity.
+
+ Examples (MSU):
+
+ Starting in Fall 2021 at MSU, institution section numbers are no
+ longer guaranteed to be three digit numbers (including leading zeroes).
+
+ So, for example the course code: fs21phy183b might have sections:
+ 001, 002, LEC1, LEC2, and be crosslisted with fs21phy233b (with
+ sections: 730, LEC3, LEC4).
+
+ The sections: LEC1, and LEC2 should be changed to _LEC1, and _LEC2
+ before creating the inner keys in the %affiliates hash of a hash,
+ passed to fetch_enrollment() in Enrollment.pm. They will however
+ be stored in the course's environment as LEC1 and LEC2.
+
+ For the crosslistings, LEC3 and LEC4 should be changed to
+ _LEC3 and _LEC4 before storing in the course's environment.db file.
+
+ In both cases when it comes time to extract the various components
+ of an institutional section code (i.e., the concatenated string) in
+ fetch_enrollment(), for example, the regexp used at MSU would be:
+
+ if ($class =~ m/^([suf]s)(\d{2})(\w{2,4})(\d{3,4}[A-Za-z]?)(\d{3}|_[A-Za-z0-9]{1,5})$/) {
+ my ($sem,$yr,$subj,$crse,$sec) = ($1,$2,$3,$4,$5);
+
+ The three digit sections would match the \d{3} and the other sections
+ (LEC1, LEC2 etc.) would match the _[A-Za-z0-9]{1,5}.
+
+ The customization in &instsec_reformat() would be:
+
+ if ($action eq 'clutter') {
+ unless ($item =~ /^\d{3}$/) {
+ $item = '_'.$item;
+ }
+ } elsif ($action eq 'declutter') {
+ if ($item =~ /^([suf]s\d{2}\w{2,4}\d{3,4}[A-Za-z]?)(\d{3}|_[A-Za-z0-9]{1,5})$/) {
+ my ($instcode,$instsec) = ($1,$2);
+ $instsec =~ s/^_//;
+ $item = $instcode.$instsec;
+ } elsif ($item =~ /^_[A-Za-z0-9]{1,5}$/) {
+ $item =~ s/^_//;
+ }
+ }
+
+=cut
+
+sub instsec_reformat {
+ my ($dom,$action,$instsecref) = @;
+ if ((ref($instsecref) eq 'HASH') &&
+ (($action eq 'clutter') || ($action eq 'declutter'))) {
+ foreach my $key (keys(%{$instsecref})) {
+ if (ref($instsecref->{$key}) eq 'ARRAY') {
+ foreach my $sec (@{$instsecref->{$key}}) {
+ if ($action eq 'clutter') {
+ # modify the section, as needed.
+ next;
+ } elsif ($action eq 'declutter') {
+ # modify the section, as needed.
+ next;
+ }
+ }
+ }
+ }
+ }
+ return 'ok';
+}
=pod
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1459 loncom/lonnet/perl/lonnet.pm:1.1460
--- loncom/lonnet/perl/lonnet.pm:1.1459 Sat Jun 12 21:37:36 2021
+++ loncom/lonnet/perl/lonnet.pm Tue Jun 15 20:52:28 2021
@@ -1,7 +1,7 @@
# The LearningOnline Network
# TCP networking package
#
-# $Id: lonnet.pm,v 1.1459 2021/06/12 21:37:36 raeburn Exp $
+# $Id: lonnet.pm,v 1.1460 2021/06/15 20:52:28 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -9788,6 +9788,38 @@
return $response;
}
+sub auto_instsec_reformat {
+ my ($cdom,$action,$instsecref) = @_;
+ return unless(($action eq 'clutter') || ($action eq 'declutter'));
+ my @homeservers;
+ if (defined(&domain($cdom,'primary'))) {
+ push(@homeservers,&domain($cdom,'primary'));
+ } else {
+ my %servers = &get_servers($cdom,'library');
+ foreach my $tryserver (keys(%servers)) {
+ if (!grep(/^\Q$tryserver\E$/, at homeservers)) {
+ push(@homeservers,$tryserver);
+ }
+ }
+ }
+ my $response;
+ my %reformatted = %{$instsecref};
+ foreach my $server (@homeservers) {
+ if (ref($instsecref) eq 'HASH') {
+ my $info = &freeze_escape($instsecref);
+ my $response=&reply('autoinstsecreformat:'.$cdom.':'.
+ $action.':'.$info,$server);
+ next if ($response =~ /(con_lost|error|no_such_host|refused|unknown_command)/);
+ my @items = split(/&/,$response);
+ foreach my $item (@items) {
+ my ($key,$value) = split(/=/,$item);
+ $reformatted{&unescape($key)} = &thaw_unescape($value);
+ }
+ }
+ }
+ return %reformatted;
+}
+
sub auto_validate_instclasses {
my ($cdom,$cnum,$owners,$classesref) = @_;
my ($homeserver,%validations);
More information about the LON-CAPA-cvs
mailing list