--- loncom/interface/lonrequestcourse.pm 2009/08/12 14:24:35 1.11 +++ loncom/interface/lonrequestcourse.pm 2014/01/05 10:55:35 1.75 @@ -1,7 +1,7 @@ # The LearningOnline Network # Request a course # -# $Id: lonrequestcourse.pm,v 1.11 2009/08/12 14:24:35 raeburn Exp $ +# $Id: lonrequestcourse.pm,v 1.75 2014/01/05 10:55:35 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -44,6 +44,66 @@ described at http://www.lon-capa.org. =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 @@ -56,54 +116,89 @@ 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) { - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; return OK; } - &Apache::loncommon::content_type($r,'text/html'); - $r->send_http_header; + &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 %stored; - my $jscript; - if ((defined($state)) && (defined($action))) { - my %elements = &form_elements($dom); - if (($action eq 'view') && ($state ne 'crstype')) { - if (defined($env{'form.request_id'})) { - %stored = &retrieve_settings($dom,$env{'form.request_id'}); - } - } - my $elementsref = {}; - if (ref($elements{$action}) eq 'HASH') { - if (ref($elements{$action}{$state}) eq 'HASH') { - $elementsref = $elements{$action}{$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); + } } } - $jscript = &Apache::lonhtmlcommon::set_form_elements($elementsref,\%stored); } - if ($state eq 'personnel') { - $jscript .= "\n".&Apache::loncommon::userbrowser_javascript(); + 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,\%can_request); + } + } else { + if ($can_request{'textbook'}) { + &print_textbook_form($r,$dom,\@incdoms,\%domdefs,$domconfig{'requestcourses'},\%can_request); + } else { + &textbook_request_disabled($r,$dom,\%can_request); + } + } + return OK; + } } - my $loaditems = &onload_action($action,$state); - - my %states; - $states{'view'} = ['pick_request','details','review','process']; - $states{'log'} = ['filter','display']; + $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'); + unshift(@{$states{'new'}},'codepick'); + } + } + + if (($action eq 'new') && (&Apache::loncoursequeueadmin::author_prompt())) { + if (ref($states{$action}) eq 'ARRAY') { + push(@{$states{$action}},'reqauthor'); } } @@ -113,137 +208,379 @@ sub handler { } } + my @invalidcrosslist; my %trail = ( - crstype => 'Course Request Action', + crstype => 'Pick Action', codepick => 'Category', courseinfo => 'Description', - enrollment => 'Enrollment', + 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', ); - my $page = 0; - my $crumb; - if (defined($action)) { - my $done = 0; - my $i=0; - if (ref($states{$action}) eq 'ARRAY') { - while ($i<@{$states{$action}} && !$done) { - if ($states{$action}[$i] eq $state) { - $page = $i; - $done = 1; - } - $i++; - } - } - 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 Requests','Course_Requests'); - last; - } else { - if (($state eq 'process') && ($i > 0)) { - &Apache::lonhtmlcommon::add_breadcrumb( - {href=>"javascript:backPage(document.requestcrs,'$states{$action}[0]')", - text=>"$trail{$states{$action}[$i]}"}); + 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') { + 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 { - &Apache::lonhtmlcommon::add_breadcrumb( - {href=>"javascript:backPage(document.requestcrs,'$states{$action}[$i]')", - text=>"$trail{$states{$action}[$i]}"}); + 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.'); } } - } else { - &Apache::lonhtmlcommon::add_breadcrumb( - {text=>'Pick Action'}); - $crumb = &Apache::lonhtmlcommon::breadcrumbs('Course Requests','Course_Requests'); + } 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(); + } + } + } + + if ($state eq 'personnel') { + $jscript .= "\n".&Apache::loncommon::userbrowser_javascript(); } - my %can_request; - my $canreq = &check_can_request($dom,\%can_request); + 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); + $crumb,\@incdoms); } else { - &request_administration($r,$action,$state,$page,\%states,$dom,$jscript, - $loaditems,$crumb); + &request_administration($r,$action,$state,$page,\%states,$dom, + $jscript,$loaditems,$crumb,$newinstcode, + $codechk,$checkedcode,$description, + $showcredits,$instcredits,\@invalidcrosslist); } } else { - $r->print(&header('Course Requests').$crumb. + $r->print(&header('Course/Community Requests').$crumb. '
'. - &mt('You do not have privileges to request creation of courses.'). + &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,'',$crumb); + &print_main_menu($r,\%can_request,\%states,$dom,$jscript,$loaditems,$crumb,\@incdoms); } else { - &request_administration($r,$action,$state,$page,\%states,$dom,$jscript, - $loaditems,$crumb); + &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') { - &print_request_logs($jscript,$loaditems,$crumb); + 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; + } + } + } + } + } + } + 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) = @_; + my ($bodytitle,$jscript,$loaditems,$jsextra,$args) = @_; if ($jscript) { $jscript = ''."\n"; } if ($loaditems) { - $loaditems = {'add_entries' => $loaditems,}; - return &Apache::loncommon::start_page($bodytitle,$jscript.$jsextra,$loaditems); - } else { - return &Apache::loncommon::start_page($bodytitle,$jscript.$jsextra); + 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) = @_; + my ($dom,$showcredits) = @_; + my $instcredits; my %elements = ( new => { crstype => { crstype => 'selectbox', action => 'selectbox', + origcnum => 'hidden', }, courseinfo => { cdescr => 'text', - clonecourse => 'text', - clonedomain => 'selectbox', + cloning => 'radio', + clonecrs => 'text', + clonedom => 'selectbox', datemode => 'radio', dateshift => 'text', }, enrollment => { - startaccess_month => 'selectbox', - startaccess_hour => 'selectbox', - endaccess_month => 'selectbox', - endaccess_hour => 'selectbox', - startaccess_day => 'text', - startaccess_year => 'text', - startaccess_minute => 'text', - startaccess_second => 'text', - endaccess_day => 'text', - endaccess_year => 'text', - endaccess_minute => 'text', - endaccess_second => 'text', + 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 => { - persontotal => 'hidden', addperson => 'checkbox', }, + review => { + cnum => 'hidden', + }, }, view => { crstype => { @@ -252,6 +589,13 @@ sub form_elements { }, }, ); + 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); @@ -267,133 +611,123 @@ sub form_elements { } if (&Apache::lonnet::auto_run('',$dom)) { my %extras = ( - sectotal => 'hidden', - startenroll_month => 'selectbox', - startenroll_hour => 'selectbox', - endenroll_month => 'selectbox', - endenroll_hour => 'selectbox', - startenroll_day => 'text', - startenroll_year => 'text', - startenroll_minute => 'text', - startenroll_second => 'text', - endenroll_day => 'text', - endenroll_year => 'text', - endenroll_minute => 'text', - endenroll_second => 'text', - crosslisttotal => 'hidden', + 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', - ); - if ($env{'form.sectotal'} > 0) { - for (my $i=0; $i<$env{'form.sectotal'}; $i++) { - $extras{'sec_'.$i} = 'checkbox', - $extras{'secnum_'.$i} = 'text', - $extras{'loncapasec_'.$i} = 'checkbox', + ); + 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 (!defined($crosslisttotal)) { + if ($env{'form.addcrosslist'}) { + $crosslisttotal ++; + } + if (!$crosslisttotal) { $crosslisttotal = 1; } - if ($crosslisttotal > 0) { - 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'; - } + 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', } + $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 (!defined($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.'_first'} = 'text', - $people{'person_'.$i.'_last'} = 'text', - $people{'person_'.$i.'_email'} = 'text', - $people{'person_'.$i.'_role'} = 'selectbox', - $people{'person_'.$i.'_sec'} = 'selectbox', - $people{'person_'.$i.'_newsec'} = 'text', - $people{'person_'.$i.'_sections'} = 'hidden', + $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; + return (\%elements,$instcredits);; } sub onload_action { my ($action,$state) = @_; my %loaditems; if (($action eq 'new') || ($action eq 'view')) { - $loaditems{'onload'} = 'javascript:setFormElements(document.requestcrs)'; - } - return \%loaditems; -} - -sub check_can_request { - my ($dom,$can_request) = @_; - my $canreq = 0; - my ($types,$typename) = &course_types(); - if ((ref($can_request) eq 'HASH') && (ref($types) eq 'ARRAY')) { - foreach my $type (@{$types}) { - if (&Apache::lonnet::usertools_access($env{'user.name'}, - $env{'user.domain'}, - $type,undef,'requestcourses')) { - $canreq ++; - if ($dom eq $env{'user.domain'}) { - $can_request->{$type} = 1; - } - } - if ($env{'environment.reqcrsotherdom.'.$type} ne '') { - my @curr = split(',',$env{'environment.reqcrsotherdom.'.$type}); - if (@curr > 0) { - $canreq ++; - unless ($dom eq $env{'user.domain'}) { - if (grep(/^\Q$dom\E$/,@curr)) { - $can_request->{$type} = 1; - } - } - } - } + 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);'; } } - return $canreq; -} - -sub course_types { - my @types = ('official','unofficial','community'); - my %typename = ( - official => 'Official course', - unofficial => 'Unofficial course', - community => 'Community', - ); - return (\@types,\%typename); + return \%loaditems; } - sub print_main_menu { - my ($r,$can_request,$states,$dom,$jscript,$loaditems,$crumb) = @_; - my ($types,$typename) = &course_types(); - my $onchange; - unless ($env{'form.interface'} eq 'textual') { - $onchange = 1; - } - + 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})) { @@ -410,14 +744,16 @@ sub print_main_menu { my $js = <<"END"; function nextPage(formname) { - var crschoice = document.requestcrs.crstype.value; - var actionchoice = document.requestcrs.action.value; + 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(); } @@ -427,19 +763,23 @@ $nextstate_setter function check_can_request(crschoice,actionchoice) { var official = ''; var unofficial = ''; - var community = ''; + var community = ''; + var textbook = ''; END - - foreach my $item (keys(%{$can_request})) { - $js .= " + 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 this domain.', - all => 'You must choose a specific course type when making a new course request.\\nAll types is not allowed.', + 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 .= <print(&header('Course Requests',$js.$jscript,$loaditems).$crumb. - '
'. - '
'. + my ($pagetitle,$pageinfo,$domaintitle,$earlyout); + if (ref($can_request) eq 'HASH') { + if (($can_request->{'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('Course Domain'). - &Apache::loncommon::select_dom_form($dom,'showdom','',1,$onchange)); + &Apache::lonhtmlcommon::row_title($domaintitle). + ''. + &Apache::loncommon::select_dom_form($dom,'showdom','',1,$onchange,$incdoms)); if (!$onchange) { $r->print(' '); } - $r->print(&Apache::lonhtmlcommon::row_closure(1). - &Apache::lonhtmlcommon::end_pick_box().'
'); - + 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::start_pick_box(). - &Apache::lonhtmlcommon::row_title('Action').' - + $r->print(&Apache::lonhtmlcommon::row_title(&mt('Action')).' + '. +
'. &Apache::lonhtmlcommon::row_closure(). - &Apache::lonhtmlcommon::row_title('Course Type').' - -'. - &Apache::lonhtmlcommon::row_closure(1). - &Apache::lonhtmlcommon::end_pick_box().'
- -
'); + &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) = @_; + 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')) { + if (($action eq 'new') || (($action eq 'view') && ($state eq 'pick_request'))) { $js = <print(&header('Request a course',$js.$jscript,$loaditems,$jsextra).$crumb); - &print_request_form($r,$action,$state,$page,$states,$dom); + $r->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') { - $r->print(&header('Manage course requests',$js.$jscript,$loaditems).$crumb); + my $jsextra; + my $formname = 'requestcrs'; + my $prev = $states->{$action}[$page-1]; + my $next = $states->{$action}[$page+1]; if ($state eq 'pick_request') { - $r->print(&print_request_status($dom)); + $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'; } - } elsif ($action eq 'log') { - $r->print(&coursereq_log('View request log',$jscript,$loaditems).$crumb); + $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 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) = @_; + 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]; @@ -567,45 +1326,29 @@ sub print_request_form { next => 'Next', ); $crstype = $env{'form.crstype'}; - $r->print('
'); - my (@codetitles,%cat_titles,%cat_order,@code_order,$instcode,$code_chk); + $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 ($prev eq 'codepick') { - if ($crstype eq 'official') { - &Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles, - \%cat_order,\@code_order); - } - if (@code_order > 0) { - my $message; - if ($instcode eq '') { - foreach my $item (@code_order) { - $instcode .= $env{'form.instcode_'.$item}; - } - $r->print(''."\n"); - } - if ($instcode ne '') { - $code_chk = &Apache::lonnet::auto_validate_instcode('',$dom,$instcode); - if ($code_chk eq 'ok') { - $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 ($code_chk ne '') { - $message .= '
'.$code_chk; - } - $message .= '
'; - } + 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.'); - } - unless ($code_chk eq 'ok') { + &mt('No course was found matching your choice of institutional course category.'); + if ($codechk ne '') { + $message .= '
'.$codechk; + } + $message .= '
'; $prev = 'crstype'; } $r->print($message); @@ -620,49 +1363,356 @@ sub print_request_form { $codepicker = &coursecode_form($dom,'instcode',\@codetitles, \%cat_titles,\%cat_order); if ($codepicker) { - $r->print('
'.&Apache::lonhtmlcommon::start_pick_box().$codepicker. + $r->print(&mt('Specify the course to be created.'). + '
'.&Apache::lonhtmlcommon::start_pick_box(). + $codepicker. &Apache::lonhtmlcommon::end_pick_box().'
'); } else { - $r->print(&courseinfo_form($dom,$formname,$crstype)); + $next = $states->{$action}[$page+2]; + $r->print(&courseinfo_form($dom,$formname,$crstype,$next)); } } else { - $r->print(&courseinfo_form($dom,$formname,$crstype)); + if ($crstype eq 'official') { + $next = $states->{$action}[$page+2]; + } + $r->print(&courseinfo_form($dom,$formname,$crstype,$next)); } } elsif ($prev eq 'codepick') { - $r->print(&courseinfo_form($dom,$formname,$crstype)); + 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)); + \%cat_titles,\%cat_order,\@code_order, + $showcredits,$instcredits,$invalidcrosslist)); } elsif ($state eq 'personnel') { - $r->print(&print_personnel_menu($dom,$formname,$crstype)); + $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); - $r->print(&print_review($formname,$dom,\@codetitles,\%cat_titles,\%cat_order, - \@code_order)); - $navtxt{'next'} = &mt('Submit course request'); + 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 $result = &print_request_outcome($dom,\@codetitles,\@code_order); + my ($storeresult,$result) = &print_request_outcome($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 = &form_elements($dom); + 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{$action}) eq 'HASH') { - if (ref($elements{$action}{$items[$i]}) eq 'HASH') { - foreach my $key (keys(%{$elements{$action}{$items[$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); } } @@ -675,31 +1725,67 @@ sub print_request_form { if (grep(/^instcode_/,@excluded)) { push(@excluded,'instcode'); } - $r->print(&Apache::lonhtmlcommon::echo_form_input(\@excluded).''); - &display_navbuttons($r,$formname,$prev,$navtxt{'prev'},$next,$navtxt{'next'}); - return; + return @excluded; } sub print_enrollment_menu { - my ($formname,$instcode,$dom,$codetitles,$cat_titles,$cat_order,$code_order) =@_; - my ($sections,$autoenroll,$access_dates); + 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 accss', + '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)) { - my ($section_form,$crosslist_form,$autoenroll_form); - $section_form = &inst_section_selector($dom,$instcode); + $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 (!defined($crosslisttotal)) { + if (!$crosslisttotal) { $crosslisttotal = 1; } if ($env{'form.addcrosslist'}) { @@ -711,70 +1797,134 @@ sub print_enrollment_menu { } if ($crosslist_form) { $crosslist_form .= - &Apache::lonhtmlcommon::row_title(&mt('Add another?')). + &Apache::lonhtmlcommon::row_title(&mt('Add another')). ''. ''.&mt('Add?').&Apache::lonhtmlcommon::row_closure(1); - } - if ($section_form || $crosslist_form) { - $sections = '
'.&Apache::lonhtmlcommon::start_pick_box(). - $section_form.$crosslist_form. - &Apache::lonhtmlcommon::end_pick_box().'
'."\n"; - } - $autoenroll_form = - &Apache::lonhtmlcommon::row_title(&mt('Add registered students automatically')). + "'".');" />'.&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(). - &Apache::lonhtmlcommon::row_title(&mt('Drop unregistered students automatically')). + &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(). - &date_setting_table($starttime,$endtime,$formname,'enroll',%enrolltitles); - if ($autoenroll_form) { - $autoenroll = '
'.&Apache::lonhtmlcommon::start_pick_box(). - $autoenroll_form. - &Apache::lonhtmlcommon::end_pick_box().'
'."\n"; + &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); } - my $access_dates_form = - &date_setting_table($starttime,$endtime,$formname,'access',%accesstitles); - if ($access_dates_form) { - $access_dates = '
'.&Apache::lonhtmlcommon::start_pick_box(). - $access_dates_form. - &Apache::lonhtmlcommon::end_pick_box().'
'."\n"; + 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 $sections.$autoenroll.$access_dates; + 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('Sections'). + $output .= &Apache::lonhtmlcommon::row_title(&mt('Sections of [_1]',$instcode)). &Apache::loncommon::start_data_table(). &Apache::loncommon::start_data_table_row(). ''.&mt('Include?').''. + 'value="'.$sectotal.'" />'. ''.&mt('Institutional Section').''. - ''.&mt('LON-CAPA 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(). - ''. - ''.$sections[$i]. + ''. + (' 'x2).''. + ''.$sections[$i]. ''. '
'; + 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($datetitles{'start'}). - $startform. - &Apache::lonhtmlcommon::row_closure(). - &Apache::lonhtmlcommon::row_title($datetitles{'end'}). - $endform.$perpetual. - &Apache::lonhtmlcommon::row_closure(1); + + $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) = @_; - my $output = '
'.&Apache::lonhtmlcommon::start_pick_box(); + 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)) { + if ((!defined($persontotal)) || (!$persontotal)) { $persontotal = 1; } if ($env{'form.addperson'}) { $persontotal ++; } - my $userlinktxt = &mt('Set User'); - my @items = ('uname','dom','last','first','email','hidedom'); + my @items = ('uname','dom','lastname','firstname','emailaddr','hidedom'); - my $roleoptions; - my @roles = &Apache::lonuserutils::roles_by_context('course'); 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); + 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_cr_'.$env{'user.domain'}. - '_'.$env{'user.name'}.'_'.$cust; + my $custrole="cr/$env{'user.domain'}/$env{'user.name'}/$cust"; $roleoptions .= ' '."\n"; } } - my @currsecs; - if ($env{'form.sectotal'}) { - for (my $i=0; $i<$env{'form.sectotal'}; $i++) { - if (defined($env{'form.loncapasec_'.$i})) { - my $lcsec = $env{'form.loncapasec_'.$i}; - unless (grep(/^\Q$lcsec\E$/,@currsecs)) { - push(@currsecs,$lcsec); - } - } - } - } + my @currsecs = ¤t_lc_sections(); my ($existtitle,$existops,$existmult,$newtitle,$seccolspan); if (@currsecs) { @@ -871,19 +2035,25 @@ sub print_personnel_menu { $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 $userlink = &Apache::loncommon::selectuser_link($formname,@linkargs,$dom,$userlinktxt); - my $uname_form = ''; + my $uname_form = ''; my $onchange = 'javascript:fix_domain('."'$formname','person_".$i."_dom',". - "'person_".$i."_hidedom'".');'. - 'openuserbrowser('."'$formname','$linkargstr','$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')); @@ -898,79 +2068,170 @@ sub print_personnel_menu { $existmult.'>'."\n".$existops.''.(' ' x3); } $sectionselector .= $newtitle. - ''. - ''."\n"; - + ''."\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').'
'. - ''.$userlink. - ''). - ''."\n". - ''."\n". - ''."\n". - ''."\n". - ''."\n". - ''."\n". - ''.&mt('Section(s)').'
'.$sectionselector.''."\n". + &Apache::lonhtmlcommon::row_title(&mt('Additional Personnel')). + '
'.&mt('Username').'
'.$uname_form.'
'.&mt('Domain').'
'.$udom_form.'
'.&mt('First Name').'
'.$form_elems{'first'}.'
'.&mt('Last Name').'
'.$form_elems{'last'}.'
'.&mt('E-mail').'
'.$form_elems{email}.'
'.&mt('Role').'
'.$roleselector.'
'."\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?')). + $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 print_request_status { - my ($dom) = @_; - my %requests = &Apache::lonnet::dumpstore('courserequests',$env{'user.domain'}, - $env{'user.name'}); - my ($output,$formname,%queue_by_date); - foreach my $key (keys(%requests)) { - if (ref($requests{$key}) eq 'HASH') { - my ($cdom,$cnum) = split('_',$key); - next if ($cdom ne $dom); +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 $timestamp = $requests{$key}{'timestamp'}; - my $crstype = $requests{$key}{'crstype'}; - my $status = $requests{$key}{'status'}; - next unless (($env{'form.crstype'} eq 'all') || - ($env{'form.crstype'} eq $crstype)); - next unless (($status eq 'approval') || ($status eq 'pending')); - if (ref($requests{$key}{'details'}) eq 'HASH') { - $entry = $key.':'.$crstype.':'.$requests{$key}{'details'}{'cdesc'}; + 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 .= ':'.$requests{$key}{'details'}{'instcode'}; + $entry .= ':'.&escape($history{'details'}{'instcode'}); } } if ($entry ne '') { - if (exists($queue_by_date{$timestamp})) { - if (ref($queue_by_date{$timestamp}) eq 'ARRAY') { - push(@{$queue_by_date{$timestamp}},$entry); + if (exists($queue_by_date{$reqtime})) { + if (ref($queue_by_date{$reqtime}) eq 'ARRAY') { + push(@{$queue_by_date{$reqtime}},$entry); } } else { - @{$queue_by_date{$timestamp}} = ($entry); + @{$queue_by_date{$reqtime}} = ($entry); } } } } - $formname = 'requestcrs'; + 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)); - $output = '
'."\n". - ''."\n". + my $formname = 'requestcrs'; + my ($types,$typenames) = &Apache::loncommon::course_types(); + my $output = ''."\n". + ''."\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').''. - ''.&mt('Description').''; - if ($env{'form.crstype'} eq 'all') { + ''.$desctitle.''. + ''.&mt('Domain').''; + if ($env{'form.crstype'} eq 'any') { $output .= ''.&mt('Type').''; } - if (($env{'form.crstype'} eq 'all') || ($env{'form.crstype'} eq 'official')) { + if (($env{'form.crstype'} eq 'any') || ($env{'form.crstype'} eq 'official')) { $output .= ''.&mt('Institutional Code').''; } $output .= ''.&mt('Date requested').''. @@ -983,14 +2244,28 @@ sub print_request_status { my ($key,$type,$desc,$instcode) = split(':',$request); my ($cdom,$cnum) = split('_',$key); $output .= &Apache::loncommon::start_data_table_row(). - ''. - ''.$desc.''; - if ($env{'form.crstype'} eq 'all') { - $output .= ''.&course_types($type).''; + ''. + ''.&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 'all') || + if (($env{'form.crstype'} eq 'any') || ($env{'form.crstype'} eq 'official')) { - $output .= ''.$instcode.''; + my $showinstcode; + if ($type eq 'official') { + $showinstcode = &unescape($instcode); + } else { + $showinstcode = &mt('Not applicable'); + } + $output .= ''.$showinstcode.''; } $output .= ''.$showtime.''. &Apache::loncommon::end_data_table_row(); @@ -999,27 +2274,455 @@ sub print_request_status { } $output .= &Apache::loncommon::end_data_table(); } 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.').'
'; + 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 ($jscript,$loaditems,$crumb) = @_; + 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 ($formname,$dom,$codetitles,$cat_titles,$cat_order,$code_order) = @_; - my ($types,$typename) = &course_types(); + 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); - $owner = $env{'user.name'}.':'.$env{'user.domain'}; - $ownername = &Apache::loncommon::plainname($env{'user.name'}, - $env{'user.domain'},'first'); - my %emails = &Apache::loncommon::getemails(); + 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 ''); @@ -1030,13 +2733,19 @@ sub print_review { $crstypename = $env{'form.crstype'}; if (ref($typename) eq 'HASH') { unless ($typename->{$env{'form.crstype'}} eq '') { - $crstypename = $typename->{$env{'form.crstype'}}; + $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).')'; if ($env{'form.crstype'} eq 'official') { if ((ref($codetitles) eq 'ARRAY') && (ref($cat_titles) eq 'HASH')) { foreach my $title (@{$codetitles}) { @@ -1052,7 +2761,14 @@ sub print_review { } } } + $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').''. @@ -1060,12 +2776,12 @@ sub print_review { $section_headers = ''.&mt('Sections').''. ''.&mt('Crosslistings').''; - my ($startenroll,$endenroll) = &dates_from_form('startenroll','endenroll'); + 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($startenroll).''. - ''.&Apache::lonlocal::locallocaltime($endenroll).''; + ''.&Apache::lonlocal::locallocaltime($enrollstart).''. + ''.&Apache::lonlocal::locallocaltime($enrollend).''; $section_values = ''. ''; @@ -1091,103 +2807,163 @@ sub print_review { &mt('Institutional course/section').''. ''; my $xlistinfo; - if ($env{'form.crosslisttotal'}) { - for (my $i=0; $i<$env{'form.crosslisttotal'}; $i++) { - if ($env{'form.crosslist_'.$i}) { - $xlistinfo .= ''; } + $xlistinfo .= $env{'form.crosslist_'.$i.'_instsec'}.''; } } if ($xlistinfo eq '') { $xlistinfo = ''; } - $section_values .= $xlistinfo.'
'. &mt('Institutional section').''.&mt('LON-CAPA 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}; - } + my $crosslisttotal = $env{'form.crosslisttotal'}; + if (!$crosslisttotal) { + $crosslisttotal = 1; + } + for (my $i=0; $i<$crosslisttotal; $i++) { + if ($env{'form.crosslist_'.$i}) { + $xlistinfo .= '
'; + 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 .= '
'; + if ($env{'form.crosslist_'.$i.'_lcsec'}) { + $xlistinfo .= $env{'form.crosslist_'.$i.'_lcsec'}; + } else { + $xlistinfo .= &mt('None'); + } + $xlistinfo .= '
'.&mt('None').'
'; + $section_values .= $xlistinfo; } + $section_values .= ''; + } 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.clonecourse'} =~ /^$match_name$/) && - ($env{'form.clonedomain'} =~ /^$match_domain$/)) { - my %coursehash = - &Apache::lonnet::courseiddump($env{'form.clonedomain'},'.',1,'.','.', - $env{'form.clonecourse'},undef,undef,'.'); - my $cloneid = $env{'form.clonedomain'}.'_'.$env{'form.clonecourse'}; - if (ref($coursehash{$cloneid}) eq 'HASH') { - $inst_headers .= ''.$ctxt{'dsh'}.''; - my $clonedesc = $coursehash{$cloneid}{'description'}; - my $cloneinst = $coursehash{$cloneid}{'inst_code'}; - - $inst_values .= ''.$clonedesc.' '; - if ($cloneinst ne '') { - $inst_values .= &mt('([_1] in [_2])',$cloneinst,$env{'form.clonedomain'}); - } else { - $inst_values .= &mt('(from [_1])',$env{'form.clonedomain'}); - } - $inst_values .= ''; - if ($env{'form.datemode'} eq 'preserve') { - $inst_values .= $ctxt{'pcd'}; - } 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').''; - } + 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'}); + 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 ($startaccess,$endaccess) = &dates_from_form('startaccess','endaccess'); - $enroll_values .= ''.&Apache::lonlocal::locallocaltime($startaccess).''; - if ($endaccess == 0) { + 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($endaccess).''; + $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('cc',$container).''. + ''.&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.'_first'}.' '. - $env{'form.person_'.$i.'_last'}.''. + ''.$env{'form.person_'.$i.'_firstname'}.' '. + $env{'form.person_'.$i.'_lastname'}.''. ''.$env{'form.person_'.$i.'_uname'}.':'. $env{'form.person_'.$i.'_dom'}.''. - ''.&Apache::lonnet::plaintext($env{'form.person_'.$i.'_role'}, - $container).''. - ''.$env{'form.person_'.$i.'_sections'}.''; + ''.&Apache::lonnet::plaintext($role,$container).''. + ''.$showsec.''; } } - my $output = '

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

'. - '
'.&Apache::lonhtmlcommon::start_pick_box(). + 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')). ''. ''. @@ -1202,7 +2978,7 @@ sub print_review { '
'.&mt('Name').'
'.$inst_headers.''."\n". ''.$inst_values.'
'."\n". &Apache::lonhtmlcommon::row_closure(). - &Apache::lonhtmlcommon::row_title(&mt('Enrollment')). + &Apache::lonhtmlcommon::row_title($enrollrow_title). ''.$enroll_headers.''."\n". ''.$enroll_values.'
'."\n". &Apache::lonhtmlcommon::row_closure(); @@ -1216,9 +2992,7 @@ sub print_review { ''.$personnel_headers.''."\n". $personnel_values.'
'."\n". &Apache::lonhtmlcommon::row_closure(1). - &Apache::lonhtmlcommon::end_pick_box(); - my $cnum = &Apache::lonnet::generate_coursenum($dom); - $output .= ''; + &Apache::lonhtmlcommon::end_pick_box().'
'; return $output; } @@ -1226,7 +3000,7 @@ 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 'endaccess') { + if ($endname eq 'accessend') { if (exists($env{'form.no_end_date'}) ) { $enddate = 0; } @@ -1235,13 +3009,84 @@ sub dates_from_form { } sub courseinfo_form { - my ($dom,$formname,$crstype) = @_; - my $output = '
'.&Apache::lonhtmlcommon::start_pick_box(). - &Apache::lonhtmlcommon::row_title('Course Description'). - ''. - &Apache::lonhtmlcommon::row_closure(1). - &Apache::lonhtmlcommon::end_pick_box().'
'. - '
'.&clone_form($dom,$formname,$crstype).'
'."\n"; + 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; } @@ -1251,17 +3096,16 @@ sub clone_form { if ($crstype eq 'community') { $type = 'Community'; } - my $cloneform = &Apache::loncommon::select_dom_form($dom,'clonedomain'). - &Apache::loncommon::selectcourse_link($formname,'clonecourse','clonedomain','','','',$type); my %lt = &clone_text(); my $output .= - &Apache::lonhtmlcommon::start_pick_box(). + &Apache::lonhtmlcommon::row_title($lt{'dmn'}).''. + &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::row_title($lt{'cid'}).''.&Apache::lonhtmlcommon::row_closure(1).''. - $cloneform.''.&Apache::lonhtmlcommon::row_closure(). + ''. + ' '. + &Apache::loncommon::selectcourse_link($formname,'clonecrs','clonedom','','','',$type). + &Apache::lonhtmlcommon::row_closure(1). &Apache::lonhtmlcommon::row_title($lt{'dsh'}).'
'. ''. - &Apache::lonhtmlcommon::row_closure(1). - &Apache::lonhtmlcommon::end_pick_box(); + &Apache::lonhtmlcommon::row_closure(1); return $output; } -sub clone_text { +sub clone_text { return &Apache::lonlocal::texthash( 'cid' => 'Course ID', 'dmn' => 'Domain', @@ -1289,10 +3132,13 @@ sub clone_text { sub coursecode_form { my ($dom,$context,$codetitles,$cat_titles,$cat_order,$num) = @_; my $output; - my %rowtitle = ( + 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); @@ -1308,7 +3154,11 @@ sub coursecode_form { my $lastitem = pop(@{$codetitles}); my $lastinput = ''; if (@{$codetitles} > 0) { - $output = &Apache::lonhtmlcommon::row_title($rowtitle{$context}). + 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 .= ''. + ''. + ''. + ''. + &Apache::loncommon::end_data_table_header_row()); + my @items = sort { $a <=> $b } keys(%ordered); + foreach my $num (@items) { + my $item = $ordered{$num}; + my $cleantitle=&HTML::Entities::encode($bookshash->{$item}->{'title'},'<>&"'); + $cleantitle=~s/'/\\'/g; + $cleantitle =~ s/^\s+//; + $r->print(&Apache::loncommon::start_data_table_row(). + ''. + ''. + ''. + ''. + &Apache::loncommon::end_data_table_row()); + } + $r->print(&Apache::loncommon::end_data_table(). + ''); + } + +# +# Table of user's current courses (owner and/or course coordinator) +# + if (keys(%cloneable)) { + my %lt = &clone_text(); + $r->print(''. + ''. + &Apache::loncommon::end_data_table_header_row()); + my %allownernames; + my %sortbytitle; + foreach my $cid (sort(keys(%cloneable))) { + if (ref($cloneable{$cid}) eq 'HASH') { + my $cdesc = $cloneable{$cid}{'description'}; + $cdesc =~ s/`/'/g; + if ($cdesc ne '') { + push(@{$sortbytitle{$cdesc}},$cid); + } + } + } + foreach my $title (sort(keys(%sortbytitle))) { + if (ref($sortbytitle{$title}) eq 'ARRAY') { + foreach my $cid (sort(@{$sortbytitle{$title}})) { + my $cleantitle=&HTML::Entities::encode($title,'<>&"'); + $cleantitle=~s/'/\\'/g; + $cleantitle =~ s/^\s+//; + my ($namestr,@owners,%ownernames); + my $singleowner = $cloneable{$cid}{'internal.courseowner'}; + push(@owners,$singleowner); + if ($cloneable{$cid}{'co-owners'} ne '') { + foreach my $item (split(/,/,$cloneable{$cid}{'internal.co-owners'})) { + push(@owners,$item); + } + } + foreach my $owner (@owners) { + my ($ownername,$ownerdom); + if ($owner =~ /:/) { + ($ownername,$ownerdom) = split(/:/,$owner); + } else { + $ownername = $owner; + if ($owner ne '') { + $ownerdom = $dom; + } + } + if ($ownername ne '' && $ownerdom ne '') { + if (exists($allownernames{$ownername.':'.$ownerdom})) { + $ownernames{$ownername.':'.$ownerdom} = $allownernames{$ownername.':'.$ownerdom}; + } else { + my %namehash=&Apache::loncommon::getnames($ownername,$ownerdom); + $ownernames{$ownername.':'.$ownerdom} = \%namehash; + $allownernames{$ownername.':'.$ownerdom} = $ownernames{$ownername.':'.$ownerdom}; + } + } + } + my @lastnames; + foreach my $owner (keys(%ownernames)) { + if (ref($ownernames{$owner}) eq 'HASH') { + push(@lastnames,$ownernames{$owner}{'lastname'}); + } + } + if (@lastnames) { + $namestr = join(', ',sort(@lastnames)); + } + $r->print(&Apache::loncommon::start_data_table_row(). + ''. + ''. + &Apache::loncommon::end_data_table_row()); + } + } + } + $r->print(&Apache::loncommon::end_data_table(). + '

'.$lt{'ncd'}. + '

'. + ''. + ''); + } +# +# 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 $crstype = 'textbook'; + 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 '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); + unless ($canclone) { + undef($clonecrs); + undef($clonedom); + } + } else { + undef($clonecrs); + undef($clonedom); + } + } + $r->print(&header('Course Creation')); + + 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 ($result,$output) = &process_request($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 ($numbook,$numcurrent) = @_; + my %lt = &Apache::lonlocal::texthash( + choose => 'Please select a content option.', + textbook => 'Please select a textbook, 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 if (!$numbook && !$numcurrent); + 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 == '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 0) { + uncheckRadio('textbook'); + } + 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; iprint("\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.

'.&mt('Include?').'
'. @@ -1373,70 +3223,162 @@ sub coursecode_form { 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'}; } } - if ($env{'form.showdom'} ne '') { - if (&Apache::lonnet::domain($env{'form.showdom'}) ne '') { - $codedom = $env{'form.showdom'}; - } - } return $codedom; } sub display_navbuttons { - my ($r,$formname,$prev,$prevtext,$next,$nexttext) = @_; + my ($r,$dom,$formname,$prev,$prevtext,$next,$nexttext,$state,$other,$othertext) = @_; $r->print('
'); if ($prev) { - $r->print(' - -    '); + $r->print(''. + (' 'x3)); } elsif ($prevtext) { - $r->print(' - -    '); - } - if ($next) { - $r->print(' - '); + $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 ($dom,$codetitles,$code_order) = @_; - my ($output,$cnum,$now,$req_notifylist,$crstype,$startenroll,$endenroll, - %sections,%crosslistings,%personnel,@baduname,@missingdom,%domconfig,); + my ($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; } - - %domconfig = &Apache::lonnet::get_dom('configuration',['requestcourses'],$dom); + $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; - $crstype = $env{'form.crstype'}; + my $ccrole = 'cc'; + if ($crstype eq 'community') { + $ccrole = 'co'; + } + my @instsections; if ($crstype eq 'official') { if (&Apache::lonnet::auto_run('',$dom)) { - ($startenroll,$endenroll)=&dates_from_form('startenroll','endenroll'); + ($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 '') { - $sections{$env{'form.secnum_'.$i}} = $env{'form.loncapasec_'.$i}; + 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'} = ''; + } } } } @@ -1450,24 +3392,118 @@ sub print_request_outcome { } } } - $xlistinfo .= $env{'form.crosslist_'.$i.'_instsec'}; - $crosslistings{$xlistinfo} = $env{'form.crosslist_'.$i.'_lcsec'}; + $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.'_uname'}; + my $udom = $env{'form.person_'.$i.'_dom'}; if (($uname =~ /^$match_username$/) && ($udom =~ /^$match_domain$/)) { if (&Apache::lonnet::domain($udom) ne '') { - $personnel{$uname.':'.$udom} = { - first => $env{'form.person_'.$i.'_first'}, - last => $env{'form.person_'.$i.'_last'}, - email => $env{'form.person_'.$i.'_email'}, - role => $env{'form.person_'.$i.'_role'}, - sections => $env{'form.person_'.$i.'_sections'}, - }; + 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); } @@ -1475,52 +3511,109 @@ sub print_request_outcome { push(@baduname,$uname.':'.$udom); } } - - my ($startaccess,$endaccess) = &dates_from_form('startaccess','endacess'); + 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); + if ($canclone) { + $clonecrs = $env{'form.clonecrs'}; + $clonedom = $env{'form.clonedom'}; + } + } + } my $details = { owner => $env{'user.name'}, domain => $env{'user.domain'}, cdom => $dom, cnum => $cnum, - cdesc => $env{'form.cdesc'}, + coursehome => $env{'form.chome'}, + cdescr => $env{'form.cdescr'}, crstype => $env{'form.crstype'}, - instcode => $env{'form.instcode'}, - clonedomain => $env{'form.clonedomain'}, - clonecourse => $env{'form.clonecourse'}, + instcode => $instcode, + defaultcredits => $credits, + uniquecode => $uniquecode, + clonedom => $clonedom, + clonecrs => $clonecrs, datemode => $env{'form.datemode'}, - dateshift => $env{'form.datshift'}, - sectotal => $env{'form.sectotal'}, + dateshift => $env{'form.dateshift'}, + sectotal => $sectotal, sections => \%sections, - crosslisttotal => $env{'form.crosslisttotal'}, - crosslistings => \%crosslistings, - autoadds => $env{'form.autoadds'}, - autodrops => $env{'form.autodrops'}, - startenroll => $startenroll, - endenroll => $endenroll, - startaccess => $startaccess, - endaccess => $endaccess, + crosslisttotal => $crosslisttotal, + crosslists => \%crosslistings, + autoadds => $autoadds, + autodrops => $autodrops, + enrollstart => $enrollstart, + enrollend => $enrollend, + accessstart => $accessstart, + accessend => $accessend, personnel => \%personnel, }; - my @inststatuses; - my $val = &get_processtype($dom,$crstype,\@inststatuses,\%domconfig); + my ($result,$output) = &process_request($dom,$cnum,$crstype,$now,$details,$instcode, + $req_notifylist,\@instsections,\%domconfig); + return ($result,$output); +} + +sub process_request { + my ($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'); + $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'); + $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); + my ($disposition,$message,$reqstatus); my %reqhash = ( - timestamp => $now, + reqtime => $now, crstype => $crstype, details => $details, ); my $requestkey = $dom.'_'.$cnum; + my $validationerror; if ($val eq 'autolimit=') { $disposition = 'process'; } elsif ($val =~ /^autolimit=(\d+)$/) { @@ -1528,250 +3621,1199 @@ sub print_request_outcome { $disposition = &check_autolimit($env{'user.name'},$env{'user.domain'}, $dom,$crstype,$limit,\$message); } elsif ($val eq 'validate') { - $disposition = - &Apache::lonnet::auto_courserequest_validation($dom,$details, - \@inststatuses,\$message); + my ($inststatuslist,$validationchk,$validation); + if (@inststatuses > 0) { + $inststatuslist = join(',',@inststatuses); + } + my $instseclist; + if (ref($instsections) eq 'ARRAY') { + if (@{$instsections} > 0) { + $instseclist = join(',',@{$instsections}); + } + } + $validationchk = + &Apache::lonnet::auto_courserequest_validation($dom, + $env{'user.name'}.':'.$env{'user.domain'},$crstype, + $inststatuslist,$instcode,$instseclist); + if ($validationchk =~ /:/) { + ($validation,$message) = split(':',$validationchk); + } else { + $validation = $validationchk; + } + if ($validation =~ /^error(.*)$/) { + $disposition = 'approval'; + $validationerror = $1; + } else { + $disposition = $validation; + } } else { $disposition = 'approval'; } - $reqhash{'status'} = $disposition; + $reqhash{'disposition'} = $disposition; + $reqstatus = $disposition; + my ($modified,$queued,$coursedesc,%customitems); + unless ($disposition eq 'rejected') { + if (ref($details) eq 'HASH') { + $coursedesc = $details->{'cdescr'}; + } + my $fullname = &Apache::loncommon::plainname($env{'user.name'}, + $env{'user.domain'}); + 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') { - $output = &mt('Your course request was 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 ($logmsg,$newusermsg,$addresult,$enrollcount,$output,$keysmsg,%longroles); - my @roles = &Apache::lonuserutils::roles_by_context('course'); + my @roles = &Apache::lonuserutils::roles_by_context('course','',$type); foreach my $role (@roles) { $longroles{$role}=&Apache::lonnet::plaintext($role,$type); } - my %reqdetails = &build_batchcreatehash($details); - my $cid = &LONCAPA::batchcreatecourse::build_course($dom,$cnum,'request',\%reqdetails,\%longroles,\$logmsg,\$newusermsg,\$addresult,\$enrollcount,\$output,\$keysmsg,$env{'user.domain'},$env{'user.name'},$cnum); - $disposition = 'created'; - if ($cid eq $cnum) { + 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'; - $output = &mt('Your course request has been processed and the course has been created.').'
'.&mt('You will need to logout and log-in again to be able to select a role in the course.'); + $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; + } + $output .= '
'.$role_result.'

'; + $creationresult = 'created'; } else { - $output = &mt('An error occurred when processing your course request.').'
'.&mt('You may want to review the request details and submit the request again.'); + $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 = { + my $request = { $requestid => { timestamp => $now, crstype => $crstype, ownername => $env{'user.name'}, ownerdom => $env{'user.domain'}, - description => $env{'form.cdesc'}, + description => $env{'form.cdescr'}, }, }; - my $putresult = &Apache::lonnet::newput_dom('courserequestqueue',$request, - $dom); - if ($putresult eq 'ok') { - my %emails = &Apache::loncommon::getemails(); - my $address; - if (($emails{'permanentemail'} ne '') || ($emails{'notification'} ne '')) { - $address = $emails{'permanentemail'}; - if ($address eq '') { - $address = $emails{'notification'}; - } - } - $output = &mt('Your course request has been recorded.').'
'; - if ($disposition eq 'approval') { - $output .= &mt('Your course request has been recorded.').'
'. - &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'}); - &Apache::loncoursequeueadmin::send_selfserve_notification($req_notifylist,$fullname,$now,$dom,$details); + 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; + } + } + unless ($queued) { + 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.') } + $output .= '
'. + ¬ification_information($disposition,$req_notifylist, + $dom,$cnum,$now); } else { - $output .= '
'. -&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.'). - '
'; + $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 ($modified && $queued && $storeresult eq 'ok') { + if ($crstype eq 'community') { + $output .= '

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

'; } else { - $reqhash{'status'} = 'domainerror'; - $reqhash{'disposition'} = $disposition; - my $warning = &mt('An error occurred saving your request in the pending requests queue.'); - $output = ''.$warning.'
'; - + $output .= '

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

'; + } + $output .= ¬ification_information($disposition,$req_notifylist,$dom,$cnum,$now); + if ($disposition eq 'approval') { + my $fullname = &Apache::loncommon::plainname($env{'user.name'}, + $env{'user.domain'}); + my $postprocess = + &Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,'queued',$env{'user.name'}, + $env{'user.domain'},$fullname,$env{'form.cdescr'}); + if ((ref($postprocess) eq 'HASH') && + ((ref($postprocess->{'queuedmsg'}) eq 'HASH') || ($postprocess->{'queuedweb'}))) { + my $recipient = $env{'user.name'}.':'.$env{'user.domain'}; + $output .= ¬ification_information($disposition,$recipient,$dom,$cnum,$now,undef,$postprocess); + } } } - my $storeresult; - if ($requestkey =~ /^($match_domain)_($match_courseid)$/) { - $storeresult = &Apache::lonnet::store_userdata(\%reqhash,$requestkey, - 'courserequests'); - } else { - $storeresult = 'error: invalid requestkey format'; + if ($validationerror ne '') { + $output .= '

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

'; } - if ($storeresult ne 'ok') { - $output .= ''.&mt('An error occurred saving a record of the details of your request.').'
'; - &logthis("Error saving course request - $requestkey for $env{'user.name'}:$env{'user.domain'} - $storeresult"); + if ($updateresult) { + $output .= $updateresult; } } - return $output; + if ($creationresult ne '') { + return ($creationresult,$output); + } else { + return ($storeresult,$output); + } } -sub get_processtype { - my ($dom,$crstype,$inststatuses,$domconfig) = @_; - return unless ((ref($inststatuses) eq 'ARRAY') && (ref($domconfig) eq 'HASH')); - my (%userenv,%settings,$val); - my @options = ('autolimit','validate','approve'); - if ($dom eq $env{'user.domain'}) { - %userenv = - &Apache::lonnet::userenvironment($env{'user.domain'},$env{'user.name'}, - 'requestcourses.'.$crstype,'inststatus'); - if ($userenv{'requestcourses.'.$crstype}) { - $val = $userenv{'requestcourses.'.$crstype}; - @{$inststatuses} = ('_custom_'); - } else { - my ($task,%alltasks); - if (ref($domconfig->{'requestcourses'}) eq 'HASH') { - %settings = %{$domconfig->{'requestcourses'}}; - if (ref($settings{$crstype}) eq 'HASH') { - if (($env{'user.adv'}) && (exists($settings{$crstype}{'_LC_adv'}))) { - $val = $settings{$crstype}{'_LC_adv'}; - @{$inststatuses} = ('_LC_adv_'); +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 { - if ($userenv{'inststatus'} ne '') { - @{$inststatuses} = split(',',$userenv{'inststatus'}); - } else { - @{$inststatuses} = ('other'); - } - foreach my $status (@{$inststatuses}) { - if (exists($settings{$crstype}{$status})) { - my $value = $settings{$crstype}{$status}; - next unless ($value); - unless (exists($alltasks{$value})) { - if (ref($alltasks{$value}) eq 'ARRAY') { - unless(grep(/^\Q$status\E$/,@{$alltasks{$value}})) { - push(@{$alltasks{$value}},$status); - } - } else { - @{$alltasks{$value}} = ($status); - } - } + &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}; } } - my $maxlimit = 0; - foreach my $key (sort(keys(%alltasks))) { - if ($key =~ /^autolimit=(\d*)$/) { - if ($1 eq '') { - $val ='autolimit='; - last; - } elsif ($1 > $maxlimit) { - $maxlimit = $1; - } + 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 ($maxlimit) { - $val = 'autolimit='.$maxlimit; - } else { - foreach my $option (@options) { - if ($alltasks{$option}) { - $val = $option; - last; - } + } + } + } + } + } + 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, + 'queuedreq',$sender); + } } } + if ($postprocess->{'queuedweb'}) { + $output .= $postprocess->{'queuedweb'}; + } } - } else { - %userenv = &Apache::lonnet::userenvironment($env{'user.domain'}, - $env{'user.name'},'reqcrsotherdom.'.$env{'form.crstype'}); - if ($userenv{'reqcrsotherdom'}) { - my @doms = split(',',$userenv{'reqcrsotherdom'}); - my $optregex = join('|',@options); - if (grep(/^\Q$dom\E:($optregex=?\d*)/,@doms)) { - $val = $1; + } elsif ($disposition eq 'pending') { + $output .= '
    '. +&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.'). + '
    '; + } 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 = 'createdreq'; + if ($code) { + $type = 'uniquecode'; + } + &Apache::loncoursequeueadmin::send_selfserve_notification($recipient,$addmsg,$dom.'_'.$cnum,$env{'form.cdescr'}, + $now,$type,$sender); } - @{$inststatuses} = ('_external_'); } + } else { + $output .= '
    '. + &mt('Your request status is: [_1].',$disposition). + '
    '; } - return $val; + 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'],[$dom]); - my ($types,$typename) = &course_types(); + 'userroles',['active','future'],['cc','co'],[$dom]); + my ($types,$typename) = &Apache::loncommon::course_types(); my %requests = &Apache::lonnet::dumpstore('courserequests',$udom,$uname); - my %count; - if (ref($types) eq 'ARRAY') { - foreach my $type (@{$types}) { - $count{$type} = 0; - } - } + my $count = 0; foreach my $key (keys(%requests)) { my ($cdom,$cnum) = split('_',$key); - if (exists($crsroles{$cnum.':'.$cdom.':cc'})) { - if (ref($requests{$key}) eq 'HASH') { - my $type = $requests{$key}{'crstype'}; - if ($type =~ /^official|unofficial|community$/) { - $count{$type} ++; - } + 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{$crstype} < $limit) { + if ($count < $limit) { return 'process'; } else { if (ref($typename) eq 'HASH') { - $$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); + 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 build_batchcreatehash { - my ($details) = @_; - my %batchhash; - if (ref($details) eq 'HASH') { +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 %batchhash; + return ($result,%reqinfo); } -sub retrieve_settings { - my ($dom,$request_id) = @_; - my %reqinfo = &get_request_settings($request_id,$dom); - my %stored; - $stored{'cdescr'} = &unescape($reqinfo{'description'}); - $stored{'startaccess'} = $reqinfo{'startaccess'}; - $stored{'endaccess'} = $reqinfo{'endaccess'}; - if ($stored{'endaccess'} == 0) { - $stored{'no_end_date'} = 1; - } - $stored{'startenroll'} = $reqinfo{'startenroll'}; - $stored{'endenroll'} = $reqinfo{'endenroll'}; - $stored{'crosslist'} = $reqinfo{'crosslist'}; - $stored{'clonecourse'} = $reqinfo{'clonecourse'}; - $stored{'clonedomain'} = $reqinfo{'clonedomain'}; - $stored{'sections'} = $reqinfo{'sections'}; - $stored{'personnel'} = $reqinfo{'personnel'}; +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; +} - return %stored; +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 get_request_settings { - my ($request_id,$dom); +sub print_textbook_form { + my ($r,$dom,$incdoms,$domdefs,$settings,$can_request) = @_; + my ($bookshash,%ordered); + my $crstype = 'textbook'; +# +# Retrieve list of textbook courses cloneable by user +# + my $numbook; + if (ref($settings) eq 'HASH') { + $bookshash = $settings->{'textbooks'}; + if (ref($bookshash) eq 'HASH') { + foreach my $item (keys(%{$bookshash})) { + my ($clonedom,$clonecrs) = split(/_/,$item); + if (ref($bookshash->{$item}) eq 'HASH') { + my ($clonedom,$clonecrs) = split(/_/,$item); + if (&Apache::loncoursequeueadmin::can_clone_course($env{'user.name'}, + $env{'user.domain'},$clonecrs,$clonedom,$crstype)) { + + my $num = $bookshash->{$item}{'order'}; + $ordered{$num} = $item; + $numbook ++; + } + } + } + } + } + +# +# 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($numbook,$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)) { + $r->print(''.(' 'x2).' '); + } + if (keys(%cloneable)) { + $r->print(''.(' 'x2).' '); + } + $r->print(''); + } else { + $r->print(''); + } + +# +# Table of cloneable textbook courses +# + if (keys(%ordered)) { + $r->print('
    '.&mt('Title').''.&mt('Author(s)').''.&mt('Subject').''.&mt('Book').''.$bookshash->{$item}->{'author'}.''.$bookshash->{$item}->{'subject'}.''.$cleantitle.''.&mt('Title').''.&mt('Owner/co-owner(s)').''.$namestr.'