diff --git a/plugin.rb b/plugin.rb index 62962c1..3b8986d 100644 --- a/plugin.rb +++ b/plugin.rb @@ -61,25 +61,28 @@ SQL isolate_namespace DiscourseSolved end + AUTO_CLOSE_TOPIC_TIMER_CUSTOM_FIELD = "solved_auto_close_topic_timer_id".freeze + def self.accept_answer!(post, acting_user) topic = post.topic - accepted_id = topic.custom_fields["accepted_answer_post_id"].to_i + if accepted_id > 0 if p2 = Post.find_by(id: accepted_id) p2.custom_fields["is_accepted_answer"] = nil p2.save! if defined?(UserAction::SOLVED) - UserAction.where(action_type: UserAction::SOLVED, target_post_id: p2.id).destroy_all + UserAction.where( + action_type: UserAction::SOLVED, + target_post_id: p2.id + ).destroy_all end end end post.custom_fields["is_accepted_answer"] = "true" topic.custom_fields["accepted_answer_post_id"] = post.id - topic.save! - post.save! if defined?(UserAction::SOLVED) UserAction.log_action!( @@ -105,23 +108,40 @@ SQL ) end - if (auto_close_hours = SiteSetting.solved_topics_auto_close_hours) > (0) && !topic.closed - topic.set_or_create_timer( + auto_close_hours = SiteSetting.solved_topics_auto_close_hours + + if (auto_close_hours > 0) && !topic.closed + topic_timer = topic.set_or_create_timer( TopicTimer.types[:close], auto_close_hours, based_on_last_post: true ) + topic.custom_fields[ + AUTO_CLOSE_TOPIC_TIMER_CUSTOM_FIELD + ] = topic_timer.id + MessageBus.publish("/topic/#{topic.id}", reload_topic: true) end + topic.save! + post.save! + DiscourseEvent.trigger(:accepted_solution, post) end def self.unaccept_answer!(post) post.custom_fields["is_accepted_answer"] = nil post.topic.custom_fields["accepted_answer_post_id"] = nil - post.topic.save! + topic = post.topic + + if timer_id = topic.custom_fields[AUTO_CLOSE_TOPIC_TIMER_CUSTOM_FIELD] + topic_timer = TopicTimer.find_by(id: timer_id) + topic_timer.destroy! if topic_timer + topic.custom_fields[AUTO_CLOSE_TOPIC_TIMER_CUSTOM_FIELD] = nil + end + + topic.save! post.save! # TODO remove_action! does not allow for this type of interface @@ -134,14 +154,13 @@ SQL # yank notification notification = Notification.find_by( - notification_type: Notification.types[:custom], - user_id: post.user_id, - topic_id: post.topic_id, - post_number: post.post_number + notification_type: Notification.types[:custom], + user_id: post.user_id, + topic_id: post.topic_id, + post_number: post.post_number ) notification.destroy! if notification - DiscourseEvent.trigger(:unaccepted_solution, post) end end diff --git a/spec/integration/solved_spec.rb b/spec/integration/solved_spec.rb index ed9811a..d6a829b 100644 --- a/spec/integration/solved_spec.rb +++ b/spec/integration/solved_spec.rb @@ -41,20 +41,32 @@ RSpec.describe "Managing Posts solved status" do end it 'can mark a post as the accepted answer correctly' do + freeze_time + post "/solution/accept.json", params: { id: p1.id } + expect(response.status).to eq(200) expect(p1.reload.custom_fields["is_accepted_answer"]).to eq("true") - expect(topic.public_topic_timer.status_type).to eq(TopicTimer.types[:close]) + expect(topic.public_topic_timer.status_type) + .to eq(TopicTimer.types[:close]) + + expect(topic.custom_fields[ + DiscourseSolved::AUTO_CLOSE_TOPIC_TIMER_CUSTOM_FIELD + ].to_i).to eq(topic.public_topic_timer.id) expect(topic.public_topic_timer.execute_at) - .to be_within(1.second).of(Time.zone.now + 2.hours) + .to eq(Time.zone.now + 2.hours) expect(topic.public_topic_timer.based_on_last_post).to eq(true) end + it 'does not set a timer when the topic is closed' do topic.update!(closed: true) post "/solution/accept.json", params: { id: p1.id } + + expect(response.status).to eq(200) + p1.reload topic.reload @@ -63,4 +75,29 @@ RSpec.describe "Managing Posts solved status" do expect(topic.closed).to eq(true) end end + + describe '#unaccept' do + before do + sign_in(user) + end + + describe 'when solved_topics_auto_close_hours is enabled' do + before do + SiteSetting.solved_topics_auto_close_hours = 2 + DiscourseSolved.accept_answer!(p1, user) + end + + it 'should unmark the post as solved' do + expect do + post "/solution/unaccept.json", params: { id: p1.id } + end.to change { topic.reload.public_topic_timer }.to(nil) + + expect(response.status).to eq(200) + p1.reload + + expect(p1.custom_fields["is_accepted_answer"]).to eq(nil) + expect(p1.topic.custom_fields["accepted_answer_post_id"]).to eq(nil) + end + end + end end