[LON-CAPA-cvs] cvs: loncom /cgi archive.pl /interface domainprefs.pm loncommon.pm loncreateuser.pm lonmenu.pm /lonnet/perl lonnet.pm /publisher loncfile.pm

raeburn raeburn at source.lon-capa.org
Mon May 20 22:57:17 EDT 2024


raeburn		Tue May 21 02:57:17 2024 EDT

  Modified files:              
    /loncom/interface	domainprefs.pm loncreateuser.pm loncommon.pm 
                     	lonmenu.pm 
    /loncom/lonnet/perl	lonnet.pm 
    /loncom/publisher	loncfile.pm 
    /loncom/cgi	archive.pl 
  Log:
  - Bug 6990. Ability to download tarball of Authoring Space's files/directories.
    - Support use of domain default and also override for individual author(s).
    - Check if there is sufficient disk space to create archive file
    - Each author may only have one archive request in process at a time
    - Remove archive file after download
    - Log archive creation and deletion actions in nohist_archivelog.db in
      author's data directory.
  
  
-------------- next part --------------
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.440 loncom/interface/domainprefs.pm:1.441
--- loncom/interface/domainprefs.pm:1.440	Wed May  1 15:18:58 2024
+++ loncom/interface/domainprefs.pm	Tue May 21 02:57:15 2024
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: domainprefs.pm,v 1.440 2024/05/01 15:18:58 raeburn Exp $
+# $Id: domainprefs.pm,v 1.441 2024/05/21 02:57:15 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -13637,6 +13637,7 @@
                             $shown = $titles{'none'};
                         }
                     } elsif ($key eq 'archive') {
+                        $domdefaults{$key} = $confhash{$key};
                         $shown = ($confhash{$key} ? &mt('Yes') : &mt('No'));
                     }
                     $resulttext .= '<li>'.&mt('[_1] set to: [_2]',$titles{$key},$shown).'</li>';
Index: loncom/interface/loncreateuser.pm
diff -u loncom/interface/loncreateuser.pm:1.479 loncom/interface/loncreateuser.pm:1.480
--- loncom/interface/loncreateuser.pm:1.479	Wed May  1 21:23:20 2024
+++ loncom/interface/loncreateuser.pm	Tue May 21 02:57:15 2024
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Create a user
 #
-# $Id: loncreateuser.pm,v 1.479 2024/05/01 21:23:20 raeburn Exp $
+# $Id: loncreateuser.pm,v 1.480 2024/05/21 02:57:15 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -3378,7 +3378,7 @@
                     $changed{'webdav'} = &tool_admin('webdav',$newcustom{'webdav'},
                                                      \%changeHash,'authordefaults');
                 }
-                if ($env{'for.customarchive'} == 1) {
+                if ($env{'form.customarchive'} == 1) {
                     $newcustom{'archive'} = $env{'form.authordefaults_archive'};
                     $changed{'archive'} = &tool_admin('archive',$newcustom{'archive'},
                                                       \%changeHash,'authordefaults');
@@ -3867,6 +3867,21 @@
                                         $newenvhash{'environment.editors'} = 'edit,xml';
                                     }
                                 }
+                            } elsif ($key eq 'archive') {
+                                $newenvhash{'environment.author.'.$key} =
+                                    $changeHash{'author.'.$key};
+                                if ($changeHash{'author.'.$key} ne '') {
+                                    $newenvhash{'environment.canarchive'} =
+                                        $changeHash{'author.'.$key};
+                                } else {
+                                    unless ($got_domdefs) {
+                                        %domdefaults =
+                                           &Apache::lonnet::get_domain_defaults($env{'user.domain'});
+                                        $got_domdefs = 1;
+                                    }
+                                    $newenvhash{'environment.canarchive'} =
+                                        $domdefaults{'archive'};
+                                }
                             } elsif ($key ne 'quota') {
                                 $newenvhash{'environment.tools.'.$key} = 
                                     $changeHash{'tools.'.$key};
Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.1430 loncom/interface/loncommon.pm:1.1431
--- loncom/interface/loncommon.pm:1.1430	Sun Apr 14 18:45:57 2024
+++ loncom/interface/loncommon.pm	Tue May 21 02:57:15 2024
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.1430 2024/04/14 18:45:57 raeburn Exp $
+# $Id: loncommon.pm,v 1.1431 2024/05/21 02:57:15 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -18072,6 +18072,12 @@
                 } else {
                     $userenv{'editors'} = 'edit,xml';
                 }
+                if ($userenv{'authorarchive'}) {
+                    $userenv{'canarchive'} = 1;
+                } elsif (($userenv{'authorarchive'} eq '') &&
+                         ($domdef{'archive'})) {
+                    $userenv{'canarchive'} = 1;
+                }
             }
 
             $userenv{'canrequest.author'} =
Index: loncom/interface/lonmenu.pm
diff -u loncom/interface/lonmenu.pm:1.553 loncom/interface/lonmenu.pm:1.554
--- loncom/interface/lonmenu.pm:1.553	Tue May 14 15:53:17 2024
+++ loncom/interface/lonmenu.pm	Tue May 21 02:57:16 2024
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Routines to control the menu
 #
-# $Id: lonmenu.pm,v 1.553 2024/05/14 15:53:17 raeburn Exp $
+# $Id: lonmenu.pm,v 1.554 2024/05/21 02:57:16 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -1262,7 +1262,7 @@
 s&7&1&del.png&Delete&dir[_3]&gocstr('/adm/cfile?action=delete','$esc_currdir')&Delete this Directory
 ENDMENUITEMS
                 unless ($crsauthor_cstr) {
-                    if ($env{'environment.authorarchive'}) {
+                    if ($env{'environment.canarchive'}) {
                         $menuitems .= (<<ENDMENUITEMS);
 s&7&7&archive.png&Export&dir[_1]&gocstr('/adm/cfile?action=archive','$esc_currdir')&Export Authoring Space Archive
 ENDMENUITEMS
Index: loncom/lonnet/perl/lonnet.pm
diff -u loncom/lonnet/perl/lonnet.pm:1.1526 loncom/lonnet/perl/lonnet.pm:1.1527
--- loncom/lonnet/perl/lonnet.pm:1.1526	Wed May  1 12:06:25 2024
+++ loncom/lonnet/perl/lonnet.pm	Tue May 21 02:57:16 2024
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # TCP networking package
 #
-# $Id: lonnet.pm,v 1.1526 2024/05/01 12:06:25 raeburn Exp $
+# $Id: lonnet.pm,v 1.1527 2024/05/21 02:57:16 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -2802,7 +2802,7 @@
         $domdefaults{'requestauthor'} = $domconfig{'requestauthor'};
     }
     if (ref($domconfig{'authordefaults'}) eq 'HASH') {
-        foreach my $item ('nocodemirror','copyright','sourceavail','domcoordacc','editors') {
+        foreach my $item ('nocodemirror','copyright','sourceavail','domcoordacc','editors','archive') {
             if ($item eq 'editors') {
                 if (ref($domconfig{'authordefaults'}{'editors'}) eq 'ARRAY') {
                     $domdefaults{$item} = join(',',@{$domconfig{'authordefaults'}{'editors'}});
@@ -5623,6 +5623,39 @@
     return;
 }
 
+sub authorarchivelog {
+    my ($hashref,$size,$filesdest,$action) = @_;
+    my $lonprtdir = $Apache::lonnet::perlvar{'lonPrtDir'};
+    my $londocroot = $Apache::lonnet::perlvar{'lonDocRoot'};
+    $filesdest =~ s{^\Q$lonprtdir/\E}{};
+    if ($filesdest =~ m{^($match_username)_($match_domain)_archive_(\d+_\d+_\d+(|[.\w]+))$}) {
+        my ($auname,$audom,$id) = ($1,$2,$3);
+        if (ref($hashref) eq 'HASH') {
+            my $namespace = 'archivelog';
+            my $dir;
+            if ($hashref->{dir} =~ m{^\Q$londocroot/priv/$audom/$auname\E(.*)$}) {
+                $dir = $1;
+            }
+            my $delflag = 0;
+            my %storehash = (
+                              id      => $id,
+                              dir     => $dir,
+                              files   => $hashref->{numfiles},
+                              subdirs => $hashref->{numdirs},
+                              bytes   => $hashref->{bytes},
+                              size    => $size,
+                              action  => $action,
+                            );
+            if ($action eq 'delete') {
+                $delflag = 1;
+            }
+            &write_log('author',$namespace,\%storehash,$delflag,$auname,
+                       $audom,$auname,$audom);
+        }
+    }
+    return;
+}
+
 sub get_course_adv_roles {
     my ($cid,$codes) = @_;
     $cid=$env{'request.course.id'} unless (defined($cid));
Index: loncom/publisher/loncfile.pm
diff -u loncom/publisher/loncfile.pm:1.128 loncom/publisher/loncfile.pm:1.129
--- loncom/publisher/loncfile.pm:1.128	Mon May 13 13:55:50 2024
+++ loncom/publisher/loncfile.pm	Tue May 21 02:57:16 2024
@@ -9,7 +9,7 @@
 #  and displays a page showing the results of the action.
 #
 #
-# $Id: loncfile.pm,v 1.128 2024/05/13 13:55:50 raeburn Exp $
+# $Id: loncfile.pm,v 1.129 2024/05/21 02:57:16 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -822,42 +822,19 @@
 sub Archive1 {
     my ($request,$fn) = @_;
     my @posstypes = qw(problem library sty sequence page task rights meta xml html xhtml htm xhtm css js tex txt gif jpg jpeg png svg other);
-    my (%location_of,%default,$compstyle);
-    foreach my $program ('tar','gzip','bzip2','xz','zip') {
-        foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/',
-                         '/usr/sbin/') {
-            if (-x $dir.$program) {
-                $location_of{$program} = $dir.$program;
-                last;
-            }
-        }
-    }
-    my (%defaults,$cancompress,$canarchive);
-    if (exists($location_of{'tar'})) {
-        $default{'tar'} = ' checked="checked"';
-        $canarchive = 1;
-        $compstyle = 'block';
-    } elsif (exists($location_of{'zip'})) {
-        $default{'zip'} = ' checked="checked"';
-        $canarchive = 1;
-        $compstyle = 'none';
-    }
-    foreach my $compress ('gzip','bzip2','xz') {
-        if (exists($location_of{$compress})) {
-            $default{$compress} = ' checked="checked"';
-            $cancompress = 1;
-            last;
-        }
-    }
+    my (%location_of,%defaults);
+    my ($compstyle,$canarchive,$cancompress,$numformat,$numcompress,$defext) =
+        &archive_tools(\%location_of,\%defaults);
     if (!$canarchive) {
         $request->print('<p class="LC_error">'.
-                        &mt('This LON-CAPA instance does not seem to have either tar or zip installed.').'</p>'.
+                        &mt('This LON-CAPA instance does not seem to have either tar or zip installed.').'</p>'."\n".
                         '<span class="LC_warning">'.
                         &mt('At least one of the two is needed in order to be able to create an archive file for: [_1].',
-                            &display($fn)).
+                            &display($fn))."\n".
                         '</span></form>');
     } elsif (-e $fn) {
-        $request->print(&Apache::lonhtmlcommon::start_pick_box().
+        $request->print('<input type="hidden" name="adload" value="" />'."\n".
+                        &Apache::lonhtmlcommon::start_pick_box().
                         &Apache::lonhtmlcommon::row_title(&mt('Directory')).
                         &display($fn).
                         &Apache::lonhtmlcommon::row_closure().
@@ -909,7 +886,7 @@
             if (exists($location_of{$possfmt})) {
                 $request->print('<span class="LC_nobreak">'.
                                 '<label><input type="radio" name="format" value="'.$possfmt.'"'.
-                                $default{$possfmt}.' onclick="toggleCompression(this.form);" /> '.
+                                $defaults{$possfmt}.' onclick="toggleCompression(this.form);" /> '.
                                 $possfmt.'</label></span>   ');
             }
         }
@@ -921,7 +898,8 @@
             foreach my $compress ('gzip','bzip2','xz') {
                 if (exists($location_of{$compress})) {
                     $request->print('<label><input type="radio" name="compress" value="'.$compress.'"'.
-                                    $default{$compress}.'  />'.$compress.'</label>  ');
+                                    $defaults{$compress}.' onclick="setArchiveExt(this.form);"  />'.
+                                    $compress.'</label>  ');
                 }
             }
         } else {
@@ -929,9 +907,16 @@
                             &mt('This LON-CAPA instance does not seem to have gzip, bzip2 or xz installed.').
                             '<br />'.&mt('No compression will be used.').'</span>');
         }
-        $request->print('</fieldset>'. 
+        $request->print('</fieldset>'."\n".
+                        '<fieldset style="display:none" id="archive_saveas">'.
+                        '<legend>'.&mt('Filename to download').'</legend>'.
+                        '<table style="border-spacing:0"><tr><td style="padding:0;">'.&mt('Name').'<br />'."\n".
+                        '<input type="text" name="archivefname" value="" size="8" /></td><td style="padding:0;">'.
+                        &mt('Extension').'<br />'."\n".
+                        '<input type="text" name="archiveext" id="archiveext" value="" size="4" readonly="readonly" />'.
+                        '</td></tr></table></fieldset>'."\n".
                         &Apache::lonhtmlcommon::row_closure(1).
-                        &Apache::lonhtmlcommon::end_pick_box()
+                        &Apache::lonhtmlcommon::end_pick_box().'<br />'."\n"
         );
         &CloseForm1($request, $fn);
     } else {
@@ -941,6 +926,110 @@
                        .'</p></form>'
         );
     }
+    return;
+}
+
+sub archive_tools {
+    my ($location_of,$defaults) = @_;
+    my ($compstyle,$canarchive,$cancompress,$numformat,$numcompress,$defext);
+    ($numformat,$numcompress) = (0,0);
+    if ((ref($location_of) eq 'HASH') && (ref($defaults) eq 'HASH')) {
+        foreach my $program ('tar','gzip','bzip2','xz','zip') {
+            foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/',
+                             '/usr/sbin/') {
+                if (-x $dir.$program) {
+                    $location_of->{$program} = $dir.$program;
+                    last;
+                }
+            }
+        }
+        foreach my $format ('tar','zip') {
+            if (exists($location_of->{$format})) {
+                unless ($canarchive) {
+                    $defext = $format;
+                    $defaults->{$format} = ' checked="checked"';
+                    if ($format eq 'tar') {
+                        $compstyle = 'block';
+                    } else {
+                        $compstyle = 'none';
+                    }
+                }
+                $canarchive = 1;
+                $numformat ++;
+            }
+        }
+        foreach my $compress ('gzip','bzip2','xz') {
+            if (exists($location_of->{$compress})) {
+                $numcompress ++;
+                unless ($cancompress) {
+                    if ($defext eq 'tar') {
+                        if ($compress eq 'gzip') {
+                            $defext .= '.gz';
+                        } elsif ($compress eq 'bzip2') {
+                            $defext .= '.bz2';
+                        } else {
+                            $defext .= ".$compress";
+                        }
+                    }
+                    $defaults->{$compress} = ' checked="checked"';
+                    $cancompress = 1;
+                }
+            }
+        }
+    }
+    if (wantarray) {
+        return ($compstyle,$canarchive,$cancompress,$numformat,$numcompress,$defext);
+    } else {
+        return $defext;
+    }
+}
+
+sub archive_in_progress {
+    my ($earlyout,$idnum);
+    if ($env{'cgi.author.archive'} =~ /^(\d+)_\d+_\d+$/) {
+        my $timestamp = $1;
+        $idnum = $env{'cgi.author.archive'};
+        if (exists($env{'cgi.'.$idnum.'.archive'})) {
+            my $hashref = &Apache::lonnet::thaw_unescape($env{'cgi.'.$idnum.'.archive'});
+            my $lonprtdir = $Apache::lonnet::perlvar{'lonPrtDir'};
+            if (-e $lonprtdir.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$idnum.'.txt') {
+                $earlyout = $timestamp;
+            } elsif (ref($hashref) eq 'HASH') {
+                my $suffix = $hashref->{'extension'};
+                if (-e $lonprtdir.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$idnum.$suffix) {
+                    $earlyout = $timestamp;
+                }
+            }
+            unless ($earlyout) {
+                &Apache::lonnet::delenv('cgi.'.$idnum.'.archive');
+                &Apache::lonnet::delenv('cgi.author.archive');
+            }
+        } else {
+            &Apache::lonnet::delenv('cgi.author.archive');
+        }
+    }
+    return ($earlyout,$idnum);
+}
+
+sub cancel_archive_form {
+    my ($r,$title,$fname,$earlyout,$idnum) = @_;
+    $r->print('<h2>'.$title.'</h2>'."\n".
+              '<form action="/adm/cfile" method="post" onsubmit="return confirmation(this);">'."\n".
+              '<input type="hidden" name="filename" value="'.$fname.'" />'."\n".
+              '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />'."\n".
+              '<p>'.&mt('Each author may only have one archive request in process at a time.')."\n".'<ul>'.
+              '<li>'.&mt('An incomplete archive request was begun: [_1].',
+                         &Apache::lonlocal::locallocaltime($earlyout)).
+              '</li>'."\n".
+              '<li>'.&mt('An archive request is considered complete when the archive file has been successfully downloaded.').'</li>'."\n".
+              '<li>'.
+              &mt('To submit a new archive request, either wait for the existing request (e.g., in another tab/window) to complete, or remove it.').'</li>'."\n".
+              '</ul></p>'."\n".
+              '<p><span class="LC_nobreak">'.&mt('Remove existing archive request?').' '."\n".
+              '<label><input type="radio" name="remove_archive_request" value="'.$idnum.'" />'.&mt('Yes').'</label>'.
+              (' 'x2)."\n".
+              '<label><input type="radio" name="remove_archive_request" value="" checked="checked" />'.&mt('No').'</label></span></p>'."\n".
+              '<br />');
 }
 
 =pod
@@ -1118,10 +1207,10 @@
                   '</a></p>');
         return;
     }
-    $r->print('<form action="/adm/cfile" method="post" name="phaseone">'.
-	      '<input type="hidden" name="qualifiedfilename" value="'.$fn.'" />'.
-	      '<input type="hidden" name="phase" value="two" />'.
-	      '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />');
+    $r->print('<form action="/adm/cfile" method="post" name="phaseone">'."\n".
+	      '<input type="hidden" name="qualifiedfilename" value="'.$fn.'" />'."\n".
+	      '<input type="hidden" name="phase" value="two" />'."\n".
+	      '<input type="hidden" name="action" value="'.$env{'form.action'}.'" />'."\n");
 
     if ($env{'form.action'} eq 'newfile' ||
         $env{'form.action'} eq 'newhtmlfile' ||
@@ -1437,10 +1526,22 @@
 }
 
 sub Archive2 {
-    my ($r,$name,$udom,$fn,$identifier) = @_;
+    my ($r,$uname,$udom,$fn,$identifier) = @_;
     my %options = (
                     dir => $fn,
+                    uname => $uname,
+                    udom => $udom,
                   );
+    if ($env{'form.adload'}) {
+        $options{'adload'} = 1;
+        if ($env{'form.archivefname'} ne '') {
+            $env{'form.archivefname'} =~ s{\.+}{.}g;
+            $options{'fname'} = $env{'form.archivefname'};
+        }
+        if ($env{'form.archiveext'} ne '') {
+            $options{'extension'} = $env{'form.archiveext'};
+        }
+    }
     my @filetypes = qw(problem library sty sequence page task rights meta xml html xhtml htm xhtm css js tex txt gif jpg jpeg png svg other);
     my (@include,%oktypes);
     map { $oktypes{$_} = 1; } @filetypes;
@@ -1473,10 +1574,40 @@
     }
     my $key = 'cgi.'.$identifier.'.archive';
     my $storestring = &Apache::lonnet::freeze_escape(\%options);
-    &Apache::lonnet::appenv({$key => $storestring});
+    &Apache::lonnet::appenv({$key => $storestring,
+                             'cgi.author.archive' => $identifier});
     return 1;
 }
 
+sub Archive3 {
+    my ($hashref) = @_;
+    if (ref($hashref) eq 'HASH') {
+        if (($hashref->{'uname'} eq $env{'user.name'}) &&
+            ($hashref->{'udom'} eq $env{'user.domain'}) &&
+            ($env{'environment.canarchive'}) &&
+            ($env{'form.delarchive'})) {
+            my $filesdest = $Apache::lonnet::perlvar{'lonPrtDir'}.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$env{'form.delarchive'};
+            if (-e $filesdest) {
+                my $size = (stat($filesdest))[7];
+                if (unlink($filesdest)) {
+                    my ($identifier,$suffix) = split(/\./,$env{'form.delarchive'},2);
+                    if (($identifier) && (exists($env{'cgi.'.$identifier.'.archive'}))) {
+                        my $delres = &Apache::lonnet::delenv('cgi.'.$identifier.'.archive');
+                        if (($delres eq 'ok') &&
+                            (exists($env{'cgi.author.archive'})) &&
+                            ($env{'cgi.author.archive'} eq $identifier)) {
+                            &Apache::lonnet::authorarchivelog($hashref,$size,$filesdest,'delete');
+                            &Apache::lonnet::delenv('cgi.author.archive');
+                        }
+                    }
+                    return 1;
+                }
+            }
+        }
+    }
+    return 0;
+}
+
 =pod
 
 =item phasetwo($r, $fn, $uname, $udom,$identifier)
@@ -1624,14 +1755,26 @@
 #
 # Determine the root filename
 # This could come in as "filename", which actually is a URL, or
-# as "qualifiedfilename", which is indeed a real filename in filesystem
+# as "qualifiedfilename", which is indeed a real filename in filesystem,
+# or in value of decompress form element, or need to be extracted
+# from %env from hashref retrieved for cgi.<id>.archive key, where id
+# is a unique cgi_id created when an Author creates an archive of
+# Authoring Space for download.
 #
-    my $fn;
+    my ($fn,$archiveref);
 
     if ($env{'form.filename'}) {
 	&Debug($r, "test: $env{'form.filename'}");
 	$fn=&unescape($env{'form.filename'});
 	$fn=&URLToPath($fn);
+    } elsif ($env{'form.delarchive'}) {
+        my ($delarchive,$suffix) = split(/\./,$env{'form.delarchive'});
+        if (($delarchive) && (exists($env{'cgi.'.$delarchive.'.archive'}))) {
+            $archiveref = &Apache::lonnet::thaw_unescape($env{'cgi.'.$delarchive.'.archive'});
+            if (ref($archiveref) eq 'HASH') {
+                $fn = $archiveref->{'dir'};
+            }
+        }
     } elsif($ENV{'QUERY_STRING'} && $env{'form.phase'} ne 'two') {
 	#Just hijack the script only the first time around to inject the
 	#correct information for further processing
@@ -1666,12 +1809,19 @@
 		       $r->filename);
 	return HTTP_NOT_ACCEPTABLE;
     }
-
+    if (($env{'form.delarchive'}) &&
+        ($env{'environment.canarchive'})) {
+        &Apache::loncommon::content_type($r,'text/plain');
+        $r->send_http_header;
+        $r->print(&Archive3($archiveref));
+        return OK;
+    }
 
     &Apache::loncommon::content_type($r,'text/html');
     $r->send_http_header;
 
-    my ($js,$identifier);
+# Declarations for items used for directory archive requests
+    my ($js,$identifier,$defext,$archive_earlyout,$archive_idnum);
     my $args = {};
 
     if (($env{'form.action'} eq 'newdir') && ($env{'form.phase'} eq 'two') && 
@@ -1691,15 +1841,60 @@
 ENDJS
         $args->{'add_entries'} = { onload => "writeDone()" };
     } elsif (($env{'form.action'} eq 'archive') &&
-             ($env{'environment.authorarchive'})) { 
-        if ($env{'form.phase'} eq 'two') {
-            $identifier = &Apache::loncommon::get_cgi_id();
-            $args->{'redirect'} = [0,"/cgi-bin/archive.pl?$identifier"];
-        } else {
-            my $check_uncheck_js = &Apache::loncommon::check_uncheck_jscript();
+             ($env{'environment.canarchive'})) {
+# Check if author already has an archive request in process
+        ($archive_earlyout,$archive_idnum) = &archive_in_progress();
+# Check if archive request was in process which author wishes to terminate
+        if ($env{'form.remove_archive_request'}) {
+            if ($env{'form.remove_archive_request'} eq $archive_idnum) {
+                if (exists($env{'cgi.'.$archive_idnum.'.archive'})) {
+                    my $archiveref = &Apache::lonnet::thaw_unescape($env{'cgi.'.$archive_idnum.'.archive'});
+                    if (ref($archiveref) eq 'HASH') {
+                        $env{'form.delarchive'} = $archive_idnum.$archiveref->{'extension'};
+                        if (&Archive3($archiveref)) {
+                            ($archive_earlyout,$archive_idnum) = &archive_in_progress();
+                        }
+                        delete($env{'form.delarchive'});
+                    }
+                }
+            }
+        }
+        if ($archive_earlyout) {
+            my $conftext =
+                &mt('Removing an existing request will terminate an active download of the archive file.');
+            &js_escape(\$conftext);
             $js = <<"ENDJS";
 <script type="text/javascript">
 // <![CDATA[
+function confirmation(form) {
+    if (form.remove_archive_request.length) {
+        for (var i=0; i<form.remove_archive_request.length; i++) {
+            if (form.remove_archive_request[i].checked) {
+                if (form.remove_archive_request[i].value == '$archive_idnum') {
+                    if (!confirm('$conftext')) {
+                        return false;
+                    }
+                }
+            }
+        }
+    }
+    return true;
+}
+// ]]>
+</script>
+
+ENDJS
+        } else {
+            if ($env{'form.phase'} eq 'two') {
+                $identifier = &Apache::loncommon::get_cgi_id();
+                $args->{'redirect'} = [0.1,"/cgi-bin/archive.pl?$identifier"];
+            } else {
+                my (%location_of,%defaults);
+                $defext = &archive_tools(\%location_of,\%defaults);
+                my $check_uncheck_js = &Apache::loncommon::check_uncheck_jscript();
+                $js = <<"ENDJS";
+<script type="text/javascript">
+// <![CDATA[
 function toggleCompression(form) {
     if (document.getElementById('tar_compression')) {
         if (form.format.length > 1) {
@@ -1715,9 +1910,57 @@
             }
         }
     }
+    setArchiveExt(form);
     return;
 }
 
+function setArchiveExt(form) {
+    var newfmt;
+    var newcomp;
+    var newdef;
+    if (document.getElementById('archiveext')) {
+        if (form.format.length) {
+            for (var i=0; i<form.format.length; i++) {
+                if (form.format[i].checked) {
+                    newfmt = form.format[i].value;
+                    break;
+                }
+            }
+        } else {
+            newfmt = form.format[0];
+        }
+        if (newfmt == 'tar') {
+            if (document.getElementById('tar_compression')) {
+                if (form.compress.length) {
+                    for (var i=0; i<form.compress.length; i++) {
+                        if (form.compress[i].checked) {
+                            newcomp = form.compress[i].value;
+                            break;
+                        }
+                    }
+                } else {
+                    newcomp = form.compress[0];
+                }
+            }
+            if (newcomp == 'gzip') {
+                newdef = newfmt+'.gz';
+            } else if (newcomp == 'bzip2') {
+                newdef = newfmt+'.bz2';
+            } else if (newcomp == 'xz') {
+                newdef = newfmt+'.'+newcomp;
+            } else {
+                newdef = newfmt;
+            }
+        } else if (newfmt == 'zip') {
+            newdef = newfmt;
+        }
+        if ((newdef == '') || (newdef == undefined) || (newdef == null)) {
+            newdef = '.$defext';
+        }
+        document.getElementById('archiveext').value = newdef;
+    }
+}
+
 function resetForm() {
     if (document.phaseone.filetype.length) {
         for (var i=0; i<document.phaseone.filetype.length; i++) {
@@ -1746,6 +1989,27 @@
         }
     }
     document.phaseone.recurse.checked = false;
+    var a = document.createElement('a');
+    var vis;
+    if (typeof a.download != "undefined") {
+        document.phaseone.adload.value = '1';
+        if (document.getElementById('archive_saveas')) {
+            document.getElementById('archive_saveas').style.display = 'block';
+            vis = '1';
+        }
+    }
+    if (vis == '1') {
+        if (document.getElementById('archiveext')) {
+            document.getElementById('archiveext').value='.$defext';
+        }
+    } else {
+        if (document.getElementById('archive_saveas')) {
+            document.getElementById('archive_saveas').style.display = 'none';
+        }
+        if (document.getElementById('archiveext')) {
+            document.getElementById('archiveext').value='';
+        }
+    }
 }
 
 $check_uncheck_js
@@ -1754,7 +2018,8 @@
 </script>
 
 ENDJS
-            $args->{'add_entries'} = { onload => "resetForm()" }; 
+                $args->{'add_entries'} = { onload => "resetForm()" };
+            }
         }
     }
     my $londocroot = $r->dir_config('lonDocRoot');
@@ -1854,7 +2119,16 @@
                 return OK; 
             }
         } elsif ($env{'form.action'} eq 'archive') {
-            unless ($env{'environment.authorarchive'}) {
+            if ($env{'environment.canarchive'}) {
+                if ($archive_earlyout) {
+                    my $fname = &url($fn);
+                    my $title = $action{$env{'form.action'}};
+                    &cancel_archive_form($r,$title,$fname,$archive_earlyout,$archive_idnum);
+                    &CloseForm1($r,$fn);
+                    $r->print(&Apache::loncommon::end_page());
+                    return OK;
+                }
+            } else {
                 $r->print('<p>'.&mt('Location').': '.&display($fn).'</p>'."\n".
                           '<p class="LC_error">'.
                           &mt('You do not have permission to export to an archive file in this Authoring Space').
@@ -1863,7 +2137,7 @@
                 return OK;
             }
         }
-        $r->print('<h2>'.$action{$env{'form.action'}}.'</h2>');
+        $r->print('<h2>'.$action{$env{'form.action'}}.'</h2>'."\n");
     } else {
         $r->print('<p class="LC_error">'
                  .&mt('Unknown Action: [_1]',$env{'form.action'})
Index: loncom/cgi/archive.pl
diff -u loncom/cgi/archive.pl:1.1 loncom/cgi/archive.pl:1.2
--- loncom/cgi/archive.pl:1.1	Mon May 13 13:55:51 2024
+++ loncom/cgi/archive.pl	Tue May 21 02:57:17 2024
@@ -1,6 +1,6 @@
 #!/usr/bin/perl
 #
-# $Id: archive.pl,v 1.1 2024/05/13 13:55:51 raeburn Exp $
+# $Id: archive.pl,v 1.2 2024/05/21 02:57:17 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -28,7 +28,7 @@
 #
 # A CGI script which creates a compressed archive file of the current
 # directory in Authoring Space, with optional (a) recursion into
-# sub-directories, (b) filtering by filetype and (c) encryption.
+# sub-directories, and (b) filtering by filetype.
 # Supported formats are: tar.gz, tar.bz2, tar.xz and zip.
 ####
 use strict;
@@ -82,13 +82,14 @@
     &Apache::lonlocal::get_language_handle();
     &Apache::loncommon::content_type(undef,'text/html');
     my $identifier = $ENV{'QUERY_STRING'};
-    my ($hashref,$dir,$dirurl,$jsdirurl,$auname,$audom,$allowed,$error,$encrypt,$enckey,$format,$compress);
+    my ($hashref,$dir,$dirurl,$jsdirurl,$auname,$audom,$allowed,$error,
+        $format,$compress,$fname,$extension,$adload,$url,$mime);
     my @posstypes = qw(problem library sty sequence page task rights meta xml html xhtml htm xhtm css js tex txt gif jpg jpeg png svg other);
-    if (($identifier) && (exists($env{'cgi.'.$identifier.'.archive'}))) {
+    if (($identifier =~ /^\d+_\d+_\d+$/) && (exists($env{'cgi.'.$identifier.'.archive'}))) {
         $hashref = &Apache::lonnet::thaw_unescape($env{'cgi.'.$identifier.'.archive'});
         if (ref($hashref) eq 'HASH') {
             $dir = $hashref->{'dir'};
-            # check for traversal
+            $dir =~ s{\.+}{.}g;
             if (-d $dir) {
                 $dirurl = $dir;
                 ($auname,$audom) = &Apache::lonnet::constructaccess($dir);
@@ -98,7 +99,7 @@
                     $maxdepth = $prefix =~ tr{/}{};
                     $jsdirurl = &js_escape($dirurl);
                     if (($auname eq $env{'user.name'}) && ($audom eq $env{'user.domain'}) &&
-                        ($env{'environment.authorarchive'})) {
+                        ($env{'environment.canarchive'})) {
                         $allowed = 1;
                         if ($hashref->{'recurse'}) {
                             $recurse = 1;
@@ -128,10 +129,6 @@
                                 }
                             }
                         }
-                        if ((exists($hashref->{'encrypt'}) && $hashref->{'encrypt'} ne '')) { 
-                            $encrypt = 1;
-                            $enckey = $hashref->{'encrypt'};
-                        }
                         if ((exists($hashref->{'format'}) && $hashref->{'format'} =~ /^zip$/i)) {
                             $format = lc($hashref->{'format'});
                         } else {
@@ -144,6 +141,15 @@
                                 $compress = 'gzip';
                             }
                         }
+                        if ($hashref->{'adload'}) {
+                            $adload = $hashref->{'adload'};
+                        }
+                        if ($hashref->{'fname'}) {
+                            $fname = $hashref->{'fname'};
+                        }
+                        if ($hashref->{'extension'}) {
+                            $extension = $hashref->{'extension'};
+                        }
                     }
                 }
             } else {
@@ -152,8 +158,10 @@
         } else {
             $error = 'nohash';
         }
-# delete cgi.$identifier.archive from %env
-        &Apache::lonnet::delenv('cgi.'.$identifier.'.archive');
+# delete cgi.$identifier.archive from %env if error
+        if ($error) {
+            &Apache::lonnet::delenv('cgi.'.$identifier.'.archive');
+        }
     } else {
         $error = 'noid';
     }
@@ -175,22 +183,16 @@
                    {'href' => '',
                     'text' => $title}];
     }
-    my $js;
-    print &Apache::loncommon::start_page($title,
-                                         $js,
-                                         {'bread_crumbs' => $brcrum,})."\n".
-          '<form name="constspace" method="post" action="">'."\n".
-          '<input type="hidden" name="filename" value="" />'."\n";
-    if ($error) {
-        print "&mt('Cannot create archive file -- \n";
-    } elsif ($allowed) {
-        my (%location_of, at tocheck);
+# Set up files to write two and url
+    my ($js,%location_of,$suffix,$namesdest,$filesdest,$filesurl);
+    if ($allowed) {
+        my @tocheck;
         if ($format ne '') {
             push(@tocheck,$format);
         }
         if ($compress ne '') {
             push(@tocheck,$compress);
-        } 
+        }
         foreach my $program (@tocheck) {
             foreach my $dir ('/bin/','/usr/bin/','/usr/local/bin/','/sbin/',
                              '/usr/sbin/') {
@@ -200,26 +202,66 @@
                 }
             }
         }
-        if (exists($location_of{$format})) {
-            my $suffix;
+        if (($format ne '') && (exists($location_of{$format}))) {
             if ($format eq 'zip') {
-                $suffix = 'zip';
+                $suffix = '.zip';
+                $mime = 'application/x-zip-compressed';
             } else {
-                $suffix = 'tar';
-                if (exists($location_of{$compress})) {
+                $suffix = '.tar';
+                if (($compress ne '') &&
+                    (exists($location_of{$compress}))) {
                     if ($compress eq 'bzip2') {
-                        $suffix .= '.bz2'; 
+                        $suffix .= '.bz2';
+                        $mime = 'application/x-bzip2';
                     } elsif ($compress eq 'gzip') {
                         $suffix .= '.gz';
+                        $mime = 'application/x-gzip';
                     } elsif ($compress eq 'xz') {
                         $suffix .= '.xz';
+                        $mime = 'application/x-xz';
                     }
                 }
             }
-            my $namesdest = $perlvar{'lonPrtDir'}.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.'.txt';
-            my $filesdest = $perlvar{'lonPrtDir'}.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.'.'.$suffix;
-            my $filesurl = '/prtspool/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.'.'.$suffix;
-            unless ($lock) { $lock=&Apache::lonnet::set_lock(&mt('Archiving [_1]',$dirurl)); }
+            $namesdest = $perlvar{'lonPrtDir'}.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.'.txt';
+            $filesdest = $perlvar{'lonPrtDir'}.'/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.$suffix;
+            $filesurl = '/prtspool/'.$env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.$suffix;
+            if ($suffix eq $extension) {
+                $fname =~ s{\Q$suffix\E$}{};
+            }
+            if ($fname eq '') {
+                $fname = $env{'user.name'}.'_'.$env{'user.domain'}.'_archive_'.$identifier.$suffix;
+            } else {
+                $fname .= $suffix;
+            }
+            my $downloadurl = &Apache::lonnet::absolute_url().$filesurl;
+            my $delarchive = $identifier.$suffix;
+            $js = &js($filesurl,$mime,$fname,$delarchive);
+        }
+    }
+    print &Apache::loncommon::start_page($title,
+                                         '',
+                                         {'bread_crumbs' => $brcrum,})."\n".
+          '<form name="constspace" method="post" action="">'."\n".
+          '<input type="hidden" name="filename" value="" />'."\n";
+    if ($error) {
+        print &mt('Cannot create archive file');
+    } elsif ($allowed) {
+        if (-e $filesdest) {
+            my $mtime = (stat($filesdest))[9];
+            print '<div id="LC_archive_desc">'."\n";
+            if ($mtime) {
+                print '<p class="LC_warning">'.&mt('Archive file already exists -- created: [_1].',
+                                                   &Apache::lonlocal::locallocaltime($mtime)).'</p>';
+            } else {
+                print '<p class="LC_warning">'.&mt('Archive file already exists.').'</p>';
+            }
+            print '</div>'."\n";
+            print &archive_link($adload,$filesurl,$suffix);
+            if ($adload) {
+                print $js;
+            }
+        } elsif (exists($location_of{$format})) {
+            unless ($lock) { $lock=&Apache::lonnet::set_lock(&mt('Creating Archive file for [_1]',$dirurl)); }
             if (open($fh,'>',$namesdest)) {
                 find(
                      {preprocess => \&filter_files,
@@ -227,38 +269,85 @@
                       no_chdir   => 1,
                      },$dir);
                 close($fh);
+                if (ref($hashref) eq 'HASH') {
+                    $hashref->{'numfiles'} = $totalfiles;
+                    $hashref->{'numdirs'} = $totalsubdirs;
+                    $hashref->{'bytes'} = $totalsize;
+                    my $storestring = &Apache::lonnet::freeze_escape($hashref);
+                    &Apache::lonnet::appenv({'cgi.'.$identifier.'.archive' => $storestring});
+                }
+                &Apache::lonnet::thaw_unescape($env{'cgi.'.$identifier.'.archive'});
                 if (($totalfiles) || ($totalsubdirs)) {
-                    print '<p>'.
-                          &mt('Archiving: [quant,_1,file,files] with total size: [_2] bytes in [quant,_3,subdirectory,subdirectories] ...',
-                              $totalfiles,$totalsize,$totalsubdirs).
-                          '</p>';
-                    my ($cwd, at args);
-                    if ($format eq 'zip') {
-                        $cwd = &Cwd::getcwd(); 
-                        @args = ('zip',$filesdest,'-v','-r','.','-i@'.$namesdest);
-                        chdir $prefix;
-                    } else {
-                        @args = ('tar',"--create","--verbose");
-                        if (($compress ne '') && (exists($location_of{$compress}))) {
-                            push(@args,"--$compress");
+                    my $freespace;
+                    my @dfargs = ('df','-k','--output=avail','/home');
+                    if (open(my $pipe,'-|', at dfargs)) {
+                        while (my $line = <$pipe>) {
+                            chomp($line);
+                            if ($line =~ /^\d+$/) {
+                                $freespace = $line;
+                                last;
+                            }
                         }
-                        push(@args,("--file=$filesdest","--directory=$prefix","--files-from=$namesdest"));
+                        close($pipe);
                     }
-                    if (open(my $pipe,'-|', at args)) {
-                        my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin('',$totalfiles); 
-                        while (<$pipe>) {
-                            &Apache::lonhtmlcommon::Increment_PrgWin('',\%prog_state,'last file');
+                    if (($freespace ne '') && ($totalsize < $freespace*1024)) {
+                        my $showsize = $totalsize/(1024*1024);
+                        if ($showsize <= 0.01) {
+                            $showsize = sprintf("%.3f",$showsize);
+                        } elsif ($showsize <= 0.1) {
+                            $showsize = sprintf("%.2f",$showsize);
+                        } elsif ($showsize < 10) {
+                            $showsize = sprintf("%.1f",$showsize);
+                        } else {
+                            $showsize = sprintf("%.0f",$showsize);
                         }
-                        &Apache::lonhtmlcommon::Close_PrgWin('',\%prog_state);
-                        close($pipe);
-                        if (!-e $filesdest) {
-                            print '<p>'.&mt('No archive file available for download').'</p>'."\n"; 
+                        print '<div id="LC_archive_desc"><p>'.
+                              &mt('Creating archive file for [quant,_1,file,files] with total size before compression of [_2] MB.',
+                                  $totalfiles,$showsize);
+                        if ($totalsubdirs) {
+                            print '<br />'.&mt('Archive includes [quant,_1,subdirectory,subdirectories].',
+                                               $totalsubdirs);
+                        }
+                        print '</p></div>';
+                        my ($cwd, at args);
+                        if ($format eq 'zip') {
+                            $cwd = &Cwd::getcwd();
+                            @args = ('zip',$filesdest,'-v','-r','.','-i@'.$namesdest);
+                            chdir $prefix;
+                        } else {
+                            @args = ('tar',"--create","--verbose");
+                            if (($compress ne '') && (exists($location_of{$compress}))) {
+                                push(@args,"--$compress");
+                            }
+                            push(@args,("--file=$filesdest","--directory=$prefix","--files-from=$namesdest"));
+                        }
+                        if (open(my $pipe,'-|', at args)) {
+                            my %prog_state=&Apache::lonhtmlcommon::Create_PrgWin('',$totalfiles); 
+                            while (<$pipe>) {
+                                &Apache::lonhtmlcommon::Increment_PrgWin('',\%prog_state,'last file');
+                            }
+                            &Apache::lonhtmlcommon::Close_PrgWin('',\%prog_state);
+                            close($pipe);
+                            if (-e $filesdest) {
+                                my $size = (stat($filesdest))[7];
+                                &Apache::lonnet::authorarchivelog($hashref,$size,$filesdest,'create');
+                                print &archive_link($adload,$filesurl,$suffix);
+                                if ($adload) {
+                                    print $js;
+                                }
+                            } else {
+                                print '<p>'.&mt('No archive file available for download').'</p>'."\n"; 
+                            }
+                        } else {
+                            print '<p>'.&mt('Could not call [_1] command',$format).'</p>'."\n";
+                        }
+                        if (($format eq 'zip') && ($cwd ne '')) {
+                            chdir $cwd;
                         }
+                    } elsif ($freespace eq '') {
+                        print '<p>'.&mt('No archive file created as the available free space could not be determined.').'</p>'."\n";
                     } else {
-                        print '<p>'.&mt('Could not call [_1] command',$format).'</p>'."\n";
-                    }
-                    if (($format eq 'zip') && ($cwd ne '')) {
-                        chdir $cwd;
+                        print '<p>'.&mt('No archive file created because there is insufficient free space available.').'</p>'."\n";
                     }
                 } else {
                     print '<p>'.&mt('No files match the requested types so no archive file was created.').'</p>'."\n";
@@ -273,7 +362,7 @@
         }
     }
     if ($dirurl) {
-        print '<br /><br />'.
+        print '<br />'.
               &Apache::lonhtmlcommon::actionbox(['<a href="'.&HTML::Entities::encode($dirurl,'\'"&<>').'">'.
                                                  &mt('Return to Directory').'</a>']);
     }
@@ -306,6 +395,7 @@
             }
             push(@ChosenFiles,$file);
         } else {
+            next if ($file =~ /^\./);
             my ($extension) = ($file =~ /\.([^.]+)$/);
             if ((!$excluded{$extension}) && ($alltypes || $includeother || $included{$extension})) {
                 push(@ChosenFiles,$file);
@@ -332,54 +422,155 @@
     print $fh "$filename\n";
 }
 
+sub archive_link {
+    my ($adload,$filesurl,$suffix) = @_;
+    if ($adload) {
+        return
+'<button id="LC_download_button" onclick="return false">'.&mt('Download').'</button></p>'."\n".
+'<div style="display:none; width:100%;" id="LC_dload_progress" >'."\n".
+'<div id="LC_dl_progressbar"></div>'."\n".
+'</div>'."\n".
+'<span id="LC_download_result"></span>'."\n";
+    } else {
+        return
+'<p><a href="'.$filesurl.'">'.&mt('Download [_1] file',$suffix).'</a></p>'."\n";
+    }
+}
+
 sub js {
-    my $output = <<'END';
-const xhrButtonSuccess = document.querySelector(".xhr.success");
-const xhrButtonError = document.querySelector(".xhr.error");
-const xhrButtonAbort = document.querySelector(".xhr.abort");
-const log = document.querySelector(".event-log");
-
-function handleEvent(e) {
-  log.textContent = `${log.textContent}${e.type}: ${e.loaded} bytes transferred\n`;
-}
-
-function addListeners(xhr) {
-  xhr.addEventListener("loadstart", handleEvent);
-  xhr.addEventListener("load", handleEvent);
-  xhr.addEventListener("loadend", handleEvent);
-  xhr.addEventListener("progress", handleEvent);
-  xhr.addEventListener("error", handleEvent);
-  xhr.addEventListener("abort", handleEvent);
-}
-
-function runXHR(url) {
-  log.textContent = "";
-
-  const xhr = new XMLHttpRequest();
-  addListeners(xhr);
-  xhr.open("GET", url);
-  xhr.send();
-  return xhr;
-}
-
-xhrButtonSuccess.addEventListener("click", () => {
-  runXHR(
-    "https://somewhere",
-  );
-});
-
-xhrButtonError.addEventListener("click", () => {
-  runXHR("http://i-dont-exist");
-});
-
-xhrButtonAbort.addEventListener("click", () => {
-  runXHR(
-    "https://somewhere",
-  ).abort();
-});
+    my ($url,$mime,$fname,$delarchive) = @_;
+    &js_escape(\$url);
+    &js_escape(\$mime);
+    &js_escape(\$fname);
+    my %js_lt = &Apache::lonlocal::texthash (
+                                              afdo => 'Archive file download complete.',
+                                              diun => 'Download is unavailable.',
+                                              tfbr => 'The archive file has been removed.',
+                                              ynrd => 'You do not have rights to download the archive file.',
+    );
+    &js_escape(\%js_lt);
+    return <<"END";
+<script type="text/javascript">
+// <![CDATA[
+
+function showProgress(event) {
+    if (event.lengthComputable) {
+        var complete = 0;
+        if (event.total > 0) {
+            complete = Math.round( (event.loaded / event.total) * 100);
+        }
+        \$( "#LC_dl_progressbar" ).progressbar({
+           value: complete
+        });
+        if (complete == '100') {
+            if (document.getElementById('LC_dload_progress')) {
+                document.getElementById('LC_dload_progress').style.display = 'none';
+            }
+        }
+    }
+}
 
-END
+function cleanUp(event) {
+    showProgress(event);
+    if (event.lengthComputable) {
+        var complete = 0;
+        if (event.total > 0) {
+            complete = Math.round( (event.loaded / event.total) * 100);
+        }
+        if (complete == 100) {
+            var dbtn = document.querySelector('#LC_download_button');
+            if (dbtn !== null) {
+                dbtn.style.display = 'none';
+            }
+            var http = new XMLHttpRequest();
+            var lcurl = "/adm/cfile";
+            var params = 'delarchive=$delarchive';
+            var result;
+            http.open("POST",lcurl, true);
+            http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
+            http.onreadystatechange = function() {
+                if ((http.readyState == 4) && (http.status == 200)) {
+                    if (http.responseText.length > 0) {
+                        if (http.responseText == 1) {
+                            if (document.getElementById('LC_archive_desc')) {
+                                document.getElementById('LC_archive_desc').style.display = 'none';
+                            }
+                            if (document.getElementById('LC_download_result')) {
+                                document.getElementById('LC_download_result').innerHTML = '$js_lt{afdo}<br />';
+                            }
+                        }
+                    }
+                }
+            }
+            http.send(params);
+        }
+    }
+}
+
+function filecheck(file, callback) {
+    const xhr = new XMLHttpRequest();
+    xhr.open('HEAD',file,true);
+    xhr.onreadystatechange = function() {
+        if (this.readyState >= 2) {
+            callback(this.status);
+            this.abort();
+        }
+    };
+    xhr.send();
+}
+
+function download(file,callback) {
+    if (document.getElementById('LC_dload_progress')) {
+        document.getElementById('LC_dload_progress').style.display = 'block';
+    }
+    const xhr = new XMLHttpRequest();
+    xhr.responseType = 'blob';
+    xhr.open('GET', file);
+    xhr.addEventListener('progress',showProgress);
+    xhr.addEventListener('load', function () {
+        callback(xhr.response);
+    });
+    xhr.addEventListener("loadend", cleanUp);
+    xhr.send();
+}
 
+function save(object,mime,name) {
+    var a = document.createElement('a');
+    var url = URL.createObjectURL(object);
+    a.href = url;
+    a.type = mime;
+    a.download = name;
+    a.click();
 }
 
+var dbtn = document.querySelector('#LC_download_button');
+if (dbtn !== null) {
+    dbtn.addEventListener('click', function () {
+        filecheck('$url',function (response) {
+            if (response == 200) {
+                download('$url', function (file) {
+                    save(file,'$mime','$fname');
+                });
+            } else if ((response == 404) || (response == 403) || (response == 406)) {
+                dbtn.style.display = 'none';
+                if (document.getElementById('LC_dload_progress')) {
+                    document.getElementById('LC_dload_progress').style.display = 'none';
+                }
+                if (document.getElementById('LC_download_result')) {
+                    if (response == 404) {
+                        document.getElementById('LC_download_result').innerHTML = '$js_lt{diun} $js_lt{tfbr}<br />';
+                    } else {
+                        document.getElementById('LC_download_result').innerHTML = '$js_lt{diun} $js_lt{ynrd}<br />';
+                    }
+                }
+            }
+        });
+    });
+}
+
+// ]]>
+</script>
 
+END
+
+}


More information about the LON-CAPA-cvs mailing list