the file does not exist. Fixed a bug I created by changing the order of update and change comparison in Asset/File.pm. This caused Asset/File.t, Asset/File/Image.t and Macro/Thumbnail.t to fail.
469 lines
13 KiB
Perl
469 lines
13 KiB
Perl
package WebGUI::Asset::File;
|
|
|
|
=head1 LEGAL
|
|
|
|
-------------------------------------------------------------------
|
|
WebGUI is Copyright 2001-2007 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 base 'WebGUI::Asset';
|
|
use WebGUI::Cache;
|
|
use WebGUI::Storage;
|
|
use WebGUI::SQL;
|
|
use WebGUI::Utility;
|
|
use FileHandle;
|
|
|
|
|
|
|
|
=head1 NAME
|
|
|
|
Package WebGUI::Asset::File
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
Provides a mechanism to upload files to WebGUI.
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use WebGUI::Asset::File;
|
|
|
|
|
|
=head1 METHODS
|
|
|
|
These methods are available from this class:
|
|
|
|
=cut
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 addRevision
|
|
|
|
Override the default method in order to deal with attachments.
|
|
|
|
=cut
|
|
|
|
sub addRevision {
|
|
my $self = shift;
|
|
my $properties = shift;
|
|
|
|
if ($self->get("storageId") ne "") {
|
|
my $newStorage = WebGUI::Storage->get($self->session,$self->get("storageId"))->copy;
|
|
$properties->{storageId} = $newStorage->getId;
|
|
}
|
|
|
|
my $newSelf = $self->SUPER::addRevision($properties);
|
|
|
|
return $newSelf;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 definition ( definition )
|
|
|
|
Defines the properties of this asset.
|
|
|
|
=head3 definition
|
|
|
|
A hash reference passed in from a subclass definition.
|
|
|
|
=cut
|
|
|
|
sub definition {
|
|
my $class = shift;
|
|
my $session = shift;
|
|
my $definition = shift;
|
|
my $i18n = WebGUI::International->new($session,"Asset_File");
|
|
push(@{$definition}, {
|
|
assetName=>$i18n->get('assetName'),
|
|
tableName=>'FileAsset',
|
|
className=>'WebGUI::Asset::File',
|
|
properties=>{
|
|
cacheTimeout => {
|
|
tab => "display",
|
|
fieldType => "interval",
|
|
defaultValue => 3600,
|
|
uiLevel => 8,
|
|
label => $i18n->get("cache timeout"),
|
|
hoverHelp => $i18n->get("cache timeout help")
|
|
},
|
|
filename=>{
|
|
noFormPost=>1,
|
|
fieldType=>'hidden',
|
|
defaultValue=>undef
|
|
},
|
|
storageId=>{
|
|
noFormPost=>1,
|
|
fieldType=>'hidden',
|
|
defaultValue=>undef
|
|
},
|
|
templateId=>{
|
|
fieldType=>'template',
|
|
defaultValue=>'PBtmpl0000000000000024'
|
|
}
|
|
}
|
|
});
|
|
return $class->SUPER::definition($session, $definition);
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
sub duplicate {
|
|
my $self = shift;
|
|
my $newAsset = $self->SUPER::duplicate(@_);
|
|
my $newStorage = $self->getStorageLocation->copy;
|
|
$newAsset->update({storageId=>$newStorage->getId});
|
|
return $newAsset;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 exportAssetData ( )
|
|
|
|
See WebGUI::AssetPackage::exportAssetData() for details.
|
|
|
|
=cut
|
|
|
|
sub exportAssetData {
|
|
my $self = shift;
|
|
my $data = $self->SUPER::exportAssetData;
|
|
push(@{$data->{storage}}, $self->get("storageId")) if ($self->get("storageId") ne "");
|
|
return $data;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getEditForm ( )
|
|
|
|
Returns the TabForm object that will be used in generating the edit page for this asset.
|
|
|
|
=cut
|
|
|
|
sub getEditForm {
|
|
my $self = shift;
|
|
my $tabform = $self->SUPER::getEditForm();
|
|
my $i18n = WebGUI::International->new($self->session, 'Asset_File');
|
|
if ($self->get("filename") ne "") {
|
|
$tabform->getTab("properties")->readOnly(
|
|
-label=>$i18n->get('current file'),
|
|
-hoverHelp=>$i18n->get('current file description', 'Asset_File'),
|
|
-value=>'<p style="display:inline;vertical-align:middle;"><a href="'.$self->getFileUrl.'"><img src="'.$self->getFileIconUrl.'" alt="'.$self->get("filename").'" style="border-style:none;vertical-align:middle;" /> '.$self->get("filename").'</a></p>'
|
|
);
|
|
|
|
}
|
|
$tabform->getTab("properties")->file(
|
|
-name => 'newFile',
|
|
-label => $i18n->get('new file'),
|
|
-hoverHelp => $i18n->get('new file description'),
|
|
);
|
|
return $tabform;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
sub getFileUrl {
|
|
my $self = shift;
|
|
#return $self->get("url");
|
|
return $self->getStorageLocation->getUrl($self->get("filename"));
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
sub getFileIconUrl {
|
|
my $self = shift;
|
|
return $self->getStorageLocation->getFileIconUrl($self->get("filename"));
|
|
}
|
|
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
sub getIcon {
|
|
my $self = shift;
|
|
my $small = shift;
|
|
if ($small && $self->get("dummy")) {
|
|
return $self->session->url->extras('assets/small/file.gif');
|
|
} elsif ($small) {
|
|
return $self->getFileIconUrl;
|
|
}
|
|
return $self->session->url->extras('assets/file.gif');
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 getStorageFromPost
|
|
|
|
We have to wrap this operation because WebGUI::Asset::File::Image calls SUPER processPropertiesFormFormPost,
|
|
which gives it the wrong type of Storage object.
|
|
|
|
=cut
|
|
|
|
sub getStorageFromPost {
|
|
my $self = shift;
|
|
my $storageId = shift;
|
|
my $fileStorageId = WebGUI::Form::File->new($self->session, {name => 'newFile', value=>$storageId })->getValueFromPost;
|
|
return WebGUI::Storage->get($self->session, $fileStorageId);
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
sub getStorageLocation {
|
|
my $self = shift;
|
|
unless (exists $self->{_storageLocation}) {
|
|
$self->setStorageLocation;
|
|
}
|
|
return $self->{_storageLocation};
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 indexContent ( )
|
|
|
|
Indexing the content of the attachment. See WebGUI::Asset::indexContent() for additonal details.
|
|
|
|
=cut
|
|
|
|
sub indexContent {
|
|
my $self = shift;
|
|
my $indexer = $self->SUPER::indexContent;
|
|
$indexer->addFile($self->getStorageLocation->getPath($self->get("filename")));
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 prepareView ( )
|
|
|
|
See WebGUI::Asset::prepareView() for details.
|
|
|
|
=cut
|
|
|
|
sub prepareView {
|
|
my $self = shift;
|
|
$self->SUPER::prepareView();
|
|
my $template = WebGUI::Asset::Template->new($self->session, $self->get("templateId"));
|
|
$template->prepare;
|
|
$self->{_viewTemplate} = $template;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
sub processPropertiesFromFormPost {
|
|
my $self = shift;
|
|
my $session = $self->session;
|
|
$self->SUPER::processPropertiesFromFormPost;
|
|
|
|
#Get the storage location out of memory. If you call getStorageLocation you risk creating another one.
|
|
my $storageLocation = $self->{_storageLocation};
|
|
my $storageId = undef;
|
|
$storageId = $storageLocation->getId if(defined $storageLocation);
|
|
|
|
#Now remove the storage location to prevent wierd caching stuff.
|
|
delete $self->{_storageLocation};
|
|
|
|
#Clear the storage location if a file was uploaded.
|
|
if($session->form->get("newFile_file") ne "") {
|
|
$storageLocation->clear();
|
|
}
|
|
|
|
#Pass in the storage Id to prevent another one from being created.
|
|
my $storage = $self->getStorageFromPost($storageId);
|
|
|
|
if (defined $storage) {
|
|
$storage->setPrivileges($self->get('ownerUserId'), $self->get('groupIdView'), $self->get('groupIdEdit'));
|
|
my $filename = $storage->getFiles()->[0];
|
|
|
|
if (defined $filename) {
|
|
my %data;
|
|
$data{filename} = $filename;
|
|
$data{storageId} = $storage->getId;
|
|
$data{title} = $filename unless ($session->form->process("title"));
|
|
$data{menuTitle} = $filename unless ($session->form->process("menuTitle"));
|
|
$data{url} = $self->getParent->get('url').'/'.$filename unless ($session->form->process("url"));
|
|
$self->setStorageLocation($storage);
|
|
$self->update(\%data);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
sub purge {
|
|
my $self = shift;
|
|
my $sth = $self->session->db->read("select storageId from FileAsset where assetId=".$self->session->db->quote($self->getId));
|
|
while (my ($storageId) = $sth->array) {
|
|
WebGUI::Storage->get($self->session,$storageId)->delete;
|
|
}
|
|
$sth->finish;
|
|
return $self->SUPER::purge;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 purgeCache ( )
|
|
|
|
See WebGUI::Asset::purgeCache() for details.
|
|
|
|
=cut
|
|
|
|
sub purgeCache {
|
|
my $self = shift;
|
|
WebGUI::Cache->new($self->session,"view_".$self->getId)->delete;
|
|
$self->SUPER::purgeCache;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
sub purgeRevision {
|
|
my $self = shift;
|
|
$self->getStorageLocation->delete;
|
|
return $self->SUPER::purgeRevision;
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub setSize {
|
|
my $self = shift;
|
|
my $fileSize = shift || 0;
|
|
my $storage = $self->getStorageLocation;
|
|
if (defined $storage) {
|
|
foreach my $file (@{$storage->getFiles}) {
|
|
$fileSize += $storage->getFileSize($file);
|
|
}
|
|
}
|
|
return $self->SUPER::setSize($fileSize);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
sub setStorageLocation {
|
|
my $self = shift;
|
|
my $storage = shift;
|
|
if (defined $storage) {
|
|
$self->{_storageLocation} = $storage;
|
|
}
|
|
elsif ($self->get("storageId") eq "") {
|
|
$self->{_storageLocation} = WebGUI::Storage->create($self->session);
|
|
$self->update({storageId=>$self->{_storageLocation}->getId});
|
|
}
|
|
else {
|
|
$self->{_storageLocation} = WebGUI::Storage->get($self->session,$self->get("storageId"));
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
=head2 update
|
|
|
|
We override the update method from WebGUI::Asset in order to handle file system privileges.
|
|
|
|
=cut
|
|
|
|
sub update {
|
|
my $self = shift;
|
|
my %before = (
|
|
owner => $self->get("ownerUserId"),
|
|
view => $self->get("groupIdView"),
|
|
edit => $self->get("groupIdEdit"),
|
|
storageId => $self->get('storageId'),
|
|
);
|
|
$self->SUPER::update(@_);
|
|
##update may have entered a new storageId. Reset the cached one just in case.
|
|
if ($self->get("storageId") ne $before{storageId}) {
|
|
$self->setStorageLocation;
|
|
}
|
|
if ($self->get("ownerUserId") ne $before{owner} || $self->get("groupIdEdit") ne $before{edit} || $self->get("groupIdView") ne $before{view}) {
|
|
$self->getStorageLocation->setPrivileges($self->get("ownerUserId"),$self->get("groupIdView"),$self->get("groupIdEdit"));
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
sub view {
|
|
my $self = shift;
|
|
if (!$self->session->var->isAdminOn && $self->get("cacheTimeout") > 10) {
|
|
my $out = WebGUI::Cache->new($self->session,"view_".$self->getId)->get;
|
|
return $out if $out;
|
|
}
|
|
my %var = %{$self->get};
|
|
$var{controls} = $self->getToolbar;
|
|
$var{fileUrl} = $self->getFileUrl;
|
|
$var{fileIcon} = $self->getFileIconUrl;
|
|
$var{fileSize} = formatBytes($self->get("assetSize"));
|
|
my $out = $self->processTemplate(\%var,undef,$self->{_viewTemplate});
|
|
if (!$self->session->var->isAdminOn && $self->get("cacheTimeout") > 10) {
|
|
WebGUI::Cache->new($self->session,"view_".$self->getId)->set($out,$self->get("cacheTimeout"));
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
sub www_edit {
|
|
my $self = shift;
|
|
return $self->session->privilege->insufficient() unless $self->canEdit;
|
|
return $self->session->privilege->locked() unless $self->canEditIfLocked;
|
|
my $i18n = WebGUI::International->new($self->session);
|
|
my $tabform = $self->getEditForm;
|
|
$tabform->getTab("display")->template(
|
|
-value=>$self->getValue("templateId"),
|
|
-hoverHelp=>$i18n->get('file template description','Asset_File'),
|
|
-namespace=>"FileAsset"
|
|
);
|
|
$self->getAdminConsole->setHelp("file add/edit", "Asset_File");
|
|
my $addEdit = ($self->session->form->process("func") eq 'add') ? $i18n->get('add','Asset_Wobject') : $i18n->get('edit','Asset_Wobject');
|
|
return $self->getAdminConsole->render($tabform->print,$addEdit.' '.$self->getName);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
# setStreamedFile and setRedirect do not interact well with the
|
|
# exporter. We have a separate method for this now.
|
|
sub exportHtml_view {
|
|
my $self = shift;
|
|
my $path = $self->getStorageLocation->getPath($self->get('filename'));
|
|
my $fh = eval { FileHandle->new($path) };
|
|
defined($fh) or return "";
|
|
binmode $fh or ($fh->close, return "");
|
|
my $block;
|
|
while (read($fh, $block, 16384) > 0) {
|
|
$self->session->output->print($block, 1);
|
|
}
|
|
$fh->close;
|
|
return 'chunked';
|
|
}
|
|
|
|
#--------------------------------------------------------------------
|
|
sub www_view {
|
|
my $self = shift;
|
|
return $self->session->privilege->noAccess() unless $self->canView;
|
|
|
|
# Check to make sure it's not in the trash or some other weird place
|
|
my $state = $self->get("state");
|
|
if ($state ne "published" && $state ne "archived") {
|
|
my $i18n = WebGUI::International->new($self->session,'Asset_File');
|
|
$self->session->http->setStatus("404");
|
|
return sprintf($i18n->get("file not found"), $self->getUrl());
|
|
}
|
|
|
|
$self->session->http->setRedirect($self->getFileUrl);
|
|
$self->session->http->setStreamedFile($self->getStorageLocation->getPath($self->get("filename")));
|
|
return 'chunked';
|
|
}
|
|
|
|
|
|
1;
|