Merge pull request #5705 from discourse/new_webhooks
FEATURE: Webhook for group and category events
This commit is contained in:
commit
efb19dbdaf
|
@ -55,7 +55,10 @@ class Admin::GroupsController < Admin::AdminController
|
||||||
|
|
||||||
# group rename is ignored for automatic groups
|
# group rename is ignored for automatic groups
|
||||||
group.name = group_params[:name] if group_params[:name] && !group.automatic
|
group.name = group_params[:name] if group_params[:name] && !group.automatic
|
||||||
save_group(group) { |g| GroupActionLogger.new(current_user, g).log_change_group_settings }
|
save_group(group) do |group|
|
||||||
|
GroupActionLogger.new(current_user, group).log_change_group_settings
|
||||||
|
DiscourseEvent.trigger(:group_updated, group)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def save_group(group)
|
def save_group(group)
|
||||||
|
|
|
@ -149,6 +149,7 @@ class CategoriesController < ApplicationController
|
||||||
old_permissions = cat.permissions_params
|
old_permissions = cat.permissions_params
|
||||||
|
|
||||||
if result = cat.update(category_params)
|
if result = cat.update(category_params)
|
||||||
|
DiscourseEvent.trigger(:category_updated, cat)
|
||||||
Scheduler::Defer.later "Log staff action change category settings" do
|
Scheduler::Defer.later "Log staff action change category settings" do
|
||||||
@staff_action_logger.log_category_settings_change(@category, category_params, old_permissions)
|
@staff_action_logger.log_category_settings_change(@category, category_params, old_permissions)
|
||||||
end
|
end
|
||||||
|
@ -165,6 +166,7 @@ class CategoriesController < ApplicationController
|
||||||
custom_slug = params[:slug].to_s
|
custom_slug = params[:slug].to_s
|
||||||
|
|
||||||
if custom_slug.present? && @category.update_attributes(slug: custom_slug)
|
if custom_slug.present? && @category.update_attributes(slug: custom_slug)
|
||||||
|
DiscourseEvent.trigger(:category_updated, @category)
|
||||||
render json: success_json
|
render json: success_json
|
||||||
else
|
else
|
||||||
render_json_error(@category)
|
render_json_error(@category)
|
||||||
|
|
|
@ -137,6 +137,7 @@ class GroupsController < ApplicationController
|
||||||
|
|
||||||
if group.update_attributes(group_params)
|
if group.update_attributes(group_params)
|
||||||
GroupActionLogger.new(current_user, group).log_change_group_settings
|
GroupActionLogger.new(current_user, group).log_change_group_settings
|
||||||
|
DiscourseEvent.trigger(:group_updated, group)
|
||||||
|
|
||||||
render json: success_json
|
render json: success_json
|
||||||
else
|
else
|
||||||
|
|
|
@ -50,6 +50,18 @@ module Jobs
|
||||||
args[:payload] = WebHookUserSerializer.new(user, scope: guardian, root: false).as_json
|
args[:payload] = WebHookUserSerializer.new(user, scope: guardian, root: false).as_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def setup_group(args)
|
||||||
|
group = Group.find(args[:group_id])
|
||||||
|
return if group.blank?
|
||||||
|
args[:payload] = WebHookGroupSerializer.new(group, scope: guardian, root: false).as_json
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup_category(args)
|
||||||
|
category = Category.find(args[:category_id])
|
||||||
|
return if category.blank?
|
||||||
|
args[:payload] = WebHookCategorySerializer.new(category, scope: guardian, root: false).as_json
|
||||||
|
end
|
||||||
|
|
||||||
def ping_event?(event_type)
|
def ping_event?(event_type)
|
||||||
event_type.to_s == 'ping'.freeze
|
event_type.to_s == 'ping'.freeze
|
||||||
end
|
end
|
||||||
|
|
|
@ -61,6 +61,9 @@ class Category < ActiveRecord::Base
|
||||||
after_update :rename_category_definition, if: :saved_change_to_name?
|
after_update :rename_category_definition, if: :saved_change_to_name?
|
||||||
after_update :create_category_permalink, if: :saved_change_to_slug?
|
after_update :create_category_permalink, if: :saved_change_to_slug?
|
||||||
|
|
||||||
|
after_commit :trigger_category_created_event, on: :create
|
||||||
|
after_commit :trigger_category_destroyed_event, on: :destroy
|
||||||
|
|
||||||
belongs_to :parent_category, class_name: 'Category'
|
belongs_to :parent_category, class_name: 'Category'
|
||||||
has_many :subcategories, class_name: 'Category', foreign_key: 'parent_category_id'
|
has_many :subcategories, class_name: 'Category', foreign_key: 'parent_category_id'
|
||||||
|
|
||||||
|
@ -508,6 +511,16 @@ SQL
|
||||||
def subcategory_list_includes_topics?
|
def subcategory_list_includes_topics?
|
||||||
subcategory_list_style.end_with?("with_featured_topics")
|
subcategory_list_style.end_with?("with_featured_topics")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def trigger_category_created_event
|
||||||
|
DiscourseEvent.trigger(:category_created, self)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def trigger_category_destroyed_event
|
||||||
|
DiscourseEvent.trigger(:category_destroyed, self)
|
||||||
|
true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# == Schema Information
|
# == Schema Information
|
||||||
|
|
|
@ -35,6 +35,9 @@ class Group < ActiveRecord::Base
|
||||||
after_save :expire_cache
|
after_save :expire_cache
|
||||||
after_destroy :expire_cache
|
after_destroy :expire_cache
|
||||||
|
|
||||||
|
after_commit :trigger_group_created_event, on: :create
|
||||||
|
after_commit :trigger_group_destroyed_event, on: :destroy
|
||||||
|
|
||||||
def expire_cache
|
def expire_cache
|
||||||
ApplicationSerializer.expire_cache_fragment!("group_names")
|
ApplicationSerializer.expire_cache_fragment!("group_names")
|
||||||
end
|
end
|
||||||
|
@ -580,6 +583,16 @@ class Group < ActiveRecord::Base
|
||||||
self.member_of(groups, user).where("gu.owner")
|
self.member_of(groups, user).where("gu.owner")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def trigger_group_created_event
|
||||||
|
DiscourseEvent.trigger(:group_created, self)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def trigger_group_destroyed_event
|
||||||
|
DiscourseEvent.trigger(:group_destroyed, self)
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def name_format_validator
|
def name_format_validator
|
||||||
|
|
|
@ -2,6 +2,8 @@ class WebHookEventType < ActiveRecord::Base
|
||||||
TOPIC = 1
|
TOPIC = 1
|
||||||
POST = 2
|
POST = 2
|
||||||
USER = 3
|
USER = 3
|
||||||
|
GROUP = 4
|
||||||
|
CATEGORY = 5
|
||||||
|
|
||||||
has_and_belongs_to_many :web_hooks
|
has_and_belongs_to_many :web_hooks
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
class WebHookCategorySerializer < CategorySerializer
|
||||||
|
|
||||||
|
%i{
|
||||||
|
can_edit
|
||||||
|
notification_level
|
||||||
|
}.each do |attr|
|
||||||
|
define_method("include_#{attr}?") do
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,12 @@
|
||||||
|
class WebHookGroupSerializer < GroupShowSerializer
|
||||||
|
|
||||||
|
%i{
|
||||||
|
is_group_user
|
||||||
|
is_group_owner
|
||||||
|
}.each do |attr|
|
||||||
|
define_method("include_#{attr}?") do
|
||||||
|
false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -42,3 +42,23 @@ end
|
||||||
WebHook.enqueue_hooks(:user, user_id: user.id, event_name: event.to_s)
|
WebHook.enqueue_hooks(:user, user_id: user.id, event_name: event.to_s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
%i(
|
||||||
|
group_created
|
||||||
|
group_updated
|
||||||
|
group_destroyed
|
||||||
|
).each do |event|
|
||||||
|
DiscourseEvent.on(event) do |group|
|
||||||
|
WebHook.enqueue_hooks(:group, group_id: group.id, event_name: event.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%i(
|
||||||
|
category_created
|
||||||
|
category_updated
|
||||||
|
category_destroyed
|
||||||
|
).each do |event|
|
||||||
|
DiscourseEvent.on(event) do |category|
|
||||||
|
WebHook.enqueue_hooks(:category, category_id: category.id, event_name: event.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -2927,6 +2927,12 @@ en:
|
||||||
user_event:
|
user_event:
|
||||||
name: "User Event"
|
name: "User Event"
|
||||||
details: "When a user logs in, logs out, is created, approved or updated."
|
details: "When a user logs in, logs out, is created, approved or updated."
|
||||||
|
group_event:
|
||||||
|
name: "Group Event"
|
||||||
|
details: "When a group is created, updated or destroyed."
|
||||||
|
category_event:
|
||||||
|
name: "Category Event"
|
||||||
|
details: "When a category is created, updated or destroyed."
|
||||||
delivery_status:
|
delivery_status:
|
||||||
title: "Delivery Status"
|
title: "Delivery Status"
|
||||||
inactive: "Inactive"
|
inactive: "Inactive"
|
||||||
|
|
|
@ -12,3 +12,13 @@ WebHookEventType.seed do |b|
|
||||||
b.id = WebHookEventType::USER
|
b.id = WebHookEventType::USER
|
||||||
b.name = "user"
|
b.name = "user"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
WebHookEventType.seed do |b|
|
||||||
|
b.id = WebHookEventType::GROUP
|
||||||
|
b.name = "group"
|
||||||
|
end
|
||||||
|
|
||||||
|
WebHookEventType.seed do |b|
|
||||||
|
b.id = WebHookEventType::CATEGORY
|
||||||
|
b.name = "category"
|
||||||
|
end
|
||||||
|
|
|
@ -21,6 +21,9 @@ Fabricator(:wildcard_web_hook, from: :web_hook) do
|
||||||
wildcard_web_hook true
|
wildcard_web_hook true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Fabricator(:post_web_hook, from: :web_hook) do
|
||||||
|
end
|
||||||
|
|
||||||
Fabricator(:topic_web_hook, from: :web_hook) do
|
Fabricator(:topic_web_hook, from: :web_hook) do
|
||||||
transient topic_hook: WebHookEventType.find_by(name: 'topic')
|
transient topic_hook: WebHookEventType.find_by(name: 'topic')
|
||||||
|
|
||||||
|
@ -36,3 +39,19 @@ Fabricator(:user_web_hook, from: :web_hook) do
|
||||||
web_hook.web_hook_event_types = [transients[:user_hook]]
|
web_hook.web_hook_event_types = [transients[:user_hook]]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Fabricator(:group_web_hook, from: :web_hook) do
|
||||||
|
transient group_hook: WebHookEventType.find_by(name: 'group')
|
||||||
|
|
||||||
|
after_build do |web_hook, transients|
|
||||||
|
web_hook.web_hook_event_types = [transients[:group_hook]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Fabricator(:category_web_hook, from: :web_hook) do
|
||||||
|
transient category_hook: WebHookEventType.find_by(name: 'category')
|
||||||
|
|
||||||
|
after_build do |web_hook, transients|
|
||||||
|
web_hook.web_hook_event_types = [transients[:category_hook]]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
|
@ -56,9 +56,14 @@ describe Jobs::EmitWebHookEvent do
|
||||||
stub_request(:post, "https://meta.discourse.org/webhook_listener")
|
stub_request(:post, "https://meta.discourse.org/webhook_listener")
|
||||||
.to_return(body: 'OK', status: 200)
|
.to_return(body: 'OK', status: 200)
|
||||||
|
|
||||||
expect do
|
WebHookEventType.all.pluck(:name).each do |name|
|
||||||
subject.execute(web_hook_id: post_hook.id, event_type: 'post', post_id: post.id)
|
web_hook_id = Fabricate("#{name}_web_hook").id
|
||||||
end.to change(WebHookEvent, :count).by(1)
|
object_id = Fabricate(name).id
|
||||||
|
|
||||||
|
expect do
|
||||||
|
subject.execute(web_hook_id: web_hook_id, event_type: name, "#{name}_id": object_id)
|
||||||
|
end.to change(WebHookEvent, :count).by(1)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'skips silently on missing post' do
|
it 'skips silently on missing post' do
|
||||||
|
|
|
@ -368,6 +368,17 @@ describe Category do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'new' do
|
||||||
|
subject { Fabricate.build(:category, user: Fabricate(:user)) }
|
||||||
|
|
||||||
|
it 'triggers a extensibility event' do
|
||||||
|
event = DiscourseEvent.track_events { subject.save! }.last
|
||||||
|
|
||||||
|
expect(event[:event_name]).to eq(:category_created)
|
||||||
|
expect(event[:params].first).to eq(subject)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "update" do
|
describe "update" do
|
||||||
it "should enforce uniqueness of slug" do
|
it "should enforce uniqueness of slug" do
|
||||||
Fabricate(:category, slug: "the-slug")
|
Fabricate(:category, slug: "the-slug")
|
||||||
|
@ -384,14 +395,21 @@ describe Category do
|
||||||
@category_id = @category.id
|
@category_id = @category.id
|
||||||
@topic_id = @category.topic_id
|
@topic_id = @category.topic_id
|
||||||
SiteSetting.shared_drafts_category = @category.id.to_s
|
SiteSetting.shared_drafts_category = @category.id.to_s
|
||||||
@category.destroy
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'is deleted correctly' do
|
it 'is deleted correctly' do
|
||||||
|
@category.destroy
|
||||||
expect(Category.exists?(id: @category_id)).to be false
|
expect(Category.exists?(id: @category_id)).to be false
|
||||||
expect(Topic.exists?(id: @topic_id)).to be false
|
expect(Topic.exists?(id: @topic_id)).to be false
|
||||||
expect(SiteSetting.shared_drafts_category).to be_blank
|
expect(SiteSetting.shared_drafts_category).to be_blank
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'triggers a extensibility event' do
|
||||||
|
event = DiscourseEvent.track_events { @category.destroy }.first
|
||||||
|
|
||||||
|
expect(event[:event_name]).to eq(:category_destroyed)
|
||||||
|
expect(event[:params].first).to eq(@category)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'latest' do
|
describe 'latest' do
|
||||||
|
|
|
@ -411,17 +411,37 @@ describe Group do
|
||||||
expect(g.usernames.split(",").sort).to eq usernames.split(",").sort
|
expect(g.usernames.split(",").sort).to eq usernames.split(",").sort
|
||||||
end
|
end
|
||||||
|
|
||||||
it "correctly destroys groups" do
|
describe 'new' do
|
||||||
|
subject { Fabricate.build(:group) }
|
||||||
|
|
||||||
g = Fabricate(:group)
|
it 'triggers a extensibility event' do
|
||||||
u1 = Fabricate(:user)
|
event = DiscourseEvent.track_events { subject.save! }.first
|
||||||
g.add(u1)
|
|
||||||
g.save!
|
|
||||||
|
|
||||||
g.destroy
|
expect(event[:event_name]).to eq(:group_created)
|
||||||
|
expect(event[:params].first).to eq(subject)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
expect(User.where(id: u1.id).count).to eq 1
|
describe 'destroy' do
|
||||||
expect(GroupUser.where(group_id: g.id).count).to eq 0
|
let(:user) { Fabricate(:user) }
|
||||||
|
let(:group) { Fabricate(:group, users: [user]) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
group.add(user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "it deleted correctly" do
|
||||||
|
group.destroy!
|
||||||
|
expect(User.where(id: user.id).count).to eq 1
|
||||||
|
expect(GroupUser.where(group_id: group.id).count).to eq 0
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'triggers a extensibility event' do
|
||||||
|
event = DiscourseEvent.track_events { group.destroy! }.first
|
||||||
|
|
||||||
|
expect(event[:event_name]).to eq(:group_destroyed)
|
||||||
|
expect(event[:params].first).to eq(group)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it "has custom fields" do
|
it "has custom fields" do
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe GroupsController do
|
||||||
|
let(:admin) { Fabricate(:admin) }
|
||||||
|
let(:category) { Fabricate(:category, user: admin) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
category
|
||||||
|
sign_in(admin)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "triggers a extensibility event" do
|
||||||
|
event = DiscourseEvent.track_events {
|
||||||
|
put "/categories/#{category.id}.json", params: {
|
||||||
|
name: 'hello',
|
||||||
|
color: 'ff0',
|
||||||
|
text_color: 'fff'
|
||||||
|
}
|
||||||
|
}.last
|
||||||
|
|
||||||
|
expect(event[:event_name]).to eq(:category_updated)
|
||||||
|
expect(event[:params].first).to eq(category)
|
||||||
|
end
|
||||||
|
end
|
|
@ -450,6 +450,15 @@ describe GroupsController do
|
||||||
expect(group.flair_color).to eq('BBB')
|
expect(group.flair_color).to eq('BBB')
|
||||||
expect(group.name).to eq('testing')
|
expect(group.name).to eq('testing')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'triggers a extensibility event' do
|
||||||
|
event = DiscourseEvent.track_events {
|
||||||
|
put "/groups/#{group.id}.json", params: { group: { flair_color: 'BBB' } }
|
||||||
|
}.last
|
||||||
|
|
||||||
|
expect(event[:event_name]).to eq(:group_updated)
|
||||||
|
expect(event[:params].first).to eq(group)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when user is not a group owner or admin" do
|
context "when user is not a group owner or admin" do
|
||||||
|
|
Loading…
Reference in New Issue