FEATURE: Filter topic and post web hook events by tags (#6726)
* FEATURE: Filter topic and post web hook events by tags * Add a spec test with unmatched tags
This commit is contained in:
parent
1a71f98d28
commit
d33d031742
|
@ -9,6 +9,11 @@ export default Ember.Controller.extend({
|
||||||
defaultEventTypes: Ember.computed.alias("adminWebHooks.defaultEventTypes"),
|
defaultEventTypes: Ember.computed.alias("adminWebHooks.defaultEventTypes"),
|
||||||
contentTypes: Ember.computed.alias("adminWebHooks.contentTypes"),
|
contentTypes: Ember.computed.alias("adminWebHooks.contentTypes"),
|
||||||
|
|
||||||
|
@computed
|
||||||
|
showTagsFilter() {
|
||||||
|
return this.siteSettings.tagging_enabled;
|
||||||
|
},
|
||||||
|
|
||||||
@computed("model.isSaving", "saved", "saveButtonDisabled")
|
@computed("model.isSaving", "saved", "saveButtonDisabled")
|
||||||
savingStatus(isSaving, saved, saveButtonDisabled) {
|
savingStatus(isSaving, saved, saveButtonDisabled) {
|
||||||
if (isSaving) {
|
if (isSaving) {
|
||||||
|
|
|
@ -63,6 +63,7 @@ export default RestModel.extend({
|
||||||
createProperties() {
|
createProperties() {
|
||||||
const types = this.get("web_hook_event_types");
|
const types = this.get("web_hook_event_types");
|
||||||
const categoryIds = this.get("categories").map(c => c.id);
|
const categoryIds = this.get("categories").map(c => c.id);
|
||||||
|
const tagNames = this.get("tag_names");
|
||||||
|
|
||||||
// Hack as {{group-selector}} accepts a comma-separated string as data source, but
|
// Hack as {{group-selector}} accepts a comma-separated string as data source, but
|
||||||
// we use an array to populate the datasource above.
|
// we use an array to populate the datasource above.
|
||||||
|
@ -81,6 +82,7 @@ export default RestModel.extend({
|
||||||
? [null]
|
? [null]
|
||||||
: types.map(type => type.id),
|
: types.map(type => type.id),
|
||||||
category_ids: Ember.isEmpty(categoryIds) ? [null] : categoryIds,
|
category_ids: Ember.isEmpty(categoryIds) ? [null] : categoryIds,
|
||||||
|
tag_names: Ember.isEmpty(tagNames) ? [null] : tagNames,
|
||||||
group_ids:
|
group_ids:
|
||||||
Ember.isEmpty(groupNames) || Ember.isEmpty(groupNames[0])
|
Ember.isEmpty(groupNames) || Ember.isEmpty(groupNames[0])
|
||||||
? [null]
|
? [null]
|
||||||
|
|
|
@ -19,6 +19,7 @@ export default Discourse.Route.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
model.set("category_ids", model.get("category_ids"));
|
model.set("category_ids", model.get("category_ids"));
|
||||||
|
model.set("tag_names", model.get("tag_names"));
|
||||||
model.set("group_ids", model.get("group_ids"));
|
model.set("group_ids", model.get("group_ids"));
|
||||||
controller.setProperties({ model, saved: false });
|
controller.setProperties({ model, saved: false });
|
||||||
},
|
},
|
||||||
|
|
|
@ -51,6 +51,13 @@
|
||||||
{{category-selector categories=model.categories}}
|
{{category-selector categories=model.categories}}
|
||||||
<div class="instructions">{{i18n 'admin.web_hooks.categories_filter_instructions'}}</div>
|
<div class="instructions">{{i18n 'admin.web_hooks.categories_filter_instructions'}}</div>
|
||||||
</div>
|
</div>
|
||||||
|
{{#if showTagsFilter}}
|
||||||
|
<div class="filter">
|
||||||
|
<label>{{d-icon 'circle' class='tracking'}}{{i18n 'admin.web_hooks.tags_filter'}}</label>
|
||||||
|
{{tag-chooser tags=model.tag_names everyTag=true}}
|
||||||
|
<div class="instructions">{{i18n 'admin.web_hooks.tags_filter_instructions'}}</div>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
<div class="filter">
|
<div class="filter">
|
||||||
<label>{{d-icon 'circle' class='tracking'}}{{i18n 'admin.web_hooks.groups_filter'}}</label>
|
<label>{{d-icon 'circle' class='tracking'}}{{i18n 'admin.web_hooks.groups_filter'}}</label>
|
||||||
{{group-selector groupNames=model.groupsFilterInName groupFinder=model.groupFinder}}
|
{{group-selector groupNames=model.groupsFilterInName groupFinder=model.groupFinder}}
|
||||||
|
|
|
@ -111,6 +111,7 @@ class Admin::WebHooksController < Admin::AdminController
|
||||||
:wildcard_web_hook, :active, :verify_certificate,
|
:wildcard_web_hook, :active, :verify_certificate,
|
||||||
web_hook_event_type_ids: [],
|
web_hook_event_type_ids: [],
|
||||||
group_ids: [],
|
group_ids: [],
|
||||||
|
tag_names: [],
|
||||||
category_ids: [])
|
category_ids: [])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,9 @@ module Jobs
|
||||||
return if web_hook.category_ids.present? && (!args[:category_id].present? ||
|
return if web_hook.category_ids.present? && (!args[:category_id].present? ||
|
||||||
!web_hook.category_ids.include?(args[:category_id]))
|
!web_hook.category_ids.include?(args[:category_id]))
|
||||||
|
|
||||||
|
return if web_hook.tag_ids.present? && (args[:tag_ids].blank? ||
|
||||||
|
(web_hook.tag_ids & args[:tag_ids]).blank?)
|
||||||
|
|
||||||
raise Discourse::InvalidParameters.new(:payload) unless args[:payload].present?
|
raise Discourse::InvalidParameters.new(:payload) unless args[:payload].present?
|
||||||
args[:payload] = JSON.parse(args[:payload])
|
args[:payload] = JSON.parse(args[:payload])
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,6 +2,7 @@ class WebHook < ActiveRecord::Base
|
||||||
has_and_belongs_to_many :web_hook_event_types
|
has_and_belongs_to_many :web_hook_event_types
|
||||||
has_and_belongs_to_many :groups
|
has_and_belongs_to_many :groups
|
||||||
has_and_belongs_to_many :categories
|
has_and_belongs_to_many :categories
|
||||||
|
has_and_belongs_to_many :tags
|
||||||
|
|
||||||
has_many :web_hook_events, dependent: :destroy
|
has_many :web_hook_events, dependent: :destroy
|
||||||
|
|
||||||
|
@ -15,6 +16,10 @@ class WebHook < ActiveRecord::Base
|
||||||
|
|
||||||
before_save :strip_url
|
before_save :strip_url
|
||||||
|
|
||||||
|
def tag_names=(tag_names_arg)
|
||||||
|
DiscourseTagging.add_or_create_tags_by_name(self, tag_names_arg, unlimited: true)
|
||||||
|
end
|
||||||
|
|
||||||
def self.content_types
|
def self.content_types
|
||||||
@content_types ||= Enum.new('application/json' => 1,
|
@content_types ||= Enum.new('application/json' => 1,
|
||||||
'application/x-www-form-urlencoded' => 2)
|
'application/x-www-form-urlencoded' => 2)
|
||||||
|
@ -68,6 +73,7 @@ class WebHook < ActiveRecord::Base
|
||||||
WebHook.enqueue_hooks(:topic, event,
|
WebHook.enqueue_hooks(:topic, event,
|
||||||
id: topic.id,
|
id: topic.id,
|
||||||
category_id: topic&.category_id,
|
category_id: topic&.category_id,
|
||||||
|
tag_ids: topic&.tags.pluck(:id),
|
||||||
payload: payload
|
payload: payload
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -80,6 +86,7 @@ class WebHook < ActiveRecord::Base
|
||||||
WebHook.enqueue_hooks(:post, event,
|
WebHook.enqueue_hooks(:post, event,
|
||||||
id: post.id,
|
id: post.id,
|
||||||
category_id: post&.topic&.category_id,
|
category_id: post&.topic&.category_id,
|
||||||
|
tag_ids: post&.topic&.tags.pluck(:id),
|
||||||
payload: payload
|
payload: payload
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
@ -10,6 +10,7 @@ class AdminWebHookSerializer < ApplicationSerializer
|
||||||
:web_hook_event_types
|
:web_hook_event_types
|
||||||
|
|
||||||
has_many :categories, serializer: BasicCategorySerializer, embed: :ids, include: false
|
has_many :categories, serializer: BasicCategorySerializer, embed: :ids, include: false
|
||||||
|
has_many :tags, key: :tag_names, serializer: TagSerializer, embed: :ids, embed_key: :name, include: false
|
||||||
has_many :groups, serializer: BasicGroupSerializer, embed: :ids, include: false
|
has_many :groups, serializer: BasicGroupSerializer, embed: :ids, include: false
|
||||||
|
|
||||||
def web_hook_event_types
|
def web_hook_event_types
|
||||||
|
|
|
@ -3082,6 +3082,8 @@ en:
|
||||||
active_notice: "We will deliver event details when it happens."
|
active_notice: "We will deliver event details when it happens."
|
||||||
categories_filter_instructions: "Relevant webhooks will only be triggered if the event is related with specified categories. Leave blank to trigger webhooks for all categories."
|
categories_filter_instructions: "Relevant webhooks will only be triggered if the event is related with specified categories. Leave blank to trigger webhooks for all categories."
|
||||||
categories_filter: "Triggered Categories"
|
categories_filter: "Triggered Categories"
|
||||||
|
tags_filter_instructions: "Relevant webhooks will only be triggered if the event is related with specified tags. Leave blank to trigger webhooks for all tags."
|
||||||
|
tags_filter: "Triggered Tags"
|
||||||
groups_filter_instructions: "Relevant webhooks will only be triggered if the event is related with specified groups. Leave blank to trigger webhooks for all groups."
|
groups_filter_instructions: "Relevant webhooks will only be triggered if the event is related with specified groups. Leave blank to trigger webhooks for all groups."
|
||||||
groups_filter: "Triggered Groups"
|
groups_filter: "Triggered Groups"
|
||||||
delete_confirm: "Delete this webhook?"
|
delete_confirm: "Delete this webhook?"
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
class CreateJoinTableWebHooksTags < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_join_table :web_hooks, :tags do |t|
|
||||||
|
t.index [:web_hook_id, :tag_id], name: 'web_hooks_tags', unique: true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -125,6 +125,42 @@ describe Jobs::EmitWebHookEvent do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'with tag filters' do
|
||||||
|
let(:tag) { Fabricate(:tag) }
|
||||||
|
let(:topic) { Fabricate(:topic, tags: [tag]) }
|
||||||
|
let(:topic_hook) { Fabricate(:topic_web_hook, tags: [tag]) }
|
||||||
|
|
||||||
|
it "doesn't emit when event is not included any tags" do
|
||||||
|
subject.execute(
|
||||||
|
web_hook_id: topic_hook.id,
|
||||||
|
event_type: 'topic',
|
||||||
|
payload: { test: "some payload" }.to_json
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "doesn't emit when event is not related with defined tags" do
|
||||||
|
subject.execute(
|
||||||
|
web_hook_id: topic_hook.id,
|
||||||
|
event_type: 'topic',
|
||||||
|
tag_ids: [Fabricate(:tag).id],
|
||||||
|
payload: { test: "some payload" }.to_json
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'emit when event is related with defined tags' do
|
||||||
|
stub_request(:post, "https://meta.discourse.org/webhook_listener")
|
||||||
|
.with(body: "{\"topic\":{\"test\":\"some payload\"}}")
|
||||||
|
.to_return(body: 'OK', status: 200)
|
||||||
|
|
||||||
|
subject.execute(
|
||||||
|
web_hook_id: topic_hook.id,
|
||||||
|
event_type: 'topic',
|
||||||
|
tag_ids: topic.tags.pluck(:id),
|
||||||
|
payload: { test: "some payload" }.to_json
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#web_hook_request' do
|
describe '#web_hook_request' do
|
||||||
it 'creates delivery event record' do
|
it 'creates delivery event record' do
|
||||||
stub_request(:post, "https://meta.discourse.org/webhook_listener")
|
stub_request(:post, "https://meta.discourse.org/webhook_listener")
|
||||||
|
|
Loading…
Reference in New Issue