DEV: adds an automation script for first accepted solution (#172)
This commit is contained in:
parent
6767d8c60b
commit
9b8aa09855
|
@ -0,0 +1,19 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class FirstAcceptedPostSolutionValidator
|
||||||
|
def self.check(post, trust_level:)
|
||||||
|
return false if post.archetype != Archetype.default
|
||||||
|
return false if !post&.user&.human?
|
||||||
|
return true if trust_level == 'any'
|
||||||
|
|
||||||
|
if TrustLevel.compare(post&.user&.trust_level, trust_level.to_i)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if !UserAction.where(user_id: post&.user_id, action_type: UserAction::SOLVED).exists?
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
|
@ -42,3 +42,17 @@ en:
|
||||||
solved_event:
|
solved_event:
|
||||||
name: "Solved Event"
|
name: "Solved Event"
|
||||||
details: "When a user marks a post as the accepted or unaccepted answer."
|
details: "When a user marks a post as the accepted or unaccepted answer."
|
||||||
|
|
||||||
|
discourse_automation:
|
||||||
|
triggerables:
|
||||||
|
first_accepted_solution:
|
||||||
|
max_trust_level:
|
||||||
|
tl1: < TL1
|
||||||
|
tl2: < TL2
|
||||||
|
tl3: < TL3
|
||||||
|
tl4: < TL4
|
||||||
|
any: Any
|
||||||
|
fields:
|
||||||
|
maximum_trust_level:
|
||||||
|
label: Trust Level
|
||||||
|
description: Users under this Trust Level will trigger this automation
|
||||||
|
|
|
@ -33,6 +33,12 @@ en:
|
||||||
name: "Tech Support"
|
name: "Tech Support"
|
||||||
description: "10 Accepted answers"
|
description: "10 Accepted answers"
|
||||||
|
|
||||||
|
discourse_automation:
|
||||||
|
triggerables:
|
||||||
|
first_accepted_solution:
|
||||||
|
title: First accepted solution
|
||||||
|
doc: Triggers when a user got a solution accepted for the first time.
|
||||||
|
|
||||||
education:
|
education:
|
||||||
topic_is_solved: |
|
topic_is_solved: |
|
||||||
### This topic has been solved
|
### This topic has been solved
|
||||||
|
|
42
plugin.rb
42
plugin.rb
|
@ -24,6 +24,7 @@ after_initialize do
|
||||||
SeedFu.fixture_paths << Rails.root.join("plugins", "discourse-solved", "db", "fixtures").to_s
|
SeedFu.fixture_paths << Rails.root.join("plugins", "discourse-solved", "db", "fixtures").to_s
|
||||||
|
|
||||||
[
|
[
|
||||||
|
'../app/lib/first_accepted_post_solution_validator.rb',
|
||||||
'../app/serializers/concerns/topic_answer_mixin.rb'
|
'../app/serializers/concerns/topic_answer_mixin.rb'
|
||||||
].each { |path| load File.expand_path(path, __FILE__) }
|
].each { |path| load File.expand_path(path, __FILE__) }
|
||||||
|
|
||||||
|
@ -752,4 +753,45 @@ SQL
|
||||||
prepend AddSolvedToTopicPostersSummary
|
prepend AddSolvedToTopicPostersSummary
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if defined?(DiscourseAutomation)
|
||||||
|
if respond_to?(:add_triggerable_to_scriptable)
|
||||||
|
on(:accepted_solution) do |post|
|
||||||
|
# testing directly automation is prone to issues
|
||||||
|
# we prefer to abstract logic in service object and test this
|
||||||
|
next if Rails.env.test?
|
||||||
|
|
||||||
|
name = 'first_accepted_solution'
|
||||||
|
DiscourseAutomation::Automation.where(trigger: name, enabled: true).find_each do |automation|
|
||||||
|
maximum_trust_level = automation.trigger_field('maximum_trust_level')&.dig('value')
|
||||||
|
if FirstAcceptedPostSolutionValidator.check(post, trust_level: maximum_trust_level)
|
||||||
|
automation.trigger!(
|
||||||
|
'kind' => name,
|
||||||
|
'accepted_post_id' => post.id,
|
||||||
|
'usernames' => [post.user.username],
|
||||||
|
'placeholders' => {
|
||||||
|
'post_url' => Discourse.base_url + post.url
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
TRUST_LEVELS = [
|
||||||
|
{ id: 1, name: 'discourse_automation.triggerables.first_accepted_solution.max_trust_level.tl1' },
|
||||||
|
{ id: 2, name: 'discourse_automation.triggerables.first_accepted_solution.max_trust_level.tl2' },
|
||||||
|
{ id: 3, name: 'discourse_automation.triggerables.first_accepted_solution.max_trust_level.tl3' },
|
||||||
|
{ id: 4, name: 'discourse_automation.triggerables.first_accepted_solution.max_trust_level.tl4' },
|
||||||
|
{ id: 'any', name: 'discourse_automation.triggerables.first_accepted_solution.max_trust_level.any' },
|
||||||
|
]
|
||||||
|
|
||||||
|
add_triggerable_to_scriptable(:first_accepted_solution, :send_pms)
|
||||||
|
|
||||||
|
DiscourseAutomation::Triggerable.add(:first_accepted_solution) do
|
||||||
|
placeholder :post_url
|
||||||
|
|
||||||
|
field :maximum_trust_level, component: :choices, extra: { content: TRUST_LEVELS }, required: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe FirstAcceptedPostSolutionValidator do
|
||||||
|
fab!(:user_tl1) { Fabricate(:user, trust_level: TrustLevel[1]) }
|
||||||
|
|
||||||
|
context 'user is under max trust level' do
|
||||||
|
context 'has no post accepted yet' do
|
||||||
|
it 'validates the post' do
|
||||||
|
post_1 = create_post(user: user_tl1)
|
||||||
|
expect(described_class.check(post_1, trust_level: TrustLevel[2])).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'has already had accepted posts' do
|
||||||
|
before do
|
||||||
|
accepted_post = create_post(user: user_tl1)
|
||||||
|
DiscourseSolved.accept_answer!(accepted_post, Discourse.system_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'doesn’t validate the post' do
|
||||||
|
post_1 = create_post(user: user_tl1)
|
||||||
|
expect(described_class.check(post_1, trust_level: TrustLevel[2])).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'user is above or equal max trust level' do
|
||||||
|
context 'has no post accepted yet' do
|
||||||
|
it 'doesn’t validate the post' do
|
||||||
|
post_1 = create_post(user: user_tl1)
|
||||||
|
expect(described_class.check(post_1, trust_level: TrustLevel[1])).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'has already had accepted posts' do
|
||||||
|
before do
|
||||||
|
accepted_post = create_post(user: user_tl1)
|
||||||
|
DiscourseSolved.accept_answer!(accepted_post, Discourse.system_user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'doesn’t validate the post' do
|
||||||
|
post_1 = create_post(user: user_tl1)
|
||||||
|
expect(described_class.check(post_1, trust_level: TrustLevel[1])).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'using any trust level' do
|
||||||
|
it 'validates the post' do
|
||||||
|
post_1 = create_post(user: user_tl1)
|
||||||
|
expect(described_class.check(post_1, trust_level: 'any')).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'user is system' do
|
||||||
|
it 'doesn’t validate the post' do
|
||||||
|
post_1 = create_post(user: Discourse.system_user)
|
||||||
|
expect(described_class.check(post_1, trust_level: 'any')).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'post is a PM' do
|
||||||
|
it 'doesn’t validate the post' do
|
||||||
|
post_1 = create_post(user: user_tl1, target_usernames: [user_tl1.username], archetype: Archetype.private_message)
|
||||||
|
expect(described_class.check(post_1, trust_level: 'any')).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue