--- loncom/interface/loncreatecourse.pm 2016/08/25 22:33:03 1.163 +++ loncom/interface/loncreatecourse.pm 2020/07/01 20:08:54 1.175 @@ -1,7 +1,7 @@ # The LearningOnline Network # Create a course # -# $Id: loncreatecourse.pm,v 1.163 2016/08/25 22:33:03 raeburn Exp $ +# $Id: loncreatecourse.pm,v 1.175 2020/07/01 20:08:54 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -80,9 +80,12 @@ use Apache::loncommon; use Apache::londocs; use Apache::lonlocal; use Apache::lonuserutils; -use Apache::lonclonecourse; use LONCAPA::batchcreatecourse; -use LONCAPA; +use LONCAPA qw(:DEFAULT :match); + +my $registered_flush; +my $registered_instcats; +my $modified_dom; # ===================================================== Phase one: fill-in form @@ -101,12 +104,13 @@ sub print_course_creation_page { foreach my $server (sort(keys(%host_servers))) { $course_home .= qq{}; } $course_home .= "\n\n"; - my $domform = &Apache::loncommon::select_dom_form($defdom,'ccdomain'); + my ($trusted,$untrusted) = &Apache::lonnet::trusted_domains('enroll',$defdom); + my $domform = &Apache::loncommon::select_dom_form($defdom,'ccdomain',undef,undef,undef,$trusted,$untrusted); my $cloneform=&Apache::loncommon::select_dom_form ($env{'request.role.domain'},'clonedomain'). &Apache::loncommon::selectcourse_link @@ -118,6 +122,8 @@ sub print_course_creation_page { my $endtime = time+(6*30*24*60*60); # 6 months from now, approx my $access_table = &Apache::lonuserutils::date_setting_table($starttime, $endtime,'create_defaultdates'); + my $openallfrom = + &Apache::lonhtmlcommon::date_setter('ccrs','openallfrom',$starttime); if (($crstype eq 'Course') || ($crstype eq 'Placement')) { $enroll_table = &Apache::lonuserutils::date_setting_table($starttime, $endtime,'create_enrolldates'); @@ -185,8 +191,13 @@ function validate(formname) { 'ncd' => "Do not clone date parameters", 'prd' => 'Clone date parameters as-is', 'shd' => 'Shift date parameters by number of days', + 'dpl' => 'URL shortcuts (for deep linking)', + 'nsl' => 'Do not clone URL shortcuts', + 'tsl' => 'Transfer URL shortcuts from existing course to new course', + 'csl' => 'Create new URL shortcuts in new course', 'assp' => "Assessment Parameters", 'oaas' => "Open all assessments", + 'sta' => "starting from:", 'mssg' => "Messaging", 'scpf' => "Set course policy feedback to Course Coordinator", 'scfc' => "Set resource content feedback to Course Coordinator", @@ -249,6 +260,8 @@ function validate(formname) { $lt{'cc'} = &mt('(will be assigned Coordinator role)'); $lt{'cgrs'} = &mt('Community Group Settings'); $lt{'cgrq'} = &mt('Set a quota for the total disk space available for storage of community group portfolio files'); + $lt{'tsl'} = &mt('Transfer URL shortcuts from existing community to new community'); + $lt{'csl'} = &mt('Create new URL shortcuts in new community'); } elsif ($crstype eq 'Placement') { $lt{'cinf'} = &mt('Placement Test Information'); $lt{'ctit'} = &mt('Placement Test Title'); @@ -264,6 +277,8 @@ function validate(formname) { } my $js = < +// $coursebrowserjs END @@ -301,7 +318,7 @@ END 'Create_Courses'); $r->print($start_page.$crumbs); - $r->print('
' + $r->print('
' .&Apache::lonhtmlcommon::start_pick_box() .&Apache::lonhtmlcommon::row_headline() @@ -371,6 +388,7 @@ END .'' .''.&mt('Yes').(' 'x2) .''.&mt('No') + .'' .&Apache::lonhtmlcommon::row_closure() ); } @@ -417,11 +435,12 @@ END .''.$lt{'navi'} .''); } + my $tinyurlhelp=&Apache::loncommon::help_open_topic('Clone_Tiny_URLs'); $r->print('
('.$lt{'stco'}.')' .&Apache::lonhtmlcommon::row_closure(1) .&Apache::lonhtmlcommon::end_pick_box() - .' ' + .' ' # Clone Course: .'' @@ -448,6 +467,17 @@ END .'' .' ' .&Apache::lonhtmlcommon::row_closure() + .&Apache::lonhtmlcommon::row_title($tinyurlhelp.$lt{'dpl'}) + .'
' + .'
' + .'' + .&Apache::lonhtmlcommon::row_closure() .&Apache::lonhtmlcommon::row_headline() .''.$lt{'asov'}.'' .&Apache::lonhtmlcommon::row_closure(1) @@ -471,7 +501,10 @@ END .&Apache::lonhtmlcommon::row_closure() .&Apache::lonhtmlcommon::row_title($lt{'oaas'}) - .'' + .'' + .''.(' 'x2) + .''.', ' + .$lt{'sta'}.' '.$openallfrom.'' .&Apache::lonhtmlcommon::row_closure() .&Apache::lonhtmlcommon::row_headline() @@ -585,7 +618,8 @@ END

-' + +

' ); } elsif ($crstype eq 'Community') { $r->print(' @@ -615,7 +649,7 @@ sub create_course { my $ccuname =&LONCAPA::clean_username($env{'form.ccuname'}); my $ccdomain=&LONCAPA::clean_domain($env{'form.ccdomain'}); my $crstype = 'Community'; - my ($enrollstart,$enrollend,$startaccess,$endaccess); + my ($enrollstart,$enrollend,$startaccess,$endaccess,$openallfrom); my %domdefaults = &Apache::lonnet::get_domain_defaults($env{'request.role.domain'}); @@ -628,6 +662,7 @@ sub create_course { } $startaccess = &Apache::lonhtmlcommon::get_date_from_form('startaccess'); $endaccess = &Apache::lonhtmlcommon::get_date_from_form('endaccess'); + $openallfrom = &Apache::lonhtmlcommon::get_date_from_form('openallfrom'); my $autharg; my $authtype; @@ -668,6 +703,7 @@ sub create_course { clonedomain => $env{'form.clonedomain'}, datemode => $env{'form.datemode'}, dateshift => $env{'form.dateshift'}, + tinyurls => $env{'form.tinyurls'}, crsid => $env{'form.crsid'}, curruser => $env{'user.name'}.':'.$env{'user.domain'}, crssections => $env{'form.crssections'}, @@ -693,6 +729,7 @@ sub create_course { disresdis => $env{'form.disresdis'}, disablechat => $env{'form.disablechat'}, openall => $env{'form.openall'}, + openallfrom => $openallfrom, firstres => $env{'form.firstres'} }; @@ -734,12 +771,20 @@ sub create_course { return; } my ($courseid,$crsudom,$crsunum,$code); - my ($success,$output) = + my ($success,$output,$clonemsgref) = &Apache::loncommon::construct_course($args,\$logmsg,\$courseid, \$crsudom,\$crsunum, $env{'user.domain'}, $env{'user.name'},'dc_create',undef,undef,\$code); $r->print($output); + if (ref($clonemsgref) eq 'ARRAY') { + my $user_lh = &Apache::loncommon::user_lang($env{'user.name'},$env{'user.domain'}); + foreach my $item (@{$clonemsgref}) { + if (ref($item) eq 'HASH') { + $r->print(&mt($item->{mt},@{$item->{args}}).'
'."\n"); + } + } + } if ($success) { # # Make the requested user a course coordinator or group coordinator @@ -763,8 +808,10 @@ sub create_course { '

'.&mt('Course identifier to share with students: [_1]',$code).'

' ); } - # Flush the course logs so reverse user roles immediately updated - $r->register_cleanup(\&Apache::lonnet::flushcourselogs); + if ($env{'form.crscode'} ne '') { + &Apache::lonnet::devalidate_cache_new('instcats',$crsudom); + } + ®ister_cleanups($r,$crsudom,$env{'form.crscode'}); $r->print('

'.&mt('Roles will be active at next login').'.

'); } $r->print('

'. @@ -773,7 +820,7 @@ sub create_course { } sub print_intro_page { - my ($r,$show_all_choices,$cancreate) = @_; + my ($r,$show_all_choices,$cancreate,$permission) = @_; my $start_page = &Apache::loncommon::start_page('Create a New Course, Community or Placement Test'); my $crumbs = &Apache::lonhtmlcommon::breadcrumbs('Creation Options','Create_Course',undef,'Create_Courses'); @@ -782,6 +829,10 @@ sub print_intro_page { my $helplink=&Apache::loncommon::help_open_topic('Create_Course_Community',&mt('Help on Creating Courses and Communities')); # Create menu + my $approve = 'Display requests awaiting approval'; + if ($permission->{'create'}) { + $approve = 'Approve or reject requests'; + } my @menu; @menu = ({ categorytitle => 'Course/Community Creation', @@ -789,7 +840,7 @@ sub print_intro_page { { linktext => 'Create a single course', url => '/adm/createcourse?phase=courseone', - permission => 1, + permission => $permission->{'create'}, #help => '', icon => 'crsnew.png', linktitle => 'Create a new course by completing an online form.' @@ -797,7 +848,7 @@ sub print_intro_page { { linktext => 'Create a single community', url => '/adm/createcourse?phase=groupone', - permission => $cancreate->{'Community'}, + permission => $permission->{'create'} && $cancreate->{'Community'}, #help => '', icon => 'crsnew.png', linktitle => 'Create a new collaborative community by completing an online form.' @@ -805,7 +856,7 @@ sub print_intro_page { { linktext => 'Create a single placement test', url => '/adm/createcourse?phase=placementone', - permission => $cancreate->{'Placement'}, + permission => $permission->{'create'} && $cancreate->{'Placement'}, #help => '', icon => 'crsnew.png', linktitle => 'Create a new placement test by completing an online form.' @@ -813,7 +864,7 @@ sub print_intro_page { { linktext => 'Create courses/communities/placement tests by uploading an attributes file', url => '/adm/createcourse?phase=batchone', - permission => 1, + permission => $permission->{'create'}, help => 'Batch_Creation', icon => 'uplcrs.png', linktitle => 'Upload an attributes file containing specifications for one or more courses, communities or placement tests in XML format.' @@ -823,7 +874,7 @@ sub print_intro_page { { categorytitle => 'Course/Community Requests', items => [ { - linktext => 'Approve or reject requests', + linktext => $approve, url => '/adm/createcourse?phase=requestdisplay', permission => $show_all_choices, #help => '', @@ -884,42 +935,70 @@ sub upload_batchfile { sub process_batchfile { my $r = shift; - my $start_page = - &Apache::loncommon::start_page('Create a New Course, Community or Placement Test'); - my $crumbs = &Apache::lonhtmlcommon::breadcrumbs('Creation Outcome','Create_Course',undef,'Create_Courses'); - my $end_page = - &Apache::loncommon::end_page(); my $defdom=$env{'request.role.domain'}; - my $batchfilepath=&Apache::lonnet::userfileupload('coursecreatorxml',undef, - 'batchupload',undef,undef, - undef,undef,$defdom); - my ($batchdir,$filename) = ($batchfilepath =~ m-^(.+)/pending/([^/]+)$-); - my ($result,$logmsg); - if (-e "$batchfilepath") { - open(FILE,"<$batchfilepath"); - my @buffer = ; - close(FILE); - if ((defined($filename)) && (defined($batchdir))) { - my @requests = ($filename); - my %courseids = (); - ($result,$logmsg) = &LONCAPA::batchcreatecourse::create_courses( - \@requests,\%courseids,'web',$defdom, - $env{'user.name'},$env{'user.domain'}); - if ($result) { - if (!-e "$batchdir/processed") { - mkdir("$batchdir/processed", 0755); - open(FILE,">$batchdir/processed/$filename"); - print FILE @buffer; + my $uname = $env{'user.name'}; + my $udom = $env{'user.domain'}; + my $dir = &LONCAPA::tempdir().'addcourse'; + my ($result,$logmsg,$clonemsg,$keysmsg,$codesref,$instcodesref); + if (($defdom =~ /^$match_domain$/) && ($uname =~ /^$match_username$/) && ($udom =~/^$match_domain$/)) { + my $batchfilepath=&Apache::lonnet::userfileupload('coursecreatorxml',undef, + 'batchupload',undef,undef, + undef,undef,$defdom); + if ($batchfilepath =~ m{^(\Q$dir/$defdom/web/$uname\E_\Q$udom\E)/pending/([^/]+)$}) { + my ($batchdir,$filename) = ($1,$2); + if (-e "$batchfilepath") { + if (open(FILE,"<",$batchfilepath)) { + my @buffer = ; close(FILE); - if (-e "$batchdir/processed/$filename") { - unlink("$batchdir/pending/$filename"); + if ((defined($filename)) && (defined($batchdir))) { + my @requests = ($filename); + my %courseids = (); + ($result,$logmsg,$clonemsg,$keysmsg,$codesref,$instcodesref) = + &LONCAPA::batchcreatecourse::create_courses( + \@requests,\%courseids,'web',$defdom, + $uname,$udom); + if (keys(%courseids) > 0) { + if (!-e "$batchdir/processed") { + mkdir("$batchdir/processed", 0755); + } + if (-d "$batchdir/processed") { + if (open(FILE,">","$batchdir/processed/$filename")) { + print FILE @buffer; + close(FILE); + } + } + if (-e "$batchdir/processed/$filename") { + unlink("$batchdir/pending/$filename"); + } + my $updatecats; + if ((ref($instcodesref) eq 'HASH') && (keys(%{$instcodesref}) > 0)) { + &Apache::lonnet::devalidate_cache_new('instcats',$defdom); + $updatecats = 1; + } + ®ister_cleanups($r,$defdom,$updatecats); + } + if ($clonemsg) { + $clonemsg = '

'.$clonemsg.'

'."\n"; + } } + } else { + $result = '

'.&mt('Could not open attributes file.').'
'.&mt('No courses created.').'

'; } + } else { + $result = '

'.&mt('No uploaded attributes file found.').'
'.&mt('No courses created.').'

'; } + } else { + $result = '

'.&mt('Invalid path to attributes file.').'
'.&mt('No courses created.').'

'; } + } else { + $result = '

'.&mt("Your username, domain, and/or your current role's domain are missing or contain invalid characters."). + '
'.&mt('No courses created.').'

'; } - $r->print($start_page.$crumbs.$logmsg.$result.'
'. - &mt('Creation options menu').''.$end_page); + $r->print(&Apache::loncommon::start_page('Create a New Course, Community or Placement Test'). + &Apache::lonhtmlcommon::breadcrumbs('Creation Outcome','Create_Course',undef,'Create_Courses'). + $logmsg.$clonemsg.$result.'
'. + &mt('Creation options menu').''. + &Apache::loncommon::end_page()); } @@ -1298,6 +1377,58 @@ ENDJS } +sub get_permission { + my ($dom) = @_; + my ($allowed,%permission); + if (&Apache::lonnet::allowed('ccc',$dom)) { + $allowed = 1; + %permission = ( + create => 1, + ); + } elsif (&Apache::lonnet::allowed('dcc',$dom)) { + $allowed = 1; + } + return ($allowed,\%permission); +} + +sub register_cleanups { + my ($r,$cdom,$updatecats) = @_; + # Flush the course logs so reverse user roles immediately updated + unless ($registered_flush) { + my $handlers = $r->get_handlers('PerlCleanupHandler'); + $r->set_handlers('PerlCleanupHandler' => [\&Apache::lonnet::flushcourselogs,@{$handlers}]); + $registered_flush=1; + } + # Update cache of self-cataloging courses on institution's server(s). + if ($updatecats) { + if (&Apache::lonnet::shared_institution($cdom)) { + unless ($registered_instcats) { + my $handlers = $r->get_handlers('PerlCleanupHandler'); + $r->set_handlers('PerlCleanupHandler' => [\&devalidate_remote_instcats,@{$handlers}]); + $registered_instcats=1; + $modified_dom = $cdom; + } + } + } + return; +} + +sub devalidate_remote_instcats { + if ($modified_dom ne '') { + my %servers = &Apache::lonnet::internet_dom_servers($modified_dom); + my %thismachine; + map { $thismachine{$_} = 1; } &Apache::lonnet::current_machine_ids(); + if (keys(%servers)) { + foreach my $server (keys(%servers)) { + next if ($thismachine{$server}); + &Apache::lonnet::remote_devalidate_cache($server,['instcats:'.$modified_dom]); + } + } + $modified_dom = ''; + } + return; +} + # ===================================================================== Handler sub handler { my $r = shift; @@ -1308,28 +1439,32 @@ sub handler { return OK; } - my $show_all_choices = 0; - my $primary_rev = &Apache::lonnet::get_server_loncaparev($env{'request.role.domain'}); - my %cancreate = ( - Community => 0, - Placement => 0, - ); - - if (($primary_rev ne 'refused') && ($primary_rev ne 'error') && - ($primary_rev ne 'unknown_cmd') && ($primary_rev ne 'no_such_host')) { - $show_all_choices = 1; - my ($primary_major,$primary_minor) = split(/\./,$primary_rev); - foreach my $key (keys(%cancreate)) { - my ($needsmajor,$needsminor) = - split(/\./,$Apache::lonnet::needsrelease{'course:crstype:'.$key}); - unless (($needsmajor > $primary_major) || - (($needsmajor == $primary_major) && ($needsminor > $primary_minor))) { - $cancreate{$key} = 1; + $registered_flush = 0; + $registered_instcats = 0; + $modified_dom = ''; + + my ($allowed,$permission) = &get_permission($env{'request.role.domain'}); + if ($allowed) { + my $show_all_choices = 0; + my $primary_rev = &Apache::lonnet::get_server_loncaparev($env{'request.role.domain'}); + my %cancreate = ( + Community => 0, + Placement => 0, + ); + if (($primary_rev ne 'refused') && ($primary_rev ne 'error') && + ($primary_rev ne 'unknown_cmd') && ($primary_rev ne 'no_such_host')) { + $show_all_choices = 1; + my ($primary_major,$primary_minor) = split(/\./,$primary_rev); + foreach my $key (keys(%cancreate)) { + my ($needsmajor,$needsminor) = + split(/\./,$Apache::lonnet::needsrelease{'course:crstype:'.$key}); + unless (($needsmajor > $primary_major) || + (($needsmajor == $primary_major) && ($needsminor > $primary_minor))) { + $cancreate{$key} = 1; + } } } - } - if (&Apache::lonnet::allowed('ccc',$env{'request.role.domain'})) { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; @@ -1340,11 +1475,12 @@ sub handler { ({href=>"/adm/createcourse", text=>"Creation Options", faq=>79,bug=>'Dom Coord Interface',}); - if (($env{'form.phase'} eq 'coursetwo') || - (($env{'form.phase'} eq 'grouptwo') && + if (($permission->{'create'}) && + (($env{'form.phase'} eq 'coursetwo') || + (($env{'form.phase'} eq 'grouptwo') && ($cancreate{'Community'})) || (($env{'form.phase'} eq 'placementtwo') && - ($cancreate{'Placement'}))) { + ($cancreate{'Placement'})))) { &Apache::lonhtmlcommon::add_breadcrumb ({href=>"/adm/createcourse?phase=$env{'form.prevphase'}", text=>&mt('[_1] Creation Settings',), @@ -1354,23 +1490,26 @@ sub handler { text=>"Creation Outcome", faq=>9,bug=>'Dom Coord Interface',}); &create_course($r); - } elsif (($env{'form.phase'} eq 'courseone') || - (($env{'form.phase'} eq 'groupone') && - ($cancreate{'Community'})) || - (($env{'form.phase'} eq 'placementone') && - ($cancreate{'Placement'}))) { + } elsif (($permission->{'create'}) && + (($env{'form.phase'} eq 'courseone') || + (($env{'form.phase'} eq 'groupone') && + ($cancreate{'Community'})) || + (($env{'form.phase'} eq 'placementone') && + ($cancreate{'Placement'})))) { &Apache::lonhtmlcommon::add_breadcrumb ({href=>"/adm/createcourse?phase=$env{'form.phase'}", text=>&mt('[_1] Creation Settings',), faq=>9,bug=>'Dom Coord Interface',}); &print_course_creation_page($r); - } elsif ($env{'form.phase'} eq 'batchone') { + } elsif (($permission->{'create'}) && + ($env{'form.phase'} eq 'batchone')) { &Apache::lonhtmlcommon::add_breadcrumb ({href=>"/adm/createcourse?phase=$env{'form.phase'}", text=>"Upload Description File", faq=>9,bug=>'Dom Coord Interface',}); &upload_batchfile($r); - } elsif ($env{'form.phase'} eq 'batchtwo') { + } elsif (($permission->{'create'}) && + ($env{'form.phase'} eq 'batchtwo')) { &Apache::lonhtmlcommon::add_breadcrumb ({href=>"/adm/createcourse?phase=$env{'form.prevphase'}", text=>"Upload Description File", @@ -1388,11 +1527,16 @@ sub handler { my $js = &courserequestbrowser_javascript(); my $start_page=&Apache::loncommon::start_page('Display Requests',$js); my $crumbs = &Apache::lonhtmlcommon::breadcrumbs('Display Requests','Course_Requests',undef,'Course_Requests'); + my $context = 'domain'; + unless ($permission->{'create'}) { + $context = 'helpdesk'; + } $r->print($start_page.$crumbs."\n".'
'. &Apache::loncoursequeueadmin::display_queued_requests( - 'domain',$env{'request.role.domain'}).'
'. + $context,$env{'request.role.domain'}).'
'. &Apache::loncommon::end_page()); - } elsif (($env{'form.phase'} eq 'requestchange') && ($show_all_choices)) { + } elsif (($permission->{'create'}) && + ($env{'form.phase'} eq 'requestchange') && ($show_all_choices)) { if ($env{'form.queue'} eq 'pending') { &Apache::lonhtmlcommon::add_breadcrumb ({href=>"/adm/createcourse?phase=pendingdisplay", @@ -1422,11 +1566,16 @@ sub handler { my $js = &courserequestbrowser_javascript(); my $start_page=&Apache::loncommon::start_page('Display Pending Queue',$js); my $crumbs = &Apache::lonhtmlcommon::breadcrumbs('Display Pending Queue','Course_Requests',undef,'Course_Requests'); + my $context = 'pending'; + unless ($permission->{'create'}) { + $context = 'displaypending'; + } $r->print($start_page.$crumbs."\n".'
'. &Apache::loncoursequeueadmin::display_queued_requests( - 'pending',$env{'request.role.domain'}).'
'. + $context,$env{'request.role.domain'}).'
'. &Apache::loncommon::end_page()); - } elsif (($env{'form.phase'} eq 'requestvalidation') && ($show_all_choices)) { + } elsif (($permission->{'create'}) && + ($env{'form.phase'} eq 'requestvalidation') && ($show_all_choices)) { my $js = &courserequestbrowser_javascript(); &Apache::lonhtmlcommon::add_breadcrumb ({href=>"/adm/createcourse?phase=pendingdisplay", @@ -1436,7 +1585,9 @@ sub handler { my $start_page=&Apache::loncommon::start_page('Requests Validation Result',$js); my $crumbs = &Apache::lonhtmlcommon::breadcrumbs('Validation Attempted','Course_Requests',undef,'Course_Requests'); $r->print($start_page.$crumbs."\n".'
'. - &Apache::loncoursequeueadmin::process_official_reqs('domain',$env{'request.role.domain'}).'
'. + &Apache::loncoursequeueadmin::process_official_reqs('domain',$env{'request.role.domain'}, + $env{'user.name'},$env{'user.domain'}). + ''. &Apache::loncommon::end_page()); } elsif (($env{'form.phase'} eq 'creationlog') && ($show_all_choices)) { &Apache::lonhtmlcommon::add_breadcrumb @@ -1453,7 +1604,7 @@ sub handler { &print_creation_logs($r); $r->print(''.&Apache::loncommon::end_page()); } else { - &print_intro_page($r,$show_all_choices,\%cancreate); + &print_intro_page($r,$show_all_choices,\%cancreate,$permission); } } else { $env{'user.error.msg'}=