diff --git a/docs/upgrades/upgrade_6.6.3-6.7.0.pl b/docs/upgrades/upgrade_6.6.3-6.7.0.pl index f87ad9606..5a6f03440 100644 --- a/docs/upgrades/upgrade_6.6.3-6.7.0.pl +++ b/docs/upgrades/upgrade_6.6.3-6.7.0.pl @@ -39,6 +39,7 @@ sub updateConfigFile { } } $newConfig{fileCacheSizeLimit} = 100000000; + $newConfig{DeleteExpiredRevisions_offset} = 365; $conf->purge; $conf->set(%newConfig); $conf->write; @@ -118,6 +119,7 @@ sub addAssetVersioning { $sth->finish; WebGUI::SQL->write("alter table asset add column creationDate bigint not null default 997995720"); WebGUI::SQL->write("alter table asset add column createdBy varchar(22) not null default '3'"); + WebGUI::SQL->write("alter table asset add column stateChanged varchar(22) not null default 997995720"); WebGUI::SQL->write("alter table asset add column stateChangedBy varchar(22) not null default '3'"); WebGUI::SQL->write("alter table asset add column isLockedBy varchar(22)"); WebGUI::SQL->write("update asset set creationDate=$now, createdBy='3'"); diff --git a/etc/WebGUI.conf.original b/etc/WebGUI.conf.original index 8916635c3..9efeab4ae 100644 --- a/etc/WebGUI.conf.original +++ b/etc/WebGUI.conf.original @@ -235,6 +235,16 @@ DeleteExpiredClipboard_offset = 30 DeleteExpiredTrash_offset = 30 +# Specify the number of days old revisions of assets should remain +# available for rollbacks. + +DeleteExpiredRevisions_offset = 365 + +# How many days after a piece of content expires should it be +# moved to the trash. + +TrashExpiredContent_offset = 30 + # What hour of the day (for example, 22 = 10 PM = 22:00:00) # should WebGUI try to synchronize user profile information from # the LDAP server. Note that this will only happen for users @@ -242,7 +252,3 @@ DeleteExpiredTrash_offset = 30 SyncProfilesToLDAP_hour = 2 -# How many days after a piece of content expires should it be -# moved to the trash. - -TrashExpiredContent_offset = 30 diff --git a/lib/WebGUI/Asset.pm b/lib/WebGUI/Asset.pm index 8a76fc4b1..52192e255 100644 --- a/lib/WebGUI/Asset.pm +++ b/lib/WebGUI/Asset.pm @@ -320,10 +320,13 @@ sub cascadeLineage { my $prepared = WebGUI::SQL->prepare("update asset set lineage=? where assetId=?"); my $descendants = WebGUI::SQL->read("select assetId,lineage from asset where lineage like ".quote($oldLineage.'%')); while (my ($assetId, $lineage) = $descendants->array) { - WebGUI::Cache->new("asset_".$assetId)->delete; - WebGUI::Cache->new("lineage_".$lineage)->delete; my $fixedLineage = $newLineage.substr($lineage,length($oldLineage)); $prepared->execute([$fixedLineage,$assetId]); + my $sth = WebGUI::SQL->read("select assetId,revisionDate from assetData where asset=".quote($assetId)); + while (my ($id,$version) = $sth->array) { + WebGUI::Cache->new("asset_".$id."/".$version)->delete; + } + $sth->finish; } $descendants->finish; } @@ -369,7 +372,7 @@ sub cut { my $self = shift; WebGUI::SQL->beginTransaction; WebGUI::SQL->write("update asset set state='clipboard-limbo' where lineage like ".quote($self->get("lineage").'%')." and state='published'"); - WebGUI::SQL->write("update asset set state='clipboard', stateChangedBy=".quote($session{user}{userId})." where assetId=".quote($self->getId)); + WebGUI::SQL->write("update asset set state='clipboard', stateChangedBy=".quote($session{user}{userId}).", stateChanged=".time()." where assetId=".quote($self->getId)); WebGUI::SQL->commit; $self->updateHistory("cut"); $self->{_properties}{state} = "clipboard"; @@ -1646,6 +1649,26 @@ sub getRank { #------------------------------------------------------------------- +=head2 getRevisionCount ( [ status ] ) + +Returns the number of revisions available for this asset. + +=head3 status + +Optionally specify to get the count based upon the status of the revisions. Options are "approved", "pending", "denied". Defaults to any status. + +=cut + +sub getRevisionCount { + my $self = shift; + my $status = shift; + my $statusClause = " and status=".quote($status) if ($status); + my ($count) = WebGUI::SQL->quickArray("select count(*) from assetData where assetId=".quote($self->getId).$statusClause); + return $count; +} + +#------------------------------------------------------------------- + =head2 getRoot () Returns the root asset object. @@ -2006,13 +2029,19 @@ sub paste { my $assetId = shift; my $pastedAsset = WebGUI::Asset->newByDynamicClass($assetId); if ($self->getId eq $pastedAsset->get("parentId") || $pastedAsset->setParent($self)) { - WebGUI::SQL->write("update asset set state='published', stateChangedBy=".quote($session{user}{userId})." where lineage like ".quote($self->get("lineage").'%')." and (state='clipboard' or state='clipboard-limbo')"); - $self->{_properties}{state} = "published"; + my $assetIds = WebGUI::SQL->buildArrayRef("select assetId from asset where lineage like ".quote($self->get("lineage").'%')." and (state='clipboard' or state='clipboard-limbo')"); + my $idList = quoteAndJoin($assetIds); + WebGUI::SQL->write("update asset set state='published', stateChangedBy=".quote($session{user}{userId}).", stateChanged=".time()." where assetId in (".$idList.")"); + my $sth = WebGUI::SQL->read("select assetId,revisionDate from assetData where assetId in (".$idList.")"); + while ( my ($id,$version) = $sth->array) { + # we do the purge directly cuz it's a lot faster than instanciating all these assets + WebGUI::Cache->new("asset_".$id."/".$version)->delete; + } + $sth->finish; $pastedAsset->updateHistory("pasted to parent ".$self->getId); return 1; } return 0; - $self->purgeCache; } #------------------------------------------------------------------- @@ -2139,9 +2168,16 @@ Sets an asset and it's descendants to a state of 'published' regardless of it's sub publish { my $self = shift; - WebGUI::SQL->write("update asset set state='published', stateChangedBy=".quote($session{user}{userId})." where lineage like ".quote($self->get("lineage").'%')); + my $assetIds = WebGUI::SQL->buildArrayRef("select assetId from asset where lineage like ".quote($self->get("lineage").'%')); + my $idList = quoteAndJoin($assetIds); + WebGUI::SQL->write("update asset set state='published', stateChangedBy=".quote($session{user}{userId}).", stateChanged=".time()." where assetId in (".$idList.")"); + my $sth = WebGUI::SQL->read("select assetId,revisionDate from assetData where assetId in (".$idList.")"); + while ( my ($id,$version) = $sth->array) { + # we do the purge directly cuz it's a lot faster than instanciating all these assets + WebGUI::Cache->new("asset_".$id."/".$version)->delete; + } + $sth->finish; $self->{_properties}{state} = "published"; - $self->purgeCache; } #------------------------------------------------------------------- @@ -2154,8 +2190,6 @@ Deletes an asset from tables and removes anything bound to that asset. sub purge { my $self = shift; - $self->purgeCache; - $self->updateHistory("purged"); WebGUI::SQL->beginTransaction; foreach my $definition (@{$self->definition}) { WebGUI::SQL->write("delete from ".$definition->{tableName}." where assetId=".quote($self->getId)); @@ -2164,9 +2198,34 @@ sub purge { WebGUI::SQL->write("delete from asset where assetId=".quote($self->getId)); WebGUI::SQL->commit; $self->purgeCache; + $self->updateHistory("purged"); $self = undef; } +#------------------------------------------------------------------- + +=head2 purgeRevision ( ) + +Deletes a revision of an asset. If it's the last revision, it purges the asset all together. + +=cut + +sub purgeRevision { + my $self = shift; + if ($self->getRevisionCount > 1) { + WebGUI::SQL->beginTransaction; + foreach my $definition (@{$self->definition}) { + WebGUI::SQL->write("delete from ".$definition->{tableName}." where assetId=".quote($self->getId)." and revisionDate=".quote($self->get("revisionDate"))); + } + WebGUI::SQL->commit; + $self->purgeCache; + $self->updateHistory("purged revision ".$self->get("revisionDate")); + } else { + $self->purge; + } +} + + #------------------------------------------------------------------- =head2 purgeTree ( ) @@ -2347,7 +2406,7 @@ sub trash { my $self = shift; WebGUI::SQL->beginTransaction; WebGUI::SQL->write("update asset set state='trash-limbo' where lineage like ".quote($self->get("lineage").'%')); - WebGUI::SQL->write("update asset set state='trash', stateChangedBy=".quote($session{user}{userId})." where assetId=".quote($self->getId)); + WebGUI::SQL->write("update asset set state='trash', stateChangedBy=".quote($session{user}{userId}).", stateChanged=".time()." where assetId=".quote($self->getId)); WebGUI::SQL->commit; $self->{_properties}{state} = "trash"; $self->updateHistory("trashed"); diff --git a/sbin/Hourly/DeleteExpiredClipboard.pm b/sbin/Hourly/DeleteExpiredClipboard.pm index e9547ec3a..127aa8649 100644 --- a/sbin/Hourly/DeleteExpiredClipboard.pm +++ b/sbin/Hourly/DeleteExpiredClipboard.pm @@ -13,7 +13,6 @@ package Hourly::DeleteExpiredClipboard; use strict; use WebGUI::Asset; -use WebGUI::DateTime; use WebGUI::Session; use WebGUI::SQL; @@ -21,9 +20,9 @@ use WebGUI::SQL; sub process { if ($session{config}{DeleteExpiredClipboard_offset} ne "") { my $expireDate = (time()-(86400*$session{config}{DeleteExpiredClipboard_offset})); - my $sth = WebGUI::SQL->read("select assetId,className from asset where state='clipboard' and lastUpdated <".$expireDate); + my $sth = WebGUI::SQL->read("select assetId,className from asset where state='clipboard' and stateChanged <".$expireDate); while (my ($id, $class) = $sth->array) { - my $asset = WebGUI::Asset->newByDynamicClass($id,$class); + my $asset = WebGUI::Asset->new($id,$class); $asset->trash; } $sth->finish; diff --git a/sbin/Hourly/DeleteExpiredRevisions.pm b/sbin/Hourly/DeleteExpiredRevisions.pm new file mode 100644 index 000000000..aed9bc49e --- /dev/null +++ b/sbin/Hourly/DeleteExpiredRevisions.pm @@ -0,0 +1,35 @@ +package Hourly::DeleteExpiredRevisions; + +#------------------------------------------------------------------- +# WebGUI is Copyright 2001-2005 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 +#------------------------------------------------------------------- + + +use strict; +use WebGUI::Asset; +use WebGUI::Session; +use WebGUI::SQL; + +#----------------------------------------- +sub process { + if ($session{config}{DeleteExpiredRevisions_offset} ne "") { + my $expireDate = (time()-(86400*$session{config}{DeleteExpiredRevisions_offset})); + my $sth = WebGUI::SQL->read("select assetData.assetId,asset.className,assetData.revisionDate from asset left join assetData on asset.assetId=assetData.assetId where assetData.revisionDate<".$expireDate." order by assetData.revisionDate asc"); + while (my ($id, $class, $version) = $sth->array) { + my $asset = WebGUI::Asset->new($id,$class,$version); + if ($asset->getRevisionCount("approved") > 1) { + $asset->purgeRevision; + } + } + $sth->finish; + } +} + +1; + diff --git a/sbin/Hourly/DeleteExpiredTrash.pm b/sbin/Hourly/DeleteExpiredTrash.pm index b1ad68656..e77e8160b 100644 --- a/sbin/Hourly/DeleteExpiredTrash.pm +++ b/sbin/Hourly/DeleteExpiredTrash.pm @@ -13,7 +13,6 @@ package Hourly::DeleteExpiredTrash; use strict; use WebGUI::Asset; -use WebGUI::DateTime; use WebGUI::Session; use WebGUI::SQL; @@ -21,9 +20,9 @@ use WebGUI::SQL; sub process { if ($session{config}{DeleteExpiredTrash_offset} ne "") { my $expireDate = (time()-(86400*$session{config}{DeleteExpiredTrash_offset})); - my $sth = WebGUI::SQL->read("select assetId,className from asset where state='trash' and lastUpdated <".$expireDate); + my $sth = WebGUI::SQL->read("select assetId,className from asset where state='trash' and stateChanged <".$expireDate); while (my ($id, $class) = $sth->array) { - my $asset = WebGUI::Asset->newByDynamicClass($id,$class); + my $asset = WebGUI::Asset->new($id,$class); $asset->purge; } $sth->finish; diff --git a/sbin/Hourly/TrashExpiredContent.pm b/sbin/Hourly/TrashExpiredContent.pm index 2cd833856..4d370f0da 100644 --- a/sbin/Hourly/TrashExpiredContent.pm +++ b/sbin/Hourly/TrashExpiredContent.pm @@ -21,9 +21,10 @@ sub process { my $offset = $session{config}{TrashExpiredContent_offset}; if ($offset ne "") { my $epoch = time()-(86400*$offset); - my $sth = WebGUI::SQL->read("select assetId,className from asset where endDate<".$epoch); - while (my ($assetId, $class) = $sth->array) { - my $asset = WebGUI::Asset->newByDynamicClass($assetId,$class); + my $sth = WebGUI::SQL->read("select asset.assetId,asset.className,max(assetData.revisionDate) from asset left join assetData on + asset.assetId=assetData.assetId where assetData.endDate<".$epoch." and assetData.status<>'pending' group by asset.assetData"); + while (my ($assetId, $class, $version) = $sth->array) { + my $asset = WebGUI::Asset->new($assetId,$class,$version); $asset->trash; } $sth->finish;