Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: Prevents assign notification & change status on solved #285

Merged
merged 12 commits into from Apr 26, 2024
Merged
7 changes: 7 additions & 0 deletions about.json
@@ -0,0 +1,7 @@
{
"tests": {
"requiredPlugins": [
"https://github.com/discourse/discourse-assign"
]
}
}
30 changes: 30 additions & 0 deletions app/lib/plugin_initializer.rb
@@ -0,0 +1,30 @@
# frozen_string_literal: true

module DiscourseSolved
class PluginInitializer
attr_reader :plugin

def initialize(plugin)
@plugin = plugin
end

def apply_plugin_api
# this method should be overridden by subclasses
raise NotImplementedError
end
end

class AssignsReminderForTopicsQuery < PluginInitializer
def apply_plugin_api
plugin.register_modifier(:assigns_reminder_assigned_topics_query) do |query|
next query if !SiteSetting.ignore_solved_topics_in_assigned_reminder
query.where.not(
id:
TopicCustomField.where(
name: ::DiscourseSolved::ACCEPTED_ANSWER_POST_ID_CUSTOM_FIELD,
).pluck(:topic_id),
)
end
end
end
end
2 changes: 2 additions & 0 deletions config/locales/server.en.yml
Expand Up @@ -11,6 +11,8 @@ en:
solved_topics_auto_close_hours: "Auto close topic (n) hours after the last reply once the topic has been marked as solved. Set to 0 to disable auto closing."
show_filter_by_solved_status: "Show a dropdown to filter a topic list by solved status."
notify_on_staff_accept_solved: "Send notification to the topic creator when a post is marked as solution by a staff."
ignore_solved_topics_in_assigned_reminder: "Prevent assigned reminder from including solved topics. only relevant when discourse-assign."
assignment_status_on_solve: "When a topic is solved update all assignments to this status"
disable_solved_education_message: "Disable education message for solved topics."
accept_solutions_topic_author: "Allow the topic author to accept a solution."
solved_add_schema_markup: "Add QAPage schema markup to HTML."
Expand Down
5 changes: 5 additions & 0 deletions config/settings.yml
Expand Up @@ -32,6 +32,11 @@ discourse_solved:
client: true
notify_on_staff_accept_solved:
default: false
ignore_solved_topics_in_assigned_reminder:
default: false
assignment_status_on_solve:
type: string
default: ""
disable_solved_education_message:
default: false
accept_solutions_topic_author:
Expand Down
12 changes: 12 additions & 0 deletions plugin.rb
Expand Up @@ -47,6 +47,8 @@ class Engine < ::Rails::Engine
require_relative "app/lib/web_hook_extension"
require_relative "app/serializers/concerns/topic_answer_mixin"

require_relative "app/lib/plugin_initializer"
DiscourseSolved::AssignsReminderForTopicsQuery.new(self).apply_plugin_api
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a better way to do this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When there is only one... probably not. If there were multiple files you would loop over each at require, apply each one. This is probably fine. Although the name of the file should be more specific. Like app/lib/plugin_initializer.rb -> lib/plugin_initializers/assigned_reminder_exclude_solved.rb

module ::DiscourseSolved
def self.accept_answer!(post, acting_user, topic: nil)
topic ||= post.topic
Expand Down Expand Up @@ -622,4 +624,14 @@ def self.skip_db?
end
end
end

if defined?(DiscourseAssign)
on(:accepted_solution) do |post|
next if SiteSetting.assignment_status_on_solve.blank?
Assigner.new(post.topic, post.acting_user).assign(
post.acting_user,
status: SiteSetting.assignment_status_on_solve,
)
end
end
end
57 changes: 57 additions & 0 deletions spec/integration/solved_spec.rb
Expand Up @@ -366,4 +366,61 @@
expect(response.status).to eq(200)
end
end

context "with discourse-assign installed", if: defined?(DiscourseAssign) do
let(:admin) { Fabricate(:admin) }
fab!(:group)

before do
SiteSetting.solved_enabled = true
SiteSetting.assign_enabled = true
SiteSetting.enable_assign_status = true
SiteSetting.assign_allowed_on_groups = "#{group.id}"
SiteSetting.assigns_public = true
SiteSetting.assignment_status_on_solve = "Done"

group.add(p1.acting_user)
group.add(user)

sign_in(user)
end

it "update all assignments to this status when a post is accepted" do
assigner = Assigner.new(p1.topic, user)
result = assigner.assign(user)
expect(result[:success]).to eq(true)

expect(p1.topic.assignment.status).to eq("New")
DiscourseSolved.accept_answer!(p1, user)

expect(p1.reload.custom_fields["is_accepted_answer"]).to eq("true")
expect(p1.topic.assignment.reload.status).to eq("Done")
end
end

context "with using assigns_reminder_assigned_topics_query modifier" do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know on this looking at it again. Since the test above relies directly on the discourse-assign plugin, maybe calling the AssignReminder class directly for testing is best? @jjaffeux want to weigh in here as well?

class DummyClass
def test
DiscoursePluginRegistry.apply_modifier(:assigns_reminder_assigned_topics_query, Topic.all)
end
end

before { SiteSetting.ignore_solved_topics_in_assigned_reminder = true }

it "should not include solved topics in the query" do
topic = Fabricate(:topic)
topic2 = Fabricate(:topic)
topic3 = Fabricate(:topic)
post = Fabricate(:post, topic: topic)

DiscourseSolved.accept_answer!(post, Discourse.system_user)

topics = DummyClass.new.test.to_a

expect(topics).not_to include(topic)

expect(topics).to include(topic2)
expect(topics).to include(topic3)
end
end
end