# functions to glue school database system into Lon-CAPA for # automated enrollment # $Id: localenroll.pm,v 1.33 2009/02/20 13:59:20 bisitz Exp $ # # Copyright Michigan State University Board of Trustees # # This file is part of the LearningOnline Network with CAPA (LON-CAPA). # # LON-CAPA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # LON-CAPA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with LON-CAPA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # /home/httpd/html/adm/gpl.txt # # http://www.lon-capa.org/ # =pod =head1 NAME localenroll =head1 SYNOPSIS This is part of the LearningOnline Network with CAPA project described at http://www.lon-capa.org. =head1 NOTABLE SUBROUTINES =over =back =cut package localenroll; use strict; =pod =item run() set this to return 1 if you want the auto enrollment to run Beginning with LON-CAPA version 2.4, use of this routine is deprecated. Whether or not Autoenroll.pl should run is set by the Domain Coordinator via "Set domain configuration", provided in the Domain Management section of the Main menu. =cut sub run() { my $dom = shift; return 0; } =pod =item fetch_enrollment() connects to the institutional classlist data source, reads classlist data and stores in an XML file in /home/httpd/perl/tmp/ classlist files are named as follows: DOMAIN_COURSE_INSTITUTIONALCODE_classlist.xml e.g., msu_43551dedcd43febmsul1_fs03nop590001_classlist.xml where DOMAIN = msu COURSE = 43551dedcd43febmsul1 INSTITUTIONALCODE = fs03nop590001 (MSU's course naming scheme - fs03 = Fall semester 2003, nop = department name, 590 = course number, 001 = section number.) fetch_enrollment requires three arguments - $dom - DOMAIN e.g., msu $affiliatesref - a reference to a hash of arrays that contains LON-CAPA courses that are to be updated as keys, and institutional coursecodes contributing enrollment to that LON-CAPA course as elements in each array. $replyref - a reference to a hash that contains LON-CAPA courses that are to be updated as keys, and the total enrollment count in all affiliated sections, as determined from institutional data as hash elements. As an example, if fetch_enrollment is called to retrieve institutional classlists for a single LON-CAPA course - 43551dedcd43febmsul1 which corresponds to fs03nop590, sections 001, 601 and 602 , and the course also accommodates enrollment from a crosslisted course in the ost department - fs03ost580002: the affiliatesref would be a reference to %affiliates which would be: @{$affiliates{'43551dedcd43febmsul1'}} = ("fs03nop590001","fs03nop590601","fs03nop590602","fs03ost580002"); fetch_enrollment would create four files in /home/httpd/perl/tmp/. msu_43551dedcd43febmsul1_fs03nop590001_classlist.xml msu_43551dedcd43febmsul1_fs03nop590601_classlist.xml msu_43551dedcd43febmsul1_fs03nop590602_classlist.xml msu_43551dedcd43febmsul1_fs03ost580002_classlist.xml In each file, student data would be stored in the following format MSU.EDU krb4 smith@msu.edu John II fs03nop590001 Smith D A12345678 with the following at the top of the file (all comment - s removed) and a closing: The and the are the activation date and expiration date for this student's role. If they are absent, then the default access start and default access end dates are used. The default access dates can be set when the course is created, and can be modified using the Automated Enrollment 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 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). If there were 10 students in fs03nop590001, 5 students in fs03nop59o601, 8 students in fs03nop590602, and 2 students in fs03ost580002, then $$reply{'43551dedcd43febmsul1'} = 25 The purpose of the %reply hash is to detect cases where the institutional enrollment is 0 (most likely due to a problem with the data source). In such a case, the LON-CAPA course roster is left unchanged (i.e., no students are expired, even if automated drops is enabled. fetch_enrollment should return a 0 or 1, depending on whether a connection could be established to the institutional data source. 0 is returned if no connection could be made. 1 is returned if connection was successful A return of 1 is required for the calling modules to perform LON-CAPA roster changes based on the contents of the XML classlist file(s), e,g,, msu_43551dedcd43febmsul1_fs03nop590001_classlist.xml XML classlist files are temporary. They are deleted after the enrollment update process in the calling module is complete. =cut sub fetch_enrollment { my ($dom,$affiliatesref,$replyref) = @_; foreach my $crs (sort keys %{$affiliatesref}) { $$replyref{$crs} = 0; } my $okflag = 0; return $okflag; } =pod =item get_sections() This is called by the Automated Enrollment Manager interface (lonpopulate.pm) to create an array of valid sections for a specific institutional coursecode. e.g., for MSU coursecode: fs03nop590 ("001","601","602") would be returned If the array returned contains at least one element, then the interface offerred 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. get_sections takes two arguments - (a) the institutional coursecode (in the MSU case this is a concatenation of semester code, department and course number), and (b) the LON-CAPA domain that contains the course. If there is no access to official course sections at your institution, then an empty array is returned, and the Automated Enrollment Manager interface will allow the course coordinator to enter section numbers in text boxes. =cut sub get_sections { my ($coursecode,$dom) = @_; my @secs = (); return @secs; } =pod =item new_course() This is called by loncreatecourse.pm and lonpopulate.pm to record that fact that a new course section has been added to LON-CAPA that requires access to institutional data At MSU, this is required, as institutional classlists can only made available to faculty who are officially assigned to a course. The new_course subroutine is used to check that the course owner of the LON-CAPA course is permitted to access the institutional classlist for any course sections and crosslisted classes that the course coordinator wishes to have affiliated with the course. If access is permitted, then 'ok' is returned. The course section or crosslisted course will only be added to the list of affiliates if 'ok' is returned. new_course takes three 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). (b) the course owner. This is the LON-CAPA username and domain of the course coordinator assigned to the course when it is first created, in the form username:domain (c) the LON-CAPA domain that contains the course =cut sub new_course { my ($course_id,$owner,$dom) = @_; my $outcome = 'ok'; return $outcome; } =pod =item validate_courseID() This is called whenever a new course section or crosslisted course is being affiliated with a LON-CAPA course (i.e., by loncreatecourse.pm and the Automated Enrollment Manager in lonpopulate.pm). A check is made that the courseID that the course coordinator wishes to affiliate with the course is valid according to the institutional schedule of official classes A valid courseID is confirmed by returning 'ok' validate_courseID takes two 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). (b) the LON-CAPA domain that contains the course =cut sub validate_courseID { my ($course_id,$dom) = @_; my $outcome = 'ok'; return $outcome; } =pod =item create_password() This is called when the authentication method set for the automated enrollment process when enrolling new users in the domain is "localauth". This could be signalled for the specific user by the value of localauth for the tag from the classlist.xml files, or if this is blank, the default authtype, set by the domain coordinator when creating the course with loncreatecourse.pm. create_password takes three arguments - (a) $authparam - the value of from the classlist.xml files, or if this blank, the default autharg, set by the domain coordinator when creating the course with loncreatecourse.pm (b) $dom - the domain of the new user. (c) $username - the username of the new user (currently not actually used) Four values are returned: (a) the value of $authparam - which might have been changed (b) a flag to indicate whether a password had been created 0 means no password created 1 means password created. In this case the calling module - Enrollment.pm will send the LON-CAPA username and password to the new user's e-mail (if one was provided), or to the course owner (if one was not provided and the new user was created by the automated process), or to the active course coordinator (if the new user was created using the 'update roster now' interface included in the Automated Enrollment Manager). (c) a flag to indicate that the authentication method is correct - 'ok'. If $authchk is not set to 'ok' then account creation and enrollment of the new user will not occur. (d) if a password was created it can be sent along. This is the password which will be included in the e-mail sent to the new user, or made available to the course owner/course coordinator if no e-mail address is provided. If you do not wish to send a password, but want to give instructions on obtaining one, you could set $newpasswd as those instructions. (e.g., $newpasswd = '(Please visit room 212, ACNS Bldg. to obtain your password)'; The value of $newpasswd is NOT written in the user's LON-CAPA passwd file in /home/httpd/lonUsers/$dom/a/b/c/abcuser/passwd, which in the case of a user employing localauth will contain 'localauth:$authparam'. If you need to include a parameter in the user's passwd file, you should return it as $authparam, i.e., the first of the variables returned by create_password(). =cut sub create_password { my ($authparam,$dom,$username) = @_; my $authchk = 'ok'; my $newpasswd = ''; my $create_passwd = 0; return ($authparam,$create_passwd,$authchk,$newpasswd); } =pod =item instcode_format() Split coursecodes into constituent parts. e.g., INSTITUTIONALCODE = fs03nop590, LON-CAPA COURSEID: 43551dedcd43febmsul1 (MSU's course naming scheme - fs03 = Fall semester 2003, nop = department name, 590 = course number) Incoming data: $dom (domain) $$instcodes{'43551dedcd43febmsul1'} = 'fs03nop590' (hash of courseIDs) fs03nop590 would be split as follows @{$codetitles} = ("year","semester","department","number") $$codes{'year'} = '2003' $$codes{'semester'} = 'Fall' $$codes{'department'} = 'nop' $$codes{'number'} = '590' requires six arguments: domain ($dom) reference to hash of institutional course IDs ($instcodes) reference to hash of codes ($codes) reference to array of titles ($codetitles) reference to hash of abbreviations used in categories reference to hash of arrays specifying sort order used in category titles e.g., %{$$cat_titles{'Semester'}} = ( fs => 'Fall', ss => 'Spring', us => 'Summer'); e.g., @{$$cat_order{'Semester'}} = ('ss','us','fs'); returns 1 parameter: 'ok' if no processing errors. Detailed help: http://yourloncapaserver/adm/help/Institutional_Integration_Course_Codes.hlp =cut sub instcode_format () { my ($dom,$instcodes,$codes,$codetitles,$cat_titles,$cat_order) = @_; my $outcome = 'ok'; return $outcome; } =pod =item institutional_photos() Called when automated enrollment manager is used to update student photos. Incoming data: six arguments (a) $dom (domain) (b) $crs (LONCAPA course number) (c) $affiliates: a reference to a hash with the keys set to the institutional course IDs for the course. (d) $result: a reference to a hash which will return usernames of students (& separated) in following categories (the keys): new, update, missing, same, deleted, noid, nouser. The list includes those students for whom the result of the modification process was either addition of a new photo. update of an existing photo, photo was found to be missing from institution's data store, photo used is same as before, or photo was deleted from storage on LON-CAPA server housing student's information, no student ID was available. (e) $action: the type of action needed. (e.g., update, delete); (f) $students: a reference to a hash with the keys set to student usernames and domains in the form username:domain, and values set to the studentID, if action is required for specific students. returns 1 parameter: 'ok' if no processing errors. other course or student specific values can be stored as values in the appropriate referenced hashes. =cut sub institutional_photos { my ($dom,$crs,$affiliates,$result,$action,$students) = @_; my $outcome = 'ok'; return $outcome; } =pod =item photo_permission() Incoming data: three arguments (a) $dom (domain) (b) $perm_reqd: a reference to a a scalar that is either 'yes' if a course owner must indicate acceptance of conditions of use, 'no' otherwise. (c) $conditions: the text of the conditions of use. returns 1 parameter: 'ok' if no processing errors. $$perm_reqd is set to 'yes' or 'no' $$agreement is set to conditions of use - plain text string which will be displayed in a textarea in a web form. =cut sub photo_permission { my ($dom,$perm_reqd,$conditions) = @_; $$perm_reqd = 'no'; $$conditions = ''; my $outcome = 'ok'; return $outcome; } =pod =item manager_photo_update() Incoming data: one argument (a) $dom (domain) returns 2 parameters: update (0 or 1), and comment. Called by automated enrollment manager, to determine whether "Update Student photos" button will be available, and if so, the message (plain text string) that will be displayed with the button. =cut sub manager_photo_update { my ($dom) = @_; my $update = 0; my $comment = ''; return ($update,$comment); } =pod =item check_section() Incoming data: three arguments (+ fourth optional argument) (a) $class - institutional class id (coursecode concatanated with section) (b) $owner - course owner (2.2 and later username:domain; pre-2.2 username; 2.6 and later - comma-separated list of username:domain for course owner and co-owners.) (c) $dom - domain of course (d) $dbh - optional database handle returns 1 parameter - $sectioncheck ('ok' or other value). Verifies that at least one of the course owner (or co-owners) have access to classlist for specific class according to institution's SIS 'ok' if access available =cut sub check_section { my ($class,$owner,$dom,$dbh) = @_; my $sectioncheck = 'ok'; return $sectioncheck; } =pod =item instcode_defaults() Incoming data: three arguments (a) $dom - domain (b) $defaults - reference to hash which will contain default regular expression matches for different components of an institutional course code (c) $code_order - reference to array which will contain order of component parts used in institutional code. returns 1 parameter - ('ok' or other value). Used to construct a regular expression to be used when searching for courses based on fragments of an institutional code. $defaults contains defaults to use for each component, and code_order contains keys of hash in order in which they are to be concatenated. e.g., INSTITUTIONALCODE = fs03nop590 (MSU's course naming scheme - fs = semester, 03 = year, nop = department name, 590 = course number) %{$defaults} = ( 'Year' => '\d{2}', 'Semester' => '^[sfu]s', 'Department' => '\w{2,3}', 'Number' => '\d{3,4}\w?', ); @{$code_order} = ('Semester','Year','Department','Number'); Detailed help: http://yourloncapaserver/adm/help/Institutional_Integration_Course_Codes.hlp =cut sub instcode_defaults { my ($dom,$defaults,$code_order) = @_; return 'ok'; } =pod =item allusers_info() Incoming data: three arguments (a) $dom - domain (b) $instusers - reference to hash which will contain hashes, where keys will be usernames and value will be a hash of user information. Keys in the inner hash will be some 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. (c) $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 all users from all available institutional datafeeds. =cut sub allusers_info { my ($dom,$instusers,$instids) = @_; my $outcome = 'ok'; return $outcome; } =pod =item get_userinfo() Incoming data: four required arguments and additional optional arguments Two modes of operation: (1) Retrieves institutional data for a single user either by username if $uname is included as second argument, or by ID if $id is included as a third argument. Either (b) or (c) must be provided. (g), (h) and (i) will be undefined. (2) Retrieves institutional user data from search of an institutional directory based on a search. (g) and (h) are required. (i) is optional. (b) and (c) will be undefined. (a) $dom - domain (b) $uname - username of user (c) $id - student/faculty ID of user (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. (f) $types - optional reference to array which contains 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 (h) $srchterm - optional if $uname or $id defined, otherwise required String to search for. (i) $srchtype - optional. Allowed values: contains, begins (defaults to exact match otherwise). 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 institutional directory searches will always be reported as being unavailable in domain $dom. =cut sub get_userinfo { my ($dom,$uname,$id,$instusers,$instids,$types, $srchby,$srchterm,$srchtype) = @_; my $outcome = 'unavailable'; return $outcome; } =pod =item inst_usertypes() Incoming data: three arguments (a) $dom - domain (b) $usertypes - reference to hash which will contain key = value, where keys are institution affiliation types (e.g., Faculty, Student etc.) and values are titles (e.g., Faculty/Academic Staff) (c) $order - reference to array which will contain the order in which institutional types should be shown when displaying data tables (e.g., default quotas or updateable user fields (see domainprefs.pm) returns 1 parameter - 'ok' if no processing error, or other value if an error occurred. =cut sub inst_usertypes { my ($dom,$usertypes,$order) = @_; @{$order} = (); %{$usertypes} = (); my $outcome = 'ok'; return $outcome; } =pod =item username_rules() Incoming data: three arguments (a) $dom - domain (b) $ruleshash - reference to hash containing rules (a hash of a hash) keys of top level hash are short names (e.g., netid, noncredit) for each key, value is a hash desc => long name for rule rule => description of rule authtype => (krb5,krb4,int, or loc) authentication type for rule authparm => authentication parameter for rule authparmfixed => 1 if authparm used when creating user for rule must be authparm authmsg => Message to display describing authentication to use for this rule (c) $rulesorder - reference to array containing rule names in order to be displayed returns 'ok' if no processing error. =cut sub username_rules { my ($dom,$ruleshash,$rulesorder) = @_; my $outcome; return $outcome; } =pod =item id_rules() Incoming data: three arguments (a) $dom - domain (b) $ruleshash - reference to hash containing rules (a hash of a hash) keys of top level hash are short names (e.g., netid, noncredit) for each key, value is a hash desc => long name for rule rule => description of rule (c) $rulesorder - reference to array containing rule names in order to be displayed returns 'ok' if no processing error. =cut sub id_rules { my ($dom,$ruleshash,$rulesorder) = @_; my $outcome; return $outcome; } =pod =item selfcreate_rules() Incoming data: three arguments (a) $dom - domain (b) $ruleshash - reference to hash containing rules (a hash of a hash) keys of top level hash are short names (e.g., netid) for each key, value is a hash desc => long name for rule rule => description of rule (c) $rulesorder - reference to array containing rule names in order to be displayed returns 'ok' if no processing error. =cut sub selfcreate_rules { my ($dom,$ruleshash,$rulesorder) = @_; my $outcome; return $outcome; } =pod =item username_check() Incoming data: four arguments (a) $dom - domain (scalar) (b) $uname - username to compare against rules (scalar) (c) $to_check (reference to array of rule names to check) (d) $resultshash (reference to hash of results) hash of results for rule checked - keys are rule names - values are: 1 or 0 (for matched or unmatched) returns 'ok' if no processing error. =cut sub username_check { my ($dom,$uname,$to_check,$resultshash) = @_; my $outcome; return $outcome; } =pod =item id_check() Incoming data: four arguments (a) $dom - domain (scalar) (b) $id - ID to compare against rules (scalar) (c) $to_check (reference to array of rule names to check) (d) $resultshash (reference to hash of results) hash of results for rule checked - keys are rule names - values are: 1 or 0 (for matched or unmatched) returns 'ok' if no processing error. =cut sub id_check { my ($dom,$id,$to_check,$resultshash) = @_; my $outcome; return $outcome; } =pod =item selfcreate_check() Incoming data: four arguments (a) $dom - domain (scalar) (b) $selfcreatename - e-mail proposed as username (compare against rules - scalar) (c) $to_check (reference to array of rule names to check) (d) $resultshash (reference to hash of results) hash of results for rule checked - keys are rule names - values are: 1 or 0 (for matched or unmatched) returns 'ok' if no processing error. =cut sub selfcreate_check { my ($dom,$selfcreatename,$to_check,$resultshash) = @_; my $outcome; return $outcome; } =pod =item AUTOLOAD() Incoming data: none Returns '' Prevents errors when undefined subroutines are called in this package Will allow new routines added in the future to be called from lond etc. without the need for customized versions of local*.pm packages to be modified to include the new subroutines immediately. See "Programming Perl" 3rd ed. pp 296-298. =back =cut sub AUTOLOAD { our $AUTOLOAD; return ''; } 1;