[prev in list] [next in list] [prev in thread] [next in thread] 

List:       lon-capa-cvs
Subject:    [LON-CAPA-cvs] cvs: doc /loncapafiles loncapafiles.lpml loncom/automation Autocreate.pl batchcreatec
From:       raeburn <raeburn () source ! lon-capa ! org>
Date:       2020-07-01 20:09:13
Message-ID: cvsraeburn1593634153 () cvsserver
[Download RAW message or body]

This is a MIME encoded message


raeburn		Wed Jul  1 20:09:13 2020 EDT

  Added files:                 
    /loncom/html/adm/help/tex	Clone_Tiny_URLs.tex 

  Modified files:              
    /loncom/interface	londocs.pm lonclonecourse.pm loncommon.pm 
                     	loncoursequeueadmin.pm loncreatecourse.pm 
                     	lonrequestcourse.pm 
    /loncom/lonnet/perl	lonnet.pm 
    /loncom/automation	batchcreatecourse.pm Autocreate.pl 
    /loncom/html/adm/help/tex	Course_Request_Clone.tex 
                             	Batch_Creation.tex 
    /doc/loncapafiles	loncapafiles.lpml 
  Log:
  - Bug 6400 
    Options for transfer or creation of tiny URLs when cloning.
  
  
["raeburn-20200701200913.txt" (text/plain)]

Index: loncom/interface/londocs.pm
diff -u loncom/interface/londocs.pm:1.670 loncom/interface/londocs.pm:1.671
--- loncom/interface/londocs.pm:1.670	Fri Mar  6 19:40:57 2020
+++ loncom/interface/londocs.pm	Wed Jul  1 20:08:53 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Documents
 #
-# $Id: londocs.pm,v 1.670 2020/03/06 19:40:57 raeburn Exp $
+# $Id: londocs.pm,v 1.671 2020/07/01 20:08:53 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -4860,7 +4860,7 @@
         $r->rflush();
         my $readonly;
         if ($canedit) {
-            my ($numnew,$errors) = \
&Apache::loncommon::make_short_symbs($cdom,$cnum,$navmap); +            my \
($numnew,$errors) = &Apache::loncommon::get_requested_shorturls($cdom,$cnum,$navmap); \
                if ($numnew) {
                 $r->print('<p class="LC_info">'.&mt('Created \
[quant,_1,URL]',$numnew).'</p>');  }
Index: loncom/interface/lonclonecourse.pm
diff -u loncom/interface/lonclonecourse.pm:1.14 \
                loncom/interface/lonclonecourse.pm:1.15
--- loncom/interface/lonclonecourse.pm:1.14	Mon Jun  1 20:35:02 2020
+++ loncom/interface/lonclonecourse.pm	Wed Jul  1 20:08:54 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # routines for clone a course
 #
-# $Id: lonclonecourse.pm,v 1.14 2020/06/01 20:35:02 raeburn Exp $
+# $Id: lonclonecourse.pm,v 1.15 2020/07/01 20:08:54 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -30,6 +30,7 @@
 package Apache::lonclonecourse;
 use LONCAPA;
 use Apache::lonnet;
+use Apache::lonlocal;
 use DateTime();
 use DateTime::TimeZone;
 
@@ -130,10 +131,14 @@
 # =============================================================== Copy a dbfile
 
 sub copydb {
-    my ($origcrsid,$newcrsid,$which,$newinstcode)=@_;
+    my ($origcrsid,$newcrsid,$which,$newinstcode,$newowner,$tinyurls)=@_;
     $which=~s/\.db$//;
     my %origcrsdata=&Apache::lonnet::coursedescription($origcrsid);
     my %newcrsdata= &Apache::lonnet::coursedescription($newcrsid);
+    if (($which eq 'tiny') && ($tinyurls eq 'delete')) {
+        return ();
+    }
+    my @info;
     my %data=&Apache::lonnet::dump
 	($which,$origcrsdata{'domain'},$origcrsdata{'num'});
     foreach my $key (keys(%data)) {
@@ -146,9 +151,89 @@
         if ($origcrsdata{'internal.coursecode'} ne $newinstcode) {
             $data{'crslabel'} =~ \
s/\Q$origcrsdata{'internal.coursecode'}\E/$newinstcode/;  }
+    } elsif ($which eq 'tiny') {
+        my $oldprefix = \
'uploaded/'.$origcrsdata{'domain'}.'/'.$origcrsdata{'num'}.'/'; +        my \
$newprefix = 'uploaded/'.$newcrsdata{'domain'}.'/'. $newcrsdata{'num'}.'/'; +        \
my (%domtiny,%tocreate,@todelete,$numnew,$errors); +        if (($tinyurls eq \
'transfer') && (keys(%data))) { +            unless \
(($origcrsdata{'internal.courseowner'} eq $newowner) && +                    \
($origcrsdata{'domain'} eq $newcrsdata{'domain'})) { +                $tinyurls = \
'create'; +                push(@info,{
+                             mt => "Action for URL shortcut(s) changed from \
'transfer' to 'create' ". +                                   "because requirements \
of same owner and some course domain ". +                                   "for new \
course and original course not met.", +                             args => [],
+                           });
+            }
+        }
+        foreach my $key (keys(%data)) {
+            my $code = $data{$key};
+            my $newkey = $key;
+            $newkey =~ s{\Q$oldprefix\E}{$newprefix}g;
+            if ($tinyurls eq 'transfer') {
+                $data{$newkey} = $code;
+                $domtiny{$code} = $newcrsdata{'num'}.'&'.$newkey;
+                push(@todelete,$key);
+            } else {
+                $tocreate{$newcrsdata{'num'}.'&'.$newkey} = 1;
+            }
+            delete($data{$key});
+        }
+        if (keys(%tocreate)) {
+            ($numnew,$errors) = \
&Apache::loncommon::make_short_symbs($newcrsdata{'domain'}, +                         \
$newcrsdata{'num'}, +                                                                 \
\%tocreate,$newowner); +            if ((ref($errors) eq 'ARRAY') && (@{$errors} > \
0)) { +                push(@info,{
+                            mt => 'Error(s) when creating URL shortcut(s) in new \
course for equivalent '. +                                  'resource(s)/folder(s) in \
original course: [_1]', +                            args => [join(', ',@{$errors})],
+                           });
+            }
+            if ($numnew) {
+                push(@info,{
+                            mt => 'New URL shortcut(s) in new course for \
[quant,_1,item] to replicate '. +                                  'shortcut(s) for \
equivalent(s) in original course.', +                            args => [$numnew],
+                           });
+            }
+            return @info;
+        } elsif (keys(%domtiny)) {
+            my $configuname = \
&Apache::lonnet::get_domainconfiguser($newcrsdata{'domain'}); +            my \
$putdomres = &Apache::lonnet::put('tiny',\%domtiny,$newcrsdata{'domain'},$configuname);
 +            if ($putdomres eq 'ok') {
+                my $delres = &Apache::lonnet::del('tiny',\@todelete,
+                                                 $origcrsdata{'domain'},
+                                                 $origcrsdata{'num'});
+
+                if ($delres eq 'ok') {
+                    push(@info,{
+                                 mt => 'URL shortcut(s) for [quant,_1,item] \
transferred, and '. +                                       'now point to \
resource(s)/folder(s) in new course instead of '. +                                   \
'equivalent(s) in original course.', +                                 args => \
[scalar(keys(%domtiny))], +                               });
+                } else {
+                    push(@info,{
+                                 mt => 'Failed to delete URL shortcut(s) in original \
course '. +                                       'when attempting to transfer to new \
course.', +                                 args => [],
+                               });
+                }
+            } else {
+                push(@info,{
+                              mt => 'Failed to store update of target course for URL \
shortcut(s) in '. +                                    'domain records.',
+                              args => [],
+                           });
+                return @info;
+            }
+        }
     }
-    return &Apache::lonnet::put
-	($which,\%data,$newcrsdata{'domain'},$newcrsdata{'num'});
+    my $putres = &Apache::lonnet::put
+                     ($which,\%data,$newcrsdata{'domain'},$newcrsdata{'num'});
+    return @info;
 }
 
 # ========================================================== Copy resourcesdata
@@ -259,32 +344,41 @@
 	    &copyfile($origcrsid,$newcrsid,$_);
 	}
     }
+    return;
 }
 # ========================================================== Copy all userfiles
 
 sub copydbfiles {
-    my ($origcrsid,$newcrsid,$newinstcode)=@_;
+    my ($origcrsid,$newcrsid,$newinstcode,$newowner,$tinyurls)=@_;
+    my @copyinfo;
 
     my ($origcrs_discussion) = ($origcrsid=~m|^/(.*)|);
     $origcrs_discussion=~s|/|_|g;
     foreach (&crsdirlist($origcrsid)) {
-	if ($_=~/\.db$/) {
-        unless ($_=~/^(nohist\_|disclikes|discussiontimes|classlist|versionupdate
-                |resourcedata|\Q$origcrs_discussion\E|slots|slot_reservations
-                |gradingqueue|reviewqueue|CODEs|groupmembership|comm_block)/) {
-            &copydb($origcrsid,$newcrsid,$_,$newinstcode);
+        if ($_=~/\.db$/) {
+            unless ($_=~/^(nohist\_|disclikes|discussiontimes|classlist|versionupdate
 +                   |resourcedata|\Q$origcrs_discussion\E|slots|slot_reservations
+                   |gradingqueue|reviewqueue|CODEs|groupmembership|comm_block)/) {
+                my @info = &copydb($origcrsid,$newcrsid,$_,$newinstcode,$newowner,
+                                   $tinyurls);
+                if (@info) {
+                    push(@copyinfo,@info);
+                }
+            }
         }
-	}
     }
+    return @copyinfo;
 }
 
 # ======================================================= Copy all course files
 
 sub copycoursefiles {
-    my ($origcrsid,$newcrsid,$date_mode,$date_shift,$newinstcode)=@_;
+    my ($origcrsid,$newcrsid,$date_mode,$date_shift,$newinstcode,$newowner,
+        $tinyurls)=@_;
     &copyuserfiles($origcrsid,$newcrsid);
-    &copydbfiles($origcrsid,$newcrsid,$newinstcode);
+    my @info = &copydbfiles($origcrsid,$newcrsid,$newinstcode,$newowner,$tinyurls);
     &copyresourcedb($origcrsid,$newcrsid,$date_mode,$date_shift);
+    return @info;
 }
 
 1;
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1343 loncom/interface/loncommon.pm:1.1344
--- loncom/interface/loncommon.pm:1.1343	Tue Jun  9 21:32:32 2020
+++ loncom/interface/loncommon.pm	Wed Jul  1 20:08:54 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1343 2020/06/09 21:32:32 raeburn Exp $
+# $Id: loncommon.pm,v 1.1344 2020/07/01 20:08:54 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -15868,7 +15868,8 @@
     my $cloneid='/'.$args->{'clonedomain'}.'/'.$args->{'clonecourse'};
     my ($clonecrsudom,$clonecrsunum)= &LONCAPA::split_courseid($cloneid);
     my $clonehome=&Apache::lonnet::homeserver($clonecrsunum,$clonecrsudom);
-    my $clonemsg;
+    my $clonetitle;
+    my @clonemsg;
     my $can_clone = 0;
     my $lctype = lc($args->{'crstype'});
     if ($lctype ne 'community') {
@@ -15876,16 +15877,38 @@
     }
     if ($clonehome eq 'no_host') {
         if ($args->{'crstype'} eq 'Community') {
-            $clonemsg = &mt('No new community created.').$linefeed.&mt('A new \
community could not be cloned from the specified original - [_1] - because it is a \
non-existent community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'}); +        \
push(@clonemsg,({ +                              mt => 'No new community created.',
+                              args => [],
+                            },
+                            {
+                              mt => 'A new community could not be cloned from the \
specified original - [_1] - because it is a non-existent community.', +               \
args => [$args->{'clonedomain'}.':'.$args->{'clonedomain'}], +                        \
}));  } else {
-            $clonemsg = &mt('No new course created.').$linefeed.&mt('A new course \
could not be cloned from the specified original - [_1] - because it is a non-existent \
                course.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
-        }     
+            push(@clonemsg,({
+                              mt => 'No new course created.',
+                              args => [],
+                            },
+                            {
+                              mt => 'A new course could not be cloned from the \
specified original - [_1] - because it is a non-existent course.', +                  \
args => [$args->{'clonecourse'}.':'.$args->{'clonedomain'}], +                        \
})); +        }
     } else {
 	my %clonedesc = &Apache::lonnet::coursedescription($cloneid,{'one_time' => 1});
+        $clonetitle = $clonedesc{'description'};
         if ($args->{'crstype'} eq 'Community') {
             if ($clonedesc{'type'} ne 'Community') {
-                $clonemsg = &mt('No new community created.').$linefeed.&mt('A new \
community could not be cloned from the specified original - [_1] - because it is a \
                course not a \
                community.',$args->{'clonecourse'}.':'.$args->{'clonedomain'});
-                return ($can_clone, $clonemsg, $cloneid, $clonehome);
+                push(@clonemsg,({
+                                  mt => 'No new community created.',
+                                  args => [],
+                                },
+                                {
+                                  mt => 'A new community could not be cloned from \
the specified original - [_1] - because it is a course not a community.', +           \
args => [$args->{'clonecourse'}.':'.$args->{'clonedomain'}], +                        \
})); +                return ($can_clone,\@clonemsg,$cloneid,$clonehome);
             }
         }
 	if (($env{'request.role.domain'} eq $args->{'clonedomain'}) &&
@@ -15974,20 +15997,34 @@
             }
             unless ($can_clone) {
                 if ($args->{'crstype'} eq 'Community') {
-                    $clonemsg = &mt('No new community created.').$linefeed.&mt('The \
new community could not be cloned from the existing community because the new \
community owner ([_1]) does not have cloning rights in the existing community \
([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); +     \
push(@clonemsg,({ +                                      mt => 'No new community \
created.', +                                      args => [],
+                                    },
+                                    {
+                                      mt => 'The new community could not be cloned \
from the existing community because the new community owner ([_1]) does not have \
cloning rights in the existing community ([_2]).', +                                  \
args => [$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}], +     \
}));  } else {
-                    $clonemsg = &mt('No new course created.').$linefeed.&mt('The new \
course could not be cloned from the existing course because the new course owner \
([_1]) does not have cloning rights in the existing course \
([_2]).',$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}); +     \
push(@clonemsg,({ +                                      mt => 'No new course \
created.', +                                      args => [],
+                                    },
+                                    {
+                                      mt => 'The new course could not be cloned from \
the existing course because the new course owner ([_1]) does not have cloning rights \
in the existing course ([_2]).', +                                      args => \
[$args->{'ccuname'}.':'.$args->{'ccdomain'},$clonedesc{'description'}], +             \
}));  }
 	    }
         }
     }
-    return ($can_clone, $clonemsg, $cloneid, $clonehome);
+    return ($can_clone,\@clonemsg,$cloneid,$clonehome,$clonetitle);
 }
 
 sub construct_course {
     my ($args,$logmsg,$courseid,$crsudom,$crsunum,$udom,$uname,$context,
-        $cnum,$category,$coderef) = @_;
-    my $outcome;
+        $cnum,$category,$coderef,$callercontext,$user_lh) = @_;
+    my ($outcome,$msgref,$clonemsgref);
     my $linefeed =  '<br />'."\n";
     if ($context eq 'auto') {
         $linefeed = "\n";
@@ -15996,18 +16033,11 @@
 #
 # Are we cloning?
 #
-    my ($can_clone, $clonemsg, $cloneid, $clonehome);
+    my ($can_clone,$cloneid,$clonehome,$clonetitle);
     if (($args->{'clonecourse'}) && ($args->{'clonedomain'})) {
-	($can_clone, $clonemsg, $cloneid, $clonehome) = &check_clone($args,$linefeed);
-	if ($context ne 'auto') {
-            if ($clonemsg ne '') {
-	        $clonemsg = '<span class="LC_error">'.$clonemsg.'</span>';
-            }
-	}
-	$outcome .= $clonemsg.$linefeed;
-
+	($can_clone,$clonemsgref,$cloneid,$clonehome,$clonetitle) = \
&check_clone($args,$linefeed);  if (!$can_clone) {
-	    return (0,$outcome);
+	    return (0,$outcome,$clonemsgref);
 	}
     }
 
@@ -16030,15 +16060,20 @@
                                              $args->{'ccuname'}.':'.
                                              $args->{'ccdomain'},
                                              $args->{'crstype'},
-                                             $cnum,$context,$category);
+                                             $cnum,$context,$category,
+                                             $callercontext);
 
     # Note: The testing routines depend on this being output; see 
     # Utils::Course. This needs to at least be output as a comment
     # if anyone ever decides to not show this, and Utils::Course::new
     # will need to be suitably modified.
-    $outcome .= &mt('New LON-CAPA [_1] ID: \
[_2]',$showncrstype,$$courseid).$linefeed; +    if (($callercontext eq 'auto') && \
($user_lh ne '')) { +        $outcome .= &mt_user($user_lh,'New LON-CAPA [_1] ID: \
[_2]',$showncrstype,$$courseid).$linefeed; +    } else {
+        $outcome .= &mt('New LON-CAPA [_1] ID: \
[_2]',$showncrstype,$$courseid).$linefeed; +    }
     if ($$courseid =~ /^error:/) {
-        return (0,$outcome);
+        return (0,$outcome,$clonemsgref);
     }
 
 #
@@ -16047,24 +16082,37 @@
     ($$crsudom,$$crsunum)= &LONCAPA::split_courseid($$courseid);
     my $crsuhome=&Apache::lonnet::homeserver($$crsunum,$$crsudom);
     if ($crsuhome eq 'no_host') {
-        $outcome .= &mt('Course creation failed, unrecognized course home \
                server.').$linefeed;
-        return (0,$outcome);
+        if (($callercontext eq 'auto') && ($user_lh ne '')) {
+            $outcome .= &mt_user($user_lh,
+                            'Course creation failed, unrecognized course home \
server.'); +        } else {
+            $outcome .= &mt('Course creation failed, unrecognized course home \
server.'); +        }
+        $outcome .= $linefeed;
+        return (0,$outcome,$clonemsgref);
     }
     $outcome .= &mt('Created on').': '.$crsuhome.$linefeed;
 
 #
 # Do the cloning
 #   
+    my @clonemsg;
     if ($can_clone && $cloneid) {
-	$clonemsg = &mt('Cloning [_1] from [_2]',$showncrstype,$clonehome);
-	if ($context ne 'auto') {
-	    $clonemsg = '<span class="LC_success">'.$clonemsg.'</span>';
-	}
-	$outcome .= $clonemsg.$linefeed;
+        push(@clonemsg,
+                      {
+                          mt => 'Created [_1] by cloning from [_2]',
+                          args => [$showncrstype,$clonetitle],
+                      });
 	my %oldcenv=&Apache::lonnet::dump('environment',$$crsudom,$$crsunum);
 # Copy all files
-	&Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},
-	                                         $args->{'dateshift'},$args->{'crscode'});
+        my @info =
+	    &Apache::lonclonecourse::copycoursefiles($cloneid,$$courseid,$args->{'datemode'},
 +	                                             \
$args->{'dateshift'},$args->{'crscode'}, +                                            \
$args->{'ccuname'}.':'.$args->{'ccdomain'}, +                                         \
$args->{'tinyurls'}); +        if (@info) {
+            push(@clonemsg,@info);
+        }
 # Restore URL
 	$cenv{'url'}=$oldcenv{'url'};
 # Restore title
@@ -16395,7 +16443,7 @@
                  ('resourcedata',\%storecontent,$$crsudom,$$crsunum); 
     }
 
-    return (1,$outcome);
+    return (1,$outcome,\@clonemsg);
 }
 
 sub make_unique_code {
@@ -18201,24 +18249,37 @@
     return $plaintext;
 }
 
-sub make_short_symbs {
+sub get_requested_shorturls {
     my ($cdom,$cnum,$navmap) = @_;
     return unless (ref($navmap));
-    my ($numnew,@errors);
+    my ($numnew,$errors);
     my @toshorten = &Apache::loncommon::get_env_multiple('form.addtiny');
     if (@toshorten) {
         my (%maps,%resources,%titles);
         &Apache::loncourserespicker::enumerate_course_contents($navmap,\%maps,\%resources,\%titles,
                
                                                                \
                'shorturls',$cdom,$cnum);
-        my %tocreate;
         if (keys(%resources)) {
+            my %tocreate;
             foreach my $item (sort {$a <=> $b} (@toshorten)) {
                 my $symb = $resources{$item};
                 if ($symb) {
                     $tocreate{$cnum.'&'.$symb} = 1;
                 }
             }
+            if (keys(%tocreate)) {
+                ($numnew,$errors) = &make_short_symbs($cdom,$cnum,
+                                                      \%tocreate);
+            }
         }
+    }
+    return ($numnew,$errors);
+}
+
+sub make_short_symbs {
+    my ($cdom,$cnum,$tocreateref,$lockuser) = @_;
+    my ($numnew,@errors);
+    if (ref($tocreateref) eq 'HASH') {
+        my %tocreate = %{$tocreateref};
         if (keys(%tocreate)) {
             my %coursetiny = &Apache::lonnet::dump('tiny',$cdom,$cnum);
             my $su = Short::URL->new(no_vowels => 1);
@@ -18226,9 +18287,11 @@
             my (%newunique,%addcourse,%courseonly,%failed);
             # get lock on tiny db
             my $now = time;
+            if ($lockuser eq '') {
+                $lockuser = $env{'user.name'}.':'.$env{'user.domain'};
+            }
             my $lockhash = {
-                                "lock\0$now" => $env{'user.name'}.
-                                                ':'.$env{'user.domain'},
+                                "lock\0$now" => $lockuser,
                             };
             my $tries = 0;
             my $gotlock = &Apache::lonnet::newput_dom('tiny',$lockhash,$cdom);
Index: loncom/interface/loncoursequeueadmin.pm
diff -u loncom/interface/loncoursequeueadmin.pm:1.58 \
                loncom/interface/loncoursequeueadmin.pm:1.59
--- loncom/interface/loncoursequeueadmin.pm:1.58	Thu Aug  3 16:28:39 2017
+++ loncom/interface/loncoursequeueadmin.pm	Wed Jul  1 20:08:54 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Utilities to administer domain course requests and course self-enroll requests
 #
-# $Id: loncoursequeueadmin.pm,v 1.58 2017/08/03 16:28:39 raeburn Exp $
+# $Id: loncoursequeueadmin.pm,v 1.59 2020/07/01 20:08:54 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -304,11 +304,11 @@
     my $stamp = time;
     my $msgcount = &Apache::lonmsg::get_uniq();
     my $sender_lh = &Apache::loncommon::user_lang($uname,$udom,$cid);
-    $subject = &Apache::lonlocal::mt_user($sender_lh,$rawsubj);
+    $subject = &mt_user($sender_lh,$rawsubj);
     $message = '';
     foreach my $item (@rawmsg) {
         if (ref($item) eq 'HASH') {
-            $message .= \
&Apache::lonlocal::mt_user($sender_lh,$item->{mt},@{$item->{args}})."\n"; +           \
$message .= &mt_user($sender_lh,$item->{mt},@{$item->{args}})."\n";  }
     }
     &Apache::lonmsg::process_sent_mail($subject,'',$numsent,$stamp,$uname,$udom,$msgcount,$cid,$$,$message,
 @@ -322,41 +322,41 @@
     foreach my $recip (sort(keys(%{$msgcc}))) {
         my ($ccname,$ccdom) = split(/:/,$recip);
         my $recip_lh = &Apache::loncommon::user_lang($ccname,$ccdom,$cid);
-        my $subject = &Apache::lonlocal::mt_user($sender_lh,$rawsubj);
+        my $subject = &mt_user($sender_lh,$rawsubj);
         my $message = '';
         foreach my $item (@rawmsg) {
             if (ref($item) eq 'HASH') {
-                $message .= &Apache::lonlocal::mt_user($sender_lh,$item->{mt},
-                                                       @{$item->{args}})."\n";
+                $message .= &mt_user($sender_lh,$item->{mt},
+                                     @{$item->{args}})."\n";
             }
         }
         if ($context eq 'coursemanagers') {
             if ($approvedlist) {
-                $message .= "\n\n".&Apache::lonlocal::mt_user($sender_lh,'Approved \
enrollments:')."\n".$approvedlist; +                $message .= \
"\n\n".&mt_user($sender_lh,'Approved enrollments:')."\n".$approvedlist;  }
             if ($rejectedlist) {
-                $message .= "\n\n".&Apache::lonlocal::mt_user($sender_lh,'Rejected \
enrollments:')."\n".$rejectedlist; +                $message .= \
"\n\n".&mt_user($sender_lh,'Rejected enrollments:')."\n".$rejectedlist;  }
         } elsif ($context eq 'domainmanagers') {
             if ($approvedlist) {
-                $message .= "\n\n".&Apache::lonlocal::mt_user($sender_lh,'Approved \
course requests:')."\n".$approvedlist; +                $message .= \
"\n\n".&mt_user($sender_lh,'Approved course requests:')."\n".$approvedlist;  }
             if ($rejectedlist) {
-                $message .= "\n\n".&Apache::lonlocal::mt_user($sender_lh,'Rejected \
course requests:')."\n".$rejectedlist; +                $message .= \
"\n\n".&mt_user($sender_lh,'Rejected course requests:')."\n".$rejectedlist;  }
         } elsif ($context eq 'authormanagers') {
             if ($approvedlist) {
-                $message .= "\n\n".&Apache::lonlocal::mt_user($sender_lh,'Approved \
author role requests:')."\n".$approvedlist; +                $message .= \
"\n\n".&mt_user($sender_lh,'Approved author role requests:')."\n".$approvedlist;  }
             if ($rejectedlist) {
-                $message .= "\n\n".&Apache::lonlocal::mt_user($sender_lh,'Rejected \
author role requests:')."\n".$rejectedlist; +                $message .= \
"\n\n".&mt_user($sender_lh,'Rejected author role requests:')."\n".$rejectedlist;  }
         } elsif ($context eq 'usernamemanagers') {
             if ($approvedlist) {
-                $message .= "\n\n".&Apache::lonlocal::mt_user($sender_lh,'Approved \
LON-CAPA account requests:')."\n".$approvedlist; +                $message .= \
"\n\n".&mt_user($sender_lh,'Approved LON-CAPA account requests:')."\n".$approvedlist; \
}  if ($rejectedlist) {
-                $message .= "\n\n".&Apache::lonlocal::mt_user($sender_lh,'Rejected \
LON-CAPA account requests:')."\n".$rejectedlist; +                $message .= \
"\n\n".&mt_user($sender_lh,'Rejected LON-CAPA account requests:')."\n".$rejectedlist; \
}  }
         $status .= &Apache::lonmsg::user_normal_msg($ccname,$ccdom,$subject,$message,undef,undef,undef,1,
 @@ -982,7 +982,9 @@
                                                      $ownerdom,$ownername);
                         if ((ref($history{'details'}) eq 'HASH') && 
                             ($history{'disposition'} eq $queue)) {
-                            my \
($logmsg,$newusermsg,$addresult,$enrollcount,$response,$keysmsg,$code,%customitems); \
+                            my \
($logmsg,$newusermsg,$addresult,$enrollcount,$response, +                             \
$keysmsg,$code,%customitems); +                            my $clonemsg = [];
                             my $fullname = '';
                             my $inprocess = \
                &Apache::lonnet::auto_crsreq_update($cdom,$cnum,$crstype,'process',$ownername,
                
                                                                                 \
$ownerdom,$fullname,$coursedesc); @@ -996,8 +998,8 @@
                             if ($history{'details'}{'clonecrs'}) {
                                 $customitems{'_LC_clonefrom'} = \
$history{'details'}{'clonedom'}.'_'.$history{'details'}{'clonecrs'};  }
-                            my ($result,$postprocess) = \
                &course_creation($cdom,$cnum,$context,$history{'details'},\$logmsg,
-                                                        \
\$newusermsg,\$addresult,\$enrollcount, +                            my \
($result,$postprocess) = &course_creation($cdom,$cnum,$context,$history{'details'}, + \
                \$logmsg,$clonemsg,\$newusermsg,\$addresult,\$enrollcount,
                                                         \
\$response,\$keysmsg,\%domdefs,$longroles,\$code,\%customitems);  if ($result eq \
'created') {  if ($crstype eq 'community') {
@@ -1010,6 +1012,9 @@
                                     if (ref($approvedmsg->[1]) eq 'HASH') {
                                         $approvedmsg->[1]->{'args'} = [$firsturl];
                                     }
+                                    if ((ref($clonemsg) eq 'ARRAY') && \
(@{$clonemsg})) { +                                        \
push(@{$approvedmsg},@{$clonemsg}); +                                    }
                                     if ($code) {
                                         push(@{$approvedmsg},
                                             {
@@ -1608,8 +1613,9 @@
 }
 
 sub course_creation {
-    my ($dom,$cnum,$context,$details,$logmsg,$newusermsg,$addresult,$enrollcount,$output,
                
-        $keysmsg,$domdefs,$longroles,$coderef,$customhash) =  @_;
+    my ($dom,$cnum,$context,$details,$logmsg,$clonemsg,$newusermsg,$addresult,
+        $enrollcount,$output,$keysmsg,$domdefs,$longroles,$coderef,$customhash,
+        $callercontext,$user_lh) = @_;
     unless ((ref($details) eq 'HASH') && (ref($domdefs) eq 'HASH') && 
             (ref($longroles) eq 'HASH')) {
         return ('error: Invalid request');
@@ -1643,8 +1649,9 @@
     }
     my %reqdetails = \
                &build_batchcreatehash($dom,$context,$details,$owneremail,$domdefs);
     my $cid = &LONCAPA::batchcreatecourse::build_course($dom,$cnum,'requestcourses',
-                  \%reqdetails,$longroles,$logmsg,$newusermsg,$addresult,
-                  $enrollcount,$output,$keysmsg,$ownerdom,$ownername,$cnum,$crstype,$coderef);
 +                  \%reqdetails,$longroles,$logmsg,$clonemsg,$newusermsg,$addresult,
+                  $enrollcount,$output,$keysmsg,$ownerdom,$ownername,$cnum,$crstype,
+                  $coderef,$callercontext,$user_lh);
     my $postprocess;
     if ($cid eq "/$dom/$cnum") {
         $result = 'created';
@@ -1664,7 +1671,7 @@
 sub build_batchcreatehash {
     my ($dom,$context,$details,$owneremail,$domdefs) = @_;
     my %batchhash;
-    my @items = qw{owner domain coursehome clonecrs clonedom datemode dateshift \
enrollstart enrollend accessstart accessend sections crosslists users uniquecode}; +  \
my @items = qw{owner domain coursehome clonecrs clonedom datemode dateshift tinyurls \
enrollstart enrollend accessstart accessend sections crosslists users uniquecode};  \
if ((ref($details) eq 'HASH') && (ref($domdefs) eq 'HASH')) {  my $emailenc = \
&escape($owneremail);  my $owner = $details->{'owner'}.':'.$details->{'domain'};
@@ -2017,9 +2024,10 @@
         $longroles{$role}=&Apache::lonnet::plaintext($role);
     }
     my %domdefs = &Apache::lonnet::get_domain_defaults($dom);
-    my ($output,$linefeed);
+    my ($output,$linefeed,$user_lh);
     if ($context eq 'auto') {
         $linefeed = "\n";
+        $user_lh = &Apache::loncommon::user_lang($dcname,$dcdom);
     } else {
         $linefeed = '<br />'."\n";
     }
@@ -2081,6 +2089,7 @@
                 $reqstatus = $disposition;
                 if ($disposition eq 'process') {
                     my \
($logmsg,$newusermsg,$addresult,$enrollcount,$response,$keysmsg,$code); +             \
my $clonemsg = [];  my %customitems;
                     my $fullname = \
                &Apache::loncommon::plainname($ownername,$ownerdom);
                     my $inprocess = \
&Apache::lonnet::auto_crsreq_update($dom,$cnum,$crstype,'process',$ownername, @@ \
                -2096,8 +2105,9 @@
                         $customitems{'_LC_clonefrom'} = \
$history{'details'}{'clonedom'}.'_'.$history{'details'}{'clonecrs'};  }
                     my ($result,$postprocess) = 
-                        \
&course_creation($dom,$cnum,'domain',$history{'details'},\$logmsg,\$newusermsg,\$addresult,
                
-                                         \
\$enrollcount,\$response,\$keysmsg,\%domdefs,\%longroles,\$code,\%customitems); +     \
&course_creation($dom,$cnum,'domain',$history{'details'},\$logmsg,$clonemsg,\$newusermsg,
 +                                         \
\$addresult,\$enrollcount,\$response,\$keysmsg,\%domdefs,\%longroles, +               \
\$code,\%customitems,$context,$user_lh);  if ($result eq 'created') {
                         $disposition = 'created';
                         $reqstatus = 'created';
@@ -2112,14 +2122,20 @@
                                 [{
                                     mt => 'Your requested course: [_1], (queued \
pending validation) has now been created.',  args => [$cdescr],
-                                 },
+                                 }];
+                            if ((ref($clonemsg) eq 'ARRAY') && (@{$clonemsg})) {
+                                push(@{$approvedmsg},@{$clonemsg});
+                            }
+                            push(@{$approvedmsg},
                                  {
                                     mt   => 'Visit [_1] to log-in and access the \
course.',  args => [$firsturl],
                                  },
                                  {
-                                    mt => 'If currently logged-in to LON-CAPA, \
                log-out and log-in again to select your new course role.'
-                                 }];
+                                    mt => 'If currently logged-in to LON-CAPA, \
log-out and log-in again to select your new course role.', +                          \
args => [], +                                 }
+                            );
                             my $sender = $dcname.':'.$dcdom;
                             if (ref($postprocess) eq 'HASH') {
                                 if (ref($postprocess->{'createdmsg'}) eq 'ARRAY') {
Index: loncom/interface/loncreatecourse.pm
diff -u loncom/interface/loncreatecourse.pm:1.174 \
                loncom/interface/loncreatecourse.pm:1.175
--- loncom/interface/loncreatecourse.pm:1.174	Fri May 22 19:35:08 2020
+++ loncom/interface/loncreatecourse.pm	Wed Jul  1 20:08:54 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Create a course
 #
-# $Id: loncreatecourse.pm,v 1.174 2020/05/22 19:35:08 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::londocs;
 use Apache::lonlocal;
 use Apache::lonuserutils;
-use Apache::lonclonecourse;
 use LONCAPA::batchcreatecourse;
 use LONCAPA qw(:DEFAULT :match);
 
@@ -192,6 +191,10 @@
                     '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:",
@@ -257,6 +260,8 @@
         $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');
@@ -430,6 +435,7 @@
                  .'<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()
@@ -461,6 +467,17 @@
                  .'</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)
@@ -686,6 +703,7 @@
                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'},
@@ -753,12 +771,20 @@
         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
@@ -913,7 +939,7 @@
     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,
@@ -927,7 +953,7 @@
                     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);
@@ -949,7 +975,10 @@
                                 \
&Apache::lonnet::devalidate_cache_new('instcats',$defdom);  $updatecats = 1;
                             } 
-                            &register_cleanups($r,$defdom,$updatecats); 
+                            &register_cleanups($r,$defdom,$updatecats);
+                        }
+                        if ($clonemsg) {
+                            $clonemsg = '<p class="LC_info">'.$clonemsg.'</p>'."\n";
                         }
                     }
                 } else {
@@ -967,7 +996,7 @@
     }
     $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());
  
@@ -1556,7 +1585,9 @@
            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
Index: loncom/interface/lonrequestcourse.pm
diff -u loncom/interface/lonrequestcourse.pm:1.108 \
                loncom/interface/lonrequestcourse.pm:1.109
--- loncom/interface/lonrequestcourse.pm:1.108	Wed Feb 12 22:15:40 2020
+++ loncom/interface/lonrequestcourse.pm	Wed Jul  1 20:08:54 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Request a course
 #
-# $Id: lonrequestcourse.pm,v 1.108 2020/02/12 22:15:40 raeburn Exp $
+# $Id: lonrequestcourse.pm,v 1.109 2020/07/01 20:08:54 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -577,6 +577,7 @@
                 clonedom         => 'selectbox',
                 datemode         => 'radio',
                 dateshift        => 'text',
+                tinyurls         => 'radio',
             },
             enrollment  => {
                 accessstart_month  => 'selectbox',
@@ -2956,7 +2957,7 @@
         $inst_values .= '<td>'.$env{'form.coursecredits'}.'</td>';
     }
 
-    my %ctxt = &clone_text();
+    my %ctxt = &clone_text($env{'form.crstype'});
     $inst_headers .= '<th>'.&mt('Clone From').'</th>';
     if (($env{'form.cloning'}) &&
         ($env{'form.clonecrs'} =~ /^$match_name$/) && 
@@ -2968,7 +2969,8 @@
             my %courseenv = &Apache::lonnet::userenvironment($env{'form.clonedom'},
                               \
$env{'form.clonecrs'},('description','internal.coursecode'));  if (keys(%courseenv) > \
                0) {
-                $inst_headers .= '<th>'.$ctxt{'dsh'}.'</th>';
+                $inst_headers .= '<th>'.$ctxt{'dsh'}.'</th>'.
+                                 '<th>'.$ctxt{'dpl'}.'</th>';
                 $inst_values .= '<td>'.$courseenv{'description'}.'&nbsp;';
                 my $cloneinst = $courseenv{'internal.coursecode'};
                 if ($cloneinst ne '') {
@@ -2984,6 +2986,14 @@
                 } else {
                     $inst_values .= $ctxt{'ncd'};
                 }
+                $inst_values .= '</td><td>';
+                if ($env{'form.tinyurls'} eq 'delete') {
+                    $inst_values .= $ctxt{'nsl'};
+                } elsif ($env{'form.tinyurls'} eq 'transfer') {
+                    $inst_values .= $ctxt{'tsl'};
+                } else {
+                    $inst_values .= $ctxt{'csl'};
+                }
                 $inst_values .= '</td>';
              } else {
                  $inst_values .= '<td>'.&mt('Unknown').'</td>';
@@ -3215,7 +3225,7 @@
     } elsif ($crstype eq 'placement') {
         $type = 'Placement'; 
     }
-    my %lt = &clone_text();
+    my %lt = &clone_text($crstype);
     my $output .= 
         &Apache::lonhtmlcommon::row_title($lt{'dmn'}).'<label>'.
         &Apache::loncommon::select_dom_form($dom,'clonedom').'</label>'.
@@ -3233,19 +3243,37 @@
         '<input type="radio" name="datemode" value="shift" checked="checked" /> '.
         $lt{'shd'}.'</label>'.
         '<input type="text" size="5" name="dateshift" value="365" />'.
+        &Apache::lonhtmlcommon::row_closure(1).
+        &Apache::lonhtmlcommon::row_title($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(1);
     return $output;
 }
 
 sub clone_text {
-    return &Apache::lonlocal::texthash(
+    my ($crstype) = @_;
+    my %lt = &Apache::lonlocal::texthash(
                'cid'  => 'Course ID',
                'dmn'  => 'Domain',
                'dsh'  => 'Date Shift',
                'ncd'  => 'Do not clone date parameters',
                'prd'  => 'Clone date parameters as-is',
                'shd'  => 'Shift date parameters by number of days',
-        );
+               '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',
+    );
+    if ($crstype eq 'Community') {
+        $lt{'tsl'} = &mt('Transfer URL shortcuts from existing course to new \
community'); +        $lt{'csl'} = &mt('Create new URL shortcuts in new course');
+    }
+    return %lt;
 }
 
 sub coursecode_form {
@@ -3692,6 +3720,7 @@
                     clonecrs       => $clonecrs,
                     datemode       => $env{'form.datemode'},
                     dateshift      => $env{'form.dateshift'},
+                    tinyurls       => $env{'form.tinyurls'},
                     sectotal       => $sectotal,
                     sections       => \%sections,
                     crosslisttotal => $crosslisttotal,
@@ -3825,7 +3854,9 @@
             $storeresult = 'rejected';
         } elsif ($disposition eq 'process') {
             my %domdefs = &Apache::lonnet::get_domain_defaults($dom);
-            my ($logmsg,$newusermsg,$addresult,$enrollcount,$response,$keysmsg,%longroles,$code);
 +            my ($logmsg,$newusermsg,$addresult,$enrollcount,$response,
+                $keysmsg,%longroles,$code);
+            my $clonemsg = [];
             my $type = 'Course';
             if ($crstype eq 'community') {
                 $type = 'Community';
@@ -3858,9 +3889,9 @@
             $customitems{'_LC_coursestartdate'} = $accessstart;
             $customitems{'_LC_courseenddate'} = $accessend;
             my ($result,$postprocess) = \
                &Apache::loncoursequeueadmin::course_creation($dom,$cnum,
-                                          \
                'autocreate',$details,\$logmsg,\$newusermsg,\$addresult,
-                                          \
                \$enrollcount,\$response,\$keysmsg,\%domdefs,\%longroles,
-                                          \$code,\%customitems);
+                                          \
'autocreate',$details,\$logmsg,$clonemsg,\$newusermsg, +                              \
\$addresult,\$enrollcount,\$response,\$keysmsg,\%domdefs, +                           \
\%longroles,\$code,\%customitems);  if (ref($postprocess) eq 'HASH') {
                 $customized = $postprocess->{'createdcustomized'};
             }
@@ -3894,6 +3925,20 @@
                     $output .= '<br />'.$role_result;
                 }
                 $output .= '</p>';
+                if ($logmsg) {
+                    $output .= '<p>'.$logmsg.'</p>';
+                }
+                if ((ref($clonemsg) eq 'ARRAY') && (@{$clonemsg})) {
+                    $output .= '<p class="LC_info">';
+                    my $user_lh = \
&Apache::loncommon::user_lang($env{'user.name'},$env{'user.domain'}); +               \
foreach my $item (@{$clonemsg}) { +                        if (ref($item) eq 'HASH') \
{ +                            $output .= &mt_user($user_lh,$item->{mt},
+                                                @{$item->{args}}).'<br />'."\n";
+                        }
+                    }
+                    $output .= '</p>'."\n";
+                }
                 $creationresult = 'created';
                 # Flush the course logs so reverse user roles immediately updated
                 unless ($registered_flush) {
@@ -4451,6 +4496,7 @@
             }
             $env{'form.datemode'} = $reqinfo{'datemode'};
             $env{'form.dateshift'} = $reqinfo{'dateshift'};
+            $env{'form.tinyurls'} = $reqinfo{'tinyurls'};
             if ($reqinfo{'crstype'} eq 'official') {
                 $env{'form.autoadds'} = $reqinfo{'autoadds'};
                 $env{'form.autodrops'} = $reqinfo{'autodrops'};
@@ -4861,17 +4907,26 @@
 #
 # Table of user's current courses (owner and/or course coordinator)
 #
-    my %lt = &clone_text();
+    my %lt = &clone_text('Course');
     if (keys(%cloneable)) {
         $r->print('<div id="showexisting" style="display:none">'.
                   &clone_selection_table($dom,'owned',\%cloneable).
-                  '<p><input type="radio" name="owndatemode" value="delete" /> \
'.$lt{'ncd'}. +                  '<fieldset \
style="display:inline-block"><legend>'.$lt{'dsh'}.'</legend><label>'. +               \
'<input type="radio" name="owndatemode" value="delete" /> '.$lt{'ncd'}.  '</label><br \
                /><label>'.
                   '<input type="radio" name="owndatemode" value="preserve" /> \
'.$lt{'prd'}.  '</label><br /><label>'.
                   '<input type="radio" name="owndatemode" value="shift" \
checked="checked" /> '.  $lt{'shd'}.'</label>'.
                   '<input type="text" size="5" name="owndateshift" value="365" />'.
+                  '</fieldset><fieldset style="display:inline-block">'.
+                  '<legend>'.$lt{'dpl'}.'</legend><label>'.
+                  '<input type="radio" name="owntinyurls" value="delete" \
/>'.$lt{'nsl'}. +                  '</label><br /><label>'.
+                  '<input type="radio" name="owntinyurls" value="transfer" \
/>'.$lt{'tsl'}. +                  '</label><br /><label>'.
+                  '<input type="radio" name="owntinyurls" value="create" \
checked="checked" />'.$lt{'csl'}. +                  '</label></fieldset>'.
                   '</div>');
     }
 #
@@ -4880,13 +4935,20 @@
     if (keys(%domcloneable)) {
         $r->print('<div id="showcolleague" style="display:none">'.
                   &clone_selection_table($dom,'colleague',\%domcloneable).
-                  '<p><input type="radio" name="colldatemode" value="delete" /> \
'.$lt{'ncd'}. +                  '<fieldset \
style="display:inline-block"><legend>'.$lt{'dsh'}.'</legend><label>'. +               \
'<input type="radio" name="colldatemode" value="delete" /> '.$lt{'ncd'}.  \
                '</label><br /><label>'.
                   '<input type="radio" name="colldatemode" value="preserve" /> \
'.$lt{'prd'}.  '</label><br /><label>'.
                   '<input type="radio" name="colldatemode" value="shift" \
checked="checked" /> '.  $lt{'shd'}.'</label>'.
                   '<input type="text" size="5" name="colldateshift" value="365" />'.
+                  '</fieldset><fieldset style="display:inline-block">'.
+                  '<legend>'.$lt{'dpl'}.'</legend><label>'.
+                  '<input type="radio" name="colltinyurls" value="delete" \
/>'.$lt{'nsl'}. +                  '</label><br /><label>'.
+                  '<input type="radio" name="colltinyurls" value="create" \
checked="checked" />'.$lt{'csl'}. +                  '</label></fieldset>'.
                   '</div>');
     }
 
@@ -5134,6 +5196,7 @@
             } else {
                 $details->{dateshift} = '';
             }
+            $details->{tinyurls} = $env{'form.owntinyurls'};
         } elsif ($reqtype eq 'colleague') {
             $details->{datemode} = $env{'form.colldatemode'};
             if ($details->{datemode} eq 'shift') {
@@ -5141,9 +5204,11 @@
             } else {
                 $details->{dateshift} = '';
             }
+            $details->{tinyurls} = $env{'form.colltinyurls'};
         } elsif (($reqtype eq 'textbook') || ($reqtype eq 'template')) {
             $details->{datemode} = 'delete';
             $details->{dateshift} = '';
+            $details->{tinyurls} = '';
         }
         if ($details->{dateshift} ne '') {
             $details->{dateshift} =~ s/[^\d\.]+//g;
@@ -5151,6 +5216,7 @@
     } else {
         $details->{datemode} = '';
         $details->{dateshift} = '';
+        $details->{tinyurls} = '';
     }
     my $lonhost = $r->dir_config('lonHostID');
     $r->rflush();
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1422 loncom/lonnet/perl/lonnet.pm:1.1423
--- loncom/lonnet/perl/lonnet.pm:1.1422	Wed May 13 17:44:10 2020
+++ loncom/lonnet/perl/lonnet.pm	Wed Jul  1 20:08:58 2020
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1422 2020/05/13 17:44:10 raeburn Exp $
+# $Id: lonnet.pm,v 1.1423 2020/07/01 20:08:58 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -10607,14 +10607,19 @@
 
 sub createcourse {
     my ($udom,$description,$url,$course_server,$nonstandard,$inst_code,
-        $course_owner,$crstype,$cnum,$context,$category)=@_;
+        $course_owner,$crstype,$cnum,$context,$category,$callercontext)=@_;
     $url=&declutter($url);
     my $cid='';
     if ($context eq 'requestcourses') {
         my $can_create = 0;
         my ($ownername,$ownerdom) = split(':',$course_owner);
         if ($udom eq $ownerdom) {
-            if (&usertools_access($ownername,$ownerdom,$category,undef,
+            my $reload;
+            if (($callercontext eq 'auto') &&
+               ($ownerdom eq $env{'user.domain'}) && ($ownername eq \
$env{'user.name'})) { +                $reload = 'reload';
+            }
+            if (&usertools_access($ownername,$ownerdom,$category,$reload,
                                   $context)) {
                 $can_create = 1;
             }
Index: loncom/automation/batchcreatecourse.pm
diff -u loncom/automation/batchcreatecourse.pm:1.44 \
                loncom/automation/batchcreatecourse.pm:1.45
--- loncom/automation/batchcreatecourse.pm:1.44	Fri May 22 15:05:36 2020
+++ loncom/automation/batchcreatecourse.pm	Wed Jul  1 20:09:03 2020
@@ -1,5 +1,5 @@
 #
-# $Id: batchcreatecourse.pm,v 1.44 2020/05/22 15:05:36 raeburn Exp $
+# $Id: batchcreatecourse.pm,v 1.45 2020/07/01 20:09:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -80,6 +80,7 @@
 # <clonedom>msu</clonedom>
 # <datemode>shift</datemode>
 # <dateshift>365</dateshift>
+# <tinyurls>create</tinyurls>
 # <showphotos></showphotos>
 # <setpolicy>1</setpolicy>
 # <setcontent>1</setcontent>
@@ -189,12 +190,16 @@
 #                   uname - username of DC who is requesting course creation
 #                   udom - domain of DC who is requesting course creation
 #  
-# outputs (four)  -  output - text recording user roles added etc.
-#                    logmsg - text to be logged
-#                    keysmsg - text containing link(s) to manage keys page(s) 
-#                    codehash - reference to hash containing courseID => unique code
-#                               where unique code is a 6 character code, to \
                distribute
-#                               to students as a shortcut to the course.
+# outputs (six)  -  output - text recording user roles added etc.
+#                   logmsg - text to be logged
+#                   cloneinfo - text output from cloning
+#                   keysmsg - text containing link(s) to manage keys page(s) 
+#                   codehash - reference to hash containing courseID => unique code
+#                              where unique code is a 6 character code, to \
distribute +#                              to students as a shortcut to the course.
+#                   instcodes - references to hash of an array, where keys are
+#                               institutional codes and values are an array of
+#                               courseIDs of courses with that code.
 #############################################################
 
 sub create_courses {
@@ -212,10 +217,12 @@
             $longroles{'Community'}{$1} = $3;
         }
     }
-    my ($logmsg,$keysmsg,$newusermsg,$addresult,%codehash,%instcodes);
+    my ($logmsg,$cloneinfo,$keysmsg,$newusermsg,$addresult,$user_lh,
+        %codehash,%instcodes);
     my %enrollcount = ();
     my $newcoursedir = LONCAPA::tempdir().'/addcourse/'.$dom.'/'.$context;
     if ($context eq 'auto') {
+        $user_lh = &Apache::loncommon::user_lang($uname,$udom);
         $newcoursedir .= '/pending';
     } else {
         if ($uname && $udom) {
@@ -227,14 +234,16 @@
     if (@{$requests} > 0) {
         foreach my $request (@{$requests}) {
             my %details = ();
+            my $clonemsg = [];
             if (-e $newcoursedir.'/'.$request) {
                 &parse_coursereqs($newcoursedir.'/'.$request, \%details);
                 foreach my $num (sort(keys(%details))) {
                     my $reqdetails = $details{$num};
                     my $code;
-                    my $courseid = 
-                        \
                &build_course($dom,$num,$context,$reqdetails,\%longroles,\$logmsg,\$newusermsg,
                
-                                      \
\$addresult,\%enrollcount,\$output,\$keysmsg,undef,undef,undef,undef,\$code); +       \
my $courseid = +                        \
&build_course($dom,$num,$context,$reqdetails,\%longroles,\$logmsg, +                  \
$clonemsg,\$newusermsg,\$addresult,\%enrollcount, +                                   \
\$output,\$keysmsg,undef,undef,undef,undef,\$code);  if ($courseid \
=~m{^/$match_domain/$match_courseid}) {  $$courseids{$courseid} = \
$details{$num}{'class'};  if ($code) {
@@ -244,11 +253,33 @@
                             \
push(@{$instcodes{$details{$num}{'coursecode'}}},$courseid);  }
                     }
+                    if (@{$clonemsg}) {
+                        if ($context eq 'web') {
+                            $cloneinfo .= '<p class="LC_info">';
+                        }
+                        foreach my $item (@{$clonemsg}) {
+                            if (ref($item) eq 'HASH') {
+                                if ($context eq 'auto') {
+                                    $cloneinfo .= &mt_user($user_lh,$item->{mt},
+                                                           @{$item->{args}});
+                                } else {
+                                    $cloneinfo .= &mt($item->{mt},@{$item->{args}});
+                                }
+                            }
+                            if ($context eq 'web') {
+                                $cloneinfo .= '<br />';
+                            }
+                            $cloneinfo .= "\n";
+                        }
+                        if ($context eq 'web') {
+                            $cloneinfo .= '</p>';
+                        }
+                    }
                 }
             }
         }
     }
-    return ($output,$logmsg,$keysmsg,\%codehash,\%instcodes);
+    return ($output,$logmsg,$cloneinfo,$keysmsg,\%codehash,\%instcodes);
 }
 
 #############################################################
@@ -271,7 +302,7 @@
     my $xlist = 0;
     my $userkey = '';
     my $role = '';
-    my @items = ('title','optional_id','coursecode','defaultcredits','coursehome','re \
shome','nonstandard','adds','drops','topmap','firstres','clonecrs','clonedom','datemod \
e','dateshift','showphotos','setpolicy','setcontent','setcomment','setkeys','keyauth', \
'disresdis','disablechat','openall','notify_owner','notify_dc','crstype','crsquota','uniquecode');
 +    my @items = ('title','optional_id','coursecode','defaultcredits','coursehome','r \
eshome','nonstandard','adds','drops','topmap','firstres','clonecrs','clonedom','datemo \
de','dateshift','tinyurls','showphotos','setpolicy','setcontent','setcomment','setkeys \
','keyauth','disresdis','disablechat','openall','notify_owner','notify_dc','crstype','crsquota','uniquecode');
  my @possroles = qw(st ad ep ta in cc co);
     my @dateitems = \
                ('enrollstart','enrollend','accessstart','accessend','openallfrom');
     my @useritems = \
('autharg','authtype','firstname','generation','lastname','middlename','studentID'); \
@@ -397,6 +428,7 @@  #   ref to hash of course creation information
 #   ref to hash of role descriptions
 #   ref to scalar used to accumulate log messages
+#   ref to array used to accumulate messages about cloning
 #   ref to scalar used to accumulate messages sent to new users
 #   ref to scalar used to accumulate results of new user additions
 #   ref to hash of enrollment counts for different roles
@@ -408,6 +440,8 @@
 #       course requests submitted via course request form.
 #   optional category
 #   optional ref to scalar for six character unique identifier
+#   caller context (e.g., auto)
+#   user language handle, if caller context is 'auto'
 #
 # outputs
 #   LON-CAPA courseID for new (created) course
@@ -415,8 +449,9 @@
 #########################################################
 
 sub build_course {
-    my ($cdom,$num,$context,$details,$longroles,$logmsg,$newusermsg,$addresult,
-        $enrollcount,$output,$keysmsg,$udom,$uname,$cnum,$category,$coderef) = @_;
+    my ($cdom,$num,$context,$details,$longroles,$logmsg,$clonemsg,$newusermsg,
+        $addresult,$enrollcount,$output,$keysmsg,$udom,$uname,$cnum,$category,
+        $coderef,$callercontext,$user_lh) = @_;
     return unless (ref($details) eq 'HASH');
     my $owner_uname = $details->{'owner'};
     my $owner_domain = $details->{'domain'};
@@ -510,6 +545,9 @@
             $details->{'datemode'} = 'shift';
             $details->{'dateshift'} = 365;
         }
+        if ($details->{'tinyurls'} !~ /^(delete|transfer|create)$/) {
+            $details->{'tinyurls'} = 'create';
+        }
         my $courseargs = {
                ccuname => $details->{'owner'},
                ccdomain => $details->{'domain'},
@@ -527,6 +565,7 @@
                clonedomain => $details->{'clonedom'},
                datemode => $details->{'datemode'},
                dateshift => $details->{'dateshift'},
+               tinyurls => $details->{'tinyurls'},
                crsid => $details->{'optional_id'},
                curruser => $details->{'owner'},
                crssections => $sectionstr,
@@ -563,10 +602,14 @@
             $$logmsg .= &mt('Invalid home server for course').': \
'.$details->{'coursehome'};  return;
         }
-        my ($success, $msg) = 
+        my ($success,$msg,$cloneinfo) = 
             &Apache::loncommon::construct_course($courseargs,$logmsg,\$courseid,\$crsudom,\$crsunum,
                
-                                                 \
$udom,$uname,$context,$cnum,$category,$coderef); +                                    \
$udom,$uname,$context,$cnum,$category,$coderef, +                                     \
$callercontext,$user_lh);  $$logmsg .= $msg;
+        if ((ref($clonemsg) eq 'ARRAY') && (ref($cloneinfo) eq 'ARRAY')) {
+             push(@{$clonemsg},@{$cloneinfo});
+        }
         if (!$success) {
             return;
         }
Index: loncom/automation/Autocreate.pl
diff -u loncom/automation/Autocreate.pl:1.21 loncom/automation/Autocreate.pl:1.22
--- loncom/automation/Autocreate.pl:1.21	Fri Jul 26 02:28:28 2019
+++ loncom/automation/Autocreate.pl	Wed Jul  1 20:09:03 2020
@@ -2,7 +2,7 @@
 #
 # Automated Course Creation script
 #
-# $Id: Autocreate.pl,v 1.21 2019/07/26 02:28:28 raeburn Exp $
+# $Id: Autocreate.pl,v 1.22 2020/07/01 20:09:03 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -175,7 +175,7 @@
     closedir(DIR);
     my %courseids = ();
     print $fh "Sending to batch - auto,$dom,$dcname,$dcdom \
                ".join(":",@requests)."\n";
-    my ($result,$logmsg,$keysmsg,$codesref,$instcodesref) =
+    my ($result,$logmsg,$clonemsg,$keysmsg,$codesref,$instcodesref) =
         &LONCAPA::batchcreatecourse::create_courses(\@requests,\%courseids,'auto',$dom,$dcname,$dcdom);
  my $outcome;
     if ($result ne '') {
@@ -187,6 +187,9 @@
     if ($keysmsg ne '') {
         $outcome .=  $keysmsg."\n";
     }
+    if ($clonemsg ne '') {
+        $outcome .= $clonemsg."\n";
+    }
     print $fh $outcome;
 
     my $output;
@@ -267,7 +270,7 @@
     $env{'user.home'} = &Apache::lonnet::homeserver($dcname,$dcdom);
     if ($defdom ne '') {
         $env{'request.role.domain'} = $defdom;
-    } 
+    }
     return;
 }
 
Index: loncom/html/adm/help/tex/Course_Request_Clone.tex
diff -u loncom/html/adm/help/tex/Course_Request_Clone.tex:1.2 \
                loncom/html/adm/help/tex/Course_Request_Clone.tex:1.3
--- loncom/html/adm/help/tex/Course_Request_Clone.tex:1.2	Sat Aug 20 16:06:50 2016
+++ loncom/html/adm/help/tex/Course_Request_Clone.tex	Wed Jul  1 20:09:07 2020
@@ -1,4 +1,12 @@
 \label{Course_Request_Clone}
 You may choose to build your new course by cloning an existing course. If you have \
Course Coordinator access or have been assigned ``cloner'' rights in an existing \
course currently in the LON-CAPA system you can search for the course and select it \
in a pop-up window, launched by the `Select Course' link.  
-Cloning a course will copy all course content, and most course settings.  Student \
enrollment, peformance data and discussion postings will not be copied.  Settings \
which involve dates (e.g., open dates, due dates, and close dates for availability of \
course content and online homework problems) will be preserved, shifted by a number \
of days, or omitted from the copy process, based on your choice for the `Date Shift'. \
+Cloning a course will copy all course content, and most course settings.  Student \
enrollment, performance data and discussion postings will not be copied.  Settings \
which involve dates (e.g., open dates, due dates, and close dates for availability of \
course content and online homework problems) will be preserved, shifted by a number \
of days, or omitted from the copy process, based on your choice for the `Date Shift'. \
+ +If the existing course contains URL shortcuts (with format: \
/tiny/$<$domain$>$/$<$unique six character code$>$), which were originally created \
using Course Editor $>$ Content Utilities $>$ ``Display/Set Shortened URLs for \
Deep-linking'', then your options for ``URL shortcuts (for deep linking)'' include: \
+\begin{enumerate} +\item All URL shortcuts in the existing course are left alone, \
and none are created in the new course, or +\item All URL shortcuts in the existing \
course are disassociated from their targets, but instead are now associated with the \
corresponding items in the new course, or +\item All URL shortcuts in the existing \
course are left alone, and new shortcuts are created for the corresponding items \
(with their own unique six character codes). +\end{enumerate}
+Note: If you select option 2, the existing course and new course must be in the same \
domain, and the same user must be the course owner of both courses, for the change to \
occur.  If either condition is unmet, option 3 will apply instead during the cloning \
                process.
Index: loncom/html/adm/help/tex/Batch_Creation.tex
diff -u loncom/html/adm/help/tex/Batch_Creation.tex:1.8 \
                loncom/html/adm/help/tex/Batch_Creation.tex:1.9
--- loncom/html/adm/help/tex/Batch_Creation.tex:1.8	Fri May 22 15:05:41 2020
+++ loncom/html/adm/help/tex/Batch_Creation.tex	Wed Jul  1 20:09:07 2020
@@ -36,6 +36,7 @@
 <clonedom>msu</clonedom>
 <datemode>shift</datemode>
 <dateshift>365</dateshift>
+<tinyurls>create</tinyurls>
 <showphotos></showphotos>
 <setpolicy>1</setpolicy>
 <setcontent>1</setcontent>
Index: doc/loncapafiles/loncapafiles.lpml
diff -u doc/loncapafiles/loncapafiles.lpml:1.1003 \
                doc/loncapafiles/loncapafiles.lpml:1.1004
--- doc/loncapafiles/loncapafiles.lpml:1.1003	Fri May 29 18:13:20 2020
+++ doc/loncapafiles/loncapafiles.lpml	Wed Jul  1 20:09:12 2020
@@ -2,7 +2,7 @@
  "http://lpml.sourceforge.net/DTD/lpml.dtd">
 <!-- loncapafiles.lpml -->
 
-<!-- $Id: loncapafiles.lpml,v 1.1003 2020/05/29 18:13:20 raeburn Exp $ -->
+<!-- $Id: loncapafiles.lpml,v 1.1004 2020/07/01 20:09:12 raeburn Exp $ -->
 
 <!--
 
@@ -3559,6 +3559,7 @@
 Chart_Student_Data.tex;
 Chatting.tex;
 Clicker_Registration.tex;
+Clone_Tiny_URLs.tex;
 Coauthor.tex;
 Construction_Space_Overview.tex;
 Content_Page_Overview.tex;

Index: loncom/html/adm/help/tex/Clone_Tiny_URLs.tex
+++ loncom/html/adm/help/tex/Clone_Tiny_URLs.tex
\label{Clone_Tiny_URLs}
If the existing course contains URL shortcuts (with format: \
/tiny/$<$domain$>$/$<$unique six character code$>$), which were originally created \
using Course Editor $>$ Content Utilities $>$ ``Display/Set Shortened URLs for \
Deep-linking'', then options for ``URL shortcuts (for deep linking)'' include: \
\begin{enumerate} \item All URL shortcuts in the existing course are left alone, and \
none are created in the new course, or \item All URL shortcuts in the existing course \
are disassociated from their targets, but instead are now associated with the \
corresponding items in the new course, or \item All URL shortcuts in the existing \
course are left alone, and new shortcuts are created for the corresponding items \
(with their own unique six character codes). \end{enumerate}
Note: If option 2 is selected, the existing course and new course must be in the same \
domain, and the same user must be the course owner of both courses, for the change to \
occur.  If either condition is unmet, option 3 will apply instead during the cloning \
process.



_______________________________________________
LON-CAPA-cvs mailing list
LON-CAPA-cvs@mail.lon-capa.org
http://mail.lon-capa.org/mailman/listinfo/lon-capa-cvs


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic