diff --git a/app/assets/javascripts/admin/templates/web-hooks-show.hbs b/app/assets/javascripts/admin/templates/web-hooks-show.hbs
index 458a18c1e22..c7a8e030888 100644
--- a/app/assets/javascripts/admin/templates/web-hooks-show.hbs
+++ b/app/assets/javascripts/admin/templates/web-hooks-show.hbs
@@ -60,6 +60,8 @@
+ {{plugin-outlet name="web-hook-fields" args=(hash model=model)}}
+
{{input type="checkbox" name="verify_certificate" checked=model.verify_certificate}} {{i18n 'admin.web_hooks.verify_certificate'}}
diff --git a/app/jobs/regular/emit_web_hook_event.rb b/app/jobs/regular/emit_web_hook_event.rb
index 2186ca9baa1..043c97214c7 100644
--- a/app/jobs/regular/emit_web_hook_event.rb
+++ b/app/jobs/regular/emit_web_hook_event.rb
@@ -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
diff --git a/app/models/web_hook.rb b/app/models/web_hook.rb
index 4eed81e6bef..dc308736d2c 100644
--- a/app/models/web_hook.rb
+++ b/app/models/web_hook.rb
@@ -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|
diff --git a/app/serializers/web_hook_post_serializer.rb b/app/serializers/web_hook_post_serializer.rb
new file mode 100644
index 00000000000..221c398fa79
--- /dev/null
+++ b/app/serializers/web_hook_post_serializer.rb
@@ -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
diff --git a/app/serializers/web_hook_topic_view_serializer.rb b/app/serializers/web_hook_topic_view_serializer.rb
new file mode 100644
index 00000000000..75c99aeb14a
--- /dev/null
+++ b/app/serializers/web_hook_topic_view_serializer.rb
@@ -0,0 +1,11 @@
+require_dependency 'pinned_check'
+
+class WebHookTopicViewSerializer < TopicViewSerializer
+ def include_post_stream?
+ false
+ end
+
+ def include_timeline_lookup?
+ false
+ end
+end
diff --git a/app/serializers/web_hook_user_serializer.rb b/app/serializers/web_hook_user_serializer.rb
new file mode 100644
index 00000000000..9e6ad411cae
--- /dev/null
+++ b/app/serializers/web_hook_user_serializer.rb
@@ -0,0 +1,5 @@
+class WebHookUserSerializer < UserSerializer
+ # remove staff attributes
+ def staff_attributes(*attrs)
+ end
+end
diff --git a/spec/jobs/emit_web_hook_event_spec.rb b/spec/jobs/emit_web_hook_event_spec.rb
index c01ecb65691..b8e956c6503 100644
--- a/spec/jobs/emit_web_hook_event_spec.rb
+++ b/spec/jobs/emit_web_hook_event_spec.rb
@@ -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)
diff --git a/spec/models/web_hook_event_type_spec.rb b/spec/models/web_hook_event_type_spec.rb
deleted file mode 100644
index bd6b8ef41bb..00000000000
--- a/spec/models/web_hook_event_type_spec.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require 'rails_helper'
-
-describe WebHookEventType do
- it { is_expected.to validate_presence_of :name }
-end