Allow providers to specify a regex that the channel identifier is checked against during validation

This commit is contained in:
David Taylor 2017-07-04 00:14:01 +01:00
parent 444e380ca1
commit 4be010fd07
10 changed files with 77 additions and 20 deletions

View File

@ -9,13 +9,15 @@ export default Ember.Controller.extend({
modalShowing: false, modalShowing: false,
actions:{ actions:{
create(provider){ create(){
this.set('modalShowing', true); this.set('modalShowing', true);
showModal('admin-plugins-chat-edit-rule', { model: this.store.createRecord('rule',{provider: provider}), admin: true }); var model = {rule: this.store.createRecord('rule',{provider: this.get('model.provider').id}), provider:this.get('model.provider')};
showModal('admin-plugins-chat-edit-rule', { model: model, admin: true });
}, },
edit(rule){ edit(rule){
this.set('modalShowing', true); this.set('modalShowing', true);
showModal('admin-plugins-chat-edit-rule', { model: rule, admin: true }); var model = {rule: rule, provider:this.get('model.provider')};
showModal('admin-plugins-chat-edit-rule', { model: model, admin: true });
}, },
delete(rule){ delete(rule){
const self = this; const self = this;

View File

@ -2,11 +2,45 @@ import Rule from 'discourse/plugins/discourse-chat-integration/admin/models/rule
import ModalFunctionality from 'discourse/mixins/modal-functionality'; import ModalFunctionality from 'discourse/mixins/modal-functionality';
import { ajax } from 'discourse/lib/ajax'; import { ajax } from 'discourse/lib/ajax';
import { extractError } from 'discourse/lib/ajax-error'; import { extractError } from 'discourse/lib/ajax-error';
import InputValidation from 'discourse/models/input-validation';
export default Ember.Controller.extend(ModalFunctionality, { export default Ember.Controller.extend(ModalFunctionality, {
model: Rule.create({}), model: Rule.create({}),
channelValidation: function(){
var regString = this.get('model.provider.channel_regex');
var regex = new RegExp(regString);
var val = this.get('model.rule.channel');
if(val == ""){ // Fail silently if field blank
return InputValidation.create({
failed: true,
});
}else if(!regString){ // Pass silently if no regex available for provider
return InputValidation.create({
ok: true,
});
}else if(regex.test(val)){ // Test against regex
return InputValidation.create({
ok: true,
reason: I18n.t('chat_integration.edit_rule_modal.channel_validation.ok')
});
}else{ // Failed regex
return InputValidation.create({
failed: true,
reason: I18n.t('chat_integration.edit_rule_modal.channel_validation.fail')
});
}
}.property('model.rule.channel'),
saveDisabled: function(){
if(this.get('channelValidation.failed')){ return true }
return false;
}.property('channelValidation.failed'),
actions: { actions: {
cancel: function(){ cancel: function(){
this.send('closeModal'); this.send('closeModal');
@ -16,7 +50,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
const self = this; const self = this;
this.get('model').update().then(function(result) { this.get('model.rule').update().then(function(result) {
self.send('closeModal'); self.send('closeModal');
}).catch(function(error) { }).catch(function(error) {
self.flash(extractError(error), 'error'); self.flash(extractError(error), 'error');

View File

@ -6,12 +6,12 @@ export default Discourse.Route.extend({
model(params, transition) { model(params, transition) {
return Ember.RSVP.hash({ return Ember.RSVP.hash({
rules: this.store.find('rule', {provider: params.provider}), rules: this.store.find('rule', {provider: params.provider}),
provider: params.provider provider: this.modelFor("admin-plugins-chat").findBy('id',params.provider)
}); });
}, },
serialize: function(model, params) { serialize: function(model, params) {
return { provider: model['provider']}; return { provider: model['provider'].get('id')};
}, },
actions: { actions: {

View File

@ -6,7 +6,7 @@
<tr class="input"> <tr class="input">
<td class="label"><label for='provider'>{{i18n "chat_integration.edit_rule_modal.provider"}}</label></td> <td class="label"><label for='provider'>{{i18n "chat_integration.edit_rule_modal.provider"}}</label></td>
<td> <td>
{{i18n (concat 'chat_integration.provider.' model.provider '.title')}} {{i18n (concat 'chat_integration.provider.' model.rule.provider '.title')}}
</td> </td>
</tr> </tr>
<tr class="instructions"> <tr class="instructions">
@ -19,20 +19,22 @@
<td> <td>
{{text-field {{text-field
name="channel" name="channel"
value=model.channel value=model.rule.channel
autofocus="autofocus" autofocus="autofocus"
id="channel-field"}} id="channel-field"}}
&nbsp;{{input-tip validation=channelValidation}}
</td> </td>
</tr> </tr>
<tr class="instructions"> <tr class="instructions">
<td></td> <td></td>
<td><label>{{i18n (concat 'chat_integration.provider.' model.provider '.channel_instructions')}}</label></td> <td><label>{{i18n (concat 'chat_integration.provider.' model.rule.provider '.channel_instructions')}}</label></td>
</tr> </tr>
<tr class="input"> <tr class="input">
<td class="label"><label for='filter'>{{i18n "chat_integration.edit_rule_modal.filter"}}</label></td> <td class="label"><label for='filter'>{{i18n "chat_integration.edit_rule_modal.filter"}}</label></td>
<td> <td>
{{combo-box name="filter" content=model.available_filters value=model.filter}} {{combo-box name="filter" content=model.rule.available_filters value=model.rule.filter}}
</td> </td>
</tr> </tr>
<tr class="instructions"> <tr class="instructions">
@ -45,7 +47,7 @@
<td> <td>
{{category-chooser {{category-chooser
name="category" name="category"
value=model.category_id value=model.rule.category_id
rootNoneLabel="chat_integration.all_categories" rootNoneLabel="chat_integration.all_categories"
rootNone=true rootNone=true
overrideWidths=false overrideWidths=false
@ -61,7 +63,7 @@
<tr class="input"> <tr class="input">
<td class="label"><label for='tags'>{{i18n "chat_integration.edit_rule_modal.tags"}}</label></td> <td class="label"><label for='tags'>{{i18n "chat_integration.edit_rule_modal.tags"}}</label></td>
<td> <td>
{{tag-chooser placeholderKey="chat_integration.all_tags" name="tags" tags=model.tags}} {{tag-chooser placeholderKey="chat_integration.all_tags" name="tags" tags=model.rule.tags}}
</td> </td>
</tr> </tr>
<tr class="instructions"> <tr class="instructions">
@ -77,7 +79,8 @@
{{/d-modal-body}} {{/d-modal-body}}
<div class="modal-footer"> <div class="modal-footer">
{{d-button class='btn-primary btn-large' action="save" title="chat_integration.edit_rule_modal.save" label="chat_integration.edit_rule_modal.save"}}
{{d-button class='btn-primary btn-large' action="save" title="chat_integration.edit_rule_modal.save" label="chat_integration.edit_rule_modal.save" disabled=saveDisabled}}
{{d-button class="btn-large" action="cancel" title="chat_integration.edit_rule_modal.cancel" label="chat_integration.edit_rule_modal.cancel"}} {{d-button class="btn-large" action="cancel" title="chat_integration.edit_rule_modal.cancel" label="chat_integration.edit_rule_modal.cancel"}}

View File

@ -27,6 +27,9 @@ en:
tags: "Tags" tags: "Tags"
channel: "Channel" channel: "Channel"
filter: "Filter" filter: "Filter"
channel_validation:
ok: "Valid"
fail: "Invalid channel format"
instructions: instructions:
filter: "Notification level. Mute overrides other matching rules." filter: "Notification level. Mute overrides other matching rules."
category: "This rule will only apply to topics in the specified category." category: "This rule will only apply to topics in the specified category."

View File

@ -5,6 +5,8 @@ module DiscourseChat::Provider::SlackProvider
PROVIDER_ENABLED_SETTING = :chat_integration_slack_enabled PROVIDER_ENABLED_SETTING = :chat_integration_slack_enabled
PROVIDER_CHANNEL_REGEX = '^[@#]\S*$'
def self.excerpt(post, max_length = SiteSetting.chat_integration_slack_excerpt_length) def self.excerpt(post, max_length = SiteSetting.chat_integration_slack_excerpt_length)
doc = Nokogiri::HTML.fragment(post.excerpt(max_length, doc = Nokogiri::HTML.fragment(post.excerpt(max_length,
remap_emoji: true, remap_emoji: true,

View File

@ -22,7 +22,7 @@
end end
def category_id=(val) def category_id=(val)
if val.nil? or val.empty? if val.nil? or val.blank?
@category_id = nil @category_id = nil
else else
@category_id = val.to_i @category_id = val.to_i
@ -103,6 +103,12 @@
# Validate channel # Validate channel
return false if @channel.blank? return false if @channel.blank?
provider = ::DiscourseChat::Provider.get_by_name(@provider)
if defined? provider::PROVIDER_CHANNEL_REGEX
channel_regex = Regexp.new provider::PROVIDER_CHANNEL_REGEX
return false if not channel_regex.match?(@channel)
end
# Validate category # Validate category
return false if not (@category_id.nil? or Category.where(id: @category_id).exists?) return false if not (@category_id.nil? or Category.where(id: @category_id).exists?)

View File

@ -69,7 +69,12 @@ after_initialize do
end end
def list_providers def list_providers
providers = ::DiscourseChat::Provider.enabled_providers.map {|x| {name: x::PROVIDER_NAME, id: x::PROVIDER_NAME}} providers = ::DiscourseChat::Provider.enabled_providers.map {|x| {
name: x::PROVIDER_NAME,
id: x::PROVIDER_NAME,
channel_regex: (defined? x::PROVIDER_CHANNEL_REGEX) ? x::PROVIDER_CHANNEL_REGEX : nil
}}
render json:providers, root: 'providers' render json:providers, root: 'providers'
end end
@ -85,7 +90,7 @@ after_initialize do
end end
filter_order = ["watch", "follow", "mute"] filter_order = ["watch", "follow", "mute"]
rules = rules.sort_by{ |r| [r.channel, filter_order.index(r.filter), r.category_id] } rules = rules.sort_by{ |r| [r.channel, r.category_id.nil? ? 0 : r.category_id, filter_order.index(r.filter)] }
render_serialized rules, DiscourseChat::RuleSerializer, root: 'rules' render_serialized rules, DiscourseChat::RuleSerializer, root: 'rules'
end end

View File

@ -82,7 +82,7 @@ RSpec.describe DiscourseChat::Rule do
it 'can be filtered by provider' do it 'can be filtered by provider' do
rule2 = DiscourseChat::Rule.new({provider:'telegram', channel:'blah'}).save! rule2 = DiscourseChat::Rule.new({provider:'telegram', channel:'blah'}).save!
rule3 = DiscourseChat::Rule.new({provider:'slack', channel:'blah'}).save! rule3 = DiscourseChat::Rule.new({provider:'slack', channel:'#blah'}).save!
expect(DiscourseChat::Rule.all.length).to eq(3) expect(DiscourseChat::Rule.all.length).to eq(3)
@ -91,8 +91,8 @@ RSpec.describe DiscourseChat::Rule do
end end
it 'can be filtered by category' do it 'can be filtered by category' do
rule2 = DiscourseChat::Rule.new({provider:'slack', channel:'blah', category_id: 1}).save! rule2 = DiscourseChat::Rule.new({provider:'slack', channel:'#blah', category_id: 1}).save!
rule3 = DiscourseChat::Rule.new({provider:'slack', channel:'blah', category_id: nil}).save! rule3 = DiscourseChat::Rule.new({provider:'slack', channel:'#blah', category_id: nil}).save!
expect(DiscourseChat::Rule.all.length).to eq(3) expect(DiscourseChat::Rule.all.length).to eq(3)
@ -122,6 +122,8 @@ RSpec.describe DiscourseChat::Rule do
expect(rule.valid?).to eq(true) expect(rule.valid?).to eq(true)
rule.channel = '' rule.channel = ''
expect(rule.valid?).to eq(false) expect(rule.valid?).to eq(false)
rule.channel = 'blah'
expect(rule.valid?).to eq(false)
end end
it 'validates category correctly' do it 'validates category correctly' do