FEATURE: add support for like webhooks (#12917)

FEATURE: add support for like webhooks (#12917)

  • FEATURE: add support for like webhooks

Add support for like webhooks. Webhook events only send on user membership in the defined webhook group filters.

This also fixes group webhook events, as before this was never used, and the logic was not correct.

diff --git a/app/jobs/regular/emit_web_hook_event.rb b/app/jobs/regular/emit_web_hook_event.rb
index 94371ea..7b22f03 100644
--- a/app/jobs/regular/emit_web_hook_event.rb
+++ b/app/jobs/regular/emit_web_hook_event.rb
@@ -115,8 +115,8 @@ module Jobs
     end
 
     def group_webhook_invalid?
-      @web_hook.group_ids.present? && (@arguments[:group_id].present? ||
-        !@web_hook.group_ids.include?(@arguments[:group_id]))
+      @web_hook.group_ids.present? && (@arguments[:group_ids].blank? ||
+        (@web_hook.group_ids & @arguments[:group_ids]).blank?)
     end
 
     def category_webhook_invalid?
diff --git a/app/models/web_hook.rb b/app/models/web_hook.rb
index 9c11c9a..ac8dade 100644
--- a/app/models/web_hook.rb
+++ b/app/models/web_hook.rb
@@ -57,13 +57,14 @@ class WebHook < ActiveRecord::Base
     end
   end
 
-  def self.enqueue_object_hooks(type, object, event, serializer = nil)
+  def self.enqueue_object_hooks(type, object, event, serializer = nil, opts = {})
     if active_web_hooks(type).exists?
       payload = WebHook.generate_payload(type, object, serializer)
 
-      WebHook.enqueue_hooks(type, event,
-        id: object.id,
-        payload: payload
+      WebHook.enqueue_hooks(type, event, opts.merge(
+                              id: object.id,
+                              payload: payload
+                            )
       )
     end
   end
diff --git a/app/models/web_hook_event_type.rb b/app/models/web_hook_event_type.rb
index ff5db8e..70f2144 100644
--- a/app/models/web_hook_event_type.rb
+++ b/app/models/web_hook_event_type.rb
@@ -13,6 +13,7 @@ class WebHookEventType < ActiveRecord::Base
   ASSIGN = 12
   USER_BADGE = 13
   GROUP_USER = 14
+  LIKE = 15
 
   has_and_belongs_to_many :web_hooks
 
diff --git a/app/serializers/web_hook_like_serializer.rb b/app/serializers/web_hook_like_serializer.rb
new file mode 100644
index 0000000..0a3e74f
--- /dev/null
+++ b/app/serializers/web_hook_like_serializer.rb
@@ -0,0 +1,5 @@
+# frozen_string_literal: true
+class WebHookLikeSerializer < ApplicationSerializer
+  has_one :post, serializer: WebHookPostSerializer, embed: :objects
+  has_one :user, serializer: BasicUserSerializer, embed: :objects
+end
diff --git a/config/initializers/012-web_hook_events.rb b/config/initializers/012-web_hook_events.rb
index 4bf6c2a..942260c 100644
--- a/config/initializers/012-web_hook_events.rb
+++ b/config/initializers/012-web_hook_events.rb
@@ -106,3 +106,9 @@ DiscourseEvent.on(:user_added_to_group) do |user, group, options|
   group_user = GroupUser.find_by(user: user, group: group)
   WebHook.enqueue_object_hooks(:group_user, group_user, :user_added_to_group, WebHookGroupUserSerializer)
 end
+
+DiscourseEvent.on(:like_created) do |post_action|
+  user = post_action.user
+  group_ids = user.groups.map(&:id)
+  WebHook.enqueue_object_hooks(:like, post_action, :post_liked, WebHookLikeSerializer, group_ids: group_ids)
+end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 0f97c5f..30febe1 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -4040,6 +4040,9 @@ en:
         group_user_event:
           name: "Group User Event"
           details: "When a user is added or removed in a group."
+        like_event:
+          name: "Like Event"
+          details: "When a user likes a post."
         delivery_status:
           title: "Delivery Status"
           inactive: "Inactive"
diff --git a/db/fixtures/007_web_hook_event_types.rb b/db/fixtures/007_web_hook_event_types.rb
index f82e548..42ed0e8 100644
--- a/db/fixtures/007_web_hook_event_types.rb
+++ b/db/fixtures/007_web_hook_event_types.rb
@@ -59,3 +59,8 @@ WebHookEventType.seed do |b|
   b.id = WebHookEventType::GROUP_USER
   b.name = "group_user"
 end
+
+WebHookEventType.seed do |b|
+  b.id = WebHookEventType::LIKE
+  b.name = "like"
+end
diff --git a/spec/fabricators/web_hook_fabricator.rb b/spec/fabricators/web_hook_fabricator.rb
index f05c5c6..554e162 100644
--- a/spec/fabricators/web_hook_fabricator.rb
+++ b/spec/fabricators/web_hook_fabricator.rb
@@ -102,3 +102,11 @@ Fabricator(:group_user_web_hook, from: :web_hook) do
     web_hook.web_hook_event_types = [transients[:group_user_hook]]
   end
 end
+
+Fabricator(:like_web_hook, from: :web_hook) do
+  transient like_hook: WebHookEventType.find_by(name: 'like')
+
+  after_build do |web_hook, transients|
+    web_hook.web_hook_event_types = [transients[:like_hook]]
+  end
+end
diff --git a/spec/jobs/emit_web_hook_event_spec.rb b/spec/jobs/emit_web_hook_event_spec.rb
index 0e649c8..9db61d2 100644
--- a/spec/jobs/emit_web_hook_event_spec.rb
+++ b/spec/jobs/emit_web_hook_event_spec.rb
@@ -234,6 +234,42 @@ describe Jobs::EmitWebHookEvent do
     end
   end
 
+  context 'with group filters' do
+    fab!(:group) { Fabricate(:group) }
+    fab!(:user) { Fabricate(:user, groups: [group]) }
+    fab!(:like_hook) { Fabricate(:like_web_hook, groups: [group]) }
+
+    it "doesn't emit when event is not included any groups" do
+      subject.execute(
+        web_hook_id: like_hook.id,
+        event_type: 'like',
+        payload: { test: "some payload" }.to_json
+      )
+    end
+
+    it "doesn't emit when event is not related with defined groups" do
+      subject.execute(
+        web_hook_id: like_hook.id,
+        event_type: 'like',
+        group_ids: [Fabricate(:group).id],
+        payload: { test: "some payload" }.to_json
+      )
+    end
+
+    it 'emit when event is related with defined groups' do
+      stub_request(:post, like_hook.payload_url)
+        .with(body: "{\"like\":{\"test\":\"some payload\"}}")
+        .to_return(body: 'OK', status: 200)
+
+      subject.execute(
+        web_hook_id: like_hook.id,
+        event_type: 'like',
+        group_ids: user.groups.pluck(:id),
+        payload: { test: "some payload" }.to_json
+      )
+    end
+  end
+
   describe '#send_webhook!' do
     it 'creates delivery event record' do
       stub_request(:post, post_hook.payload_url)
diff --git a/spec/models/web_hook_spec.rb b/spec/models/web_hook_spec.rb
index 03c665a..492cb83 100644
--- a/spec/models/web_hook_spec.rb
+++ b/spec/models/web_hook_spec.rb
@@ -572,5 +572,25 @@ describe WebHook do
       expect(payload["group_id"]).to eq(group.id)
       expect(payload["user_id"]).to eq(user.id)
     end
+
+    it 'should enqueue hooks for user likes in a group' do
+      group = Fabricate(:group)
+      Fabricate(:like_web_hook, groups: [group])
+      group_user = Fabricate(:group_user, group: group, user: user)
+      poster = Fabricate(:user)
+      post = Fabricate(:post, user: poster)
+      like = Fabricate(:post_action, post: post, user: user, post_action_type_id: PostActionType.types[:like])
+      now = Time.now
+      freeze_time now
+
+      DiscourseEvent.trigger(:like_created, like)
+
+      job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first
+      expect(job_args["event_name"]).to eq("post_liked")
+      expect(job_args["group_ids"]).to eq([group.id])
+      payload = JSON.parse(job_args["payload"])
+      expect(payload["post"]["id"]).to eq(post.id)
+      expect(payload["user"]["id"]).to eq(user.id)
+    end
   end
 end

GitHub sha: 75e159f0

This commit appears in #12917 which was approved by eviltrout. It was merged by featheredtoast.