diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3bd3cdf86..13c219e45 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -187,6 +187,40 @@ job_integration_otrs_31:
- rake db:migrate
- ruby -I test/ test/integration/otrs_import_test.rb
+job_integration_twitter_ff:
+ stage: browser
+ tags:
+ - browser-ff
+ - twitter
+ script:
+ - export BROWSER_PORT=3041
+ - export WS_PORT=3042
+ - export BROWSER_URL=http://$IP:$BROWSER_PORT
+ - RAILS_ENV=test rake db:create
+ - script/bootstrap.sh
+ - rake assets:precompile
+ - script/build/test_startup.sh $RAILS_ENV $BROWSER_PORT $WS_PORT
+ - ruby -I test/ test/integration/twitter_browser_test.rb || script/build/test_shutdown.sh $RAILS_ENV $BROWSER_PORT $WS_PORT 1
+ - script/build/test_shutdown.sh $RAILS_ENV $BROWSER_PORT $WS_PORT
+http://192.168.122.75:3041/api/v1/external_credentials/twitter/callback
+
+job_integration_facebook_ff:
+ stage: browser
+ tags:
+ - browser-ff
+ - facebook
+ script:
+ - export BROWSER_PORT=3051
+ - export WS_PORT=3052
+ - export BROWSER_URL=http://$IP:$BROWSER_PORT
+ - RAILS_ENV=test rake db:create
+ - script/bootstrap.sh
+ - rake assets:precompile
+ - script/build/test_startup.sh $RAILS_ENV $BROWSER_PORT $WS_PORT
+ - ruby -I test/ test/integration/facebook_browser_test.rb || script/build/test_shutdown.sh $RAILS_ENV $BROWSER_PORT $WS_PORT 1
+ - script/build/test_shutdown.sh $RAILS_ENV $BROWSER_PORT $WS_PORT
+http://192.168.122.75:3051/api/v1/external_credentials/facebook/callback
+
job_integration_autowizard_ff:
stage: browser
tags:
@@ -264,8 +298,8 @@ job_integration_autowizard_chrome:
tags:
- browser-chrome
script:
- - export BROWSER_PORT=3071
- - export WS_PORT=3072
+ - export BROWSER_PORT=4001
+ - export WS_PORT=4002
- export BROWSER_URL=http://$IP:$BROWSER_PORT
- RAILS_ENV=test rake db:create
- cp contrib/auto_wizard_example.json auto_wizard.json
@@ -280,8 +314,8 @@ job_integration_browser_chrome_1:
tags:
- browser-chrome
script:
- - export BROWSER_PORT=3041
- - export WS_PORT=3042
+ - export BROWSER_PORT=4011
+ - export WS_PORT=4012
- export BROWSER_URL=http://$IP:$BROWSER_PORT
- unset MAILBOX_AUTO1
- unset MAILBOX_AUTO2
@@ -300,8 +334,8 @@ job_integration_browser_chrome_2:
tags:
- browser-chrome
script:
- - export BROWSER_PORT=3051
- - export WS_PORT=3052
+ - export BROWSER_PORT=4021
+ - export WS_PORT=4022
- export BROWSER_URL=http://$IP:$BROWSER_PORT
- unset MAILBOX_AUTO1
- unset MAILBOX_AUTO2
@@ -320,8 +354,8 @@ job_integration_browser_chrome_3:
tags:
- browser-chrome
script:
- - export BROWSER_PORT=3061
- - export WS_PORT=3062
+ - export BROWSER_PORT=4031
+ - export WS_PORT=4032
- export BROWSER_URL=http://$IP:$BROWSER_PORT
- unset MAILBOX_AUTO1
- unset MAILBOX_AUTO2
diff --git a/app/assets/javascripts/app/controllers/_application_controller.coffee b/app/assets/javascripts/app/controllers/_application_controller.coffee
index ed717fc64..044669b66 100644
--- a/app/assets/javascripts/app/controllers/_application_controller.coffee
+++ b/app/assets/javascripts/app/controllers/_application_controller.coffee
@@ -486,9 +486,6 @@ class App.Controller extends Spine.Controller
item.created_by = App.User.find( item.created_by_id )
items
- ws_send: (data) ->
- App.Event.trigger( 'ws:send', JSON.stringify(data) )
-
# central method, is getting called on every ticket form change
ticketFormChanges: (params, attribute, attributes, classname, form, ui) =>
if @formMeta.dependencies && @formMeta.dependencies[attribute.name]
@@ -573,6 +570,10 @@ class App.Controller extends Spine.Controller
logoUrl: ->
"#{@Config.get('image_path')}/#{@Config.get('product_logo')}"
+ selectAll: (e) ->
+ e.currentTarget.focus()
+ e.currentTarget.select()
+
class App.ControllerPermanent extends App.Controller
constructor: ->
super
diff --git a/app/assets/javascripts/app/controllers/_channel/facebook.coffee b/app/assets/javascripts/app/controllers/_channel/facebook.coffee
index 8ec5d5c9b..045c025ed 100644
--- a/app/assets/javascripts/app/controllers/_channel/facebook.coffee
+++ b/app/assets/javascripts/app/controllers/_channel/facebook.coffee
@@ -1,16 +1,186 @@
-class App.ChannelFacebook extends App.Controller
+class Index extends App.ControllerContent
+ events:
+ 'click .js-new': 'new'
+ 'click .js-edit': 'edit'
+ 'click .js-delete': 'delete'
+ 'click .js-configApp': 'configApp'
+
constructor: ->
super
+ return if !@authenticate()
- @title 'Facebook'
+ #@interval(@load, 60000)
+ @load()
- # render page
- @render()
-
- render: ->
-
- @html App.view('channel/facebook')(
- head: 'some header'
+ load: =>
+ @startLoading()
+ @ajax(
+ id: 'facebook_index'
+ type: 'GET'
+ url: "#{@apiPath}/channels/facebook_index"
+ processData: true
+ success: (data, status, xhr) =>
+ @stopLoading()
+ App.Collection.loadAssets(data.assets)
+ @callbackUrl = data.callback_url
+ @render(data)
)
-App.Config.set( 'Facebook', { prio: 6000, name: 'Facebook', parent: '#channels', target: '#channels/facebook', controller: App.ChannelFacebook, role: ['Admin'] }, 'NavBarAdmin' )
+ render: (data) =>
+
+ # if no facebook app is registered, show intro
+ if !App.ExternalCredential.findByAttribute(name: 'facebook')
+ @html App.view('facebook/index')()
+ return
+
+ channels = []
+ for channel_id in data.channel_ids
+ channel = App.Channel.find(channel_id)
+ if channel && channel.options && channel.options.sync
+ displayName = '-'
+ if channel.options.sync.wall.group_id
+ group = App.Group.find(channel.options.sync.wall.group_id)
+ displayName = group.displayName()
+ channel.options.sync.wall.groupName = displayName
+ for page in channel.options.pages
+ displayName = '-'
+ for page_id, pageParams of channel.options.sync.pages
+ if page.id is page_id
+ if pageParams.group_id
+ group = App.Group.find(pageParams.group_id)
+ displayName = group.displayName()
+ page.groupName = displayName
+ channels.push channel
+ @html App.view('facebook/list')(
+ channels: channels
+ )
+ # accounts: accounts
+ # showDescription: showDescription
+ # description: description
+
+ if @channel_id
+ @edit(undefined, @channel_id)
+
+ configApp: =>
+ external_credential = App.ExternalCredential.findByAttribute('name', 'facebook')
+ contentInline = $(App.view('facebook/app_config')(
+ external_credential: external_credential
+ callbackUrl: @callbackUrl
+ ))
+ contentInline.find('.js-select').on('click', (e) =>
+ @selectAll(e)
+ )
+ modal = new App.ControllerModal(
+ head: 'Connect Facebook App'
+ container: @el.parents('.content')
+ contentInline: contentInline
+ shown: true
+ button: 'Connect'
+ cancel: true
+ small: true
+ onSubmit: (e) =>
+ @formDisable(e)
+
+ # verify app credentals
+ @ajax(
+ id: 'facebook_app_verify'
+ type: 'POST'
+ url: "#{@apiPath}/external_credentials/facebook/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: 'facebook', 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) ->
+ window.location.href = "#{@apiPath}/external_credentials/facebook/link_account"
+
+ edit: (e, id) =>
+ if e
+ e.preventDefault()
+ id = $(e.target).closest('.action').data('id')
+ channel = App.Channel.find(id)
+ if !channel.options.sync
+ channel.options.sync = {}
+ if !channel.options.sync.wall
+ channel.options.sync.wall = {}
+ if !channel.options.sync.pages
+ channel.options.sync.pages = {}
+ content = $( App.view('facebook/account_edit')(channel: channel) )
+
+ 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.html(selection)
+
+ groupSelection(channel.options.sync.wall.group_id, content.find('.js-wall .js-groups'), 'wall')
+ for page in channel.options.pages
+ pageConfigured = false
+ for page_id, pageParams of channel.options.sync.pages
+ if page.id is page_id
+ pageConfigured = true
+ groupSelection(pageParams.group_id, content.find(".js-groups[data-page-id=#{page.id}]"), "pages::#{page.id}")
+ if !pageConfigured
+ groupSelection('', content.find(".js-groups[data-page-id=#{page.id}]"), "pages::#{page.id}")
+
+ modal = new App.ControllerModal(
+ head: 'Facebook Account'
+ container: @el.parents('.content')
+ contentInline: content
+ shown: true
+ cancel: true
+ onSubmit: (e) =>
+ @formDisable(e)
+ channel.options.sync = modal.formParams()
+ @ajax(
+ id: 'channel_facebook_update'
+ type: 'POST'
+ url: "#{@apiPath}/channels/facebook_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(
+ description: App.Twitter.description
+ container: @el.closest('.content')
+ )
+
+App.Config.set('Facebook', { prio: 5100, name: 'Facebook', parent: '#channels', target: '#channels/facebook', controller: Index, role: ['Admin'] }, 'NavBarAdmin')
diff --git a/app/assets/javascripts/app/controllers/_channel/twitter.coffee b/app/assets/javascripts/app/controllers/_channel/twitter.coffee
index d45412153..33478f7c1 100644
--- a/app/assets/javascripts/app/controllers/_channel/twitter.coffee
+++ b/app/assets/javascripts/app/controllers/_channel/twitter.coffee
@@ -4,7 +4,6 @@ class Index extends App.ControllerContent
'click .js-edit': 'edit'
'click .js-delete': 'delete'
'click .js-configApp': 'configApp'
- 'click .js-configApp': 'configApp'
constructor: ->
super
@@ -23,12 +22,13 @@ class Index extends App.ControllerContent
success: (data, status, xhr) =>
@stopLoading()
App.Collection.loadAssets(data.assets)
+ @callbackUrl = data.callback_url
@render(data)
)
render: (data) =>
- # if no twitter app is registered, show into
+ # if no twitter app is registered, show intro
if !App.ExternalCredential.findByAttribute(name: 'twitter')
@html App.view('twitter/index')()
return
@@ -66,12 +66,19 @@ class Index extends App.ControllerContent
if @channel_id
@edit(undefined, @channel_id)
- configApp: ->
- external_credential = App.ExternalCredential.findByAttribute(name: 'twitter')
+ configApp: =>
+ external_credential = App.ExternalCredential.findByAttribute('name', 'twitter')
+ contentInline = $(App.view('twitter/app_config')(
+ external_credential: external_credential
+ callbackUrl: @callbackUrl
+ ))
+ contentInline.find('.js-select').on('click', (e) =>
+ @selectAll(e)
+ )
modal = new App.ControllerModal(
head: 'Connect Twitter App'
container: @el.parents('.content')
- contentInline: App.view('twitter/app_config')(external_credential: external_credential)
+ contentInline: contentInline
shown: true
button: 'Connect'
cancel: true
diff --git a/app/assets/javascripts/app/controllers/_profile/calendar_subscriptions.coffee b/app/assets/javascripts/app/controllers/_profile/calendar_subscriptions.coffee
index ef0c3e101..1009cc0db 100644
--- a/app/assets/javascripts/app/controllers/_profile/calendar_subscriptions.coffee
+++ b/app/assets/javascripts/app/controllers/_profile/calendar_subscriptions.coffee
@@ -37,10 +37,6 @@ class CalendarSubscriptions extends App.Controller
$(e.currentTarget).next().removeClass('is-hidden')
$(e.currentTarget).remove()
- selectAll: (e) ->
- e.currentTarget.focus()
- e.currentTarget.select()
-
onOptionsChange: =>
@setAllPreferencesToFalse()
diff --git a/app/assets/javascripts/app/views/facebook/account_edit.jst.eco b/app/assets/javascripts/app/views/facebook/account_edit.jst.eco
new file mode 100644
index 000000000..80e464ea0
--- /dev/null
+++ b/app/assets/javascripts/app/views/facebook/account_edit.jst.eco
@@ -0,0 +1,20 @@
+
+
+
+ <%- @T('Wall') %>
+
+ <%= @channel.options.user.name %> ->
+
+
+
+
+ <%- @T('Pages') %>
+
+ <% if @channel.options.pages: %>
+ <% for page in @channel.options.pages: %>
+ <%= page.name %> ->
+ <% end %>
+ <% end %>
+
+
+
\ No newline at end of file
diff --git a/app/assets/javascripts/app/views/facebook/app_config.jst.eco b/app/assets/javascripts/app/views/facebook/app_config.jst.eco
new file mode 100644
index 000000000..1bbb27c70
--- /dev/null
+++ b/app/assets/javascripts/app/views/facebook/app_config.jst.eco
@@ -0,0 +1,29 @@
+
+
+ The tutorial on how to create a Facebook App is hosted on zammad.org/facebook-app-tutorial
+
+
+ <%- @T('Enter your %s App Keys', 'Facebook') %>
+
+
+ <%- @T('Your callback URL') %>
+
+
\ No newline at end of file
diff --git a/app/assets/javascripts/app/views/facebook/index.jst.eco b/app/assets/javascripts/app/views/facebook/index.jst.eco
new file mode 100644
index 000000000..9ca4976b3
--- /dev/null
+++ b/app/assets/javascripts/app/views/facebook/index.jst.eco
@@ -0,0 +1,14 @@
+
+
+
+
+
+ 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.
+
+
<%- @T('Connect Facebook App') %>
+
+
\ No newline at end of file
diff --git a/app/assets/javascripts/app/views/facebook/list.jst.eco b/app/assets/javascripts/app/views/facebook/list.jst.eco
new file mode 100644
index 000000000..657a79b70
--- /dev/null
+++ b/app/assets/javascripts/app/views/facebook/list.jst.eco
@@ -0,0 +1,41 @@
+
+
+
+<% for channel in @channels: %>
+
+
+
<%- @Icon('status', 'supergood-color inline') %> <%= channel.options.user.name %> <%= channel.options.user.id %>
+
+
+
+
<%- @T('Wall') %>
+ <%= channel.options.user.name %> -> <%= channel.options.sync.wall.groupName %>
+
+
+
+
+
<%- @T('Pages') %>
+ <% if channel.options.pages: %>
+ <% for page in channel.options.pages: %>
+ <%= page.name %> -> <%= page.groupName %>
+ (<%= page.perms %>)
+ <% end %>
+ <% end %>
+
+
+
+
<%- @T('Delete') %>
+
<%- @T('Edit') %>
+
+
+<% end %>
+
\ No newline at end of file
diff --git a/app/assets/javascripts/app/views/twitter/app_config.jst.eco b/app/assets/javascripts/app/views/twitter/app_config.jst.eco
index 145393c16..933967e60 100644
--- a/app/assets/javascripts/app/views/twitter/app_config.jst.eco
+++ b/app/assets/javascripts/app/views/twitter/app_config.jst.eco
@@ -3,7 +3,7 @@
The tutorial on how to create a Twitter App is hosted on zammad.org/twitter-app-tutorial
- Enter your Twitter App Keys
+ <%- @T('Enter your %s App Keys', 'Twitter') %>
+ <%- @T('Your callback URL') %>
+
\ No newline at end of file
diff --git a/app/controllers/channels_controller.rb b/app/controllers/channels_controller.rb
index bad56e2b7..e64be0c33 100644
--- a/app/controllers/channels_controller.rb
+++ b/app/controllers/channels_controller.rb
@@ -59,6 +59,7 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
render json: {
assets: assets,
channel_ids: channel_ids,
+ callback_url: ExternalCredential.callback_url('twitter'),
}
end
@@ -67,6 +68,29 @@ curl http://localhost/api/v1/channels.json -v -u #{login}:#{password} -H "Conten
model_update_render(Channel, params)
end
+ def facebook_index
+ assets = {}
+ ExternalCredential.where(name: 'facebook').each {|external_credential|
+ assets = external_credential.assets(assets)
+ }
+ channel_ids = []
+ Channel.order(:id).each {|channel|
+ next if channel.area != 'Facebook::Account'
+ assets = channel.assets(assets)
+ channel_ids.push channel.id
+ }
+ render json: {
+ assets: assets,
+ channel_ids: channel_ids,
+ callback_url: ExternalCredential.callback_url('facebook'),
+ }
+ end
+
+ def facebook_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')
diff --git a/app/controllers/external_credentials_controller.rb b/app/controllers/external_credentials_controller.rb
index eeb28d36d..8ca86bc0f 100644
--- a/app/controllers/external_credentials_controller.rb
+++ b/app/controllers/external_credentials_controller.rb
@@ -34,13 +34,12 @@ class ExternalCredentialsController < ApplicationController
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))
+ attributes = ExternalCredential.request_account_to_link(provider)
session[:request_token] = attributes[:request_token]
redirect_to attributes[:authorize_url]
end
@@ -56,11 +55,11 @@ class ExternalCredentialsController < ApplicationController
private
def callback_url(provider)
- "#{Setting.get('http_type')}://#{Setting.get('fqdn')}#{Rails.configuration.api_path}/external_credentials/#{provider}/callback"
+ ExternalCredential.callback_url(provider)
end
def app_url(provider, channel_id)
- "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/#channels/#{provider}/#{channel_id}"
+ ExternalCredential.app_url(provider, channel_id)
end
end
diff --git a/app/models/external_credential.rb b/app/models/external_credential.rb
index 830316238..9d5c5c429 100644
--- a/app/models/external_credential.rb
+++ b/app/models/external_credential.rb
@@ -9,9 +9,9 @@ class ExternalCredential < ApplicationModel
backend.app_verify(params)
end
- def self.request_account_to_link(provider, callback)
+ def self.request_account_to_link(provider)
backend = load_backend(provider)
- backend.request_account_to_link(callback)
+ backend.request_account_to_link
end
def self.link_account(provider, request_token, params)
@@ -19,6 +19,14 @@ class ExternalCredential < ApplicationModel
backend.link_account(request_token, params)
end
+ def self.callback_url(provider)
+ "#{Setting.get('http_type')}://#{Setting.get('fqdn')}#{Rails.configuration.api_path}/external_credentials/#{provider}/callback"
+ end
+
+ def self.app_url(provider, channel_id)
+ "#{Setting.get('http_type')}://#{Setting.get('fqdn')}/#channels/#{provider}/#{channel_id}"
+ end
+
def self.load_backend(provider)
adapter = "ExternalCredential::#{provider.camelcase}"
require "#{adapter.to_filename}"
diff --git a/config/routes/channel.rb b/config/routes/channel.rb
index bd3286140..0bc9e246a 100644
--- a/config/routes/channel.rb
+++ b/config/routes/channel.rb
@@ -13,6 +13,10 @@ Zammad::Application.routes.draw do
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
+ # facebook helper
+ match api_path + '/channels/facebook_index', to: 'channels#facebook_index', via: :get
+ match api_path + '/channels/facebook_verify/:id', to: 'channels#facebook_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
diff --git a/lib/external_credential/facebook.rb b/lib/external_credential/facebook.rb
new file mode 100644
index 000000000..689007320
--- /dev/null
+++ b/lib/external_credential/facebook.rb
@@ -0,0 +1,87 @@
+class ExternalCredential::Facebook
+
+ def self.app_verify(params)
+ request_account_to_link(params)
+ params
+ end
+
+ def self.request_account_to_link(credentials = {})
+ external_credential = ExternalCredential.find_by(name: 'facebook')
+ if !credentials[:application_id]
+ credentials[:application_id] = external_credential.credentials['application_id']
+ end
+ if !credentials[:application_secret]
+ credentials[:application_secret] = external_credential.credentials['application_secret']
+ end
+
+ oauth = Koala::Facebook::OAuth.new(
+ credentials[:application_id],
+ credentials[:application_secret],
+ ExternalCredential.callback_url('facebook'),
+ )
+ oauth.get_app_access_token.inspect
+ state = rand(999_999_999_999).to_s
+ {
+ request_token: state,
+ authorize_url: oauth.url_for_oauth_code(permissions: 'publish_pages, manage_pages', state: state),
+ }
+ end
+
+ def self.link_account(_request_token, params)
+ # fail if request_token.params[:oauth_token] != params[:state]
+ external_credential = ExternalCredential.find_by(name: 'facebook')
+ fail 'No such account' if !external_credential
+ oauth = Koala::Facebook::OAuth.new(
+ external_credential.credentials['application_id'],
+ external_credential.credentials['application_secret'],
+ ExternalCredential.callback_url('facebook'),
+ )
+
+ access_token = oauth.get_access_token(params[:code])
+ client = Koala::Facebook::API.new(access_token)
+ user = client.get_object('me')
+ #p client.get_connections('me', 'accounts').inspect
+ pages = []
+ client.get_connections('me', 'accounts').each { |page|
+ pages.push(
+ id: page['id'],
+ name: page['name'],
+ access_token: page['access_token'],
+ perms: page['perms'],
+ )
+ }
+
+ # check if account already exists
+ Channel.where(area: 'Facebook::Account').each {|channel|
+ next if !channel.options
+ next if !channel.options['user']
+ next if !channel.options['user']['id']
+ next if channel.options['user']['id'] != user['id']
+ channel.options['auth']['access_token'] = access_token
+ channel.options['pages'] = pages
+ channel.save
+ return channel
+ }
+
+ # create channel
+ Channel.create(
+ area: 'Facebook::Account',
+ options: {
+ adapter: 'facebook',
+ auth: {
+ access_token: access_token
+ },
+ user: user,
+ pages: pages,
+ sync: {
+ wall: {},
+ pages: [],
+ }
+ },
+ active: true,
+ created_by_id: 1,
+ updated_by_id: 1,
+ )
+ end
+
+end
diff --git a/lib/external_credential/twitter.rb b/lib/external_credential/twitter.rb
index 71b4ee5f9..4f9968e8d 100644
--- a/lib/external_credential/twitter.rb
+++ b/lib/external_credential/twitter.rb
@@ -1,15 +1,11 @@
class ExternalCredential::Twitter
def self.app_verify(params)
- attributes = {
- consumer_key: params[:consumer_key],
- consumer_secret: params[:consumer_secret],
- }
- request_account_to_link('', attributes)
- attributes
+ request_account_to_link(params)
+ params
end
- def self.request_account_to_link(callback_url, credentials = {})
+ def self.request_account_to_link(credentials = {})
external_credential = ExternalCredential.find_by(name: 'twitter')
if !credentials[:consumer_key]
credentials[:consumer_key] = external_credential.credentials['consumer_key']
@@ -21,8 +17,9 @@ class ExternalCredential::Twitter
credentials[:consumer_key],
credentials[:consumer_secret], {
site: 'https://api.twitter.com'
- })
- request_token = consumer.get_request_token(oauth_callback: callback_url)
+ }
+ )
+ request_token = consumer.get_request_token(oauth_callback: ExternalCredential.callback_url('twitter'))
{
request_token: request_token,
authorize_url: request_token.authorize_url,
@@ -41,6 +38,21 @@ class ExternalCredential::Twitter
)
user = client.user
+ # check if account already exists
+ Channel.where(area: 'Twitter::Account').each {|channel|
+ next if !channel.options
+ next if !channel.options['user']
+ next if !channel.options['user']['id']
+ next if channel.options['user']['id'] != user['id']
+
+ # update access_token
+ channel.options['auth']['external_credential_id'] = external_credential.id
+ channel.options['auth']['oauth_token'] = access_token.token
+ channel.options['auth']['oauth_token_secret'] = access_token.secret
+ channel.save
+ return channel
+ }
+
# create channel
Channel.create(
area: 'Twitter::Account',
diff --git a/test/integration/facebook_browser_test.rb b/test/integration/facebook_browser_test.rb
new file mode 100644
index 000000000..e8e275e4f
--- /dev/null
+++ b/test/integration/facebook_browser_test.rb
@@ -0,0 +1,170 @@
+# encoding: utf-8
+require 'browser_test_helper'
+
+class FacebookBrowserTest < TestCase
+ def test_add_config
+
+ # app config
+ if !ENV['FACEBOOK_APP_ID']
+ fail "ERROR: Need FACEBOOK_APP_ID - hint FACEBOOK_APP_ID='1234'"
+ end
+ app_id = ENV['FACEBOOK_APP_ID']
+ if !ENV['FACEBOOK_APP_SECRET']
+ fail "ERROR: Need FACEBOOK_APP_SECRET - hint FACEBOOK_APP_SECRET='1234'"
+ end
+ app_secret = ENV['FACEBOOK_APP_SECRET']
+ if !ENV['FACEBOOK_USER_LOGIN']
+ fail "ERROR: Need FACEBOOK_USER_LOGIN - hint FACEBOOK_USER_LOGIN='1234'"
+ end
+ user_login = ENV['FACEBOOK_USER_LOGIN']
+ if !ENV['FACEBOOK_USER_PW']
+ fail "ERROR: Need FACEBOOK_USER_PW - hint FACEBOOK_USER_PW='1234'"
+ end
+ user_pw = ENV['FACEBOOK_USER_PW']
+
+ @browser = browser_instance
+ login(
+ username: 'master@example.com',
+ password: 'test',
+ url: browser_url,
+ )
+ tasks_close_all()
+
+ click(css: 'a[href="#manage"]')
+ click(css: 'a[href="#channels/facebook"]')
+
+ click(css: '#content .js-configApp')
+ sleep 2
+ set(
+ css: '#content .modal [name=application_id]',
+ value: app_id,
+ )
+ set(
+ css: '#content .modal [name=application_secret]',
+ value: 'wrong',
+ )
+ click(css: '#content .modal .js-submit')
+
+ watch_for(
+ css: '#content .modal .alert',
+ value: 'Error',
+ )
+
+ set(
+ css: '#content .modal [name=application_secret]',
+ value: app_secret,
+ )
+ click(css: '#content .modal .js-submit')
+
+ watch_for_disappear(
+ css: '#content .modal .alert',
+ value: 'Error',
+ )
+
+ watch_for(
+ css: '#content .js-new',
+ value: 'add account',
+ )
+
+ click(css: '#content .js-configApp')
+
+ set(
+ css: '#content .modal [name=application_secret]',
+ value: 'wrong',
+ )
+ click(css: '#content .modal .js-submit')
+
+ watch_for(
+ css: '#content .modal .alert',
+ value: 'Error',
+ )
+
+ set(
+ css: '#content .modal [name=application_secret]',
+ value: app_secret,
+ )
+ click(css: '#content .modal .js-submit')
+
+ watch_for_disappear(
+ css: '#content .modal .alert',
+ value: 'Error',
+ )
+
+ watch_for(
+ css: '#content .js-new',
+ value: 'add account',
+ )
+
+ click(css: '#content .js-new')
+
+ watch_for(
+ css: 'body',
+ value: 'Facebook Login',
+ )
+
+ set(
+ css: '#email',
+ value: user_login,
+ )
+ set(
+ css: '#pass',
+ value: user_pw,
+ )
+ click(css: '#login_button_inline')
+
+ #sleep 10
+ #click(css: 'div[role="dialog"] button[type="submit"][name="__CONFIRM__"]')
+ #sleep 10
+ #click(css: 'div[role="dialog"] button[type="submit"][name="__CONFIRM__"]')
+ #sleep 10
+
+ #watch_for(
+ # css: '#content .modal',
+ # value: '',
+ #)
+
+ watch_for(
+ css: '#navigation',
+ value: 'Dashboard',
+ )
+
+ #click(css: '#content .modal .js-close')
+
+ watch_for(
+ css: '#content',
+ value: 'Hansi Merkur',
+ )
+ exists(
+ css: '#content .main .action:nth-child(1)'
+ )
+ exists_not(
+ css: '#content .main .action:nth-child(2)'
+ )
+
+ click(css: '#content .js-new')
+
+ sleep 10
+
+ #click(css: '#login_button_inline')
+
+ #watch_for(
+ # css: '#content .modal',
+ # value: 'Search Terms',
+ #)
+
+ #click(css: '#content .modal .js-close')
+
+ watch_for(
+ css: '#content',
+ value: 'Hansi Merkur',
+ )
+ exists(
+ css: '#content .main .action:nth-child(1)'
+ )
+ exists_not(
+ css: '#content .main .action:nth-child(2)'
+ )
+
+ end
+
+end
diff --git a/test/integration/twitter_browser_test.rb b/test/integration/twitter_browser_test.rb
new file mode 100644
index 000000000..a36d72852
--- /dev/null
+++ b/test/integration/twitter_browser_test.rb
@@ -0,0 +1,163 @@
+# encoding: utf-8
+require 'browser_test_helper'
+
+class TwitterBrowserTest < TestCase
+ def test_add_config
+
+ # app config
+ if !ENV['TWITTER_CONSUMER_KEY']
+ fail "ERROR: Need TWITTER_CONSUMER_KEY - hint TWITTER_CONSUMER_KEY='1234'"
+ end
+ consumer_key = ENV['TWITTER_CONSUMER_KEY']
+ if !ENV['TWITTER_CONSUMER_SECRET']
+ fail "ERROR: Need TWITTER_CONSUMER_SECRET - hint TWITTER_CONSUMER_SECRET='1234'"
+ end
+ consumer_secret = ENV['TWITTER_CONSUMER_SECRET']
+
+ if !ENV['TWITTER_USER_LOGIN']
+ fail "ERROR: Need TWITTER_USER_LOGIN - hint TWITTER_USER_LOGIN='1234'"
+ end
+ twitter_user_loign = ENV['TWITTER_USER_LOGIN']
+
+ if !ENV['TWITTER_USER_PW']
+ fail "ERROR: Need TWITTER_USER_PW - hint TWITTER_USER_PW='1234'"
+ end
+ twitter_pw = ENV['TWITTER_USER_PW']
+
+ @browser = browser_instance
+ login(
+ username: 'master@example.com',
+ password: 'test',
+ url: browser_url,
+ )
+ tasks_close_all()
+
+ click(css: 'a[href="#manage"]')
+ click(css: 'a[href="#channels/twitter"]')
+ click(css: '#content .js-configApp')
+ sleep 2
+ set(
+ css: '#content .modal [name=consumer_key]',
+ value: consumer_key,
+ )
+ set(
+ css: '#content .modal [name=consumer_secret]',
+ value: 'wrong',
+ )
+ click(css: '#content .modal .js-submit')
+
+ watch_for(
+ css: '#content .modal .alert',
+ value: 'Authorization Required',
+ )
+
+ set(
+ css: '#content .modal [name=consumer_secret]',
+ value: consumer_secret,
+ )
+ click(css: '#content .modal .js-submit')
+
+ watch_for_disappear(
+ css: '#content .modal .alert',
+ value: 'Authorization Required',
+ )
+
+ watch_for(
+ css: '#content .js-new',
+ value: 'add account',
+ )
+
+ click(css: '#content .js-configApp')
+
+ set(
+ css: '#content .modal [name=consumer_secret]',
+ value: 'wrong',
+ )
+ click(css: '#content .modal .js-submit')
+
+ watch_for(
+ css: '#content .modal .alert',
+ value: 'Authorization Required',
+ )
+
+ set(
+ css: '#content .modal [name=consumer_secret]',
+ value: consumer_secret,
+ )
+ click(css: '#content .modal .js-submit')
+
+ watch_for_disappear(
+ css: '#content .modal .alert',
+ value: 'Authorization Required',
+ )
+
+ watch_for(
+ css: '#content .js-new',
+ value: 'add account',
+ )
+
+ click(css: '#content .js-new')
+
+ sleep 10
+
+ set(
+ css: '#username_or_email',
+ value: twitter_user_loign,
+ )
+ set(
+ css: '#password',
+ value: twitter_pw,
+ )
+ click(css: '#allow')
+
+ #watch_for(
+ # css: '.notice.callback',
+ # value: 'Redirecting you back to the application',
+ #)
+
+ watch_for(
+ css: '#content .modal',
+ value: 'Search Terms',
+ )
+
+ click(css: '#content .modal .js-close')
+
+ watch_for(
+ css: '#content',
+ value: 'Armin Theo',
+ )
+ exists(
+ css: '#content .main .action:nth-child(1)'
+ )
+ exists_not(
+ css: '#content .main .action:nth-child(2)'
+ )
+
+ # add account again
+ click(css: '#content .js-new')
+
+ sleep 10
+
+ click(css: '#allow')
+
+ watch_for(
+ css: '#content .modal',
+ value: 'Search Terms',
+ )
+
+ click(css: '#content .modal .js-close')
+
+ watch_for(
+ css: '#content',
+ value: 'Armin Theo',
+ )
+ exists(
+ css: '#content .main .action:nth-child(1)'
+ )
+ exists_not(
+ css: '#content .main .action:nth-child(2)'
+ )
+
+ end
+
+end