diff --git a/app/controllers/api/v1/inbox/webhooks_controller.rb b/app/controllers/api/v1/account/webhooks_controller.rb similarity index 86% rename from app/controllers/api/v1/inbox/webhooks_controller.rb rename to app/controllers/api/v1/account/webhooks_controller.rb index 47ada02a8..dc56debfc 100644 --- a/app/controllers/api/v1/inbox/webhooks_controller.rb +++ b/app/controllers/api/v1/account/webhooks_controller.rb @@ -1,4 +1,4 @@ -class Api::V1::Inbox::WebhooksController < Api::BaseController +class Api::V1::Account::WebhooksController < Api::BaseController before_action :check_authorization before_action :fetch_webhook, only: [:update, :destroy] @@ -23,7 +23,7 @@ class Api::V1::Inbox::WebhooksController < Api::BaseController private def webhook_params - params.require(:webhook).permit(:account_id, :inbox_id, :urls).merge(urls: params[:urls]) + params.require(:webhook).permit(:account_id, :inbox_id, :url) end def fetch_webhook diff --git a/app/listeners/webhook_listener.rb b/app/listeners/webhook_listener.rb index 4b370404f..0da0fdad4 100644 --- a/app/listeners/webhook_listener.rb +++ b/app/listeners/webhook_listener.rb @@ -3,13 +3,17 @@ class WebhookListener < BaseListener message = extract_message_and_account(event)[0] inbox = message.inbox - return unless message.reportable? && inbox.webhook.present? + return unless message.reportable? - webhook = message.inbox.webhook - payload = message.push_event_data.merge(event: __method__.to_s) + payload = message.webhook_data.merge(event: __method__.to_s) + # Account webhooks + inbox.account.webhooks.account.each do |webhook| + WebhookJob.perform_later(webhook.url, payload) + end - webhook.urls.each do |url| - WebhookJob.perform_later(url, payload) + # Inbox webhooks + inbox.webhooks.inbox.each do |webhook| + WebhookJob.perform_later(webhook.url, payload) end end end diff --git a/app/models/account.rb b/app/models/account.rb index dc73a1e62..30987d041 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -60,6 +60,13 @@ class Account < ApplicationRecord } end + def webhook_data + { + id: id, + name: name + } + end + private def create_subscription diff --git a/app/models/contact.rb b/app/models/contact.rb index ab5d88990..112a261c8 100644 --- a/app/models/contact.rb +++ b/app/models/contact.rb @@ -41,4 +41,11 @@ class Contact < ApplicationRecord pubsub_token: pubsub_token } end + + def webhook_data + { + id: id, + name: name + } + end end diff --git a/app/models/conversation.rb b/app/models/conversation.rb index 924deaaa1..6facd6ad6 100644 --- a/app/models/conversation.rb +++ b/app/models/conversation.rb @@ -93,6 +93,13 @@ class Conversation < ApplicationRecord Conversations::EventDataPresenter.new(self).lock_data end + def webhook_data + { + display_id: display_id, + additional_attributes: additional_attributes + } + end + private def dispatch_events diff --git a/app/models/inbox.rb b/app/models/inbox.rb index fdc717c84..3420cf3f0 100644 --- a/app/models/inbox.rb +++ b/app/models/inbox.rb @@ -33,7 +33,7 @@ class Inbox < ApplicationRecord has_many :members, through: :inbox_members, source: :user has_many :conversations, dependent: :destroy has_many :messages, through: :conversations - has_one :webhook, dependent: :destroy + has_many :webhooks, dependent: :destroy after_create :subscribe_webhook, if: :facebook? after_destroy :delete_round_robin_agents @@ -60,6 +60,13 @@ class Inbox < ApplicationRecord account.users.find_by(id: user_id) end + def webhook_data + { + id: id, + name: name + } + end + private def delete_round_robin_agents diff --git a/app/models/message.rb b/app/models/message.rb index 94524eba8..633e44d34 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -50,6 +50,7 @@ class Message < ApplicationRecord belongs_to :inbox belongs_to :conversation belongs_to :user, required: false + belongs_to :contact, required: false has_one :attachment, dependent: :destroy, autosave: true @@ -78,6 +79,21 @@ class Message < ApplicationRecord incoming? || outgoing? end + def webhook_data + { + id: id, + content: content, + created_at: created_at, + message_type: message_type, + source_id: source_id, + sender: user.try(:webhook_data), + contact: contact.try(:webhook_data), + inbox: inbox.webhook_data, + conversation: conversation.webhook_data, + account: account.webhook_data + } + end + private def dispatch_event diff --git a/app/models/user.rb b/app/models/user.rb index 7d1e8391d..26567854b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -110,4 +110,12 @@ class User < ApplicationRecord avatar_url: avatar_url } end + + def webhook_data + { + id: id, + name: name, + email: email + } + end end diff --git a/app/models/webhook.rb b/app/models/webhook.rb index 81f416e98..4e1810826 100644 --- a/app/models/webhook.rb +++ b/app/models/webhook.rb @@ -2,19 +2,20 @@ # # Table name: webhooks # -# id :bigint not null, primary key -# urls :string -# created_at :datetime not null -# updated_at :datetime not null -# account_id :integer -# inbox_id :integer +# id :bigint not null, primary key +# url :string +# webhook_type :integer default("account") +# created_at :datetime not null +# updated_at :datetime not null +# account_id :integer +# inbox_id :integer # class Webhook < ApplicationRecord belongs_to :account - belongs_to :inbox + belongs_to :inbox, optional: true validates :account_id, presence: true - validates :inbox_id, presence: true - serialize :urls, Array + + enum webhook_type: { account: 0, inbox: 1 } end diff --git a/app/views/api/v1/inbox/index.json.jbuilder b/app/views/api/v1/account/index.json.jbuilder similarity index 100% rename from app/views/api/v1/inbox/index.json.jbuilder rename to app/views/api/v1/account/index.json.jbuilder diff --git a/app/views/api/v1/account/webhooks/_webhook.json.jbuilder b/app/views/api/v1/account/webhooks/_webhook.json.jbuilder new file mode 100644 index 000000000..b02de2098 --- /dev/null +++ b/app/views/api/v1/account/webhooks/_webhook.json.jbuilder @@ -0,0 +1,9 @@ +json.id webhook.id +json.url webhook.url +json.account_id webhook.account_id +if webhook.inbox + json.inbox do + json.id webhook.inbox.id + json.name webhook.inbox.name + end +end diff --git a/app/views/api/v1/inbox/webhooks/create.json.jbuilder b/app/views/api/v1/account/webhooks/create.json.jbuilder similarity index 100% rename from app/views/api/v1/inbox/webhooks/create.json.jbuilder rename to app/views/api/v1/account/webhooks/create.json.jbuilder diff --git a/app/views/api/v1/inbox/webhooks/index.json.jbuilder b/app/views/api/v1/account/webhooks/index.json.jbuilder similarity index 100% rename from app/views/api/v1/inbox/webhooks/index.json.jbuilder rename to app/views/api/v1/account/webhooks/index.json.jbuilder diff --git a/app/views/api/v1/inbox/webhooks/update.json.jbuilder b/app/views/api/v1/account/webhooks/update.json.jbuilder similarity index 100% rename from app/views/api/v1/inbox/webhooks/update.json.jbuilder rename to app/views/api/v1/account/webhooks/update.json.jbuilder diff --git a/app/views/api/v1/inbox/webhooks/_webhook.json.jbuilder b/app/views/api/v1/inbox/webhooks/_webhook.json.jbuilder deleted file mode 100644 index 93c0caadf..000000000 --- a/app/views/api/v1/inbox/webhooks/_webhook.json.jbuilder +++ /dev/null @@ -1,7 +0,0 @@ -json.id webhook.id -json.urls webhook.urls -json.account_id webhook.account_id -json.inbox do - json.id webhook.inbox.id - json.name webhook.inbox.name -end diff --git a/config/routes.rb b/config/routes.rb index a067eb30f..f5336a1e9 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -38,7 +38,7 @@ Rails.application.routes.draw do resource :contact_merge, only: [:create] end - namespace :inbox do + namespace :account do resources :webhooks, except: [:show] end diff --git a/db/migrate/20200225160650_rename_urls_to_url.rb b/db/migrate/20200225160650_rename_urls_to_url.rb new file mode 100644 index 000000000..01744a4d0 --- /dev/null +++ b/db/migrate/20200225160650_rename_urls_to_url.rb @@ -0,0 +1,5 @@ +class RenameUrlsToUrl < ActiveRecord::Migration[6.0] + def change + rename_column :webhooks, :urls, :url + end +end \ No newline at end of file diff --git a/db/migrate/20200225162150_add_type_to_webhook.rb b/db/migrate/20200225162150_add_type_to_webhook.rb new file mode 100644 index 000000000..c4a576da1 --- /dev/null +++ b/db/migrate/20200225162150_add_type_to_webhook.rb @@ -0,0 +1,5 @@ +class AddTypeToWebhook < ActiveRecord::Migration[6.0] + def change + add_column :webhooks, :webhook_type, :integer, default: '0' + end +end \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index daeeaae56..603df4afd 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_02_17_192734) do +ActiveRecord::Schema.define(version: 2020_02_25_162150) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -262,9 +262,10 @@ ActiveRecord::Schema.define(version: 2020_02_17_192734) do create_table "webhooks", force: :cascade do |t| t.integer "account_id" t.integer "inbox_id" - t.string "urls" + t.string "url" t.datetime "created_at", precision: 6, null: false t.datetime "updated_at", precision: 6, null: false + t.integer "webhook_type", default: 0 end add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" diff --git a/spec/controllers/api/v1/inbox/webhook_controller_spec.rb b/spec/controllers/api/v1/account/webhook_controller_spec.rb similarity index 76% rename from spec/controllers/api/v1/inbox/webhook_controller_spec.rb rename to spec/controllers/api/v1/account/webhook_controller_spec.rb index fdd5eb502..fbfeafd1a 100644 --- a/spec/controllers/api/v1/inbox/webhook_controller_spec.rb +++ b/spec/controllers/api/v1/account/webhook_controller_spec.rb @@ -3,99 +3,91 @@ require 'rails_helper' RSpec.describe 'Webhooks API', type: :request do let(:account) { create(:account) } let(:inbox) { create(:inbox, account: account) } - let(:webhook) { create(:webhook, account: account, inbox: inbox, urls: ['https://hello.com']) } + let(:webhook) { create(:webhook, account: account, inbox: inbox, url: 'https://hello.com') } let(:administrator) { create(:user, account: account, role: :administrator) } let(:agent) { create(:user, account: account, role: :agent) } - describe 'GET /api/v1/inbox/webhooks' do + describe 'GET /api/v1/account/webhooks' do context 'when it is an authenticated agent' do it 'returns unauthorized' do - get '/api/v1/inbox/webhooks', + get '/api/v1/account/webhooks', headers: agent.create_new_auth_token, as: :json - expect(response).to have_http_status(:unauthorized) end end context 'when it is an authenticated admin user' do it 'gets all webhook' do - get '/api/v1/inbox/webhooks', + get '/api/v1/account/webhooks', headers: administrator.create_new_auth_token, as: :json - expect(response).to have_http_status(:success) expect(JSON.parse(response.body)['payload']['webhooks'].count).to eql account.webhooks.count end end end - describe 'POST /api/v1/inbox/webhooks' do + describe 'POST /api/v1/account/webhooks' do context 'when it is an authenticated agent' do it 'returns unauthorized' do - post '/api/v1/inbox/webhooks', + post '/api/v1/account/webhooks', headers: agent.create_new_auth_token, as: :json - expect(response).to have_http_status(:unauthorized) end end context 'when it is an authenticated admin user' do it 'creates webhook' do - post '/api/v1/inbox/webhooks', - params: { account_id: account.id, inbox_id: inbox.id, urls: ['https://hello.com'] }, + post '/api/v1/account/webhooks', + params: { account_id: account.id, inbox_id: inbox.id, url: 'https://hello.com' }, headers: administrator.create_new_auth_token, as: :json - expect(response).to have_http_status(:success) - expect(JSON.parse(response.body)['payload']['webhook']['urls']).to eql ['https://hello.com'] + expect(JSON.parse(response.body)['payload']['webhook']['url']).to eql 'https://hello.com' end end end - describe 'PUT /api/v1/inbox/webhooks/:id' do + describe 'PUT /api/v1/account/webhooks/:id' do context 'when it is an authenticated agent' do it 'returns unauthorized' do - put "/api/v1/inbox/webhooks/#{webhook.id}", + put "/api/v1/account/webhooks/#{webhook.id}", headers: agent.create_new_auth_token, as: :json - expect(response).to have_http_status(:unauthorized) end end context 'when it is an authenticated admin user' do it 'updates webhook' do - put "/api/v1/inbox/webhooks/#{webhook.id}", - params: { urls: ['https://hello.com', 'https://world.com'] }, + put "/api/v1/account/webhooks/#{webhook.id}", + params: { url: 'https://hello.com' }, headers: administrator.create_new_auth_token, as: :json - expect(response).to have_http_status(:success) - expect(JSON.parse(response.body)['payload']['webhook']['urls']).to eql ['https://hello.com', 'https://world.com'] + expect(JSON.parse(response.body)['payload']['webhook']['url']).to eql 'https://hello.com' end end end - describe 'DELETE /api/v1/inbox/webhooks/:id' do + describe 'DELETE /api/v1/account/webhooks/:id' do context 'when it is an authenticated agent' do it 'returns unauthorized' do - delete "/api/v1/inbox/webhooks/#{webhook.id}", + delete "/api/v1/account/webhooks/#{webhook.id}", headers: agent.create_new_auth_token, as: :json - expect(response).to have_http_status(:unauthorized) end end context 'when it is an authenticated admin user' do it 'deletes webhook' do - delete "/api/v1/inbox/webhooks/#{webhook.id}", + delete "/api/v1/account/webhooks/#{webhook.id}", headers: administrator.create_new_auth_token, as: :json - expect(response).to have_http_status(:success) expect(account.webhooks.count).to be 0 end diff --git a/spec/factories/webhooks.rb b/spec/factories/webhooks.rb index 5cb322526..53456ad1a 100644 --- a/spec/factories/webhooks.rb +++ b/spec/factories/webhooks.rb @@ -2,6 +2,6 @@ FactoryBot.define do factory :webhook do account_id { 1 } inbox_id { 1 } - urls { ['MyString'] } + url { 'MyString' } end end diff --git a/spec/listeners/webhook_listener_spec.rb b/spec/listeners/webhook_listener_spec.rb index 6c29c5fdf..826f22458 100644 --- a/spec/listeners/webhook_listener_spec.rb +++ b/spec/listeners/webhook_listener_spec.rb @@ -25,7 +25,7 @@ describe WebhookListener do context 'when webhook is configured' do it 'triggers webhook' do webhook = create(:webhook, inbox: inbox, account: account) - expect(WebhookJob).to receive(:perform_later).with(webhook.urls[0], message.push_event_data.merge(event: 'message_created')).once + expect(WebhookJob).to receive(:perform_later).with(webhook.url, message.webhook_data.merge(event: 'message_created')).once listener.message_created(event) end end diff --git a/spec/models/inbox_spec.rb b/spec/models/inbox_spec.rb index 5fc166cb0..abe14211d 100644 --- a/spec/models/inbox_spec.rb +++ b/spec/models/inbox_spec.rb @@ -23,7 +23,7 @@ RSpec.describe Inbox do it { is_expected.to have_many(:conversations).dependent(:destroy) } it { is_expected.to have_many(:messages).through(:conversations) } - it { is_expected.to have_one(:webhook) } + it { is_expected.to have_many(:webhooks).dependent(:destroy) } end describe '#add_member' do diff --git a/spec/models/webhook_spec.rb b/spec/models/webhook_spec.rb index 7ac53419c..ca3ef213f 100644 --- a/spec/models/webhook_spec.rb +++ b/spec/models/webhook_spec.rb @@ -3,11 +3,9 @@ require 'rails_helper' RSpec.describe Webhook, type: :model do describe 'validations' do it { is_expected.to validate_presence_of(:account_id) } - it { is_expected.to validate_presence_of(:inbox_id) } end describe 'associations' do it { is_expected.to belong_to(:account) } - it { is_expected.to belong_to(:inbox) } end end