--- loncom/publisher/loncfile.pm 2023/07/14 23:20:15 1.127 +++ loncom/publisher/loncfile.pm 2024/05/13 13:55:50 1.128 @@ -9,7 +9,7 @@ # and displays a page showing the results of the action. # # -# $Id: loncfile.pm,v 1.127 2023/07/14 23:20:15 raeburn Exp $ +# $Id: loncfile.pm,v 1.128 2024/05/13 13:55:50 raeburn Exp $ # # Copyright Michigan State University Board of Trustees # @@ -70,10 +70,10 @@ use HTML::Entities(); use Apache::Constants qw(:common :http :methods); use Apache::lonnet; use Apache::loncommon(); +use Apache::lonhtmlcommon; use Apache::lonlocal; use LONCAPA qw(:DEFAULT :match); - my $DEBUG=0; my $r; # Needs to be global for some stuff RF. @@ -819,6 +819,130 @@ sub Decompress1 { } } +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; + } + } + if (!$canarchive) { + $request->print('

'. + &mt('This LON-CAPA instance does not seem to have either tar or zip installed.').'

'. + ''. + &mt('At least one of the two is needed in order to be able to create an archive file for: [_1].', + &display($fn)). + ''); + } elsif (-e $fn) { + $request->print(&Apache::lonhtmlcommon::start_pick_box(). + &Apache::lonhtmlcommon::row_title(&mt('Directory')). + &display($fn). + &Apache::lonhtmlcommon::row_closure(). + &Apache::lonhtmlcommon::row_title(&mt('Options'). + &Apache::loncommon::help_open_topic('Archiving_Directory_Options')). + '
'.&mt('Recurse').''. + ''. + '
'. + '
'.&mt('File types (extensions) to include').(' 'x2). + ''.(' 'x5).''.(' 'x2). + ''. + (' 'x2). + ''. + ''); + my $rem; + my $numinrow = 6; + for (my $i=0; $i<@posstypes; $i++) { + my $rem = $i%($numinrow); + if ($rem == 0) { + if ($i > 0) { + $request->print(''."\n"); + } + $request->print(''."\n"); + } + $request->print(''."\n"); + } + $rem = scalar(@posstypes)%($numinrow); + my $colsleft; + if ($rem) { + $colsleft = $numinrow - $rem; + } + if ($colsleft > 1 ) { + $request->print(''."\n"); + } elsif ($colsleft == 1) { + $request->print(''."\n"); + } + $request->print('
'. + ''. + '  
'."\n". + '
'. + '
'.&mt('Archive file format').''); + foreach my $possfmt ('tar','zip') { + if (exists($location_of{$possfmt})) { + $request->print(''. + '   '); + } + } + $request->print('
'."\n". + '
'. + ''.&mt('Compression to apply to tar file').''. + ''); + if ($cancompress) { + foreach my $compress ('gzip','bzip2','xz') { + if (exists($location_of{$compress})) { + $request->print('  '); + } + } + } else { + $request->print(''. + &mt('This LON-CAPA instance does not seem to have gzip, bzip2 or xz installed.'). + '
'.&mt('No compression will be used.').'
'); + } + $request->print('
'. + &Apache::lonhtmlcommon::row_closure(1). + &Apache::lonhtmlcommon::end_pick_box() + ); + &CloseForm1($request, $fn); + } else { + $request->print('

' + .&mt('No such directory: [_1]', + &display($fn)) + .'

' + ); + } +} + =pod =item NewFile1 @@ -994,7 +1118,7 @@ sub phaseone { '

'); return; } - $r->print('
'. + $r->print(''. ''. ''. ''); @@ -1033,6 +1157,8 @@ sub phaseone { &Delete1($r, $uname, $udom, $fn); } elsif ($env{'form.action'} eq 'decompress') { &Decompress1($r, $uname, $udom, $fn); + } elsif ($env{'form.action'} eq 'archive') { + &Archive1($r,$fn); } elsif ($env{'form.action'} eq 'copy') { if ($newfilename) { &Copy1($r, $uname, $udom, $fn, $newfilename); @@ -1310,9 +1436,50 @@ sub decompress2 { return 1; } +sub Archive2 { + my ($r,$name,$udom,$fn,$identifier) = @_; + my %options = ( + dir => $fn, + ); + 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; + my @posstypes = &Apache::loncommon::get_env_multiple('form.filetype'); + foreach my $type (@posstypes) { + if ($oktypes{$type}) { + push(@include,$type); + } + } + if (scalar(@include) == scalar(@filetypes)) { + $options{'types'} = 'all'; + } else { + $options{'types'} = join(',',@include); + } + if (exists($env{'form.recurse'})) { + $options{'recurse'} = 1; + } + if (exists($env{'form.encrypt'})) { + if ($env{'form.enckey'} ne '') { + $options{'encrypt'} = $env{'form.enckey'}; + } + } + $options{'format'} = 'tar'; + $options{'compress'} = 'gzip'; + if ((exists($env{'form.format'})) && $env{'form.format'} =~ /^zip$/i) { + $options{'format'} = 'zip'; + delete($options{'compress'}); + } elsif ((exists($env{'form.compress'})) && ($env{'form.compress'} =~ /^(xz|bzip2)$/i)) { + $options{'compress'} = lc($env{'form.compress'}); + } + my $key = 'cgi.'.$identifier.'.archive'; + my $storestring = &Apache::lonnet::freeze_escape(\%options); + &Apache::lonnet::appenv({$key => $storestring}); + return 1; +} + =pod -=item phasetwo($r, $fn, $uname, $udom) +=item phasetwo($r, $fn, $uname, $udom,$identifier) Controls the phase 2 processing of file management requests for construction space. In phase one, the user @@ -1343,7 +1510,7 @@ Parameters: =cut sub phasetwo { - my ($r,$fn,$uname,$udom)=@_; + my ($r,$fn,$uname,$udom,$identifier)=@_; &Debug($r, "loncfile - Entering phase 2 for $fn"); @@ -1380,6 +1547,9 @@ sub phasetwo { return ; } $dest = $dir."/."; + } elsif ($env{'form.action'} eq 'archive') { + &Archive2($r,$uname,$udom,$fn,$identifier); + return; } elsif ($env{'form.action'} eq 'rename' || $env{'form.action'} eq 'move') { if($env{'form.newfilename'}) { @@ -1462,7 +1632,7 @@ sub handler { &Debug($r, "test: $env{'form.filename'}"); $fn=&unescape($env{'form.filename'}); $fn=&URLToPath($fn); - } elsif($ENV{'QUERY_STRING'} && $env{'form.phase'} ne 'two') { + } 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 $fn=&unescape($env{'form.decompress'}); @@ -1501,22 +1671,92 @@ sub handler { &Apache::loncommon::content_type($r,'text/html'); $r->send_http_header; - my (%loaditem,$js); + my ($js,$identifier); + my $args = {}; - if ( ($env{'form.action'} eq 'newdir') && ($env{'form.phase'} eq 'two') && ( ($env{'form.callingmode'} eq 'testbank') || ($env{'form.callingmode'} eq 'imsimport') ) ) { + if (($env{'form.action'} eq 'newdir') && ($env{'form.phase'} eq 'two') && + (($env{'form.callingmode'} eq 'testbank') || ($env{'form.callingmode'} eq 'imsimport'))) { my $newdirname = $env{'form.newfilename'}; - $js = qq| + &js_escape(\$newdirname); + $js = <<"ENDJS"; -|; - $loaditem{'onload'} = "writeDone()"; +// ]]> + +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(); + $js = <<"ENDJS"; + + +ENDJS + $args->{'add_entries'} = { onload => "resetForm()" }; + } + } my $londocroot = $r->dir_config('lonDocRoot'); my $trailfile = $fn; $trailfile =~ s{^/(priv/)}{$londocroot/$1}; @@ -1546,15 +1786,15 @@ function writeDone() { 'href' => '', }); - $r->print(&Apache::loncommon::start_page($title, - $js, - {'add_entries' => \%loaditem,}) + $r->print(&Apache::loncommon::start_page($title,$js,$args) .&Apache::lonhtmlcommon::breadcrumbs() .&Apache::loncommon::head_subbox( &Apache::loncommon::CSTR_pageheader($trailfile)) ); - $r->print('

'.&mt('Location').': '.&display($fn).'

'); + unless ($env{'form.action'} eq 'archive') { + $r->print('

'.&mt('Location').': '.&display($fn).'

'); + } if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) { unless ($crsauthor) { @@ -1573,6 +1813,7 @@ function writeDone() { 'move' => 'Move', 'newdir' => 'New Directory', 'decompress' => 'Decompress', + 'archive' => 'Export directory to archive file', 'copy' => 'Copy', 'newfile' => 'New Resource', 'newhtmlfile' => 'New Resource', @@ -1604,6 +1845,23 @@ function writeDone() { ); return OK; } + if ($env{'form.action'} eq 'archive') { + $r->print('

'.&mt('Location').': '.&display($fn).'

'."\n". + '

'. + &mt('Export to an archive file is not permitted in Course Authoring Space'). + '

'."\n". + &Apache::loncommon::end_page()); + return OK; + } + } elsif ($env{'form.action'} eq 'archive') { + unless ($env{'environment.authorarchive'}) { + $r->print('

'.&mt('Location').': '.&display($fn).'

'."\n". + '

'. + &mt('You do not have permission to export to an archive file in this Authoring Space'). + '

'."\n". + &Apache::loncommon::end_page()); + return OK; + } } $r->print('

'.$action{$env{'form.action'}}.'

'); } else { @@ -1617,7 +1875,7 @@ function writeDone() { if ($env{'form.phase'} eq 'two') { &Debug($r, "loncfile::handler entering phase2"); - &phasetwo($r,$fn,$uname,$udom); + &phasetwo($r,$fn,$uname,$udom,$identifier); } else { &Debug($r, "loncfile::handler entering phase1"); &phaseone($r,$fn,$uname,$udom);