webgui/lib/WebGUI/AssetExportHtml.pm
Drake 57f7fe1c6f Make the asset exporter use one session per asset, so as to avoid breaking
state that relies on only one asset being viewed per session.
2006-10-12 02:45:43 +00:00

340 lines
12 KiB
Perl

package WebGUI::Asset;
=head1 LEGAL
-------------------------------------------------------------------
WebGUI is Copyright 2001-2006 Plain Black Corporation.
-------------------------------------------------------------------
Please read the legal notices (docs/legal.txt) and the license
(docs/license.txt) that came with this distribution before using
this software.
-------------------------------------------------------------------
http://www.plainblack.com info@plainblack.com
-------------------------------------------------------------------
=cut
use strict;
use File::Path;
use FileHandle;
=head1 NAME
Package WebGUI::AssetExportHtml
=head1 DESCRIPTION
This is a mixin package for WebGUI::Asset that contains all clipboard related functions.
=head1 SYNOPSIS
use WebGUI::Asset;
=head1 METHODS
These methods are available from this class:
=cut
#-------------------------------------------------------------------
=head2 checkExportPath ( )
Returns a descriptive error message (HTML) if the export path is not writable, does not exist, or is not specified in the per-domain WebGUI config file.
=cut
sub checkExportPath {
my $self = shift;
my $error;
if(defined $self->session->config->get("exportPath")) {
if(-d $self->session->config->get("exportPath")) {
unless (-w $self->session->config->get("exportPath")) {
$error .= 'Error: The export path '.$self->session->config->get("exportPath").' is not writable.<br />
Make sure that the webserver has permissions to write to that directory';
}
} else {
eval {mkpath($self->session->config->get("exportPath"),0)};
if ($@) {
$error .= 'Error: The export path '.$self->session->config->get("exportPath").' does not exist, and couldn\'t create it because '.$@;
}
}
} else {
$error.= 'Error: The export path is not configured. Please set the exportPath variable in the WebGUI config file';
}
$error = '<p><b>'.$error.'</b></p>' if $error;
return $error;
}
#-------------------------------------------------------------------
# Private method to do most of the work for exporting. Returns
# ($success_flag, $description).
# Buggo: probably shouldn't be doing i18n stuff here; refactor this
# further
sub _exportAsHtml {
my $self = shift;
my $quiet = shift;
my $userId = shift;
my $index = shift;
my $extrasUploadsAction = shift;
my $rootUrlAction = shift;
my $startTime = $self->session->datetime->time();
my $exportPathError = $self->checkExportPath();
if ($exportPathError) {
return (0, $exportPathError);
}
my $exportPath = $self->session->config->get('exportPath');
my $defaultAssetId = $self->session->setting->get('defaultPage');
my $defaultAssetPath = undef;
my $i18n = WebGUI::International->new($self->session, 'Asset');
my $tempSession = WebGUI::Session->open($self->session->config->getWebguiRoot, $self->session->config->getFilename);
$tempSession->user({userId=>$userId});
my $newSelf = WebGUI::Asset->new($tempSession, $self->getId, $self->get("className"), $self->get("revisionDate"));
my $assetIds = $newSelf->getLineage(["self","descendants"],{endingLineageLength=>$newSelf->getLineageLength+$self->session->form->process("depth")});
$tempSession->var->end;
$tempSession->close;
foreach my $assetId (@{$assetIds}) {
my $assetSession = WebGUI::Session->open($self->session->config->getWebguiRoot, $self->session->config->getFilename);
$assetSession->user({userId => $userId});
my $asset = WebGUI::Asset->newByDynamicClass($assetSession, $assetId);
my $url = $asset->get("url");
$self->session->output->print(sprintf($i18n->get('exporting page'), $url)) unless $quiet;
unless ($asset->canView($userId)) {
$self->session->output->print(sprintf($i18n->get('bad user privileges')."\n")) unless $quiet;
next;
}
my $path;
my $filename;
if ($url =~ /\./) {
if ($url =~ /^(.*)\/(.*)$/) {
$path = $1;
$filename = $2;
if ($filename eq "") {
$filename = $path;
$path = undef;
}
} else {
$path = undef;
$filename = $url;
}
} else {
$path = $url;
$filename = $index;
}
if ($asset->getId eq $defaultAssetId) {
$defaultAssetPath = $path.'/'.$filename;
}
$path = $exportPath . (length($path)? "/$path" : "");
eval { mkpath($path) };
if($@) {
return (0, sprintf($i18n->get('could not create path'), $path, $@));
}
$path .= "/".$filename;
my $file = eval { FileHandle->new(">".$path) or die "$!" };
if ($@) {
return (0, sprintf($i18n->get('could not open path'), $path, $@));
} else {
$assetSession->output->setHandle($file);
$assetSession->asset($asset);
my $content = $asset->www_view;
unless ($content eq "chunked") {
$assetSession->output->print($content);
}
$file->close;
}
$assetSession->var->end;
$assetSession->close;
$self->session->output->print($i18n->get('done')) unless $quiet;
}
if ($extrasUploadsAction eq 'symlink') {
my ($extrasPath, $uploadsPath) = ($self->session->config->get('extrasPath'), $self->session->config->get('uploadsPath'));
my ($extrasUrl, $uploadsUrl) = ($self->session->config->get('extrasURL'), $self->session->config->get('uploadsURL'));
s#^/*## for ($extrasUrl, $uploadsUrl);
my ($extrasDst, $uploadsDst) = ($exportPath.'/'.$extrasUrl, $exportPath.'/'.$uploadsUrl);
# TODO: internationalize
$self->session->output->print("Symlinking extras and uploads dirs.\n") unless $quiet;
foreach my $rec ([$extrasPath, $extrasDst],
[$uploadsPath, $uploadsDst]) {
my ($path, $dst) = @$rec;
if (-l $dst) {
next if (readlink $dst eq $path);
unlink $dst or return (0, sprintf("Could not unlink %s: %s", $dst, $!));
}
eval { mkpath($dst) };
$@ and return (0, sprintf("Could not create path %s: %s", $dst, $@));
rmdir $dst or return (0, sprintf("Could not remove directory at path %s: %s", $dst, $!));
symlink $path, $dst or return (0, sprintf("Could not symlink %s to %s: %s", $path, $dst, $!));
}
} elsif ($extrasUploadsAction eq 'none') {
# Nothing. This is the default.
}
if ($rootUrlAction eq 'symlinkDefault') {
# TODO: internationalize
if (defined $defaultAssetPath) {
{
my ($src, $dst) = ($defaultAssetPath, $exportPath.'/'.$index);
$self->session->output->print("Symlinking default asset.\n") unless $quiet;
if (-l $dst) {
last if (readlink $dst eq $src);
unlink $dst or return (0, sprintf("Could not unlink %s: %s", $dst, $!));
}
symlink $src, $dst or return (0, sprintf("Could not symlink %s to %s: %s", $src, $dst, $!));
}
} else {
$self->session->output->print("Not symlinking default asset; not included in exported subtree.\n") unless $quiet;
}
} elsif ($rootUrlAction eq 'none') {
# Nothing. This is the default.
}
return (1, sprintf($i18n->get('export information'), scalar(@{$assetIds}), ($self->session->datetime->time()-$startTime)));
}
=head2 exportAsHtml
Same as www_exportGenerate except without the output. Returns
"success" if successful, otherwise returns an error message.
=cut
sub exportAsHtml {
my $self = shift;
my ($success, $description) = $self->_exportAsHtml(1, '1', 'index.html');
return $success? "success" : $description;
}
#-------------------------------------------------------------------
=head2 www_export
Displays the export page administrative interface
=cut
sub www_export {
my $self = shift;
return $self->session->privilege->insufficient() unless ($self->session->user->isInGroup(13));
$self->getAdminConsole->setHelp("page export", "Asset");
my $i18n = WebGUI::International->new($self->session, "Asset");
my $f = WebGUI::HTMLForm->new($self->session,-action=>$self->getUrl);
$f->hidden(
-name => "func",
-value => "exportStatus"
);
$f->integer(
-label=>$i18n->get('Depth'),
-hoverHelp=>$i18n->get('Depth description'),
-name=>"depth",
-value=>99,
);
$f->selectBox(
-label=>$i18n->get('Export as user'),
-hoverHelp=>$i18n->get('Export as user description'),
-name=>"userId",
-options=>$self->session->db->buildHashRef("select userId, username from users"),
-value=>[1],
);
$f->text(
-label=>$i18n->get("directory index"),
-hoverHelp=>$i18n->get("directory index description"),
-name=>"index",
-value=>"index.html"
);
# TODO: internationalize
# TODO: maybe add copy options to these boxes alongside symlink
$f->selectBox(
-label => "Extras and uploads directories",
-hoverHelp => "What action to take regarding the extras and uploads directories, which are often referenced by parts of the site. Symlink means to use a symbolic link (not available on all systems) to the original directory. None means to do nothing, and ignore the extras and uploads directories; this will probably cause references to them to break in the exported site unless you've prepared the directories already.",
-name => "extrasUploadsAction",
-options => { 'symlink' => 'Symlink',
'none' => 'None' },
-value => ['none'],
);
$f->selectBox(
-label => "Root URL",
-hoverHelp => "What action to take regarding queries to the root URL. Symlink Default means to create a symbolic link from the root-URL index file to the index file of the default asset (not available on all systems). None means to do nothing, which usually causes queries to the root URL to be rejected in the exported site.",
-name => "rootUrlAction",
-options => { 'symlinkDefault' => 'Symlink Default',
'none' => 'None' },
-value => ['none'],
);
$f->submit;
$self->getAdminConsole->render($self->checkExportPath.$f->print,$i18n->get('Export Page'));
}
#-------------------------------------------------------------------
=head2 www_exportStatus
Displays the export status page
=cut
sub www_exportStatus {
my $self = shift;
return $self->session->privilege->insufficient() unless ($self->session->user->isInGroup(13));
my $i18n = WebGUI::International->new($self->session, "Asset");
my $iframeUrl = $self->getUrl('func=exportGenerate');
foreach my $formVar (qw/index depth userId extrasUploadsAction rootUrlAction/) {
$iframeUrl = $self->session->url->append($iframeUrl, $formVar.'='.$self->session->form->process($formVar));
}
my $output = '<iframe src="'.$iframeUrl.'" title="'.$i18n->get('Page Export Status').'" width="410" height="200"></iframe>';
$self->getAdminConsole->render($output,$i18n->get('Page Export Status'),"Asset");
}
#-------------------------------------------------------------------
=head2 www_exportGenerate
Executes the export process and displays real time status. This operation is displayed by exportStatus in an IFRAME.
=cut
sub www_exportGenerate {
my $self = shift;
return $self->session->privilege->insufficient() unless ($self->session->user->isInGroup(13));
# This routine is called in an IFRAME and prints status output directly to the browser.
$|++; # Unbuffered data output
$self->session->http->sendHeader;
my $i18n = WebGUI::International->new($self->session, 'Asset');
my ($success, $description) =
$self->_exportAsHtml(0, $self->session->form->process('userId'),
$self->session->form->process('index'),
$self->session->form->process('extrasUploadsAction'),
$self->session->form->process('rootUrlAction'));
if (!$success) {
$self->session->output->print($description,1);
return;
}
$self->session->output->print($description,1);
$self->session->output->print('<a target="_parent" href="'.$self->getUrl.'">'.$i18n->get(493,'WebGUI').'</a>');
return;
}
1;