# The LearningOnline Network with CAPA
# Handler to retrieve an old version of a file
#
# $Id: lonretrieve.pm,v 1.53 2023/07/23 12:24:16 raeburn Exp $
#
# Copyright Michigan State University Board of Trustees
#
# This file is part of the LearningOnline Network with CAPA (LON-CAPA).
#
# LON-CAPA is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# LON-CAPA is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with LON-CAPA; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# /home/httpd/html/adm/gpl.txt
#
# http://www.lon-capa.org/
#
#
###
=head1 NAME
Apache::lonretrieve - retrieves an old version of a file
=head1 SYNOPSIS
Invoked by /etc/httpd/conf/srm.conf:
<Location /adm/retrieve>
PerlAccessHandler Apache::lonacc
SetHandler perl-script
PerlHandler Apache::lonretrieve
ErrorDocument 403 /adm/login
ErrorDocument 404 /adm/notfound.html
ErrorDocument 406 /adm/unauthorized.html
ErrorDocument 500 /adm/errorhandler
</Location>
=head1 INTRODUCTION
This module retrieves an old published version of a file.
This is part of the LearningOnline Network with CAPA project
described at http://www.lon-capa.org.
=head1 HANDLER SUBROUTINE
This routine is called by Apache and mod_perl.
=over 4
=item *
Get query string for limited number of parameters
=item *
Start page output
=item *
print phase relevant output
=item *
(phase one is to select version; phase two retrieves version)
=back
=head1 OTHER SUBROUTINES
=over 4
=item *
phaseone() : Interface for selecting previous version.
=item *
phasetwo() : Interface for presenting specified version.
=back
=cut
package Apache::lonretrieve;
use strict;
use Apache::File;
use File::Copy;
use Apache::Constants qw(:common :http :methods);
use Apache::loncommon();
use Apache::lonlocal;
use Apache::lonnet;
use LONCAPA();
# ------------------------------------ Interface for selecting previous version
sub phaseone {
my ($r,$fn,$uname,$udom)=@_;
my $urldir = "/res/$udom/$uname".$fn;
my $resfn = $r->dir_config('lonDocRoot').$urldir;
$urldir =~ s{[^/]+$}{};
my $resdir = $r->dir_config('lonDocRoot').$urldir;
my ($main,$suffix,$is_meta) = &get_file_info($fn);
if (-e $resfn) {
$r->print('<form action="/adm/retrieve?inhibitmenu=yes" method="post">'.
'<input type="hidden" name="filename" value="/priv/'.$udom.'/'.$uname.$fn.'" />'.
'<input type="hidden" name="phase" value="two" />'.
&Apache::loncommon::start_data_table().
&Apache::loncommon::start_data_table_header_row().
'<th>'.&mt('Select').'</th>'.
'<th>'.&mt('Version').'</th>'.
'<th>'.&mt('Published on ...').'</th>');
if (!$is_meta) {
$r->print('<th>'.&mt('Metadata').'</th>');
}
if ($is_meta
|| &Apache::loncommon::fileembstyle($suffix) eq 'ssi') {
$r->print('<th>'.&mt('Diffs').'</th>');
}
$r->print(&Apache::loncommon::end_data_table_header_row());
opendir(DIR,$resdir);
my @files = grep(/^\Q$main\E\.(\d+)\.\Q$suffix\E$/,readdir(DIR));
@files = sort {
my ($aver) = ($a=~/^\Q$main\E\.(\d+)\.\Q$suffix\E$/);
my ($bver) = ($b=~/^\Q$main\E\.(\d+)\.\Q$suffix\E$/);
return $aver <=> $bver;
} (@files);
closedir(DIR);
foreach my $filename (@files) {
if ($filename=~/^\Q$main\E\.(\d+)\.\Q$suffix\E$/) {
my $version=$1;
my $rmtime=&Apache::lonnet::metadata($resdir.'/'.$filename,'lastrevisiondate');
$r->print(&Apache::loncommon::start_data_table_row().
'<td><input type="radio" name="version" value="'.
$version.'" /></td><td>'.&mt('Previously published version').' '.$version.'</td>'.
'<td>'.&Apache::lonlocal::locallocaltime($rmtime).'</td>');
if (!$is_meta) {
$r->print('<td>'.
&Apache::loncommon::modal_link($urldir.$filename.'.meta',
&mt('Metadata Version [_1]',$version),550,450).'</td>');
}
if ($is_meta
|| &Apache::loncommon::fileembstyle($suffix) eq 'ssi') {
$r->print('<td>'.
&Apache::loncommon::modal_link(
'/adm/diff?filename=/priv/'.$udom.'/'.$uname.$fn.
'&versiontwo=priv&versionone='.$version,
&mt('Diffs with Version [_1]',$version),550,450).
'</td>');
}
$r->print(&Apache::loncommon::end_data_table_row());
}
}
closedir(DIR);
my $rmtime=&Apache::lonnet::metadata($resfn,'lastrevisiondate');
$r->print(&Apache::loncommon::start_data_table_row().
'<td><input type="radio" name="version" value="new" /></td>'.
'<td><b>'.&mt('Currently published version').'</b></td>'.
'<td>'.&Apache::lonlocal::locallocaltime($rmtime).'</td>'
);
if (!$is_meta) {
$r->print('<td>',
&Apache::loncommon::modal_link($urldir.$main.'.'.$suffix.'.meta',
&mt('Metadata current version'),550,450).'</td>');
}
if ($is_meta
|| &Apache::loncommon::fileembstyle($suffix) eq 'ssi') {
$r->print('<td>'.
&Apache::loncommon::modal_link(
'/adm/diff?filename=/priv/'.
$udom.'/'.$uname.$fn.
'&versiontwo=priv',
&mt('Diffs with current Version'),550,450).
'</td>');
}
$r->print(&Apache::loncommon::end_data_table_row().
&Apache::loncommon::end_data_table().
'<p>'.'<span class="LC_warning">'.
&mt('Retrieval of an old version will overwrite the file currently in Authoring Space.').'</span></p>');
if (!$is_meta) {
$r->print('<p>'.'<span class="LC_warning">'.
&mt('This will only retrieve the resource. If you want to retrieve the metadata, you will need to do that separately.').
'</span></p>');
}
$r->print('<input type="submit" value="'.&mt('Retrieve selected Version').'" /></form>');
} else {
$r->print('<p class="LC_warning">'.&mt('No previous versions published.').'</p>');
}
}
# ---------------------------------- Interface for presenting specified version
sub phasetwo {
my ($r,$fn,$uname,$udom)=@_;
if ($env{'form.version'}) {
my $version=$env{'form.version'};
if ($version eq 'new') {
$r->print('<h3>'.&mt('Retrieving current (most recent) version').'</h3>');
} else {
$r->print('<h3>'.&mt('Retrieving old version').' '.$version.'</h3>');
}
my ($main,$suffix,$is_meta) = &get_file_info($fn);
my $logfile;
my $ctarget=$r->dir_config('lonDocRoot')."/priv/$udom/$uname".$fn;
my $vfn=$fn;
if ($version ne 'new') {
$vfn=~s/\.(\Q$suffix\E)$/\.$version\.$1/;
}
my $csource=$r->dir_config('lonDocRoot')."/res/$udom/$uname".$vfn;
my $logname = $ctarget;
if ($is_meta) { $logname =~ s/\.meta$//; }
$logname = $ctarget.'.log';
unless ($logfile=Apache::File->new('>>'.$logname)) {
$r->print('<span class="LC_error">'
.&mt('No write permission to user directory, FAIL')
.'</span>');
}
print $logfile
"\n\n================= Retrieve ".localtime()." ================\n".
"Version: $version\nSource: $csource\nTarget: $ctarget\n";
$r->print('<p>'.&mt('Copying file').': ');
if (copy($csource,$ctarget)) {
$r->print('<span class="LC_success">'
.&mt('ok')
.'</span>');
print $logfile "Copied sucessfully.\n\n";
$r->print(&Apache::lonhtmlcommon::scripttag('parent.location.reload();'));
} else {
my $error=$!;
$r->print('<span class="LC_error">'
.&mt('Copy failed: [_1]',$error)
.'</span>');
print $logfile "Copy failed: $error\n\n";
}
} else {
$r->print('<p class="LC_info">'.&mt('Please pick a version to retrieve:').'</p>');
&phaseone($r,$fn,$uname,$udom);
}
}
sub get_file_info {
my ($fn) = @_;
my ($main,$suffix) = ($fn=~/\/([^\/]+)\.(\w+)$/);
my $is_meta=0;
if ($suffix eq 'meta') {
$is_meta = 1;
($main,$suffix) = ($main=~/(.+)\.(\w+)$/);
$suffix .= '.meta';
}
return ($main,$suffix,$is_meta);
}
# ---------------------------------------------------------------- Main Handler
sub handler {
my $r=shift;
my $fn;
# Get query string for limited number of parameters
&Apache::loncommon::get_unprocessed_cgi($ENV{'QUERY_STRING'},
['filename']);
if ($env{'form.filename'}) {
$fn=$env{'form.filename'};
$fn =~ s{^https?\://[^/]+}{};
} else {
$r->log_reason($env{'user.name'}.' at '.$env{'user.domain'}.
' unspecified filename for retrieval', $r->filename);
return HTTP_NOT_FOUND;
}
unless ($fn) {
$r->log_reason($env{'user.name'}.' at '.$env{'user.domain'}.
' trying to retrieve non-existing file', $r->filename);
return HTTP_NOT_FOUND;
}
# ----------------------------------------------------------- Start page output
my $uname;
my $udom;
my $crsauthor;
($uname,$udom) = &Apache::lonnet::constructaccess($fn);
unless (($uname ne '') && ($udom ne '')) {
$r->log_reason($uname.' at '.$udom.
' trying to publish file '.$env{'form.filename'}.
' ('.$fn.') - not authorized',
$r->filename);
return HTTP_NOT_ACCEPTABLE;
}
&Apache::loncommon::content_type($r,'text/html');
$r->send_http_header;
# Breadcrumbs
my $text = 'Authoring Space';
my $href = &Apache::loncommon::authorspace($fn);
if ($env{'request.course.id'}) {
my $cnum = $env{'course.'.$env{'request.course.id'}.'.num'};
my $cdom = $env{'course.'.$env{'request.course.id'}.'.domain'};
if ($href eq "/priv/$cdom/$cnum/") {
$text = 'Course Authoring Space';
$crsauthor = 1;
}
}
&Apache::lonhtmlcommon::clear_breadcrumbs();
&Apache::lonhtmlcommon::add_breadcrumb({
'text' => $text,
'href' => $href,
});
&Apache::lonhtmlcommon::add_breadcrumb({
'text' => 'Retrieve previous version',
'href' => '',
});
my $londocroot = $r->dir_config('lonDocRoot');
my $trailfile = $fn;
$trailfile =~ s{^/(priv/)}{$londocroot/$1};
$r->print(&Apache::loncommon::start_page('Retrieve Published Resources')
.&Apache::lonhtmlcommon::breadcrumbs()
.&Apache::loncommon::head_subbox(
&Apache::loncommon::CSTR_pageheader($trailfile))
);
$fn=~s{/priv/$LONCAPA::domain_re/$LONCAPA::username_re}{};
$r->print('<p>'
.&mt('Retrieve previous versions of [_1]'
,'<span class="LC_filename">'.$fn.'</span>')
.'</p>');
unless ($crsauthor) {
if (($uname ne $env{'user.name'}) || ($udom ne $env{'user.domain'})) {
$r->print('<p><span class="LC_info">'
.&mt('Co-Author [_1]'
,&Apache::loncommon::plainname($uname,$udom)
.' ('.$uname.':'.$udom.')')
.'</span></p>');
}
}
if ($env{'form.phase'} eq 'two') {
&phasetwo($r,$fn,$uname,$udom);
} else {
&phaseone($r,$fn,$uname,$udom);
}
$r->print(&Apache::loncommon::end_page());
return OK;
}
1;
__END__
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>