diff --git a/about.json b/about.json new file mode 100644 index 0000000..0ab5dbc --- /dev/null +++ b/about.json @@ -0,0 +1,7 @@ +{ + "tests": { + "requiredPlugins": [ + "https://github.com/discourse/discourse-assign" + ] + } +} diff --git a/app/lib/plugin_initializers/assigned_reminder_exclude_solved.rb b/app/lib/plugin_initializers/assigned_reminder_exclude_solved.rb new file mode 100644 index 0000000..f3aa8f8 --- /dev/null +++ b/app/lib/plugin_initializers/assigned_reminder_exclude_solved.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 diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index faef853..ff72237 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -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." diff --git a/config/settings.yml b/config/settings.yml index 21e9ba1..5e67f0b 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -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: diff --git a/plugin.rb b/plugin.rb index 9ee53c1..701c303 100644 --- a/plugin.rb +++ b/plugin.rb @@ -45,6 +45,8 @@ after_initialize do require_relative "app/lib/web_hook_extension" require_relative "app/serializers/concerns/topic_answer_mixin" + require_relative "app/lib/plugin_initializers/assigned_reminder_exclude_solved" + DiscourseSolved::AssignsReminderForTopicsQuery.new(self).apply_plugin_api module ::DiscourseSolved def self.accept_answer!(post, acting_user, topic: nil) topic ||= post.topic @@ -585,4 +587,14 @@ after_initialize do required: true 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 diff --git a/spec/integration/solved_spec.rb b/spec/integration/solved_spec.rb index 898edfb..3dea06c 100644 --- a/spec/integration/solved_spec.rb +++ b/spec/integration/solved_spec.rb @@ -428,4 +428,62 @@ RSpec.describe "Managing Posts solved status" do 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" + SiteSetting.ignore_solved_topics_in_assigned_reminder = false + group.add(p1.acting_user) + group.add(user) + + sign_in(user) + end + describe "updating assignment status on solve when assignment_status_on_solve is set" do + 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 + + describe "assigned topic reminder" + it "excludes solved topics when ignore_solved_topics_in_assigned_reminder is false" do + other_topic = Fabricate(:topic, title: "Topic that should be there") + post = Fabricate(:post, topic: other_topic, user: user) + + other_topic2 = Fabricate(:topic, title: "Topic that should be there2") + post2 = Fabricate(:post, topic: other_topic2, user: user) + + Assigner.new(post.topic, user).assign(user) + Assigner.new(post2.topic, user).assign(user) + + reminder = PendingAssignsReminder.new + topics = reminder.send(:assigned_topics, user, order: :asc) + expect(topics.to_a.length).to eq(2) + + DiscourseSolved.accept_answer!(post2, Discourse.system_user) + topics = reminder.send(:assigned_topics, user, order: :asc) + expect(topics.to_a.length).to eq(2) + expect(topics).to include(other_topic2) + + SiteSetting.ignore_solved_topics_in_assigned_reminder = true + topics = reminder.send(:assigned_topics, user, order: :asc) + expect(topics.to_a.length).to eq(1) + expect(topics).not_to include(other_topic2) + expect(topics).to include(other_topic) + end + end + end end