migrate to getLineageIterator to save memory

This commit is contained in:
Doug Bell 2010-06-01 16:22:42 -05:00
parent cc87552a22
commit 2c75ab27e6
34 changed files with 794 additions and 187 deletions

View file

@ -579,8 +579,7 @@ sub getEventNext {
'assetData.assetId',
);
my $events = $self->getLineage(['siblings'], {
#returnObjects => 1,
my $events = $self->getLineageIterator(['siblings'], {
includeOnlyClasses => ['WebGUI::Asset::Event'],
joinClass => 'WebGUI::Asset::Event',
orderByClause => join(",", @orderByColumns),
@ -588,9 +587,12 @@ sub getEventNext {
limit => 1,
});
return undef unless $events->[0];
return WebGUI::Asset->newByDynamicClass($self->session,$events->[0]);
my $nextEvent;
eval { $nextEvent = $events->() };
if ( WebGUI::Error->caught('WebGUI::Error::ObjecNotFound') ) {
return undef; # Normal error
}
return $nextEvent;
}
@ -636,8 +638,7 @@ sub getEventPrev {
'assetData.assetId DESC',
);
my $events = $self->getLineage(['siblings'], {
#returnObjects => 1,
my $events = $self->getLineageIterator(['siblings'], {
includeOnlyClasses => ['WebGUI::Asset::Event'],
joinClass => 'WebGUI::Asset::Event',
orderByClause => join(",",@orderByColumns),
@ -645,8 +646,12 @@ sub getEventPrev {
limit => 1,
});
return undef unless $events->[0];
return WebGUI::Asset->newByDynamicClass($self->session,$events->[0]);
my $prevEvent;
eval { $prevEvent = $events->() };
if ( WebGUI::Error->caught( 'WebGUI::Error::ObjectNotFound' ) ) {
return undef; # Normal error
}
return $prevEvent;
}
@ -1483,35 +1488,46 @@ sub processPropertiesFromFormPost {
# Delete old events
if ($old_id) {
my $events = $self->getLineage(["siblings"], {
returnObjects => 1,
my $events = $self->getLineageIterator(["siblings"], {
includeOnlyClasses => ['WebGUI::Asset::Event'],
joinClass => 'WebGUI::Asset::Event',
whereClause => qq{Event.recurId = "$old_id"},
});
$_->purge for @$events;
while ( 1 ) {
my $event;
eval { $event = $events->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error(sprintf "Couldn't instance event asset %s to delete it", $x->id);
next;
}
last unless $event;
$event->purge;
}
}
}
else {
# TODO: Give users a form property to decide what events to update
# TODO: Make a workflow activity to do this, so that updating
# 1 million events doesn't kill the server.
# TODO: Make this use WebGUI::ProgressBar so 1 million events doesn't kill the server.
# Just update related events
my %properties = %{ $self->get };
delete $properties{startDate};
delete $properties{endDate};
delete $properties{url}; # addRevision will create a new url for us
my $events = $self->getLineage(["siblings"], {
#returnObjects => 1,
my $events = $self->getLineageIterator(["siblings"], {
includeOnlyClasses => ['WebGUI::Asset::Event'],
joinClass => 'WebGUI::Asset::Event',
whereClause => q{Event.recurId = "}.$self->get("recurId").q{"},
});
for my $eventId (@{$events}) {
my $event = WebGUI::Asset->newByDynamicClass($session, $eventId);
while ( 1 ) {
my $event;
eval { $event = $events->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error(sprintf "Couldn't instance event asset %s to update it", $x->id);
next;
}
last unless $event;
# Add a revision
$properties{ startDate } = $event->get("startDate");
$properties{ endDate } = $event->get("endDate");

View file

@ -59,14 +59,12 @@ sub _fixReplyCount {
my $self = shift;
my $asset = shift;
my $lastPost = $asset->getLineage( [ qw{ self descendants } ], {
returnObjects => 1,
my $lastPostId = $asset->getLineage( [ qw{ self descendants } ], {
isa => 'WebGUI::Asset::Post',
orderByClause => 'assetData.revisionDate desc',
limit => 1,
} )->[0];
if ($lastPost) {
if (my $lastPost = WebGUI::Asset->newByDynamicClass( $self->session, $lastPostId ) ) {
$asset->incrementReplies( $lastPost->get( 'revisionDate' ), $lastPost->getId );
}
else {
@ -1024,10 +1022,7 @@ sub paste {
$self->next::method(@_);
# First, figure out what Thread we're under
my $thread = $self->getLineage( [ qw{ self ancestors } ], {
returnObjects => 1,
isa => 'WebGUI::Asset::Post::Thread',
} )->[0];
my $thread = $self->getThread;
# If the pasted asset is not a thread we'll have to update the threadId of it and all posts below it.
if ( $self->get('threadId') ne $self->getId ) {

View file

@ -492,7 +492,7 @@ Returns a list of the post objects in this thread, including the thread post its
sub getPosts {
my $self = shift;
$self->getLineage(["self","descendants"], {
return $self->getLineage(["self","descendants"], {
returnObjects => 1,
includeArchived => 1,
includeOnlyClasses => ["WebGUI::Asset::Post","WebGUI::Asset::Post::Thread"],

View file

@ -356,7 +356,15 @@ sub getThingOptions {
tie my %options, 'Tie::IxHash', ( "" => "" );
my $thingyIter = WebGUI::Asset->getRoot($session)
->getLineageIterator( ['descendants'], { includeOnlyClasses => ['WebGUI::Asset::Wobject::Thingy'], } );
while ( my $thingy = $thingyIter->() ) {
while ( 1 ) {
my $thingy;
eval { $thingy = $thingyIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $thingy;
tie my %things, 'Tie::IxHash', (
$session->db->buildHash( "SELECT thingId, label FROM Thingy_things WHERE assetId=?", [ $thingy->getId ] ) );
$options{ $thingy->get('title') } = \%things;

View file

@ -27,13 +27,13 @@ use base qw(WebGUI::AssetAspect::RssFeed WebGUI::Asset::Wobject);
#-------------------------------------------------------------------
sub _computePostCount {
my $self = shift;
return scalar @{$self->getLineage(['descendants'], {includeOnlyClasses => ['WebGUI::Asset::Post']})};
return $self->getDescendantCount({includeOnlyClasses => ['WebGUI::Asset::Post']});
}
#-------------------------------------------------------------------
sub _computeThreadCount {
my $self = shift;
return scalar @{$self->getLineage(['children'], {includeOnlyClasses => ['WebGUI::Asset::Post::Thread']})};
return $self->getChildCount({includeOnlyClasses => ['WebGUI::Asset::Post::Thread']});
}
#-------------------------------------------------------------------
@ -1387,11 +1387,19 @@ sub processPropertiesFromFormPost {
$self->createSubscriptionGroup;
}
if ($updatePrivs) {
foreach my $descendant (@{$self->getLineage(["descendants"],{returnObjects=>1})}) {
$descendant->update({
groupIdView=>$self->get("groupIdView"),
groupIdEdit=>$self->get("groupIdEdit")
});
my $descendantIter = $self->getLineageIterator(['descendants']);
while ( 1 ) {
my $descendant;
eval { $descendant = $descendantIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $descendant;
$descendant->update({
groupIdView=>$self->get("groupIdView"),
groupIdEdit=>$self->get("groupIdEdit")
});
}
}
$self->session->scratch->delete($self->getId."_sortBy");
@ -1686,16 +1694,21 @@ sub www_unarchiveAll {
my $pb = WebGUI::ProgressBar->new($session);
my $i18n = WebGUI::International->new($session, 'Asset_Collaboration');
$pb->start($i18n->get('unarchive all'), $self->getUrl('func=edit'));
my $threadIds = $self->getLineage(['children'],{
my $threadIter = $self->getLineageIterator(['children'],{
includeOnlyClasses => [ 'WebGUI::Asset::Post::Thread' ],
statusToInclude => [ 'archived' ],
} );
ASSET: foreach my $threadId (@$threadIds) {
my $thread = WebGUI::Asset->newPending($session, $threadId);
if (!$thread || !$thread->canEdit) {
next ASSET;
ASSET: while ( 1 ) {
my $thread;
eval { $thread = $threadIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $thread;
if ($thread->canEdit) {
$thread->unarchive;
}
$thread->unarchive;
}
return $pb->finish( $self->getUrl('func=edit') );
}

View file

@ -189,9 +189,16 @@ sub getEditForm {
my $i18n = WebGUI::International->new($self->session, "Asset_Dashboard");
if ($self->session->form->process("func") ne "add") {
my @assetsToHide = split("\n",$self->getValue("assetsToHide"));
my $children = $self->getLineage(["children"],{"returnObjects"=>1, excludeClasses=>["WebGUI::Asset::Wobject::Layout"]});
my $childIter = $self->getLineageIterator(["children"],{excludeClasses=>["WebGUI::Asset::Wobject::Layout"]});
my %childIds;
foreach my $child (@{$children}) {
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
$childIds{$child->getId} = $child->getTitle.' ['.ref($child).']';
}
$tabform->getTab("display")->checkList(
@ -255,9 +262,16 @@ their templates.
sub prepareView {
my $self = shift;
$self->SUPER::prepareView;
my $children = $self->getLineage( ["children"], { returnObjects=>1, excludeClasses=>["WebGUI::Asset::Wobject::Layout","WebGUI::Asset::Wobject::Dashboard"] });
my @hidden = split("\n",$self->get("assetsToHide"));
foreach my $child (@{$children}) {
my $childIter = $self->getLineageIterator( ["children"], {excludeClasses=>["WebGUI::Asset::Wobject::Layout","WebGUI::Asset::Wobject::Dashboard"] });
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
unless (isIn($child->getId, @hidden) || !($child->canView)) {
$self->session->style->setRawHeadTags($child->getExtraHeadTags);
$child->prepareView;
@ -323,8 +337,9 @@ sub view {
);
my $templateId = $self->get("templateId");
my $children = $self->getLineage( ["children"], { returnObjects=>1, excludeClasses=>["WebGUI::Asset::Wobject::Layout","WebGUI::Asset::Wobject::Dashboard"] });
# XXX Not using getLineageIterator because we loop over the children three times...
# I'm sure there's a more efficient way to do this. We'll figure it out someday.
my $children = $self->getLineage( ["children"], { returnObjects=>1, excludeClasses=>["WebGUI::Asset::Wobject::Layout","WebGUI::Asset::Wobject::Dashboard"] });
my @positions = split(/\./,$self->getContentPositions);
my @hidden = split("\n",$self->get("assetsToHide"));
foreach my $child (@{$children}) {

View file

@ -607,10 +607,10 @@ returns true if the EMS has subission forms attached
sub hasSubmissionForms {
my $self = shift;
# are there ~any~ forms attached to this ems?
my $res = $self->getLineage(['children'],{ limit => 1,
my $count = $self->getDescendantCount({
includeOnlyClasses => ['WebGUI::Asset::EMSSubmissionForm'],
} );
return scalar(@$res);
return $count;
}
#-------------------------------------------------------------------
@ -1038,12 +1038,12 @@ then call www_editSubmission on it
sub www_editSubmission {
my $self = shift;
my $submissionId = $self->session->form->get('submissionId');
my $asset = $self->getLineage(['descendants'], { returnObjects => 1,
my $asset = $self->getLineageIterator(['descendants'], {
joinClass => "WebGUI::Asset::EMSSubmission",
whereClause => 'submissionId = ' . int($submissionId),
includeOnlyClasses => ['WebGUI::Asset::EMSSubmission'],
} );
return $asset->[0]->www_editSubmission;
return $asset->()->www_editSubmission;
}
@ -1389,6 +1389,7 @@ sub www_getBadgesAsJson {
my ($db, $form) = $session->quick(qw(db form));
my %results = ();
$results{records} = [];
# TODO: Use getLineageIterator here instead
BADGE: foreach my $badge (@{$self->getBadges}) {
next BADGE unless $badge->canView;
push(@{$results{records}}, {

View file

@ -122,7 +122,15 @@ Overridden to check the revision dates of children as well
sub getContentLastModified {
my $self = shift;
my $mtime = $self->get("revisionDate");
foreach my $child (@{ $self->getLineage(["children"],{returnObjects=>1}) }) {
my $childIter = $self->getLineageIterator(["children"]);
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
my $child_mtime = $child->getContentLastModified;
$mtime = $child_mtime if ($child_mtime > $mtime);
}
@ -233,7 +241,7 @@ sub view {
my $vars = $self->getTemplateVars;
# TODO: Getting the children template vars should be a seperate method.
my %rules = ( returnObjects => 1);
my %rules = ( );
if ( $self->get( "sortAlphabetically" ) ) {
$rules{ orderByClause } = "assetData.title " . $self->get( "sortOrder" );
}
@ -241,9 +249,16 @@ sub view {
$rules{ orderByClause } = "asset.lineage " . $self->get( "sortOrder" );
}
my $children = $self->getLineage( ["children"], \%rules);
foreach my $child ( @{ $children } ) {
# TODO: Instead of this it should be using $child->getTemplateVars || $child->get
my $childIter = $self->getLineageIterator( ["children"], \%rules);
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
# TODO: Instead of this it should be using $child->getTemplateVars || $child->get
if ( $child->isa("WebGUI::Asset::Wobject::Folder") ) {
push @{ $vars->{ "subfolder_loop" } }, {
id => $child->getId,

View file

@ -927,17 +927,21 @@ sub hasSpaceAvailable {
# Compile the amount of disk space used
my $maxSpace = $self->get( "maxSpacePerUser" ) * ( 1_024 ** 2 ); # maxSpacePerUser is in MB
my $spaceUsed = 0;
my $fileIds
= $self->getLineage( [ 'descendants' ], {
my $fileIter
= $self->getLineageIterator( [ 'descendants' ], {
joinClass => 'WebGUI::Asset::File::GalleryFile',
whereClause => 'ownerUserId = ' . $db->quote( $userId ),
} );
for my $assetId ( @{ $fileIds } ) {
my $asset = WebGUI::Asset->newByDynamicClass( $self->session, $assetId );
next unless $asset;
$spaceUsed += $asset->get( 'assetSize' );
while ( 1 ) {
my $file;
eval { $file = $fileIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $file;
$spaceUsed += $file->get( 'assetSize' );
return 0 if ( $spaceUsed + $spaceWanted >= $maxSpace );
}

View file

@ -180,9 +180,16 @@ sub getEditForm {
}
else {
my @assetsToHide = split("\n",$self->getValue("assetsToHide"));
my $children = $self->getLineage(["children"],{"returnObjects"=>1, excludeClasses=>["WebGUI::Asset::Wobject::Layout"]});
my $childIter = $self->getLineageIterator(["children"],{excludeClasses=>["WebGUI::Asset::Wobject::Layout"]});
my %childIds;
foreach my $child (@{$children}) {
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
$childIds{$child->getId} = $child->getTitle;
}
$extraFields{assetsToHide} = {
@ -256,11 +263,18 @@ sub prepareView {
my %placeHolder;
my @children;
for my $child ( @{ $self->getLineage( ["children"], {
returnObjects => 1,
my $childIter = $self->getLineageIterator( ["children"], {
excludeClasses => ["WebGUI::Asset::Wobject::Layout"],
} ) } ) {
} );
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
my $assetId = $child->getId;
next
if ($hidden{$assetId} || ! $child->canView);
@ -412,7 +426,15 @@ sub getContentLastModified {
# Buggo: this is a little too conservative. Children that are hidden maybe shouldn't count. Hm.
my $self = shift;
my $mtime = $self->SUPER::getContentLastModified;
foreach my $child (@{$self->getLineage(["children"],{returnObjects=>1, excludeClasses=>['WebGUI::Asset::Wobject::Layout']})}) {
my $childIter = $self->getLineageIterator(["children"],{excludeClasses=>['WebGUI::Asset::Wobject::Layout']});
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
my $child_mtime = $child->getContentLastModified;
$mtime = $child_mtime if ($child_mtime > $mtime);
}

View file

@ -315,11 +315,17 @@ sub deleteAttribute {
[$attributeId,$self->getId]);
# recalculate scores for MatrixListings
my @listings = @{ $self->getLineage(['descendants'], {
my $listingIter = $self->getLineageIterator(['descendants'], {
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
returnObjects => 1,
}) };
foreach my $listing (@listings){
});
while ( 1 ) {
my $listing;
eval { $listing = $listingIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $listing;
$listing->updateScore;
}
@ -661,17 +667,23 @@ sub view {
if ($self->canEdit){
# Get all the MatrixListings that are still pending.
my @pendingListings = @{ $self->getLineage(['descendants'], {
my $pendingIter = $self->getLineageIterator(['descendants'], {
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
orderByClause => "revisionDate asc",
returnObjects => 1,
statusToInclude => ['pending'],
}) };
foreach my $pendingListing (@pendingListings){
});
while ( 1 ) {
my $pending;
eval { $pending = $pendingIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $pending;
push (@{ $var->{pending_loop} }, {
url => $pendingListing->getUrl
."?func=view;revision=".$pendingListing->get('revisionDate'),
name => $pendingListing->get('title'),
url => $pending->getUrl
."?func=view;revision=".$pending->get('revisionDate'),
name => $pending->get('title'),
});
}
}
@ -747,18 +759,23 @@ sub view {
# Get the 5 MatrixListings that were last updated as objects using getLineage.
my @lastUpdatedListings = @{ $self->getLineage(['descendants'], {
my $lastUpdatedIter = $self->getLineageIterator(['descendants'], {
includeOnlyClasses => ['WebGUI::Asset::MatrixListing'],
joinClass => "WebGUI::Asset::MatrixListing",
orderByClause => "lastUpdated desc",
limit => 5,
returnObjects => 1,
}) };
foreach my $lastUpdatedListing (@lastUpdatedListings){
});
for ( 1..5 ) {
my $lastUpdated;
eval { $lastUpdated = $lastUpdatedIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $lastUpdated;
push (@{ $varStatistics->{last_updated_loop} }, {
url => $lastUpdatedListing->getUrl,
name => $lastUpdatedListing->get('title'),
lastUpdated => $session->datetime->epochToHuman($lastUpdatedListing->get('lastUpdated'),"%z")
url => $lastUpdated->getUrl,
name => $lastUpdated->get('title'),
lastUpdated => $session->datetime->epochToHuman($lastUpdated->get('lastUpdated'),"%z")
});
}
$varStatistics->{lastUpdated_sortButton} = "<span id='sortByUpdated'><button type='button'>"

View file

@ -114,8 +114,15 @@ sub view {
my $first;
my @forum_loop;
my $i18n = WebGUI::International->new($self->session,"Asset_MessageBoard");
my $children = $self->getLineage(["children"],{includeOnlyClasses=>["WebGUI::Asset::Wobject::Collaboration"],returnObjects=>1});
foreach my $child (@{$children}) {
my $childIter = $self->getLineageIterator(["children"],{includeOnlyClasses=>["WebGUI::Asset::Wobject::Collaboration"]});
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
$count++;
next unless ($child->canView);
if ($count == 1) {

View file

@ -372,13 +372,28 @@ sub view {
# we've got to determine what our start point is based upon user conditions
my $start;
$self->session->asset(WebGUI::Asset->newByUrl($self->session)) unless ($self->session->asset);
my $current = $self->session->asset;
my $var = {'page_loop' => []};
my $current = $self->session->asset;
# no current asset is set
unless (defined $current) {
$current = WebGUI::Asset->getDefault($self->session);
}
# Add properties from current asset
foreach my $property (@interestingProperties) {
$var->{'currentPage.'.$property} = $current->get($property);
}
$var->{'currentPage.menuTitle'} = $current->getMenuTitle;
$var->{'currentPage.title'} = $current->getTitle;
$var->{'currentPage.isHome'} = ($current->getId eq $self->session->setting->get("defaultPage"));
$var->{'currentPage.url'} = $current->getUrl;
$var->{'currentPage.hasChild'} = $current->hasChildren;
$var->{'currentPage.rank'} = $current->getRank;
$var->{'currentPage.rankIs'.$current->getRank} = 1;
# Build the asset tree
if ($self->get("startType") eq "specificUrl") {
$start = WebGUI::Asset->newByUrl($self->session,$self->get("startPoint"));
} elsif ($self->get("startType") eq "relativeToRoot") {
@ -392,24 +407,12 @@ sub view {
my @includedRelationships = split("\n",$self->get("assetsToInclude"));
my %rules;
$rules{returnObjects} = 1;
$rules{endingLineageLength} = $start->getLineageLength+$self->get("descendantEndPoint");
$rules{assetToPedigree} = $current if (isIn("pedigree",@includedRelationships));
$rules{ancestorLimit} = $self->get("ancestorEndPoint");
$rules{orderByClause} = 'rpad(asset.lineage, 255, 9) desc' if ($self->get('reversePageLoop'));
my @interestingProperties = ('assetId', 'parentId', 'ownerUserId', 'synopsis', 'newWindow');
my $assets = $start->getLineage(\@includedRelationships,\%rules);
my $var = {'page_loop' => []};
foreach my $property (@interestingProperties) {
$var->{'currentPage.'.$property} = $current->get($property);
}
$var->{'currentPage.menuTitle'} = $current->getMenuTitle;
$var->{'currentPage.title'} = $current->getTitle;
$var->{'currentPage.isHome'} = ($current->getId eq $self->session->setting->get("defaultPage"));
$var->{'currentPage.url'} = $current->getUrl;
$var->{'currentPage.hasChild'} = $current->hasChildren;
$var->{'currentPage.rank'} = $current->getRank;
$var->{'currentPage.rankIs'.$current->getRank} = 1;
my $currentLineage = $current->get("lineage");
my $lineageToSkip = "noskip";
my $absoluteDepthOfLastPage;
@ -417,8 +420,7 @@ sub view {
my %lastChildren;
my $previousPageData = undef;
my $eh = $self->session->errorHandler;
foreach my $asset (@{$assets}) {
while ( my $asset = $assets->() ) {
# skip pages we shouldn't see
my $pageLineage = $asset->get("lineage");
next if ($pageLineage =~ m/^$lineageToSkip/);

View file

@ -288,7 +288,15 @@ sub view {
# get other shelves
my @childShelves = ();
SHELF: foreach my $child (@{$self->getLineage(['children'],{returnObjects=>1,includeOnlyClasses=>['WebGUI::Asset::Wobject::Shelf']})}) {
my $childIter = $self->getLineageIterator(['children'],{includeOnlyClasses=>['WebGUI::Asset::Wobject::Shelf']});
SHELF: while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
next SHELF unless $child->canView;
my $properties = $child->get;
$properties->{url} = $child->getUrl;

View file

@ -400,14 +400,21 @@ for generating an RSS and Atom feeds.
sub getRssFeedItems {
my $self = shift;
my $stories = $self->getLineageIterator(['descendants'],{
my $storyIter = $self->getLineageIterator(['descendants'],{
excludeClasses => ['WebGUI::Asset::Wobject::Folder'],
orderByClause => 'creationDate desc, lineage',
returnObjects => 1,
limit => $self->get('itemsPerFeed'),
});
my $storyData = [];
while (my $story = $stories->()) {
while ( 1 ) {
my $story;
eval { $story = $storyIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $story;
push @{ $storyData }, $story->getRssData;
}
return $storyData;

View file

@ -79,15 +79,19 @@ sub appendMostPopular {
my $self = shift;
my $var = shift;
my $limit = shift || $self->get("mostPopularCount");
foreach my $asset (@{$self->getLineage(["children"],{returnObjects=>1, limit=>$limit, includeOnlyClasses=>["WebGUI::Asset::WikiPage"], joinClass => 'WebGUI::Asset::WikiPage', orderByClause => 'WikiPage.views DESC'})}) {
if (defined $asset) {
my $assetIter = $self->getLineageIterator(["children"],{limit=>$limit, includeOnlyClasses=>["WebGUI::Asset::WikiPage"], joinClass => 'WebGUI::Asset::WikiPage', orderByClause => 'WikiPage.views DESC'});
while ( 1 ) {
my $asset;
eval { $asset = $assetIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $asset;
push(@{$var->{mostPopular}}, {
title=>$asset->getTitle,
url=>$asset->getUrl,
});
} else {
$self->session->errorHandler->error("Couldn't instanciate wikipage for master ".$self->getId);
}
}
}
@ -734,7 +738,16 @@ sub processPropertiesFromFormPost {
or ($self->session->form->process('groupIdEdit') ne $self->get('groupIdEdit')));
my $ret = $self->next::method(@_);
if ($groupsChanged) {
foreach my $child (@{$self->getLineage(['children'], {returnObjects => 1})}) {
# XXX Should this do descendants for WikiPage attachments?
my $childIter = $self->getLineageIterator(['children']);
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
$child->update({ groupIdView => $self->get('groupIdView'),
groupIdEdit => $self->get('groupIdEdit') });
}

View file

@ -53,10 +53,19 @@ sub duplicateBranch {
my $childrenOnly = shift;
my $newAsset = $self->duplicate({skipAutoCommitWorkflows=>1,skipNotification=>1});
# Correctly handle positions for Layout assets
my $contentPositions = $self->get("contentPositions");
my $assetsToHide = $self->get("assetsToHide");
foreach my $child (@{$self->getLineage(["children"],{returnObjects=>1})}) {
my $childIter = $self->getLineageIterator(["children"]);
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
my $newChild = $childrenOnly ? $child->duplicate({skipAutoCommitWorkflows=>1, skipNotification=>1}) : $child->duplicateBranch;
$newChild->setParent($newAsset);
my ($oldChildId, $newChildId) = ($child->getId, $newChild->getId);
@ -355,11 +364,18 @@ sub www_editBranchSave {
$urlBase = $form->text("baseUrl");
$endOfUrl = $form->selectBox("endOfUrl");
}
my $descendants = $self->getLineage(["self","descendants"],{returnObjects=>1});
DESCENDANT: foreach my $descendant (@{$descendants}) {
my $descendantIter = $self->getLineageIterator(["self","descendants"]);
while ( 1 ) {
my $descendant;
eval { $descendant = $descendantIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $descendant;
if ( !$descendant->canEdit ) {
$pb->update(sprintf $i18n->get('skipping %s'), $descendant->getTitle);
next DESCENDANT;
next;
}
$pb->update(sprintf $i18n->get('editing %s'), $descendant->getTitle);
my $url;

View file

@ -67,7 +67,15 @@ sub cut {
$session->db->write("update asset set state='clipboard', stateChangedBy=?, stateChanged=? where assetId=?", [$session->user->userId, time(), $self->getId]);
$session->db->commit;
$self->{_properties}{state} = "clipboard";
foreach my $asset ($self, @{$self->getLineage(['descendants'], {returnObjects => 1})}) {
my $assetIter = $self->getLineageIterator(['descendants']);
while ( 1 ) {
my $asset;
eval { $asset = $assetIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $asset;
$asset->purgeCache;
$asset->updateHistory('cut');
}
@ -212,11 +220,18 @@ sub paste {
$pastedAsset->updateHistory("pasted to parent ".$self->getId);
# Update lineage in search index.
my $updateAssets = $pastedAsset->getLineage(['self', 'descendants'], {returnObjects => 1});
my $assetIter = $pastedAsset->getLineageIterator(['self', 'descendants']);
while ( 1 ) {
my $asset;
eval { $asset = $assetIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $asset;
foreach (@{$updateAssets}) {
$outputSub->(sprintf $i18n->get('indexing %s'), $pastedAsset->getTitle) if defined $outputSub;
$_->indexContent();
$asset->indexContent();
}
return 1;

View file

@ -451,13 +451,23 @@ boolean indicating whether or not this asset is exportable.
sub exportCheckExportable {
my $self = shift;
# We have ourself already, check it first
return 0 unless $asset->get('isExportable');
# get this asset's ancestors. return objects as a shortcut since we'd be
# instantiating them all anyway.
my $assets = $self->getLineage( ['ancestors'], { returnObjects => 1 } );
my $assetIter = $self->getLineageIterator( ['self','ancestors'] );
# process each one. return false if any of the assets in the lineage, or
# this asset itself, isn't exportable.
foreach my $asset ( @{$assets}, $self ) {
while ( 1 ) {
my $asset;
eval { $asset = $assetIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $asset;
return 0 unless $asset->get('isExportable');
}

View file

@ -215,35 +215,91 @@ Returns the number of children this asset has. This excludes assets in the trash
=head3 opts
A hashref of options. Currently only one option is supported.
A hashref of options.
=head4 includeTrash
If this value of this hash key is true, then assets in any state will be counted. Normally,
only those that are published or achived are counted.
=head4 includeOnlyClasses
Only count these classes. Arrayref of class names
=cut
sub getChildCount {
my $self = shift;
my $opts = shift || {};
my $stateWhere = $opts->{includeTrash} ? '' : "asset.state='published' and";
my ($count) = $self->session->db->quickArray("select count(distinct asset.assetId) from asset, assetData where asset.assetId=assetData.assetId and $stateWhere parentId=? and (assetData.status in ('approved', 'archived') or assetData.tagId=?)", [$self->getId, $self->session->scratch->get('versionTag')]);
my $sql = "select count(distinct asset.assetId)
from asset, assetData
where asset.assetId=assetData.assetId
and parentId=?
and (assetData.status in ('approved', 'archived') or assetData.tagId=?)";
my @params = ( $self->getId, $self->session->scratch->get('versionTag') );
if ( !$opt->{ includeTrash } ) {
$sql .= ' AND asset.state=?';
push @params, "published";
}
# XXX This code is duplicated in getLineageSql and getDescendantCount. Merge the three ways?
if ( $opt->{ includeOnlyClasses } ) {
my @classes;
if ( !ref $opt->{includeOnlyClasses} eq 'ARRAY' ) {
@classes = $opt->{includeOnlyClasses};
}
else {
@classes = @{ $opt->{includeOnlyClasses} };
}
$sql .= "AND className IN (" . join( ',', ("?") x @classes ) . ")";
push @params, @classes;
}
my ($count) = $self->session->db->quickArray($sql, \@params);
return $count;
}
#-------------------------------------------------------------------
=head2 getDescendantCount ( )
=head2 getDescendantCount ( opts )
Returns the number of descendants this asset has. This includes only assets that are published, and not
in the clipboard or trash.
=head3 opts
=head4 includeOnlyClasses
Only count these classes. Arrayref of class names
=cut
sub getDescendantCount {
my $self = shift;
my ($count) = $self->session->db->quickArray("select count(distinct asset.assetId) from asset, assetData where asset.assetId=assetData.assetId and asset.state = 'published' and assetData.status in ('approved','archived') and asset.lineage like ?", [$self->get("lineage")."%"]);
my $opt = shift || {};
my $sql = "select count(distinct asset.assetId)
from asset, assetData
where asset.assetId = assetData.assetId
and asset.state = 'published'
and assetData.status in ('approved','archived')
and asset.lineage like ? ";
my @params = ( $self->get("lineage")."%" );
# XXX This code is duplicated in getLineageSql and getChildCount. Merge the three ways?
if ( $opt->{includeOnlyClasses} ) {
my @classes;
if ( !ref $opt->{includeOnlyClasses} eq 'ARRAY' ) {
@classes = $opt->{includeOnlyClasses};
}
else {
@classes = @{ $opt->{includeOnlyClasses} };
}
$sql .= "AND className IN (" . join( ',', ("?") x @classes ) . ")";
push @params, @classes;
}
my ($count) = $self->session->db->quickArray($sql, \@params);
$count--; # have to subtract self
return $count;
}
@ -923,14 +979,21 @@ sub setRank {
my $parentLineage = $self->getParentLineage;
my $reverse = ($newRank < $currentRank) ? 1 : 0;
my $siblings = $self->getLineage(["siblings"],{returnObjects=>1, invertTree=>$reverse});
my $temp = substr($self->session->id->generate(),0,6);
my $previous = $self->get("lineage");
$self->session->db->beginTransaction;
$outputSub->('moving %s aside', $self->getTitle);
$self->cascadeLineage($temp);
foreach my $sibling (@{$siblings}) {
my $siblingIter = $self->getLineageIterator(["siblings"],{invertTree=>$reverse});
while ( 1 ) {
my $sibling;
eval { $sibling = $siblingIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $sibling;
if (isBetween($sibling->getRank, $newRank, $currentRank)) {
$outputSub->('moving %s', $sibling->getTitle);
$sibling->cascadeLineage($previous);

View file

@ -63,7 +63,8 @@ Turns this package into a package file and returns the storage location object o
sub exportPackage {
my $self = shift;
my $storage = WebGUI::Storage->createTemp($self->session);
foreach my $asset (@{$self->getLineage(["self","descendants"],{returnObjects=>1, statusToInclude=>['approved', 'archived']})}) {
my $assets = $self->getLineage(["self","descendants"],{statusToInclude=>['approved', 'archived']})
while ( my $asset = $assets->() ) {
my $data = $asset->exportAssetData;
$storage->addFileFromScalar($data->{properties}{lineage}.".json", JSON->new->utf8->pretty->encode($data));
foreach my $storageId (@{$data->{storage}}) {

View file

@ -141,24 +141,23 @@ sub purge {
}
# assassinate the offspring
my $kids = $self->getLineage(["children"],{
returnObjects => 1,
my $childIter = $self->getLineageIterator(["children"],{
statesToInclude => [qw(published clipboard clipboard-limbo trash trash-limbo)],
statusToInclude => [qw(approved archived pending)],
});
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) {
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
unless ($child->purge) {
$session->errorHandler->security("delete one of (".$self->getId.")'s children which is a system protected page");
$outputSub->(sprintf $i18n->get('Trying to delete system page %s. Aborting'), $self->getTitle);
return 0;
}
}
else {
$outputSub->($i18n->get('Undefined child'));
$session->errorHandler->error("getLineage returned an undefined object in the AssetTrash->purge method. Unable to purge asset.");
}
}
# Delete shortcuts to this asset
@ -266,7 +265,8 @@ sub trash {
return undef;
}
foreach my $asset ($self, @{$self->getLineage(['descendants'], {returnObjects => 1})}) {
my $assets = $self->getLineage(['self','descendants']);
while ( my $asset = $assets->() ) {
$outputSub->($i18n->get('Clearing search index'));
my $index = WebGUI::Search::Index->new($asset);
$index->delete;

View file

@ -383,13 +383,20 @@ ENDHTML
### Crumbtrail
my $crumb_markup = '<li><a href="%s">%s</a> &gt;</li>';
my $ancestors = $currentAsset->getLineage( ['ancestors'], { returnObjects => 1 } );
my $ancestorIter = $currentAsset->getLineageIterator( ['ancestors'] );
$output .= '<ol id="crumbtrail">';
for my $asset ( @{ $ancestors } ) {
while ( 1 ) {
my $ancestor;
eval { $ancestor = $ancestorIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $ancestor;
$output .= sprintf $crumb_markup,
$asset->getUrl( 'op=assetManager;method=manage' ),
$asset->get( "menuTitle" ),
$ancestor->getUrl( 'op=assetManager;method=manage' ),
$ancestor->get( "menuTitle" ),
;
}

View file

@ -61,7 +61,6 @@ sub handler {
}
my $pages = WebGUI::Asset->getRoot($session)->getLineageIterator(["self","descendants"],{
returnObjects => 1,
includeOnlyClasses => ["WebGUI::Asset::Wobject::Layout"],
whereClause => $whereClause,
limit => 20000

View file

@ -184,8 +184,15 @@ sub www_assetTree {
$session->http->setCacheControl("none");
my $base = WebGUI::Asset->newByUrl($session) || WebGUI::Asset->getRoot($session);
my @crumb;
my $ancestors = $base->getLineage(["self","ancestors"],{returnObjects=>1});
foreach my $ancestor (@{$ancestors}) {
my $ancestorIter = $base->getLineageIterator(["self","ancestors"]);
while ( 1 ) {
my $ancestor;
eval { $ancestor = $ancestorIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $ancestor;
my $url = $ancestor->getUrl("op=formHelper;sub=assetTree;class=Asset;formId=".$session->form->process("formId"));
$url .= ";classLimiter=".$session->form->process("classLimiter","className") if ($session->form->process("classLimiter","className"));
push(@crumb,'<a href="'.$url.'" class="crumb">'.$ancestor->get("menuTitle").'</a>');
@ -224,10 +231,17 @@ sub www_assetTree {
</style></head><body>
<div class="base">
<div class="crumbTrail">'.join(" &gt; ", @crumb)."</div><br />\n";
my $children = $base->getLineage(["children","self"],{returnObjects=>1});
my $childIter = $base->getLineageIterator(["children","self"]);
my $i18n = WebGUI::International->new($session);
my $limit = $session->form->process("classLimiter","className");
foreach my $child (@{$children}) {
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
next unless $child->canView;
if ($limit eq "" || $child->get("className") =~ /^$limit/) {
my $tempChild = $child->get("title");

View file

@ -208,13 +208,27 @@ JS
my $output = '<div class="nav">';
my $base = WebGUI::Asset->newByUrl($session) || WebGUI::Asset->getRoot($session);
my @crumb;
my $ancestors = $base->getLineage(["self","ancestors"],{returnObjects=>1});
foreach my $ancestor (@{$ancestors}) {
my $ancestorIter = $base->getLineageIterator(["self","ancestors"]);
while ( 1 ) {
my $ancestor;
eval { $ancestor = $ancestorIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $ancestor;
push(@crumb,'<a href="'.$ancestor->getUrl("op=formHelper;class=HTMLArea;sub=pageTree").'" class="crumb">'.$ancestor->get("menuTitle").'</a>');
}
$output .= '<div class="crumbTrail">'.join(" &gt; ", @crumb)."</div>\n<ul>";
my $children = $base->getLineage(["children"],{returnObjects=>1});
foreach my $child (@{$children}) {
my $childIter = $base->getLineageIterator(["children"]);
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
next unless $child->canView;
$output .= '<li><a href="#" class="selectLink" onclick="selectLink(\'' . $child->get('url') . '\'); return false;">['
. $i18n->get("select") . ']</a> <a href="' . $child->getUrl("op=formHelper;class=HTMLArea;sub=pageTree")
@ -253,8 +267,15 @@ JS
my @crumb;
my $media;
my $ancestors = $base->getLineage(["self","ancestors"],{returnObjects=>1});
foreach my $ancestor (@{$ancestors}) {
my $ancestorIter = $base->getLineageIterator(["self","ancestors"]);
while ( 1 ) {
my $ancestor;
eval { $ancestor = $ancestorIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $ancestor;
push(@crumb,'<a href="'.$ancestor->getUrl("op=formHelper;class=HTMLArea;sub=imageTree").'" class="crumb">'.$ancestor->get("menuTitle").'</a>');
if ($ancestor->get('assetId') eq 'PBasset000000000000003') {
$media = $ancestor;
@ -276,8 +297,8 @@ JS
$output .= '<div class="crumbTrail">'.join(" &gt; ", @crumb)."</div>\n<ul>";
my $useAssetUrls = $session->config->get("richEditorsUseAssetUrls");
my $children = $base->getLineage(["children"],{returnObjects=>1});
foreach my $child (@{$children}) {
my $children = $base->getLineage(["children"]);
while ( my $child = $children->() ) {
next unless $child->canView;
$output .= '<li>';
if ($child->isa('WebGUI::Asset::File::Image')) {

View file

@ -125,8 +125,18 @@ the available Rich Text Editor assets.
sub getOptions {
my $self = shift;
my $editors = WebGUI::Asset->getRoot($self->session)->getLineage(['descendants'], {includeOnlyClasses => ['WebGUI::Asset::RichEdit'], returnObjects => 1});
my %options = map { $_->getId => $_->getTitle } @$editors;
my $editorIter = WebGUI::Asset->getRoot($self->session)->getLineageIterator( ['descendants'], {includeOnlyClasses => ['WebGUI::Asset::RichEdit']});
my %options;
while ( 1 ) {
my $editor;
eval { $editor = $editorIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $editor;
$options{ $editor->getId } = $editor->getTitle;
}
return \%options;
}

View file

@ -256,10 +256,16 @@ sub www_chooseContentSave {
# update default site style
$session->setting->set( "userFunctionStyleId", $self->get('styleTemplateId') );
foreach my $asset ( @{ $home->getLineage( [ "self", "descendants" ], { returnObjects => 1 } ) } ) {
if ( defined $asset ) {
$asset->update( { styleTemplateId => $self->get("styleTemplateId") } );
my $assetIter = $home->getLineageIterator( [ "self", "descendants" ] );
while ( 1 ) {
my $asset;
eval { $asset = $assetIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $asset;
$asset->update( { styleTemplateId => $self->get("styleTemplateId") } );
}
# add new pages

View file

@ -363,7 +363,15 @@ sub www_defaultStyleSave {
# update default site style
$session->setting->set( "userFunctionStyleId", $self->get('styleTemplateId') );
my $home = WebGUI::Asset->getDefault( $session );
foreach my $asset ( @{ $home->getLineage( [ "self", "descendants" ], { returnObjects => 1 } ) } ) {
my $assetIter = $home->getLineageIterator( [ "self", "descendants" ] );
while ( 1 ) {
my $asset;
eval { $asset = $assetIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $asset;
if ( defined $asset ) {
$asset->update( { styleTemplateId => $self->get("styleTemplateId") } );
}

View file

@ -77,21 +77,30 @@ sub execute {
ARCHIVE: while (my $archive = $getAnArchive->()) {
next ARCHIVE unless $archive && $archive->get("archiveAfter");
my $archiveDate = $epoch - $archive->get("archiveAfter");
my $folders = $archive->getLineage(
my $folderIter = $archive->getLineageIterator(
['children'],
{
statusToInclude => ['approved'],
whereClause => 'creationDate < '.$session->db->quote($archiveDate),
returnObjects => 1,
},
);
FOLDER: foreach my $folder (@{ $folders }) {
next FOLDER unless $folder;
my $stories = $folder->getLineage(
['children'], { returnObjects => 1, },
);
STORY: foreach my $story (@{ $stories }) {
next STORY unless $story;
FOLDER: while ( 1 ) {
my $folder;
eval { $folder = $folderIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $folder;
my $storyIter = $folder->getLineageIterator( ['children'] );
STORY: while ( 1 ) {
my $story;
eval { $story = $storyIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $story;
$story->update({ status => 'archived' });
if (time() > $expireTime) {
return $self->WAITING(1);

View file

@ -107,14 +107,20 @@ sub execute {
# kill temporary assets
my $tempspace = WebGUI::Asset->getTempspace($self->session);
my $children = $tempspace->getLineage(["children"], {
returnObjects => 1,
my $childIter = $tempspace->getLineageIterator(["children"], {
statesToInclude => [qw(trash clipboard published)],
statusToInclude => [qw(pending archived approved)],
});
foreach my $asset (@{$children}) {
if (time() - $asset->get("revisionDate") > $self->get("storageTimeout")) {
unless ($asset->purge) {
while ( 1 ) {
my $child;
eval { $child = $childIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $child;
if (time() - $child->get("revisionDate") > $self->get("storageTimeout")) {
unless ($child->purge) {
return $self->ERROR;
}
}

View file

@ -78,11 +78,18 @@ sub execute {
my $limit = 2_500;
my $timeLimit = $self->getTTL;
my $list = $root->getLineage( ['descendants'], { returnObjects => 1,
my $emsFormIter = $root->getLineageIterator( ['descendants'], {
includeOnlyClasses => ['WebGUI::Asset::EMSSubmissionForm'],
} );
for my $emsForm ( @$list ) {
while ( 1 ) {
my $emsForm;
eval { $emsForm = $emsFormIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $emsForm;
my $daysBeforeCleanup = $emsForm->get('daysBeforeCleanup') ;
next if ! $daysBeforeCleanup;
my $whereClause = q{ submissionStatus='denied' };
@ -91,12 +98,19 @@ sub execute {
}
my $checkDate = time - ( 60*60*24* $daysBeforeCleanup );
$whereClause .= q{ and assetData.lastModified < } . $checkDate;
my $res = $emsForm->getLineage(['children'],{ returnObjects => 1,
my $submissionIter = $emsForm->getLineageIterator(['children'],{
joinClass => 'WebGUI::Asset::EMSSubmission',
includeOnlyClasses => ['WebGUI::Asset::EMSSubmission'],
whereClause => $whereClause,
} );
for my $submission ( @$res ) {
while ( 1 ) {
my $submission;
eval { $submission = $submissionIter->() };
if ( my $x = WebGUI::Error->caught('WebGUI::Error::ObjectNotFound') ) {
$session->log->error($x->full_message);
next;
}
last unless $submission;
$submission->purge;
$limit--;
return $self->WAITING(1) if ! $limit or time > $start + $timeLimit;

View file

@ -78,7 +78,7 @@ sub execute {
my $limit = 2_500;
my $timeLimit = 60;
my $list = $root->getLineage( ['descendants'], { returnObjects => 1,
my $list = $root->getLineage( ['descendants'], {
includeOnlyClasses => ['WebGUI::Asset::EMSSubmissionForm'],
} );

265
sbin/findBrokenAssets.pl Normal file
View file

@ -0,0 +1,265 @@
#!/usr/bin/env perl
#-------------------------------------------------------------------
# WebGUI is Copyright 2001-2009 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 File::Basename ();
use File::Spec;
my $webguiRoot;
BEGIN {
$webguiRoot = File::Spec->rel2abs( File::Spec->catdir( File::Basename::dirname(__FILE__), File::Spec->updir ) );
unshift @INC, File::Spec->catdir( $webguiRoot, 'lib' );
}
$|++; # disable output buffering
our ( $configFile, $help, $man, $fix, $delete );
use Pod::Usage;
use Getopt::Long;
use WebGUI::Session;
# Get parameters here, including $help
GetOptions(
'configFile=s' => \$configFile,
'help' => \$help,
'man' => \$man,
'fix' => \$fix,
'delete' => \$delete,
);
pod2usage( verbose => 1 ) if $help;
pod2usage( verbose => 2 ) if $man;
pod2usage( msg => "Must specify a config file!" ) unless $configFile;
my $session = start( $webguiRoot, $configFile );
sub progress {
my ( $total, $current ) = @_;
local $| = 1;
my $done = int( ( ( $current / $total ) * 100 ) / 2 );
$done &&= $done - 1; # Fit the >
my $space = 49 - $done;
print "\r[", '=' x $done, '>', ' ' x $space, ']';
printf ' (%d/%d)', $current, $total;
}
my $totalAsset = $session->db->quickScalar('SELECT COUNT(*) FROM asset');
my $totalAssetData = $session->db->quickScalar('SELECT COUNT( DISTINCT( assetId ) ) FROM assetData' );
my $total = $totalAsset >= $totalAssetData ? $totalAsset : $totalAssetData;
# Order by to put corrupt parents before corrupt children
# Join assetData to get all asset and assetData
my $sql = "SELECT * FROM asset LEFT JOIN assetData USING ( assetId ) GROUP BY assetId ORDER BY lineage ASC";
my $sth = $session->db->read($sql);
my $count = 1;
my %classTables; # Cache definition lookups
while ( my %row = $sth->hash ) {
eval { WebGUI::Asset->newPending( $session, $row{assetId} ) };
if ( $@ ) {
# Replace the progress bar with a message
printf "\r%-68s", "-- Corrupt: $row{assetId}";
# Should we do something?
if ($fix) {
my $classTables = $classTables{ $row{className} } ||= do {
eval "require $row{className}";
[ map { $_->{tableName} } reverse @{ $row{className}->definition($session) } ];
};
$row{revisionDate} ||= time;
for my $table ( @{$classTables} ) {
my $sqlFind = "SELECT * FROM $table WHERE assetId=? ORDER BY revisionDate DESC";
my @params = @row{qw( assetId )};
my $insertRow = $session->db->quickHashRef( $sqlFind, \@params ) || {};
if ( $row{revisionDate} != $insertRow->{revisionDate} ) {
$insertRow->{ assetId } = $row{assetId};
$insertRow->{ revisionDate } = $row{revisionDate};
my $cols = join ",", keys %$insertRow;
my @values = values %$insertRow;
my $places = join ",", ('?') x @values;
my $sqlFix = "INSERT INTO $table ($cols) VALUES ($places)";
$session->db->write( $sqlFix, \@values );
}
}
print "Fixed.\n";
# Make sure we have a valid parent
unless ( WebGUI::Asset->newByDynamicClass( $session, $row{parentId} ) ) {
my $asset = WebGUI::Asset->newByDynamicClass( $session, $row{assetId} );
$asset->setParent( WebGUI::Asset->getImportNode( $session ) );
print "\tNOTE: Invalid parent. Asset moved to Import Node\n";
}
} ## end if ($fix)
elsif ($delete) {
my $classTables = $classTables{ $row{className} } ||= do {
eval "require $row{className}";
[ map { $_->{tableName} } reverse @{ $row{className}->definition($session) } ];
};
my @params = @row{qw( assetId revisionDate )};
for my $table ( @{$classTables} ) {
my $sqlDelete = "DELETE FROM $table WHERE assetId=? AND revisionDate=?";
$session->db->write( $sqlDelete, \@params );
}
$session->db->write( "DELETE FROM asset WHERE assetId=?", [$row{assetId}] );
print "Deleted.\n";
} ## end elsif ($delete)
else { # report
print "\n";
if ( $row{revisionDate} ) {
printf "%10s: %s\n", "revised", scalar( localtime $row{revisionDate} );
}
# Parent
if ( my $parent = WebGUI::Asset->newByDynamicClass( $session, $row{parentId} ) ) {
printf "%10s: %s (%s)\n", "parent", $parent->getTitle, $parent->getId;
}
elsif ( $session->db->quickScalar( "SELECT * FROM asset WHERE assetId=?", [$row{parentId}] ) ) {
print "Parent corrupt ($row{parentId}).\n";
}
else {
print "Parent missing ($row{parentId}).\n";
}
# More properties
if ( $row{revisionDate} ) {
my %assetData = $session->db->quickHash( "SELECT * FROM assetData WHERE assetId=? AND revisionDate=?",
[ @row{ "assetId", "revisionDate" } ] );
for my $key (qw( title url )) {
printf "%10s: %s\n", $key, $assetData{$key};
}
}
else {
print "No current asset data.\n";
}
# Previous revisions
my %lastRev
= $session->db->quickHash(
"SELECT * FROM assetData WHERE assetId=? AND revisionDate != ? ORDER BY revisionDate DESC",
[ $row{assetId}, $row{revisionDate} ]
);
if ( $lastRev{assetId} ) {
print "Previous revision:\n";
for my $key (qw( title url )) {
printf "%10s: %s\n", $key, $lastRev{$key};
}
}
else {
print "No previous revisions.\n";
}
# Asset History
my $history = $session->db->buildArrayRefOfHashRefs(
"SELECT * FROM assetHistory LEFT JOIN users USING (userId) WHERE assetId=? ORDER BY dateStamp DESC",
[ $row{assetId} ],
);
if ( $history->[0] ) {
my $username = $history->[0]{username} || "<Unknown User>";
printf "Last action '%s'\n\tby %s\n\ton %s\n",
$history->[0]{actionTaken},
$username,
scalar( localtime $history->[0]{dateStamp} ),
;
}
} ## end else [ if ($fix) ]
} ## end if ( !$asset )
progress( $total, $count++ );
} ## end while ( my %row = $sth->hash)
finish($session);
print "\n";
#----------------------------------------------------------------------------
# Your sub here
#----------------------------------------------------------------------------
sub start {
my $webguiRoot = shift;
my $configFile = shift;
my $session = WebGUI::Session->open( $webguiRoot, $configFile );
$session->user( { userId => 3 } );
return $session;
}
#----------------------------------------------------------------------------
sub finish {
my $session = shift;
$session->var->end;
$session->close;
}
__END__
=head1 NAME
findBrokenAssets.pl -- Find and fix broken assets
=head1 SYNOPSIS
findBrokenAssets.pl --configFile config.conf [--fix|--delete]
utility --help
=head1 DESCRIPTION
This utility will find any broken assets that cannot be instantiated and are
causing undesired operation of your website.
It can also automatically delete them or fix them so you can restore missing data.
=head1 ARGUMENTS
=head1 OPTIONS
=over
=item B<--configFile config.conf>
The WebGUI config file to use. Only the file name needs to be specified,
since it will be looked up inside WebGUI's configuration directory.
This parameter is required.
=item B<--delete>
Delete any corrupted assets.
=item B<--fix>
Try to fix any corrupted assets.
=item B<--help>
Shows a short summary and usage
=item B<--man>
Shows this document
=back
=head1 AUTHOR
Copyright 2001-2009 Plain Black Corporation.
=cut
#vim:ft=perl