# # $Id: batchcreatecourse.pm,v 1.40.2.2 2019/07/26 14:52:26 raeburn 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/ # package LONCAPA::batchcreatecourse; use LONCAPA::Configuration; use LONCAPA::Enrollment; use HTML::Parser; use Time::Local; use Apache::lonnet; use Apache::loncommon; use Apache::lonlocal; use LONCAPA qw(:match); use strict; # Collection of routines used for batch creation of courses and users. # &create_courses() should be called by an Autocreate.pl # script via a cron entry, or alternatively from a web page, after upload # of a file containing an XML description of a course request (lonbatchccrs.pm). # # XML file(s) describing courses that are to be created in domain $dom are stored in # /home/httpd/perl/tmp/addcourse/$dom # # &create_courses() will create an account for the course owner # (if one does not currently exist), will create the course (cloning if necessary), # and will add additional instructional staff (creating accounts if necessary). # # Example of XML file (which could contain more than one class to be created): # # # # # Underwater Basket Weaving # Course # ss05ubw101 # 3 # msul1 # msu # /res/msu/ # # 1 # 1 # 2005:01:04:10:30 # 2005:07:04:20:30 # 2005:01:10:10:30 # 2005:05:31:10:30 # # krb4 # MSU.EDU # # # # nav # 20 # 1 # 466011437c34194msul1 # msu # shift # 365 # # 1 # 1 # 1 # 0 # keyadmin:msu # 1 # 1 # # 1 # 1 # # sparty # msu # krb4 # MSU.EDU # # #
# 001 # 1 #
#
# 002 # 2 #
#
# # # ss05zzz101001 # 1 # # # # # sparty # msu # sparty@msu.edu # krb4 # # MSU # # Spartanx # # # # # # # itds0001 # northwood5 # itds0001@msu.edu # int # # Info # # Techcx # # # # # 2005:01:01:12:10 # 2005:12:01:12:10 # 1 # 2 # # # # #
# # Many of these are binary options (corresponding to either checkboxes or # radio buttons in the interactive CCRS page). Examples include: # setpolicy, setcontent, setcomment, setkeys, disableresdis, disablechat, openall, # uniquecode # # A value of 1 between opening and closing tags is equivalent to a # checked checkbox or 'Yes' response in the original CCRS web page. # A value of 0 or blank is equivalent to an unchecked box or 'No' # response. Dates are in format YYYY:MM:DD:HH:MM:SS (:separators required) # # firstres can be nav, syl, or blank for "Navigate Contents", Syllabus, or # no entry respectively. # # crstype can be Course or Community # # crsquota is the total disk space permitted for course group portfolio files # in all course groups. # # For format of other parameters, refer to the interactive CCRS page # and view how the equivalent parameter is displayed in the web form. # ############################################################## # create_courses() - creates courses described in @$requests, # files listed in @$requests are deleted # after the files have been parsed. # # Directory for retrieval of files listed in @$requests is: # /home/httpd/perl/tmp/addcourse/$dom/auto/pending if $context = auto # /home/httpd/perl/tmp/addcourse/$dom/web/$uname_$udom/pending if $context = web # # inputs (six) - requests - ref to array of filename(s) containing course requests # courseids - ref to hash to store LON-CAPA course ids of new courses # context - auto if called from command line, web if called from browser # dom - domain for which the course is being created # uname - username of DC who is requesting course creation # udom - domain of DC who is requesting course creation # # outputs (four) - output - text recording user roles added etc. # logmsg - text to be logged # keysmsg - text containing link(s) to manage keys page(s) # codehash - reference to hash containing courseID => unique code # where unique code is a 6 character code, to distribute # to students as a shortcut to the course. ############################################################# sub create_courses { my ($requests,$courseids,$context,$dom,$uname,$udom) = @_; my $output; my $perlvarref = LONCAPA::Configuration::read_conf('loncapa.conf'); # Get role names my %longroles = (); open(FILE,"<$$perlvarref{'lonTabDir'}.'/rolesplain.tab"); my @rolesplain = ; close(FILE); foreach my $item (@rolesplain) { if ($item =~ /^(st|ta|ep|ad|in|cc|co):([\w\s]+):?([\w\s]*)/) { $longroles{'Course'}{$1} = $2; $longroles{'Community'}{$1} = $3; } } my ($logmsg,$keysmsg,$newusermsg,$addresult,%codehash,%instcodes); my %enrollcount = (); my $newcoursedir = LONCAPA::tempdir().'/addcourse/'.$dom.'/'.$context; if ($context eq 'auto') { $newcoursedir .= '/pending'; } else { if ($uname && $udom) { $newcoursedir .= '/'.$uname.'_'.$udom.'/pending'; } else { $logmsg = "batchcreatecourse::create_courses() called without username and/or domain of requesting Domain Coordinator"; } } if (@{$requests} > 0) { foreach my $request (@{$requests}) { my %details = (); if (-e $newcoursedir.'/'.$request) { &parse_coursereqs($newcoursedir.'/'.$request, \%details); foreach my $num (sort(keys(%details))) { my $reqdetails = $details{$num}; my $code; my $courseid = &build_course($dom,$num,$context,$reqdetails,\%longroles,\$logmsg,\$newusermsg, \$addresult,\%enrollcount,\$output,\$keysmsg,undef,undef,undef,undef,\$code); if ($courseid =~m{^/$match_domain/$match_courseid}) { $$courseids{$courseid} = $details{$num}{'class'}; if ($code) { $codehash{$courseid} = $code; } if ($details{$num}{'coursecode'} ne '') { push(@{$instcodes{$details{$num}{'coursecode'}}},$courseid); } } } } } } return ($output,$logmsg,$keysmsg,\%codehash,\%instcodes); } ############################################################# # # parse_coursereqs() # inputs (two) - coursefile - path to XML file containing course(s) to be created. # - details - reference to hash containing extracted information. # outputs (none) # ############################################################ sub parse_coursereqs { my ($coursefile,$details) = @_; # Note all start and end dates should be in this format: # YYYY:MM:DD:HH:MM:SS (:separators required). my $uname = ''; my @state = (); my $num = 0; my $secid = 0; my $xlist = 0; my $userkey = ''; my $role = ''; my @items = ('title','optional_id','coursecode','defaultcredits','coursehome','reshome','nonstandard','adds','drops','topmap','firstres','clonecrs','clonedom','datemode','dateshift','showphotos','setpolicy','setcontent','setcomment','setkeys','keyauth','disresdis','disablechat','openall','notify_owner','notify_dc','crstype','crsquota','uniquecode'); my @possroles = qw(st ad ep ta in cc co); my @dateitems = ('enrollstart','enrollend','accessstart','accessend'); my @useritems = ('autharg','authtype','firstname','generation','lastname','middlename','studentID'); my $p = HTML::Parser->new ( xml_mode => 1, start_h => [sub { my ($tagname, $attr) = @_; push(@state, $tagname); if ("@state" eq "class") { %{$$details{$num}} = (); $$details{$num}{'class'} = $attr->{id}; %{$$details{$num}{'users'}} = (); %{$$details{$num}{'sections'}} = (); $secid = 0; $xlist = 0; } if ("@state" eq "class users user roles role") { $role = $attr->{id}; if (grep(/^\Q$role\E$/,@possroles)) { push(@{$$details{$num}{'users'}{$userkey}{'roles'}}, $role); %{$$details{$num}{'users'}{$userkey}{$role}} = (); @{$$details{$num}{'users'}{$userkey}{$role}{'usec'}} = (); } } if ("@state" eq "class sections section") { $secid ++; %{$$details{$num}{'sections'}{$secid}} = (); } if ("@state" eq "class crosslists xlist") { $xlist ++; %{$$details{$num}{'crosslists'}{$xlist}} = (); } }, "tagname, attr"], text_h => [sub { my ($text) = @_; if ("@state" eq "class owner username") { $$details{$num}{'owner'} = $text; } elsif ("@state" eq "class owner domain") { $$details{$num}{'domain'} = $text; } elsif ("@state" eq "class sections section inst") { $$details{$num}{'sections'}{$secid}{'inst'} = $text; } elsif ("@state" eq "class sections section loncapa") { $$details{$num}{'sections'}{$secid}{'loncapa'} = $text; } elsif ("@state" eq "class crosslists xlist inst") { $$details{$num}{'crosslists'}{$xlist}{'inst'} = $text; } elsif ("@state" eq "class crosslists xlist loncapa") { $$details{$num}{'crosslists'}{$xlist}{'loncapa'} = $text; } elsif ("@state" eq "class owner authtype") { $$details{$num}{'ownerauthtype'} = $text; } elsif ("@state" eq "class owner autharg") { $$details{$num}{'ownerauthparam'} = $text; } elsif ("@state" eq "class authentication method") { $$details{$num}{'authtype'} = $text; } elsif ("@state" eq "class authentication param") { $$details{$num}{'authparam'} = $text; } elsif ("@state" eq "class users user username") { $userkey = $text; } elsif ("@state" eq "class users user domain") { $userkey .= ':'.$text; %{$$details{$num}{'users'}{$userkey}} = (); @{$$details{$num}{'users'}{$userkey}{'roles'}} = (); } elsif ("@state" eq "class users user email") { $$details{$num}{'users'}{$userkey}{'emailaddr'} = $text; $$details{$num}{'users'}{$userkey}{'emailenc'} = &LONCAPA::escape($text); } elsif ("@state" eq "class users user roles role start") { if (grep(/^\Q$role\E$/,@possroles)) { $$details{$num}{'users'}{$userkey}{$role}{'start'} = &process_date($text); } } elsif ("@state" eq "class users user roles role end") { if (grep(/^\Q$role\E$/,@possroles)) { $$details{$num}{'users'}{$userkey}{$role}{'end'} = &process_date($text); } } elsif ("@state" eq "class users user roles role usec") { if (grep(/^\Q$role\E$/,@possroles)) { unless ($text eq '') { push(@{$$details{$num}{'users'}{$userkey}{$role}{'usec'}},$text); } } } else { foreach my $item (@items) { if ("@state" eq "class $item") { $$details{$num}{$item} = $text; } } foreach my $item (@dateitems) { if ("@state" eq "class $item") { $$details{$num}{$item} = &process_date($text); } } foreach my $item (@useritems) { if ("@state" eq "class users user $item") { $$details{$num}{'users'}{$userkey}{$item} = $text; } } } }, "dtext"], end_h => [sub { my ($tagname) = @_; if ("@state" eq "class") { $num ++; } pop @state; }, "tagname"], ); $p->parse_file($coursefile); $p->eof; return; } ######################################################### # # build_course() # # inputs # course domain # course request number # context - auto if called from command line, web if called from DC web interface # ref to hash of course creation information # ref to hash of role descriptions # ref to scalar used to accumulate log messages # ref to scalar used to accumulate messages sent to new users # ref to scalar used to accumulate results of new user additions # ref to hash of enrollment counts for different roles # ref to scalar used to accumulate information about added roles # ref to scalar used to accumulate information about access keys # domain of DC creating course # username of DC creating course # optional course number, if unique course number already obtained (e.g., for # course requests submitted via course request form. # optional category # optional ref to scalar for six character unique identifier # # outputs # LON-CAPA courseID for new (created) course # ######################################################### sub build_course { my ($cdom,$num,$context,$details,$longroles,$logmsg,$newusermsg,$addresult, $enrollcount,$output,$keysmsg,$udom,$uname,$cnum,$category,$coderef) = @_; return unless (ref($details) eq 'HASH'); my $owner_uname = $details->{'owner'}; my $owner_domain = $details->{'domain'}; my $owner = $owner_uname.':'.$owner_domain; my $sectionstr = ''; my $xliststr = ''; my $noenddate = ''; my $outcome; my ($courseid,$crsudom,$crsunum,$crstype,$ccrole,$rolenames); if ($details->{'crstype'} eq 'Community') { $crstype = $details->{'crstype'}; $ccrole ='co'; if (ref($longroles) eq 'HASH') { $rolenames = $longroles->{'Community'}; } } else { $crstype = 'Course'; $ccrole = 'cc'; if (ref($longroles) eq 'HASH') { $rolenames = $longroles->{'Course'}; } } my $linefeed; if ($context eq 'auto') { $linefeed = "\n"; } else { $linefeed = "
\n"; } if ($details->{'accessend'} eq '') { $noenddate = 1; } my $reshome = $details->{'reshome'}; if ($reshome eq '') { $reshome = '/res/'.$cdom; } my $firstres = $details->{'firstres'}; if ($firstres eq '') { if ($crstype eq 'Community') { $firstres = 'nav'; } else { $firstres = 'syl'; } } foreach my $secid (sort(keys(%{$details->{'sections'}}))) { $sectionstr .= $details->{'sections'}{$secid}{'inst'}.':'.$details->{'sections'}{$secid}{'loncapa'}.','; } $sectionstr =~ s/,$//; foreach my $xlist (sort(keys(%{$details->{'crosslists'}}))) { $xliststr .= $details->{'crosslists'}{$xlist}{'inst'}.':'.$details->{'crosslists'}{$xlist}{'loncapa'}.','; } $xliststr =~ s/,$//; my %courseinfo = ( inst_code => $details->{'coursecode'}, description => $details->{'title'} ); if (&Apache::lonnet::homeserver($details->{'owner'},$details->{'domain'}) eq 'no_host') { # Add user if no account my $ownerargs = {'auth' => $details->{'ownerauthtype'}, 'authparam' => $details->{'ownerauthparam'}, 'emailenc' => $details->{'emailenc'}, 'udom' => $details->{'domain'}, 'uname' => $details->{'owner'}, 'pid' => $details->{'users'}{$owner}{'studentID'}, 'first' => $details->{'users'}{$owner}{'firstname'}, 'middle' => $details->{'users'}{$owner}{'middlename'}, 'last' => $details->{'users'}{$owner}{'lastname'}, 'gene' => $details->{'users'}{$owner}{'generation'}, 'usec' => '', 'end' => '', 'start' => '', 'emailaddr' => $details->{'users'}{$owner}{'email'}, 'cid' => '', 'context' => 'createowner', 'linefeed' => $linefeed, 'role' => $ccrole, }; $outcome = &LONCAPA::Enrollment::create_newuser($ownerargs,$logmsg,$newusermsg,$enrollcount,$addresult,$rolenames,\%courseinfo,$context); } else { $outcome = 'ok'; } if ($outcome eq 'ok') { if ($details->{'datemode'} !~ /^(preserve|shift|delete)$/) { $details->{'datemode'} = 'shift'; $details->{'dateshift'} = 365; } my $courseargs = { ccuname => $details->{'owner'}, ccdomain => $details->{'domain'}, cdescr => $details->{'title'}, crstype => $details->{'crstype'}, curl => $details->{'topmap'}, course_domain => $cdom, course_home => $details->{'coursehome'}, nonstandard => $details->{'nonstandard'}, crscode => $details->{'coursecode'}, defaultcredits => $details->{'defaultcredits'}, crsquota => $details->{'crsquota'}, uniquecode => $details->{'uniquecode'}, clonecourse => $details->{'clonecrs'}, clonedomain => $details->{'clonedom'}, datemode => $details->{'datemode'}, dateshift => $details->{'dateshift'}, crsid => $details->{'optional_id'}, curruser => $details->{'owner'}, crssections => $sectionstr, crsxlist => $xliststr, autoadds => $details->{'adds'}, autodrops => $details->{'drops'}, notify => $details->{'notify_owner'}, notify_dc => $details->{'notify_dc'}, no_end_date => $noenddate, showphotos => $details->{'showphotos'}, authtype => $details->{'authtype'}, autharg => $details->{'authparam'}, enrollstart => $details->{'enrollstart'}, enrollend => $details->{'enrollend'}, startaccess => $details->{'accessstart'}, endaccess => $details->{'accessend'}, setpolicy => $details->{'setpolicy'}, setcontent => $details->{'setcontent'}, setcomment => $details->{'setcomment'}, reshome => $reshome, setkeys => $details->{'setkeys'}, keyauth => $details->{'keyauth'}, disresdis => $details->{'disresdis'}, disablechat => $details->{'disablechat'}, openall => $details->{'openall'}, firstres => $firstres }; if ($details->{'textbook'}) { $courseargs->{'textbook'} = $details->{'textbook'}; } my %host_servers = &Apache::lonnet::get_servers($cdom,'library'); if (! exists($host_servers{$details->{'coursehome'}})) { $$logmsg .= &mt('Invalid home server for course').': '.$details->{'coursehome'}; return; } my ($success, $msg) = &Apache::loncommon::construct_course($courseargs,$logmsg,\$courseid,\$crsudom,\$crsunum, $udom,$uname,$context,$cnum,$category,$coderef); $$logmsg .= $msg; if (!$success) { return; } } else { return; } # # Make owner a coordinator # if (($owner_domain) && ($owner_uname)) { &Apache::lonnet::assignrole($owner_domain,$owner_uname,$courseid,$ccrole,'','','','',$context); } # # Process other reqested users # my @courseroles = qw(st ep ta in); push(@courseroles,$ccrole); if (&owner_is_dc($owner_uname,$owner_domain,$crsudom)) { push(@courseroles,'ad'); } my $stulogmsg = ''; foreach my $userkey (sort(keys(%{$details->{'users'}}))) { my $url = '/'.$crsudom.'/'.$crsunum; next if (ref($details->{'users'}{$userkey}{'roles'}) ne 'ARRAY'); if (@{$details->{'users'}{$userkey}{'roles'}} > 0) { my ($username,$userdom) = split/:/,$userkey; if (&Apache::lonnet::homeserver($username,$userdom) eq 'no_host') { # Add user if no account my @reqroles = @{$details->{'users'}{$userkey}{'roles'}}; my @badroles; my $firstrole = shift(@reqroles); while (@reqroles > 0) { if ($firstrole =~ m{^cr/($match_domain)/($match_username)/([^/]+)$}) { if (($1 eq $owner_domain) && ($2 eq $owner_uname)) { last; } else { push(@badroles,$firstrole); $firstrole = shift(@reqroles); } } elsif (grep(/^\Q$firstrole\E$/,@courseroles)) { last; } else { push(@badroles,$firstrole); $firstrole = shift(@reqroles); } } if (@badroles > 0) { if (@badroles > 1) { $$output .= &mt('The following requested roles are unavailable:').' '.join(', ',@badroles); } else { $$output .= &mt('The following requested role: [_1] is unavailable.',$badroles[0]); } } my $firstsec; unless (($firstrole eq $ccrole) || ($firstrole eq '')) { $firstsec = $details->{'users'}{$userkey}{$firstrole}{'usec'}[0]; } my $userargs = { 'auth' => $details->{'users'}{$userkey}{'authtype'}, 'authparam' => $details->{'users'}{$userkey}{'autharg'}, 'emailenc' => $details->{'users'}{$userkey}{'emailenc'}, 'udom' => $userdom, 'uname' => $username, 'pid' => $details->{'users'}{$userkey}{'studentID'}, 'first' => $details->{'users'}{$userkey}{'firstname'}, 'middle' => $details->{'users'}{$userkey}{'middlename'}, 'last' => $details->{'users'}{$userkey}{'lastname'}, 'gene' => $details->{'users'}{$userkey}{'generation'}, 'usec' => $firstsec, 'end' => $details->{'users'}{$userkey}{'end'}, 'start' => $details->{'users'}{$userkey}{'start'}, 'emailaddr' => $details->{'users'}{$userkey}{'emailaddr'}, 'cid' => $courseid, 'crs' => $crsunum, 'cdom' => $crsudom, 'context' => 'createcourse', 'linefeed' => $linefeed, 'role' => $details->{'users'}{$userkey}{'roles'}[0], }; if ($userargs->{'role'} eq 'st') { if (exists($details->{'users'}{$userkey}{'credits'})) { $userargs->{'credits'} = $details->{'users'}{$userkey}{'credits'}; $userargs->{'credits'} =~ s/[^\d\.]//g; } } $outcome = &LONCAPA::Enrollment::create_newuser($userargs,$logmsg,$newusermsg,$enrollcount,$addresult,$longroles,\%courseinfo,$context); # now add other roles and other sections. if ($outcome eq 'ok') { if ((($firstrole ne 'st') && ($firstrole ne $ccrole) && ($firstrole ne '')) && (@{$details->{'users'}{$userkey}{$firstrole}{'usec'}} > 1)) { for (my $i=1; $i<@{$details->{'users'}{$userkey}{$firstrole}{'usec'}}; $i++) { my $curr_role = $firstrole; my $start = $details->{'users'}{$userkey}{$curr_role}{'start'}; my $end = $details->{'users'}{$userkey}{$curr_role}{'end'}; my $usec = $details->{'users'}{$userkey}{$firstrole}{'usec'}[$i]; $url = '/'.$crsudom.'/'.$crsunum; if ($usec ne '') { $url .= '/'.$usec; } if ($firstrole =~ m{^cr/($match_domain)/($match_username)/([^/]+)$}) { $$output .= &Apache::loncommon::commit_customrole($userdom,$username,$url,$1,$2,$3,$start,$end,$context); } else { $$output .= &Apache::loncommon::commit_standardrole($userdom,$username,$url,$curr_role,$start,$end,$crsudom,$crsunum,$usec,$context); } } } if (@reqroles > 0) { foreach my $curr_role (@reqroles) { my $start = $details->{'users'}{$userkey}{$curr_role}{'start'}; my $end = $details->{'users'}{$userkey}{$curr_role}{'end'}; if ($curr_role eq 'st') { my $usec = $details->{'users'}{$userkey}{$curr_role}{'usec'}[0]; $url = '/'.$crsudom.'/'.$crsunum; if ($usec ne '') { $url .= '/'.$usec; } my $credits; if (exists($details->{'users'}{$userkey}{'credits'})) { $credits = $details->{'users'}{$userkey}{'credits'}; $credits =~ s/[^\d\.]//g; } $$output .= &Apache::loncommon::commit_studentrole(\$stulogmsg,$userdom,$username,$url,$curr_role,$start,$end,$crsudom,$crsunum,$usec,$context,$credits); } elsif ($curr_role eq $ccrole) { $url = '/'.$crsudom.'/'.$crsunum; my $usec = ''; $$output .= &Apache::loncommon::commit_standardrole($userdom,$username,$url,$curr_role,$start,$end,$crsudom,$crsunum,$usec,$context); } elsif ((grep(/^\Q$curr_role\E$/,@courseroles)) || ($curr_role =~ m{^cr/$match_domain/$match_username/[^/]+$})) { foreach my $usec (@{$details->{'users'}{$userkey}{$curr_role}{'usec'}}) { $url = '/'.$crsudom.'/'.$crsunum; if ($usec ne '') { $url .= '/'.$usec; } if ($curr_role =~ m{^cr/($match_domain)/($match_username)/([^/]+)$}) { if (($1 eq $owner_domain) && ($2 eq $owner_uname)) { $$output .= &Apache::loncommon::commit_customrole($userdom,$username,$url,$1,$2,$3,$start,$end,$context); } else { $$output = &mt('Requested custom role: [_1] unavailable, as it was not defined by the course owner.',$curr_role); } } else { $$output .= &Apache::loncommon::commit_standardrole($userdom,$username,$url,$curr_role,$start,$end,$crsudom,$crsunum,$usec,$context); } } } else { $$output .= &mt('Requested role: [_1] is unavailable.',$curr_role); } } } } } else { foreach my $curr_role (@{$details->{'users'}{$userkey}{'roles'}}) { my $start = $details->{'users'}{$userkey}{$curr_role}{'start'}; my $end = $details->{'users'}{$userkey}{$curr_role}{'end'}; if ($curr_role eq 'st') { my $usec = $details->{'users'}{$userkey}{$curr_role}{'usec'}[0]; $url = '/'.$crsudom.'/'.$crsunum; if ($usec ne '') { $url .= '/'.$usec; } my $credits; if (exists($details->{'users'}{$userkey}{'credits'})) { $credits = $details->{'users'}{$userkey}{'credits'}; $credits =~ s/[^\d\.]//g; } $$output .= &Apache::loncommon::commit_studentrole(\$stulogmsg,$userdom,$username,$url,$curr_role,$start,$end,$crsudom,$crsunum,$usec,$context,$credits); } elsif ((grep(/^\Q$curr_role\E$/,@courseroles)) || ($curr_role =~ m{^cr/$match_domain/$match_username/[^/]+$})) { if (@{$details->{'users'}{$userkey}{$curr_role}{'usec'}} > 0) { foreach my $usec (@{$details->{'users'}{$userkey}{$curr_role}{'usec'}}) { $url = '/'.$crsudom.'/'.$crsunum; if ($usec ne '') { $url .= '/'.$usec; } my $stdresult; if ($curr_role =~ m{/^cr/($match_domain)/($match_username)/([^/]+)$}) { if (($1 eq $owner_domain) && ($2 eq $owner_uname)) { $stdresult = &Apache::loncommon::commit_customrole($userdom,$username,$url,$1,$2,$3,$start,$end,$context); } else { $stdresult = &mt('Requested custom role: [_1] unavailable, as it was not defined by the course owner.',$curr_role); } } else { $stdresult = &Apache::loncommon::commit_standardrole($userdom,$username,$url,$curr_role,$start,$end,$crsudom,$crsunum,$usec,$context); } $$output .= $stdresult; } } else { $url = '/'.$crsudom.'/'.$crsunum; if ($curr_role =~ m{^cr/($match_domain)/($match_username)/([^/]+)$}) { if (($1 eq $owner_domain) && ($2 eq $owner_uname)) { $$output .= &Apache::loncommon::commit_customrole($userdom,$username,$url,$1,$2,$3,$start,$end,$context); } else { $$output .= &mt('Requested custom role: [_1] unavailable, as it was not defined by the course owner.',$curr_role); } } else { $$output .= &Apache::loncommon::commit_standardrole($userdom,$username,$url,$curr_role,$start,$end,$crsudom,$crsunum,'',$context); } } } else { $$output .= &mt('Requested role: [_1] is unavailable.',$curr_role); } } } } } # Information about keys. if ($details->{'setkeys'}) { $$keysmsg .= ''.&mt('Manage Access Keys').' for '.$details->{'title'}.$linefeed; } # Flush the course logs so reverse user roles immediately updated &Apache::lonnet::flushcourselogs(); return $courseid; } sub owner_is_dc { my ($owner_uname,$owner_dom,$cdom) = @_; my $is_dc = 0; my %roles = &Apache::lonnet::get_my_roles($owner_uname,$owner_dom,'userroles', ['active'],['dc'],[$cdom]); if ($roles{$owner_uname.':'.$owner_dom.':dc'}) { $is_dc = 1; } return $is_dc; } ######################################################### # # process_date() # # input - date/time string in format YYYY:MM:DD:HH:MM:SS (:separators required). # output - corresponding UNIX time (seconds since epoch). # ######################################################### sub process_date { my $timestr = shift; my $timestamp = ''; if ($timestr !~ /:/) { $timestamp = ''; } else { my @entries = split(/:/,$timestr); for (my $j=0; $j<@entries; $j++) { if ( length($entries[$j]) > 1 ) { $entries[$j] =~ s/^0//; } $entries[$j] =~ s/\D//g; if ($entries[$j] < 0) { $entries[$j] = 0; } } if ($entries[1] > 0) { $entries[1] = $entries[1] - 1; } if ($entries[5] > 60) { $entries[5] = 60; } if ($entries[4] > 59) { $entries[4] = 59; } if ($entries[3] > 23) { $entries[3] = 23; } if ($entries[2] > 31) { $entries[2] = 31; } if ($entries[1] > 11) { $entries[1] = 11; } if ($entries[2] == 31) { if (($entries[1] == 3) || ($entries[1] == 5) || ($entries[1] == 8) || ($entries[1] == 10)) { $entries[2] = 30; } } if ($entries[1] == 1) { if ($entries[2] > 29) { $entries[2] = 29; } if ($entries[2] == 29) { if ($entries[0]%4 != 0) { $entries[2] = 28; } elsif ( $entries[0]%100 == 0 && $entries[0]%400 != 0) { $entries[2] = 28; } } } $timestamp = timelocal($entries[5],$entries[4],$entries[3],$entries[2],$entries[1],$entries[0]); } return $timestamp; } 1; 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.