Skip to content

Commit 4032a1e

Browse files
FIX: Search bug for status:unsolved returns topics from non-solution enabled categories (#241)
* FIX: Search bug for status:unsolved returns topics from non-solution enabled categories * fixed rubocop issues
1 parent 7b90566 commit 4032a1e

File tree

3 files changed

+146
-15
lines changed

3 files changed

+146
-15
lines changed

plugin.rb

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ class Engine < ::Rails::Engine
7676

7777
AUTO_CLOSE_TOPIC_TIMER_CUSTOM_FIELD = "solved_auto_close_topic_timer_id"
7878
ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD = "accepted_answer_post_id"
79+
ENABLE_ACCEPTED_ANSWERS_CUSTOM_FIELD = "enable_accepted_answers"
7980

8081
def self.accept_answer!(post, acting_user, topic: nil)
8182
topic ||= post.topic
@@ -502,9 +503,10 @@ class ::Guardian
502503
def self.reset_accepted_answer_cache
503504
@@allowed_accepted_cache["allowed"] = begin
504505
Set.new(
505-
CategoryCustomField.where(name: "enable_accepted_answers", value: "true").pluck(
506-
:category_id,
507-
),
506+
CategoryCustomField.where(
507+
name: ::DiscourseSolved::ENABLE_ACCEPTED_ANSWERS_CUSTOM_FIELD,
508+
value: "true",
509+
).pluck(:category_id),
508510
)
509511
end
510512
end
@@ -586,14 +588,32 @@ def topic_accepted_answer
586588
end
587589

588590
Search.advanced_filter(/status:unsolved/) do |posts|
589-
posts.where(
590-
"topics.id NOT IN (
591-
SELECT tc.topic_id
592-
FROM topic_custom_fields tc
593-
WHERE tc.name = '#{::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD}' AND
594-
tc.value IS NOT NULL
595-
)",
596-
)
591+
if SiteSetting.allow_solved_on_all_topics
592+
posts.where(
593+
"topics.id NOT IN (
594+
SELECT tc.topic_id
595+
FROM topic_custom_fields tc
596+
WHERE tc.name = '#{::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD}' AND
597+
tc.value IS NOT NULL
598+
)",
599+
)
600+
else
601+
posts.where(
602+
"topics.id NOT IN (
603+
SELECT tc.topic_id
604+
FROM topic_custom_fields tc
605+
WHERE tc.name = '#{::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD}' AND
606+
tc.value IS NOT NULL
607+
) AND topics.id IN (
608+
SELECT top.id
609+
FROM topics top
610+
INNER JOIN category_custom_fields cc
611+
ON top.category_id = cc.category_id
612+
WHERE cc.name = '#{::DiscourseSolved::ENABLE_ACCEPTED_ANSWERS_CUSTOM_FIELD}' AND
613+
cc.value = 'true'
614+
)",
615+
)
616+
end
597617
end
598618
end
599619

@@ -655,7 +675,7 @@ class ::ListableTopicSerializer
655675
TopicList.preloaded_custom_fields << ::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD
656676
end
657677
if Site.respond_to? :preloaded_category_custom_fields
658-
Site.preloaded_category_custom_fields << "enable_accepted_answers"
678+
Site.preloaded_category_custom_fields << ::DiscourseSolved::ENABLE_ACCEPTED_ANSWERS_CUSTOM_FIELD
659679
end
660680
if Search.respond_to? :preloaded_topic_custom_fields
661681
Search.preloaded_topic_custom_fields << ::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD
@@ -696,7 +716,7 @@ class ::ListableTopicSerializer
696716
)
697717
CategoryCustomField.create!(
698718
category_id: solved_category.id,
699-
name: "enable_accepted_answers",
719+
name: ::DiscourseSolved::ENABLE_ACCEPTED_ANSWERS_CUSTOM_FIELD,
700720
value: "true",
701721
)
702722
puts "discourse-solved enabled on category '#{solved_category.name}' (#{solved_category.id})."
@@ -706,7 +726,7 @@ class ::ListableTopicSerializer
706726
unless SiteSetting.allow_solved_on_all_topics
707727
solved_category_id =
708728
CategoryCustomField
709-
.where(name: "enable_accepted_answers", value: "true")
729+
.where(name: ::DiscourseSolved::ENABLE_ACCEPTED_ANSWERS_CUSTOM_FIELD, value: "true")
710730
.first
711731
.category_id
712732

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
Fabricator(:custom_topic, from: :topic) do
3+
transient :custom_topic_name
4+
transient :value
5+
after_create do |top, transients|
6+
custom_topic =
7+
TopicCustomField.new(
8+
topic_id: top.id,
9+
name: transients[:custom_topic_name],
10+
value: transients[:value],
11+
)
12+
custom_topic.save
13+
end
14+
end

spec/integration/solved_spec.rb

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
RSpec.describe "Managing Posts solved status" do
66
let(:topic) { Fabricate(:topic) }
7-
let(:user) { Fabricate(:trust_level_4) }
7+
fab!(:user) { Fabricate(:trust_level_4) }
88
let(:p1) { Fabricate(:post, topic: topic) }
99

1010
before { SiteSetting.allow_solved_on_all_topics = true }
@@ -39,6 +39,103 @@
3939
result = Search.execute("carrot")
4040
expect(result.posts.pluck(:id)).to eq([solved_post.id, normal_post.id])
4141
end
42+
43+
describe "#advanced_search" do
44+
fab!(:category_enabled) do
45+
category = Fabricate(:category)
46+
category_custom_field =
47+
CategoryCustomField.new(
48+
category_id: category.id,
49+
name: ::DiscourseSolved::ENABLE_ACCEPTED_ANSWERS_CUSTOM_FIELD,
50+
value: "true",
51+
)
52+
category_custom_field.save
53+
category
54+
end
55+
fab!(:category_disabled) do
56+
category = Fabricate(:category)
57+
category_custom_field =
58+
CategoryCustomField.new(
59+
category_id: category.id,
60+
name: ::DiscourseSolved::ENABLE_ACCEPTED_ANSWERS_CUSTOM_FIELD,
61+
value: "false",
62+
)
63+
category_custom_field.save
64+
category
65+
end
66+
fab!(:topic_unsolved) do
67+
Fabricate(
68+
:custom_topic,
69+
user: user,
70+
category: category_enabled,
71+
custom_topic_name: ::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD,
72+
)
73+
end
74+
fab!(:topic_solved) do
75+
Fabricate(
76+
:custom_topic,
77+
user: user,
78+
category: category_enabled,
79+
custom_topic_name: ::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD,
80+
)
81+
end
82+
fab!(:topic_disabled_1) do
83+
Fabricate(
84+
:custom_topic,
85+
user: user,
86+
category: category_disabled,
87+
custom_topic_name: ::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD,
88+
)
89+
end
90+
fab!(:topic_disabled_2) do
91+
Fabricate(
92+
:custom_topic,
93+
user: user,
94+
category: category_disabled,
95+
custom_topic_name: "another_custom_field",
96+
)
97+
end
98+
fab!(:post_unsolved) { Fabricate(:post, topic: topic_unsolved) }
99+
fab!(:post_solved) do
100+
post = Fabricate(:post, topic: topic_solved)
101+
DiscourseSolved.accept_answer!(post, Discourse.system_user)
102+
post
103+
end
104+
fab!(:post_disabled_1) { Fabricate(:post, topic: topic_disabled_1) }
105+
fab!(:post_disabled_2) { Fabricate(:post, topic: topic_disabled_2) }
106+
107+
before do
108+
SearchIndexer.enable
109+
Jobs.run_immediately!
110+
111+
SearchIndexer.index(topic_unsolved, force: true)
112+
SearchIndexer.index(topic_solved, force: true)
113+
SearchIndexer.index(topic_disabled_1, force: true)
114+
SearchIndexer.index(topic_disabled_2, force: true)
115+
end
116+
117+
after { SearchIndexer.disable }
118+
119+
describe "searches for unsolved topics" do
120+
describe "when allow solved on all topics is disabled" do
121+
before { SiteSetting.allow_solved_on_all_topics = false }
122+
123+
it "only returns posts where 'Allow topic owner and staff to mark a reply as the solution' is enabled and post is not solved" do
124+
result = Search.execute("status:unsolved")
125+
expect(result.posts.pluck(:id)).to match_array([post_unsolved.id])
126+
end
127+
end
128+
describe "when allow solved on all topics is enabled" do
129+
before { SiteSetting.allow_solved_on_all_topics = true }
130+
it "only returns posts where the post is not solved" do
131+
result = Search.execute("status:unsolved")
132+
expect(result.posts.pluck(:id)).to match_array(
133+
[post_unsolved.id, post_disabled_1.id, post_disabled_2.id],
134+
)
135+
end
136+
end
137+
end
138+
end
42139
end
43140

44141
describe "auto bump" do

0 commit comments

Comments
 (0)