diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index b207c5081..0b3b2e21a 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -13,6 +13,9 @@ - Graphics::Magick is now the standard graphics package in WebGUI, but Image::Magick will be supported for backwards compatibility. See gotcha.txt for details. + - fix: A bug where it was possible to delete a system page if it were made + the child of a non-system page that you had edit rights to. + - api: Added a unified contraints system for the file and image assets. - Added file attachments to the Wiki. - Added a new attachments form control. - Added a form control skeleton. diff --git a/docs/upgrades/upgrade_7.3.22-7.4.0.pl b/docs/upgrades/upgrade_7.3.22-7.4.0.pl index 65e4daa01..54f7f1d19 100644 --- a/docs/upgrades/upgrade_7.3.22-7.4.0.pl +++ b/docs/upgrades/upgrade_7.3.22-7.4.0.pl @@ -98,6 +98,7 @@ sub addWikiAttachments { $db->write("alter table WikiPage drop column storageId"); my $root = WebGUI::Asset->getRoot($session); $root->addChild({title=>"Tempspace", url=>"tempspace", className=>"WebGUI::Asset::Wobject::Folder"}, "tempspace0000000000000"); + $db->write("update asset set isSystem=1 where assetId=?", ["tempspace0000000000000"]); } #------------------------------------------------- diff --git a/lib/WebGUI/Asset/File.pm b/lib/WebGUI/Asset/File.pm index 50571acb0..da096ae3b 100644 --- a/lib/WebGUI/Asset/File.pm +++ b/lib/WebGUI/Asset/File.pm @@ -67,6 +67,25 @@ sub addRevision { return $newSelf; } +#------------------------------------------------------------------- + +=head2 applyConstraints ( options ) + +Enforce certain things when new files are uploaded. + +=head3 options + +A hash reference of optional parameters. None at this time. + +=cut + +sub applyConstraints { + my $self = shift; + $self->getStorageLocation->setPrivileges($self->get('ownerUserId'), $self->get('groupIdView'), $self->get('groupIdEdit')); + $self->setSize; +} + + #------------------------------------------------------------------- =head2 definition ( definition ) @@ -285,7 +304,6 @@ sub processPropertiesFromFormPost { 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) { @@ -299,6 +317,7 @@ sub processPropertiesFromFormPost { $self->update(\%data); } } + $self->applyConstraints; } diff --git a/lib/WebGUI/Asset/File/Image.pm b/lib/WebGUI/Asset/File/Image.pm index 58e7a9199..ffa6cb19e 100644 --- a/lib/WebGUI/Asset/File/Image.pm +++ b/lib/WebGUI/Asset/File/Image.pm @@ -46,6 +46,53 @@ These methods are available from this class: +#------------------------------------------------------------------- + +=head2 applyConstraints ( options ) + +Things that are done after a new file is attached. + +=head3 options + +A hash reference of optional parameters. + +=head4 maxImageSize + +An integer (in pixels) representing the longest edge the image may have. + +=head4 thumbnailSize + +An integer (in pixels) representing the longest edge a thumbnail may have. + +=cut + +sub applyConstraints { + my $self = shift; + my $options = shift; + $self->SUPER::applyConstraints($options); + my $maxImageSize = $options->{maxImageSize} || $self->session->setting->get("maxImageSize"); + my $thumbnailSize = $options->{thumbnailSize} || $self->session->setting->get("thumbnailSize"); + my $parameters = $self->get("parameters"); + my $storage = $self->getStorageLocation; + unless ($parameters =~ /alt\=/) { + $self->update({parameters=>$parameters.' alt="'.$self->get("title").'"'}); + } + my $file = $self->get("filename"); + my ($w, $h) = $storage->getSizeInPixels($file); + if($w > $maxImageSize || $h > $maxImageSize) { + if($w > $h) { + $storage->resize($file, $maxImageSize); + } + else { + $storage->resize($file, 0, $maxImageSize); + } + } + $self->generateThumbnail($thumbnailSize); + $self->setSize; +} + + + #------------------------------------------------------------------- =head2 definition ( definition ) @@ -219,23 +266,7 @@ sub prepareView { sub processPropertiesFromFormPost { my $self = shift; $self->SUPER::processPropertiesFromFormPost; - my $parameters = $self->get("parameters"); - my $storage = $self->getStorageLocation; - unless ($parameters =~ /alt\=/) { - $self->update({parameters=>$parameters.' alt="'.$self->get("title").'"'}); - } - my $max_size = $self->session->setting->get("maxImageSize"); - my $file = $self->get("filename"); - my ($w, $h) = $storage->getSizeInPixels($file); - if($w > $max_size || $h > $max_size) { - if($w > $h) { - $storage->resize($file, $max_size); - } - else { - $storage->resize($file, 0, $max_size); - } - } - $self->generateThumbnail($self->session->form->process("thumbnailSize")); + $self->applyConstraints; } #------------------------------------------------------------------- diff --git a/lib/WebGUI/Asset/FilePile.pm b/lib/WebGUI/Asset/FilePile.pm index d04e8ab78..753cf1303 100644 --- a/lib/WebGUI/Asset/FilePile.pm +++ b/lib/WebGUI/Asset/FilePile.pm @@ -165,20 +165,6 @@ sub editSave { $data{templateId} = 'PBtmpl0000000000000024'; if ($selfName eq "WebGUI::Asset::File::Image") { $data{templateId} = 'PBtmpl0000000000000088'; - $data{parameters} = 'alt="'.$self->get("title").'"'; - - # Resize image if it is bigger than the max allowed image size. - my $maxSize = $self->session->setting->get("maxImageSize"); - my ($width, $height) = $tempStorage->getSizeInPixels($filename); - if($width > $maxSize || $height > $maxSize) { - if($width > $height) { - $tempStorage->resize($filename, $maxSize); - } - else { - $tempStorage->resize($filename, 0, $maxSize); - } - } - } $data{url} = $self->getParent->get('url').'/'.$filename; @@ -188,11 +174,7 @@ sub editSave { #Get the current storage location my $storage = $newAsset->getStorageLocation(); $storage->addFileFromFilesystem($tempStorage->getPath($filename)); - $storage->setPrivileges($data{"ownerUserId"},$data{"groupIdView"},$data{"groupIdEdit"}); - - $newAsset->setSize($tempStorage->getFileSize($filename)); - $newAsset->generateThumbnail if ($selfName eq "WebGUI::Asset::File::Image"); - $newAsset->update({ storageId=> $storage->getId }); + $newAsset->applyConstraints; #Now remove the reference to the storeage location to prevent problems with different revisions. delete $newAsset->{_storageLocation}; diff --git a/lib/WebGUI/Asset/WikiPage.pm b/lib/WebGUI/Asset/WikiPage.pm index af21dee28..ab51fd0fe 100644 --- a/lib/WebGUI/Asset/WikiPage.pm +++ b/lib/WebGUI/Asset/WikiPage.pm @@ -175,7 +175,9 @@ sub getEditForm { } $var->{formAttachment} = WebGUI::Form::Attachments($session, { value => $children, - maxAttachments => $wiki->get("allowAttachments") + maxAttachments => $wiki->get("allowAttachments"), + maxImageSize => $wiki->get("maxImageSize"), + thumbnailSize => $wiki->get("thumbnailSize"), }); return $self->processTemplate($var, $wiki->getValue('pageEditTemplateId')); } @@ -236,6 +238,7 @@ sub processPropertiesFromFormPost { $self->update({isProtected => $self->session->form("isProtected")}); } + # deal with attachments from the attachments form control my @attachments = $self->session->form->param("attachments"); my @tags = (); foreach my $assetId (@attachments) { @@ -243,11 +246,18 @@ sub processPropertiesFromFormPost { if (defined $asset) { unless ($asset->get("parentId") eq $self->getId) { $asset->setParent($self); + $asset->update({ + ownerUserId => $self->get("ownerUserId"), + groupIdEdit => $self->get("groupIdEdit"), + groupIdView => $self->get("groupIdView"), + }); } push(@tags, $asset->get("tagId")); $asset->setVersionTag($self->get("tagId")); } } + + # clean up empty tags foreach my $tag (@tags) { my $version = WebGUI::VersionTag->new($self->session, $tag); if (defined $version) { @@ -256,6 +266,8 @@ sub processPropertiesFromFormPost { } } } + + # wiki pages are auto committed $self->requestAutoCommit; } diff --git a/lib/WebGUI/AssetLineage.pm b/lib/WebGUI/AssetLineage.pm index c440c3c8d..2cfe6e857 100644 --- a/lib/WebGUI/AssetLineage.pm +++ b/lib/WebGUI/AssetLineage.pm @@ -260,11 +260,12 @@ A hash reference comprising modifiers to relative listing. Rules include: =head4 statesToInclude -An array reference containing a list of states that should be returned. Defaults to 'published'. Options include 'published', 'trash', 'cliboard', 'clipboard-limbo' and 'trash-limbo'. +An array reference containing a list of states that should be returned. Defaults to 'published'. Options include +'published', 'trash', 'clipboard', 'clipboard-limbo' and 'trash-limbo'. =head4 statusToInclude -An array reference containing a list of status that should be returned. Defaults to 'approved'. Options include 'approved', 'pending', 'deleted', and 'archived'. +An array reference containing a list of status that should be returned. Defaults to 'approved'. Options include 'approved', 'pending', and 'archived'. =head4 endingLineageLength diff --git a/lib/WebGUI/AssetTrash.pm b/lib/WebGUI/AssetTrash.pm index 88e015503..6a963a0b9 100644 --- a/lib/WebGUI/AssetTrash.pm +++ b/lib/WebGUI/AssetTrash.pm @@ -95,7 +95,8 @@ sub getAssetsInTrash { =head2 purge ( [ options ] ) -Deletes an asset from tables and removes anything bound to that asset, including descendants. +Deletes an asset from tables and removes anything bound to that asset, including descendants. Returns 1 on success +and 0 on failure. =head3 options @@ -110,30 +111,66 @@ A boolean that, if true, will skip dealing with exported files. sub purge { my $self = shift; my $options = shift; - return undef if ($self->getId eq $self->session->setting->get("defaultPage") || $self->getId eq $self->session->setting->get("notFoundPage") || $self->get("isSystem")); + my $session = $self->session; + + # can't delete if it's one of these things + if ($self->getId eq $session->setting->get("defaultPage") || $self->getId eq $session->setting->get("notFoundPage") || $self->get("isSystem")) { + $session->errorHandler->security("delete a system protected page (".$self->getId.")"); + return 0; + } + + # assassinate the offspring + my $kids = $self->getLineage(["children"],{returnObjects=>1, statesToInclude=>['published', 'clipboard', 'clipboard-limbo','trash','trash-limbo']}); + foreach my $kid (@{$kids}) { + # Technically get lineage should never return an undefined object from getLineage when called like this, but it did so this saves the world from destruction. + if (defined $kid) { + unless ($kid->purge) { + $self->errorHandler->security("delete one of (".$self->getId.")'s children which is a system protected page"); + return 0; + } + } + else { + $session->errorHandler->error("getLineage returned an undefined object in the AssetTrash->purge method. Unable to purge asset."); + } + } + + # gotta delete stuff we've exported unless ($options->{skipExported}) { $self->_invokeWorkflowOnExportedFiles($self->session->setting->get('purgeWorkflow'), 1); } - my $kids = $self->getLineage(["children"],{returnObjects=>1, statesToInclude=>['published', 'clipboard', 'clipboard-limbo','trash','trash-limbo']}); - foreach my $kid (@{$kids}) { - # Technically get lineage should never return an undefined object from getLineage when called like this, but it did so this saves the world from destruction. - (defined $kid) ? $kid->purge : - $self->session->errorHandler->warn("getLineage returned an undefined object in the AssetTrash->purge method. Unable to purge asset."); - } - WebGUI::Keyword->new($self->session)->deleteKeywordsForAsset($self); + # gonna need this at the end + my $tagId = $self->get("tagId"); + + # clean up keywords + WebGUI::Keyword->new($session)->deleteKeywordsForAsset($self); + + # clean up search engine WebGUI::Search::Index->new($self)->delete; - $self->session->db->beginTransaction; - $self->session->db->write("delete from metaData_values where assetId = ".$self->session->db->quote($self->getId)); - foreach my $definition (@{$self->definition($self->session)}) { - $self->session->db->write("delete from ".$definition->{tableName}." where assetId=".$self->session->db->quote($self->getId)); - } - $self->session->db->write("delete from asset where assetId=".$self->session->db->quote($self->getId)); - $self->session->db->commit; + + # clean up cache + WebGUI::Cache->new($session)->deleteChunk(["asset",$self->getId]); $self->purgeCache; - WebGUI::Cache->new($self->session)->deleteChunk(["asset",$self->getId]); + + # delete stuff out of the asset tables + $session->db->beginTransaction; + $session->db->write("delete from metaData_values where assetId = ?",[$self->getId]); + foreach my $definition (@{$self->definition($session)}) { + $session->db->write("delete from ".$definition->{tableName}." where assetId=?", [$self->getId]); + } + $session->db->write("delete from asset where assetId=?", [$self->getId]); + $session->db->commit; + + # log that we've purged this asset $self->updateHistory("purged"); $self = undef; + + # clean up version tag if empty + my $versionTag = WebGUI::VersionTag->new($session, $tagId); + if ($versionTag->getAssetCount == 0) { + $versionTag->rollback; + } + return 1; } diff --git a/lib/WebGUI/Form/Attachments.pm b/lib/WebGUI/Form/Attachments.pm index e485b2fe8..63e27f796 100644 --- a/lib/WebGUI/Form/Attachments.pm +++ b/lib/WebGUI/Form/Attachments.pm @@ -69,6 +69,16 @@ How many attachments will be allowed to be uploaded. Defaults to 1. An array reference of asset objects (not ids, but objects) that should be displayed in the attachments box. +=head4 maxImageSize + +An integer (in pixels) of the maximum height or width an image can be. Defaults to the size in the main settings if +not specified. + +=head4 thumbnailSize + +An integer (in pixels) of the proportional size of a thumbnail for an image. Defaults to the size in the main +settings if not specified. + =cut sub definition { @@ -86,6 +96,8 @@ sub definition { maxAttachments=>{ defaultValue=>1 }, + maxImageSize=>{}, + thumbnailSize=>{}, profileEnabled=>{ defaultValue=>0 }, @@ -122,11 +134,14 @@ Renders an attachments control. sub toHtml { my $self = shift; my @assetIds = @{$self->get("value")}; + my $thumbnail = $self->get("thumbnailSize") || $self->session->setting->get("thumbnailSize"); + my $image = $self->get("maxImageSize") || $self->session->setting->get("maxImageSize"); my $attachmentsList = "attachments=".join(";attachments=", @assetIds) if (scalar(@assetIds)); return '
'; + .";maxAttachments=".$self->get("maxAttachments")).";maxImageSize=".$image.";thumbnailSize=" + .$thumbnail.";".$attachmentsList + .'" style="width: 100%; height: 120px;">'; } @@ -200,6 +215,8 @@ sub www_show { X