From 75e159f0ed6df4db271c528ed49098ea4a0f25c3 Mon Sep 17 00:00:00 2001 From: Jeff Wong Date: Fri, 30 Apr 2021 14:08:38 -1000 Subject: [PATCH] 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. --- app/jobs/regular/emit_web_hook_event.rb | 4 +-- app/models/web_hook.rb | 9 +++--- app/models/web_hook_event_type.rb | 1 + app/serializers/web_hook_like_serializer.rb | 5 +++ config/initializers/012-web_hook_events.rb | 6 ++++ config/locales/client.en.yml | 3 ++ db/fixtures/007_web_hook_event_types.rb | 5 +++ spec/fabricators/web_hook_fabricator.rb | 8 +++++ spec/jobs/emit_web_hook_event_spec.rb | 36 +++++++++++++++++++++ spec/models/web_hook_spec.rb | 20 ++++++++++++ 10 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 app/serializers/web_hook_like_serializer.rb diff --git a/app/jobs/regular/emit_web_hook_event.rb b/app/jobs/regular/emit_web_hook_event.rb index 94371eaa33..7b22f0398b 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 9c11c9af54..ac8dadeb2c 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 ff5db8e583..70f2144f8a 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 0000000000..0a3e74fb08 --- /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 4bf6c2afc1..942260c85c 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 0f97c5f963..30febe1340 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 f82e548f06..42ed0e861b 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 f05c5c6f8c..554e162fd1 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 0e649c882e..9db61d2f3c 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 03c665acc2..492cb83a7d 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