# The LearningOnline Network # Request a course # # $Id: lonrequestcourse.pm,v 1.87 2015/05/21 23:40:09 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/ # ### =head1 NAME Apache::lonrequestcourse.pm =head1 SYNOPSIS Allows users to request creation of new courses. This is part of the LearningOnline Network with CAPA project described at http://www.lon-capa.org. =head1 SUBROUTINES =over =item handler() =item get_breadcrumbs() =item header() =item form_elements() =item onload_action() =item print_main_menu() =item request_administration() =item close_popup_form() =item get_instcode() =item print_request_form() =item print_enrollment_menu() =item show_invalid_crosslists() =item inst_section_selector() =item date_setting_table() =item print_personnel_menu() =item print_request_status() =item print_request_logs() =item print_review() =item dates_from_form() =item courseinfo_form() =item clone_form() =item clone_text() =item coursecode_form() =item get_course_dom() =item display_navbuttons() =item print_request_outcome() =item check_autolimit() =item retrieve_settings() =item get_request_settings() =item extract_instcode() =item generate_date_items() =back =cut package Apache::lonrequestcourse; use strict; use Apache::Constants qw(:common :http); use Apache::lonnet; use Apache::loncommon; use Apache::lonlocal; use Apache::loncoursequeueadmin; use Apache::lonuserutils; use LONCAPA qw(:DEFAULT :match); sub handler { my ($r) = @_; &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; if ($r->header_only) { return OK; } &Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'}, ['action','showdom','cnum','state','crstype','queue','tabs']); &Apache::lonhtmlcommon::clear_breadcrumbs(); my $dom = &get_course_dom(); my $action = $env{'form.action'}; my $state = $env{'form.state'}; my (%states,%stored); my ($jscript,$uname,$udom,$result,$warning,$showcredits,$instcredits,%can_request, %request_domains,@incdoms); my %domdefs = &Apache::lonnet::get_domain_defaults($dom); if ($domdefs{'officialcredits'} || $domdefs{'unofficialcredits'} || $domdefs{'textbookcredits'}) { $showcredits = 1; } my $canreq = &Apache::lonnet::check_can_request($dom,\%can_request,\%request_domains); foreach my $item (keys(%request_domains)) { if (ref($request_domains{$item}) eq 'ARRAY') { foreach my $possdom (@{$request_domains{$item}}) { unless(grep(/^\Q$possdom\E$/,@incdoms)) { push(@incdoms,$possdom); } } } } if ($canreq) { if (($env{'form.crstype'} eq 'textbook') || (scalar(keys(%can_request)) == 1) && ($can_request{'textbook'})) { my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$dom); if ($action eq 'log') { my $usetabs; if ((scalar(keys(%can_request)) == 1) && ($can_request{'textbook'})) { $usetabs = 1; } elsif ($env{'form.tabs'} eq 'on') { $usetabs = 1; } &Apache::lonhtmlcommon::add_breadcrumb({text=>'Course Request'}); my $crumb = &Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests'); &print_request_logs($r,$dom,undef,undef,$crumb,$usetabs); } elsif ($action eq 'process') { if ($can_request{'textbook'}) { &process_textbook_request($r,$dom,$action,\%domdefs,\%domconfig,\%can_request); } else { &textbook_request_disabled($r,$dom,$action,\%can_request); } } elsif ($action eq 'display') { my ($uname,$udom,$result,$warning) = &domcoord_display($dom); if ($warning ne '') { my $args = { only_body => 1 }; $r->print(&header('Course/Community Requests','','' ,'',$args). '

'.&mt('Course/Community Request Details').'

'. '
'.$warning.'
'. &close_popup_form()); } else { $states{'display'} = ['details']; my $loaditems = &onload_action($action,$state); my $page = 0; &request_administration($r,$action,$state,$page,\%states,$dom,$jscript, $loaditems,'','','','','',$showcredits,'','', $uname,$udom); } } else { if ($can_request{'textbook'}) { &print_textbook_form($r,$dom,\@incdoms,\%domdefs,$domconfig{'requestcourses'},\%can_request); } else { &textbook_request_disabled($r,$dom,$action,\%can_request); } } return OK; } } $states{'display'} = ['details']; $states{'view'} = ['pick_request','details','cancel','removal']; $states{'log'} = ['display']; $states{'new'} = ['courseinfo','enrollment','personnel','review','process']; if (($action eq 'new') && ($env{'form.crstype'} eq 'official')) { unless ($env{'form.state'} eq 'crstype') { unshift(@{$states{'new'}},'codepick'); } } if (($action eq 'new') && (&Apache::loncoursequeueadmin::author_prompt())) { if (ref($states{$action}) eq 'ARRAY') { push(@{$states{$action}},'reqauthor'); } } foreach my $key (keys(%states)) { if (ref($states{$key}) eq 'ARRAY') { unshift (@{$states{$key}},'crstype'); } } my @invalidcrosslist; my %trail = ( crstype => 'Pick Action', codepick => 'Category', courseinfo => 'Description', enrollment => 'Access Dates', personnel => 'Personnel', review => 'Review', process => 'Result', reqauthor => 'Authoring Space Result', pick_request => 'Display Summary', details => 'Request Details', cancel => 'Cancel Request', removal => 'Outcome', display => 'Request Logs', ); if (($env{'form.crstype'} eq 'official') && (&Apache::lonnet::auto_run('',$dom))) { $trail{'enrollment'} = 'Enrollment'; } my ($page,$crumb,$newinstcode,$codechk,$checkedcode,$description) = &get_breadcrumbs($dom,$action,\$state,\%states,\%trail); if ($action eq 'display') { ($uname,$udom,$result,$warning) = &domcoord_display($dom); } elsif ((defined($state)) && (defined($action))) { if (($action eq 'view') && ($state eq 'details')) { if ((defined($env{'form.showdom'})) && (defined($env{'form.cnum'}))) { my $result = &retrieve_settings($env{'form.showdom'},$env{'form.cnum'}); } } elsif ($env{'form.crstype'} eq 'official') { if (&Apache::lonnet::auto_run('',$dom)) { if (($action eq 'new') && (($state eq 'enrollment') || ($state eq 'personnel'))) { my $checkcrosslist = 0; for (my $i=0; $i<$env{'form.crosslisttotal'}; $i++) { if ($env{'form.crosslist_'.$i}) { $checkcrosslist ++; } } if ($checkcrosslist) { my %codechk; my (@codetitles,%cat_titles,%cat_order,@code_order,$lastitem); &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles, \%cat_titles, \%cat_order, \@code_order); my $numtitles = scalar(@codetitles); if ($numtitles) { for (my $i=0; $i<$env{'form.crosslisttotal'}; $i++) { if ($env{'form.crosslist_'.$i}) { my $codecheck; my $crosslistcode = ''; foreach my $item (@code_order) { $crosslistcode .= $env{'form.crosslist_'.$i.'_'.$item}; } if ($crosslistcode ne '') { ($codechk{$i}, my $rest) = &Apache::lonnet::auto_validate_instcode('',$dom,$crosslistcode); } unless ($codechk{$i} eq 'valid') { $env{'form.crosslist_'.$i} = ''; push(@invalidcrosslist,$crosslistcode); } } } } } } } } (my $elements,$instcredits) = &form_elements($dom,$showcredits); my $elementsref = {}; if ((ref($elements) eq 'HASH') && (ref($elements->{$action}) eq 'HASH')) { if (ref($elements->{$action}{$state}) eq 'HASH') { $elementsref = $elements->{$action}{$state}; } } if (($state eq 'courseinfo') && ($env{'form.clonedom'} eq '')) { $env{'form.clonedom'} = $dom; } if ($state eq 'crstype') { $jscript = &mainmenu_javascript(); } else { $jscript = &Apache::lonhtmlcommon::set_form_elements($elementsref,\%stored); if ($state eq 'courseinfo') { $jscript .= &cloning_javascript(); } elsif ($state eq 'process') { $jscript .= &processing_javascript(); } } } if ($state eq 'personnel') { $jscript .= "\n".&Apache::loncommon::userbrowser_javascript(); } my $loaditems = &onload_action($action,$state); if ($action eq 'new') { if ($canreq) { if ($state eq 'crstype') { &print_main_menu($r,\%can_request,\%states,$dom,$jscript,$loaditems, $crumb,\@incdoms); } else { &request_administration($r,$action,$state,$page,\%states,$dom, $jscript,$loaditems,$crumb,$newinstcode, $codechk,$checkedcode,$description, $showcredits,$instcredits,\@invalidcrosslist); } } else { $r->print(&header('Course/Community Requests').$crumb. '
'. &mt('You do not have privileges to request creation of courses or communities.'). '
'.&Apache::loncommon::end_page()); } } elsif ($action eq 'view') { if ($state eq 'crstype') { &print_main_menu($r,\%can_request,\%states,$dom,$jscript,$loaditems,$crumb,\@incdoms); } else { &request_administration($r,$action,$state,$page,\%states,$dom,$jscript, $loaditems,$crumb,'','','','',$showcredits); } } elsif ($action eq 'display') { if ($warning ne '') { my $args = { only_body => 1 }; $r->print(&header('Course/Community Requests','','' ,'',$args).$crumb. '

'.&mt('Course/Community Request Details').'

'. '
'.$warning.'
'. &close_popup_form()); } else { &request_administration($r,$action,$state,$page,\%states,$dom,$jscript, $loaditems,$crumb,'','','','',$showcredits,'','', $uname,$udom); } } elsif ($action eq 'log') { if ($state eq 'crstype') { &print_main_menu($r,\%can_request,\%states,$dom,$jscript,'',$crumb,\@incdoms); } else { $jscript .= < 1) { for (var i=0; i{$action}) eq 'ARRAY') { while ($i<@{$states->{$action}} && !$done) { if ($states->{$action}[$i] eq $$state) { $page = $i; $done = 1; } $i++; } } if ($env{'form.crstype'} eq 'official') { if ($page > 1) { if ($states->{$action}[$page-1] eq 'codepick') { if ($env{'form.instcode'} eq '') { ($newinstcode,$numtitles) = &get_instcode($dom); if ($numtitles) { if ($newinstcode eq '') { $$state = 'codepick'; $page --; } else { ($codechk,$description) = &Apache::lonnet::auto_validate_instcode('', $dom,$newinstcode); if ($codechk ne 'valid') { $$state = 'codepick'; $page --; } $checkedcode = 1; } } } } } } if (ref($states->{$action}) eq 'ARRAY') { for (my $i=0; $i<@{$states->{$action}}; $i++) { if ($$state eq $states->{$action}[$i]) { &Apache::lonhtmlcommon::add_breadcrumb( {text=>"$trail->{$$state}"}); $crumb = &Apache::lonhtmlcommon::breadcrumbs('Course/Community Requests','Course_Requests'); last; } else { if (($$state eq 'process') || ($$state eq 'removal') || ($$state eq 'reqauthor')) { &Apache::lonhtmlcommon::add_breadcrumb( { href => '/adm/requestcourse', text => "$trail->{$states->{$action}[$i]}", } ); } else { &Apache::lonhtmlcommon::add_breadcrumb( { href => "javascript:backPage(document.requestcrs,'$states->{$action}[$i]')", text => "$trail->{$states->{$action}[$i]}", } ); } } } } } else { &Apache::lonhtmlcommon::add_breadcrumb( {text=>'Pick Action'}); $crumb = &Apache::lonhtmlcommon::breadcrumbs('Course/Community Requests','Course_Requests'); } } else { &Apache::lonhtmlcommon::add_breadcrumb( {text=>'Pick Action'}); $crumb = &Apache::lonhtmlcommon::breadcrumbs('Course/Community Requests','Course_Requests'); } return ($page,$crumb,$newinstcode,$codechk,$checkedcode,$description); } sub header { my ($bodytitle,$jscript,$loaditems,$jsextra,$args) = @_; if ($jscript) { $jscript = ''."\n"; } if ($loaditems) { if (ref($args) eq 'HASH') { my %loadhash = ( 'add_entries' => $loaditems, ); my %arghash = (%loadhash,%{$args}); $args = \%arghash; } else { $args = {'add_entries' => $loaditems,}; } } return &Apache::loncommon::start_page($bodytitle,$jscript.$jsextra,$args); } sub form_elements { my ($dom,$showcredits) = @_; my $instcredits; my %elements = ( new => { crstype => { crstype => 'selectbox', action => 'selectbox', origcnum => 'hidden', }, courseinfo => { cdescr => 'text', cloning => 'radio', clonecrs => 'text', clonedom => 'selectbox', datemode => 'radio', dateshift => 'text', }, enrollment => { accessstart_month => 'selectbox', accessstart_hour => 'selectbox', accessend_month => 'selectbox', accessend_hour => 'selectbox', accessstart_day => 'text', accessstart_year => 'text', accessstart_minute => 'text', accessstart_second => 'text', accessend_day => 'text', accessend_year => 'text', accessend_minute => 'text', accessend_second => 'text', no_end_date => 'checkbox', }, personnel => { addperson => 'checkbox', }, review => { cnum => 'hidden', }, }, view => { crstype => { crstype => 'selectbox', action => 'selectbox', }, }, ); my %servers = &Apache::lonnet::get_servers($dom,'library'); my $numlib = keys(%servers); if ($numlib > 1) { $elements{'new'}{'courseinfo'}{'chome'} = 'selectbox'; } else { $elements{'new'}{'courseinfo'}{'chome'} = 'hidden'; } my (@codetitles,%cat_titles,%cat_order,@code_order,$lastitem); &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, \%cat_order,\@code_order); my $numtitles = scalar(@codetitles); if ($numtitles) { my %extras; $lastitem = pop(@codetitles); $extras{'instcode_'.$lastitem} = 'text'; foreach my $item (@codetitles) { $extras{'instcode_'.$item} = 'selectbox'; } $elements{'new'}{'codepick'} = \%extras; } if (&Apache::lonnet::auto_run('',$dom)) { my %extras = ( enrollstart_month => 'selectbox', enrollstart_hour => 'selectbox', enrollend_month => 'selectbox', enrollend_hour => 'selectbox', enrollstart_day => 'text', enrollstart_year => 'text', enrollstart_minute => 'text', enrollstart_second => 'text', enrollend_day => 'text', enrollend_year => 'text', enrollend_minute => 'text', enrollend_second => 'text', addcrosslist => 'checkbox', autoadds => 'radio', autodrops => 'radio', ); my ($instcode,$titlescount) = &get_instcode($dom); if ($instcode) { my @sections = &Apache::lonnet::auto_get_sections(undef,$dom,$instcode); if (@sections) { $extras{'sectotal'} = 'hidden'; if ($env{'form.sectotal'} > 0) { for (my $i=0; $i<$env{'form.sectotal'}; $i++) { $extras{'sec_'.$i} = 'radio'; $extras{'secnum_'.$i} = 'text'; $extras{'loncapasec_'.$i} = 'text'; } } } else { $extras{'addsection'} = 'checkbox'; my $sectotal = $env{'form.sectotal'}; if ($env{'form.addsection'}) { $sectotal ++; } for (my $i=0; $i<$sectotal; $i++) { $extras{'sec_'.$i} = 'checkbox'; $extras{'secnum_'.$i} = 'text', $extras{'loncapasec_'.$i} = 'text', } } (my $outcome,my $desc,$instcredits) = &Apache::lonnet::auto_validate_instcode(undef,$dom,$instcode); if ($showcredits && $instcredits eq '') { $extras{'coursecredits'} = 'text'; } } elsif (($env{'form.crstype'} eq 'unofficial') || ($env{'form.crstype'} eq 'textbook')) { if ($showcredits) { $extras{'coursecredits'} = 'text'; } } my $crosslisttotal = $env{'form.crosslisttotal'}; if ($env{'form.addcrosslist'}) { $crosslisttotal ++; } if (!$crosslisttotal) { $crosslisttotal = 1; } for (my $i=0; $i<$env{'form.crosslisttotal'}; $i++) { if ($numtitles) { $extras{'crosslist_'.$i.'_'.$lastitem} = 'text'; } if (@codetitles > 0) { foreach my $item (@codetitles) { $extras{'crosslist_'.$i.'_'.$item} = 'selectbox'; } } $extras{'crosslist_'.$i} = 'checkbox'; $extras{'crosslist_'.$i.'_instsec'} = 'text', $extras{'crosslist_'.$i.'_lcsec'} = 'text', } my %mergedhash = (%{$elements{'new'}{'enrollment'}},%extras); %{$elements{'new'}{'enrollment'}} = %mergedhash; } my %people; my $persontotal = $env{'form.persontotal'}; if ($env{'form.addperson'}) { $persontotal ++; } if ((!defined($persontotal)) || (!$persontotal)) { $persontotal = 1; } for (my $i=0; $i<$persontotal; $i++) { $people{'person_'.$i.'_uname'} = 'text', $people{'person_'.$i.'_dom'} = 'selectbox', $people{'person_'.$i.'_hidedom'} = 'hidden', $people{'person_'.$i.'_firstname'} = 'text', $people{'person_'.$i.'_lastname'} = 'text', $people{'person_'.$i.'_emailaddr'} = 'text', $people{'person_'.$i.'_role'} = 'selectbox', $people{'person_'.$i.'_sec'} = 'selectbox', $people{'person_'.$i.'_newsec'} = 'text', } my %personnelhash = (%{$elements{'new'}{'personnel'}},%people); %{$elements{'new'}{'personnel'}} = %personnelhash; return (\%elements,$instcredits);; } sub onload_action { my ($action,$state) = @_; my %loaditems; if (($action eq 'new') || ($action eq 'view')) { if ($state eq 'crstype') { $loaditems{'onload'} = 'javascript:setAction(document.mainmenu_action);javascript:setType(document.mainmenu_coursetype)'; } else { $loaditems{'onload'} = 'javascript:setFormElements(document.requestcrs);'; } if ($state eq 'courseinfo') { $loaditems{'onload'} .= 'javascript:setCloneDisplay(document.requestcrs);'; } if ($state eq 'process') { $loaditems{'onload'} .= 'javascript:hideProcessing();'; } } return \%loaditems; } sub print_main_menu { my ($r,$can_request,$states,$dom,$jscript,$loaditems,$crumb,$incdoms) = @_; my ($types,$typename) = &Apache::loncommon::course_types(); my $onchange = 'this.form.submit()'; my $nextstate_setter = "\n"; if (ref($states) eq 'HASH') { foreach my $key (keys(%{$states})) { if (ref($states->{$key}) eq 'ARRAY') { $nextstate_setter .= " if (actionchoice == '$key') { nextstate = '".$states->{$key}[1]."'; } "; } } } my $js = <<"END"; function nextPage(formname) { var crschoice = document.mainmenu_coursetype.crstype.value; var actionchoice = document.mainmenu_action.action.value; if (check_can_request(crschoice,actionchoice) == true) { if ((actionchoice == 'new') && (crschoice == 'official')) { nextstate = 'codepick'; } else { $nextstate_setter } formname.crstype.value = crschoice; formname.action.value = actionchoice; formname.state.value= nextstate; formname.submit(); } return; } function check_can_request(crschoice,actionchoice) { var official = ''; var unofficial = ''; var community = ''; var textbook = ''; END if (ref($can_request) eq 'HASH') { foreach my $item (keys(%{$can_request})) { $js .= " $item = 1; "; } } my %lt = &Apache::lonlocal::texthash( official => 'You are not permitted to request creation of an official course in this domain.', unofficial => 'You are not permitted to request creation of an unofficial course in this domain.', community => 'You are not permitted to request creation of a community in this domain.', textbook => 'You are not permitted to request creation of a textbook course in this domain', all => 'You must choose a specific course type when making a new course request.', allt => '"All types" is not allowed.', ); $js .= <{'official'}) || ($can_request->{'unofficial'}) || $can_request->{'textbook'}) { if ($can_request->{'community'}) { $pagetitle = 'Course/Community Requests'; $pageinfo = &mt('Request creation of a new course or community, or review your pending requests.'); $domaintitle = &mt('Course/Community Domain'); } else { $pagetitle = 'Course Requests'; $pageinfo = &mt('Request creation of a new course, or review your pending course requests.'); $domaintitle = &mt('Course Domain'); } } elsif ($can_request->{'community'}) { $pagetitle = 'Community Requests'; $pageinfo = &mt('Request creation of a new course, or review your pending requests.'); $domaintitle = &mt('Community Domain'); } elsif ((ref($incdoms) eq 'ARRAY') && ((@{$incdoms} > 1) || ((@{$incdoms} == 1) && ($incdoms->[0] ne $dom)))) { $pagetitle = 'Course/Community Requests'; $pageinfo = &mt('You do not have rights to request creation of courses in this domain; please choose a different domain.'); $domaintitle = &mt('Course/Community Domain'); } else { $pagetitle = 'Course/Community Requests'; $pageinfo = &mt('You do not have rights to request creation of courses or communities.'); $earlyout = 1; } } $r->print(&header($pagetitle,$js.$jscript,$loaditems).$crumb. '

'.$pageinfo.'

'); if ($earlyout) { $r->print(&Apache::loncommon::end_page()); return; } $r->print('
'. &Apache::lonhtmlcommon::start_pick_box(). &Apache::lonhtmlcommon::row_title($domaintitle). '
'. &Apache::loncommon::select_dom_form($dom,'showdom','',1,$onchange,$incdoms)); if (!$onchange) { $r->print(' '); } unless ((ref($can_request) eq 'HASH') && (keys(%{$can_request}) > 0)) { $r->print('
'.&Apache::lonhtmlcommon::row_closure(1)."\n". &Apache::lonhtmlcommon::end_pick_box().'
'."\n". &Apache::loncommon::end_page()); return; } $r->print(''.&Apache::lonhtmlcommon::row_closure()); my $formname = 'requestcrs'; my $nexttext = &mt('Next'); $r->print(&Apache::lonhtmlcommon::row_title(&mt('Action')).'
'. &Apache::lonhtmlcommon::row_closure(). &Apache::lonhtmlcommon::row_title(&mt('Type')).'
'."\n". &Apache::lonhtmlcommon::row_closure(1)."\n". &Apache::lonhtmlcommon::end_pick_box().''."\n". '
'."\n". ''."\n". ''."\n". ''."\n". ''."\n". ''."\n". '
'); $r->print(&Apache::loncommon::end_page()); return; } sub request_administration { my ($r,$action,$state,$page,$states,$dom,$jscript,$loaditems,$crumb, $newinstcode,$codechk,$checkedcode,$description,$showcredits, $instcredits,$invalidcrosslist,$uname,$udom) = @_; my $js; if (($action eq 'new') || (($action eq 'view') && ($state eq 'pick_request'))) { $js = <print(&header($title,$js.$jscript,$loaditems,$jsextra).$crumb); &print_request_form($r,$action,$state,$page,$states,$dom,$newinstcode, $codechk,$checkedcode,$description,$showcredits, $instcredits,$invalidcrosslist); } elsif ($action eq 'view') { my $jsextra; my $formname = 'requestcrs'; my $prev = $states->{$action}[$page-1]; my $next = $states->{$action}[$page+1]; if ($state eq 'pick_request') { $next = $states->{$action}[$page+1]; $jsextra = &viewrequest_javascript($formname,$next); } elsif ($state eq 'details') { $jsextra = &viewdetails_javascript($formname); } elsif ($state eq 'cancel') { $jsextra = &viewcancel_javascript($formname); } my $title; if ($env{'form.crstype'} eq 'community') { $title = 'Manage community requests'; } else { $title = 'Manage course requests'; } $r->print(&header($title,$js.$jscript.$jsextra,$loaditems).$crumb); my $form = '
'; if ($state eq 'pick_request') { my $title; if ($env{'form.crstype'} eq 'community') { $title = &mt('Pending community requests'); } elsif ($env{'form.crstype'} eq 'official') { $title = &mt('Pending requests for official courses'); } elsif ($env{'form.crstype'} eq 'unofficial') { $title = &mt('Pending requests for unofficial courses'); } elsif ($env{'form.crstype'} eq 'textbook') { $title = &mt('Pending requests for textbook courses'); } else { $title = &mt('Pending course/community requests'); } $r->print('

'.$title.'

'."\n".$form."\n". &print_request_status($dom,$action).'
'); } elsif ($state eq 'details') { my (@codetitles,%cat_titles,%cat_order,@code_order,$instcode,$code_chk); my $origcnum = $env{'form.cnum'}; if ($origcnum eq '') { $origcnum = $env{'form.origcnum'}; } if ($env{'form.crstype'} eq 'official') { &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, \%cat_order,\@code_order); } my $title; if ($env{'form.crstype'} eq 'community') { $title = &mt('Community Request Details'); } else { $title = &mt('Course Request Details'); } $r->print('

'.$title.'

'."\n".$form."\n". &print_review($dom,\@codetitles,\%cat_titles,\%cat_order, \@code_order,'','','','',$instcredits)."\n". ''."\n"); my @excluded = &get_excluded_elements($dom,$states,'new','review', $showcredits); push(@excluded,'origcnum'); $r->print(&Apache::lonhtmlcommon::echo_form_input(\@excluded).'
'); my $other = 'modify'; my %navtxt = &Apache::lonlocal::texthash ( prev => 'Back', other => 'Modify Request', next => 'Cancel Request', ); &display_navbuttons($r,$dom,$formname,$prev,$navtxt{'prev'},$next, $navtxt{'next'},$state,$other,$navtxt{'other'}); $r->print(''); } elsif ($state eq 'cancel') { my $title; if ($env{'form.crstype'} eq 'community') { $title = &mt('Cancel community request'); } else { $title = &mt('Cancel course request'); } my ($result,$output) = &print_cancel_request($dom,$env{'form.origcnum'}); $r->print('

'.$title.'

'."\n".$form."\n". $output); my @excluded = &get_excluded_elements($dom,$states,'view','cancel', $showcredits); $r->print(&Apache::lonhtmlcommon::echo_form_input(\@excluded).'
'); my %navtxt = &Apache::lonlocal::texthash ( prev => 'Back', next => 'Confirm Cancellation', ); if ($result eq 'ok') { &display_navbuttons($r,$dom,$formname,$prev,$navtxt{'prev'},$next, $navtxt{'next'},$state); } else { &display_navbuttons($r,$dom,$formname,$prev,$navtxt{'prev'},undef, '',$state); } $r->print(''); } elsif ($state eq 'removal') { my $cnum = $env{'form.origcnum'}; my $statuskey = 'status:'.$dom.':'.$cnum; my %userreqhash = &Apache::lonnet::get('courserequests',[$statuskey], $env{'user.domain'},$env{'user.name'}); my $currstatus = $userreqhash{$statuskey}; my ($result,$error); if (($currstatus eq 'approval') || ($currstatus eq 'pending')) { my %status = ( $statuskey => 'cancelled', ); my $statusresult = &Apache::lonnet::put('courserequests',\%status); if ($statusresult eq 'ok') { my $delresult = &Apache::lonnet::del_dom('courserequestqueue', [$cnum.'_'.$currstatus],$dom); if ($delresult eq 'ok') { $result = 'ok'; } else { $error = &mt('An error occurred when updating the pending requests queue: [_1]',$delresult); } } else { $error = &mt("An error occurred when updating the status of this request in the requestor's records: [_1]",$statusresult); } } else { $error = &mt('The current status of this request could not be verified as pending approval/institutional action.'); } $r->print('

'.&mt('Request Cancellation').'

'."\n".$form."\n". ''."\n". ''."\n". ''."\n". ''."\n"); if ($result eq 'ok') { if ($env{'form.crstype'} eq 'community') { $r->print(&mt('Your community request has been cancelled.')); } else { $r->print(&mt('Your course request has been cancelled.')); } } else { $r->print('
'. &mt('The request cancellation process was not complete.'). '
'.$error.'
'); } $r->print(''); } } elsif ($action eq 'display') { my $formname = 'requestcrs'; my (@codetitles,%cat_titles,%cat_order,@code_order,$instcode,$code_chk); if ($env{'form.crstype'} eq 'official') { &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, \%cat_order,\@code_order); } my ($title,$header); if ($env{'form.crstype'} eq 'community') { $title = 'Community Request'; $header = &mt('Community Request'); } else { $title = 'Course Request'; $header = &mt('Course Request'); } $r->print(&header($title,'','','',{ 'only_body' => 1}). $crumb."\n".'

'.$header.'

'. &print_review($dom,\@codetitles,\%cat_titles,\%cat_order, \@code_order,$uname,$udom,'','',$instcredits)."\n". '
'. &close_popup_form()); } $r->print(&Apache::loncommon::end_page()); return; } sub domcoord_display { my ($dom) = @_; my ($uname,$udom,$result,$warning); if (($dom eq $env{'request.role.domain'}) && (&Apache::lonnet::allowed('ccc',$dom))) { if ($env{'form.cnum'} ne '') { my $cnum = $env{'form.cnum'}; my $queue = $env{'form.queue'}; my $reqkey = $cnum.'_'.$queue; my $namespace = 'courserequestqueue'; my $domconfig = &Apache::lonnet::get_domainconfiguser($dom); my %queued = &Apache::lonnet::get($namespace,[$reqkey],$dom,$domconfig); if (ref($queued{$reqkey}) eq 'HASH') { $uname = $queued{$reqkey}{'ownername'}; $udom = $queued{$reqkey}{'ownerdom'}; if (($udom =~ /^$match_domain$/) && ($uname =~ /^$match_username$/)) { $result = &retrieve_settings($dom,$cnum,$udom,$uname); } else { if ($env{'form.crstype'} eq 'community') { $warning = &mt('Invalid username or domain for community requestor'); } else { $warning = &mt('Invalid username or domain for course requestor'); } } } else { if ($env{'form.crstype'} eq 'community') { $warning = &mt('No information was found for this community request.'); } else { $warning = &mt('No information was found for this course request.'); } } } else { $warning = &mt('No course request ID provided.'); } } else { if ($env{'form.crstype'} eq 'any') { $warning = &mt('You do not have rights to view course or community request information.'); } elsif ($env{'form.crstype'} eq 'community') { $warning = &mt('You do not have rights to view community request information.'); } else { $warning = &mt('You do not have rights to view course request information.'); } } return ($uname,$udom,$result,$warning); } sub enrollment_lcsec_js { my %alerts = §ion_check_alerts(); my $secname = $alerts{'badsec'}; my $secnone = $alerts{'reserved'}; my $output = ' function validateEnrollSections(formname,nextstate) { var badsectotal = 0; var reservedtotal = 0; var secTest = ""; '; for (my $i=0; $i<$env{'form.sectotal'}; $i++) { $output .= " var selSec = 0; for (var j=0; j "You need to change one or more LON-CAPA section names - none is a reserved word in the system, and may not be used.", badsec => 'You need to change one or more LON-CAPA section names - names may only contain letters or numbers.', separate => 'Separate multiple sections with a comma.' ); return %lt; } sub section_check_javascript { return <<"END"; function validsection(field,mult) { var str = field.value; var badsec=0; var reserved=0; if (window.RegExp) { var badsecnum=0; var reservednum=0; var pattern=/[^a-zA-Z0-9]/; str = str.replace(/(^\\s*)|(\\s*\$)/gi,""); str = str.replace(/[ ]{2,}/gi," "); if (mult == '1') { var sections = new Array(); sections = str.split(/\\s*[\\s,;:]\\s*/); var i; for (i=0; i 0) { return 'badsec'; } if (reservednum > 0) { return 'reserved'; } } return; } END } sub close_popup_form { my $close= &mt('Close Window'); return << "END";

END } sub get_instcode { my ($dom) = @_; my ($instcode,$numtitles); my (@codetitles,%cat_titles,%cat_order,@code_order,$instcode,$code_chk); &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, \%cat_order,\@code_order); $numtitles = scalar(@codetitles); if (@code_order > 0) { my $message; foreach my $item (@code_order) { $instcode .= $env{'form.instcode_'.$item}; } } return ($instcode,$numtitles); } sub print_request_form { my ($r,$action,$state,$page,$states,$dom,$newinstcode,$codechk,$checkedcode, $description,$showcredits,$instcredits,$invalidcrosslist) = @_; my $formname = 'requestcrs'; my ($next,$prev,$message,$output,$codepicker,$crstype); $prev = $states->{$action}[$page-1]; $next = $states->{$action}[$page+1]; my %navtxt = &Apache::lonlocal::texthash ( prev => 'Back', next => 'Next', ); $crstype = $env{'form.crstype'}; $r->print('
'); my (@codetitles,%cat_titles,%cat_order,@code_order,$instcode,$code_chk, @disallowed); if ($crstype eq 'official') { if ($env{'form.instcode'} ne '') { $instcode = $env{'form.instcode'}; } elsif ($newinstcode ne '') { $instcode = $newinstcode; } if ($checkedcode) { if ($codechk eq 'valid') { $message = '
'. &mt('The chosen course category [_1] is valid.',''. $instcode.''). '
'; } else { $message = '
'. &mt('No course was found matching your choice of institutional course category.'); if ($codechk ne '') { $message .= '
'.$codechk; } $message .= '
'; $prev = 'crstype'; } $r->print($message); } } if ($prev eq 'crstype') { if ($crstype eq 'official') { &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, \%cat_order,\@code_order); } if (@code_order > 0) { $codepicker = &coursecode_form($dom,'instcode',\@codetitles, \%cat_titles,\%cat_order); if ($codepicker) { $r->print(&mt('Specify the course to be created.'). '
'.&Apache::lonhtmlcommon::start_pick_box(). $codepicker. &Apache::lonhtmlcommon::end_pick_box().'
'); } else { $next = $states->{$action}[$page+2]; $r->print(&courseinfo_form($dom,$formname,$crstype,$next)); } } else { if ($crstype eq 'official') { $next = $states->{$action}[$page+2]; } $r->print(&courseinfo_form($dom,$formname,$crstype,$next)); } } elsif ($prev eq 'codepick') { if ($instcode eq '') { $prev = $states->{$action}[$page-2]; } $r->print(&courseinfo_form($dom,$formname,$crstype,$next,$description)); } elsif ($state eq 'enrollment') { if ($crstype eq 'official') { &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, \%cat_order,\@code_order); } $r->print(&print_enrollment_menu($formname,$instcode,$dom,\@codetitles, \%cat_titles,\%cat_order,\@code_order, $showcredits,$instcredits,$invalidcrosslist)); } elsif ($state eq 'personnel') { $r->print(&print_personnel_menu($dom,$formname,$crstype,$invalidcrosslist)); } elsif ($state eq 'review') { my (%alerts,%rulematch,%inst_results,%curr_rules,%got_rules,%disallowmsg); my $now = time; for (my $i=0; $i<$env{'form.persontotal'}; $i++) { my $personname = $env{'form.person_'.$i.'_uname'}; my $persondom = $env{'form.person_'.$i.'_dom'}; if (($personname =~ /^$match_username$/) && ($persondom =~ /^$match_domain$/)) { if (&Apache::lonnet::domain($persondom)) { my $personhome = &Apache::lonnet::homeserver($personname,$persondom); if ($personhome eq 'no_host') { if ($persondom ne $dom) { my $skipuser = 1; if ($env{'user.role.dc./'.$persondom.'/'}) { my ($start,$end) = split('.',$env{'user.role.dc./'.$persondom.'/'}); if (((!$start) || ($start < $now)) && ((!$end) || ($end > $now))) { $skipuser = 0; } } if ($skipuser) { push(@disallowed,$i); $disallowmsg{$i} = &mt('[_1] was excluded because new users need to be from the course domain',''.$personname.':'.$persondom.''); next; } } my $usertype = &get_usertype($persondom,$personname,\%curr_rules,\%got_rules); if (&Apache::lonuserutils::can_create_user($dom,'requestcrs',$usertype)) { my ($allowed,$msg,$authtype,$authparam) = &check_newuser_rules($persondom,$personname, \%alerts,\%rulematch,\%inst_results, \%curr_rules,\%got_rules); if ($allowed) { my %domdefaults = &Apache::lonnet::get_domain_defaults($persondom); if ($usertype eq 'official') { if ($authtype eq '') { $authtype = $domdefaults{'auth_def'}; $authparam = $domdefaults{'auth_arg_def'}; } } elsif ($usertype eq 'unofficial') { if ($authtype eq '') { $authtype = 'internal'; $authparam = ''; } } else { $authtype = $domdefaults{'auth_def'}; $authparam = $domdefaults{'auth_arg_def'}; } if (($authtype eq '') || (($authtype =~/^krb/) && ($authparam eq ''))) { push(@disallowed,$i); $disallowmsg{$i} = &mt('[_1] was excluded because institutional information is incomplete for this new user.',''.$personname.':'.$persondom.''); next; } if (ref($inst_results{$personname.':'.$persondom}) eq 'HASH') { if ($inst_results{$personname.':'.$persondom}{'lastname'} ne '') { $env{'form.person_'.$i.'_lastname'} = $inst_results{$personname.':'.$persondom}{'lastname'}; } if ($inst_results{$personname.':'.$persondom}{'firstname'} ne '') { $env{'form.person_'.$i.'_firstname'} = $inst_results{$personname.':'.$persondom}{'firstname'}; } if ($inst_results{$personname.':'.$persondom}{'permanentemail'} ne '') { $env{'form.person_'.$i.'_emailaddr'} = $inst_results{$personname.':'.$persondom}{'permanentemail'}; } } } else { push(@disallowed,$i); $disallowmsg{$i} = &mt('[_1] was excluded because the username violated format rules for the domain',''.$personname.':'.$persondom.''); } } else { push(@disallowed,$i); $disallowmsg{$i} = &mt('[_1] was excluded because you may not request new users in the domain',''.$personname.':'.$persondom.''); } } else { my %userenv = &Apache::lonnet::userenvironment($persondom,$personname,'lastname','firstname','permanentemail'); if ($env{'form.person_'.$i.'_lastname'} eq '') { $env{'form.person_'.$i.'_lastname'} = $userenv{'lastname'}; } if ($env{'form.person_'.$i.'_firstname'} eq '') { $env{'form.person_'.$i.'_firstname'} = $userenv{'firstname'}; } if ($env{'form.person_'.$i.'_emailaddr'} eq '') { $env{'form.person_'.$i.'_emailaddr'} = $userenv{'permanentemail'}; } } } elsif ($personname ne '') { push(@disallowed,$i); $disallowmsg{$i} = &mt('[_1] was excluded because the domain is invalid',''.$personname.':'.$persondom.''); } } elsif ($personname ne '') { push(@disallowed,$i); $disallowmsg{$i} = &mt('[_1] was excluded because the username or domain is invalid.',''.$personname.':'.$persondom.''); } } my $cnum; if ($env{'form.origcnum'} =~ /^($match_courseid)$/) { $cnum = $env{'form.origcnum'}; } else { my $gentype = 'Course'; if ($crstype eq 'community') { $gentype = 'Community'; } $cnum = &Apache::lonnet::generate_coursenum($dom,$gentype); } &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, \%cat_order,\@code_order); if ($crstype eq 'community') { $r->print('

'.&mt('Review community request details before submission').'

'); } else { $r->print('

'.&mt('Review course request details before submission').'

'); } $r->print(&print_review($dom,\@codetitles,\%cat_titles,\%cat_order,\@code_order,'','',\@disallowed,\%disallowmsg,$instcredits). ''); my $fullname = &Apache::loncommon::plainname($env{'user.name'}, $env{'user.domain'}); my $postprocess = &Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,'review',$env{'user.name'}, $env{'user.domain'},$fullname,$env{'form.cdescr'}); if (ref($postprocess) eq 'HASH') { if ($postprocess->{'reviewweb'}) { $r->print($postprocess->{'reviewweb'}); } } if ($crstype eq 'community') { $navtxt{'next'} = &mt('Submit community request'); } else { $navtxt{'next'} = &mt('Submit course request'); } } elsif ($state eq 'process') { if ($crstype eq 'official') { &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, \%cat_order,\@code_order); } my $lonhost = $r->dir_config('lonHostID'); my ($storeresult,$result) = &print_request_outcome($r,$lonhost,$dom,\@codetitles, \@code_order,$instcredits); $r->print($result); if (($storeresult eq 'ok') || ($storeresult eq 'created')) { if ($storeresult eq 'ok') { $r->print('

'. &mt('Modify this request').''.(' 'x4). ''.&mt('Make another request').'

'); } if (&Apache::loncoursequeueadmin::author_prompt()) { &print_author_prompt($r,$env{'form.action'},$env{'form.cnum'},$env{'form.showdom'}, $env{'form.crstype'},$storeresult); } elsif ($storeresult eq 'created') { $r->print('

'.&mt('Make another request').'

'); } } } elsif ($state eq 'reqauthor') { my ($result,@links); if ($env{'form.requestauthor'}) { $r->print(&Apache::loncoursequeueadmin::process_reqauthor(\$result)); if ($result eq 'created') { my $role = 'au'; my $spec = "$role./$env{'form.showdom'}/"; push(@links,&mt('Enter your Authoring Space with role: [_1]', ''. &Apache::lonnet::plaintext($role).'')); } } if (($env{'form.disposition'} eq 'created') && ($env{'form.cnum'} =~ /^$match_courseid$/) && ($env{'form.showdom'} =~ /^$match_domain$/)) { my ($spec,$area,$role,$type); my $role = 'cc'; my $spec = "$role./$env{'form.showdom'}/$env{'form.cnum'}"; my $type = 'Course'; if ($env{'form.crstype'} eq 'community') { $type = 'Community'; } my $showrole = &Apache::lonnet::plaintext($role,$type); unshift(@links,&mt('Enter new course with role: [_1]', ''.$showrole.'')); } if (@links > 1) { $r->print(&mt('New roles will be listed on your [_1]Roles[_2] page.', '','').' '.&mt('Choose a role:'). '
    '); foreach my $link (@links) { $r->print('
  • '.$link.'
  • '); } $r->print('
'); } elsif (@links == 1) { $r->print('

'.$links[0].'

'); } } my @excluded = &get_excluded_elements($dom,$states,$action,$state,$showcredits); if ($state eq 'personnel') { push(@excluded,'persontotal'); } if ($state eq 'review') { if (@disallowed > 0) { my @items = qw(uname dom lastname firstname emailaddr hidedom role newsec); my @currsecs = ¤t_lc_sections(); if (@currsecs) { push(@items,'sec'); } my $count = 0; for (my $i=0; $i<$env{'form.persontotal'}; $i++) { unless ($env{'form.person_'.$i.'_uname'} eq '') { if (grep(/^$i$/,@disallowed)) { foreach my $item (@items) { $env{'form.person_'.$i.'_'.$item} = ''; } } else { foreach my $item (@items) { $env{'form.person_'.$count.'_'.$item} = $env{'form.person_'.$i.'_'.$item}; } } } $count ++; } $env{'form.persontotal'} = $count; } } if ($state eq 'enrollment') { push(@excluded,('sectotal','crosslisttotal')); } if (($state eq 'process') || ($state eq 'reqauthor')) { $r->print('
'); } else { $r->print(&Apache::lonhtmlcommon::echo_form_input(\@excluded).''); &display_navbuttons($r,$dom,$formname,$prev,$navtxt{'prev'},$next, $navtxt{'next'},$state); } return; } sub print_author_prompt { my ($r,$action,$cnum,$showdom,$crstype,$storeresult) = @_; $r->print('

'.&mt('Access to Authoring Space').'

'. '

'. &mt('Although assessment items can be created directly inside a course, such items only use part of the assessment capabilities of LON-CAPA.'). '
'. &mt('By contrast, items created in Authoring Space, then imported into a course, can use all of the features of the assessment engine.').'

'. '

'.&mt('Request Authoring Space access now?'). ' '. ''. (' 'x2). ''. '

'. ''. ''. ''. ''. ''. ''. ''. '
'); } sub get_usertype { my ($persondom,$personname,$curr_rules,$got_rules) = @_; my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($persondom,'username'); my $usertype = &Apache::lonuserutils::check_usertype($persondom,$personname, $rules,$curr_rules,$got_rules); return $usertype; } sub check_newuser_rules { my ($persondom,$personname,$alerts,$rulematch,$inst_results,$curr_rules, $got_rules) = @_; my $allowed = 1; my $newuser = 1; my ($checkhash,$userchkmsg,$authtype,$authparam); my $checks = { 'username' => 1 }; $checkhash->{$personname.':'.$persondom} = { 'newuser' => $newuser }; &Apache::loncommon::user_rule_check($checkhash,$checks,$alerts,$rulematch, $inst_results,$curr_rules,$got_rules); if (ref($alerts->{'username'}) eq 'HASH') { if (ref($alerts->{'username'}{$persondom}) eq 'HASH') { my $domdesc = &Apache::lonnet::domain($persondom,'description'); if ($alerts->{'username'}{$persondom}{$personname}) { if (ref($curr_rules->{$persondom}) eq 'HASH') { $userchkmsg = &Apache::loncommon::instrule_disallow_msg('username', $domdesc,1). &Apache::loncommon::user_rule_formats($persondom, $domdesc,$curr_rules->{$persondom}{'username'}, 'username'); } $allowed = 0; } } } if ($allowed) { if (ref($rulematch) eq 'HASH') { if (ref($rulematch->{$personname.':'.$persondom}) eq 'HASH') { my $matchedrule = $rulematch->{$personname.':'.$persondom}{'username'}; my ($rules,$ruleorder) = &Apache::lonnet::inst_userrules($persondom,'username'); if (ref($rules) eq 'HASH') { if (ref($rules->{$matchedrule}) eq 'HASH') { $authtype = $rules->{$matchedrule}{'authtype'}; $authparam = $rules->{$matchedrule}{'authparm'}; } } } } } return ($allowed,$userchkmsg,$authtype,$authparam); } sub get_excluded_elements { my ($dom,$states,$action,$state,$showcredits) = @_; my @excluded = ('counter'); my ($elements,$instcredits) = &form_elements($dom,$showcredits); if (ref($states) eq 'HASH') { if (ref($states->{$action}) eq 'ARRAY') { my @items = @{$states->{$action}}; my $numitems = scalar(@items); if ($numitems) { for (my $i=$numitems-1; $i>=0; $i--) { if ((ref($elements) eq 'HASH') && (ref($elements->{$action}) eq 'HASH')) { if (ref($elements->{$action}{$items[$i]}) eq 'HASH') { foreach my $key (keys(%{$elements->{$action}{$items[$i]}})) { push(@excluded,$key); } } } last if ($items[$i] eq $state); } } } } if (grep(/^instcode_/,@excluded)) { push(@excluded,'instcode'); } return @excluded; } sub print_enrollment_menu { my ($formname,$instcode,$dom,$codetitles,$cat_titles,$cat_order,$code_order, $showcredits,$instcredits,$invalidcrosslist) =@_; my ($sections,$autoenroll,$access_dates,$output,$hasauto,$hascredits, $creditsrow,$domdefcredits); my $starttime = time; my $endtime = time+(6*30*24*60*60); # 6 months from now, approx my %accesstitles = ( 'start' => 'Default start access', 'end' => 'Default end access', ); my %enrolltitles = ( 'start' => 'Start auto-enrollment', 'end' => 'End auto-enrollment', ); if ($showcredits) { unless ($env{'form.crstype'} eq 'community') { my %domdefs = &Apache::lonnet::get_domain_defaults($dom); $domdefcredits = $domdefs{$env{'form.crstype'}.'credits'}; } } if ($env{'form.crstype'} eq 'official') { if (&Apache::lonnet::auto_run('',$dom)) { $output = &show_invalid_crosslists($invalidcrosslist); my ($section_form,$crosslist_form); if ($instcode ne '') { $section_form = &inst_section_selector($dom,$instcode); if ($section_form eq '') { my $sectotal = $env{'form.sectotal'}; if (!$sectotal) { $sectotal = 1; } if ($env{'form.addsection'}) { $sectotal ++; } for (my $i=0; $i<$sectotal; $i++) { $section_form .= §ions_form($dom,$instcode,$i); } if ($section_form) { $section_form .= &Apache::lonhtmlcommon::row_title(&mt('Add another')). ''. ''.&mt('Add?').&Apache::lonhtmlcommon::row_closure(); } } } if ($section_form) { $sections = &Apache::lonhtmlcommon::row_headline(). '

'.&Apache::loncommon::help_open_topic('Course_Request_Sections'). ' '.&mt('Sections for auto-enrollment').'

'. &Apache::lonhtmlcommon::row_closure(1). $section_form; } my $crosslisttotal = $env{'form.crosslisttotal'}; if (!$crosslisttotal) { $crosslisttotal = 1; } if ($env{'form.addcrosslist'}) { $crosslisttotal ++; } for (my $i=0; $i<$crosslisttotal; $i++) { $crosslist_form .= &coursecode_form($dom,'crosslist',$codetitles, $cat_titles,$cat_order,$i); } if ($crosslist_form) { $crosslist_form .= &Apache::lonhtmlcommon::row_title(&mt('Add another')). ''. ''.&mt('Add?').&Apache::lonhtmlcommon::row_closure(); $sections .= &Apache::lonhtmlcommon::row_headline. '

'.&Apache::loncommon::help_open_topic('Course_Request_Crosslist').' '.&mt('Crosslisted courses for auto-enrollment').'

'. &Apache::lonhtmlcommon::row_closure(1). $crosslist_form; } $hasauto = 1; $autoenroll = &Apache::lonhtmlcommon::row_title(&Apache::loncommon::help_open_topic('Course_Request_Autoadd').' '.&mt('Add registered students automatically')). ''.(' 'x3).''. &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::row_title(&Apache::loncommon::help_open_topic('Course_Request_Autodrop').' '.&mt('Drop unregistered students automatically')). ''.(' 'x3).''. &Apache::lonhtmlcommon::row_closure(1). &date_setting_table($starttime,$endtime,$formname,'enroll', $hasauto,undef,%enrolltitles); if ($showcredits) { if ($instcredits) { $creditsrow = &mt('[quant,_1,credit]',$instcredits); } else { $creditsrow = ''. ''; } $hascredits = 1; } } } elsif (($env{'form.crstype'} eq 'unofficial') || ($env{'form.crstype'} eq 'textbook')) { if ($showcredits) { $creditsrow = ''. ''; $hascredits = 1; } } my $access_dates = &date_setting_table($starttime,$endtime,$formname,'access',$hasauto, $hascredits,%accesstitles); $output .= &Apache::lonhtmlcommon::start_pick_box(); if ($sections) { $output .= $sections; } if ($autoenroll) { $output .= &Apache::lonhtmlcommon::row_headline('Auto-enroll'). '

'.&mt('Auto-enrollment settings').'

'. &Apache::lonhtmlcommon::row_closure(1). $autoenroll; } if ($access_dates) { my $header = &mt('Access dates for students'); if ($env{'form.crstype'} eq 'community') { $header = &mt('Access dates for community members'); } $output .= &Apache::lonhtmlcommon::row_headline('Access'). '

'.$header.'

'. &Apache::lonhtmlcommon::row_closure(1). $access_dates; } if ($creditsrow) { $output .= &Apache::lonhtmlcommon::row_headline('Credits'). '

'.&mt('Credits earned by students').'

'. &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::row_title(&mt('Default credits')). $creditsrow. &Apache::lonhtmlcommon::row_closure(1); } return '
'.&Apache::lonhtmlcommon::start_pick_box().$output. &Apache::lonhtmlcommon::end_pick_box().'
'; } sub show_invalid_crosslists { my ($invalidcrosslist) = @_; my $output; if (ref($invalidcrosslist) eq 'ARRAY') { if (@{$invalidcrosslist} > 0) { $output = '
'. &mt('The following crosslisted courses were invalid:').'
    '; foreach my $item (@{$invalidcrosslist}) { $output .= '
  • '.$item.'
  • '; } $output .= '

'; } } return $output; } sub inst_section_selector { my ($dom,$instcode) = @_; my @sections = &Apache::lonnet::auto_get_sections(undef,$dom,$instcode); my $sectotal = scalar(@sections); my $output; if ($sectotal) { $output .= &Apache::lonhtmlcommon::row_title(&mt('Sections of [_1]',$instcode)). &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). ''.&mt('Include?').''. ''.&mt('Institutional Section').''. ''.&Apache::loncommon::help_open_topic('Course_Request_LCSection'). ' '.&mt('LON-CAPA section').''. &Apache::loncommon::end_data_table_row(); for (my $i=0; $i<@sections; $i++) { my $colflag = $i%2; my $secon = ' checked="checked"'; my $secoff = ''; if ($env{'form.origcnum'}) { $secoff = $secon; $secon=''; } $output .= &Apache::loncommon::start_data_table_row(). ''. (' 'x2).''. ''.$sections[$i]. ''. ''. &Apache::loncommon::end_data_table_row(); } $output .= &Apache::loncommon::end_data_table(). &Apache::lonhtmlcommon::row_closure(); } return $output; } sub date_setting_table { my ($starttime,$endtime,$formname,$prefix,$hasauto,$hascredits,%datetitles)=@_; my ($perpetual,$table); my $startform = &Apache::lonhtmlcommon::date_setter($formname,$prefix.'start', $starttime,'','','',1,'','','',1); my $endform = &Apache::lonhtmlcommon::date_setter($formname,$prefix.'end', $endtime,'','','',1,'','','',1); my $closure = ''; if ($prefix eq 'access') { $perpetual = ' '; unless ($hascredits) { $closure = '1'; } } my %help_item = ( access => { start => 'Course_Request_Access_Start', end => 'Course_Request_Access_End', }, enroll => { start => 'Course_Request_Enroll_Start', end => 'Course_Request_Enroll_End', }, ); if ($hasauto) { $help_item{'access'}{'start'} = 'Course_Request_RegAccess_Start'; $help_item{'access'}{'end'} = 'Course_Request_RegAccess_End'; } $table = &Apache::lonhtmlcommon::row_title(&Apache::loncommon::help_open_topic($help_item{$prefix}{'start'}). ' '.&mt($datetitles{'start'})).$startform. &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::row_title(&Apache::loncommon::help_open_topic($help_item{$prefix}{'end'}). ' '.&mt($datetitles{'end'})).$endform.$perpetual. &Apache::lonhtmlcommon::row_closure($closure); return $table; } sub print_personnel_menu { my ($dom,$formname,$crstype,$invalidcrosslist) = @_; my $output; if ($crstype eq 'official') { if (&Apache::lonnet::auto_run('',$dom)) { $output .= &show_invalid_crosslists($invalidcrosslist); } } $output .= '
'.&Apache::lonhtmlcommon::start_pick_box(); my $persontotal = $env{'form.persontotal'}; if ((!defined($persontotal)) || (!$persontotal)) { $persontotal = 1; } if ($env{'form.addperson'}) { $persontotal ++; } my @items = ('uname','dom','lastname','firstname','emailaddr','hidedom'); my $type = 'Course'; if ($crstype eq 'community') { $type = 'Community'; } my $roleoptions; my @roles = &Apache::lonuserutils::roles_by_context('course','',$type); foreach my $role (@roles) { my $plrole = &Apache::lonnet::plaintext($role,$type); $roleoptions .= ' '."\n"; } my %customroles=&Apache::lonuserutils::my_custom_roles(); if (keys(%customroles) > 0) { foreach my $cust (sort(keys(%customroles))) { my $custrole="cr/$env{'user.domain'}/$env{'user.name'}/$cust"; $roleoptions .= ' '."\n"; } } my @currsecs = ¤t_lc_sections(); my ($existtitle,$existops,$existmult,$newtitle,$seccolspan); if (@currsecs) { my $existsize = scalar(@currsecs); if ($existsize > 3) { $existsize = 3; } if ($existsize > 1) { $existmult = ' multiple="multiple" size="'.$existsize.'" '; } @currsecs = sort { $a <=> $b } (@currsecs); $existtitle = &mt('Official').': '; $existops = ''; foreach my $sec (@currsecs) { $existops .= ''."\n"; } $seccolspan = ' colspan="2"'; $newtitle = &mt('Other').': '; } if ($persontotal) { my %lt = &Apache::lonlocal::texthash( community => 'Requestor is automatically assigned Coordinator role.', official => 'Requestor is automatically assigned Course Coordinator role.', ); $lt{'unofficial'} = $lt{'official'}; $lt{'textbook'} = $lt{'textbook'}; $output .= &Apache::lonhtmlcommon::row_headline(). '

'.&Apache::loncommon::help_open_topic('Course_Request_Personnel').' '.$lt{$crstype}.' '.&mt('Include other personnel?').'

'; } for (my $i=0; $i<$persontotal; $i++) { my @linkargs = map { 'person_'.$i.'_'.$_ } (@items); my $linkargstr = join("','",@linkargs); my $uname_form = ''; my $onchange = 'javascript:fix_domain('."'$formname','person_".$i."_dom',". "'person_".$i."_hidedom','person_".$i."_uname'".');'; my $udom_form = &Apache::loncommon::select_dom_form($dom,'person_'.$i.'_dom','', 1,$onchange). ''; my %form_elems; foreach my $item (@items) { next if (($item eq 'dom') || ($item eq 'uname') || ($item eq 'hidedom')); $form_elems{$item} = ''; } my $roleselector = ''; my $sectionselector; if (@currsecs) { $sectionselector = $existtitle.''.(' ' x3); } $sectionselector .= $newtitle. ''."\n"; my $usersrchlinktxt = &mt('Search for user'); my $usersrchlink = &Apache::loncommon::selectuser_link($formname,@linkargs,$dom, $usersrchlinktxt); my $userchklinktxt = &mt('Check username'); my $userchklink = &Apache::loncommon::selectuser_link($formname,@linkargs,$dom, $userchklinktxt,'checkusername'); $output .= &Apache::lonhtmlcommon::row_title(&mt('Additional Personnel')). ''."\n". ''. ''."\n".''. ''."\n". ''."\n". ''."\n". ''."\n". ''. &Apache::loncommon::help_open_topic('Course_Request_Rolesection').' '.&mt('LON-CAPA Section(s)').'
'.$sectionselector.''."\n". '
'.$usersrchlink.''. &mt('Username').': '.$uname_form.' '.$userchklink.'
'."\n". ''.&mt('Domain').': '.$udom_form.'
'.&mt('First Name').'
'.$form_elems{'firstname'}.'
'.&mt('Last Name').'
'.$form_elems{'lastname'}.'
'.&mt('E-mail').'
'.$form_elems{'emailaddr'}.'
'.&Apache::loncommon::help_open_topic('Course_Roles').' '.&mt('Role').'
'.$roleselector.'
'.&Apache::lonhtmlcommon::row_closure(); } $output .= &Apache::lonhtmlcommon::row_title(&mt('Add another')). ''. ''.&mt('Add?').&Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::end_pick_box().'
'; if ($crstype eq 'community') { $output .= '

'.&mt('You may also add users later, once the community has been created, by using the "Manage community users" link, accessible from the "Main Menu".').'

'; } else { $output .= '

'.&mt('You may also add users later, once the course has been created, by using the "Manage course users" link, accessible from the "Main Menu".').'

'; } return $output; } sub current_lc_sections { my @currsecs; if ($env{'form.sectotal'}) { for (my $i=0; $i<$env{'form.sectotal'}; $i++) { if ($env{'form.sec_'.$i}) { if (defined($env{'form.loncapasec_'.$i})) { my $lcsec = $env{'form.loncapasec_'.$i}; unless (grep(/^\Q$lcsec\E$/,@currsecs)) { push(@currsecs,$lcsec); } } } } } return @currsecs; } sub sorted_request_history { my ($dom,$action,$curr_req) = @_; my ($after,$before,$statusfilter,$crstypefilter); if ($env{'form.status'} ne '') { $statusfilter = $env{'form.status'}; } if ($env{'form.crstype'} ne '') { $crstypefilter = $env{'form.crstype'}; } if (ref($curr_req) eq 'HASH') { $after = $curr_req->{'requested_after_date'}, $before = $curr_req->{'requested_before_date'}; $statusfilter = $curr_req->{'status'}; $crstypefilter = $curr_req->{'crstype'}; } my %statusinfo = &Apache::lonnet::dump('courserequests',$env{'user.domain'}, $env{'user.name'},'^status:'.$dom); my %queue_by_date; my ($types,$typenames) = &Apache::loncommon::course_types(); foreach my $key (keys(%statusinfo)) { if ($action eq 'view') { next unless (($statusinfo{$key} eq 'approval') || ($statusinfo{$key} eq 'pending')); } else { next unless (($statusfilter eq 'any') || ($statusfilter eq $statusinfo{$key})); } (undef,my($cdom,$cnum)) = split(':',$key); next if ($cdom ne $dom); my $requestkey = $cdom.'_'.$cnum; if ($requestkey =~ /^($match_domain)_($match_courseid)$/) { my %history = &Apache::lonnet::restore($requestkey,'courserequests', $env{'user.domain'},$env{'user.name'}); my $entry; my $reqtime = $history{'reqtime'}; my $lastupdate = $history{'timestamp'}; my $crstype = $history{'crstype'}; my $disposition = $history{'disposition'}; my $status = $history{'status'}; my $uniquecode = $history{'code'}; if ($action eq 'view') { next if ((exists($history{'status'})) && ($history{'status'} eq 'created')); } else { next if (($reqtime < $after) || ($reqtime > $before)); } next unless (($crstypefilter eq 'any') || ($crstypefilter eq $crstype)); if ($action eq 'view') { next unless (($disposition eq 'approval') || ($disposition eq 'pending')); } if (ref($history{'details'}) eq 'HASH') { $entry = $requestkey.':'.$crstype.':'. &escape($history{'details'}{'cdescr'}); if ($action eq 'log') { $entry .= ':'.$uniquecode.':'.$lastupdate.':'; if ($statusinfo{$key} ne '') { $entry .= $statusinfo{$key}; } elsif ($status ne '') { $entry .= $status; } else { $entry .= $disposition; } } if ($crstype eq 'official') { $entry .= ':'.&escape($history{'details'}{'instcode'}); } } if ($entry ne '') { if (exists($queue_by_date{$reqtime})) { if (ref($queue_by_date{$reqtime}) eq 'ARRAY') { push(@{$queue_by_date{$reqtime}},$entry); } } else { @{$queue_by_date{$reqtime}} = ($entry); } } } } return %queue_by_date; } sub print_request_status { my ($dom,$action) = @_; my %queue_by_date = &sorted_request_history($dom,$action); my @sortedtimes = sort {$a <=> $b} (keys(%queue_by_date)); my $formname = 'requestcrs'; my ($types,$typenames) = &Apache::loncommon::course_types(); my $output = ''."\n". ''."\n". ''."\n". ''."\n". ''."\n"; if (@sortedtimes > 0) { my $desctitle; if ($env{'form.crstype'} eq 'any') { $desctitle = &mt('Course/Community Description') } elsif ($env{'form.crstype'} eq 'community') { $desctitle = &mt('Community Description') } else { $desctitle = &mt('Course Description'); } $output .= &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(). ''.&mt('Action').''. ''.$desctitle.''. ''.&mt('Domain').''; if ($env{'form.crstype'} eq 'any') { $output .= ''.&mt('Type').''; } if (($env{'form.crstype'} eq 'any') || ($env{'form.crstype'} eq 'official')) { $output .= ''.&mt('Institutional Code').''; } $output .= ''.&mt('Date requested').''. &Apache::loncommon::end_data_table_header_row(); my $count = 0; foreach my $item (@sortedtimes) { my $showtime = &Apache::lonlocal::locallocaltime($item); if (ref($queue_by_date{$item}) eq 'ARRAY') { foreach my $request (sort(@{$queue_by_date{$item}})) { my ($key,$type,$desc,$instcode) = split(':',$request); my ($cdom,$cnum) = split('_',$key); $output .= &Apache::loncommon::start_data_table_row(). ''. ''.&unescape($desc).''. ''.$cdom.''; if ($env{'form.crstype'} eq 'any') { my $typename; if (ref($typenames) eq 'HASH') { $typename = &mt($typenames->{$type}); } if ($typename eq '') { $typename = &mt('Unknown type'); } $output .= ''.$typename.''; } if (($env{'form.crstype'} eq 'any') || ($env{'form.crstype'} eq 'official')) { my $showinstcode; if ($type eq 'official') { $showinstcode = &unescape($instcode); } else { $showinstcode = &mt('Not applicable'); } $output .= ''.$showinstcode.''; } $output .= ''.$showtime.''. &Apache::loncommon::end_data_table_row(); } } } $output .= &Apache::loncommon::end_data_table(); } else { if ($env{'form.crstype'} eq 'any') { $output .= '
'.&mt('You have no matching course or community requests awaiting approval by a Domain Coordinator or held in a queue pending administrative action at your institution.').'
'; } elsif ($env{'form.crstype'} eq 'community') { $output .= '
'.&mt('You have no matching community requests awaiting approval by a Domain Coordinator or held in a queue pending administrative action at your institution.').'
'; } else { $output .= '
'.&mt('You have no matching course requests awaiting approval by a Domain Coordinator or held in a queue pending administrative action at your institution.').'
'; } } $output .= '
'; return $output; } sub print_cancel_request { my ($dom,$cnum) = @_; my $requestkey = $dom.'_'.$cnum; my ($result,$output); if ($requestkey =~ /^($match_domain)_($match_courseid)$/) { my %history = &Apache::lonnet::restore($requestkey,'courserequests', $env{'user.domain'},$env{'user.name'}); my $timestamp = $history{'reqtime'}; my $crstype = $history{'crstype'}; my $status = $history{'status'}; if (($status eq 'cancelled') || ($status eq 'created')) { if ($status eq 'cancelled') { $output = &mt('This request has already been cancelled.'); } elsif ($status eq 'created') { $output = &mt('This request has already been processed, and a course created.'); } $output = &mt('No further action will be taken'); } elsif (ref($history{'details'}) eq 'HASH') { my ($types,$typename) = &Apache::loncommon::course_types(); my $showtype = $crstype; if (defined($typename->{$crstype})) { $showtype = $typename->{$crstype}; } $output = '

'.&Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(). ''.&mt('Description').''.&mt('Requested').''. ''.&mt('Type').''. &Apache::loncommon::end_data_table_header_row(). &Apache::loncommon::start_data_table_row(). ''.$history{details}{'cdescr'}.''. &Apache::lonlocal::locallocaltime($timestamp).''. ''.$showtype.''. &Apache::loncommon::end_data_table_row(). &Apache::loncommon::end_data_table(). '

'; if ($crstype eq 'community') { $output .= &mt('Cancelling the request will remove it from the queue of pending community requests').'
'; } else { $output .= &mt('Cancelling the request will remove it from the queue of pending course requests').''; } $result = 'ok'; } else { $output = '
'.&mt('No record exists for the course ID').'
'; } } else { $output = '
'.&mt('Invalid course ID').'
'; } return ($result,$output); } sub viewrequest_javascript { my ($formname,$next) = @_; return <<"ENDJS"; function chooseRequest(cdom,cnum) { document.$formname.showdom.value = cdom; document.$formname.cnum.value = cnum; nextPage(document.$formname,'$next'); } ENDJS } sub viewdetails_javascript { my ($formname) = @_; return << "ENDJS"; function nextPage(formname,nextstate) { if (nextstate == "modify") { formname.state.value = "personnel"; formname.action.value = "new"; } else { formname.state.value = nextstate; } formname.submit(); } function backPage(formname,prevstate) { formname.state.value = prevstate; formname.submit(); } ENDJS } sub viewcancel_javascript { my $alert = &mt('Are you sure you want to cancel this request?').'\\n'. &mt('Your request will be removed.'); return << "ENDJS"; function nextPage(formname,nextstate) { if (confirm('$alert')) { formname.state.value = nextstate; formname.submit(); } return; } ENDJS } sub print_request_logs { my ($r,$dom,$jscript,$loaditems,$crumb,$usetabs) = @_; my $title; if ($env{'form.crstype'} eq 'community') { $title = 'Community Request Logs'; } elsif ($env{'form.crstype'} eq 'any') { $title = 'Course/Community Request Logs'; } else { $title = 'Course Request Logs'; } $r->print(&header($title,$jscript,$loaditems).$crumb); if ($usetabs) { &startContentScreen($r,'textbooklogs'); } my $formname = 'requestcrs'; $r->print('
'."\n". ''."\n". ''."\n"); # set defaults my $now = time(); my $defstart = $now - (7*24*3600); #7 days ago my %defaults = ( page => '1', show => '10', crstype => 'any', status => 'any', requested_before_date => $now, requested_after_date => $defstart, ); my ($types,$typenames) = &Apache::loncommon::course_types(); my $more_records = 0; my %curr; foreach my $item ('show','page','crstype','status') { $curr{$item} = $env{'form.'.$item}; } $curr{'requested_after_date'} = &Apache::lonhtmlcommon::get_date_from_form('requested_after_date'); $curr{'requested_before_date'} = &Apache::lonhtmlcommon::get_date_from_form('requested_before_date'); foreach my $key (keys(%defaults)) { if ($curr{$key} eq '') { $curr{$key} = $defaults{$key}; } } my ($statuses,$statusnames) = &reqstatus_names($curr{'crstype'}); $r->print(''. &requestlog_display_filter($formname,\%curr)); my %queue_by_date = &sorted_request_history($dom,$env{'form.action'},\%curr); my @sortedtimes = sort {$a <=> $b} (keys(%queue_by_date)); my $showntablehdr = 0; my $tablehdr = &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_header_row(). ' '.&mt('Request Date').''. ''.&mt('Description').''; if ($curr{'crstype'} eq 'any') { $tablehdr .= ''.&mt('Course Type').''; } if (($curr{'crstype'} eq 'official') || ($curr{'crstype'} eq 'any')) { $tablehdr .= ''.&mt('Institutional Code').''; } my $showuniquecode; my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$dom); if (($curr{'status'} eq 'any') || ($curr{'status'} eq 'created')) { if (ref($domconfig{'requestcourses'}) eq 'HASH') { if (ref($domconfig{'requestcourses'}{'uniquecode'}) eq 'HASH') { if ($curr{'crstype'} eq 'any') { my @types = qw(official unofficial community textbook); foreach my $type (@types) { if ($domconfig{'requestcourses'}{'uniquecode'}{$type}) { $showuniquecode = 1; last; } } } elsif ($domconfig{'requestcourses'}{'uniquecode'}{$curr{'crstype'}}) { $showuniquecode = 1; } } } } if ($showuniquecode) { $tablehdr .= ''.&mt('Unique Code').''; } if ($curr{'status'} eq 'any') { $tablehdr .= ''.&mt('Status').''; } elsif ($curr{'status'} eq 'created') { $tablehdr .= ''.&mt('Creation Date').''; } elsif ($curr{'status'} eq 'cancelled') { $tablehdr .= ''.&mt('Cancellation Date').''; } elsif ($curr{'status'} eq 'rejected') { $tablehdr .= ''.&mt('Rejection Date').''; } $tablehdr .= &Apache::loncommon::end_data_table_header_row(); my ($minshown,$maxshown); $minshown = 1; my $count = 0; if ($curr{'show'} ne &mt('all')) { $maxshown = $curr{'page'} * $curr{'show'}; if ($curr{'page'} > 1) { $minshown = 1 + ($curr{'page'} - 1) * $curr{'show'}; } } my $norecords; if (@sortedtimes > 0) { foreach my $item (@sortedtimes) { if ($curr{'show'} ne &mt('all')) { if ($count >= $curr{'page'} * $curr{'show'}) { $more_records = 1; last; } } $count ++; next if ($count < $minshown); if (!$showntablehdr) { $r->print($tablehdr); $showntablehdr = 1; } my $showtime = &Apache::lonlocal::locallocaltime($item); if (ref($queue_by_date{$item}) eq 'ARRAY') { foreach my $request (sort(@{$queue_by_date{$item}})) { my ($key,$crstype,$desc,$uniquecode,$timestamp,$status,$instcode) = split(':',$request); my ($cdom,$cnum) = split('_',$key); my $output = &Apache::loncommon::start_data_table_row(). ''.$count.''. ''.$showtime.''. ''.&unescape($desc).''; if ($curr{'crstype'} eq 'any') { my $typename; if (ref($typenames) eq 'HASH') { $typename = &mt($typenames->{$crstype}); } if ($typename eq '') { $typename = &mt('Unknown type'); } $output .= ''.$typename.''; } if (($curr{'crstype'} eq 'any') || ($curr{'crstype'} eq 'official')) { my $showinstcode; if ($crstype eq 'official') { $showinstcode = &unescape($instcode); } else { $showinstcode = &mt('Not applicable'); } $output .= ''.$showinstcode.''; } if ($showuniquecode) { if ($status eq 'created') { $output .= ''.$uniquecode.''; } else { $output .= ''.&mt('Not applicable').''; } } if ($curr{'status'} eq 'any') { my $statusname = &mt('Unknown status'); if (ref($statusnames) eq 'HASH') { if ($statusnames->{$status} ne '') { $statusname = $statusnames->{$status}; } } if (($status eq 'created') || ($status eq 'cancelled') || ($status eq 'rejected')) { $statusname .= ' '.&Apache::lonlocal::locallocaltime($timestamp); } $output .= ''.$statusname.''; } elsif (($status eq 'created') || ($status eq 'cancelled') || ($status eq 'rejected')) { $output .= ''.&Apache::lonlocal::locallocaltime($timestamp).''; } $output .= &Apache::loncommon::end_data_table_row(); $r->print($output); } } } if ($showntablehdr) { $r->print(&Apache::loncommon::end_data_table()); if (($curr{'page'} > 1) || ($more_records)) { $r->print(''); if ($curr{'page'} > 1) { $r->print(''); } if ($more_records) { $r->print(''); } $r->print('
'.&mt('Previous [_1] changes',$curr{'show'}).''.&mt('Next [_1] changes',$curr{'show'}).'
'); $r->print(<<"ENDSCRIPT"); ENDSCRIPT } } else { $norecords = 1; } } else { $norecords = 1; } if ($norecords) { $r->print('

'. &mt('There are no records to display'). '

'); } if ($usetabs) { $r->print(''); } $r->print('
'); if ($usetabs) { &endContentScreen($r); } $r->print(&Apache::loncommon::end_page()); return; } sub reqstatus_names { my ($crstype) = @_; my @statuses = qw(created approval pending rejected cancelled); my %statusnames = &Apache::lonlocal::texthash ( created => 'Created', approval => 'Queued pending approval', pending => 'Queued pending validation', rejected => 'Request rejected', cancelled => 'Request cancelled', ); if (($crstype eq 'official') || ($crstype eq 'unofficial') || ($crstype eq 'textbook')) { $statusnames{'created'} = &mt('Course created'); } elsif ($crstype eq 'community') { $statusnames{'created'} = &mt('Community created'); } return (\@statuses,\%statusnames); } sub requestlog_display_filter { my ($formname,$curr) = @_; my $nolink = 1; my $output = ''; my $startform = &Apache::lonhtmlcommon::date_setter($formname,'requested_after_date', $curr->{'requested_after_date'},undef, undef,undef,undef,undef,undef,undef,$nolink); my $endform = &Apache::lonhtmlcommon::date_setter($formname,'requested_before_date', $curr->{'requested_before_date'},undef, undef,undef,undef,undef,undef,undef,$nolink); $output .= ''. ''; my ($types,$typenames) = &Apache::loncommon::course_types(); if (ref($types) eq 'ARRAY') { if (@{$types} > 1) { $output .= ''; } } my ($statuses,$statusnames) = &reqstatus_names($curr->{'crstype'}); if (ref($statuses) eq 'ARRAY') { if (@{$statuses} > 1) { $output .= ''; } } $output .= '
'. ''.&mt('Records/page:').'
'. &Apache::lonmeta::selectbox('show',$curr->{'show'},undef, (&mt('all'),5,10,20,50,100,1000,10000)). '
  '.&mt('Window during which course/community was requested:').'
'. ''. ''. '
'.&mt('After:'). ''.$startform.'
'.&mt('Before:').''.$endform.'
'. '
  '. &mt('Course Type:').'
'. &mt('Request Status:').'
'; # Update Display button $output .= '

'. ''. '


'; return $output; } sub print_review { my ($dom,$codetitles,$cat_titles,$cat_order,$code_order,$uname,$udom, $disallowed,$disallowmsg,$instcredits) = @_; my ($types,$typename) = &Apache::loncommon::course_types(); my ($owner,$ownername,$owneremail); if ($uname eq '' || $udom eq '') { $uname = $env{'user.name'}; $udom = $env{'user.domain'}; } $owner = $uname.':'.$udom; $ownername = &Apache::loncommon::plainname($uname,$udom,'first'); my %emails = &Apache::loncommon::getemails($uname,$udom); foreach my $email ('permanentemail','critnotification','notification') { $owneremail = $emails{$email}; last if ($owneremail ne ''); } my ($inst_headers,$inst_values,$crstypename,$enroll_headers,$enroll_values, $section_headers,$section_values,$personnel_headers,$personnel_values); $crstypename = $env{'form.crstype'}; if (ref($typename) eq 'HASH') { unless ($typename->{$env{'form.crstype'}} eq '') { $crstypename = &mt($typename->{$env{'form.crstype'}}); } } my $category = 'Course'; if ($env{'form.crstype'} eq 'community') { $category = 'Community'; } $inst_headers = ''.&mt('Description').''.&mt('Type').''; $inst_values = ''.$env{'form.cdescr'}.''.$crstypename.''; my $enrollrow_title = &mt('Default Access Dates').'
'. '('.&Apache::lonnet::plaintext('st',$category).')'; my $instcode; if ($env{'form.crstype'} eq 'official') { if ((ref($codetitles) eq 'ARRAY') && (ref($cat_titles) eq 'HASH')) { foreach my $title (@{$codetitles}) { if ($env{'form.instcode_'.$title} ne '') { $inst_headers .= ''.$title.''; my $longitem = $env{'form.instcode_'.$title}; if (ref($cat_titles->{$title}) eq 'HASH') { if ($cat_titles->{$title}{$env{'form.instcode_'.$title}} ne '') { $longitem = $cat_titles->{$title}{$env{'form.instcode_'.$title}}; } } $inst_values .= ''.$longitem.''; } } } if (ref($code_order) eq 'ARRAY') { foreach my $item (@{$code_order}) { $instcode .= $env{'form.instcode_'.$item}; } } $inst_headers .= ''.&mt('Credits').''; if ($instcredits) { $inst_values .= ''.$instcredits.''; } else { $inst_values .= ''.$env{'form.coursecredits'}.''; } if (&Apache::lonnet::auto_run('',$dom)) { $enrollrow_title = &mt('Enrollment'); $enroll_headers = ''.&mt('Automatic Adds').''. ''.&mt('Automatic Drops').''. ''.&mt('Enrollment Starts').''. ''.&mt('Enrollment Ends').''; $section_headers = ''.&mt('Sections').''. ''.&mt('Crosslistings').''; my ($enrollstart,$enrollend) = &dates_from_form('enrollstart','enrollend'); my @autoroster = (&mt('No'),&mt('Yes')); $enroll_values = ''.$autoroster[$env{'form.autoadds'}].''. ''.$autoroster[$env{'form.autodrops'}].''. ''.&Apache::lonlocal::locallocaltime($enrollstart).''. ''.&Apache::lonlocal::locallocaltime($enrollend).''; $section_values = ''. ''; my $secinfo; if ($env{'form.sectotal'} > 0) { for (my $i=0; $i<$env{'form.sectotal'}; $i++) { if ($env{'form.sec_'.$i}) { $secinfo .= ''; } } } if ($secinfo eq '') { $secinfo = ''; } $section_values .= $secinfo.'
'. &mt('Institutional section').''.&mt('LON-CAPA section').'
'.$env{'form.secnum_'.$i}.''; if ($env{'form.loncapasec_'.$i} ne '') { $secinfo .= $env{'form.loncapasec_'.$i}; } else { $secinfo .= &mt('None'); } $secinfo .= '
'.&mt('None').'
'. ''. ''; my $xlistinfo; my $crosslisttotal = $env{'form.crosslisttotal'}; if (!$crosslisttotal) { $crosslisttotal = 1; } for (my $i=0; $i<$crosslisttotal; $i++) { if ($env{'form.crosslist_'.$i}) { $xlistinfo .= ''; } } if ($xlistinfo eq '') { $xlistinfo = ''; } $section_values .= $xlistinfo; } $section_values .= '
'. &mt('Institutional course/section').''.&mt('LON-CAPA section').'
'; if (ref($code_order) eq 'ARRAY') { if (@{$code_order} > 0) { foreach my $item (@{$code_order}) { $xlistinfo .= $env{'form.crosslist_'.$i.'_'.$item}; } } } $xlistinfo .= $env{'form.crosslist_'.$i.'_instsec'}.''; if ($env{'form.crosslist_'.$i.'_lcsec'}) { $xlistinfo .= $env{'form.crosslist_'.$i.'_lcsec'}; } else { $xlistinfo .= &mt('None'); } $xlistinfo .= '
'.&mt('None').'
'; } elsif (($env{'form.crstype'} eq 'unofficial') || ($env{'form.crstype'} eq 'textbook')) { $inst_headers .= ''.&mt('Credits').''; $inst_values .= ''.$env{'form.coursecredits'}.''; } my %ctxt = &clone_text(); $inst_headers .= ''.&mt('Clone From').''; if (($env{'form.cloning'}) && ($env{'form.clonecrs'} =~ /^$match_name$/) && ($env{'form.clonedom'} =~ /^$match_domain$/)) { my $canclone = &Apache::loncoursequeueadmin::can_clone_course($uname, $udom,$env{'form.clonecrs'},$env{'form.clonedom'}, $env{'form.crstype'},$dom,$instcode); if ($canclone) { my %courseenv = &Apache::lonnet::userenvironment($env{'form.clonedom'}, $env{'form.clonecrs'},('description','internal.coursecode')); if (keys(%courseenv) > 0) { $inst_headers .= ''.$ctxt{'dsh'}.''; $inst_values .= ''.$courseenv{'description'}.' '; my $cloneinst = $courseenv{'internal.coursecode'}; if ($cloneinst ne '') { $inst_values .= $cloneinst.' '.&mt('in').' '.$env{'form.clonedom'}; } else { $inst_values .= &mt('from').' '.$env{'form.clonedom'}; } $inst_values .= ''; if ($env{'form.datemode'} eq 'preserve') { $inst_values .= $ctxt{'prd'}; } elsif ($env{'form.datemode'} eq 'shift') { $inst_values .= &mt('Shift dates by [_1] days',$env{'form.dateshift'}); } else { $inst_values .= $ctxt{'ncd'}; } $inst_values .= ''; } else { $inst_values .= ''.&mt('Unknown').''; } } else { $inst_values .= ''.&mt('Not permitted'),''; } } else { $inst_values .= ''.&mt('None').''; } $enroll_headers .= ''.&mt('Access Starts').''. ''.&mt('Access Ends').''; my ($accessstart,$accessend) = &dates_from_form('accessstart','accessend'); $enroll_values .= ''.&Apache::lonlocal::locallocaltime($accessstart).''; if ($accessend == 0) { $enroll_values .= ''.&mt('No end date').''; } else { $enroll_values .= ''.&Apache::lonlocal::locallocaltime($accessend).''; } my $container = 'Course'; my $ccrole = 'cc'; if ($env{'form.crstype'} eq 'community') { $container = 'Community'; $ccrole = 'co'; } $personnel_headers = ''.&mt('Name').''.&mt('Username:Domain'). ''.&mt('Role').''.&mt('LON-CAPA Sections'). ''; $personnel_values .= ''.$ownername.''.$owner.''. ''.&Apache::lonnet::plaintext($ccrole,$container).''. ''.&mt('None').''; for (my $i=0; $i<$env{'form.persontotal'}; $i++) { if ($env{'form.person_'.$i.'_uname'} ne '') { if (ref($disallowed) eq 'ARRAY') { next if (grep(/^$i$/,@{$disallowed})); } my @officialsecs = &Apache::loncommon::get_env_multiple('form.person_'.$i.'_sec'); my @allsecs; foreach my $sec (@officialsecs) { next unless ($sec =~ /\w/); next if ($sec =~ /\W/); next if ($sec eq 'none'); push(@allsecs,$sec); } my $newsec = $env{'form.person_'.$i.'_newsec'}; $newsec =~ s/^\s+//; $newsec =~s/\s+$//; my @newsecs = split(/\s*[\s,;:]\s*/,$newsec); foreach my $sec (@newsecs) { next unless ($sec =~ /\w/); next if ($sec =~ /\W/); next if ($sec eq 'none'); if ($sec ne '') { unless (grep(/^\Q$sec\E$/,@allsecs)) { push(@allsecs,$sec); } } } my $showsec; if (@allsecs) { $showsec = join(', ',@allsecs); } if ($showsec eq '') { $showsec = &mt('None'); } if ($env{'form.person_'.$i.'_role'} eq $ccrole) { $showsec = &mt('None'); } my $role = $env{'form.person_'.$i.'_role'}; $personnel_values .= ''.$env{'form.person_'.$i.'_firstname'}.' '. $env{'form.person_'.$i.'_lastname'}.''. ''.$env{'form.person_'.$i.'_uname'}.':'. $env{'form.person_'.$i.'_dom'}.''. ''.&Apache::lonnet::plaintext($role,$container).''. ''.$showsec.''; } } my $output; if (ref($disallowed) eq 'ARRAY') { if (@{$disallowed} > 0) { if (ref($disallowmsg) eq 'HASH') { $output = '

'. &mt('Not all requested personnel could be included.').'

    '; foreach my $item (@{$disallowed}) { $output .= '
  • '.$disallowmsg->{$item}.'
  • '; } $output .= '

'; } } } $output .= '
'.&Apache::lonhtmlcommon::start_pick_box(). &Apache::lonhtmlcommon::row_title(&mt('Owner')). ''. ''. ''. ''. ''."\n". ''. ''. '
'.&mt('Name').''.&mt('Username:Domain').''.&mt('E-mail address').'
'.$ownername.''.$owner.''.$owneremail.'
'."\n". &Apache::lonhtmlcommon::row_closure(). &Apache::lonhtmlcommon::row_title(&mt('Description')). ''.$inst_headers.''."\n". ''.$inst_values.'
'."\n". &Apache::lonhtmlcommon::row_closure(). &Apache::lonhtmlcommon::row_title($enrollrow_title). ''.$enroll_headers.''."\n". ''.$enroll_values.'
'."\n". &Apache::lonhtmlcommon::row_closure(); if ($section_headers ne '') { $output .= &Apache::lonhtmlcommon::row_title(&mt('Sections')). ''.$section_headers.''."\n". ''.$section_values.'
'."\n". &Apache::lonhtmlcommon::row_closure(); } $output .= &Apache::lonhtmlcommon::row_title(&mt('Personnel')). ''.$personnel_headers.''."\n". $personnel_values.'
'."\n". &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::end_pick_box().'
'; return $output; } sub dates_from_form { my ($startname,$endname) = @_; my $startdate = &Apache::lonhtmlcommon::get_date_from_form($startname); my $enddate = &Apache::lonhtmlcommon::get_date_from_form($endname); if ($endname eq 'accessend') { if (exists($env{'form.no_end_date'}) ) { $enddate = 0; } } return ($startdate,$enddate); } sub courseinfo_form { my ($dom,$formname,$crstype,$next,$description) = @_; my %lt = &Apache::lonlocal::texthash( official => 'You must provide a (brief) course description.', community => 'You must provide a (brief) community description.' ); $lt{'unofficial'} = $lt{'official'}; $lt{'textbook'} = $lt{'official'}; my $js_validate = <<"ENDJS"; ENDJS my $title = &mt('Brief Course Description'); my $clonetitle = &mt('Clone content and settings from an existing course?'); if ($crstype eq 'community') { $title = &mt('Brief Community Description'); $clonetitle = &mt('Clone content and settings from an existing community?'); } my $output .= $js_validate."\n".&Apache::lonhtmlcommon::start_pick_box(). &Apache::lonhtmlcommon::row_headline(). '

'.&Apache::loncommon::help_open_topic('Course_Request_Description').' '.$title.'

'. &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::row_title(&mt('Description')). ''; my ($home_server_pick,$numlib) = &Apache::loncommon::home_server_form_item($dom,'chome', 'default','hide'); if ($numlib > 1) { $output .= &Apache::lonhtmlcommon::row_closure(). &Apache::lonhtmlcommon::row_title(&mt('Home Server for Course')); } $output .= $home_server_pick. &Apache::lonhtmlcommon::row_closure(). &Apache::lonhtmlcommon::row_headline(). '

'.&Apache::loncommon::help_open_topic('Course_Request_Clone').' '.$clonetitle. &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::row_title(&mt('Clone?')). ''. '

'. &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::row_headline(). ''. &Apache::lonhtmlcommon::end_pick_box()."\n"; return $output; } sub clone_form { my ($dom,$formname,$crstype) = @_; my $type = 'Course'; if ($crstype eq 'community') { $type = 'Community'; } my %lt = &clone_text(); my $output .= &Apache::lonhtmlcommon::row_title($lt{'dmn'}).''. &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::row_title($lt{'cid'}).' '. &Apache::loncommon::selectcourse_link($formname,'clonecrs','clonedom','','','',$type). &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::row_title($lt{'dsh'}).'

'. ''. &Apache::lonhtmlcommon::row_closure(1); return $output; } sub clone_text { return &Apache::lonlocal::texthash( 'cid' => 'Course ID', 'dmn' => 'Domain', 'dsh' => 'Date Shift', 'ncd' => 'Do not clone date parameters', 'prd' => 'Clone date parameters as-is', 'shd' => 'Shift date parameters by number of days', ); } sub coursecode_form { my ($dom,$context,$codetitles,$cat_titles,$cat_order,$num) = @_; my $output; my %rowtitle = &Apache::lonlocal::texthash ( instcode => 'Course Category', crosslist => 'Cross Listed Course', ); my %helpitem = ( instcode => 'Course_Request_Category', ); if ((ref($codetitles) eq 'ARRAY') && (ref($cat_titles) eq 'HASH') && (ref($cat_order))) { my ($sel,$instsec,$lcsec); $sel = $context; if ($context eq 'crosslist') { $sel .= '_'.$num; $instsec = &mt('Institutional section').'
'. ''; $lcsec = &mt('LON-CAPA section').'
'. ''; } if (@{$codetitles} > 0) { my $lastitem = pop(@{$codetitles}); my $lastinput = ''; if (@{$codetitles} > 0) { my $helplink; if (defined($helpitem{$context})) { $helplink = &Apache::loncommon::help_open_topic($helpitem{$context}).' '; } $output = &Apache::lonhtmlcommon::row_title($helplink.$rowtitle{$context}). ''; if ($context eq 'crosslist') { $output .= ''; } foreach my $title (@{$codetitles}) { if (ref($cat_order->{$title}) eq 'ARRAY') { if (@{$cat_order->{$title}} > 0) { $output .= ''."\n"; } } if ($context eq 'crosslist') { $output .= ''. '
'.&mt('Include?').'
'. '
'.$title.'
'."\n". '
'.$lastitem.'
'."\n". $lastinput.'
'.$instsec.''.$lcsec.'
'; } else { $output .= ''. &Apache::lonhtmlcommon::row_closure(). &Apache::lonhtmlcommon::row_title('Course '.$lastitem). $lastinput; } } else { if ($context eq 'crosslist') { $output .= &Apache::lonhtmlcommon::row_title($rowtitle{$context}). ''. ''. ''. '
'.$lastitem.'
'.$lastinput.'
'.$instsec.''.$lcsec.'
'; } else { $output .= &Apache::lonhtmlcommon::row_title('Course '.$lastitem). $lastinput; } } $output .= &Apache::lonhtmlcommon::row_closure(1); push(@$codetitles,$lastitem); } elsif ($context eq 'crosslist') { $output .= &Apache::lonhtmlcommon::row_title($rowtitle{$context}). '
'. ''.&mt('Include?'). ''. ''.&mt('Institutional ID').'
'. ''. '
'.$lcsec.'
'. &Apache::lonhtmlcommon::row_closure(1); } } return $output; } sub sections_form { my ($dom,$instcode,$num) = @_; my $rowtitle; if ($instcode eq '') { $rowtitle = &mt('Sections'); } else { $rowtitle = &mt('Sections of [_1]',$instcode); } return &Apache::lonhtmlcommon::row_title($rowtitle). '
'. ''.&mt('Include?'). ''. ''.&mt('Institutional section').'
'. ''. '
'.&mt('LON-CAPA section').'
'. ''. '
'. &Apache::lonhtmlcommon::row_closure(1); } sub get_course_dom { my $codedom = &Apache::lonnet::default_login_domain(); if ($env{'form.showdom'} ne '') { if (&Apache::lonnet::domain($env{'form.showdom'}) ne '') { return $env{'form.showdom'}; } } if (($env{'user.domain'} ne '') && ($env{'user.domain'} ne 'public')) { my ($types,$typename) = &Apache::loncommon::course_types(); if (ref($types) eq 'ARRAY') { foreach my $type (@{$types}) { if (&Apache::lonnet::usertools_access($env{'user.name'}, $env{'user.domain'},$type, undef,'requestcourses')) { return $env{'user.domain'}; } } my @possible_doms; foreach my $type (@{$types}) { my $dom_str = $env{'environment.reqcrsotherdom.'.$type}; if ($dom_str ne '') { my @domains = split(',',$dom_str); foreach my $entry (@domains) { my ($extdom,$extopt) = split(':',$entry); if ($extdom eq $env{'request.role.domain'}) { return $extdom; } unless(grep(/^\Q$extdom\E$/,@possible_doms)) { push(@possible_doms,$extdom); } } } } if (@possible_doms) { @possible_doms = sort(@possible_doms); return $possible_doms[0]; } } $codedom = $env{'user.domain'}; if ($env{'request.role.domain'} ne '') { $codedom = $env{'request.role.domain'}; } } return $codedom; } sub display_navbuttons { my ($r,$dom,$formname,$prev,$prevtext,$next,$nexttext,$state,$other,$othertext) = @_; $r->print('
'); if ($prev) { $r->print(''. (' 'x3)); } elsif ($prevtext) { $r->print(''.(' 'x3)); } if ($state eq 'details') { $r->print(' '); } my $gotnext; if ($state eq 'courseinfo') { $r->print(''); $gotnext = 1; } elsif ($state eq 'enrollment') { if (($env{'form.crstype'} eq 'official') && (&Apache::lonnet::auto_run('',$dom))) { $r->print(''); $gotnext = 1; } } elsif ($state eq 'personnel') { if ($env{'form.persontotal'} > 0) { $r->print(''); $gotnext = 1; } } unless ($gotnext) { if ($next) { $r->print(' '); } } $r->print('
'); } sub print_request_outcome { my ($r,$lonhost,$dom,$codetitles,$code_order,$instcredits) = @_; my ($output,$cnum,$now,$req_notifylist,$crstype,$enrollstart,$enrollend, %sections,%crosslistings,%personnel,@baduname,@missingdom,%domconfig, $uniquecode); my $sectotal = $env{'form.sectotal'}; my $crosslisttotal = 0; $cnum = $env{'form.cnum'}; unless ($cnum =~ /^$match_courseid$/) { $output = &mt('Invalid LON-CAPA course number for the new course')."\n"; return $output; } $crstype = $env{'form.crstype'}; my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$dom); if (ref($domconfig{'requestcourses'}) eq 'HASH') { if (ref($domconfig{'requestcourses'}{'notify'}) eq 'HASH') { $req_notifylist = $domconfig{'requestcourses'}{'notify'}{'approval'}; } if (ref($domconfig{'requestcourses'}{'uniquecode'}) eq 'HASH') { $uniquecode = $domconfig{'requestcourses'}{'uniquecode'}{$crstype}; } } $now = time; my $ccrole = 'cc'; if ($crstype eq 'community') { $ccrole = 'co'; } my @instsections; if ($crstype eq 'official') { if (&Apache::lonnet::auto_run('',$dom)) { ($enrollstart,$enrollend)=&dates_from_form('enrollstart','enrollend'); } for (my $i=0; $i<$env{'form.sectotal'}; $i++) { if ($env{'form.sec_'.$i}) { if ($env{'form.secnum_'.$i} ne '') { my $sec = $env{'form.secnum_'.$i}; $sections{$i}{'inst'} = $sec; if (($sec ne '') && (!grep(/^\Q$sec\E$/,@instsections))) { push(@instsections,$sec); } $sections{$i}{'loncapa'} = $env{'form.loncapasec_'.$i}; $sections{$i}{'loncapa'} =~ s/\W//g; if ($sections{$i}{'loncapa'} eq 'none') { $sections{$i}{'loncapa'} = ''; } } } } for (my $i=0; $i<$env{'form.crosslisttotal'}; $i++) { if ($env{'form.crosslist_'.$i}) { my $xlistinfo = ''; if (ref($code_order) eq 'ARRAY') { if (@{$code_order} > 0) { foreach my $item (@{$code_order}) { $xlistinfo .= $env{'form.crosslist_'.$i.'_'.$item}; } } } $crosslistings{$i}{'instcode'} = $xlistinfo; if ($xlistinfo ne '') { $crosslisttotal ++; } $crosslistings{$i}{'instsec'} = $env{'form.crosslist_'.$i.'_instsec'}; $crosslistings{$i}{'loncapa'} = $env{'form.crosslist_'.$i.'_lcsec'}; } } } else { $enrollstart = ''; $enrollend = ''; } my (%alerts,%rulematch,%inst_results,%curr_rules,%got_rules,%disallowmsg,%skipped); for (my $i=0; $i<$env{'form.persontotal'}; $i++) { my $uname = $env{'form.person_'.$i.'_uname'}; my $udom = $env{'form.person_'.$i.'_dom'}; if (($uname =~ /^$match_username$/) && ($udom =~ /^$match_domain$/)) { if (&Apache::lonnet::domain($udom) ne '') { unless (ref($personnel{$uname.':'.$udom}) eq 'HASH') { $personnel{$uname.':'.$udom} = { firstname => $env{'form.person_'.$i.'_firstname'}, lastname => $env{'form.person_'.$i.'_lastname'}, emailaddr => $env{'form.person_'.$i.'_emailaddr'}, }; if (&Apache::lonnet::homeserver($uname,$udom) eq 'no_host') { my $usertype = &get_usertype($udom,$uname,\%curr_rules,\%got_rules); if (&Apache::lonuserutils::can_create_user($udom,'requestcrs',$usertype)) { my ($allowed,$msg,$authtype,$authparam) = &check_newuser_rules($udom,$uname,\%alerts,\%rulematch, \%inst_results,\%curr_rules,\%got_rules); if ($allowed) { my %domdefaults = &Apache::lonnet::get_domain_defaults($udom); if ($usertype eq 'official') { if ($authtype eq '') { $authtype = $domdefaults{'auth_def'}; $authparam = $domdefaults{'auth_arg_def'}; } else { if ($authtype eq 'loc') { $authtype = 'localauth'; } elsif ($authtype eq 'int') { $authtype = 'internal'; } if ($authtype !~ /^(krb4|krb5|internal|localauth)$/) { $authtype = $domdefaults{'auth_def'}; $authparam = $domdefaults{'auth_arg_def'}; } } } elsif ($usertype eq 'unofficial') { if ($authtype eq '') { $authtype = 'internal'; $authparam = ''; } } else { $authtype = $domdefaults{'auth_def'}; $authparam = $domdefaults{'auth_arg_def'}; } if (($authtype eq '') || (($authtype =~/^krb(4|5)$/) && ($authparam eq '')) || ($authtype !~ /^(krb4|krb5|internal|localauth)$/)) { $skipped{$uname.':'.$udom} = 1; next; } else { $personnel{$uname.':'.$udom}{'authtype'} = $authtype; $personnel{$uname.':'.$udom}{'autharg'} = $authparam; } } else { $skipped{$uname.':'.$udom} = 1; next; } } else { $skipped{$uname.':'.$udom} = 1; next; } } } my $role = $env{'form.person_'.$i.'_role'}; unless ($role eq '') { if (ref($personnel{$uname.':'.$udom}{'roles'}) eq 'ARRAY') { my @curr_roles = @{$personnel{$uname.':'.$udom}{'roles'}}; unless (grep(/^\Q$role\E$/,@curr_roles)) { push(@{$personnel{$uname.':'.$udom}{'roles'}},$role); } } else { @{$personnel{$uname.':'.$udom}{'roles'}} = ($role); } if ($role eq $ccrole) { @{$personnel{$uname.':'.$udom}{$role}{'usec'}} = (); } else { my @currsec = &Apache::loncommon::get_env_multiple('form.person_'.$i.'_sec'); my @allsecs; foreach my $sec (@currsec) { next unless ($sec =~ /\w/); next if ($sec =~ /\W/); next if ($sec eq 'none'); push(@allsecs,$sec); } my $newsec = $env{'form.person_'.$i.'_newsec'}; $newsec =~ s/^\s+//; $newsec =~s/\s+$//; my @newsecs = split(/[\s,;]+/,$newsec); foreach my $sec (@newsecs) { next if ($sec =~ /\W/); next if ($sec eq 'none'); if ($sec ne '') { unless (grep(/^\Q$sec\E$/,@allsecs)) { push(@allsecs,$sec); } } } @{$personnel{$uname.':'.$udom}{$role}{'usec'}} = @allsecs; } } } else { push(@missingdom,$uname.':'.$udom); } } else { push(@baduname,$uname.':'.$udom); } } if (keys(%skipped)) { foreach my $key (keys(%skipped)) { delete($personnel{$key}); } } my ($accessstart,$accessend) = &dates_from_form('accessstart','accessend'); my $autodrops = 0; if ($env{'form.autodrops'}) { $autodrops = $env{'form.autodrops'}; } my $autoadds = 0; if ($env{'form.autoadds'}) { $autoadds = $env{'form.autoadds'}; } my $instcode = ''; if (exists($env{'form.instcode'})) { $instcode = $env{'form.instcode'}; } my $credits; if ($instcredits) { $credits = $instcredits; } elsif (exists($env{'form.coursecredits'})) { $credits = $env{'form.coursecredits'}; } my $clonecrs = ''; my $clonedom = ''; if (($env{'form.cloning'}) && ($env{'form.clonecrs'} =~ /^($match_courseid)$/) && ($env{'form.clonedom'} =~ /^($match_domain)$/)) { my $clonehome = &Apache::lonnet::homeserver($env{'form.clonecrs'}, $env{'form.clonedom'}); if ($clonehome ne 'no_host') { my $canclone = &Apache::loncoursequeueadmin::can_clone_course($env{'user.name'}, $env{'user.domain'},$env{'form.clonecrs'},$env{'form.clonedom'}, $crstype,$dom,$instcode); if ($canclone) { $clonecrs = $env{'form.clonecrs'}; $clonedom = $env{'form.clonedom'}; } } } my $details = { owner => $env{'user.name'}, domain => $env{'user.domain'}, cdom => $dom, cnum => $cnum, coursehome => $env{'form.chome'}, cdescr => $env{'form.cdescr'}, crstype => $env{'form.crstype'}, instcode => $instcode, defaultcredits => $credits, uniquecode => $uniquecode, clonedom => $clonedom, clonecrs => $clonecrs, datemode => $env{'form.datemode'}, dateshift => $env{'form.dateshift'}, sectotal => $sectotal, sections => \%sections, crosslisttotal => $crosslisttotal, crosslists => \%crosslistings, autoadds => $autoadds, autodrops => $autodrops, enrollstart => $enrollstart, enrollend => $enrollend, accessstart => $accessstart, accessend => $accessend, personnel => \%personnel, }; my ($result,$output) = &process_request($r,$lonhost,$dom,$cnum,$crstype,$now,$details,$instcode, $req_notifylist,\@instsections,\%domconfig); return ($result,$output); } sub process_request { my ($r,$lonhost,$dom,$cnum,$crstype,$now,$details,$instcode,$req_notifylist,$instsections, $domconfig) = @_; my (@inststatuses,$storeresult,$creationresult,$output); my $val = &Apache::loncoursequeueadmin::get_processtype('course',$env{'user.name'}, $env{'user.domain'},$env{'user.adv'}, $dom,$crstype,\@inststatuses,$domconfig); if ($val eq '') { if ($crstype eq 'official') { $output = &mt('You are not permitted to request creation of official courses.'); } elsif ($crstype eq 'unofficial') { $output = &mt('You are not permitted to request creation of unofficial courses.'); } elsif ($crstype eq 'community') { $output = &mt('You are not permitted to request creation of communities'); } elsif ($crstype eq 'textbook') { $output = &mt('You are not permitted to request creation of textbook courses'); } else { $output = &mt('Unrecognized course type: [_1]',$crstype); } $storeresult = 'notpermitted'; } else { my ($disposition,$message,$reqstatus,$coursedesc); my %reqhash = ( reqtime => $now, crstype => $crstype, details => $details, ); my $requestkey = $dom.'_'.$cnum; my $validationerror; my $fullname = &Apache::loncommon::plainname($env{'user.name'}, $env{'user.domain'}); if (ref($details) eq 'HASH') { $coursedesc = $details->{'cdescr'}; } if ($val eq 'autolimit=') { $disposition = 'process'; } elsif ($val =~ /^autolimit=(\d+)$/) { my $limit = $1; $disposition = &check_autolimit($env{'user.name'},$env{'user.domain'}, $dom,$crstype,$limit,\$message); } elsif ($val eq 'validate') { my ($inststatuslist,$validationchk,$validation,%custominfo); if (ref($details) eq 'HASH') { if ($details->{'clonecrs'}) { $custominfo{'_LC_clonefrom'} = $details->{'clonedom'}.'_'.$details->{'clonecrs'}; } } if (@inststatuses > 0) { $inststatuslist = join(',',@inststatuses); } my $instseclist; if (ref($instsections) eq 'ARRAY') { if (@{$instsections} > 0) { $instseclist = join(',',@{$instsections}); } } my $preprocess = &Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,'prevalidate',$env{'user.name'}, $env{'user.domain'},$fullname,$coursedesc); if (ref($preprocess) eq 'HASH') { if (ref($preprocess->{'formitems'}) eq 'HASH') { foreach my $key (keys(%{$preprocess->{'formitems'}})) { if ($preprocess->{'formitems'}->{$key} eq 'multiple') { if (exists($env{'form.'.$key})) { @{$custominfo{$key}} = &Apache::loncommon::get_env_multiple($env{'form.'.$key}); } } else { if (exists($env{'form.'.$key})) { $custominfo{$key} = $env{'form.'.$key}; } } } } } $validationchk = &Apache::lonnet::auto_courserequest_validation($dom, $env{'user.name'}.':'.$env{'user.domain'},$crstype, $inststatuslist,$instcode,$instseclist,\%custominfo); if ($validationchk =~ /:/) { ($validation,$message) = split(':',$validationchk); } else { $validation = $validationchk; } if ($validation =~ /^error(.*)$/) { $disposition = 'approval'; $validationerror = $1; } else { $disposition = $validation; } } else { $disposition = 'approval'; } $reqhash{'disposition'} = $disposition; $reqstatus = $disposition; my ($modified,$queued,$coursedesc,$token,%customitems); unless ($disposition eq 'rejected') { my $inprocess = &Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,'process',$env{'user.name'}, $env{'user.domain'},$fullname,$coursedesc); if (ref($inprocess) eq 'HASH') { if (ref($inprocess->{'formitems'}) eq 'HASH') { foreach my $key (keys(%{$inprocess->{'formitems'}})) { if ($inprocess->{'formitems'}->{$key} eq 'multiple') { if (exists($env{'form.'.$key})) { @{$customitems{$key}} = &Apache::loncommon::get_env_multiple($env{'form.'.$key}); } } else { if (exists($env{'form.'.$key})) { $customitems{$key} = $env{'form.'.$key}; $reqhash{'custom'}{$key} = $customitems{$key}; } } } } } } if ($disposition eq 'rejected') { if ($crstype eq 'community') { $output = &mt('Your community request was rejected.'); } else { $output = &mt('Your course request was rejected.'); } if ($message) { $output .= '
'.$message.'
'; } $storeresult = 'rejected'; } elsif ($disposition eq 'process') { my %domdefs = &Apache::lonnet::get_domain_defaults($dom); my ($logmsg,$newusermsg,$addresult,$enrollcount,$response,$keysmsg,%longroles,$code); my $type = 'Course'; if ($crstype eq 'community') { $type = 'Community'; } my @roles = &Apache::lonuserutils::roles_by_context('course','',$type); foreach my $role (@roles) { $longroles{$role}=&Apache::lonnet::plaintext($role,$type); } $r->print('
'."\n". &mt('Your request is being processed; this page will update when processing is complete.'). '
'); $r->rflush(); if (ref($details) eq 'HASH') { if ($details->{'clonecrs'}) { $customitems{'_LC_clonefrom'} = $details->{'clonedom'}.'_'.$details->{'clonecrs'}; } } my ($result,$postprocess) = &Apache::loncoursequeueadmin::course_creation($dom,$cnum, 'autocreate',$details,\$logmsg,\$newusermsg,\$addresult, \$enrollcount,\$response,\$keysmsg,\%domdefs,\%longroles, \$code,\%customitems); if ($result eq 'created') { $disposition = 'created'; $reqstatus = 'created'; my $role_result = &update_requestors_roles($dom,$cnum,$crstype,$details, \%longroles); if ($crstype eq 'community') { $output = '

'.&mt('Your community request has been processed and the community has been created.'); } else { $output = '

'.&mt('Your course request has been processed and the course has been created.'); } if (($code) || ((ref($postprocess) eq 'HASH') && (($postprocess->{'createdweb'}) || ($postprocess->{'createdmsg'})))) { $output .= ¬ification_information($disposition,$env{'user.name'}.':'.$env{'user.domain'}, $dom,$cnum,$now,$code,$postprocess); } if ($code) { $reqhash{'code'} = $code; } if (ref($postprocess) eq 'HASH') { if (ref($postprocess->{'createdactions'}) eq 'HASH') { if (ref($postprocess->{'createdactions'}{'environment'}) eq 'HASH') { &Apache::loncoursequeueadmin::postprocess_crsenv($dom,$cnum, $postprocess->{'createdactions'}{'environment'}); } } } $output .= '
'.$role_result.'

'; $creationresult = 'created'; } else { $output = ''; if ($crstype eq 'community') { $output .= &mt('An error occurred when processing your community request.'); } else { $output .= &mt('An error occurred when processing your course request.'); } $output .= '
'. &mt('You may want to review the request details and submit the request again.'). '
'; $creationresult = 'error'; } } else { my $requestid = $cnum.'_'.$disposition; my $request = { $requestid => { timestamp => $now, crstype => $crstype, ownername => $env{'user.name'}, ownerdom => $env{'user.domain'}, description => $env{'form.cdescr'}, lonhost => $lonhost, }, }; if ($crstype eq 'official') { $request->{$requestid}->{'instcode'} = $instcode; } my $statuskey = 'status:'.$dom.':'.$cnum; my %userreqhash = &Apache::lonnet::get('courserequests',[$statuskey], $env{'user.domain'},$env{'user.name'}); if ($userreqhash{$statuskey} ne '') { $modified = 1; my $uname = &Apache::lonnet::get_domainconfiguser($dom); my %queuehash = &Apache::lonnet::get('courserequestqueue', [$cnum.'_approval', $cnum.'_pending'],$dom,$uname); if (($queuehash{$cnum.'_approval'} ne '') || ($queuehash{$cnum.'_pending'} ne '')) { $queued = 1; if (ref($queuehash{$cnum.'_pending'}) eq 'HASH') { $token = $queuehash{$cnum.'_pending'}{'token'}; } } } unless ($queued) { if (($disposition eq 'pending') && ($crstype ne 'official')) { my %reqinfo = ( $cnum.':'.$dom => $now.':'.$env{'user.name'}.':'.$env{'user.domain'}, ); $token = &Apache::lonnet::tmpput(\%reqinfo,$lonhost); $request->{$requestid}->{'token'} = $token; } my $putresult = &Apache::lonnet::newput_dom('courserequestqueue',$request, $dom); if ($putresult eq 'ok') { if ($crstype eq 'community') { $output .= &mt('Your community request has been recorded.'); } else { $output .= &mt('Your course request has been recorded.') } unless ($disposition eq 'pending') { $output .= '
'. ¬ification_information($disposition,$req_notifylist, $dom,$cnum,$now); } } else { $reqstatus = 'domainerror'; $reqhash{'disposition'} = $disposition; my $warning = &mt('An error occurred saving your request in the pending requests queue.'); $output = ''.$warning.'
'; } } } ($storeresult,my $updateresult) = &Apache::loncoursequeueadmin::update_coursereq_status(\%reqhash,$dom, $cnum,$reqstatus,'request',$env{'user.domain'},$env{'user.name'}); if ($storeresult eq 'ok') { my $postprocess; if (($disposition eq 'approval') || ($disposition eq 'pending')) { my $updateaction = $disposition; if ($disposition eq 'approval') { $updateaction = 'queued'; } my $fullname = &Apache::loncommon::plainname($env{'user.name'}, $env{'user.domain'}); $postprocess = &Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,$updateaction,$env{'user.name'}, $env{'user.domain'},$fullname,$env{'form.cdescr'}); } if ($modified && $queued) { if ($crstype eq 'community') { $output .= '

'.&mt('Your community request has been updated').'

'; } else { $output .= '

'.&mt('Your course request has been updated').'

'; } if ($disposition eq 'approval') { $output .= ¬ification_information($disposition,$req_notifylist,$dom,$cnum,$now); } } if ($disposition eq 'approval') { if ((ref($postprocess) eq 'HASH') && ((ref($postprocess->{'queuedmsg'}) eq 'HASH') || ($postprocess->{'queuedweb'}))) { ¬ification_information($disposition,undef,$dom,$cnum,$now,undef,$postprocess); } } elsif ($disposition eq 'pending') { my $pendingform; if ($crstype ne 'official') { $pendingform = &pending_validation_form($dom,$cnum,$crstype,$now,$token, $lonhost,$env{'form.cdescr'}); } if ($pendingform) { $output .= $pendingform; } else { $output .= ¬ification_information($disposition,undef,$dom,$cnum,$now,undef,$postprocess); } } } if ($validationerror ne '') { $output .= '

'.&mt('An error occurred validating your request with institutional data sources: [_1].',$validationerror).'

'; } if ($updateresult) { $output .= $updateresult; } } if ($creationresult ne '') { return ($creationresult,$output); } else { return ($storeresult,$output); } } sub update_requestors_roles { my ($dom,$cnum,$crstype,$details,$longroles) = @_; my $now = time; my ($active,$future,$numactive,$numfuture,$output); my $owner = $env{'user.name'}.':'.$env{'user.domain'}; if (ref($details) eq 'HASH') { if (ref($details->{'personnel'}) eq 'HASH') { my $ccrole = 'cc'; if ($crstype eq 'community') { $ccrole = 'co'; } unless (ref($details->{'personnel'}{$owner}) eq 'HASH') { $details->{'personnel'}{$owner} = { 'roles' => [$ccrole], $ccrole => { 'usec' => [] }, }; } my @roles; if (ref($details->{'personnel'}{$owner}{'roles'}) eq 'ARRAY') { @roles = sort(@{$details->{'personnel'}{$owner}{'roles'}}); unless (grep(/^\Q$ccrole\E$/,@roles)) { push(@roles,$ccrole); } } else { @roles = ($ccrole); } foreach my $role (@roles) { my $refresh=$env{'user.refresh.time'}; if ($refresh eq '') { $refresh = $env{'user.login.time'}; } if ($refresh eq '') { $refresh = $now; } my $start = $refresh-1; my $end = '0'; if ($role eq 'st') { if ($details->{'accessstart'} ne '') { $start = $details->{'accessstart'}; } if ($details->{'accessend'} ne '') { $end = $details->{'accessend'}; } } my @usecs; if ($role ne $ccrole) { if (ref($details->{'personnel'}{$owner}{$role}{'usec'}) eq 'ARRAY') { @usecs = @{$details->{'personnel'}{$owner}{$role}{'usec'}}; } } if ($role eq 'st') { if (@usecs > 1) { my $firstsec = $usecs[0]; @usecs = ($firstsec); } } if (@usecs == 0) { push(@usecs,''); } foreach my $usec (@usecs) { my (%userroles,%newrole,%newgroups,$spec,$area); my $area = '/'.$dom.'/'.$cnum; my $spec = $role.'.'.$area; if ($usec ne '') { $spec .= '/'.$usec; $area .= '/'.$usec; } if ($role =~ /^cr\//) { &Apache::lonnet::custom_roleprivs(\%newrole,$role,$dom, $cnum,$spec,$area); } else { &Apache::lonnet::standard_roleprivs(\%newrole,$role,$dom, $spec,$cnum,$area); } &Apache::lonnet::set_userprivs(\%userroles,\%newrole, \%newgroups); $userroles{'user.role.'.$spec} = $start.'.'.$end; &Apache::lonnet::appenv(\%userroles,[$role,'cm']); if (($end == 0) || ($end > $now)) { my $showrole = $role; if ($role =~ /^cr\//) { $showrole = &Apache::lonnet::plaintext($role,$crstype); } elsif (ref($longroles) eq 'HASH') { if ($longroles->{$role} ne '') { $showrole = $longroles->{$role}; } } if ($start <= $now) { $active .= '
  • '.$showrole; if ($usec ne '') { $active .= ' - '.&mt('section:').' '.$usec; } $active .= '
  • '; $numactive ++; } else { $future .= '
  • '.$showrole; if ($usec ne '') { $future .= ' - '.&mt('section:').' '.$usec; } $future .= '
  • '; $numfuture ++; } } } } } } if ($active) { if ($numactive == 1) { if ($crstype eq 'Community') { $output = &mt('Use the following link to enter the community:'); } else { $output = &mt('Use the following link to enter the course:'); } } else { if ($crstype eq 'Community') { $output = &mt('Use the following links to your new roles to enter the community:'); } else { $output = &mt('Use the following links to your new roles to enter the course:'); } } $output .= '
      '.$active.'

    '; } if ($future) { if ($crstype eq 'Community') { $output .= &mt('The following community [quant,_1,role] will become available for selection from your [_2]roles page[_3], once the default student access start date - [_4] - has been reached:',$numfuture,'','',&Apache::lonlocal::locallocaltime($details->{'accessstart'})) } else { $output .= &mt('The following course [quant,_1,role] will become available for selection from your [_2]roles page[_3], once the default student access start date - [_4] - has been reached:',$numfuture,'','',&Apache::lonlocal::locallocaltime($details->{'accessstart'})); } $output .= '
      '.$future.'
    '; } return $output; } sub notification_information { my ($disposition,$req_notifylist,$dom,$cnum,$now,$code,$postprocess) = @_; my %emails = &Apache::loncommon::getemails(); my $address; if (($emails{'permanentemail'} ne '') || ($emails{'notification'} ne '')) { $address = $emails{'permanentemail'}; if ($address eq '') { $address = $emails{'notification'}; } } my $output; if ($disposition eq 'approval') { $output .= &mt('A message will be sent to your LON-CAPA account when a domain coordinator takes action on your request.').'
    '. &mt('To access your LON-CAPA message, go to the Main Menu and click on "Send and Receive Messages".').'
    '; if ($address ne '') { $output.= &mt('An e-mail will also be sent to: [_1] when this occurs.',$address).'
    '; } if ($req_notifylist) { my $fullname = &Apache::loncommon::plainname($env{'user.name'}, $env{'user.domain'}); my $sender = $env{'user.name'}.':'.$env{'user.domain'}; &Apache::loncoursequeueadmin::send_selfserve_notification($req_notifylist,"$fullname ($env{'user.name'}:$env{'user.domain'})", 'undef',$env{'form.cdescr'},$now,'coursereq',$sender); } if (ref($postprocess) eq 'HASH') { if (ref($postprocess->{'queuedmsg'}) eq 'ARRAY') { if (scalar(@{$postprocess->{'queuedmsg'}}) > 0) { my $recipient = $env{'user.name'}.':'.$env{'user.domain'}; my $sender = $recipient; my $addmsg = []; foreach my $item (@{$postprocess->{'queuedmsg'}}) { if (ref($item) eq 'HASH') { if ($item->{'mt'} ne '') { push(@{$addmsg},$item); } } } if (scalar(@{$addmsg}) > 0) { &Apache::loncoursequeueadmin::send_selfserve_notification($recipient,$addmsg,undef, $env{'form.cdescr'},$now, 'queuedcrsreq',$sender); } } } if ($postprocess->{'queuedweb'}) { $output .= $postprocess->{'queuedweb'}; } } } elsif ($disposition eq 'pending') { my $pending_default = '
    '. &mt('Your request has been placed in a queue pending administrative action.').'
    '. &mt("Usually this means that your institution's information systems do not list you among the instructional personnel for this course.").'
    '. &mt('The list of instructional personnel for the course will be automatically checked daily, and once you are listed the request will be processed.'). '
    '; if (ref($postprocess) eq 'HASH') { if ($postprocess->{'pendingweb'}) { $output .= $postprocess->{'pendingweb'}; } else { $output .= $pending_default; } } else { $output .= $pending_default; } } elsif ($disposition eq 'created') { if (($code) || ((ref($postprocess) eq 'HASH') && ((ref($postprocess->{'createdmsg'}) eq 'ARRAY') || ($postprocess->{'createdweb'})))) { my $addmsg = []; my $recipient = $env{'user.name'}.':'.$env{'user.domain'}; my $sender = $recipient; if ($code) { push(@{$addmsg},{ mt => 'Students can automatically select your course: "[_1]" by entering this code: [_2]', args => [$env{'form.cdescr'},$code], }); $output .= '

    '. &mt('Students can automatically select your course by entering this code: [_1].',''.$code.''). '
    '. &mt('A message has been sent to your LON-CAPA account with this information.'); if ($address ne '') { $output.= '
    '.&mt('An e-mail has also been sent to: [_1] with this code.',$address); } $output .= '

    '; } if (ref($postprocess) eq 'HASH') { if (ref($postprocess->{'createdmsg'}) eq 'ARRAY') { foreach my $item (@{$postprocess->{'createdmsg'}}) { if (ref($item) eq 'HASH') { if ($item->{'mt'} ne '') { push(@{$addmsg},$item); } } } } if ($postprocess->{'createdweb'}) { $output .= $postprocess->{'createdweb'} } } if (scalar(@{$addmsg}) > 0) { my $type = 'createdcrsreq'; if ($code) { $type = 'uniquecode'; } &Apache::loncoursequeueadmin::send_selfserve_notification($recipient,$addmsg,$dom.'_'.$cnum,$env{'form.cdescr'}, $now,$type,$sender); } } } else { $output .= '
    '. &mt('Your request status is: [_1].',$disposition). '
    '; } return $output; } sub pending_validation_form { my ($cdom,$cnum,$crstype,$now,$token,$lonhost,$cdesc) = @_; my $output; my %postvalues = ( 'owner' => $env{'user.name'}.':'.$env{'user.domain'}, 'course' => $cdom.'_'.$cnum, 'coursetype' => $crstype, ); my %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$cdom); if (ref($domconfig{'requestcourses'}) eq 'HASH') { my ($url,$buttontext,$code,@fields); if (ref($domconfig{'requestcourses'}{'validation'}) eq 'HASH') { $postvalues{'description'} = $cdesc; $url = $domconfig{'requestcourses'}{'validation'}{'url'}; if (ref($domconfig{'requestcourses'}{'validation'}{'fields'}) eq 'ARRAY') { @fields = @{$domconfig{'requestcourses'}{'validation'}{'fields'}}; } $buttontext = $domconfig{'requestcourses'}{'validation'}{'button'}; $output .= $domconfig{'requestcourses'}{'validation'}{'markup'}; if (($url =~ m{^(https?\://|/)}) && (@fields > 0)) { $output .= '
    '."\n"; foreach my $field (@fields) { if ($postvalues{$field}) { $output .= ''."\n"; } } if ($buttontext eq '') { if ($crstype eq 'community') { $buttontext = &mt('Create community'); } else { $buttontext = &mt('Create course'); } } my $protocol = $Apache::lonnet::protocol{$lonhost}; $protocol = 'http' if ($protocol ne 'https'); my $crscreator = $protocol.'://'.&Apache::lonnet::hostname($lonhost).'/cgi-bin/createpending.pl'; $output .= ''."\n". ''."\n". ''."\n". '
    '."\n"; } } } return $output; } sub check_autolimit { my ($uname,$udom,$dom,$crstype,$limit,$message) = @_; my %crsroles = &Apache::lonnet::get_my_roles($env{'user.name'},$env{'user.domain'}, 'userroles',['active','future'],['cc','co'],[$dom]); my ($types,$typename) = &Apache::loncommon::course_types(); my %requests = &Apache::lonnet::dumpstore('courserequests',$udom,$uname); my $count = 0; foreach my $key (keys(%requests)) { my ($cdom,$cnum) = split('_',$key); if (ref($requests{$key}) eq 'HASH') { next if ($requests{$key}{'crstype'} ne $crstype); if (($crstype eq 'community') && (exists($crsroles{$cnum.':'.$cdom.':co'}))) { $count ++; } elsif ((($crstype eq 'official') || ($crstype eq 'unofficial') || ($crstype eq 'textbook')) && (exists($crsroles{$cnum.':'.$cdom.':cc'}))) { $count ++; } } } if ($count < $limit) { return 'process'; } else { if (ref($typename) eq 'HASH') { if ($crstype eq 'community') { $$message = &mt('Your request has not been processed because you have reached the limit for the number of communities.'). '
    '.&mt("Your limit is [_1].",$limit); } else { $$message = &mt('Your request has not been processed because you have reached the limit for the number of courses of this type.'). '
    '.&mt("Your $typename->{$crstype} limit is [_1].",$limit); } } return 'rejected'; } return; } sub retrieve_settings { my ($dom,$cnum,$udom,$uname) = @_; if ($udom eq '' || $uname eq '') { $udom = $env{'user.domain'}; $uname = $env{'user.name'}; } my ($result,%reqinfo) = &get_request_settings($dom,$cnum,$udom,$uname); if ($result eq 'ok') { if (($udom eq $reqinfo{'domain'}) && ($uname eq $reqinfo{'owner'})) { $env{'form.chome'} = $reqinfo{'coursehome'}; $env{'form.cdescr'} = $reqinfo{'cdescr'}; $env{'form.crstype'} = $reqinfo{'crstype'}; &generate_date_items($reqinfo{'accessstart'},'accessstart'); &generate_date_items($reqinfo{'accessend'},'accessend'); if ($reqinfo{'accessend'} == 0) { $env{'form.no_end_date'} = 1; } if (($reqinfo{'crstype'} eq 'official') && (&Apache::lonnet::auto_run('',$dom))) { &generate_date_items($reqinfo{'enrollstart'},'enrollstart'); &generate_date_items($reqinfo{'enrollend'},'enrollend'); } $env{'form.clonecrs'} = $reqinfo{'clonecrs'}; $env{'form.clonedom'} = $reqinfo{'clonedom'}; if (($reqinfo{'clonecrs'} ne '') && ($reqinfo{'clonedom'} ne '')) { $env{'form.cloning'} = 1; } $env{'form.datemode'} = $reqinfo{'datemode'}; $env{'form.dateshift'} = $reqinfo{'dateshift'}; if ($reqinfo{'crstype'} eq 'official') { $env{'form.autoadds'} = $reqinfo{'autoadds'}; $env{'form.autodrops'} = $reqinfo{'autodrops'}; if ($reqinfo{'instcode'} ne '') { $env{'form.sectotal'} = $reqinfo{'sectotal'}; $env{'form.crosslisttotal'} = $reqinfo{'crosslisttotal'}; $env{'form.instcode'} = $reqinfo{'instcode'}; my $crscode = { $cnum => $reqinfo{'instcode'}, }; &extract_instcode($dom,'instcode',$crscode,$cnum); (undef,undef,my $instcredits) = &Apache::lonnet::auto_validate_instcode(undef,$dom, $reqinfo{'instcode'}); if ($instcredits ne $reqinfo{'defaultcredits'}) { $env{'form.coursecredits'} = $reqinfo{'defaultcredits'}; } } } elsif (($reqinfo{'crstype'} eq 'unofficial') || ($reqinfo{'crstype'} eq 'textbook')) { $env{'form.coursecredits'} = $reqinfo{'defaultcredits'}; } my @currsec; if (ref($reqinfo{'sections'}) eq 'HASH') { foreach my $i (sort(keys(%{$reqinfo{'sections'}}))) { if (ref($reqinfo{'sections'}{$i}) eq 'HASH') { my $sec = $reqinfo{'sections'}{$i}{'inst'}; $env{'form.secnum_'.$i} = $sec; $env{'form.sec_'.$i} = '1'; if (!grep(/^\Q$sec\E$/,@currsec)) { push(@currsec,$sec); } $env{'form.loncapasec_'.$i} = $reqinfo{'sections'}{$i}{'loncapa'}; } } } if (ref($reqinfo{'crosslists'}) eq 'HASH') { foreach my $i (sort(keys(%{$reqinfo{'crosslists'}}))) { if (ref($reqinfo{'crosslists'}{$i}) eq 'HASH') { $env{'form.crosslist_'.$i} = '1'; $env{'form.crosslist_'.$i.'_instsec'} = $reqinfo{'crosslists'}{$i}{'instsec'}; $env{'form.crosslist_'.$i.'_lcsec'} = $reqinfo{'crosslists'}{$i}{'loncapa'}; if ($reqinfo{'crosslists'}{$i}{'instcode'} ne '') { my $key = $cnum.$i; my $crscode = { $key => $reqinfo{'crosslists'}{$i}{'instcode'}, }; &extract_instcode($dom,'crosslist',$crscode,$key,$i); } } } } if (ref($reqinfo{'personnel'}) eq 'HASH') { my $i = 0; foreach my $user (sort(keys(%{$reqinfo{'personnel'}}))) { my ($uname,$udom) = split(':',$user); if (ref($reqinfo{'personnel'}{$user}) eq 'HASH') { if (ref($reqinfo{'personnel'}{$user}{'roles'}) eq 'ARRAY') { foreach my $role (sort(@{$reqinfo{'personnel'}{$user}{'roles'}})) { $env{'form.person_'.$i.'_role'} = $role; $env{'form.person_'.$i.'_firstname'} = $reqinfo{'personnel'}{$user}{'firstname'}; $env{'form.person_'.$i.'_lastname'} = $reqinfo{'personnel'}{$user}{'lastname'}; ; $env{'form.person_'.$i.'_emailaddr'} = $reqinfo{'personnel'}{$user}{'emailaddr'}; $env{'form.person_'.$i.'_uname'} = $uname; $env{'form.person_'.$i.'_dom'} = $udom; if (ref($reqinfo{'personnel'}{$user}{$role}) eq 'HASH') { if (ref($reqinfo{'personnel'}{$user}{$role}{'usec'}) eq 'ARRAY') { my @usecs = @{$reqinfo{'personnel'}{$user}{$role}{'usec'}}; my @newsecs; if (@usecs > 0) { foreach my $sec (@usecs) { if (grep(/^\Q$sec\E/,@currsec)) { $env{'form.person_'.$i.'_sec'} = $sec; } else { push(@newsecs,$sec); } } } if (@newsecs > 0) { $env{'form.person_'.$i.'_newsec'} = join(',',@newsecs); } } } $i ++; } } } } $env{'form.persontotal'} = $i; } } } return $result; } sub get_request_settings { my ($dom,$cnum,$udom,$uname) = @_; my $requestkey = $dom.'_'.$cnum; my ($result,%reqinfo); if ($requestkey =~ /^($match_domain)_($match_courseid)$/) { my %history = &Apache::lonnet::restore($requestkey,'courserequests',$udom,$uname); my $disposition = $history{'disposition'}; if (($disposition eq 'approval') || ($disposition eq 'pending')) { if (ref($history{'details'}) eq 'HASH') { %reqinfo = %{$history{'details'}}; $result = 'ok'; } else { $result = 'nothash'; } } else { $result = 'notqueued'; } } else { $result = 'invalid'; } return ($result,%reqinfo); } sub extract_instcode { my ($cdom,$element,$crscode,$crskey,$counter) = @_; my (%codes,@codetitles,%cat_titles,%cat_order); if (&Apache::lonnet::auto_instcode_format('requests',$cdom,$crscode,\%codes, \@codetitles,\%cat_titles, \%cat_order) eq 'ok') { if (ref($codes{$crskey}) eq 'HASH') { if (@codetitles > 0) { my $sel = $element; if ($element eq 'crosslist') { $sel .= '_'.$counter; } foreach my $title (@codetitles) { $env{'form.'.$sel.'_'.$title} = $codes{$crskey}{$title}; } } } } return; } sub generate_date_items { my ($currentval,$item) = @_; if ($currentval =~ /\d+/) { my ($tzname,$sec,$min,$hour,$mday,$month,$year) = &Apache::lonhtmlcommon::get_timedates($currentval); $env{'form.'.$item.'_day'} = $mday; $env{'form.'.$item.'_month'} = $month+1; $env{'form.'.$item.'_year'} = $year; } return; } sub print_textbook_form { my ($r,$dom,$incdoms,$domdefs,$settings,$can_request) = @_; my (%prefab,%ordered,%numprefab); my $crstype = 'textbook'; # # Retrieve list of prefabricated courses (textbook courses and templates) cloneable by user # foreach my $type ('textbooks','templates') { $numprefab{$type} = 0; if (ref($settings) eq 'HASH') { $prefab{$type} = $settings->{$type}; if (ref($prefab{$type}) eq 'HASH') { foreach my $item (keys(%{$prefab{$type}})) { my ($clonedom,$clonecrs) = split(/_/,$item); if (ref($prefab{$type}{$item}) eq 'HASH') { if (&Apache::loncoursequeueadmin::can_clone_course($env{'user.name'}, $env{'user.domain'},$clonecrs,$clonedom,$crstype,$dom)) { my $num = $prefab{$type}{$item}{'order'}; $ordered{$type}{$num} = $item; $numprefab{$type} ++; } } } } } } # # Check if domain has multiple library servers # my ($home_server_pick,$numlib) = &Apache::loncommon::home_server_form_item($dom,'chome', 'default','hide'); if ($numlib > 1) { $home_server_pick = &mt('Home Server for Course').': '.$home_server_pick.'
    '; } # # Retrieve information about courses owned by user, or in which user has an active or future # Course Coordinator role # my $numcurrent; my %cloneable = &Apache::lonnet::courseiddump($dom,'.',1,'.',$env{'user.name'}.':'.$env{'user.domain'}, undef,undef,undef,'Course'); my %ccroles = &Apache::lonnet::get_my_roles($env{'user.name'},$env{'user.domain'},'userroles', ['active','future'],['cc']); foreach my $role (keys(%ccroles)) { my ($cnum,$cdom,$rest) = split(/:/,$role,3); unless (exists($cloneable{$cdom.'_'.$cnum})) { my %courseinfo = &Apache::lonnet::coursedescription($cdom.'_'.$cnum,{'one_time' => 1}); $cloneable{$cdom.'_'.$cnum} = \%courseinfo; } } my $numcurrent = scalar(keys(%cloneable)); my $jscript = &textbook_request_javascript(\%numprefab,$numcurrent); my %loaditems; $loaditems{'onload'} = 'javascript:uncheckAllRadio();'; $r->print(&header('Course Request',$jscript,\%loaditems)); if (ref($can_request) eq 'HASH') { unless ((scalar(keys(%{$can_request})) == 1) && ($can_request->{'textbook'})) { &Apache::lonhtmlcommon::add_breadcrumb( { href => '/adm/requestcourse', text => 'Pick action', }); } } &Apache::lonhtmlcommon::add_breadcrumb({text=>'Course Request'}); $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests')); &startContentScreen($r,'textbookrequests'); # # Show domain selector form, if required. # if (@{$incdoms} > 1) { my $onchange = 'this.form.submit()'; $r->print('
    '. '
    '.&mt('Domain').''. &Apache::loncommon::select_dom_form($dom,'showdom','',1,$onchange,$incdoms). '
    '); } # # Course request form # # # Course Title # $r->print('
    '. '
    '. '
    '. ''.&mt('Course Information').''. ''.&mt('Title').': '. '
    '. $home_server_pick.'
    '. '
    '); # # Content source selection, if more than one available # if (keys(%cloneable) || keys(%ordered)) { $r->print('
    '. '
    '.&mt('Course Content').''); if (keys(%ordered)) { if (ref($ordered{'textbooks'}) eq 'HASH') { $r->print(''.(' 'x2).' '); } if (ref($ordered{'templates'}) eq 'HASH') { $r->print(''.(' 'x2).' '); } } if (keys(%cloneable)) { $r->print(''.(' 'x2).' '); } $r->print(''); } else { $r->print(''); } # # Table of cloneable textbook courses # if (keys(%ordered)) { foreach my $type ('textbooks','templates') { my $divid = 'showtextbook'; my $radioid = 'book'; if ($type eq 'templates') { $divid = 'showtemplate'; $radioid = 'template'; } if (ref($ordered{$type}) eq 'HASH') { $r->print(''); } } } # # Table of user's current courses (owner and/or course coordinator) # if (keys(%cloneable)) { my %lt = &clone_text(); $r->print(''); } # # End of content selector # if (keys(%cloneable) || keys(%ordered)) { $r->print('
    '); } my %accesstitles = ( 'start' => 'Default start access', 'end' => 'Default end access', ); my %help_item = ( start => 'Course_Request_Access_Start', end => 'Course_Request_Access_End', ); my $starttime = time; my $endtime = time+(6*30*24*60*60); # 6 months from now, approx my $startform = &Apache::lonhtmlcommon::date_setter('requestcourse','accessstart', $starttime,'','','',1,'','','',1); my $endform = &Apache::lonhtmlcommon::date_setter('requestcourse','accessend', $endtime,'','','',1,'','','',1); # # Set default start and end dates for student access # $r->print('
    '. '
    '.&mt('Student Access Dates').''. &Apache::loncommon::help_open_topic($help_item{'start'}). ' '.&mt($accesstitles{'start'}).$startform.'
    '. &Apache::loncommon::help_open_topic($help_item{'end'}). ' '.&mt($accesstitles{'end'}).$endform.'
    '); # # Display any custom fields for this course type # my $fullname = &Apache::loncommon::plainname($env{'user.name'}, $env{'user.domain'}); my $postprocess = &Apache::lonnet::auto_crsreq_update($dom,undef,$crstype,'review', $env{'user.name'}, $env{'user.domain'},$fullname); if (ref($postprocess) eq 'HASH') { if ($postprocess->{'reviewweb'}) { $r->print($postprocess->{'reviewweb'}); } } # # Submit button # $r->print(''. ''. ''); # # End request form # $r->print('
    '); &endContentScreen($r). $r->print(&Apache::loncommon::end_page()); return; } sub process_textbook_request { my ($r,$dom,$action,$domdefs,$domconfig,$can_request) = @_; my ($uniquecode,$req_notifylist); my $crstype = 'textbook'; if (ref($domconfig) eq 'HASH') { if (ref($domconfig->{'requestcourses'}) eq 'HASH') { if (ref($domconfig->{'requestcourses'}{'notify'}) eq 'HASH') { $req_notifylist = $domconfig->{'requestcourses'}{'notify'}{'approval'}; } if (ref($domconfig->{'requestcourses'}{'uniquecode'}) eq 'HASH') { $uniquecode = $domconfig->{'requestcourses'}{'uniquecode'}{$crstype}; } } } my $now = time; my $reqtype = $env{'form.cloning'}; my (@inststatuses,$storeresult,$creationresult); my $cnum = &Apache::lonnet::generate_coursenum($dom,'Course'); my ($clonefrom,$clonedom,$clonecrs); if ($reqtype eq 'textbook') { $clonefrom = $env{'form.book'}; } elsif ($reqtype eq 'template') { $clonefrom = $env{'form.template'}; } elsif ($reqtype eq 'existing') { $clonefrom = $env{'form.owned'}; } my ($accessstart,$accessend) = &dates_from_form('accessstart','accessend'); if ($clonefrom) { ($clonedom,$clonecrs) = split(/_/,$clonefrom); if (&Apache::lonnet::homeserver($clonecrs,$clonedom) ne 'no_host') { my $canclone = &Apache::loncoursequeueadmin::can_clone_course($env{'user.name'}, $env{'user.domain'},$clonecrs,$clonedom,$crstype,$dom); unless ($canclone) { undef($clonecrs); undef($clonedom); } } else { undef($clonecrs); undef($clonedom); } } my $js = &processing_javascript(); my $loaditems = { onload => 'javascript:hideProcessing();', }; $r->print(&header('Course Creation',$js,$loaditems)); if (ref($can_request) eq 'HASH') { unless ((scalar(keys(%{$can_request})) == 1) && ($can_request->{'textbook'})) { &Apache::lonhtmlcommon::add_breadcrumb( { href => '/adm/requestcourse', text => 'Pick action', }); } } &Apache::lonhtmlcommon::add_breadcrumb( { href => '/adm/requestcourse', text => "Create Course", } ); &Apache::lonhtmlcommon::add_breadcrumb({text=>'Request Processed'}); $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests')); &startContentScreen($r,'textbookrequests'); my $details = { owner => $env{'user.name'}, domain => $env{'user.domain'}, cdom => $dom, cnum => $cnum, coursehome => $env{'form.chome'}, cdescr => $env{'form.cdescr'}, crstype => $crstype, uniquecode => $uniquecode, clonedom => $clonedom, clonecrs => $clonecrs, accessstart => $accessstart, accessend => $accessend, personnel => {}, }; if ($reqtype eq 'existing') { $details->{datemode} = $env{'form.datemode'}; $details->{dateshift} = $env{'form.dateshift'}; } my $lonhost = $r->dir_config('lonHostID'); $r->rflush(); my ($result,$output) = &process_request($r,$lonhost,$dom,$cnum,$crstype,$now,$details,'', $req_notifylist,[],$domconfig); $r->print($output); if (&Apache::loncoursequeueadmin::author_prompt()) { &print_author_prompt($r,$action,$cnum,$dom,$crstype,$result); } elsif ($result eq 'created') { $r->print('

    '.&mt('Create another course').'

    '); } &endContentScreen($r); $r->print(&Apache::loncommon::end_page()); } sub textbook_request_javascript { my ($numprefab,$numcurrent) = @_; return unless (ref($numprefab) eq 'HASH'); return if (!$numprefab->{'textbooks'} && !$numprefab->{'templates'} && !$numcurrent); my %lt = &Apache::lonlocal::texthash( choose => 'Please select a content option.', textbook => 'Please select a textbook, or choose a different option.', template => 'Please select a template, or choose a different option.', existing => 'Please select one of your existing courses to copy, or choose a different option.', title => 'Please enter a course title.', ); return <<"ENDSCRIPT"; function cloneChoice() { if (document.requestcourse.cloning) { var radioLength = document.requestcourse.cloning.length; if (radioLength == undefined) { var val = document.requestcourse.cloning.value; if ((val == 'textbook') || (val == 'template') || (val == 'existing')) { var elem = document.getElementById('show'+val); if (document.requestcourse.cloning.checked) { elem.style.display = 'block'; } else { uncheckRadio(val); elem.style.display = 'none'; } } } else { for (var i=0; i{'textbooks'}; var numtemplate = $numprefab->{'templates'}; var numcurrent = $numcurrent; if (numbook > 0) { uncheckRadio('textbook'); } if (nutemplate > 0) { uncheckRadio('template'); }m if (numcurrent > 0) { uncheckRadio('existing'); } return; } function validTextbookReq() { if (document.requestcourse.cloning) { var cloneChoice = 0; var radioLength = document.requestcourse.cloning.length; if (radioLength == undefined) { if (document.requestcourse.cloning.checked == false) { alert("$lt{'choose'}"); return false; } else { cloneChoice = document.requestcourse.cloning.value; } } else { for (var i=0; i '/adm/requestcourse', text => 'Pick action', }); } } } $r->print(&header('Course Request')); &Apache::lonhtmlcommon::add_breadcrumb({text=>'Course Request'}); $r->print(&Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests'). '
    '. '

    '.&mt('You do not have privileges to request creation of textbook courses.').'

    '); if (ref($can_request) eq 'HASH') { if (scalar(keys(%{$can_request})) > 1) { $r->print(''.&mt('Go back').''); } } $r->print('
    '. &Apache::loncommon::end_page()); return; } sub startContentScreen { my ($r,$mode)=@_; $r->print("\n".''."\n"); $r->print('
    '); } sub endContentScreen { my ($r)=@_; $r->print('
    '); } 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.