diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index be65a8c40..46c83a252 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -96,6 +96,7 @@ - fixed #9140: Date format error when adding tasks to PM - fixed #8800: Errors in POD of Asset-related mix-in modules (Bernd Kalbfuß-Zimmermann) - fixed #9143: Yes No user profile fields problem when default == 1 + - fixed #8775: Miscount in number of replies in CS Thread (Martin Kamerbeek / Oqapi) 7.5.34 - fixed: Regression with ProfileField->formField. Added tests to prevent future regression diff --git a/lib/WebGUI/Asset/Post.pm b/lib/WebGUI/Asset/Post.pm index e5a045185..e2f6e8ab3 100644 --- a/lib/WebGUI/Asset/Post.pm +++ b/lib/WebGUI/Asset/Post.pm @@ -33,7 +33,41 @@ use WebGUI::Utility; use WebGUI::VersionTag; our @ISA = qw(WebGUI::Asset); +#------------------------------------------------------------------- +=head2 _fixReplyCount ( asset ) + +Fixes the mismatch in number of replies and lastPost in a thread and/or a CS that occurs after a cut or paste +action. + +Note: if invoked on a thread the CS containing it will very likely be changed as well, but likely in an incorrect +manner. Therfore, after running this method on a Thread you probably also want to run it on the container CS. + +=head3 asset + +The instanciated asset to fix. This may only be either a WebGUI::Asset::Post::Thread or a +WebGUI::Asset::Wobject::Collaboration. + +=cut + +sub _fixReplyCount { + my $self = shift; + my $asset = shift; + + my $lastPost = $asset->getLineage( [ qw{ self descendants } ], { + returnObjects => 1, + isa => 'WebGUI::Asset::Post', + orderByClause => 'assetData.revisionDate desc', + limit => 1, + } )->[0]; + + if ($lastPost) { + $asset->incrementReplies( $lastPost->get( 'revisionDate' ), $lastPost->getId ); + } + else { + $asset->incrementReplies( undef, undef ); + } +} #------------------------------------------------------------------- @@ -175,6 +209,29 @@ sub commit { } } +#------------------------------------------------------------------- +sub cut { + my $self = shift; + + # Fetch the Thread and CS before cutting the asset. + my $thread = $self->getThread; + my $cs = $thread->getParent; + + # Cut the asset + my $result = $self->SUPER::cut; + + # If a post is being cut update the thread reply count first + if ($thread->getId ne $self->getId) { + $self->_fixReplyCount( $thread ); + } + + # Update the CS reply count. This step is also necessary when a Post is cut since the Thread's incrementReplies + # also calls the CS's incrementReplies, possibly with the wrong last post Id. + $self->_fixReplyCount( $cs ); + + return $result; +} + #------------------------------------------------------------------- sub definition { my $class = shift; @@ -820,6 +877,43 @@ sub notifySubscribers { } } +#------------------------------------------------------------------- +sub paste { + my $self = shift; + + $self->SUPER::paste(@_); + + # First, figure out what Thread we're under + my $thread = $self->getLineage( [ qw{ self ancestors } ], { + returnObjects => 1, + isa => 'WebGUI::Asset::Post::Thread', + } )->[0]; + + # 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 ) { + # Check if we're actually pasting under a thread. + if ($thread) { + # If so, get the threadId from the thread and fetch all posts that must be updated. + my $threadId = $thread->getId; + my $childPosts = $self->getLineage( [ qw{ self descendants } ], { + returnObjects => 1, + isa => 'WebGUI::Asset::Post', + } ); + + # Finally update all these Posts + foreach my $asset ( @{ $childPosts } ) { + $asset->update( { threadId => $threadId } ); + } + } + else { + # We're putting Posts in a place they don't belong, so issue a warning. + $self->session->log->warn('Posts pasted under an asset that is not a Thread'); + } + } + + # Recount the replies under the thread. + $thread->sumReplies; +} #------------------------------------------------------------------- sub processPropertiesFromFormPost { @@ -884,11 +978,12 @@ sub postProcess { #------------------------------------------------------------------- -sub publish { - my $self = shift; - $self->SUPER::publish(@_); - $self->getThread->sumReplies; -} +#sub publish { +# my $self = shift; +# $self->SUPER::publish(@_); +# +# $self->getThread->sumReplies; +#} #------------------------------------------------------------------- diff --git a/lib/WebGUI/AssetLineage.pm b/lib/WebGUI/AssetLineage.pm index 8891ec89d..3a7f7289d 100644 --- a/lib/WebGUI/AssetLineage.pm +++ b/lib/WebGUI/AssetLineage.pm @@ -193,7 +193,7 @@ sub getChildCount { my $self = shift; my $opts = shift || {}; my $stateWhere = $opts->{includeTrash} ? '' : "asset.state='published' and"; - my ($count) = $self->session->db->quickArray("select count(*) 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 ($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')]); return $count; } @@ -208,7 +208,7 @@ in the clipboard or trash. sub getDescendantCount { my $self = shift; - my ($count) = $self->session->db->quickArray("select count(*) 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 ($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")."%"]); $count--; # have to subtract self return $count; }