FIX: Payload for webhooks should be current as of the time the event was triggered.
https://meta.discourse.org/t/group-category-tag-user-deleted-webhooks-not-firing/87752
This commit is contained in:
parent
cba3942850
commit
bf84037f79
|
@ -2,8 +2,14 @@ require 'excon'
|
|||
|
||||
module Jobs
|
||||
class EmitWebHookEvent < Jobs::Base
|
||||
PING_EVENT = 'ping'.freeze
|
||||
|
||||
def execute(args)
|
||||
[:web_hook_id, :event_type].each do |key|
|
||||
%i{
|
||||
web_hook_id
|
||||
event_type
|
||||
payload
|
||||
}.each do |key|
|
||||
raise Discourse::InvalidParameters.new(key) unless args[key].present?
|
||||
end
|
||||
|
||||
|
@ -19,8 +25,7 @@ module Jobs
|
|||
return if web_hook.category_ids.present? && (!args[:category_id].present? ||
|
||||
!web_hook.category_ids.include?(args[:category_id]))
|
||||
|
||||
event_type = args[:event_type].to_s
|
||||
return unless self.send("setup_#{event_type}", args)
|
||||
args[:payload] = JSON.parse(args[:payload])
|
||||
end
|
||||
|
||||
web_hook_request(args, web_hook)
|
||||
|
@ -32,50 +37,8 @@ module Jobs
|
|||
Guardian.new(Discourse.system_user)
|
||||
end
|
||||
|
||||
def setup_post(args)
|
||||
post = Post.with_deleted.find_by(id: args[:post_id])
|
||||
return if post.blank?
|
||||
args[:payload] = WebHookPostSerializer.new(post, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
def setup_topic(args)
|
||||
topic_view = TopicView.new(args[:topic_id], Discourse.system_user)
|
||||
return if topic_view.blank?
|
||||
args[:payload] = WebHookTopicViewSerializer.new(topic_view, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
def setup_user(args)
|
||||
user = User.find_by(id: args[:user_id])
|
||||
return if user.blank?
|
||||
args[:payload] = WebHookUserSerializer.new(user, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
def setup_group(args)
|
||||
group = Group.find_by(id: args[:group_id])
|
||||
return if group.blank?
|
||||
args[:payload] = WebHookGroupSerializer.new(group, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
def setup_category(args)
|
||||
category = Category.find_by(id: args[:category_id])
|
||||
return if category.blank?
|
||||
args[:payload] = WebHookCategorySerializer.new(category, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
def setup_tag(args)
|
||||
tag = Tag.find_by(id: args[:tag_id])
|
||||
return if tag.blank?
|
||||
args[:payload] = TagSerializer.new(tag, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
def setup_flag(args)
|
||||
flag = PostAction.find_by(id: args[:flag_id])
|
||||
return if flag.blank?
|
||||
args[:payload] = WebHookFlagSerializer.new(flag, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
def ping_event?(event_type)
|
||||
event_type.to_s == 'ping'.freeze
|
||||
PING_EVENT == event_type.to_s
|
||||
end
|
||||
|
||||
def build_web_hook_body(args, web_hook)
|
||||
|
@ -89,7 +52,6 @@ module Jobs
|
|||
end
|
||||
|
||||
new_body = Plugin::Filter.apply(:after_build_web_hook_body, self, body)
|
||||
|
||||
MultiJson.dump(new_body)
|
||||
end
|
||||
|
||||
|
@ -120,7 +82,7 @@ module Jobs
|
|||
'Content-Length' => body.bytesize,
|
||||
'Content-Type' => content_type,
|
||||
'Host' => uri.host,
|
||||
'User-Agent' => "Discourse/" + Discourse::VERSION::STRING,
|
||||
'User-Agent' => "Discourse/#{Discourse::VERSION::STRING}",
|
||||
'X-Discourse-Instance' => Discourse.base_url,
|
||||
'X-Discourse-Event-Id' => web_hook_event.id,
|
||||
'X-Discourse-Event-Type' => args[:event_type]
|
||||
|
@ -129,7 +91,7 @@ module Jobs
|
|||
headers['X-Discourse-Event'] = args[:event_name].to_s if args[:event_name].present?
|
||||
|
||||
if web_hook.secret.present?
|
||||
headers['X-Discourse-Event-Signature'] = "sha256=" + OpenSSL::HMAC.hexdigest("sha256", web_hook.secret, body)
|
||||
headers['X-Discourse-Event-Signature'] = "sha256=#{OpenSSL::HMAC.hexdigest("sha256", web_hook.secret, body)}"
|
||||
end
|
||||
|
||||
now = Time.zone.now
|
||||
|
|
|
@ -30,30 +30,79 @@ class WebHook < ActiveRecord::Base
|
|||
[WebHookEventType.find(WebHookEventType::POST)]
|
||||
end
|
||||
|
||||
def self.find_by_type(type)
|
||||
def strip_url
|
||||
self.payload_url = (payload_url || "").strip.presence
|
||||
end
|
||||
|
||||
def self.active_web_hooks(type)
|
||||
WebHook.where(active: true)
|
||||
.joins(:web_hook_event_types)
|
||||
.where("web_hooks.wildcard_web_hook = ? OR web_hook_event_types.name = ?", true, type.to_s)
|
||||
.uniq
|
||||
end
|
||||
|
||||
def self.enqueue_hooks(type, opts = {})
|
||||
find_by_type(type).each do |w|
|
||||
Jobs.enqueue(:emit_web_hook_event, opts.merge(web_hook_id: w.id, event_type: type.to_s))
|
||||
def self.enqueue_hooks(type, opts = {}, web_hooks = nil)
|
||||
(web_hooks || active_web_hooks(type)).each do |web_hook|
|
||||
Jobs.enqueue(:emit_web_hook_event, opts.merge(
|
||||
web_hook_id: web_hook.id, event_type: type.to_s
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
def self.enqueue_topic_hooks(event, topic, user = nil)
|
||||
WebHook.enqueue_hooks(:topic, topic_id: topic.id, category_id: topic&.category_id, event_name: event.to_s)
|
||||
def self.enqueue_object_hooks(type, object, event, serializer = nil)
|
||||
Scheduler::Defer.later("Enqueue User Webhook") do
|
||||
web_hooks = active_web_hooks(type)
|
||||
return if web_hooks.empty?
|
||||
serializer ||= "WebHook#{type.capitalize}Serializer".constantize
|
||||
|
||||
WebHook.enqueue_hooks(type, {
|
||||
event_name: event.to_s,
|
||||
payload: serializer.new(object,
|
||||
scope: self.guardian,
|
||||
root: false
|
||||
).to_json
|
||||
}, web_hooks)
|
||||
end
|
||||
end
|
||||
|
||||
def self.enqueue_post_hooks(event, post, user = nil)
|
||||
WebHook.enqueue_hooks(:post, post_id: post.id, category_id: post&.topic&.category_id, event_name: event.to_s)
|
||||
def self.enqueue_topic_hooks(event, topic)
|
||||
Scheduler::Defer.later("Enqueue Topic Webhook") do
|
||||
web_hooks = active_web_hooks('topic')
|
||||
return if web_hooks.empty?
|
||||
topic_view = TopicView.new(topic.id, Discourse.system_user)
|
||||
|
||||
WebHook.enqueue_hooks(:topic, {
|
||||
category_id: topic&.category_id,
|
||||
event_name: event.to_s,
|
||||
payload: WebHookTopicViewSerializer.new(topic_view,
|
||||
scope: self.guardian,
|
||||
root: false
|
||||
).to_json
|
||||
}, web_hooks)
|
||||
end
|
||||
end
|
||||
|
||||
def strip_url
|
||||
self.payload_url = (payload_url || "").strip.presence
|
||||
def self.enqueue_post_hooks(event, post)
|
||||
Scheduler::Defer.later("Enqueue Post Webhook") do
|
||||
web_hooks = active_web_hooks('post')
|
||||
return if web_hooks.empty?
|
||||
|
||||
WebHook.enqueue_hooks(:post, {
|
||||
category_id: post&.topic&.category_id,
|
||||
event_name: event.to_s,
|
||||
payload: WebHookPostSerializer.new(post,
|
||||
scope: self.guardian,
|
||||
root: false
|
||||
).to_json
|
||||
}, web_hooks)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.guardian
|
||||
@guardian ||= Guardian.new(Discourse.system_user)
|
||||
end
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
%i(topic_destroyed topic_recovered).each do |event|
|
||||
DiscourseEvent.on(event) do |topic, user|
|
||||
WebHook.enqueue_topic_hooks(event, topic, user)
|
||||
%i(
|
||||
topic_destroyed
|
||||
topic_recovered
|
||||
).each do |event|
|
||||
DiscourseEvent.on(event) do |topic, _|
|
||||
WebHook.enqueue_topic_hooks(event, topic)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -8,16 +11,17 @@ DiscourseEvent.on(:topic_status_updated) do |topic, status|
|
|||
WebHook.enqueue_topic_hooks("topic_#{status}_status_updated", topic)
|
||||
end
|
||||
|
||||
DiscourseEvent.on(:topic_created) do |topic, _, user|
|
||||
WebHook.enqueue_topic_hooks(:topic_created, topic, user)
|
||||
DiscourseEvent.on(:topic_created) do |topic, _, _|
|
||||
WebHook.enqueue_topic_hooks(:topic_created, topic)
|
||||
end
|
||||
|
||||
%i(post_created
|
||||
post_destroyed
|
||||
post_recovered).each do |event|
|
||||
|
||||
DiscourseEvent.on(event) do |post, _, user|
|
||||
WebHook.enqueue_post_hooks(event, post, user)
|
||||
%i(
|
||||
post_created
|
||||
post_destroyed
|
||||
post_recovered
|
||||
).each do |event|
|
||||
DiscourseEvent.on(event) do |post, _, _|
|
||||
WebHook.enqueue_post_hooks(event, post)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -39,7 +43,7 @@ end
|
|||
user_updated
|
||||
).each do |event|
|
||||
DiscourseEvent.on(event) do |user|
|
||||
WebHook.enqueue_hooks(:user, user_id: user.id, event_name: event.to_s)
|
||||
WebHook.enqueue_object_hooks(:user, user, event)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -49,7 +53,7 @@ end
|
|||
group_destroyed
|
||||
).each do |event|
|
||||
DiscourseEvent.on(event) do |group|
|
||||
WebHook.enqueue_hooks(:group, group_id: group.id, event_name: event.to_s)
|
||||
WebHook.enqueue_object_hooks(:group, group, event)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -59,7 +63,7 @@ end
|
|||
category_destroyed
|
||||
).each do |event|
|
||||
DiscourseEvent.on(event) do |category|
|
||||
WebHook.enqueue_hooks(:category, category_id: category.id, event_name: event.to_s)
|
||||
WebHook.enqueue_object_hooks(:category, category, event)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -69,7 +73,7 @@ end
|
|||
tag_destroyed
|
||||
).each do |event|
|
||||
DiscourseEvent.on(event) do |tag|
|
||||
WebHook.enqueue_hooks(:tag, tag_id: tag.id, event_name: event.to_s)
|
||||
WebHook.enqueue_object_hooks(:tag, tag, event)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -80,6 +84,6 @@ end
|
|||
flag_deferred
|
||||
).each do |event|
|
||||
DiscourseEvent.on(event) do |flag|
|
||||
WebHook.enqueue_hooks(:flag, flag_id: flag.id, event_name: event.to_s)
|
||||
WebHook.enqueue_object_hooks(:flag, flag, event, WebHookFlagSerializer)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,21 +7,41 @@ describe Jobs::EmitWebHookEvent do
|
|||
let(:user) { Fabricate(:user) }
|
||||
|
||||
it 'raises an error when there is no web hook record' do
|
||||
expect { subject.execute(event_type: 'post') }.to raise_error(Discourse::InvalidParameters)
|
||||
expect do
|
||||
subject.execute(event_type: 'post', payload: {})
|
||||
end.to raise_error(Discourse::InvalidParameters)
|
||||
end
|
||||
|
||||
it 'raises an error when there is no event type' do
|
||||
expect { subject.execute(web_hook_id: 1) }.to raise_error(Discourse::InvalidParameters)
|
||||
expect do
|
||||
subject.execute(web_hook_id: 1, payload: {})
|
||||
end.to raise_error(Discourse::InvalidParameters)
|
||||
end
|
||||
|
||||
it 'raises an error when there is no payload' do
|
||||
expect do
|
||||
subject.execute(web_hook_id: 1, event_type: 'post')
|
||||
end.to raise_error(Discourse::InvalidParameters)
|
||||
end
|
||||
|
||||
it "doesn't emit when the hook is inactive" do
|
||||
Jobs::EmitWebHookEvent.any_instance.expects(:web_hook_request).never
|
||||
subject.execute(web_hook_id: inactive_hook.id, event_type: 'post', post_id: post.id)
|
||||
subject.execute(
|
||||
web_hook_id: inactive_hook.id,
|
||||
event_type: 'post',
|
||||
payload: { test: "some payload" }.to_json
|
||||
)
|
||||
end
|
||||
|
||||
it 'emits normally with sufficient arguments' do
|
||||
Jobs::EmitWebHookEvent.any_instance.expects(:web_hook_request).once
|
||||
subject.execute(web_hook_id: post_hook.id, event_type: 'post', post_id: post.id)
|
||||
stub_request(:post, "https://meta.discourse.org/webhook_listener")
|
||||
.with(body: "{\"post\":{\"test\":\"some payload\"}}")
|
||||
.to_return(body: 'OK', status: 200)
|
||||
|
||||
subject.execute(
|
||||
web_hook_id: post_hook.id,
|
||||
event_type: 'post',
|
||||
payload: { test: "some payload" }.to_json
|
||||
)
|
||||
end
|
||||
|
||||
context 'with category filters' do
|
||||
|
@ -31,69 +51,64 @@ describe Jobs::EmitWebHookEvent do
|
|||
let(:topic_hook) { Fabricate(:topic_web_hook, categories: [category]) }
|
||||
|
||||
it "doesn't emit when event is not related with defined categories" do
|
||||
Jobs::EmitWebHookEvent.any_instance.expects(:web_hook_request).never
|
||||
|
||||
subject.execute(web_hook_id: topic_hook.id,
|
||||
event_type: 'topic',
|
||||
topic_id: topic.id,
|
||||
user_id: user.id,
|
||||
category_id: topic.category.id)
|
||||
subject.execute(
|
||||
web_hook_id: topic_hook.id,
|
||||
event_type: 'topic',
|
||||
category_id: topic.category.id,
|
||||
payload: { test: "some payload" }.to_json
|
||||
)
|
||||
end
|
||||
|
||||
it 'emit when event is related with defined categories' do
|
||||
Jobs::EmitWebHookEvent.any_instance.expects(:web_hook_request).once
|
||||
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',
|
||||
topic_id: topic_with_category.id,
|
||||
user_id: user.id,
|
||||
category_id: topic_with_category.category.id)
|
||||
subject.execute(
|
||||
web_hook_id: topic_hook.id,
|
||||
event_type: 'topic',
|
||||
category_id: topic_with_category.category.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
|
||||
stub_request(:post, "https://meta.discourse.org/webhook_listener")
|
||||
.to_return(body: 'OK', status: 200)
|
||||
|
||||
WebHookEventType.all.pluck(:name).each do |name|
|
||||
web_hook_id = Fabricate("#{name}_web_hook").id
|
||||
object_id = Fabricate(name).id
|
||||
|
||||
expect do
|
||||
subject.execute(web_hook_id: web_hook_id, event_type: name, "#{name}_id": object_id)
|
||||
subject.execute(
|
||||
web_hook_id: web_hook_id,
|
||||
event_type: name,
|
||||
payload: { test: "some payload" }.to_json
|
||||
)
|
||||
end.to change(WebHookEvent, :count).by(1)
|
||||
end
|
||||
end
|
||||
|
||||
it 'skips silently on missing post' do
|
||||
expect do
|
||||
subject.execute(web_hook_id: post_hook.id, event_type: 'post', post_id: (Post.maximum(:id).to_i + 1))
|
||||
end.not_to raise_error
|
||||
end
|
||||
|
||||
it 'should not skip trashed post' do
|
||||
stub_request(:post, "https://meta.discourse.org/webhook_listener")
|
||||
.to_return(body: 'OK', status: 200)
|
||||
|
||||
expect do
|
||||
post.trash!
|
||||
subject.execute(web_hook_id: post_hook.id, event_type: 'post', post_id: post.id)
|
||||
end.to change(WebHookEvent, :count).by(1)
|
||||
end
|
||||
|
||||
it 'sets up proper request headers' do
|
||||
stub_request(:post, "https://meta.discourse.org/webhook_listener")
|
||||
.to_return(headers: { test: 'string' }, body: 'OK', status: 200)
|
||||
|
||||
subject.execute(web_hook_id: post_hook.id, event_type: 'ping', event_name: 'ping')
|
||||
subject.execute(
|
||||
web_hook_id: post_hook.id,
|
||||
event_type: described_class::PING_EVENT,
|
||||
event_name: described_class::PING_EVENT,
|
||||
payload: { test: "some payload" }.to_json
|
||||
)
|
||||
|
||||
event = WebHookEvent.last
|
||||
headers = MultiJson.load(event.headers)
|
||||
expect(headers['Content-Length']).to eq(13)
|
||||
expect(headers['Host']).to eq("meta.discourse.org")
|
||||
expect(headers['X-Discourse-Event-Id']).to eq(event.id)
|
||||
expect(headers['X-Discourse-Event-Type']).to eq('ping')
|
||||
expect(headers['X-Discourse-Event']).to eq('ping')
|
||||
expect(headers['X-Discourse-Event-Type']).to eq(described_class::PING_EVENT)
|
||||
expect(headers['X-Discourse-Event']).to eq(described_class::PING_EVENT)
|
||||
expect(headers['X-Discourse-Event-Signature']).to eq('sha256=162f107f6b5022353274eb1a7197885cfd35744d8d08e5bcea025d309386b7d6')
|
||||
expect(event.payload).to eq(MultiJson.dump(ping: 'OK'))
|
||||
expect(event.status).to eq(200)
|
||||
|
|
|
@ -42,69 +42,76 @@ describe WebHook do
|
|||
expect(post_hook.payload_url).to eq("https://example.com")
|
||||
end
|
||||
|
||||
describe '#find_by_type' do
|
||||
describe '#active_web_hooks' do
|
||||
it "returns unique hooks" do
|
||||
post_hook.web_hook_event_types << WebHookEventType.find_by(name: 'topic')
|
||||
post_hook.update!(wildcard_web_hook: true)
|
||||
|
||||
expect(WebHook.find_by_type(:post)).to eq([post_hook])
|
||||
expect(WebHook.active_web_hooks(:post)).to eq([post_hook])
|
||||
end
|
||||
|
||||
it 'find relevant hooks' do
|
||||
expect(WebHook.find_by_type(:post)).to eq([post_hook])
|
||||
expect(WebHook.find_by_type(:topic)).to eq([topic_hook])
|
||||
expect(WebHook.active_web_hooks(:post)).to eq([post_hook])
|
||||
expect(WebHook.active_web_hooks(:topic)).to eq([topic_hook])
|
||||
end
|
||||
|
||||
it 'excludes inactive hooks' do
|
||||
post_hook.update_attributes!(active: false)
|
||||
post_hook.update!(active: false)
|
||||
|
||||
expect(WebHook.find_by_type(:post)).to eq([])
|
||||
expect(WebHook.find_by_type(:topic)).to eq([topic_hook])
|
||||
expect(WebHook.active_web_hooks(:post)).to eq([])
|
||||
expect(WebHook.active_web_hooks(:topic)).to eq([topic_hook])
|
||||
end
|
||||
|
||||
describe 'wildcard web hooks' do
|
||||
let!(:wildcard_hook) { Fabricate(:wildcard_web_hook) }
|
||||
|
||||
it 'should include wildcard hooks' do
|
||||
expect(WebHook.active_web_hooks(:wildcard)).to eq([wildcard_hook])
|
||||
|
||||
expect(WebHook.active_web_hooks(:post)).to contain_exactly(
|
||||
post_hook, wildcard_hook
|
||||
)
|
||||
|
||||
expect(WebHook.active_web_hooks(:topic)).to contain_exactly(
|
||||
topic_hook, wildcard_hook
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#enqueue_hooks' do
|
||||
it 'enqueues hooks with id and name' do
|
||||
Jobs.expects(:enqueue).with(:emit_web_hook_event, web_hook_id: post_hook.id, event_type: 'post')
|
||||
|
||||
WebHook.enqueue_hooks(:post)
|
||||
before do
|
||||
SiteSetting.queue_jobs = true
|
||||
end
|
||||
|
||||
it 'accepts additional parameters' do
|
||||
Jobs.expects(:enqueue).with(:emit_web_hook_event, web_hook_id: post_hook.id, post_id: 1, event_type: 'post')
|
||||
payload = { test: 'some payload' }.to_json
|
||||
WebHook.enqueue_hooks(:post, payload: payload)
|
||||
|
||||
WebHook.enqueue_hooks(:post, post_id: 1)
|
||||
end
|
||||
end
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.first["args"].first
|
||||
|
||||
context 'includes wildcard hooks' do
|
||||
let!(:wildcard_hook) { Fabricate(:wildcard_web_hook) }
|
||||
|
||||
describe '#find_by_type' do
|
||||
it 'can find wildcard hooks' do
|
||||
expect(WebHook.find_by_type(:wildcard)).to eq([wildcard_hook])
|
||||
end
|
||||
|
||||
it 'can include wildcard hooks' do
|
||||
expect(WebHook.find_by_type(:post).sort_by(&:id)).to eq([post_hook, wildcard_hook])
|
||||
expect(WebHook.find_by_type(:topic).sort_by(&:id)).to eq([topic_hook, wildcard_hook])
|
||||
|
||||
end
|
||||
expect(job_args["web_hook_id"]).to eq(post_hook.id)
|
||||
expect(job_args["event_type"]).to eq('post')
|
||||
expect(job_args["payload"]).to eq(payload)
|
||||
end
|
||||
|
||||
describe '#enqueue_hooks' do
|
||||
it 'enqueues hooks with ids' do
|
||||
Jobs.expects(:enqueue).with(:emit_web_hook_event, web_hook_id: post_hook.id, event_type: 'post')
|
||||
Jobs.expects(:enqueue).with(:emit_web_hook_event, web_hook_id: wildcard_hook.id, event_type: 'post')
|
||||
context 'includes wildcard hooks' do
|
||||
let!(:wildcard_hook) { Fabricate(:wildcard_web_hook) }
|
||||
|
||||
WebHook.enqueue_hooks(:post)
|
||||
end
|
||||
describe '#enqueue_hooks' do
|
||||
it 'enqueues hooks with ids' do
|
||||
WebHook.enqueue_hooks(:post)
|
||||
|
||||
it 'accepts additional parameters' do
|
||||
Jobs.expects(:enqueue).with(:emit_web_hook_event, web_hook_id: post_hook.id, post_id: 1, event_type: 'post')
|
||||
Jobs.expects(:enqueue).with(:emit_web_hook_event, web_hook_id: wildcard_hook.id, post_id: 1, event_type: 'post')
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.first["args"].first
|
||||
|
||||
WebHook.enqueue_hooks(:post, post_id: 1)
|
||||
expect(job_args["web_hook_id"]).to eq(post_hook.id)
|
||||
expect(job_args["event_type"]).to eq('post')
|
||||
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["web_hook_id"]).to eq(wildcard_hook.id)
|
||||
expect(job_args["event_type"]).to eq('post')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -115,39 +122,51 @@ describe WebHook do
|
|||
let(:admin) { Fabricate(:admin) }
|
||||
let(:topic) { Fabricate(:topic, user: user) }
|
||||
let(:post) { Fabricate(:post, topic: topic, user: user) }
|
||||
let(:topic_web_hook) { Fabricate(:topic_web_hook) }
|
||||
|
||||
before do
|
||||
SiteSetting.queue_jobs = true
|
||||
topic_web_hook
|
||||
end
|
||||
|
||||
describe 'when there are no active hooks' do
|
||||
it 'should not enqueue anything' do
|
||||
topic_web_hook.destroy!
|
||||
post = PostCreator.create(user, raw: 'post', title: 'topic', skip_validations: true)
|
||||
expect(Jobs::EmitWebHookEvent.jobs.length).to eq(0)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should enqueue the right hooks for topic events' do
|
||||
Fabricate(:topic_web_hook)
|
||||
|
||||
post = PostCreator.create(user, raw: 'post', title: 'topic', skip_validations: true)
|
||||
topic_id = post.topic_id
|
||||
topic_id = post.topic.id
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("topic_created")
|
||||
expect(job_args["topic_id"]).to eq(topic_id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(topic_id)
|
||||
|
||||
PostDestroyer.new(user, post).destroy
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("topic_destroyed")
|
||||
expect(job_args["topic_id"]).to eq(topic_id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(topic_id)
|
||||
|
||||
PostDestroyer.new(user, post).recover
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("topic_recovered")
|
||||
expect(job_args["topic_id"]).to eq(topic_id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(topic_id)
|
||||
|
||||
%w{archived closed visible}.each do |status|
|
||||
post.topic.update_status(status, true, topic.user)
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("topic_#{status}_status_updated")
|
||||
expect(job_args["topic_id"]).to eq(topic_id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(topic_id)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -172,10 +191,7 @@ describe WebHook do
|
|||
it 'should enqueue the right hooks for post events' do
|
||||
Fabricate(:web_hook)
|
||||
|
||||
user
|
||||
topic
|
||||
|
||||
post = PostCreator.create(user,
|
||||
post = PostCreator.create!(user,
|
||||
raw: 'post',
|
||||
topic_id: topic.id,
|
||||
reply_to_post_number: 1,
|
||||
|
@ -183,30 +199,57 @@ describe WebHook do
|
|||
)
|
||||
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
Sidekiq::Worker.clear_all
|
||||
|
||||
expect(job_args["event_name"]).to eq("post_created")
|
||||
expect(job_args["post_id"]).to eq(post.id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(post.id)
|
||||
|
||||
Jobs::EmitWebHookEvent.jobs.clear
|
||||
|
||||
# post destroy or recover triggers a moderator post
|
||||
expect { PostDestroyer.new(user, post).destroy }
|
||||
.to change { Jobs::EmitWebHookEvent.jobs.count }.by(2)
|
||||
.to change { Jobs::EmitWebHookEvent.jobs.count }.by(3)
|
||||
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.first["args"].first
|
||||
job_args = Jobs::EmitWebHookEvent.jobs[0]["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("post_edited")
|
||||
expect(job_args["post_id"]).to eq(post.id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(post.id)
|
||||
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
job_args = Jobs::EmitWebHookEvent.jobs[1]["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("post_destroyed")
|
||||
expect(job_args["post_id"]).to eq(post.id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(post.id)
|
||||
|
||||
PostDestroyer.new(user, post).recover
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
job_args = Jobs::EmitWebHookEvent.jobs[2]["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("topic_destroyed")
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(post.topic.id)
|
||||
|
||||
Jobs::EmitWebHookEvent.jobs.clear
|
||||
|
||||
expect { PostDestroyer.new(user, post).recover }
|
||||
.to change { Jobs::EmitWebHookEvent.jobs.count }.by(3)
|
||||
|
||||
job_args = Jobs::EmitWebHookEvent.jobs[0]["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("post_edited")
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(post.id)
|
||||
|
||||
job_args = Jobs::EmitWebHookEvent.jobs[1]["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("post_recovered")
|
||||
expect(job_args["post_id"]).to eq(post.id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(post.id)
|
||||
|
||||
job_args = Jobs::EmitWebHookEvent.jobs[2]["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("topic_recovered")
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(post.topic.id)
|
||||
end
|
||||
|
||||
it 'should enqueue the right hooks for user events' do
|
||||
|
@ -216,37 +259,43 @@ describe WebHook do
|
|||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("user_created")
|
||||
expect(job_args["user_id"]).to eq(user.id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(user.id)
|
||||
|
||||
admin
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("user_created")
|
||||
expect(job_args["user_id"]).to eq(admin.id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(admin.id)
|
||||
|
||||
user.approve(admin)
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("user_approved")
|
||||
expect(job_args["user_id"]).to eq(user.id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(user.id)
|
||||
|
||||
UserUpdater.new(admin, user).update(username: 'testing123')
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("user_updated")
|
||||
expect(job_args["user_id"]).to eq(user.id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(user.id)
|
||||
|
||||
user.logged_out
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("user_logged_out")
|
||||
expect(job_args["user_id"]).to eq(user.id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(user.id)
|
||||
|
||||
user.logged_in
|
||||
job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
|
||||
|
||||
expect(job_args["event_name"]).to eq("user_logged_in")
|
||||
expect(job_args["user_id"]).to eq(user.id)
|
||||
payload = JSON.parse(job_args["payload"])
|
||||
expect(payload["id"]).to eq(user.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe WebHookEnqueuer do
|
||||
describe '#find_by_type' do
|
||||
let(:enqueuer) { WebHookEnqueuer.new }
|
||||
let!(:post_hook) { Fabricate(:web_hook, payload_url: " https://example.com ") }
|
||||
let!(:topic_hook) { Fabricate(:topic_web_hook) }
|
||||
|
||||
it "returns unique hooks" do
|
||||
post_hook.web_hook_event_types << WebHookEventType.find_by(name: 'topic')
|
||||
post_hook.update!(wildcard_web_hook: true)
|
||||
|
||||
expect(enqueuer.find_by_type(:post)).to eq([post_hook])
|
||||
end
|
||||
|
||||
it 'find relevant hooks' do
|
||||
expect(enqueuer.find_by_type(:post)).to eq([post_hook])
|
||||
expect(enqueuer.find_by_type(:topic)).to eq([topic_hook])
|
||||
end
|
||||
|
||||
it 'excludes inactive hooks' do
|
||||
post_hook.update!(active: false)
|
||||
|
||||
expect(enqueuer.find_by_type(:post)).to eq([])
|
||||
expect(enqueuer.find_by_type(:topic)).to eq([topic_hook])
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue