From be8021388859c08cf4a7faf79770da9608cb049b Mon Sep 17 00:00:00 2001 From: Thorsten Eckel Date: Thu, 9 Jul 2015 16:56:01 +0200 Subject: [PATCH] Initial version of facebook channel connector. --- app/models/channel/facebook.rb | 67 +++-- .../ticket/article/communicate_facebook.rb | 23 +- lib/facebook.rb | 239 ++++++++++++++++++ 3 files changed, 296 insertions(+), 33 deletions(-) create mode 100644 lib/facebook.rb diff --git a/app/models/channel/facebook.rb b/app/models/channel/facebook.rb index 2c9b4e517..4cc289611 100644 --- a/app/models/channel/facebook.rb +++ b/app/models/channel/facebook.rb @@ -1,35 +1,56 @@ -# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ +# Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/ -#require 'rubygems' -#require 'twitter' +require 'facebook' class Channel::Facebook - # def fetch(:oauth_token, :oauth_token_secret) - def fetch + def fetch (channel) + + @channel = channel + @facebook = Facebook.new( @channel[:options][:auth] ) + @sync = @channel[:options][:sync] + + Rails.logger.debug 'facebook fetch started' + + fetch_feed + + disconnect + + Rails.logger.debug 'facebook fetch completed' + end + + def send(article, _notification = false) + + @channel = Channel.find_by( area: 'Facebook::Inbound', active: true ) + @facebook = Facebook.new( @channel[:options][:auth] ) + + tweet = @facebook.from_article(article) + disconnect + + tweet end def disconnect - + @facebook.disconnect end - def send + private - Rails.logger.debug('face!!!!!!!!!!!!!!') - graph_api = Koala::Facebook::API.new( - 'AAACqTciZAPsQBAHO9DbM333y2DcL5kccHyIObZB7WhaZBVUXUIeBNChkshvShCgiN6uwZC3r3l4cDvAZAPTArNIkemEraojzN1veNPZBADQAZDZD' - ) - graph_api.put_object( - 'id', - 'comments', - { - message: body - } - ) - # client.direct_message_create( - # 'medenhofer', - # self.body, - # options = {} - # ) + def fetch_feed + + return if !@sync[:group_id] + + counter = 0 + feed = @facebook.client.get_connections('me', 'feed') + feed.each { |f| + + break if @sync[:limit] && @sync[:limit] <= counter + + post = @facebook.client.get_object( f['id'] ) + + @facebook.to_group( post, @sync[:group_id] ) + + counter += 1 + } end end diff --git a/app/models/observer/ticket/article/communicate_facebook.rb b/app/models/observer/ticket/article/communicate_facebook.rb index ea6e4bf84..54b4578ee 100644 --- a/app/models/observer/ticket/article/communicate_facebook.rb +++ b/app/models/observer/ticket/article/communicate_facebook.rb @@ -1,5 +1,7 @@ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ +require 'channel/facebook' + class Observer::Ticket::Article::CommunicateFacebook < ActiveRecord::Observer observe 'ticket::_article' @@ -13,17 +15,18 @@ class Observer::Ticket::Article::CommunicateFacebook < ActiveRecord::Observer return 1 if sender.nil? return 1 if sender['name'] == 'Customer' - # only apply on emails + # only apply for facebook type = Ticket::Article::Type.lookup( id: record.type_id ) - return if type['name'] != 'facebook' + return if type['name'] !~ /\Afacebook/ - a = Channel::Facebook.new - a.send( - { - from: 'me@znuny.com', - to: 'medenhofer', - body: record.body - } - ) + facebook = Channel::Facebook.new + post = facebook.send({ + type: type['name'], + to: record.to, + body: record.body, + in_reply_to: record.in_reply_to + }) + record.message_id = post['id'] + record.save end end diff --git a/lib/facebook.rb b/lib/facebook.rb new file mode 100644 index 000000000..a2b8d880e --- /dev/null +++ b/lib/facebook.rb @@ -0,0 +1,239 @@ +# Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/ + +require 'koala' + +class Facebook + + attr_accessor :client, :account + + def initialize(options) + + connect( options[:auth][:access_token] ) + + page_access_token = access_token_for_page( options[:sync] ) + + if page_access_token + connect( page_access_token ) + end + + @account = client.get_object('me') + end + + def connect(access_token) + @client = Koala::Facebook::API.new( access_token ) + end + + def disconnect + + return if !@client + + @client = nil + end + + def pages + pages = [] + @client.get_connections('me', 'accounts').each { |page| + pages.push({ + id: page['id'], + name: page['name'], + access_token: page['access_token'], + }) + } + pages + end + + def user(post) + + return if !post['from'] + return if !post['from']['id'] + return if !post['from']['name'] + + return if !post['from']['id'] == @account['id'] + + @client.get_object( post['from']['id'] ) + end + + def to_user(post) + + Rails.logger.debug 'Create user from post...' + Rails.logger.debug post.inspect + + # do post_user lookup + post_user = user(post) + + return if !post_user + + auth = Authorization.find_by( uid: post_user['id'], provider: 'facebook' ) + + # create or update user + user_data = { + login: post_user['id'], # TODO + firstname: post_user['first_name'] || post_user['name'], + lastname: post_user['last_name'] || '', + email: '', + password: '', + # TODO: image_source: '', + # TODO: note: '', + active: true, + roles: Role.where( name: 'Customer' ), + } + if auth + user_data[:id] = auth.user_id + end + user = User.create_or_update( user_data ) + + # create or update authorization + auth_data = { + uid: post_user['id'], + username: post_user['id'], # TODO + user_id: user.id, + provider: 'facebook' + } + if auth + auth.update_attributes( auth_data ) + else + Authorization.new( auth_data ) + end + + UserInfo.current_user_id = user.id + + user + end + + def to_ticket(post, group_id) + + Rails.logger.debug 'Create ticket from post...' + Rails.logger.debug post.inspect + Rails.logger.debug group_id.inspect + + user = to_user(post) + return if !user + + Ticket.create( + customer_id: user.id, + title: "#{post['message'][0, 37]}...", + group_id: group_id, + state: Ticket::State.find_by( name: 'new' ), + priority: Ticket::Priority.find_by( name: '2 normal' ), + ) + end + + def to_article(post, ticket) + + Rails.logger.debug 'Create article from post...' + Rails.logger.debug post.inspect + Rails.logger.debug ticket.inspect + + # set ticket state to open if not new + if ticket.state.name != 'new' + ticket.state = Ticket::State.find_by( name: 'open' ) + ticket.save + end + + user = to_user(comment) + return if !user + + feed_post = { + from: user.name, + body: post['message'], + message_id: post['id'], + type: Ticket::Article::Type.find_by( name: 'facebook feed post' ), + } + articles = [] + articles.push( feed_post ) + + post['comments']['data'].each { |comment| + + user = to_user(comment) + + next if !user + + post_comment = { + from: user.name, + body: comment['message'], + message_id: comment['id'], + type: Ticket::Article::Type.find_by( name: 'facebook feed comment' ), + } + articles.push( post_comment ) + + # TODO: sub-comments + # comment_data = @client.get_object( comment['id'] ) + } + + articles.invert.each { |article| + + break if Ticket::Article.find_by( message_id: article[:message_id] ) + + article = { + to: @account['name'], + ticket_id: ticket.id, + internal: false, + }.merge( article ) + + Ticket::Article.create( article ) + } + end + + def to_group(post, group_id) + + Rails.logger.debug 'import post' + + ticket = nil + # use transaction + ActiveRecord::Base.transaction do + + UserInfo.current_user_id = 1 + + existing_article = Ticket::Article.find_by( message_id: post['id'] ) + if existing_article + ticket = existing_article.ticket + else + ticket = to_ticket(post, group_id) + return if !ticket + end + + to_article(post, ticket) + + # execute ticket events + Observer::Ticket::Notification.transaction + end + + ticket + end + + def from_article(article) + + post = nil + # TODO: article[:type] == 'facebook feed post' + if article[:type] == 'facebook feed comment' + + Rails.logger.debug 'Create feed comment from article...' + + post = @client.put_wall_post(article[:body], {}, article[:in_reply_to]) + else + fail "Can't handle unknown facebook article type '#{article[:type]}'." + end + + Rails.logger.debug post.inspect + @client.get_object( post['id'] ) + end + + private + + def access_token_for_page(lookup) + + access_token = nil + pages.each { |page| + + next if !lookup[:page_id] && !lookup[:page] + next if lookup[:page_id] && lookup[:page_id].to_s != page[:id] + next if lookup[:page] && lookup[:page] != page[:name] + + access_token = page[:access_token] + + break + } + + access_token + end +end