# The LearningOnline Network
# Request a course
#
# $Id: lonrequestcourse.pm,v 1.12 2009/08/12 14:39:23 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
###
=head1 NAME
Apache::lonrequestcourse.pm
=head1 SYNOPSIS
Allows users to request creation of new courses.
This is part of the LearningOnline Network with CAPA project
described at http://www.lon-capa.org.
=head1 SUBROUTINES
=over
=item handler()
=item header()
=item form_elements()
=item onload_action()
=item check_can_request()
=item course_types()
=item print_main_menu()
=item request_administration()
=item print_request_form()
=item print_enrollment_menu()
=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 get_processtype()
=item check_autolimit()
=item build_batchcreatehash()
=item retrieve_settings()
=item get_request_settings()
=back
=cut
package Apache::lonrequestcourse;
use strict;
use Apache::Constants qw(:common :http);
use Apache::lonnet;
use Apache::loncommon;
use Apache::lonlocal;
use Apache::loncoursequeueadmin;
use LONCAPA qw(:DEFAULT :match);
sub handler {
my ($r) = @_;
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::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};
}
}
$jscript = &Apache::lonhtmlcommon::set_form_elements($elementsref,\%stored);
}
if ($state eq 'personnel') {
$jscript .= "\n".&Apache::loncommon::userbrowser_javascript();
}
my $loaditems = &onload_action($action,$state);
my %states;
$states{'view'} = ['pick_request','details','review','process'];
$states{'log'} = ['filter','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');
}
}
foreach my $key (keys(%states)) {
if (ref($states{$key}) eq 'ARRAY') {
unshift (@{$states{$key}},'crstype');
}
}
my %trail = (
crstype => 'Course Request Action',
codepick => 'Category',
courseinfo => 'Description',
enrollment => 'Enrollment',
personnel => 'Personnel',
review => 'Review',
process => 'Result',
pick_request => 'Display Summary',
);
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]}"});
} 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 Requests','Course_Requests');
}
my %can_request;
my $canreq = &check_can_request($dom,\%can_request);
if ($action eq 'new') {
if ($canreq) {
if ($state eq 'crstype') {
&print_main_menu($r,\%can_request,\%states,$dom,$jscript,$loaditems,
$crumb);
} else {
&request_administration($r,$action,$state,$page,\%states,$dom,$jscript,
$loaditems,$crumb);
}
} else {
$r->print(&header('Course Requests').$crumb.
'
'.
&mt('You do not have privileges to request creation of courses.').
'
'.&Apache::loncommon::end_page());
}
} elsif ($action eq 'view') {
if ($state eq 'crstype') {
&print_main_menu($r,\%can_request,\%states,$dom,$jscript,'',$crumb);
} else {
&request_administration($r,$action,$state,$page,\%states,$dom,$jscript,
$loaditems,$crumb);
}
} elsif ($action eq 'log') {
&print_request_logs($jscript,$loaditems,$crumb);
} else {
&print_main_menu($r,\%can_request,\%states,$dom,$jscript,'',$crumb);
}
return OK;
}
sub header {
my ($bodytitle,$jscript,$loaditems,$jsextra) = @_;
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);
}
}
sub form_elements {
my ($dom) = @_;
my %elements =
(
new => {
crstype => {
crstype => 'selectbox',
action => 'selectbox',
},
courseinfo => {
cdescr => 'text',
clonecourse => 'text',
clonedomain => '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',
no_end_date => 'checkbox',
},
personnel => {
persontotal => 'hidden',
addperson => 'checkbox',
},
},
view => {
crstype => {
crstype => 'selectbox',
action => 'selectbox',
},
},
);
my (@codetitles,%cat_titles,%cat_order,@code_order,$lastitem);
&Apache::lonnet::auto_possible_instcodes($dom,\@codetitles,\%cat_titles,
\%cat_order,\@code_order);
my $numtitles = scalar(@codetitles);
if ($numtitles) {
my %extras;
$lastitem = pop(@codetitles);
$extras{'instcode_'.$lastitem} = 'text';
foreach my $item (@codetitles) {
$extras{'instcode_'.$item} = 'selectbox';
}
$elements{'new'}{'codepick'} = \%extras;
}
if (&Apache::lonnet::auto_run('',$dom)) {
my %extras = (
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',
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 $crosslisttotal = $env{'form.crosslisttotal'};
if (!defined($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';
}
}
$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)) {
$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',
}
my %personnelhash = (%{$elements{'new'}{'personnel'}},%people);
%{$elements{'new'}{'personnel'}} = %personnelhash;
return %elements;
}
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;
}
}
}
}
}
}
return $canreq;
}
sub course_types {
my @types = ('official','unofficial','community');
my %typename = (
official => 'Official course',
unofficial => 'Unofficial course',
community => 'Community',
);
return (\@types,\%typename);
}
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 $nextstate_setter = "\n";
if (ref($states) eq 'HASH') {
foreach my $key (keys(%{$states})) {
if (ref($states->{$key}) eq 'ARRAY') {
$nextstate_setter .=
" if (actionchoice == '$key') {
nextstate = '".$states->{$key}[1]."';
}
";
}
}
}
my $js = <<"END";
function nextPage(formname) {
var crschoice = document.requestcrs.crstype.value;
var actionchoice = document.requestcrs.action.value;
if (check_can_request(crschoice,actionchoice) == true) {
if ((actionchoice == 'new') && (crschoice == 'official')) {
nextstate = 'codepick';
} else {
$nextstate_setter
}
formname.state.value= nextstate;
formname.submit();
}
return;
}
function check_can_request(crschoice,actionchoice) {
var official = '';
var unofficial = '';
var community = '';
END
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.',
);
$js .= <print(&header('Course Requests',$js.$jscript,$loaditems).$crumb.
'
'.
'
');
my $formname = 'requestcrs';
my $nexttext = &mt('Next');
$r->print('');
$r->print(&Apache::loncommon::end_page());
return;
}
sub request_administration {
my ($r,$action,$state,$page,$states,$dom,$jscript,$loaditems,$crumb) = @_;
my $js;
if (($action eq 'new') || ($action eq 'view')) {
$js = <print(&header('Request a course',$js.$jscript,$loaditems,$jsextra).$crumb);
&print_request_form($r,$action,$state,$page,$states,$dom);
} elsif ($action eq 'view') {
$r->print(&header('Manage course requests',$js.$jscript,$loaditems).$crumb);
if ($state eq 'pick_request') {
$r->print(&print_request_status($dom));
}
} elsif ($action eq 'log') {
$r->print(&coursereq_log('View request log',$jscript,$loaditems).$crumb);
}
$r->print(&Apache::loncommon::end_page());
return;
}
sub print_request_form {
my ($r,$action,$state,$page,$states,$dom) = @_;
my $formname = 'requestcrs';
my ($next,$prev,$message,$output,$codepicker,$crstype);
$prev = $states->{$action}[$page-1];
$next = $states->{$action}[$page+1];
my %navtxt = &Apache::lonlocal::texthash (
prev => 'Back',
next => 'Next',
);
$crstype = $env{'form.crstype'};
$r->print('