--- loncom/enrollment/localenroll.pm 2009/09/13 03:14:12 1.39
+++ loncom/enrollment/localenroll.pm 2021/06/15 20:52:27 1.61
@@ -1,6 +1,6 @@
# functions to glue school database system into Lon-CAPA for
# automated enrollment
-# $Id: localenroll.pm,v 1.39 2009/09/13 03:14:12 raeburn Exp $
+# $Id: localenroll.pm,v 1.61 2021/06/15 20:52:27 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -39,8 +39,6 @@ described at http://www.lon-capa.org.
=head1 NOTABLE SUBROUTINES
-=over
-
=cut
package localenroll;
@@ -48,6 +46,8 @@ package localenroll;
use strict;
=pod
+
+=over
=item run()
set this to return 1 if you want the auto enrollment to run
@@ -123,6 +123,8 @@ sub run() {
D
A12345678
+
+
with the following at the top of the file
@@ -142,11 +144,25 @@ sub run() {
Manager, or via the 'Upload a class list','Enroll a single student' or
'Modify student data' utilities in the Enrollment Manager, by checking the
'make these dates the default for future enrollment' checkbox. If no default
- dates have been set, then the tudent role will be active immediately, and will
+ dates have been set, then the student role will be active immediately, and will
remain active until the role is explicitly expired using ENRL -> Drop students.
If dates are to included in the XML file, they should be in the format
YYYY:MM:DD:HH:MM:SS (: separators required).
+ The tag need only be used if the credits earned by the students will
+ be different from the default for the course. The course default is set when the
+ course is created and can be modifed by a Domain Coordinator via "View or
+ modify a course or community" on the DC's Main Menu screen.
+
+ A value for should be the institutional status used for students,
+ and should be one of the types defined in the "Institutional user types"
+ section in the domain config screen for:
+ "Default authentication/language/timezone/portal/types"
+
+ If no status types are defined for the domain this tag can be omitted.
+ If Autoupdate.pl is enabled in your domain, updates to the institutional
+ status set here will be updated by Autoupdate.pl, should changes occur.
+
If there were 10 students in fs03nop590001, 5 students in fs03nop59o601,
8 students in fs03nop590602, and 2 students in fs03ost580002,
then $$reply{'43551dedcd43febmsul1'} = 25
@@ -191,7 +207,7 @@ sub fetch_enrollment {
("001","601","602") would be returned
If the array returned contains at least one element, then
- the interface offerred to the course coordinator, lists
+ the interface offered to the course coordinator, lists
official sections and provides a checkbox to use to
select enrollment in the LON-CAPA course from each official section.
@@ -233,7 +249,7 @@ sub get_sections {
The course section or crosslisted course will only be added to the list of
affiliates if 'ok' is returned.
- new_course takes three arguments -
+ new_course takes three required arguments -
(a) the institutional courseID (in the MSU case this is a concatenation of
semester code, department code, course number, and section number
e.g., fs03nop590001).
@@ -242,10 +258,16 @@ sub get_sections {
username:domain
(c) the LON-CAPA domain that contains the course
+ new_course also takes optional fourth and fifth arguments -
+ (d) the course co-owners, as a comma-separated list of username:domain for
+ any co-owners.
+ (e) database handle (might be set when new_course() is called by check_section
+ routine within localenroll.pm).
+
=cut
sub new_course {
- my ($course_id,$owner,$dom) = @_;
+ my ($course_id,$owner,$dom,$coowners) = @_;
my $outcome = 'ok';
return $outcome;
}
@@ -297,8 +319,14 @@ validate_instcode takes three arguments
(c) an optional institutional username for the course owner.
An array is returned containing (a) the result of the check for a valid
-instcode, and (b) an (optional) course description.
+instcode, (b) an (optional) course description, and (c) the default credits
+earned by students when completing this course. If no institutional credits
+value is available, the default credits for the course can be set via the
+course request form, or via XML in a batch file, of via the web form used
+by the Domain Coordinator to create new courses one at a time.
+
A valid instcode is confirmed by returning 'valid'.
+
If no course description is available, '' should be set as
the value of the second item in the returned array.
@@ -308,7 +336,34 @@ sub validate_instcode {
my ($dom,$instcode,$owner) = @_;
my $outcome = '';
my $description = '';
- return ($outcome,$description);
+ my $credits = '';
+ return ($outcome,$description,$credits);
+}
+
+=pod
+
+=item validate_crosslist_access()
+
+This is called for an official course to check whether a course
+with the institutional code can have access to enrollment data
+from a cross-listed institutional section code, given a co-owner.
+
+validate_crosslist_access() takes four arguments -
+(a) the course's LON-CAPA domain
+(b) the institional course code assigned to the course
+(c) the institutional course section code for the crosslisting
+(d) the co-owner to check for affiliation with the crosslisting
+ (username:domain).
+
+A combination of (a), (b), (c) and (d) with access to enrollment
+data, as per institutional policies, is confirmed by returning 'valid'.
+
+=cut
+
+sub validate_crosslist_access {
+ my ($dom,$instcode,$inst_xlist,$coowner) = @_;
+ my $outcome = '';
+ return $outcome;
}
=pod
@@ -320,9 +375,10 @@ automatically, or held in a queue pendin
the institution.
Course requests will trigger this check if the process type has been set
-to 'validate' for the course type (official, unofficial or community) and
-the requestor's affiliation. Whether "validate" is an available option
-in the Domain Configuration menu is controlled by auto_courserequest_checks().
+to 'validate' for the course type (official, unofficial, textbook,
+placement or community) and the requestor's affiliation. Whether
+"validate" is an available option in the Domain Configuration menu
+is controlled by auto_courserequest_checks().
One scenario is where the request is for an official course, in which case
a check could be made that the requestor is listed as instructor of
record for the course in the institution's course schedule/database.
@@ -331,34 +387,44 @@ Other scenarios are possible, and the ro
to whatever rules a domain wishes to implement to run validations against
given the data passed in to the routine.
-validate_crsreq takes six arguments -
+validate_crsreq takes seven arguments -
(a) the LON-CAPA domain that will contain the course.
(b) the username:domain for the course owner.
- (c) the course type (official, unofficial or community)
+ (c) the course type (official, unofficial,textbook, placement or community)
(d) a comma-separated list of institutional affiliations of
the course owner.
(e) the institutional code (in the MSU case this is a concatenation of
- semester code, department code, and course number, e.g., fs03nop590.
+ semester code, department code, and course number, e.g., fs03nop590).
(f) a comma-separated list of institutional sections included in
the course request (only applicable to official courses).
+ (g) an optional reference to a hash of custom form data.
+ The custom form data will come from crsreq_updates(), with one
+ additional item: $custominfo->{'_LC_clonefrom'}, provided internally
+ (the courseID of the LON-CAPA course being cloned).
A valid courserequest is confirmed by returning 'process'.
-The following can be returned: process, rejected, pending, approval or error (with error condition - no :), followed by a : and then an optional message.
+The following can be returned: process, rejected, pending, approval or
+error (with error condition - no :), followed by a : and then an optional message.
(a) process - the requestor is the recorded instructor - create the course
-(b) reject - the requestor should never be requesting this course, reject the
+
+(b) rejected - the requestor should never be requesting this course, reject the
request permanently
+
(c) pending - the requestor is not the recorded instructor, but could
become so after administrative action at the institution. Put the
- request in a queue and check localenroll:validate_instcode()
- periodically until the status changes to "valid".
+ request in a queue and, if an official course, check
+ localenroll:validate_instcode() periodically until the status changes to
+ "valid".
+
(d) approval - the request will be held pending review by a Domain Coordinator.
+
(e) error (followed by the error condition).
=cut
sub validate_crsreq {
- my ($dom,$owner,$crstype,$inststatuslist,$instcode,$instseclist) = @_;
+ my ($dom,$owner,$crstype,$inststatuslist,$instcode,$instseclist,$custominfo) = @_;
my $outcome = 'approval';
return $outcome;
}
@@ -371,10 +437,11 @@ This is used to determine whether the "v
possible choices for course request processing in the Domain Configuration
menu for Course Requests. Ultimately it is called by domainprefs.pm (via:
lonnet -> lond -> localenroll.pm) The domain configuration menu includes
-a table where columns are course type (official, unofficial or community)
-and rows are institutional affiliations (e.g., Faculty, Staff, Student etc.).
+a table where columns are course type (official, unofficial, textbook,
+placement or community) and rows are institutional affiliations
+(e.g., Faculty, Staff, Student etc.).
-crsreq_checks() takes three arguments: $dom, $reqtyes, $validations.
+crsreq_checks() takes three arguments: $dom, $reqtypes, $validations.
$dom - the domain for which validation options are needed.
$reqtypes - ref to an ARRAY of course types (i.e., official, unofficial and community.
$validations - ref to a hash of a hash which will determine whether "validate"
@@ -415,6 +482,277 @@ sub crsreq_checks {
=pod
+=item crsreq_updates()
+
+This is used to customize the LON-CAPA course request process.
+There are two hash references: $incoming, and $outgoing; $incoming can
+contain additional information collected from the requester, whereas $outgoing
+can contain custom items to send back to lonrequestcourse.pm, which creates the
+HTML displayed to the user during a course request.
+
+Different key-value pairs may be returned to lonrequestcourse.pm in the $outgoing
+hashref depending on the current action. The available actions are:
+review, prevalidate, process, created and queued.
+
+One scenario would be to return HTML markup in: $outgoing->{'reviewweb'},
+i.e., where the action is 'review', to prompt the user to provide additional
+information as part of the course request, at the request review stage,
+(i.e,, the page which contains the button used to submit a completed course request).
+
+The HTML could contain form elements (e.g., radio buttons etc.). The value(s)
+selected by the requester in those form elements will be available in the incoming
+hashref, for a subsequent action, if the corresponding keys have been included
+in $outgoing->{'formitems'}, i.e., $outgoing will be hash of a hash. If a
+particular form item will the single valued, the value set for the key in the
+inner hash in $outgoing should be 1, otherwise, if it will be multi-valued,
+the value should be multiple.
+
+The $outgoing hashref can contain a 'formitems' key for both the prevalidate
+and process actions, as calls to localenroll::crsreq_update() can originate
+in lonrequestcourse::process_request() for both of those actions.
+
+The retrieved form values are passed to localenroll::validate_crsreq() as the
+optional seventh arg (a hashref) -- $custominfo.
+
+=cut
+
+sub crsreq_updates {
+ my ($cdom,$cnum,$crstype,$action,$ownername,$ownerdomain,$fullname,$title,
+ $code,$accessstart,$accessend,$incoming,$outgoing) = @_;
+ unless (ref($outgoing) eq 'HASH') {
+ return 'fail';
+ }
+ my %extrainfo;
+ if (ref($incoming) eq 'HASH') {
+ %extrainfo = %{$incoming};
+ }
+ if ($action eq 'review') {
+ $outgoing->{'reviewweb'} = '';
+ } elsif ($action eq 'prevalidate') {
+ $outgoing->{'formitems'} = {}; # key=>value, where key is form element name
+ # and value is multiple, if there
+ # are multiple form elements with
+ # the same name.
+ } elsif ($action eq 'process') {
+ $outgoing->{'formitems'} = {}; # key=>value, where key is form element name
+ # and value is multiple, if there
+ # are multiple form elements with
+ # the same name.
+ } elsif ($action eq 'created') {
+ $outgoing->{'createdweb'} = '';
+ $outgoing->{'createdmsg'} = [{
+ mt => '',
+ args => [],
+ }];
+ $outgoing->{'createdactions'} = {
+ environment => {},
+ };
+ # environment can contain key=>value for
+ # items to set in the course environment.
+ # These would be items which are NOT included
+ # in the items set via options in the course
+ # request form. Currently self-enrollment
+ # settings are the only ones allowed, i.e.,
+ # internal.selfenroll_types internal.selfenroll_registered
+ # internal.selfenroll_section internal.selfenroll_start_access
+ # internal.selfenroll_end_access internal.selfenroll_limit
+ # internal.selfenroll_cap internal.selfenroll_approval
+ # internal.selfenroll_notifylist
+ } elsif ($action eq 'queued') {
+ $outgoing->{'queuedmsg'} = [{
+ mt => '',
+ args => [],
+ }];
+ $outgoing->{'queuedweb'} = '';
+ }
+ return 'ok'
+}
+
+=pod
+
+=item export_grades()
+
+This routine can be customized to push grade information to some other gradebook,
+LCMS, or administrative system external to LON-CAPA.
+
+export_grades() takes five arguments -
+(a) the LON-CAPA course ID
+(b) the LON-CAPA course domain
+(c) a hash reference containing the following:
+ scope => scope of the grades (e.g., course, map or resource).
+ instcode => institutional course code (if an official course)
+ crstype => course type -- Course, Community or Placement
+ context => calling context, e.g., "completion" when a student completes a placement test.
+(d) a perl data structure (hash of a hash) containing the grade data.
+ in the outer hash, the keys are student's username:domain
+ in the inner hash, keys are:
+ id => student/employee ID
+ lastname => student's last name
+ firstname => student's first name
+ email => student's "permannent" e-mail address
+ section => student's LON-CAPA course section
+ total => total points earned
+ bytitle => reference to a hash (keys are question titles, values are points
+ bysymb => reference to a hash (keys are symbs, i.e., unique resource identifiers).
+(e) reference to a hash which will contain information to return.
+ keys will be the student's username:domain. Value of 1 to show grades pushed
+ successfully.
+
+=cut
+
+sub export_grades {
+ my ($cnum,$cdom,$hashref,$dataref,$outgoing) = @_;
+ my %info;
+ if (ref($hashref) eq 'HASH') {
+ %info = %{$hashref};
+ }
+ if ((ref($dataref) eq 'HASH') && (ref($outgoing) eq 'HASH')) {
+ foreach my $key (keys(%{$dataref})) {
+ $outgoing->{$key} = 1;
+ }
+ return 'ok';
+ } else {
+ return 'error';
+ }
+}
+
+=pod
+
+=item check_instclasses()
+
+ This is used to supply information about which instituional course sections
+ and cross-listings are available to supply enrollment data, given the current
+ list of owner and co-owners. The data are used to populate the column titled:
+ "Auto-enrollment of registered students" when showing full detailed for a course
+ in the course catalog.
+
+ This subroutine takes four arguments -
+
+ (a) $owners - comma-separated list of username:domain for course owner
+ and co-owners.
+ (b) $dom - domain of course.
+ (c) $classes - reference to hash of institutional course sections and
+ crosslistings for which access to enrollment data is being checked.
+ (d) $validated - reference to hash which will be populated with all
+ keys from incoming $classes hashref, for which one or more of the
+ owner/co-owners has rights to access enrollment data. For each
+ key included in $validated hashref, corresponding value will be set to 1.
+
+ The subroutine returns 'ok' if there is no processing error.
+
+=cut
+
+
+sub check_instclasses {
+ my ($owners,$dom,$classes,$validated) = @_;
+ if ((ref($classes) eq 'HASH') && (ref($validated) eq 'HASH')) {
+ foreach my $class (keys(%{$classes})){
+ if (&check_section($class,$owners,$dom) eq 'ok') {
+ $validated->{$class} = 1;
+ }
+ }
+ }
+ 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
+
=item create_password()
This is called when the authentication method set for the automated
@@ -521,14 +859,18 @@ sub instcode_format () {
Gather acceptable values for institutional categories to use in course creation request form for official courses.
- requires four arguments:
+ requires five arguments:
+
domain ($dom)
reference to array of titles ($codetitles)
reference to hash of abbreviations used in categories ($cat_titles).
- reference to hash of arrays specifying sort order used in category titles ($cat_order).
+ reference to hash of arrays specifying sort order used in
+ category titles ($cat_order).
+ reference to array which will contain order of component parts used
+ in institutional code ($code_order).
e.g.,
- @{$codetitles} = ("Year","Semester","Department","Number");
+ @{$codetitles} = ('Year','Semester',"Department','Number');
%{$$cat_titles{'Semester'}} = (
fs => 'Fall',
@@ -536,23 +878,22 @@ Gather acceptable values for institution
us => 'Summer');
@{$$cat_order{'Semester'}} = ('ss','us','fs');
+ @{$code_order} = ('Semester','Year','Department','Number');
returns 1 parameter: 'ok' if no processing errors.
=cut
sub possible_instcodes {
- my ($dom,$codetitles,$cat_titles,$cat_order) = @_;
+ my ($dom,$codetitles,$cat_titles,$cat_order,$code_order) = @_;
@{$codetitles} = ();
%{$$cat_titles{'Semester'}} = ();
@{$$cat_order{'Semester'}} = ('ss','us','fs');
- ($$cat_titles{'Department'},$$cat_order{'Department'}) = &get_all_depts($dom);
- ($$cat_titles{'Year'},$$cat_order{'Year'}) = &get_possible_years($dom);
+ @{$code_order} = ();
return 'ok';
}
-
=pod
=item institutional_photos()
@@ -728,6 +1069,9 @@ sub instcode_defaults {
keys will be unique IDs (student or faculty/staff ID)
values will be either: scalar (username) or an array
if a single ID matches multiple usernames.
+ (d) $lc_users - reference to hash containing LON-CAPA usernames in
+ in domain $dom, as keys. Needed if institutional
+ data source only allows query by username.
returns 1 parameter - 'ok' if no processing error, or other value
if an error occurred.
side effects - populates the $instusers and $instids refs to hashes.
@@ -738,7 +1082,7 @@ sub instcode_defaults {
=cut
sub allusers_info {
- my ($dom,$instusers,$instids) = @_;
+ my ($dom,$instusers,$instids,$lc_users) = @_;
my $outcome = 'ok';
return $outcome;
}
@@ -774,8 +1118,8 @@ sub allusers_info {
institutional types to check.
(g) $srchby - optional if $uname or $id defined, otherwise required.
Allowed values include: 1. lastfirst, 2. last, 3. uname
- corresponding to searches by 1. lastname,firstname;
- 2. lastname; 3. username
+ 4. email, corresponding to searches by 1. lastname,firstname;
+ 2. lastname; 3. username; 4. e-mail address
(h) $srchterm - optional if $uname or $id defined, otherwise required
String to search for.
(i) $srchtype - optional. Allowed values: contains, begins (defaults
@@ -806,8 +1150,64 @@ sub get_userinfo {
=pod
+=item get_multusersinfo
+
+ (a) $dom - domain
+ (b) $type - username or id
+ (c) $unamenames - reference to hash containing usernames of users
+ (d) $instusers - reference to hash which will contain info for user
+ as key = value; keys will be one or all of:
+ lastname,firstname,middlename,generation,id,inststatus -
+ institutional status (e.g., faculty,staff,student)
+ Values are all scalars except inststatus,
+ which is an array.
+ (e) $instids - reference to hash which will contain ID numbers -
+ keys will be unique IDs (student or faculty/staff ID)
+ values will be either: scalar (username) or an array
+ if a single ID matches multiple usernames.
+
+ returns 1 parameter - 'ok' if no processing error, or other value
+ if an error occurred.
+
+ side effects - populates the $instusers and $instids refs to hashes.
+ with information for specified username, or specified
+ id, if fifth argument provided, from all available, or
+ specified (e.g., faculty only) institutional datafeeds,
+ if sixth argument provided.
+
+ WARNING: You need to set $outcome to 'ok' once you have customized
+ this routine to communicate with an instititional
+ directory data source, otherwise retrieval of institutional
+ user information will always be reported as being unavailable
+ in domain $dom.
+
+=cut
+
+sub get_multusersinfo {
+ my ($dom,$type,$usernames,$instusers,$instids) = @_;
+ my $outcome = 'unavailable';
+ return $outcome;
+}
+
+=pod
+
=item inst_usertypes()
+ Starting with LON-CAPA 2.11.0 use of this subroutine
+ is deprecated. The domain configuration web GUI
+ accessible to Domain Coordinators will be used to
+ manage institutional types. If you have previously
+ customized this routine, then values set there will
+ be used when displaying the "Institutional user types"
+ section in the domain config screen for:
+ "Default authentication/language/timezone/portal/types".
+
+ Once you have visited that screen and saved the settings,
+ configuration thereafter will be via the web GUI of
+ values stored in the domain's configuration.db file on
+ the primary library server in the domain, and values in
+ inst_usertypes() will no longer be consulted.
+
Incoming data: three arguments
(a) $dom - domain
(b) $usertypes - reference to hash which will contain