mirror of
https://github.com/discourse/discourse-solved.git
synced 2025-05-06 08:28:29 +00:00
* FEATURE: Publish WebHook event when solving/unsolving This feature will publish a post edit webhook event whenever a solution is accepted or unaccepted. I went ahead and used the existing post-edit webhook because all the post custom fields for the solved plugin are already included in the post-edit serializer. * Create Solved Event Webhook This commit adds a solved event webhook that will only trigger when an answer has been marked as accepted or unaccepted. It uses 100 as the webhook ID. This way any new webhooks in core can keep using lower numbers like 11, 12, 13, but plugins can use 101, 102, etc. * Removed functionality that was added to core This [PR][1] to discourse core adds what what removed in this commit. It is better to have this logic in core so that it is discoverable and future webhooks won't end up accidentally using the same ID. [1]: https://github.com/discourse/discourse/pull/9110 * UX: Add "solved" status filter in advanced search page. And rename `in:solved` to `status:solved`. * FEATURE: Publish WebHook event when solving/unsolving This feature will publish a post edit webhook event whenever a solution is accepted or unaccepted. I went ahead and used the existing post-edit webhook because all the post custom fields for the solved plugin are already included in the post-edit serializer. * Create Solved Event Webhook This commit adds a solved event webhook that will only trigger when an answer has been marked as accepted or unaccepted. It uses 100 as the webhook ID. This way any new webhooks in core can keep using lower numbers like 11, 12, 13, but plugins can use 101, 102, etc. * Removed functionality that was added to core This [PR][1] to discourse core adds what what removed in this commit. It is better to have this logic in core so that it is discoverable and future webhooks won't end up accidentally using the same ID. [1]: https://github.com/discourse/discourse/pull/9110 Co-authored-by: Vinoth Kannan <vinothkannan@vinkas.com>
152 lines
4.2 KiB
Ruby
152 lines
4.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
require_relative '../fabricators/solved_hook_fabricator.rb'
|
|
|
|
RSpec.describe "Managing Posts solved status" do
|
|
let(:topic) { Fabricate(:topic) }
|
|
let(:user) { Fabricate(:trust_level_4) }
|
|
let(:p1) { Fabricate(:post, topic: topic) }
|
|
|
|
before do
|
|
SiteSetting.allow_solved_on_all_topics = true
|
|
end
|
|
|
|
describe 'auto bump' do
|
|
it 'does not automatically bump solved topics' do
|
|
category = Fabricate(:category_with_definition)
|
|
|
|
post = create_post(category: category)
|
|
post2 = create_post(category: category)
|
|
|
|
DiscourseSolved.accept_answer!(post, Discourse.system_user)
|
|
|
|
category.num_auto_bump_daily = 2
|
|
category.save!
|
|
|
|
freeze_time 1.month.from_now
|
|
|
|
expect(category.auto_bump_topic!).to eq(true)
|
|
|
|
freeze_time 13.hours.from_now
|
|
|
|
expect(category.auto_bump_topic!).to eq(false)
|
|
|
|
expect(post.topic.reload.posts_count).to eq(1)
|
|
expect(post2.topic.reload.posts_count).to eq(2)
|
|
end
|
|
end
|
|
|
|
describe 'accepting a post as the answer' do
|
|
before do
|
|
sign_in(user)
|
|
SiteSetting.solved_topics_auto_close_hours = 2
|
|
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.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 eq_time(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
|
|
|
|
expect(p1.custom_fields["is_accepted_answer"]).to eq("true")
|
|
expect(topic.public_topic_timer).to eq(nil)
|
|
expect(topic.closed).to eq(true)
|
|
end
|
|
|
|
it 'works with staff and trashed topics' do
|
|
topic.trash!(Discourse.system_user)
|
|
|
|
post "/solution/accept.json", params: { id: p1.id }
|
|
expect(response.status).to eq(403)
|
|
|
|
sign_in(Fabricate(:admin))
|
|
post "/solution/accept.json", params: { id: p1.id }
|
|
expect(response.status).to eq(200)
|
|
|
|
p1.reload
|
|
expect(p1.custom_fields["is_accepted_answer"]).to eq("true")
|
|
end
|
|
|
|
it 'does not allow you to accept a whisper' do
|
|
whisper = Fabricate(:post, topic: topic, post_type: Post.types[:whisper])
|
|
sign_in(Fabricate(:admin))
|
|
|
|
post "/solution/accept.json", params: { id: whisper.id }
|
|
expect(response.status).to eq(403)
|
|
end
|
|
|
|
it 'triggers a webhook' do
|
|
Fabricate(:solved_web_hook)
|
|
post "/solution/accept.json", params: { id: p1.id }
|
|
|
|
job_args = Jobs::EmitWebHookEvent.jobs[0]["args"].first
|
|
|
|
expect(job_args["event_name"]).to eq("accepted_solution")
|
|
payload = JSON.parse(job_args["payload"])
|
|
expect(payload["id"]).to eq(p1.id)
|
|
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
|
|
|
|
it 'triggers a webhook' do
|
|
Fabricate(:solved_web_hook)
|
|
post "/solution/unaccept.json", params: { id: p1.id }
|
|
|
|
job_args = Jobs::EmitWebHookEvent.jobs[0]["args"].first
|
|
|
|
expect(job_args["event_name"]).to eq("unaccepted_solution")
|
|
payload = JSON.parse(job_args["payload"])
|
|
expect(payload["id"]).to eq(p1.id)
|
|
end
|
|
end
|
|
end
|