Init version of twitter admin.

This commit is contained in:
Martin Edenhofer 2015-12-21 01:48:49 +01:00
parent 272a569b10
commit b990fa6daf
19 changed files with 342 additions and 152 deletions

View file

@ -654,6 +654,9 @@ class App.ControllerModal extends App.Controller
post: ->
# nothing
element: =>
@el
render: =>
if @buttonSubmit is true
@buttonSubmit = 'Submit'
@ -688,6 +691,11 @@ class App.ControllerModal extends App.Controller
e.preventDefault()
@el.modal('hide')
formParams: =>
if @container
return @formParam(@container.find('.modal form'))
return @formParam(@$('.modal form'))
onShow: ->
# do nothing

View file

@ -268,6 +268,7 @@ class App.ControllerGenericDestroyConfirm extends App.ControllerModal
buttonSubmit: 'yes'
buttonClass: 'btn--danger'
head: 'Confirm'
small: true
content: ->
App.i18n.translateContent('Sure to delete this object?')
@ -275,9 +276,9 @@ class App.ControllerGenericDestroyConfirm extends App.ControllerModal
onSubmit: =>
@item.destroy(
done: =>
@close()
if @callback
@callback()
@close()
fail: =>
@log 'errors'
@close()
@ -348,6 +349,8 @@ class App.ControllerNavSidbar extends App.ControllerContent
constructor: (params) ->
super
@params = params
# get groups
groups = App.Config.get(@configKey)
groupsUnsorted = []
@ -385,6 +388,9 @@ class App.ControllerNavSidbar extends App.ControllerContent
else if @target && item.target is window.location.hash
item.active = true
selectedItem = item
else if @target && window.location.hash.match(item.target)
item.active = true
selectedItem = item
else
item.active = false
@ -400,7 +406,7 @@ class App.ControllerNavSidbar extends App.ControllerContent
renderContainer: =>
return if $( ".#{@configKey}" )[0]
@html App.view('generic/navbar_level2/index')(
className: @configKey
className: @configKey
)
renderNavBar: (selectedItem) =>
@ -427,9 +433,8 @@ class App.ControllerNavSidbar extends App.ControllerContent
@activeController.render()
return
@activeController = new selectedItem.controller(
el: @$('.main')
)
@params.el = @$('.main')
@activeController = new selectedItem.controller(@params)
class App.GenericHistory extends App.ControllerModal
buttonClose: true

View file

@ -1,27 +1,24 @@
class Index extends App.ControllerContent
events:
'click .js-new': 'new'
'click .js-edit': 'edit'
'click .js-delete': 'delete'
'click .js-create-app': 'createApp'
'click .js-new': 'new'
'click .js-edit': 'edit'
'click .js-delete': 'delete'
'click .js-configApp': 'configApp'
'click .js-configApp': 'configApp'
constructor: ->
super
# check authentication
return if !@authenticate()
@render()
#@interval(@load, 60000)
#@load()
@load()
load: ->
load: =>
@startLoading()
@ajax(
id: 'twitter_index'
type: 'GET'
url: @apiPath + '/channels/twitter_index'
url: "#{@apiPath}/channels/twitter_index"
processData: true
success: (data, status, xhr) =>
@stopLoading()
@ -29,73 +26,173 @@ class Index extends App.ControllerContent
@render(data)
)
render: =>
# accounts = App.Twitter.search(
# sortBy: 'name'
# )
render: (data) =>
# # show description button, only if content exists
# showDescription = false
# if App.Twitter.description
# if !_.isEmpty(accounts)
# showDescription = true
# else
# description = marked(App.Twitter.description)
# if no twitter app is registered, show into
if !App.ExternalCredential.findByAttribute(name: 'twitter')
@html App.view('twitter/index')()
return
@html App.view('twitter/index')()
channels = []
for channel_id in data.channel_ids
channel = App.Channel.find(channel_id)
if channel && channel.options && channel.options.sync && channel.options.sync.search
for search in channel.options.sync.search
displayName = '-'
if search.group_id
group = App.Group.find(search.group_id)
displayName = group.displayName()
search.groupName = displayName
if channel && channel.options && channel.options.sync && channel.options.sync.mentions
displayName = '-'
if channel.options.sync.mentions.group_id
group = App.Group.find(channel.options.sync.mentions.group_id)
displayName = group.displayName()
channel.options.sync.mentions.groupName = displayName
if channel && channel.options && channel.options.sync && channel.options.sync.direct_messages
displayName = '-'
if channel.options.sync.direct_messages.group_id
group = App.Group.find(channel.options.sync.direct_messages.group_id)
displayName = group.displayName()
channel.options.sync.direct_messages.groupName = displayName
channels.push channel
@html App.view('twitter/list')(
channels: channels
)
# accounts: accounts
# showDescription: showDescription
# description: description
createApp: ->
modal = new App.ControllerModal
if @channel_id
@edit(undefined, @channel_id)
configApp: ->
external_credential = App.ExternalCredential.findByAttribute(name: 'twitter')
modal = new App.ControllerModal(
head: 'Connect Twitter App'
container: @el.parents('.content')
content: App.view('twitter/app_create')
contentInline: App.view('twitter/app_config')(external_credential: external_credential)
shown: true
button: 'Connect'
cancel: true
onSubmit: =>
@html App.view('twitter/list')()
modal.close()
small: true
onSubmit: (e) =>
@formDisable(e)
# verify app credentals
@ajax(
id: 'twitter_app_verify'
type: 'POST'
url: "#{@apiPath}/external_credentials/twitter/app_verify"
data: JSON.stringify(modal.formParams())
processData: true
success: (data, status, xhr) =>
if data.attributes
if !external_credential
external_credential = new App.ExternalCredential
external_credential.load(name: 'twitter', credentials: modal.formParams())
external_credential.save(
done: =>
@load()
modal.close()
fail: ->
modal.element().find('.alert').removeClass('hidden').text('Unable to create entry.')
)
return
@formEnable(e)
modal.element().find('.alert').removeClass('hidden').text(data.error || 'Unable to verify App.')
)
)
new: (e) ->
# e.preventDefault()
# new App.ControllerGenericNew(
# pageData:
# title: 'SLAs'
# object: 'Sla'
# objects: 'SLAs'
# genericObject: 'Sla'
# container: @el.closest('.content')
# callback: @load
# large: true
# )
window.location.href = "#{@apiPath}/external_credentials/twitter/link_account"
edit: (e) ->
# e.preventDefault()
# id = $(e.target).closest('.action').data('id')
# new App.ControllerGenericEdit(
# id: id
# pageData:
# title: 'SLAs'
# object: 'Sla'
# objects: 'SLAs'
# genericObject: 'Sla'
# callback: @load
# container: @el.closest('.content')
# large: true
# )
edit: (e, id) =>
if e
e.preventDefault()
id = $(e.target).closest('.action').data('id')
channel = App.Channel.find(id)
content = $( App.view('twitter/account_edit')(channel: channel) )
delete: (e) ->
# e.preventDefault()
# id = $(e.target).closest('.action').data('id')
# item = App.Twitter.find(id)
# new App.ControllerGenericDestroyConfirm(
# item: item
# container: @el.closest('.content')
# callback: @load
# )
groupSelection = (selected_id, el, prefix) ->
selection = App.UiElement.select.render(
name: "#{prefix}::group_id"
multiple: false
limit: 100
null: false
relation: 'Group'
nulloption: true
default: selected_id
)
el.find('.js-groups').html(selection)
placeholderAdd = (value = '', group_id) ->
placeholder = content.find('.js-searchTermPlaceholder').clone()
placeholder.removeClass('hidden').removeClass('js-searchTermPlaceholder')
placeholder.find('input').val(value)
placeholder.find('input').attr('name', 'search::term')
groupSelection(group_id, placeholder, 'search')
content.find('.js-searchTermList').append(placeholder)
for item in channel.options.sync.search
placeholderAdd(item.term, item.group_id, 'search')
content.find('.js-searchTermAdd').on('click', ->
placeholderAdd('', '')
)
content.find('.js-searchTerm').on('click', '.js-searchTermRemove',(e) ->
$(e.target).closest('.js-searchTermItem').remove()
)
groupSelection(channel.options.sync.mentions.group_id, content.find('.js-mention'), 'mentions')
groupSelection(channel.options.sync.direct_messages.group_id, content.find('.js-directMessage'), 'direct_messages')
modal = new App.ControllerModal(
head: 'Twitter Account'
container: @el.parents('.content')
contentInline: content
shown: true
cancel: true
onSubmit: (e) =>
@formDisable(e)
params = modal.formParams()
search = []
position = 0
if params.search
if _.isArray(params.search.term)
for key in params.search.term
item =
term: params.search.term[position]
group_id: params.search.group_id[position]
search.push item
position += 1
else
search.push params.search
params.search = search
channel.options.sync = params
@ajax(
id: 'channel_twitter_update'
type: 'POST'
url: "#{@apiPath}/channels/twitter_verify/#{channel.id}"
data: JSON.stringify(channel.attributes())
processData: true
success: (data, status, xhr) =>
@load()
modal.close()
fail: =>
@formEnable(e)
)
)
delete: (e) =>
e.preventDefault()
id = $(e.target).closest('.action').data('id')
item = App.Channel.find(id)
new App.ControllerGenericDestroyConfirm(
item: item
container: @el.closest('.content')
callback: @load
)
description: (e) =>
new App.ControllerGenericDescription(
@ -103,4 +200,4 @@ class Index extends App.ControllerContent
container: @el.closest('.content')
)
App.Config.set( 'Twitter', { prio: 5000, name: 'Twitter', parent: '#channels', target: '#channels/twitter', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
App.Config.set('Twitter', { prio: 5000, name: 'Twitter', parent: '#channels', target: '#channels/twitter', controller: Index, role: ['Admin'] }, 'NavBarAdmin')

View file

@ -1,13 +1,14 @@
class IndexRouter extends App.ControllerNavSidbar
configKey: 'NavBarAdmin'
App.Config.set( 'manage', IndexRouter, 'Routes' )
App.Config.set( 'manage/:target', IndexRouter, 'Routes' )
App.Config.set( 'settings/:target', IndexRouter, 'Routes' )
App.Config.set( 'channels/:target', IndexRouter, 'Routes' )
App.Config.set( 'system/:target', IndexRouter, 'Routes' )
App.Config.set('manage', IndexRouter, 'Routes')
App.Config.set('manage/:target', IndexRouter, 'Routes')
App.Config.set('settings/:target', IndexRouter, 'Routes')
App.Config.set('channels/:target', IndexRouter, 'Routes')
App.Config.set('channels/:target/:channel_id', IndexRouter, 'Routes')
App.Config.set('system/:target', IndexRouter, 'Routes')
App.Config.set( 'Manage', { prio: 1000, name: 'Manage', target: '#manage', role: ['Admin'] }, 'NavBarAdmin' )
App.Config.set( 'Channels', { prio: 2500, name: 'Channels', target: '#channels', role: ['Admin'] }, 'NavBarAdmin' )
App.Config.set( 'Settings', { prio: 7000, name: 'Settings', target: '#settings', role: ['Admin'] }, 'NavBarAdmin' )
App.Config.set( 'System', { prio: 8000, name: 'System', target: '#system', role: ['Admin'] }, 'NavBarAdmin' )
App.Config.set('Manage', { prio: 1000, name: 'Manage', target: '#manage', role: ['Admin'] }, 'NavBarAdmin')
App.Config.set('Channels', { prio: 2500, name: 'Channels', target: '#channels', role: ['Admin'] }, 'NavBarAdmin')
App.Config.set('Settings', { prio: 7000, name: 'Settings', target: '#settings', role: ['Admin'] }, 'NavBarAdmin')
App.Config.set('System', { prio: 8000, name: 'System', target: '#system', role: ['Admin'] }, 'NavBarAdmin')

View file

@ -206,4 +206,4 @@ class Verify extends App.ControllerContent
removeAll: true
@formEnable( @$('form') )
App.Config.set( 'password_reset_verify/:token', Verify, 'Routes' )
App.Config.set('password_reset_verify/:token', Verify, 'Routes')

View file

@ -77,6 +77,7 @@ class _ajaxSingleton
head: 'StatusCode: ' + status
contentInline: '<pre>' + App.Utils.htmlEscape(detail) + '</pre>'
buttonClose: true
buttonSubmit: false
)
)

View file

@ -115,7 +115,6 @@ class App.Auth
# store user data
sessionUser = App.User.fullLocal(data.session.id)
console.log('set', sessionUser)
App.Session.set(sessionUser)
# trigger auth ok with new session data

View file

@ -0,0 +1,4 @@
class App.ExternalCredential extends App.Model
@configure 'ExternalCredential', 'name', 'credentials'
@extend Spine.Model.Ajax
@url: @apiPath + '/external_credentials'

View file

@ -0,0 +1,31 @@
<div class="alert alert--danger hidden" role="alert"></div>
<fieldset>
<%- @T('Search Terms') %>
<div class="js-searchTerm">
<div class="js-searchTermItem js-searchTermPlaceholder hidden">
<input name="" value=""> -> <div class="js-groups"></div>
<div class="btn btn--text js-searchTermRemove">
<%- @Icon('trash') %> <%- @T('Remove') %>
</div>
<hr>
</div>
<div class="js-searchTermList"></div>
<div class="btn btn--text js-searchTermAdd">
<%- @Icon('plus-small') %> <%- @T('Add') %>
</div>
</div>
<hr>
<div class="js-mention">
<%- @T('Mentions') %> -> <div class="js-groups"></div>
</div>
<hr>
<div class="js-directMessage">
<%- @T('Direct Messages') %> -> <div class="js-groups"></div>
</div>
</fieldset>

View file

@ -0,0 +1,23 @@
<div class="alert alert--danger hidden" role="alert"></div>
<p>
The tutorial on how to create a Twitter App is hosted on <a href="http://zammad.org/twitter-app-tutorial" target="_blank">zammad.org/twitter-app-tutorial</a>
</p>
<fieldset>
<h2>Enter your Twitter App Keys</h2>
<div class="input form-group">
<div class="formGroup-label">
<label for="consumer_key">Twitter API Key <span>*</span></label>
</div>
<div class="controls">
<input id="consumer_key" type="text" name="consumer_key" value="<% if @external_credential && @external_credential.credentials: %><%= @external_credential.credentials.consumer_key %><% end %>" class="form-control" required autocomplete="off" >
</div>
</div>
<div class="input form-group">
<div class="formGroup-label">
<label for="consumer_secret">Twitter API Secret <span>*</span></label>
</div>
<div class="controls">
<input id="consumer_secret" type="text" name="consumer_secret" value="<% if @external_credential && @external_credential.credentials: %><%= @external_credential.credentials.consumer_secret %><% end %>" class="form-control" required autocomplete="off" >
</div>
</div>
</fieldset>

View file

@ -1,32 +0,0 @@
<h2>Create Twitter App</h2>
<p>
The tutorial on how to create a Twitter App is hosted on <a href="http://zammad.org/twitter-app-tutorial" target="_blank">zammad.org/twitter-app-tutorial</a>
</p>
<fieldset>
<div class="input form-group">
<div class="formGroup-label">
<label for="CallbackURL">Callback URL</label>
</div>
<div class="controls">
<input id="CallbackURL" type="text" name="name" class="form-control" value="http://example.com/twitter-app" readonly>
<span class="help-block">You need this callback URL for the Twitter App setup.</span>
</div>
</div>
<h2>Enter your Twitter App Keys</h2>
<div class="input form-group">
<div class="formGroup-label">
<label for="TwitterApiKey">Twitter API Key <span>*</span></label>
</div>
<div class="controls">
<input id="TwitterApiKey" type="text" name="name" class="form-control">
</div>
</div>
<div class="input form-group">
<div class="formGroup-label">
<label for="TwitterApiKeySecret">Twitter API Secret <span>*</span></label>
</div>
<div class="controls">
<input id="TwitterApiKeySecret" type="text" name="name" class="form-control">
</div>
</div>
</fieldset>

View file

@ -9,6 +9,6 @@
<p>
Lorem ipsum Consequat ex dolore ullamco dolor ut eu eiusmod voluptate. Lorem ipsum Non aliquip Ut veniam cupidatat velit deserunt. Lorem ipsum Id reprehenderit deserunt esse eiusmod exercitation. Lorem ipsum Voluptate mollit sed Ut nulla consequat enim. Lorem ipsum Adipisicing ullamco dolor elit officia pariatur ex ea laboris Ut exercitation proident sed. Lorem ipsum In officia reprehenderit sed nulla incididunt aute incididunt ad quis tempor. Lorem ipsum Dolore est id minim dolore et labore incididunt commodo. Lorem ipsum Excepteur non consectetur anim ut nostrud amet et. Lorem ipsum Sunt nostrud nulla officia aute laborum enim in pariatur sit enim et.
</p>
<div class="btn btn--success js-create-app"><%- @T('Connect Twitter App') %></div>
<div class="btn btn--success js-configApp"><%- @T('Connect Twitter App') %></div>
</div>
</div>

View file

@ -4,47 +4,60 @@
</div>
<div class="page-header-meta">
<a class="btn js-config"><%- @T('Configure App') %></a>
<a class="btn js-configApp"><%- @T('Configure App') %></a>
<a class="btn btn--success js-new"><%- @T('Add Account') %></a>
</div>
</div>
<div class="page-content">
<div class="action">
<% for channel in @channels: %>
<div class="action" data-id="<%= channel.id %>">
<div class="action-block action-row">
<h2><%- @Icon('status', 'supergood-color inline') %> Zammad Community <span class="text-muted">@zammad_community</span></h2>
<h2><%- @Icon('status', 'supergood-color inline') %> <%= channel.options.user.name %> <span class="text-muted">@<%= channel.options.user.screen_name %></span></h2>
</div>
<div class="action-flow action-flow--row">
<div class="action-block">
<h3><%- @T('Search Terms') %></h3>
zammad
<% if channel.options.sync.search: %>
<% for search in channel.options.sync.search: %>
<%= search.term %><br>
<% end %>
<% end %>
</div>
<%- @Icon('arrow-right', 'action-flow-icon') %>
<div class="action-block">
<h3><%- @T('Group') %></h3>
social network
<% if channel.options.sync.search: %>
<% for search in channel.options.sync.search: %>
<%= search.groupName %><br>
<% end %>
<% end %>
</div>
</div>
<div class="action-flow action-flow--row">
<div class="action-block">
<h3><%- @T('Mentions') %></h3>
@zammad_community
@<%= channel.options.user.screen_name %>
</div>
<%- @Icon('arrow-right', 'action-flow-icon') %>
<div class="action-block">
<h3><%- @T('Group') %></h3>
social network
<% if channel.options.sync.mentions: %>
<%= channel.options.sync.mentions.groupName %>
<% end %>
</div>
</div>
<div class="action-flow action-flow--row">
<div class="action-block">
<h3><%- @T('Direct Messages') %></h3>
@zammad_community
@<%= channel.options.user.screen_name %>
</div>
<%- @Icon('arrow-right', 'action-flow-icon') %>
<div class="action-block">
<h3><%- @T('Group') %></h3>
social network
<% if channel.options.sync.direct_messages: %>
<%= channel.options.sync.direct_messages.groupName %>
<% end %>
</div>
</div>
<div class="action-controls">
@ -52,4 +65,5 @@
<div class="sla-edit btn js-edit"><%- @T('Edit') %></div>
</div>
</div>
<% end %>
</div>

View file

@ -45,6 +45,28 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
model_destory_render(Channel, params)
end
def twitter_index
assets = {}
ExternalCredential.where(name: 'twitter').each {|external_credential|
assets = external_credential.assets(assets)
}
channel_ids = []
Channel.order(:id).each {|channel|
next if channel.area != 'Twitter::Account'
assets = channel.assets(assets)
channel_ids.push channel.id
}
render json: {
assets: assets,
channel_ids: channel_ids,
}
end
def twitter_verify
return if deny_if_not_role(Z_ROLENAME_ADMIN)
model_update_render(Channel, params)
end
def email_index
return if deny_if_not_role(Z_ROLENAME_ADMIN)
system_online_service = Setting.get('system_online_service')

View file

@ -15,28 +15,12 @@ class ExternalCredentialsController < ApplicationController
def create
return if deny_if_not_role(Z_ROLENAME_ADMIN)
# try access
begin
attributes = ExternalCredential.app_verify(params)
model_create_render(ExternalCredential, { name: params[:provider].downcase, credentials: attributes })
return
rescue => e
render json: { error: e.message }, status: :unprocessable_entity
end
model_create_render(ExternalCredential, params)
end
def update
return if deny_if_not_role(Z_ROLENAME_ADMIN)
# try access
begin
attributes = ExternalCredential.app_verify(params)
model_update_render(ExternalCredential, { name: params[:provider].downcase, credentials: attributes })
return
rescue => e
render json: { error: e.message }, status: :unprocessable_entity
end
model_update_render(ExternalCredential, params)
end
def destroy
@ -44,26 +28,29 @@ class ExternalCredentialsController < ApplicationController
model_destory_render(ExternalCredential, params)
end
def app_verify
attributes = ExternalCredential.app_verify(params)
render json: { attributes: attributes }, status: :ok
return
rescue => e
render json: { error: e.message }, status: :ok
end
def link_account
return if deny_if_not_role(Z_ROLENAME_ADMIN)
provider = params[:provider].downcase
attributes = ExternalCredential.request_account_to_link(provider, callback_url(provider))
session[:request_token] = attributes[:request_token]
redirect_to attributes[:authorize_url]
end
def callback
return if deny_if_not_role(Z_ROLENAME_ADMIN)
provider = params[:provider].downcase
channel = ExternalCredential.link_account(provider, session[:request_token], params)
session[:request_token] = nil
render json: channel
redirect_to app_url(provider, channel.id)
end
private
@ -72,4 +59,8 @@ class ExternalCredentialsController < ApplicationController
"#{Setting.get('http_type')}://#{Setting.get('fqdn')}#{Rails.configuration.api_path}/external_credentials/#{provider}/callback"
end
def app_url(provider, channel_id)
"#{Setting.get('http_type')}://#{Setting.get('fqdn')}/#channels/#{provider}/#{channel_id}"
end
end

View file

@ -47,6 +47,8 @@ class Channel::Driver::Twitter
def fetch (options, channel)
options = check_external_credential(options)
@tweet = Tweet.new(options[:auth])
@sync = options[:sync]
@channel = channel
@ -90,6 +92,8 @@ class Channel::Driver::Twitter
# return if we run import mode
return if Setting.get('import_mode')
options = check_external_credential(options)
@tweet = Tweet.new(options[:auth])
tweet = @tweet.from_article(article)
disconnect
@ -164,4 +168,15 @@ class Channel::Driver::Twitter
counter += 1
}
end
def check_external_credential(options)
if options[:auth] && options[:auth][:external_credential_id]
external_credential = ExternalCredential.find_by(id: options[:auth][:external_credential_id])
fail "No such ExternalCredential.find(#{options[:auth][:external_credential_id]})" if !external_credential
options[:auth][:consumer_key] = external_credential.credentials['consumer_key']
options[:auth][:consumer_secret] = external_credential.credentials['consumer_secret']
end
options
end
end

View file

@ -9,8 +9,12 @@ Zammad::Application.routes.draw do
match api_path + '/channels/email_verify', to: 'channels#email_verify', via: :post
match api_path + '/channels/email_notification', to: 'channels#email_notification', via: :post
# twitter helper
match api_path + '/channels/twitter_index', to: 'channels#twitter_index', via: :get
match api_path + '/channels/twitter_verify/:id', to: 'channels#twitter_verify', via: :post
# channels
match api_path + '/channels/group/:id', to: 'channels#group_update', via: :post
match api_path + '/channels/:id', to: 'channels#destroy', via: :delete
match api_path + '/channels/group/:id', to: 'channels#group_update', via: :post
match api_path + '/channels/:id', to: 'channels#destroy', via: :delete
end

View file

@ -9,6 +9,7 @@ Zammad::Application.routes.draw do
match api_path + '/external_credentials/:id', to: 'external_credentials#destroy', via: :delete
# callback URL
match api_path + '/external_credentials/:provider/app_verify', to: 'external_credentials#app_verify', via: :post
match api_path + '/external_credentials/:provider/link_account', to: 'external_credentials#link_account', via: :get
match api_path + '/external_credentials/:provider/callback', to: 'external_credentials#callback', via: :get

View file

@ -11,9 +11,15 @@ class ExternalCredential::Twitter
def self.request_account_to_link(callback_url, credentials = {})
external_credential = ExternalCredential.find_by(name: 'twitter')
if !credentials[:consumer_key]
credentials[:consumer_key] = external_credential.credentials['consumer_key']
end
if !credentials[:consumer_secret]
credentials[:consumer_secret] = external_credential.credentials['consumer_secret']
end
consumer = OAuth::Consumer.new(
credentials[:consumer_key] || external_credential.credentials[:consumer_key],
credentials[:consumer_secret] || external_credential.credentials[:consumer_secret], {
credentials[:consumer_key],
credentials[:consumer_secret], {
site: 'https://api.twitter.com'
})
request_token = consumer.get_request_token(oauth_callback: callback_url)
@ -25,7 +31,6 @@ class ExternalCredential::Twitter
def self.link_account(request_token, params)
fail if request_token.params[:oauth_token] != params[:oauth_token]
external_credential = ExternalCredential.find_by(name: 'twitter')
access_token = request_token.get_access_token(oauth_verifier: params[:oauth_verifier])
client = Twitter::REST::Client.new(
@ -44,6 +49,7 @@ class ExternalCredential::Twitter
user: {
id: user.id,
screen_name: user.screen_name,
name: user.name,
},
auth: {
external_credential_id: external_credential.id,