--- loncom/interface/loncoursequeueadmin.pm 2014/04/16 13:32:43 1.45 +++ loncom/interface/loncoursequeueadmin.pm 2017/08/03 16:11:46 1.57 @@ -1,7 +1,7 @@ # The LearningOnline Network # Utilities to administer domain course requests and course self-enroll requests # -# $Id: loncoursequeueadmin.pm,v 1.45 2014/04/16 13:32:43 raeburn Exp $ +# $Id: loncoursequeueadmin.pm,v 1.57 2017/08/03 16:11:46 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -105,13 +105,13 @@ sub send_selfserve_notification { $rawsubj = 'Self-enrollment requests processed'; push(@rawmsg,{ mt => 'Enrollment requests in the following course: [_1] have been processed.', - args => ["\n$contextdesc"], + args => ["\n$contextdesc\n"], }); } elsif ($context eq 'domainmanagers') { $rawsubj = 'Course/Community requests reviewed'; push(@rawmsg,{ - mt => 'Course/Community creation requests in the following domain: "[_1]" have been reviewed.', - args => ["\n$contextdesc"], + mt => 'Course/Community creation requests in the following domain: [_1] have been reviewed.', + args => ["\n$contextdesc\n"], }); if (ref($textstr) eq 'ARRAY') { push(@rawmsg,@{$textstr}); @@ -119,8 +119,8 @@ sub send_selfserve_notification { } elsif ($context eq 'authormanagers') { $rawsubj = 'Authoring Space requests reviewed'; push(@rawmsg,{ - mt => 'Authoring requests in the following domain: "[_1]" have been reviewed.', - args => ["\n$contextdesc"], + mt => 'Authoring requests in the following domain: [_1] have been reviewed.', + args => ["\n$contextdesc\n"], }); if (ref($textstr) eq 'ARRAY') { push(@rawmsg,@{$textstr}); @@ -128,8 +128,8 @@ sub send_selfserve_notification { } elsif ($context eq 'usernamemanagers') { $rawsubj = 'LON-CAPA account requests reviewed'; push(@rawmsg,{ - mt => 'Account requests in the following domain: "[_1]" have been reviewed.', - args => ["\n$contextdesc"], + mt => 'Account requests in the following domain: [_1] have been reviewed.', + args => ["\n$contextdesc\n"], }); if (ref($textstr) eq 'ARRAY') { push(@rawmsg,@{$textstr}); @@ -396,6 +396,8 @@ sub display_queued_requests { if ($context eq 'pending') { $disposition = 'pending'; $nextphase = 'requestvalidation'; + } elsif ($context eq 'displaypending') { + $disposition = 'pending'; } %requesthash = &Apache::lonnet::dump_dom($namespace,$dom,'_'.$disposition); $nextelement = '<input type="hidden" name="phase" value="'.$nextphase.'" />'; @@ -422,7 +424,7 @@ sub display_queued_requests { my ($cnum,$disposition) = split('_',$item); $entry = $cnum.':'.$requesthash{$item}{'ownername'}.':'. $requesthash{$item}{'ownerdom'}.':'; - if ($context eq 'pending') { + if (($context eq 'pending') || ($context eq 'displaypending')) { $entry .= $requesthash{$item}{'instcode'}; } else { $entry .= $requesthash{$item}{'crstype'}; @@ -441,10 +443,12 @@ sub display_queued_requests { if (keys(%queue_by_date) > 0) { if ($context eq 'course') { $output .= '<h3>'.&mt('Self-enrollment requests queued pending approval by a Coordinator').'</h3>'; - } elsif ($context eq 'pending') { + } elsif (($context eq 'pending') || ($context eq 'displaypending')) { $output .= '<h3>'.&mt('Requests for official courses queued pending validation').'</h3>'. '<p>'.&mt('Requests are validated against institutional data to confirm that the requestor is an instructor of record.').'<br />'. - &mt('Validation is attempted when the request is submitted.').' '.&mt('If unvalidated, the request will be held in a queue.').' '.&mt('Validation of pending requests is automatically repeated daily.').'</p>'; + &mt('Validation is attempted when the request is submitted.').' '. + &mt('If unvalidated, the request will be held in a queue.').' '. + &mt('Validation of pending requests is automatically repeated daily.').'</p>'; } elsif ($context eq 'requestauthor') { $output .= '<h3>'.&mt('Requests for Authoring Space queued pending approval by a Domain Coordinator').'</h3>'; } elsif ($context eq 'requestusername') { @@ -472,8 +476,9 @@ sub display_queued_requests { if ($context eq 'pending') { $output .= '<br /><input type="submit" name="validationcheck" value="'. &mt('Validate').'" /><br />'."\n". - '<p>'.&mt('Any course/community requests which are successfully validated will be created immediately.').' '.&mt('Unvalidated requests will be listed for manual approval/rejection.').'</p>'; - } else { + '<p>'.&mt('Any course/community requests which are successfully validated will be created immediately.').' '. + &mt('Unvalidated requests will be listed for manual approval/rejection.').'</p>'; + } elsif (($context ne 'helpdesk') && ($context ne 'displaypending')) { $output .= '<br /><input type="submit" name="processqueue" value="'.&mt('Save').'" />'; } $output .= '</form>'; @@ -481,7 +486,7 @@ sub display_queued_requests { $output .= '<div class="LC_info">'; if ($context eq 'course') { $output .= &mt('There are currently no enrollment requests awaiting approval.'); - } elsif ($context eq 'pending') { + } elsif (($context eq 'pending') || ($context eq 'displaypending')) { $output .= &mt('There are currently no requests for official courses awaiting validation.'); } elsif ($context eq 'requestauthor') { $output .= &mt('There are currently no requests for Authoring Space awaiting approval.'); @@ -501,7 +506,7 @@ sub build_queue_display { my %crstypes; my $output = &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(); - unless ($context eq 'pending') { + unless (($context eq 'pending') || ($context eq 'displaypending') || ($context eq 'helpdesk')) { $output .= '<th>'.&mt('Action').'</th>'; } $output .= '<th>'.&mt('Requestor').'</th>'; @@ -513,7 +518,7 @@ sub build_queue_display { } elsif ($context eq 'requestusername') { $output .= '<th>'.&mt('Date requested').'</th>'. '<th>'.&mt('Details').'</th>'; - } elsif ($context eq 'pending' || $context eq 'stillpending') { + } elsif ($context eq 'pending' || $context eq 'displaypending' || $context eq 'stillpending') { $output .= '<th>'.&mt('Institutional code').'</th>'. '<th>'.&mt('Date requested').'</th>'. '<th>'.&mt('Details').'</th>'; @@ -523,6 +528,7 @@ sub build_queue_display { unofficial => 'Unofficial course', community => 'Community', textbook => 'Textbook course', + placement => 'Placement test', ); $output .= '<th>'.&mt('Type').'</th>'. '<th>'.&mt('Date requested').'</th>'. @@ -568,7 +574,7 @@ sub build_queue_display { } else { my ($cnum,$ownername,$ownerdom,$type,$cdesc); my $queued = 'approval'; - if ($context eq 'pending' || $context eq 'stillpending') { + if ($context eq 'pending' || $context eq 'displaypending' || $context eq 'stillpending') { ($cnum,$ownername,$ownerdom,$instcode,$cdesc)=split(/:/,$request,5); $queued = 'pending'; } else { @@ -586,7 +592,7 @@ sub build_queue_display { &Apache::loncommon::plainname($ownername,$ownerdom), $ownername,$ownerdom); } - unless ($context eq 'pending') { + unless (($context eq 'pending') || ($context eq 'displaypending') || ($context eq 'helpdesk')) { $row = '<td><span class="LC_nobreak"><label>'. '<input type="radio" value="'.$approve.'" name="'.$count.'radioreq" />'.&mt('Approve').'</label>'. '<label>'.(' 'x2). @@ -605,7 +611,7 @@ sub build_queue_display { $row .= '<td>'.$showtime.'</td>'."\n". '<td>'.$detailslink.'</td>'."\n"; } else { - if ($context eq 'pending' || $context eq 'stillpending') { + if ($context eq 'pending' || $context eq 'displaypending' || $context eq 'stillpending') { $row .= '<td>'.$instcode.'</td>'."\n"; } else { $row .= '<td>'.$crstype.'</td>'."\n"; @@ -651,7 +657,7 @@ sub update_request_queue { $beneficiary = 'enroller'; $cid = $env{'request.course.id'}; $crstype = lc(&Apache::loncommon::course_type()); - $firsturl = &course_portal_url($cnum,$cdom); + $firsturl = &Apache::lonnet::course_portal_url($cnum,$cdom); %requesthash = &Apache::lonnet::dump($namespace,$cdom,$cnum); $access_start = $env{'course.'.$cid.'.internal.selfenroll_start_access'}; $access_end = $env{'course.'.$cid.'.internal.selfenroll_end_access'}; @@ -680,7 +686,7 @@ sub update_request_queue { } } my $domconfiguser = &Apache::lonnet::get_domainconfiguser($cdom); - $firsturl = &course_portal_url($domconfiguser,$cdom); + $firsturl = &Apache::lonnet::course_portal_url($domconfiguser,$cdom); $approvedmsg = [{ mt => 'Your request for Authoring Space has been approved.', }, @@ -705,7 +711,7 @@ sub update_request_queue { } } my $domconfiguser = &Apache::lonnet::get_domainconfiguser($cdom); - $firsturl = &course_portal_url($domconfiguser,$cdom); + $firsturl = &Apache::lonnet::course_portal_url($domconfiguser,$cdom); $approvedmsg = [{ mt => 'Your request for a LON-CAPA account has been approved.', }, @@ -886,7 +892,7 @@ sub update_request_queue { $middlename = $curr{$uname}{'middlename'}; $lastname = $curr{$uname}{'lastname'}; $generation = $curr{$uname}{'generation'}; - $inststatus = $curr{$uname}{'usertype'}; + $inststatus = $curr{$uname}{'inststatus'}; my ($key,$caller)=split(/&/,$curr{$uname}{'tmpinfo'}); if ($caller eq 'createaccount') { @@ -968,6 +974,9 @@ sub update_request_queue { } } } + if ($history{'details'}{'clonecrs'}) { + $customitems{'_LC_clonefrom'} = $history{'details'}{'clonedom'}.'_'.$history{'details'}{'clonecrs'}; + } my ($result,$postprocess) = &course_creation($cdom,$cnum,$context,$history{'details'},\$logmsg, \$newusermsg,\$addresult,\$enrollcount, \$response,\$keysmsg,\%domdefs,$longroles,\$code,\%customitems); @@ -977,7 +986,7 @@ sub update_request_queue { } else { $approvedmsg = $approvalmsg{'course'}; } - my $firsturl = &course_portal_url($cnum,$cdom); + my $firsturl = &Apache::lonnet::course_portal_url($cnum,$cdom); if (ref($approvedmsg) eq 'ARRAY') { if (ref($approvedmsg->[1]) eq 'HASH') { $approvedmsg->[1]->{'args'} = [$firsturl]; @@ -1311,7 +1320,7 @@ sub update_request_queue { my $syllabuslink = &Apache::loncommon::syllabuswrapper($showcourse,$cnum,$cdom); if ($codes{$cnum}) { - $syllabuslink .= &mt('Unique code: [_1]',$codes{$cnum}); + $syllabuslink .= ' '.&mt('Unique code: [_1]',$codes{$cnum}); } $output .= '<li>'.$syllabuslink.'</li>'; } @@ -1561,22 +1570,6 @@ sub update_request_queue { return $output; } -sub course_portal_url { - my ($cnum,$cdom) = @_; - my $chome = &Apache::lonnet::homeserver($cnum,$cdom); - my $hostname = &Apache::lonnet::hostname($chome); - my $protocol = $Apache::lonnet::protocol{$chome}; - $protocol = 'http' if ($protocol ne 'https'); - my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom); - my $firsturl; - if ($domdefaults{'portal_def'}) { - $firsturl = $domdefaults{'portal_def'}; - } else { - $firsturl = $protocol.'://'.$hostname; - } - return $firsturl; -} - sub get_student_counts { my ($cdom,$cnum) = @_; my (%idx,%stucounts); @@ -1600,12 +1593,14 @@ sub course_creation { $keysmsg,$domdefs,$longroles,$coderef,$customhash) = @_; unless ((ref($details) eq 'HASH') && (ref($domdefs) eq 'HASH') && (ref($longroles) eq 'HASH')) { - return 'error: Invalid request'; + return ('error: Invalid request'); } my ($result,$ownername,$ownerdom); my $crstype = $details->{'crstype'}; my $coursedesc = $details->{'cdescr'}; - my %domconfig = &Apache::lonnet::get_dom('configuration',['requestauthor'],$dom); + my $accessstart = $details->{'accessstart'}; + my $accessend = $details->{'accessend'}; + my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$dom); if (ref($domconfig{'requestcourses'}) eq 'HASH') { if (ref($domconfig{'requestcourses'}{'uniquecode'}) eq 'HASH') { if ($domconfig{'requestcourses'}{'uniquecode'}{$crstype}) { @@ -1639,7 +1634,8 @@ sub course_creation { $code = $$coderef; } $postprocess = &Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,$result,$ownername, - $ownerdom,$fullname,$coursedesc,$code,$customhash); + $ownerdom,$fullname,$coursedesc,$code, + $accessstart,$accessend,$customhash); } else { $result = 'error: '.$cid; } @@ -1668,6 +1664,8 @@ sub build_batchcreatehash { $batchhash{'authparam'} = $domdefs->{'auth_arg_def'}; if ($details->{'crstype'} eq 'community') { $batchhash{'crstype'} = 'Community'; + } elsif ($details->{'crstype'} eq 'placement') { + $batchhash{'crstype'} = 'Placement'; } else { if ($details->{'crstype'} eq 'textbook') { if ($details->{'clonecrs'} && $details->{'clonedom'}) { @@ -1713,12 +1711,13 @@ sub build_batchcreatehash { $batchhash{'users'}{$owner}{lastname} = $owner_lastname; $batchhash{'users'}{$owner}{emailenc} = $emailenc; $batchhash{'users'}{$owner}{owneremail} = $owneremail; + $batchhash{'setcomment'} = 1; } return %batchhash; } sub can_clone_course { - my ($uname,$udom,$clonecrs,$clonedom,$crstype) = @_; + my ($uname,$udom,$clonecrs,$clonedom,$crstype,$dom,$instcode) = @_; my $canclone; my $ccrole = 'cc'; if ($crstype eq 'community') { @@ -1729,19 +1728,70 @@ sub can_clone_course { if (exists($roleshash{$clonecrs.':'.$clonedom.':'.$ccrole})) { $canclone = 1; } else { - my %courseenv = &Apache::lonnet::userenvironment($clonedom,$clonecrs,('cloners')); + my %courseenv = &Apache::lonnet::userenvironment($clonedom,$clonecrs, + ('cloners','internal.coursecode')); my $cloners = $courseenv{'cloners'}; + my $clonefromcode = $courseenv{'internal.coursecode'}; if ($cloners ne '') { my @cloneable = split(',',$cloners); if (grep(/^\*$/,@cloneable)) { $canclone = 1; - } - if (grep(/^\*:\Q$udom\E$/,@cloneable)) { + } elsif (grep(/^\*:\Q$udom\E$/,@cloneable)) { $canclone = 1; - } - if (grep(/^\Q$uname\E:\Q$udom\E$/,@cloneable)) { + } elsif (grep(/^\Q$uname\E:\Q$udom\E$/,@cloneable)) { $canclone = 1; } + unless ($canclone) { + if (($clonefromcode) && ($instcode) && ($clonedom eq $dom)) { + my (%gotdomdefaults,%gotcodedefaults); + foreach my $cloner (@cloneable) { + if (($cloner ne '*') && ($cloner !~ /^\*\:$match_domain$/) && + ($cloner !~ /^$match_username\:$match_domain$/) && ($cloner ne '')) { + if ($cloner =~ /\=/) { + my (%codedefaults,@code_order); + if (ref($gotcodedefaults{$clonedom}) eq 'HASH') { + if (ref($gotcodedefaults{$clonedom}{'defaults'}) eq 'HASH') { + %codedefaults = %{$gotcodedefaults{$clonedom}{'defaults'}}; + } + if (ref($gotcodedefaults{$clonedom}{'order'}) eq 'ARRAY') { + @code_order = @{$gotcodedefaults{$dom}{'order'}}; + } + } else { + &Apache::lonnet::auto_instcode_defaults($clonedom, + \%codedefaults, + \@code_order); + $gotcodedefaults{$clonedom}{'defaults'} = \%codedefaults; + $gotcodedefaults{$clonedom}{'order'} = \@code_order; + } + if (@code_order > 0) { + if (&Apache::lonnet::check_instcode_cloning(\%codedefaults,\@code_order, + $cloner,$clonefromcode,$instcode)) { + $canclone = 1; + last; + } + } + } + } + } + } + } + } else { + my %domdefs = &Apache::lonnet::get_domain_defaults($clonedom); + if ($domdefs{'canclone'}) { + unless ($domdefs{'canclone'} eq 'none') { + if ($domdefs{'canclone'} eq 'domain') { + if ($udom eq $clonedom) { + $canclone = 1; + } + } elsif (($clonefromcode) && ($instcode) && + ($clonedom eq $dom)) { + if (&Apache::lonnet::default_instcode_cloning($clonedom,$domdefs{'canclone'}, + $clonefromcode,$instcode)) { + $canclone = 1; + } + } + } + } } unless ($canclone) { if (&Apache::lonnet::is_course_owner($clonedom,$clonecrs,$uname,$udom)) { @@ -2023,6 +2073,9 @@ sub process_official_reqs { } } } + if ($history{'details'}{'clonecrs'}) { + $customitems{'_LC_clonefrom'} = $history{'details'}{'clonedom'}.'_'.$history{'details'}{'clonecrs'}; + } my ($result,$postprocess) = &course_creation($dom,$cnum,'domain',$history{'details'},\$logmsg,\$newusermsg,\$addresult, \$enrollcount,\$response,\$keysmsg,\%domdefs,\%longroles,\$code,\%customitems); @@ -2032,7 +2085,7 @@ sub process_official_reqs { my $cid = $dom.'_'.$cnum; push(@{$newcids{$instcode}},$cid); if ($dcname && $dcdom) { - my $firsturl = &course_portal_url($cnum,$dom); + my $firsturl = &Apache::lonnet::course_portal_url($cnum,$dom); my $beneficiary = 'pendingrequestor'; my $now = time; my $owner = $ownername.':'.$ownerdom; @@ -2059,6 +2112,11 @@ sub process_official_reqs { } } } + if (ref($postprocess->{'createdactions'}) eq 'HASH') { + if (ref($postprocess->{'createdactions'}{'environment'}) eq 'HASH') { + &postprocess_crsenv($dom,$cnum,$postprocess->{'createdactions'}{'environment'}); + } + } } &send_selfserve_notification($owner,$approvedmsg, $cid,$cdescr,$now, @@ -2130,6 +2188,56 @@ sub process_official_reqs { return $output; } +sub postprocess_crsenv { + my ($dom,$cnum,$postprocessenv) = @_; + if (ref($postprocessenv) eq 'HASH') { + my $cid = $dom.'_'.$cnum; + my %settablecrsenv = ( + 'internal.selfenroll_types' => 1, + 'internal.selfenroll_registered' => 1, + 'internal.selfenroll_section' => 1, + 'internal.selfenroll_start_access' => 1, + 'internal.selfenroll_end_access' => 1, + 'internal.selfenroll_limit' => 1, + 'internal.selfenroll_cap' => 1, + 'internal.selfenroll_approval' => 1, + 'internal.selfenroll_notifylist' => 1, + ); + my %needcrsidput = ( + 'internal.selfenroll_types' => 1, + 'internal.selfenroll_start_date' => 1, + 'internal. selfenroll_end_date' => 1, + ); + my (@needupdate,%newcrsenv); + foreach my $key (keys(%{$postprocessenv})) { + if ($settablecrsenv{$key}) { + $newcrsenv{$key} = $postprocessenv->{$key}; + if ($needcrsidput{$key}) { + push(@needupdate,$key); + } + } + if (keys(%newcrsenv)) { + my $putresult = &Apache::lonnet::put('environment',\%newcrsenv,$dom,$cnum); + if ($putresult eq 'ok') { + if (@needupdate) { + my %crsinfo = + &Apache::lonnet::courseiddump($dom,'.',1,'.','.',$cnum,undef,undef,'.'); + if (ref($crsinfo{$cid}) eq 'HASH') { + foreach my $key (@needupdate) { + $crsinfo{$cid}{$key} = $newcrsenv{$key}; + } + my $chome = &Apache::lonnet::homeserver($cnum,$dom); + &Apache::lonnet::courseidput($dom,\%crsinfo,$chome,'notime'); + } + } + } + } + } + } + return; +} + + sub requestcourses_validation_types { my @items = ('url','fields','button','markup'); my %names = &Apache::lonlocal::texthash (