Skip to content
This repository was archived by the owner on Jul 22, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/ai_helper/assistant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ def generate_prompt(
json_summary_schema_key = bot.persona.response_format&.first.to_h
helper_chunk = partial.read_buffered_property(json_summary_schema_key["key"]&.to_sym)

if helper_chunk.present?
if !helper_chunk.nil? && !helper_chunk.empty?
helper_response << helper_chunk
block.call(helper_chunk) if block
end
Expand Down
13 changes: 13 additions & 0 deletions lib/personas/tools/researcher.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def filter_description
- status:open|closed|archived|noreplies|single_user - topic status filters
- max_results:N - limit results (per OR group)
- order:latest|oldest|latest_topic|oldest_topic|likes - sort order
#{assign_tip}

**OR Logic:** Each OR group processes independently - filters don't cross boundaries.

Expand All @@ -56,6 +57,16 @@ def filter_description
TEXT
end

def assign_tip
if SiteSetting.respond_to?(:assign_enabled) && SiteSetting.assign_enabled
(<<~TEXT).strip
assigned_to:username or assigned_to:username1,username2 - topics assigned to a specific user
assigned_to:* - topics assigned to any user
assigned_to:nobody - topics not assigned to any user
TEXT
end
end

def name
"researcher"
end
Expand Down Expand Up @@ -113,6 +124,8 @@ def invoke(&blk)
else
process_filter(filter, goals, post, &blk)
end
rescue StandardError => e
{ error: "Error processing research: #{e.message}" }
end

def details
Expand Down
2 changes: 1 addition & 1 deletion lib/summarization/fold_content.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def fold(items, user, &on_partial_blk)
partial_summary =
partial.read_buffered_property(json_summary_schema_key["key"]&.to_sym)

if partial_summary.present?
if !partial_summary.nil? && !partial_summary.empty?
summary << partial_summary
on_partial_blk.call(partial_summary) if on_partial_blk
end
Expand Down
28 changes: 28 additions & 0 deletions lib/utils/research/filter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,34 @@ def self.word_to_date(str)
end
end

def self.assign_allowed?(guardian)
SiteSetting.respond_to?(:assign_enabled) && SiteSetting.assign_enabled &&
(guardian.can_assign? || SiteSetting.assigns_public)
end

register_filter(/\Aassigned_to:(.+)\z/i) do |relation, name, filter|
if !assign_allowed?(filter.guardian)
raise Discourse::InvalidAccess.new(
"Assigns are not enabled or you do not have permission to see assigns.",
)
end

if (name == "nobody")
relation.joins("LEFT JOIN assignments a ON a.topic_id = topics.id AND a.active").where(
"a.assigned_to_id IS NULL",
)
elsif name == "*"
relation.joins("JOIN assignments a ON a.topic_id = topics.id AND a.active").where(
"a.assigned_to_id IS NOT NULL",
)
else
usernames = name.split(",").map(&:strip).map(&:downcase)
relation.joins("JOIN assignments a ON a.topic_id = topics.id AND a.active").where(
"a.assigned_to_id" => User.where(username_lower: usernames).select(:id),
)
end
end

register_filter(/\Agroups?:([a-zA-Z0-9_\-,]+)\z/i) do |relation, groups_param, filter|
if groups_param.include?(",")
group_names = groups_param.split(",").map(&:strip)
Expand Down
47 changes: 47 additions & 0 deletions spec/lib/utils/research/filter_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@
fab!(:bug_post) { Fabricate(:post, topic: bug_topic, user: user) }
fab!(:feature_bug_post) { Fabricate(:post, topic: feature_bug_topic, user: user) }
fab!(:no_tag_post) { Fabricate(:post, topic: no_tag_topic, user: user) }
fab!(:admin1) { Fabricate(:admin, username: "admin1") }
fab!(:admin2) { Fabricate(:admin, username: "admin2") }

describe "group filtering" do
before do
Expand Down Expand Up @@ -192,6 +194,51 @@
end
end

if SiteSetting.respond_to?(:assign_enabled)
describe "assign filtering" do
before do
SiteSetting.assign_enabled = true
assigner = Assigner.new(feature_topic, admin1)
assigner.assign(admin1)

assigner = Assigner.new(bug_topic, admin1)
assigner.assign(admin2)
end

let(:admin_guardian) { Guardian.new(admin1) }

it "can find topics assigned to a user" do
filter = described_class.new("assigned_to:#{admin1.username}", guardian: admin_guardian)
expect(filter.search.pluck(:id)).to contain_exactly(feature_post.id)
end

it "can find topics assigned to multiple users" do
filter =
described_class.new(
"assigned_to:#{admin1.username},#{admin2.username}",
guardian: admin_guardian,
)
expect(filter.search.pluck(:id)).to contain_exactly(feature_post.id, bug_post.id)
end

it "can find topics assigned to nobody" do
filter = described_class.new("assigned_to:nobody", guardian: admin_guardian)
expect(filter.search.pluck(:id)).to contain_exactly(feature_bug_post.id, no_tag_post.id)
end

it "can find all assigned topics" do
filter = described_class.new("assigned_to:*", guardian: admin_guardian)
expect(filter.search.pluck(:id)).to contain_exactly(feature_post.id, bug_post.id)
end

it "raises an error if assigns are disabled" do
SiteSetting.assign_enabled = false
filter = described_class.new("assigned_to:sam")
expect { filter.search }.to raise_error(Discourse::InvalidAccess)
end
end
end

it "can limit number of results" do
filter = described_class.new("category:Feedback max_results:1", limit: 5)
expect(filter.search.pluck(:id).length).to eq(1)
Expand Down
Loading