1
0
mirror of https://github.com/flarum/core.git synced 2025-08-16 05:14:20 +02:00

Fix Last Posted Discussion, Improve DiscussionCount (#78)

The calculation/caching of the last posted discsussion is currently not very good. This PR adds fixes for:

Ensuring that private and hidden discussions aren't returned
Hiding and restoring discussions (hidden discussions shouldn't be returned)
Editing tags on a discussion (previously the discussion wasn't removed from the old tags).
This commit is contained in:
Alexander Skvortsov
2020-06-28 15:07:06 -04:00
committed by GitHub
parent 2a21725fe3
commit 6a6d2f3803
2 changed files with 63 additions and 30 deletions

View File

@@ -9,12 +9,15 @@
namespace Flarum\Tags\Listener; namespace Flarum\Tags\Listener;
use Flarum\Discussion\Discussion;
use Flarum\Discussion\Event\Deleted; use Flarum\Discussion\Event\Deleted;
use Flarum\Discussion\Event\Hidden;
use Flarum\Discussion\Event\Restored;
use Flarum\Discussion\Event\Started; use Flarum\Discussion\Event\Started;
use Flarum\Post\Event\Deleted as PostDeleted; use Flarum\Post\Event\Deleted as PostDeleted;
use Flarum\Post\Event\Hidden; use Flarum\Post\Event\Hidden as PostHidden;
use Flarum\Post\Event\Posted; use Flarum\Post\Event\Posted;
use Flarum\Post\Event\Restored; use Flarum\Post\Event\Restored as PostRestored;
use Flarum\Tags\Event\DiscussionWasTagged; use Flarum\Tags\Event\DiscussionWasTagged;
use Flarum\Tags\Tag; use Flarum\Tags\Tag;
use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Contracts\Events\Dispatcher;
@@ -29,11 +32,13 @@ class UpdateTagMetadata
$events->listen(Started::class, [$this, 'whenDiscussionIsStarted']); $events->listen(Started::class, [$this, 'whenDiscussionIsStarted']);
$events->listen(DiscussionWasTagged::class, [$this, 'whenDiscussionWasTagged']); $events->listen(DiscussionWasTagged::class, [$this, 'whenDiscussionWasTagged']);
$events->listen(Deleted::class, [$this, 'whenDiscussionIsDeleted']); $events->listen(Deleted::class, [$this, 'whenDiscussionIsDeleted']);
$events->listen(Hidden::class, [$this, 'whenDiscussionIsHidden']);
$events->listen(Restored::class, [$this, 'whenDiscussionIsRestored']);
$events->listen(Posted::class, [$this, 'whenPostIsPosted']); $events->listen(Posted::class, [$this, 'whenPostIsPosted']);
$events->listen(PostDeleted::class, [$this, 'whenPostIsDeleted']); $events->listen(PostDeleted::class, [$this, 'whenPostIsDeleted']);
$events->listen(Hidden::class, [$this, 'whenPostIsHidden']); $events->listen(PostHidden::class, [$this, 'whenPostIsHidden']);
$events->listen(Restored::class, [$this, 'whenPostIsRestored']); $events->listen(PostRestored::class, [$this, 'whenPostIsRestored']);
} }
/** /**
@@ -49,7 +54,7 @@ class UpdateTagMetadata
*/ */
public function whenDiscussionWasTagged(DiscussionWasTagged $event) public function whenDiscussionWasTagged(DiscussionWasTagged $event)
{ {
$oldTags = Tag::whereIn('id', array_pluck($event->oldTags, 'id')); $oldTags = Tag::whereIn('id', array_pluck($event->oldTags, 'id'))->get();
$this->updateTags($event->discussion, -1, $oldTags); $this->updateTags($event->discussion, -1, $oldTags);
$this->updateTags($event->discussion, 1); $this->updateTags($event->discussion, 1);
@@ -65,6 +70,22 @@ class UpdateTagMetadata
$event->discussion->tags()->detach(); $event->discussion->tags()->detach();
} }
/**
* @param Hidden $event
*/
public function whenDiscussionIsHidden(Hidden $event)
{
$this->updateTags($event->discussion, -1);
}
/**
* @param Restored $event
*/
public function whenDiscussionIsRestored(Restored $event)
{
$this->updateTags($event->discussion, 1);
}
/** /**
* @param Posted $event * @param Posted $event
*/ */
@@ -74,7 +95,7 @@ class UpdateTagMetadata
} }
/** /**
* @param Deleted $event * @param PostDeleted $event
*/ */
public function whenPostIsDeleted(PostDeleted $event) public function whenPostIsDeleted(PostDeleted $event)
{ {
@@ -82,47 +103,57 @@ class UpdateTagMetadata
} }
/** /**
* @param Hidden $event * @param PostHidden $event
*/ */
public function whenPostIsHidden(Hidden $event) public function whenPostIsHidden(PostHidden $event)
{ {
$this->updateTags($event->post->discussion); $this->updateTags($event->post->discussion, 0, null, $event->post);
} }
/** /**
* @param Restored $event * @param PostRestored $event
*/ */
public function whenPostIsRestored(Restored $event) public function whenPostIsRestored(PostRestored $event)
{ {
$this->updateTags($event->post->discussion); $this->updateTags($event->post->discussion, 0, null, $event->post);
} }
/** /**
* @param \Flarum\Discussion\Discussion $discussion * @param \Flarum\Discussion\Discussion $discussion
* @param int $delta * @param int $delta
* @param Tag[]|null $tags * @param Tag[]|null $tags
* @param Post $post: This is only used when a post has been hidden
*/ */
protected function updateTags($discussion, $delta = 0, $tags = null) protected function updateTags(Discussion $discussion, $delta = 0, $tags = null, $post = null)
{ {
if (! $discussion) {
return;
}
// We do not count private discussions in tags
if ($discussion->is_private) {
return;
}
if (! $tags) { if (! $tags) {
$tags = $discussion->tags; $tags = $discussion->tags;
} }
foreach ($tags as $tag) { // If we've just hidden or restored a post, the discussion's last posted at metadata might not have updated yet.
$tag->discussion_count += $delta; // Therefore, we must refresh the last post, even though that might be repeated in the future.
if ($post) {
$discussion->refreshLastPost();
}
if ($discussion->last_posted_at > $tag->last_posted_at) { foreach ($tags as $tag) {
// We do not count private discussions or hidden discussions in tags
if (! $discussion->is_private) {
$tag->discussion_count += $delta;
}
// If this is a new / restored discussion, it isn't private, it isn't null,
// and it's more recent than what we have now, set it as last posted discussion.
if ($delta >= 0 && ! $discussion->is_private && $discussion->hidden_at == null && ($discussion->last_posted_at >= $tag->last_posted_at)) {
$tag->setLastPostedDiscussion($discussion); $tag->setLastPostedDiscussion($discussion);
} elseif ($discussion->id == $tag->last_posted_discussion_id) { } elseif ($discussion->id == $tag->last_posted_discussion_id) {
// This is to persist refreshLastPost above. It is here instead of there so that
// if it's not necessary, we save a DB query.
if ($post) {
$discussion->save();
}
// This discussion is currently the last posted discussion, but since it didn't qualify for the above check,
// it should not be the last posted discussion. Therefore, we should refresh the last posted discussion..
$tag->refreshLastPostedDiscussion(); $tag->refreshLastPostedDiscussion();
} }

View File

@@ -110,18 +110,20 @@ class Tag extends AbstractModel
public function refreshLastPostedDiscussion() public function refreshLastPostedDiscussion()
{ {
if ($lastPostedDiscussion = $this->discussions()->latest('last_posted_at')->first()) { if ($lastPostedDiscussion = $this->discussions()->where('is_private', false)->whereNull('hidden_at')->latest('last_posted_at')->first()) {
$this->setLastPostedDiscussion($lastPostedDiscussion); $this->setLastPostedDiscussion($lastPostedDiscussion);
} else {
$this->setLastPostedDiscussion(null);
} }
return $this; return $this;
} }
public function setLastPostedDiscussion(Discussion $discussion) public function setLastPostedDiscussion(Discussion $discussion = null)
{ {
$this->last_posted_at = $discussion->last_posted_at; $this->last_posted_at = optional($discussion)->last_posted_at;
$this->last_posted_discussion_id = $discussion->id; $this->last_posted_discussion_id = optional($discussion)->id;
$this->last_posted_user_id = $discussion->last_posted_user_id; $this->last_posted_user_id = optional($discussion)->last_posted_user_id;
return $this; return $this;
} }