the assetSize in the db was set wrong. This happened when a File/Image was added, and when it is committed. Editing the Asset would fix it, but once it was committed, the files in the Storage area were not added. List of Changes: 1) Removed setSize from File/Image.pm. It can inherit from File. 2) In Asset::File::processPropertiesFromFormPost, set _storageLocation to the Storage object. Remove the call to setSize since it's done in ->update 3) In Asset::File::setSize, fetch the current storage object via getStorageLocation. 4) In Asset::File::update, move the call to update after the filesystem work. This way changes in the size of the permissions file get accounted for. 5) In Asset::update, call setSize after all changes, regardless of whether or not properties have changed. 6) In Asset::setSize, refactor out the size calculation and update $self's properties cache so that long running scripts have the right size.
448 lines
12 KiB
Perl
448 lines
12 KiB
Perl
package WebGUI::Asset::File;
|
|
|
|
=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 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');
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------
|
|
|
|
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 $fileStorageId = WebGUI::Form::File->new($session, {name => 'newFile', value=>$storageId })->getValueFromPost;
|
|
my $storage = WebGUI::Storage->get($session, $fileStorageId);
|
|
|
|
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->{_storageLocation} = $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;
|
|
if ($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'),
|
|
);
|
|
##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"));
|
|
}
|
|
$self->SUPER::update(@_);
|
|
}
|
|
|
|
#-------------------------------------------------------------------
|
|
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;
|