diff --git a/app/controllers/api/v1/widget/integrations/dyte_controller.rb b/app/controllers/api/v1/widget/integrations/dyte_controller.rb new file mode 100644 index 000000000..0661b4a3c --- /dev/null +++ b/app/controllers/api/v1/widget/integrations/dyte_controller.rb @@ -0,0 +1,36 @@ +class Api::V1::Widget::Integrations::DyteController < Api::V1::Widget::BaseController + before_action :set_message + + def add_participant_to_meeting + if @message.content_type != 'integrations' + return render json: { + error: I18n.t('errors.dyte.invalid_message_type') + }, status: :unprocessable_entity + end + + response = dyte_processor_service.add_participant_to_meeting( + @message.content_attributes['data']['meeting_id'], + @conversation.contact + ) + render_response(response) + end + + private + + def render_response(response) + render json: response, status: response[:error].blank? ? :ok : :unprocessable_entity + end + + def dyte_processor_service + Integrations::Dyte::ProcessorService.new(account: @web_widget.inbox.account, conversation: @conversation) + end + + def set_message + @message = @web_widget.inbox.messages.find(permitted_params[:message_id]) + @conversation = @message.conversation + end + + def permitted_params + params.permit(:website_token, :message_id) + end +end diff --git a/app/javascript/dashboard/components/widgets/conversation/bubble/Integration.vue b/app/javascript/dashboard/components/widgets/conversation/bubble/Integration.vue index 1978b9b5a..80843854d 100644 --- a/app/javascript/dashboard/components/widgets/conversation/bubble/Integration.vue +++ b/app/javascript/dashboard/components/widgets/conversation/bubble/Integration.vue @@ -14,16 +14,16 @@ export default { mixins: [inboxMixin], props: { messageId: { - type: Number, - required: true, + type: [String, Number], + default: 0, }, contentAttributes: { type: Object, default: () => ({}), }, inboxId: { - type: Number, - required: true, + type: [String, Number], + default: 0, }, }, computed: { diff --git a/app/javascript/dashboard/components/widgets/conversation/bubble/integrations/Dyte.vue b/app/javascript/dashboard/components/widgets/conversation/bubble/integrations/Dyte.vue index de4b07da0..8fca037f9 100644 --- a/app/javascript/dashboard/components/widgets/conversation/bubble/integrations/Dyte.vue +++ b/app/javascript/dashboard/components/widgets/conversation/bubble/integrations/Dyte.vue @@ -30,8 +30,7 @@ + diff --git a/app/javascript/widget/i18n/locale/en.json b/app/javascript/widget/i18n/locale/en.json index 6329cdeb3..141e9b102 100644 --- a/app/javascript/widget/i18n/locale/en.json +++ b/app/javascript/widget/i18n/locale/en.json @@ -86,5 +86,11 @@ "BUTTON_TEXT": "Request a conversation transcript", "SEND_EMAIL_SUCCESS": "The chat transcript was sent successfully", "SEND_EMAIL_ERROR": "There was an error, please try again" + }, + "INTEGRATIONS": { + "DYTE": { + "CLICK_HERE_TO_JOIN": "Click here to join", + "LEAVE_THE_ROOM": "Leave the call" + } } } diff --git a/config/routes.rb b/config/routes.rb index 06fb29bb3..787f13f75 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -217,6 +217,13 @@ Rails.application.routes.draw do end resources :inbox_members, only: [:index] resources :labels, only: [:create, :destroy] + namespace :integrations do + resource :dyte, controller: 'dyte', only: [] do + collection do + post :add_participant_to_meeting + end + end + end end end diff --git a/spec/controllers/api/v1/widget/integrations/dyte_controller_spec.rb b/spec/controllers/api/v1/widget/integrations/dyte_controller_spec.rb new file mode 100644 index 000000000..5d5ace90b --- /dev/null +++ b/spec/controllers/api/v1/widget/integrations/dyte_controller_spec.rb @@ -0,0 +1,74 @@ +require 'rails_helper' + +RSpec.describe '/api/v1/widget/integrations/dyte', type: :request do + let(:account) { create(:account) } + let(:web_widget) { create(:channel_widget, account: account) } + let(:contact) { create(:contact, account: account, email: nil) } + let(:contact_inbox) { create(:contact_inbox, contact: contact, inbox: web_widget.inbox) } + let(:conversation) { create(:conversation, contact: contact, account: account, inbox: web_widget.inbox, contact_inbox: contact_inbox) } + let(:payload) { { source_id: contact_inbox.source_id, inbox_id: web_widget.inbox.id } } + let(:token) { ::Widget::TokenService.new(payload: payload).generate_token } + let(:message) { create(:message, conversation: conversation, account: account, inbox: conversation.inbox) } + let!(:integration_message) do + create(:message, content_type: 'integrations', + content_attributes: { type: 'dyte', data: { meeting_id: 'm_id' } }, + conversation: conversation, account: account, inbox: conversation.inbox) + end + + before do + create(:integrations_hook, :dyte, account: account) + end + + describe 'POST /api/v1/widget/integrations/dyte/add_participant_to_meeting' do + context 'when token is invalid' do + it 'returns error' do + post add_participant_to_meeting_api_v1_widget_integrations_dyte_url, + params: { website_token: web_widget.website_token }, + as: :json + + expect(response).to have_http_status(:not_found) + end + end + + context 'when token is valid' do + context 'when message is not an integration message' do + it 'returns error' do + post add_participant_to_meeting_api_v1_widget_integrations_dyte_url, + headers: { 'X-Auth-Token' => token }, + params: { website_token: web_widget.website_token, message_id: message.id }, + as: :json + + expect(response).to have_http_status(:unprocessable_entity) + response_body = JSON.parse(response.body) + expect(response_body['error']).to eq('Invalid message type. Action not permitted') + end + end + + context 'when message is an integration message' do + before do + stub_request(:post, 'https://api.cluster.dyte.in/v1/organizations/org_id/meetings/m_id/participant') + .to_return( + status: 200, + body: { success: true, data: { authResponse: { userAdded: true, id: 'random_uuid', auth_token: 'json-web-token' } } }.to_json, + headers: { 'Content-Type' => 'application/json' } + ) + end + + it 'returns authResponse' do + post add_participant_to_meeting_api_v1_widget_integrations_dyte_url, + headers: { 'X-Auth-Token' => token }, + params: { website_token: web_widget.website_token, message_id: integration_message.id }, + as: :json + + expect(response).to have_http_status(:success) + response_body = JSON.parse(response.body) + expect(response_body['authResponse']).to eq( + { + 'userAdded' => true, 'id' => 'random_uuid', 'auth_token' => 'json-web-token' + } + ) + end + end + end + end +end