fix: Twitter inbox creation error (#1783)
fixes #1708 Co-authored-by: Pranav <pranav@chatwoot.com>
This commit is contained in:
parent
ac15f08995
commit
850041bc1d
11 changed files with 156 additions and 62 deletions
|
@ -0,0 +1,29 @@
|
|||
class Api::V1::Accounts::Twitter::AuthorizationsController < Api::V1::Accounts::BaseController
|
||||
include TwitterConcern
|
||||
|
||||
before_action :check_authorization
|
||||
|
||||
def create
|
||||
@response = twitter_client.request_oauth_token(url: twitter_callback_url)
|
||||
if @response.status == '200'
|
||||
::Redis::Alfred.setex(oauth_token, Current.account.id)
|
||||
render json: { success: true, url: oauth_authorize_endpoint(oauth_token) }
|
||||
else
|
||||
render json: { success: false }, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def oauth_token
|
||||
parsed_body['oauth_token']
|
||||
end
|
||||
|
||||
def oauth_authorize_endpoint(oauth_token)
|
||||
"#{twitter_api_base_url}/oauth/authorize?oauth_token=#{oauth_token}"
|
||||
end
|
||||
|
||||
def check_authorization
|
||||
raise Pundit::NotAuthorizedError unless Current.account_user.administrator?
|
||||
end
|
||||
end
|
26
app/controllers/concerns/twitter_concern.rb
Normal file
26
app/controllers/concerns/twitter_concern.rb
Normal file
|
@ -0,0 +1,26 @@
|
|||
module TwitterConcern
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
private
|
||||
|
||||
def parsed_body
|
||||
@parsed_body ||= Rack::Utils.parse_nested_query(@response.raw_response.body)
|
||||
end
|
||||
|
||||
def host
|
||||
ENV.fetch('FRONTEND_URL', '')
|
||||
end
|
||||
|
||||
def twitter_client
|
||||
Twitty::Facade.new do |config|
|
||||
config.consumer_key = ENV.fetch('TWITTER_CONSUMER_KEY', nil)
|
||||
config.consumer_secret = ENV.fetch('TWITTER_CONSUMER_SECRET', nil)
|
||||
config.base_url = twitter_api_base_url
|
||||
config.environment = ENV.fetch('TWITTER_ENVIRONMENT', '')
|
||||
end
|
||||
end
|
||||
|
||||
def twitter_api_base_url
|
||||
'https://api.twitter.com'
|
||||
end
|
||||
end
|
|
@ -1,30 +0,0 @@
|
|||
class Twitter::AuthorizationsController < Twitter::BaseController
|
||||
def create
|
||||
@response = twitter_client.request_oauth_token(url: twitter_callback_url)
|
||||
|
||||
if @response.status == '200'
|
||||
::Redis::Alfred.setex(oauth_token, account.id)
|
||||
redirect_to oauth_authorize_endpoint(oauth_token)
|
||||
else
|
||||
redirect_to app_new_twitter_inbox_url(account_id: account.id)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def oauth_token
|
||||
parsed_body['oauth_token']
|
||||
end
|
||||
|
||||
def user
|
||||
@user ||= User.find_by(id: params[:user_id])
|
||||
end
|
||||
|
||||
def account
|
||||
@account ||= user.account
|
||||
end
|
||||
|
||||
def oauth_authorize_endpoint(oauth_token)
|
||||
"#{twitter_api_base_url}/oauth/authorize?oauth_token=#{oauth_token}"
|
||||
end
|
||||
end
|
|
@ -1,24 +1,3 @@
|
|||
class Twitter::BaseController < ApplicationController
|
||||
private
|
||||
|
||||
def parsed_body
|
||||
@parsed_body ||= Rack::Utils.parse_nested_query(@response.raw_response.body)
|
||||
end
|
||||
|
||||
def host
|
||||
ENV.fetch('FRONTEND_URL', '')
|
||||
end
|
||||
|
||||
def twitter_client
|
||||
Twitty::Facade.new do |config|
|
||||
config.consumer_key = ENV.fetch('TWITTER_CONSUMER_KEY', nil)
|
||||
config.consumer_secret = ENV.fetch('TWITTER_CONSUMER_SECRET', nil)
|
||||
config.base_url = twitter_api_base_url
|
||||
config.environment = ENV.fetch('TWITTER_ENVIRONMENT', '')
|
||||
end
|
||||
end
|
||||
|
||||
def twitter_api_base_url
|
||||
'https://api.twitter.com'
|
||||
end
|
||||
include TwitterConcern
|
||||
end
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class Twitter::CallbacksController < Twitter::BaseController
|
||||
include TwitterConcern
|
||||
|
||||
def show
|
||||
return redirect_to twitter_app_redirect_url if permitted_params[:denied]
|
||||
|
||||
|
|
14
app/javascript/dashboard/api/channel/twitterClient.js
Normal file
14
app/javascript/dashboard/api/channel/twitterClient.js
Normal file
|
@ -0,0 +1,14 @@
|
|||
/* global axios */
|
||||
import ApiClient from '../ApiClient';
|
||||
|
||||
class TwitterClient extends ApiClient {
|
||||
constructor() {
|
||||
super('twitter', { accountScoped: true });
|
||||
}
|
||||
|
||||
generateAuthorization() {
|
||||
return axios.post(`${this.url}/authorization`);
|
||||
}
|
||||
}
|
||||
|
||||
export default new TwitterClient();
|
|
@ -0,0 +1,9 @@
|
|||
import TwitterClient from '../../channel/twitterClient';
|
||||
import ApiClient from '../../ApiClient';
|
||||
|
||||
describe('#TwitterClient', () => {
|
||||
it('creates correct instance', () => {
|
||||
expect(TwitterClient).toBeInstanceOf(ApiClient);
|
||||
expect(TwitterClient).toHaveProperty('generateAuthorization');
|
||||
});
|
||||
});
|
|
@ -38,7 +38,8 @@
|
|||
"PICK_A_VALUE": "Pick a value"
|
||||
},
|
||||
"TWITTER": {
|
||||
"HELP": "To add your Twitter profile as a channel, you need to authenticate your Twitter Profile by clicking on 'Sign in with Twitter' "
|
||||
"HELP": "To add your Twitter profile as a channel, you need to authenticate your Twitter Profile by clicking on 'Sign in with Twitter' ",
|
||||
"ERROR_MESSAGE": "There was an error connecting to Twitter, please try again"
|
||||
},
|
||||
"WEBSITE_CHANNEL": {
|
||||
"TITLE": "Website channel",
|
||||
|
|
|
@ -1,27 +1,42 @@
|
|||
<template>
|
||||
<div class="wizard-body columns content-box small-9">
|
||||
<div class="login-init full-height text-center">
|
||||
<form method="POST" action="/twitter/authorization">
|
||||
<input type="hidden" name="user_id" :value="currentUserID" />
|
||||
<form @submit.prevent="requestAuthorization">
|
||||
<woot-submit-button
|
||||
icon-class="ion-social-twitter"
|
||||
button-text="Sign in with Twitter"
|
||||
type="submit"
|
||||
:loading="isRequestingAuthorization"
|
||||
/>
|
||||
</form>
|
||||
<p>{{ $t('INBOX_MGMT.ADD.TWITTER.HELP') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import twitterClient from '../../../../../api/channel/twitterClient';
|
||||
|
||||
export default {
|
||||
computed: {
|
||||
...mapGetters({
|
||||
currentUserID: 'getCurrentUserID',
|
||||
}),
|
||||
mixins: [alertMixin],
|
||||
data() {
|
||||
return { isRequestingAuthorization: false };
|
||||
},
|
||||
methods: {
|
||||
async requestAuthorization() {
|
||||
try {
|
||||
this.isRequestingAuthorization = true;
|
||||
const response = await twitterClient.generateAuthorization();
|
||||
const {
|
||||
data: { url },
|
||||
} = response;
|
||||
window.location.href = url;
|
||||
} catch (error) {
|
||||
this.showAlert(this.$t('INBOX_MGMT.ADD.TWITTER.ERROR_MESSAGE'));
|
||||
} finally {
|
||||
this.isRequestingAuthorization = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -107,6 +107,10 @@ Rails.application.routes.draw do
|
|||
end
|
||||
end
|
||||
|
||||
namespace :twitter do
|
||||
resource :authorization, only: [:create]
|
||||
end
|
||||
|
||||
resources :webhooks, except: [:show]
|
||||
namespace :integrations do
|
||||
resources :apps, only: [:index, :show]
|
||||
|
@ -202,7 +206,6 @@ Rails.application.routes.draw do
|
|||
post 'webhooks/twitter', to: 'api/v1/webhooks#twitter_events'
|
||||
|
||||
namespace :twitter do
|
||||
resource :authorization, only: [:create]
|
||||
resource :callback, only: [:show]
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe 'Twitter Authorization API', type: :request do
|
||||
let(:account) { create(:account) }
|
||||
|
||||
describe 'POST /api/v1/accounts/{account.id}/twitter/authorization' do
|
||||
context 'when it is an unauthenticated user' do
|
||||
it 'returns unauthorized' do
|
||||
post "/api/v1/accounts/#{account.id}/twitter/authorization"
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when it is an authenticated user' do
|
||||
let(:agent) { create(:user, account: account, role: :agent) }
|
||||
let(:administrator) { create(:user, account: account, role: :administrator) }
|
||||
let(:twitter_client) { double }
|
||||
let(:twitter_response) { double }
|
||||
let(:raw_response) { double }
|
||||
|
||||
it 'returns unathorized for agent' do
|
||||
post "/api/v1/accounts/#{account.id}/twitter/authorization",
|
||||
headers: agent.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:unauthorized)
|
||||
end
|
||||
|
||||
it 'creates a new authorization and returns the redirect url' do
|
||||
allow(Twitty::Facade).to receive(:new).and_return(twitter_client)
|
||||
allow(twitter_client).to receive(:request_oauth_token).and_return(twitter_response)
|
||||
allow(twitter_response).to receive(:status).and_return('200')
|
||||
allow(twitter_response).to receive(:raw_response).and_return(raw_response)
|
||||
allow(raw_response).to receive(:body).and_return('oauth_token=test_token')
|
||||
|
||||
post "/api/v1/accounts/#{account.id}/twitter/authorization",
|
||||
headers: administrator.create_new_auth_token,
|
||||
as: :json
|
||||
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(JSON.parse(response.body)['url']).to include('test_token')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue