FIX: Update draft count after creating a post (#13884)

FIX: Update draft count after creating a post (#13884)

When a post is created, the draft sequence is increased and then older drafts are automatically executing a raw SQL query. This skipped the Draft model callbacks and did not update user’s draft count.

I fixed another problem related to a raw SQL query from Draft.cleanup! method.

diff --git a/app/models/draft.rb b/app/models/draft.rb
index 7b39d44..924c987 100644
--- a/app/models/draft.rb
+++ b/app/models/draft.rb
@@ -254,6 +254,8 @@ class Draft < ActiveRecord::Base
     # remove old drafts
     delete_drafts_older_than_n_days = SiteSetting.delete_drafts_older_than_n_days.days.ago
     Draft.where("updated_at < ?", delete_drafts_older_than_n_days).destroy_all
+
+    UserStat.update_draft_count
   end
 
   def self.backup_draft(user, key, sequence, data)
diff --git a/app/models/user_stat.rb b/app/models/user_stat.rb
index 69bc63a..045dcac 100644
--- a/app/models/user_stat.rb
+++ b/app/models/user_stat.rb
@@ -202,19 +202,32 @@ class UserStat < ActiveRecord::Base
     self.class.update_distinct_badge_count(self.user_id)
   end
 
-  def self.update_draft_count(user_id)
-    draft_count = DB.query_single <<~SQL, user_id: user_id
-      UPDATE user_stats
-      SET draft_count = (SELECT COUNT(*) FROM drafts WHERE user_id = :user_id)
-      WHERE user_id = :user_id
-      RETURNING draft_count
-    SQL
+  def self.update_draft_count(user_id = nil)
+    if user_id.present?
+      draft_count = DB.query_single <<~SQL, user_id: user_id
+        UPDATE user_stats
+        SET draft_count = (SELECT COUNT(*) FROM drafts WHERE user_id = :user_id)
+        WHERE user_id = :user_id
+        RETURNING draft_count
+      SQL
 
-    MessageBus.publish(
-      '/user',
-      { draft_count: draft_count.first },
-      user_ids: [user_id]
-    )
+      MessageBus.publish(
+        '/user',
+        { draft_count: draft_count.first },
+        user_ids: [user_id]
+      )
+    else
+      DB.exec <<~SQL
+        UPDATE user_stats
+        SET draft_count = new_user_stats.draft_count
+        FROM (SELECT user_stats.user_id, COUNT(drafts.id) draft_count
+              FROM user_stats
+              LEFT JOIN drafts ON user_stats.user_id = drafts.user_id
+              GROUP BY user_stats.user_id) new_user_stats
+        WHERE user_stats.user_id = new_user_stats.user_id
+          AND user_stats.draft_count <> new_user_stats.draft_count
+      SQL
+    end
   end
 
   # topic_reply_count is a count of posts in other users' topics
diff --git a/lib/post_creator.rb b/lib/post_creator.rb
index 69a94bd..922c7e3 100644
--- a/lib/post_creator.rb
+++ b/lib/post_creator.rb
@@ -229,6 +229,7 @@ class PostCreator
       @post.topic.reload
 
       publish
+      UserStat.update_draft_count(@user.id)
 
       track_latest_on_category
       enqueue_jobs unless @opts[:skip_jobs]
diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb
index f7d1c09..368ba3b 100644
--- a/spec/components/post_creator_spec.rb
+++ b/spec/components/post_creator_spec.rb
@@ -165,7 +165,9 @@ describe PostCreator do
             "/latest",
             "/latest",
             "/topic/#{created_post.topic_id}",
-            "/topic/#{created_post.topic_id}"
+            "/topic/#{created_post.topic_id}",
+            "/user",
+            "/user"
           ].sort
         )
 
@@ -194,7 +196,7 @@ describe PostCreator do
         user_action = messages.find { |m| m.channel == "/u/#{p.user.username}" }
         expect(user_action).not_to eq(nil)
 
-        expect(messages.filter { |m| m.channel != "/distributed_hash" }.length).to eq(5)
+        expect(messages.filter { |m| m.channel != "/distributed_hash" }.length).to eq(6)
       end
 
       it 'extracts links from the post' do
@@ -281,12 +283,14 @@ describe PostCreator do
       it 'creates post stats' do
         Draft.set(user, Draft::NEW_TOPIC, 0, "test")
         Draft.set(user, Draft::NEW_TOPIC, 0, "test1")
+        expect(user.user_stat.draft_count).to eq(1)
 
         begin
           PostCreator.track_post_stats = true
           post = creator.create
           expect(post.post_stat.typing_duration_msecs).to eq(0)
           expect(post.post_stat.drafts_saved).to eq(2)
+          expect(user.reload.user_stat.draft_count).to eq(0)
         ensure
           PostCreator.track_post_stats = false
         end
diff --git a/spec/models/draft_spec.rb b/spec/models/draft_spec.rb
index 54218c5..0e4dc72 100644
--- a/spec/models/draft_spec.rb
+++ b/spec/models/draft_spec.rb
@@ -152,6 +152,7 @@ describe Draft do
     Draft.set(user, key, 0, 'draft')
     Draft.cleanup!
     expect(Draft.count).to eq 1
+    expect(user.user_stat.draft_count).to eq(1)
 
     seq = DraftSequence.next!(user, key)
 
@@ -161,6 +162,7 @@ describe Draft do
     Draft.cleanup!
 
     expect(Draft.count).to eq 0
+    expect(user.reload.user_stat.draft_count).to eq(0)
 
     Draft.set(Fabricate(:user), Draft::NEW_TOPIC, 0, 'draft')
 

GitHub sha: 300db3d3fa635ef8e132123e1d96e380946f6cc1

This commit appears in #13884 which was approved by eviltrout. It was merged by nbianca.

This commit has been mentioned on Discourse Meta. There might be relevant details there: