diff --git a/app/models/web_hook_event_type.rb b/app/models/web_hook_event_type.rb index d3822d1ede..952c1c2062 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 NOTIFICATION = 10 SOLVED = 11 ASSIGN = 12 + USER_BADGE = 13 has_and_belongs_to_many :web_hooks diff --git a/app/services/badge_granter.rb b/app/services/badge_granter.rb index 2249b33692..c6dfd82170 100644 --- a/app/services/badge_granter.rb +++ b/app/services/badge_granter.rb @@ -410,7 +410,7 @@ class BadgeGranter end def self.send_notification(user_id, username, locale, badge) - I18n.with_locale(notification_locale(locale)) do + notification = I18n.with_locale(notification_locale(locale)) do Notification.create!( user_id: user_id, notification_type: Notification.types[:granted_badge], @@ -423,6 +423,10 @@ class BadgeGranter }.to_json ) end + + DiscourseEvent.trigger(:user_badge_granted, badge, user_id) + + notification end end diff --git a/config/initializers/012-web_hook_events.rb b/config/initializers/012-web_hook_events.rb index 6ce6501ff3..727119a627 100644 --- a/config/initializers/012-web_hook_events.rb +++ b/config/initializers/012-web_hook_events.rb @@ -74,6 +74,16 @@ end end end +%i( + user_badge_granted +).each do |event| + # user_badge_revoked + DiscourseEvent.on(event) do |badge, user_id| + ub = UserBadge.find_by(badge: badge, user_id: user_id) + WebHook.enqueue_object_hooks(:user_badge, ub, event, UserBadgeSerializer) + end +end + DiscourseEvent.on(:reviewable_created) do |reviewable| WebHook.enqueue_object_hooks(:reviewable, reviewable, :reviewable_created, reviewable.serializer) end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 9345ba5272..f395e62717 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -3562,6 +3562,9 @@ en: notification_event: name: "Notification Event" details: "When a user receives a notification in their feed." + user_badge_event: + name: "Badge Grant Event" + details: "When a user receives a badge." 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 5cbcd3edc2..8bf8e93805 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::ASSIGN b.name = "assign" end + +WebHookEventType.seed do |b| + b.id = WebHookEventType::USER_BADGE + b.name = "user_badge" +end diff --git a/spec/fabricators/web_hook_fabricator.rb b/spec/fabricators/web_hook_fabricator.rb index 6d03c7b47f..4647251080 100644 --- a/spec/fabricators/web_hook_fabricator.rb +++ b/spec/fabricators/web_hook_fabricator.rb @@ -102,3 +102,11 @@ Fabricator(:notification_web_hook, from: :web_hook) do web_hook.web_hook_event_types = [transients[:notification_hook]] end end + +Fabricator(:user_badge_web_hook, from: :web_hook) do + transient user_badge_hook: WebHookEventType.find_by(name: 'user_badge') + + after_build do |web_hook, transients| + web_hook.web_hook_event_types = [transients[:user_badge_hook]] + end +end diff --git a/spec/models/web_hook_spec.rb b/spec/models/web_hook_spec.rb index 47b4c20bb7..586458a614 100644 --- a/spec/models/web_hook_spec.rb +++ b/spec/models/web_hook_spec.rb @@ -486,5 +486,30 @@ describe WebHook do payload = JSON.parse(job_args["payload"]) expect(payload["id"]).to eq(reviewable.id) end + + it 'should enqueue the right hooks for badge grants' do + Fabricate(:user_badge_web_hook) + badge = Fabricate(:badge) + badge.multiple_grant = true + badge.show_posts = true + badge.save + + now = Time.now + freeze_time now + + BadgeGranter.grant(badge, user, granted_by: admin, post_id: post.id) + + job_args = Jobs::EmitWebHookEvent.jobs.last["args"].first + expect(job_args["event_name"]).to eq("user_badge_granted") + payload = JSON.parse(job_args["payload"]) + expect(payload["badge_id"]).to eq(badge.id) + expect(payload["user_id"]).to eq(user.id) + expect(payload["granted_by_id"]).to eq(admin.id) + # be_within required because rounding occurs + expect(Time.zone.parse(payload["granted_at"]).to_f).to be_within(0.001).of(now.to_f) + expect(payload["post_id"]).to eq(post.id) + + # Future work: revoke badge hook + end end end