FEATURE: Allow easier customization to the web hook event serialization.
This commit is contained in:
parent
bbc85e1e29
commit
cfbfea0596
|
@ -60,6 +60,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{{plugin-outlet name="web-hook-fields" args=(hash model=model)}}
|
||||
|
||||
<div>
|
||||
{{input type="checkbox" name="verify_certificate" checked=model.verify_certificate}} {{i18n 'admin.web_hooks.verify_certificate'}}
|
||||
</div>
|
||||
|
|
|
@ -3,32 +3,24 @@ require 'excon'
|
|||
module Jobs
|
||||
class EmitWebHookEvent < Jobs::Base
|
||||
def execute(args)
|
||||
raise Discourse::InvalidParameters.new(:web_hook_id) unless args[:web_hook_id].present?
|
||||
raise Discourse::InvalidParameters.new(:event_type) unless args[:event_type].present?
|
||||
|
||||
args = args.dup
|
||||
|
||||
if args[:topic_id]
|
||||
args[:topic_view] = TopicView.new(args[:topic_id], Discourse.system_user)
|
||||
[:web_hook_id, :event_type].each do |key|
|
||||
raise Discourse::InvalidParameters.new(key) unless args[key].present?
|
||||
end
|
||||
|
||||
if args[:post_id]
|
||||
# deleted post so skip
|
||||
return unless args[:post] = Post.find_by(id: args[:post_id])
|
||||
end
|
||||
web_hook = WebHook.find_by(id: args[:web_hook_id])
|
||||
raise Discourse::InvalidParameters(:web_hook_id) if web_hook.blank?
|
||||
|
||||
if args[:user_id]
|
||||
return unless args[:user] = User.find_by(id: args[:user_id])
|
||||
end
|
||||
|
||||
web_hook = WebHook.find(args[:web_hook_id])
|
||||
|
||||
unless args[:event_type] == 'ping'
|
||||
unless ping_event?(args[:event_type])
|
||||
return unless web_hook.active?
|
||||
|
||||
return if web_hook.group_ids.present? && (args[:group_id].present? ||
|
||||
!web_hook.group_ids.include?(args[:group_id]))
|
||||
|
||||
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}")
|
||||
end
|
||||
|
||||
web_hook_request(args, web_hook)
|
||||
|
@ -36,12 +28,56 @@ module Jobs
|
|||
|
||||
private
|
||||
|
||||
def web_hook_request(args, web_hook)
|
||||
def guardian
|
||||
Guardian.new(Discourse.system_user)
|
||||
end
|
||||
|
||||
def setup_post(args)
|
||||
post = Post.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) rescue nil)
|
||||
return if topic_view.blank?
|
||||
args[:payload] = WebHookTopicViewSerializer.new(post, 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(post, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
def ping_event?(event_type)
|
||||
event_type.to_s == 'ping'.freeze
|
||||
end
|
||||
|
||||
def build_web_hook_body(args, web_hook)
|
||||
body = {}
|
||||
guardian = Guardian.new(Discourse.system_user)
|
||||
event_type = args[:event_type].to_s
|
||||
|
||||
if ping_event?(event_type)
|
||||
body[:ping] = 'OK'
|
||||
else
|
||||
body[event_type] = args[:payload]
|
||||
end
|
||||
|
||||
new_body = Plugin::Filter.apply(:after_build_web_hook_body, self, body)
|
||||
|
||||
MultiJson.dump(new_body)
|
||||
end
|
||||
|
||||
def web_hook_request(args, web_hook)
|
||||
uri = URI(web_hook.payload_url)
|
||||
conn = Excon.new(uri.to_s,
|
||||
ssl_verify_peer: web_hook.verify_certificate,
|
||||
retry_limit: 0)
|
||||
|
||||
conn = Excon.new(
|
||||
uri.to_s,
|
||||
ssl_verify_peer: web_hook.verify_certificate,
|
||||
retry_limit: 0
|
||||
)
|
||||
|
||||
body = build_web_hook_body(args, web_hook)
|
||||
web_hook_event = WebHookEvent.create!(web_hook_id: web_hook.id)
|
||||
|
@ -53,6 +89,7 @@ module Jobs
|
|||
else
|
||||
'application/json'
|
||||
end
|
||||
|
||||
headers = {
|
||||
'Accept' => '*/*',
|
||||
'Connection' => 'close',
|
||||
|
@ -64,6 +101,7 @@ module Jobs
|
|||
'X-Discourse-Event-Id' => web_hook_event.id,
|
||||
'X-Discourse-Event-Type' => args[:event_type]
|
||||
}
|
||||
|
||||
headers['X-Discourse-Event'] = args[:event_name].to_s if args[:event_name].present?
|
||||
|
||||
if web_hook.secret.present?
|
||||
|
@ -72,45 +110,23 @@ module Jobs
|
|||
|
||||
now = Time.zone.now
|
||||
response = conn.post(headers: headers, body: body)
|
||||
|
||||
web_hook_event.update!(
|
||||
headers: MultiJson.dump(headers),
|
||||
payload: body,
|
||||
status: response.status,
|
||||
response_headers: MultiJson.dump(response.headers),
|
||||
response_body: response.body,
|
||||
duration: ((Time.zone.now - now) * 1000).to_i
|
||||
)
|
||||
|
||||
MessageBus.publish("/web_hook_events/#{web_hook.id}", {
|
||||
web_hook_event_id: web_hook_event.id,
|
||||
event_type: args[:event_type]
|
||||
}, user_ids: User.human_users.staff.pluck(:id))
|
||||
rescue
|
||||
web_hook_event.destroy!
|
||||
end
|
||||
|
||||
web_hook_event.update_attributes!(headers: MultiJson.dump(headers),
|
||||
payload: body,
|
||||
status: response.status,
|
||||
response_headers: MultiJson.dump(response.headers),
|
||||
response_body: response.body,
|
||||
duration: ((Time.zone.now - now) * 1000).to_i)
|
||||
MessageBus.publish("/web_hook_events/#{web_hook.id}", {
|
||||
web_hook_event_id: web_hook_event.id,
|
||||
event_type: args[:event_type]
|
||||
}, user_ids: User.staff.pluck(:id))
|
||||
end
|
||||
|
||||
def build_web_hook_body(args, web_hook)
|
||||
body = {}
|
||||
guardian = Guardian.new(Discourse.system_user)
|
||||
|
||||
if topic_view = args[:topic_view]
|
||||
body[:topic] = TopicViewSerializer.new(topic_view, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
if post = args[:post]
|
||||
body[:post] = PostSerializer.new(post, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
if user = args[:user]
|
||||
body[:user] = UserSerializer.new(user, scope: guardian, root: false).as_json
|
||||
end
|
||||
|
||||
body[:ping] = 'OK' if args[:event_type] == 'ping'
|
||||
|
||||
raise Discourse::InvalidParameters.new if body.empty?
|
||||
|
||||
MultiJson.dump(body)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -41,11 +41,11 @@ class WebHook < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def self.enqueue_topic_hooks(event, topic, user=nil)
|
||||
WebHook.enqueue_hooks(:topic, topic_id: topic.id, user_id: user&.id, category_id: topic&.category_id, event_name: event.to_s)
|
||||
WebHook.enqueue_hooks(:topic, topic_id: topic.id, category_id: topic&.category_id, event_name: event.to_s)
|
||||
end
|
||||
|
||||
def self.enqueue_post_hooks(event, post, user=nil)
|
||||
WebHook.enqueue_hooks(:post, post_id: post.id, topic_id: post&.topic_id, user_id: user&.id, category_id: post&.topic&.category_id, event_name: event.to_s)
|
||||
WebHook.enqueue_hooks(:post, post_id: post.id, category_id: post&.topic&.category_id, event_name: event.to_s)
|
||||
end
|
||||
|
||||
%i(topic_destroyed topic_recovered).each do |event|
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
class WebHookPostSerializer < PostSerializer
|
||||
def include_can_edit?
|
||||
false
|
||||
end
|
||||
|
||||
def can_delete
|
||||
false
|
||||
end
|
||||
|
||||
def can_recover
|
||||
false
|
||||
end
|
||||
|
||||
def can_wiki
|
||||
false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,11 @@
|
|||
require_dependency 'pinned_check'
|
||||
|
||||
class WebHookTopicViewSerializer < TopicViewSerializer
|
||||
def include_post_stream?
|
||||
false
|
||||
end
|
||||
|
||||
def include_timeline_lookup?
|
||||
false
|
||||
end
|
||||
end
|
|
@ -0,0 +1,5 @@
|
|||
class WebHookUserSerializer < UserSerializer
|
||||
# remove staff attributes
|
||||
def staff_attributes(*attrs)
|
||||
end
|
||||
end
|
|
@ -10,14 +10,10 @@ describe Jobs::EmitWebHookEvent do
|
|||
expect { subject.execute(event_type: 'post') }.to raise_error(Discourse::InvalidParameters)
|
||||
end
|
||||
|
||||
it 'raises an error when there is no event name' do
|
||||
it 'raises an error when there is no event type' do
|
||||
expect { subject.execute(web_hook_id: 1) }.to raise_error(Discourse::InvalidParameters)
|
||||
end
|
||||
|
||||
it 'raises an error when event name is invalid' do
|
||||
expect { subject.execute(web_hook_id: post_hook.id, event_type: 'post_random') }.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)
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
require 'rails_helper'
|
||||
|
||||
describe WebHookEventType do
|
||||
it { is_expected.to validate_presence_of :name }
|
||||
end
|
Loading…
Reference in New Issue