From c859e41650965abcf8eeaf29015d30656f40b5fb Mon Sep 17 00:00:00 2001 From: Nat Date: Fri, 6 Jun 2025 23:32:03 +0800 Subject: [PATCH 1/3] FIX: User directory for solutions should update when value changes from positive to zero --- plugin.rb | 35 +++++++++++++++--------------- spec/models/directory_item_spec.rb | 27 +++++++++++++++++++++++ 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/plugin.rb b/plugin.rb index 13f51a0d..c3c7cb54 100644 --- a/plugin.rb +++ b/plugin.rb @@ -291,23 +291,24 @@ def self.skip_db? query = <<~SQL WITH x AS ( - SELECT p.user_id, COUNT(DISTINCT st.id) AS solutions - FROM discourse_solved_solved_topics AS st - JOIN posts AS p - ON p.id = st.answer_post_id - AND COALESCE(st.created_at, :since) > :since - AND p.deleted_at IS NULL - JOIN topics AS t - ON t.id = st.topic_id - AND t.archetype <> 'private_message' - AND t.deleted_at IS NULL - JOIN users AS u - ON u.id = p.user_id - WHERE u.id > 0 - AND u.active - AND u.silenced_till IS NULL - AND u.suspended_till IS NULL - GROUP BY p.user_id + SELECT users.id AS user_id, + COUNT(DISTINCT CASE WHEN + st.topic_id IS NOT NULL AND + t.id IS NOT NULL AND + t.archetype <> 'private_message' AND + t.deleted_at IS NULL AND + p.deleted_at IS NULL + THEN st.topic_id ELSE NULL END) AS solutions + FROM users + LEFT JOIN posts p ON p.user_id = users.id + LEFT JOIN discourse_solved_solved_topics st + ON st.answer_post_id = p.id + AND st.created_at >= :since + LEFT JOIN topics t ON t.id = st.topic_id + WHERE users.active + AND users.silenced_till IS NULL + AND users.suspended_till IS NULL + GROUP BY users.id ) UPDATE directory_items di SET solutions = x.solutions diff --git a/spec/models/directory_item_spec.rb b/spec/models/directory_item_spec.rb index 7e2034ce..7b72585f 100644 --- a/spec/models/directory_item_spec.rb +++ b/spec/models/directory_item_spec.rb @@ -101,5 +101,32 @@ ).solutions, ).to eq(1) end + + context "when refreshing across dates" do + it "updates the user's solution count from 1 to 0" do + freeze_time 40.days.ago + DiscourseSolved.accept_answer!(topic_post1, Discourse.system_user) + + DirectoryItem.refresh! + + expect( + DirectoryItem.find_by( + user_id: user.id, + period_type: DirectoryItem.period_types[:monthly], + ).solutions, + ).to eq(1) + + unfreeze_time + + DirectoryItem.refresh! + + expect( + DirectoryItem.find_by( + user_id: user.id, + period_type: DirectoryItem.period_types[:monthly], + ).solutions, + ).to eq(0) + end + end end end From 9a9f5d6fa609eb1a7d80b19ff39b9df0dd3c0917 Mon Sep 17 00:00:00 2001 From: Nat Date: Fri, 6 Jun 2025 23:48:21 +0800 Subject: [PATCH 2/3] suggestions --- plugin.rb | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugin.rb b/plugin.rb index c3c7cb54..7b4b19b1 100644 --- a/plugin.rb +++ b/plugin.rb @@ -292,20 +292,21 @@ def self.skip_db? query = <<~SQL WITH x AS ( SELECT users.id AS user_id, - COUNT(DISTINCT CASE WHEN + COUNT(DISTINCT st.topic_id) FILTER (WHERE st.topic_id IS NOT NULL AND t.id IS NOT NULL AND t.archetype <> 'private_message' AND t.deleted_at IS NULL AND p.deleted_at IS NULL - THEN st.topic_id ELSE NULL END) AS solutions + ) AS solutions FROM users LEFT JOIN posts p ON p.user_id = users.id LEFT JOIN discourse_solved_solved_topics st ON st.answer_post_id = p.id AND st.created_at >= :since LEFT JOIN topics t ON t.id = st.topic_id - WHERE users.active + WHERE users.id > 0 + AND users.active AND users.silenced_till IS NULL AND users.suspended_till IS NULL GROUP BY users.id From 7fa551a8db67b6b846314f6797bddc5c0a50c6c5 Mon Sep 17 00:00:00 2001 From: Nat Date: Wed, 11 Jun 2025 10:28:31 +0800 Subject: [PATCH 3/3] no ex join --- plugin.rb | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/plugin.rb b/plugin.rb index 7b4b19b1..c37e9844 100644 --- a/plugin.rb +++ b/plugin.rb @@ -290,33 +290,34 @@ def self.skip_db? end query = <<~SQL + UPDATE directory_items di + SET solutions = 0 + WHERE di.period_type = :period_type AND di.solutions IS NOT NULL; + WITH x AS ( - SELECT users.id AS user_id, - COUNT(DISTINCT st.topic_id) FILTER (WHERE - st.topic_id IS NOT NULL AND - t.id IS NOT NULL AND - t.archetype <> 'private_message' AND - t.deleted_at IS NULL AND - p.deleted_at IS NULL - ) AS solutions - FROM users - LEFT JOIN posts p ON p.user_id = users.id - LEFT JOIN discourse_solved_solved_topics st - ON st.answer_post_id = p.id - AND st.created_at >= :since - LEFT JOIN topics t ON t.id = st.topic_id - WHERE users.id > 0 - AND users.active - AND users.silenced_till IS NULL - AND users.suspended_till IS NULL - GROUP BY users.id + SELECT p.user_id, COUNT(DISTINCT st.id) AS solutions + FROM discourse_solved_solved_topics AS st + JOIN posts AS p + ON p.id = st.answer_post_id + AND COALESCE(st.created_at, :since) > :since + AND p.deleted_at IS NULL + JOIN topics AS t + ON t.id = st.topic_id + AND t.archetype <> 'private_message' + AND t.deleted_at IS NULL + JOIN users AS u + ON u.id = p.user_id + WHERE u.id > 0 + AND u.active + AND u.silenced_till IS NULL + AND u.suspended_till IS NULL + GROUP BY p.user_id ) UPDATE directory_items di - SET solutions = x.solutions - FROM x - WHERE x.user_id = di.user_id - AND di.period_type = :period_type - AND di.solutions <> x.solutions + SET solutions = x.solutions + FROM x + WHERE x.user_id = di.user_id + AND di.period_type = :period_type; SQL add_directory_column("solutions", query:)