--- loncom/interface/loncreatecourse.pm	2020/05/22 19:57:57	1.158.2.6
+++ 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.158.2.6 2020/05/22 19:57:57 raeburn Exp $
+# $Id: loncreatecourse.pm,v 1.175 2020/07/01 20:08:54 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -80,7 +80,6 @@ use Apache::loncommon;
 use Apache::londocs;
 use Apache::lonlocal;
 use Apache::lonuserutils;
-use Apache::lonclonecourse;
 use LONCAPA::batchcreatecourse;
 use LONCAPA qw(:DEFAULT :match);
 
@@ -95,6 +94,8 @@ sub print_course_creation_page {
     my $crstype = 'Community';
     if ($env{'form.phase'} eq 'courseone') {
         $crstype = 'Course';
+    } elsif ($env{'form.phase'} eq 'placementone') {
+        $crstype = 'Placement';
     }
     my $defdom=$env{'request.role.domain'};
     my %domdefaults = &Apache::lonnet::get_domain_defaults($defdom);
@@ -108,7 +109,8 @@ sub print_course_creation_page {
         $course_home .= qq{>$server $host_servers{$server}</option>};
     }
     $course_home .= "\n</select>\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
@@ -122,7 +124,7 @@ sub print_course_creation_page {
                                              $endtime,'create_defaultdates');
     my $openallfrom =
         &Apache::lonhtmlcommon::date_setter('ccrs','openallfrom',$starttime);
-    if ($crstype eq 'Course') {
+    if (($crstype eq 'Course') || ($crstype eq 'Placement')) {
         $enroll_table = &Apache::lonuserutils::date_setting_table($starttime,
                                               $endtime,'create_enrolldates');
         ($krbdef,$krbdefdom) =
@@ -189,6 +191,10 @@ 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:",
@@ -222,6 +228,7 @@ function validate(formname) {
                     'cgrq' => 'Set a quota for the total disk space available for storage of course group portfolio files',
                     'opco' => 'Open Course',
                     'opcm' => 'Open Community',
+                    'oppt' => 'Open Placement Test',
 	       );
     $lt{'kaut'} = &mt('Key authority ([_1]id:domain[_2]) if other than course','<tt>','</tt>');
     $lt{'toin'} = &mt('to interface with institutional data, e.g., [_1]fs13glg231[_2] for [_3]Fall 2013 Geology 231[_4]','<tt>','</tt>','<i>','</i>');
@@ -253,6 +260,20 @@ 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');
+        $lt{'chsr'} = &mt('Placement Test Home Server');
+        $lt{'cidn'} = &mt('Placement Test ID/Number');
+        $lt{'crco'} = &mt('Placement Test Content');
+        $lt{'cncr'} = &mt('Completely new placement test');
+        $lt{'cecr'} = &mt('Clone an existing placement test');
+        $lt{'sacr'} = &mt('Do NOT generate as standard placement test');
+        $lt{'stco'} = &mt('standard placement tests only');
+        $lt{'navi'} = &mt('Placement Test Contents');
+        $lt{'cid'}  = &mt('Placement Test ID');
     }
     my $js = <<END;
 <script type="text/javascript">
@@ -285,6 +306,7 @@ END
     my %titles = &Apache::lonlocal::texthash(
                   courseone => 'Create a New Course',
                   groupone => 'Create a New Community',
+                  placementone=> 'Create a New Placement Test',
     );  
     my $start_page = 
         &Apache::loncommon::start_page($titles{$env{'form.phase'}},$js);
@@ -329,14 +351,16 @@ END
              .'<input type="text" size="30" name="crsid" />'
              .&Apache::lonhtmlcommon::row_closure()
     );
-    if ($crstype eq 'Course') {
+    if (($crstype eq 'Course') || ($crstype eq 'Placement')) {
         $r->print(&Apache::lonhtmlcommon::row_headline()
                  .'<h3>'.$lt{'iinf'}.'</h3>'
-                 .$lt{'stat'}.' '
-                 .&mt('Default credits can also be specified, if different from the domain defaults (official courses: [_1]; unofficial courses: [_2]; textbook courses: [_3]).',
-                      $domdefaults{'officialcredits'},$domdefaults{'unofficialcredits'},$domdefaults{'textbookcredits'})
-                 .&Apache::lonhtmlcommon::row_closure()
-
+                 .$lt{'stat'});
+        if ($crstype eq 'Course') {
+            $r->print(' '
+                     .&mt('Default credits can also be specified, if different from the domain defaults (official courses: [_1]; unofficial courses: [_2]; textbook courses: [_3]).',
+                          $domdefaults{'officialcredits'},$domdefaults{'unofficialcredits'},$domdefaults{'textbookcredits'}));
+        }
+        $r->print(&Apache::lonhtmlcommon::row_closure()
                  .&Apache::lonhtmlcommon::row_title($lt{'ccod'})
                  .'<input type="text" size="30" name="crscode" />'
                  .'<br />('.$lt{'toin'}.')'
@@ -352,7 +376,8 @@ END
                  .'<br />('.$lt{'cscs'}.')'
                  .&Apache::lonhtmlcommon::row_closure()
         );
-        if ($domdefaults{'officialcredits'} || $domdefaults{'unofficialcredits'} || $domdefaults{'textbookcredits'}) {
+        if (($crstype eq 'Course') && ($domdefaults{'officialcredits'} || 
+            $domdefaults{'unofficialcredits'} || $domdefaults{'textbookcredits'})) {
             $r->print(&Apache::lonhtmlcommon::row_title($lt{'ccre'})
                      .'<input type="text" size="3" name="defaultcredits" />'
                      .'<br />('.$lt{'cred'}.')'
@@ -363,9 +388,13 @@ END
                      .'<span class="LC_nobreak">'
                      .'<input type="radio" name="uniquecode" value="1" />'.&mt('Yes').('&nbsp;'x2)
                      .'<input type="radio" name="uniquecode" value="0" checked="checked" />'.&mt('No')
-                     .'</span> 
+                     .'</span>'
                      .&Apache::lonhtmlcommon::row_closure()
-            );
+                 );
+    }
+    my $blankchk;
+    if ($crstype eq 'Placement') {
+        $blankchk = ' checked="checked"';
     }
     # Table: New Course / Clone Course
     $r->print(&Apache::lonhtmlcommon::row_headline()
@@ -391,15 +420,14 @@ END
                  .&Apache::lonhtmlcommon::row_closure()
                  .&Apache::lonhtmlcommon::row_title($lt{'fres'})
                  .'<label>'
-                 .'<input type="radio" name="firstres" value="blank" />'.$lt{'blnk'}
-                 .'</label>'
-                 .'&nbsp;');
+                 .'<input type="radio" name="firstres" value="blank"'.$blankchk.' />'.$lt{'blnk'}
+                 .'</label>');
     if ($crstype eq 'Community') {
-        $r->print('<label>'
+        $r->print('&nbsp;<label>'
                  .'<input type="radio" name="firstres" value="nav" checked="checked" />'.$lt{'navi'}
                  .'</label>');
-    } else {
-        $r->print('<label>'
+    } elsif ($crstype eq 'Course') {
+        $r->print('&nbsp;<label>'
                  .'<input type="radio" name="firstres" value="syl" checked="checked" />'.$lt{'sllb'}
                  .'</label>'
                  .'&nbsp;'
@@ -407,6 +435,7 @@ END
                  .'<input type="radio" name="firstres" value="nav" />'.$lt{'navi'}
                  .'</label>');
     }
+    my $tinyurlhelp=&Apache::loncommon::help_open_topic('Clone_Tiny_URLs');
     $r->print('<br />('.$lt{'stco'}.')'
                  .&Apache::lonhtmlcommon::row_closure(1)
                  .&Apache::lonhtmlcommon::end_pick_box()
@@ -438,6 +467,17 @@ END
                  .'</label>'
                  .' <input type="text" size="5" name="dateshift" value="365" />'
                  .&Apache::lonhtmlcommon::row_closure()
+                 .&Apache::lonhtmlcommon::row_title($tinyurlhelp.$lt{'dpl'})
+                 .'<label>'
+                 .'<input type="radio" name="tinyurls" value="delete" /> '.$lt{'nsl'}
+                 .'</label><br />'
+                 .'<label>'
+                 .'<input type="radio" name="tinyurls" value="transfer" /> '.$lt{'tsl'}
+                 .'</label><br />'
+                 .'<label>'
+                 .'<input type="radio" name="tinyurls" value="create" checked="checked" /> '.$lt{'csl'}
+                 .'</label>'
+                 .&Apache::lonhtmlcommon::row_closure()
                  .&Apache::lonhtmlcommon::row_headline()
                  .'<span class="LC_info">'.$lt{'asov'}.'</span>'
                  .&Apache::lonhtmlcommon::row_closure(1)
@@ -515,7 +555,7 @@ END
                  .'<input type="text" name="reshome" size="30" value="/res/'.$defdom.'/" />'
                  .&Apache::lonhtmlcommon::row_closure()
     );
-    if ($crstype eq 'Course') {
+    unless ($crstype eq 'Community') {
         $r->print(&Apache::lonhtmlcommon::row_headline()
                  .'<h3>'.$lt{'aens'}.'</h3>'
                  .&Apache::lonhtmlcommon::row_closure()
@@ -589,6 +629,14 @@ END
 <input type="submit" value="'.$lt{'opcm'}.'" />
 </p>'
         );
+    } elsif ($crstype eq 'Placement') {
+        $r->print('
+<p>
+<input type="hidden" name="prevphase" value="placementone" />
+<input type="hidden" name="phase" value="placementtwo" />
+<input type="button" onclick="verify_message(this.form)" value="'.$lt{'oppt'}.'" />
+</p>'
+        );
     }
     $r->print('</form>'.
               $end_page);
@@ -609,6 +657,8 @@ sub create_course {
         $crstype='Course';
         $enrollstart=&Apache::lonhtmlcommon::get_date_from_form('startenroll');
         $enrollend=&Apache::lonhtmlcommon::get_date_from_form('endenroll');
+    } elsif ($env{'form.phase'} eq 'placementtwo') {
+        $crstype='Placement';
     }
     $startaccess = &Apache::lonhtmlcommon::get_date_from_form('startaccess');
     $endaccess   = &Apache::lonhtmlcommon::get_date_from_form('endaccess');
@@ -653,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'},
@@ -720,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}}).'<br />'."\n");
+            }
+        }
+    }
     if ($success) {
         #
 	# Make the requested user a course coordinator or group coordinator
@@ -763,7 +822,7 @@ sub create_course {
 sub print_intro_page {
     my ($r,$show_all_choices,$cancreate,$permission) = @_;
     my $start_page =
-        &Apache::loncommon::start_page('Create a New Course or Community');
+        &Apache::loncommon::start_page('Create a New Course, Community or Placement Test');
     my $crumbs = &Apache::lonhtmlcommon::breadcrumbs('Creation Options','Create_Course',undef,'Create_Courses');
     my $end_page =
         &Apache::loncommon::end_page();
@@ -795,12 +854,20 @@ sub print_intro_page {
                linktitle => 'Create a new collaborative community by completing an online form.'
           },
           {
-               linktext => 'Create courses/communities by uploading an attributes file',
+               linktext => 'Create a single placement test',
+               url => '/adm/createcourse?phase=placementone',
+               permission => $permission->{'create'} && $cancreate->{'Placement'},
+               #help => '',
+               icon => 'crsnew.png',
+               linktitle => 'Create a new placement test by completing an online form.'
+          },
+          {
+               linktext => 'Create courses/communities/placement tests by uploading an attributes file',
                url => '/adm/createcourse?phase=batchone',
                permission => $permission->{'create'},
                help => 'Batch_Creation',
                icon => 'uplcrs.png',
-               linktitle => 'Upload an attributes file containing specifications for one or more courses or communities in XML format.'
+               linktitle => 'Upload an attributes file containing specifications for one or more courses, communities or placement tests in XML format.'
           },
        ]
        },
@@ -812,7 +879,7 @@ sub print_intro_page {
                permission => $show_all_choices,
                #help => '',
                icon => 'rcrs.png',
-               linktitle => 'Display course and community creation requests submitted by authorized users, held pending approval by a Domain Coordinator.'
+               linktitle => 'Display course, community creation and placement test requests submitted by authorized users, held pending approval by a Domain Coordinator.'
            },
            {
                linktext => 'View pending official course requests',
@@ -833,7 +900,7 @@ sub print_intro_page {
                permission => $show_all_choices,
                #help => '',
                icon => 'document-properties.png',
-               linktitle => 'Display information about when, how and by whom courses and communities were created in this domain.'
+               linktitle => 'Display information about when, how and by whom courses, communities and placement tests were created in this domain.'
            },
        ]
        },
@@ -850,18 +917,18 @@ sub print_intro_page {
 sub upload_batchfile {
     my $r = shift;
     my $start_page =
-        &Apache::loncommon::start_page('Create a New Course or Community');
-    my $crumbs = &Apache::lonhtmlcommon::breadcrumbs('Upload Course/Community Attributes File','Create_Course',undef,'Create_Courses');
+        &Apache::loncommon::start_page('Create a New Course, Community, or Placement Test');
+    my $crumbs = &Apache::lonhtmlcommon::breadcrumbs('Upload Course/Community/Placement Test Attributes File','Create_Course',undef,'Create_Courses');
     my $end_page =
         &Apache::loncommon::end_page();
     $r->print($start_page.$crumbs);
-    $r->print('<h3>'.&mt('Upload a courses or communities attributes file').'</h3>');
+    $r->print('<h3>'.&mt('Upload a courses, communities or placement tests attributes file').'</h3>');
     $r->print('<form name="batchcreate" method="post" '.
                 'enctype="multipart/form-data" action="/adm/createcourse">'.
               '<input type="file" name="coursecreatorxml" />'.
               '<input type="hidden" name="phase" value="batchtwo" /><br /><br />'.
               '<input type="submit" name="batchsubmit" '.
-              'value="'.&mt('Create Courses/Communities').'" /></form>');
+              'value="'.&mt('Create Courses/Communities/Placement Tests').'" /></form>');
     $r->print($end_page);
     return;
 }
@@ -872,7 +939,7 @@ sub process_batchfile {
     my $uname = $env{'user.name'};
     my $udom = $env{'user.domain'};
     my $dir = &LONCAPA::tempdir().'addcourse';
-    my ($result,$logmsg,$keysmsg,$codesref,$instcodesref);
+    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,
@@ -886,7 +953,7 @@ sub process_batchfile {
                     if ((defined($filename)) && (defined($batchdir))) {
                         my @requests = ($filename);
                         my %courseids = ();
-                       ($result,$logmsg,$keysmsg,$codesref,$instcodesref) =
+                        ($result,$logmsg,$clonemsg,$keysmsg,$codesref,$instcodesref) =
                             &LONCAPA::batchcreatecourse::create_courses(
                                        \@requests,\%courseids,'web',$defdom,
                                        $uname,$udom);
@@ -907,9 +974,11 @@ sub process_batchfile {
                             if ((ref($instcodesref) eq 'HASH') && (keys(%{$instcodesref}) > 0)) {
                                 &Apache::lonnet::devalidate_cache_new('instcats',$defdom);
                                 $updatecats = 1;
-                            }
+                            } 
                             &register_cleanups($r,$defdom,$updatecats);
-
+                        }
+                        if ($clonemsg) {
+                            $clonemsg = '<p class="LC_info">'.$clonemsg.'</p>'."\n";
                         }
                     }
                 } else {
@@ -927,9 +996,10 @@ sub process_batchfile {
     }
     $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.$result.'<br /><a href="/adm/createcourse">'.
+              $logmsg.$clonemsg.$result.'<br /><a href="/adm/createcourse">'.
               &mt('Creation options menu').'</a>'.
               &Apache::loncommon::end_page());
+ 
 }
 
 sub courserequestbrowser_javascript {
@@ -1013,6 +1083,8 @@ sub print_creation_logs {
         $crstype = '.';
     } elsif ($curr{'type'} eq 'community') {
         $crstype = 'Community';
+    } elsif ($curr{'type'} eq 'placement') {
+        $crstype = 'Placement';
     }
 
     my ($instcodefilter,$regexpok);
@@ -1103,6 +1175,8 @@ sub print_creation_logs {
         my $showtype;
         if ($courses{$cid}{type} eq 'Community') {
             $showtype = &mt('community');
+        } elsif ($courses{$cid}{type} eq 'Placement') {
+            $showtype = &mt('placement test');
         } else {
             my $instcode = $courses{$cid}{inst_code};
             if ($instcode ne '')  {
@@ -1375,13 +1449,14 @@ sub handler {
         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) =
+                my ($needsmajor,$needsminor) = 
                     split(/\./,$Apache::lonnet::needsrelease{'course:crstype:'.$key});
                 unless (($needsmajor > $primary_major) ||
                         (($needsmajor == $primary_major) && ($needsminor > $primary_minor))) {
@@ -1402,8 +1477,10 @@ sub handler {
             faq=>79,bug=>'Dom Coord Interface',});
        if (($permission->{'create'}) &&
            (($env{'form.phase'} eq 'coursetwo') ||
-            (($env{'form.phase'} eq 'grouptwo') &&
-            ($cancreate{'Community'})))) {
+            (($env{'form.phase'} eq 'grouptwo') && 
+            ($cancreate{'Community'})) ||
+           (($env{'form.phase'} eq 'placementtwo') &&
+            ($cancreate{'Placement'})))) { 
            &Apache::lonhtmlcommon::add_breadcrumb
                  ({href=>"/adm/createcourse?phase=$env{'form.prevphase'}",
                    text=>&mt('[_1] Creation Settings',),
@@ -1414,9 +1491,11 @@ sub handler {
                    faq=>9,bug=>'Dom Coord Interface',});
            &create_course($r);
        } elsif (($permission->{'create'}) &&
-                (($env{'form.phase'} eq 'courseone') ||
-                 (($env{'form.phase'} eq 'groupone') &&
-                 ($cancreate{'Community'})))) {
+                (($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',),
@@ -1457,7 +1536,7 @@ sub handler {
                          $context,$env{'request.role.domain'}).'</div>'.
                      &Apache::loncommon::end_page());
        } elsif (($permission->{'create'}) &&
-                ($env{'form.phase'} eq 'requestchange') && ($show_all_choices)) { 
+                ($env{'form.phase'} eq 'requestchange') && ($show_all_choices)) {
            if ($env{'form.queue'} eq 'pending') {
                &Apache::lonhtmlcommon::add_breadcrumb
                    ({href=>"/adm/createcourse?phase=pendingdisplay",
@@ -1496,7 +1575,7 @@ sub handler {
                          $context,$env{'request.role.domain'}).'</div>'.
                      &Apache::loncommon::end_page());
        } elsif (($permission->{'create'}) &&
-                ($env{'form.phase'} eq 'requestvalidation') && ($show_all_choices)) { 
+                ($env{'form.phase'} eq 'requestvalidation') && ($show_all_choices)) {
            my $js = &courserequestbrowser_javascript();
            &Apache::lonhtmlcommon::add_breadcrumb
                  ({href=>"/adm/createcourse?phase=pendingdisplay",
@@ -1506,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".'<div>'.
-                     &Apache::loncoursequeueadmin::process_official_reqs('domain',$env{'request.role.domain'}).'</div>'.
+                     &Apache::loncoursequeueadmin::process_official_reqs('domain',$env{'request.role.domain'},
+                                                                         $env{'user.name'},$env{'user.domain'}).
+                     '</div>'.
                      &Apache::loncommon::end_page());
        } elsif (($env{'form.phase'} eq 'creationlog') && ($show_all_choices)) {
            &Apache::lonhtmlcommon::add_breadcrumb