Allow providers to define a data schema for their channel parameters

This commit is contained in:
David Taylor 2017-07-13 20:50:45 +01:00
parent e07a4da460
commit 4b25dcec8f
6 changed files with 86 additions and 34 deletions

View File

@ -2,28 +2,39 @@ class DiscourseChat::Channel < DiscourseChat::PluginModel
KEY_PREFIX = 'channel:'
# Setup ActiveRecord::Store to use the JSON field to read/write these values
store :value, accessors: [ :provider, :descriptor ], coder: JSON
store :value, accessors: [ :provider, :data ], coder: JSON
validate :provider_and_descriptor_valid?
after_initialize :init_data
def provider_and_descriptor_valid?
def init_data
self.data = {} if self.data.nil?
end
validate :provider_valid?, :data_valid?
def provider_valid?
# Validate provider
if not ::DiscourseChat::Provider.provider_names.include? provider
errors.add(:provider, "#{provider} is not a valid provider")
return
end
# Validate descriptor
if descriptor.blank?
errors.add(:descriptor, "channel descriptor cannot be blank")
end
def data_valid?
# If provider is invalid, don't try and check data
return unless ::DiscourseChat::Provider.provider_names.include? provider
params = ::DiscourseChat::Provider.get_by_name(provider)::CHANNEL_PARAMETERS
unless params.keys.sort == data.keys.sort
errors.add(:data, "data does not match the required structure for provider #{provider}")
return
end
provider_class = ::DiscourseChat::Provider.get_by_name(provider)
if defined? provider_class::PROVIDER_CHANNEL_REGEX
channel_regex = Regexp.new provider_class::PROVIDER_CHANNEL_REGEX
if not channel_regex.match?(descriptor)
errors.add(:descriptor, "#{descriptor} is not a valid channel descriptor for provider #{provider}")
data.each do |key, value|
regex_string = params[key]
if !Regexp.new(regex_string).match?(value)
errors.add(:data, "data.#{key} is invalid")
end
end
end

View File

@ -3,7 +3,7 @@ module DiscourseChat::Provider::SlackProvider
PROVIDER_ENABLED_SETTING = :chat_integration_slack_enabled
PROVIDER_CHANNEL_REGEX = '^[@#]\S*$'
CHANNEL_PARAMETERS = {"channel" => '^[@#]\S*$'}
def self.excerpt(post, max_length = SiteSetting.chat_integration_slack_excerpt_length)
doc = Nokogiri::HTML.fragment(post.excerpt(max_length,

View File

@ -1,10 +1,10 @@
module DiscourseChat
module Provider
module TelegramProvider
include Provider
PROVIDER_NAME = "telegram".freeze
PROVIDER_ENABLED_SETTING = :chat_integration_telegram_enabled
CHANNEL_PARAMETERS = {}
end
end
end

View File

@ -8,6 +8,8 @@ RSpec.shared_context "dummy provider" do
module ::DiscourseChat::Provider::DummyProvider
PROVIDER_NAME = "dummy".freeze
PROVIDER_ENABLED_SETTING = :chat_integration_enabled # Tie to main plugin enabled setting
CHANNEL_PARAMETERS = {}
@@sent_messages = []
@@raise_exception = nil
@ -30,9 +32,37 @@ RSpec.shared_context "dummy provider" do
end
let(:provider){::DiscourseChat::Provider::DummyProvider}
end
RSpec.shared_context "validated dummy provider" do
before(:each) do
if defined? ::DiscourseChat::Provider::Dummy2Provider
::DiscourseChat::Provider.send(:remove_const, :Dummy2Provider)
end
module ::DiscourseChat::Provider::Dummy2Provider
PROVIDER_NAME = "dummy2".freeze
PROVIDER_ENABLED_SETTING = :chat_integration_enabled # Tie to main plugin enabled setting
CHANNEL_PARAMETERS = {"val" => '\S+'}
@@sent_messages = []
def self.trigger_notification(post, channel)
@@sent_messages.push(post: post.id, channel: channel)
end
def self.sent_messages
@@sent_messages
end
end
end
let(:provider){::DiscourseChat::Provider::DummyProvider}
end
RSpec.configure do |rspec|
rspec.include_context "dummy provider"
rspec.include_context "validated dummy provider"
end

View File

@ -3,6 +3,7 @@ require_relative '../dummy_provider'
RSpec.describe DiscourseChat::Channel do
include_context "dummy provider"
include_context "validated dummy provider"
it 'should save and load successfully' do
@ -10,7 +11,6 @@ RSpec.describe DiscourseChat::Channel do
chan = DiscourseChat::Channel.create({
provider:"dummy",
descriptor: "#random",
})
expect(DiscourseChat::Channel.all.length).to eq(1)
@ -18,23 +18,22 @@ RSpec.describe DiscourseChat::Channel do
loadedChan = DiscourseChat::Channel.find(chan.id)
expect(loadedChan.provider).to eq('dummy')
expect(loadedChan.descriptor).to eq('#random')
end
it 'can be filtered by provider' do
channel1 = DiscourseChat::Channel.create({provider:'dummy', descriptor:'blah'})
channel2 = DiscourseChat::Channel.create({provider:'slack', descriptor:'#blah'})
channel3 = DiscourseChat::Channel.create({provider:'slack', descriptor:'#blah'})
channel1 = DiscourseChat::Channel.create!(provider:'dummy')
channel2 = DiscourseChat::Channel.create!(provider:'dummy2', data:{val:"blah"})
channel3 = DiscourseChat::Channel.create!(provider:'dummy2', data:{val:"blah"})
expect(DiscourseChat::Channel.all.length).to eq(3)
expect(DiscourseChat::Channel.with_provider('slack').length).to eq(2)
expect(DiscourseChat::Channel.with_provider('dummy2').length).to eq(2)
expect(DiscourseChat::Channel.with_provider('dummy').length).to eq(1)
end
it 'can find its own rules' do
channel = DiscourseChat::Channel.create({provider:'dummy', descriptor:'blah'})
channel = DiscourseChat::Channel.create({provider:'dummy'})
expect(channel.rules.size).to eq(0)
DiscourseChat::Rule.create(channel: channel)
DiscourseChat::Rule.create(channel: channel)
@ -43,21 +42,33 @@ RSpec.describe DiscourseChat::Channel do
end
describe 'validations' do
let(:channel) { DiscourseChat::Channel.create(
provider:"dummy",
descriptor: "#general"
) }
let(:channel) { }
it 'validates provider correctly' do
channel = DiscourseChat::Channel.create!(provider:"dummy")
expect(channel.valid?).to eq(true)
channel.provider = 'somerandomprovider'
expect(channel.valid?).to eq(false)
end
it 'validates channel correctly' do
expect(channel.valid?).to eq(true)
channel.descriptor = ''
expect(channel.valid?).to eq(false)
it 'succeeds with valid data' do
channel2 = DiscourseChat::Channel.new(provider:"dummy2", data:{val:"hello"})
expect(channel2.valid?).to eq(true)
end
it 'disallows invalid data' do
channel2 = DiscourseChat::Channel.new(provider:"dummy2", data:{val:''})
expect(channel2.valid?).to eq(false)
end
it 'disallows unknown keys' do
channel2 = DiscourseChat::Channel.new(provider:"dummy2", data:{val:"hello", unknown:"world"})
expect(channel2.valid?).to eq(false)
end
it 'requires all keys' do
channel2 = DiscourseChat::Channel.new(provider:"dummy2", data:{})
expect(channel2.valid?).to eq(false)
end
end

View File

@ -7,7 +7,7 @@ RSpec.describe DiscourseChat::Rule do
let(:tag1){Fabricate(:tag)}
let(:tag2){Fabricate(:tag)}
let(:channel){DiscourseChat::Channel.create(provider:'dummy', descriptor:'#general')}
let(:channel){DiscourseChat::Channel.create(provider:'dummy')}
describe '.alloc_key' do
it 'should return sequential numbers' do
@ -87,8 +87,8 @@ RSpec.describe DiscourseChat::Rule do
end
it 'can be filtered by channel' do
channel2 = DiscourseChat::Channel.create(provider:'dummy', descriptor:'#random')
channel3 = DiscourseChat::Channel.create(provider:'dummy', descriptor:'#another')
channel2 = DiscourseChat::Channel.create(provider:'dummy')
channel3 = DiscourseChat::Channel.create(provider:'dummy')
rule2 = DiscourseChat::Rule.create(channel:channel)
rule3 = DiscourseChat::Rule.create(channel:channel)