Add helper method to intelligently create new rules (avoiding duplicates)

This commit is contained in:
David Taylor 2017-07-06 01:11:26 +01:00
parent fd333d59b7
commit aa6430e23e
2 changed files with 147 additions and 0 deletions

View File

@ -1,6 +1,7 @@
module DiscourseChat module DiscourseChat
module Helper module Helper
# Produce a string with a list of all rules associated with a channel
def self.status_for_channel(provider, channel) def self.status_for_channel(provider, channel)
rules = DiscourseChat::Rule.all_for_channel(provider, channel) rules = DiscourseChat::Rule.all_for_channel(provider, channel)
@ -40,6 +41,61 @@ module DiscourseChat
return text return text
end end
# Create a rule for a specific channel
# Designed to be used by provider's "Slash commands"
# Will intelligently adjust existing rules to avoid duplicates
# Returns
# :updated if an existing rule has been updated
# :created if a new rule has been created
# false if there was an error
def self.smart_create_rule(provider:, channel:, filter:, category_id:, tags:)
existing_rules = DiscourseChat::Rule.all_for_channel(provider, channel)
# Select the ones that have the same category
same_category = existing_rules.select { |rule| rule.category_id == category_id }
same_category_and_tags = same_category.select{ |rule| (rule.tags.nil? ? [] : rule.tags.sort) == (tags.nil? ? [] : tags.sort) }
if same_category_and_tags.size > 0
# These rules have exactly the same criteria as what we're trying to create
the_rule = same_category_and_tags.shift # Take out the first one
same_category_and_tags.each do |rule| # Destroy all the others - they're duplicates
rule.destroy
end
return :updated if the_rule.update(filter:filter) # Update the filter
return false # Error, probably validation
end
same_category_and_filters = same_category.select { |rule| rule.filter == filter }
if same_category_and_filters.size > 0
# These rules are exactly the same, except for tags. Let's combine the tags together
tags = [] if tags.nil?
same_category_and_filters.each do |rule|
tags = tags | rule.tags unless rule.tags.nil? # Append the tags together, avoiding duplicates by magic
end
the_rule = same_category_and_filters.shift # Take out the first one
if the_rule.update(tags: tags) # Update the tags
same_category_and_filters.each do |rule| # Destroy all the others - they're duplicates
rule.destroy
end
return :updated
end
return false # Error
end
# This rule is unique! Create a new one:
return :created if Rule.new({provider: provider, channel: channel, filter: filter, category_id: category_id, tags: tags}).save
return false # Error
end
end end
end end

View File

@ -4,6 +4,8 @@ RSpec.describe DiscourseChat::Manager do
let(:category) {Fabricate(:category)} let(:category) {Fabricate(:category)}
let(:tag1){Fabricate(:tag)} let(:tag1){Fabricate(:tag)}
let(:tag2){Fabricate(:tag)}
let(:tag3){Fabricate(:tag)}
describe '.status_for_channel' do describe '.status_for_channel' do
@ -54,4 +56,93 @@ RSpec.describe DiscourseChat::Manager do
end end
describe '.smart_create_rule' do
it 'creates a rule when there are none' do
val = DiscourseChat::Helper.smart_create_rule(provider: 'slack',
channel: '#general',
filter: 'watch',
category_id: category.id,
tags: [tag1.name]
)
expect(val).to eq(:created)
record = DiscourseChat::Rule.all.first
expect(record.provider).to eq('slack')
expect(record.channel).to eq('#general')
expect(record.filter).to eq('watch')
expect(record.category_id).to eq(category.id)
expect(record.tags).to eq([tag1.name])
end
it 'updates a rule when it has the same category and tags' do
existing = DiscourseChat::Rule.new({provider: 'slack',
channel: '#general',
filter: 'watch',
category_id: category.id,
tags: [tag2.name, tag1.name]
}).save!
val = DiscourseChat::Helper.smart_create_rule(provider: 'slack',
channel: '#general',
filter: 'mute',
category_id: category.id,
tags: [tag1.name, tag2.name]
)
expect(val).to eq(:updated)
expect(DiscourseChat::Rule.all.size).to eq(1)
expect(DiscourseChat::Rule.all.first.filter).to eq('mute')
end
it 'updates a rule when it has the same category and filter' do
existing = DiscourseChat::Rule.new({provider: 'slack',
channel: '#general',
filter: 'watch',
category_id: category.id,
tags: [tag1.name, tag2.name]
}).save!
val = DiscourseChat::Helper.smart_create_rule(provider: 'slack',
channel: '#general',
filter: 'watch',
category_id: category.id,
tags: [tag1.name, tag3.name]
)
expect(val).to eq(:updated)
expect(DiscourseChat::Rule.all.size).to eq(1)
expect(DiscourseChat::Rule.all.first.tags).to contain_exactly(tag1.name, tag2.name, tag3.name)
end
it 'destroys duplicate rules on save' do
DiscourseChat::Rule.new({provider: 'slack', channel: '#general', filter: 'watch'}).save!
DiscourseChat::Rule.new({provider: 'slack', channel: '#general', filter: 'watch'}).save!
expect(DiscourseChat::Rule.all.size).to eq(2)
val = DiscourseChat::Helper.smart_create_rule(provider: 'slack',
channel: '#general',
filter: 'watch',
category_id: nil,
tags: nil
)
expect(val).to eq(:updated)
expect(DiscourseChat::Rule.all.size).to eq(1)
end
it 'returns false on error' do
val = DiscourseChat::Helper.smart_create_rule(provider: 'nonexistantprovider',
channel: '#general',
filter: 'watch',
category_id: nil,
tags: nil
)
expect(val).to eq(false)
end
end
end end