123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- class Facebook
- attr_accessor :client, :account
- =begin
- client = Facebook.new('user_or_page_access_token')
- =end
- def initialize(access_token)
- connect(access_token)
- end
- =begin
- reconnect with other access_token
- client.connect('user_or_page_access_token')
- =end
- def connect(access_token)
- @client = Koala::Facebook::API.new(access_token)
- end
- =begin
- disconnect client
- client.disconnect
- =end
- def disconnect
- return if !@client
- @client = nil
- end
- =begin
- get pages of user
- pages = client.pages
- result
- [
- {
- id: '12345',
- name: 'Some Page Name',
- access_token, 'some_access_token_for_page',
- },
- ]
- =end
- def pages
- @client.get_connections('me', 'accounts').map do |page|
- {
- id: page['id'],
- name: page['name'],
- access_token: page['access_token']
- }
- end
- end
- =begin
- get current user
- pages = current_user
- result
- {
- 'id' => '1234567890123456',
- 'name' => 'Page/User Name',
- 'access_token' => 'some_acces_token'
- }
- =end
- def current_user
- @client.get_object('me')
- end
- =begin
- get user of comment/post
- pages = user(comment_or_post)
- result
- ???
- =end
- def user(item)
- return if !item['from']
- return if !item['from']['id']
- cache_key = "FB:User:Lookup:#{item['from']['id']}"
- cache = Rails.cache.read(cache_key)
- return cache if cache
- begin
- result = @client.get_object(item['from']['id'], fields: 'first_name,last_name,email')
- rescue
- result = @client.get_object(item['from']['id'], fields: 'name')
- end
- if result
- Rails.cache.write(cache_key, result, { expires_in: 15.minutes })
- end
- result
- end
- def to_user(item)
- Rails.logger.debug { 'Create user from item...' }
- Rails.logger.debug { item.inspect }
- # do item_user lookup
- item_user = user(item)
- return if !item_user
- auth = Authorization.find_by(uid: item_user['id'], provider: 'facebook')
- # create or update user
- user_data = {
- image_source: "https://graph.facebook.com/#{item_user['id']}/picture?type=large",
- }
- if auth
- user = User.find(auth.user_id)
- user.update!(user_data)
- else
- user_data[:login] = item_user['id']
- if item_user['first_name'] && item_user['last_name']
- user_data[:firstname] = item_user['first_name']
- user_data[:lastname] = item_user['last_name']
- else
- user_data[:firstname] = item_user['name']
- end
- user_data[:active] = true
- user_data[:role_ids] = Role.signup_role_ids
- user = User.create(user_data)
- end
- if user_data[:image_source]
- avatar = Avatar.add(
- object: 'User',
- o_id: user.id,
- url: user_data[:image_source],
- source: 'facebook',
- deletable: true,
- updated_by_id: user.id,
- created_by_id: user.id,
- )
- # update user link
- if avatar && user.image != avatar.store_hash
- user.image = avatar.store_hash
- user.save
- end
- end
- # create authorization
- if !auth
- auth_data = {
- uid: item_user['id'],
- username: item_user['id'],
- user_id: user.id,
- provider: 'facebook'
- }
- Authorization.create(auth_data)
- end
- UserInfo.current_user_id = user.id
- user
- end
- def to_ticket(post, group_id, channel, page)
- 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
- # prepare title
- title = post['message']
- if title.length > 80
- title = "#{title[0, 80]}..."
- end
- state = get_state(page, post)
- Ticket.create!(
- customer_id: user.id,
- title: title,
- group_id: group_id,
- state: state,
- priority: Ticket::Priority.find_by(name: '2 normal'),
- preferences: {
- channel_id: channel.id,
- channel_fb_object_id: page['id'],
- facebook: {
- permalink_url: post['permalink_url'],
- }
- },
- )
- end
- def to_article(post, ticket, page)
- Rails.logger.debug { 'Create article from post...' }
- Rails.logger.debug { post.inspect }
- Rails.logger.debug { ticket.inspect }
- user = to_user(post)
- return if !user
- to = nil
- if post['to'] && post['to']['data']
- post['to']['data'].each do |to_entry|
- if to
- to += ', '
- else
- to = ''
- end
- to += to_entry['name']
- end
- end
- feed_post = {
- from: post['from']['name'],
- to: to,
- body: post['message'],
- message_id: post['id'],
- type_id: Ticket::Article::Type.find_by(name: 'facebook feed post').id,
- }
- articles = []
- articles.push(feed_post)
- if post['comments'] && post['comments']['data']
- articles += nested_comments(post['comments']['data'], post['id'])
- end
- base_url = nil
- if ticket.preferences['facebook'] && ticket.preferences['facebook']['permalink_url']
- base_url = ticket.preferences['facebook']['permalink_url']
- end
- articles.each do |article|
- next if Ticket::Article.exists?(message_id: article[:message_id])
- # set ticket state to open if not new
- ticket_state = get_state(page, post, ticket)
- if ticket_state.name != ticket.state.name
- ticket.state = ticket_state
- ticket.save!
- end
- links = []
- if base_url
- url = base_url
- realtive_id = article[:message_id].split('_')[1]
- if realtive_id
- url += "?comment_id=#{realtive_id}"
- end
- links = [
- {
- url: url,
- target: '_blank',
- name: 'on Facebook',
- },
- ]
- end
- article = {
- # to: @account['name'],
- ticket_id: ticket.id,
- internal: false,
- sender_id: Ticket::Article::Sender.lookup(name: 'Customer').id,
- created_by_id: 1,
- updated_by_id: 1,
- preferences: {
- links: links,
- },
- }.merge(article)
- Ticket::Article.create(article)
- end
- end
- def to_group(post, group_id, channel, page)
- Rails.logger.debug { 'import post' }
- return if !post['message']
- ticket = nil
- # use transaction
- Transaction.execute(reset_user_id: true, context: 'facebook') do
- existing_article = Ticket::Article.find_by(message_id: post['id'])
- ticket = if existing_article
- existing_article.ticket
- else
- to_ticket(post, group_id, channel, page)
- end
- to_article(post, ticket, page)
- end
- ticket
- end
- def from_article(article)
- if article[:type] != 'facebook feed comment'
- raise "Can't handle unknown facebook article type '#{article[:type]}'."
- end
- Rails.logger.debug { 'Create feed comment from article...' }
- post = @client.put_comment(article[:in_reply_to], article[:body])
- Rails.logger.debug { post.inspect }
- @client.get_object(post['id'])
- end
- private
- def get_state(page, post, ticket = nil)
- # no changes in post is from page user itself
- if post['from'] && post['from']['id'].to_s == page['id'].to_s
- if !ticket
- return Ticket::State.find_by(name: 'closed')
- end
- return ticket.state
- end
- state = Ticket::State.find_by(default_create: true)
- return state if !ticket
- return ticket.state if ticket.state_id == state.id
- Ticket::State.find_by(default_follow_up: true)
- end
- def access_token_for_page(lookup)
- access_token = nil
- pages.each do |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
- end
- access_token
- end
- def nested_comments(comments, in_reply_to)
- Rails.logger.debug { 'Fetching nested comments...' }
- Rails.logger.debug { comments.inspect }
- result = []
- return result if comments.blank?
- comments.each do |comment|
- user = to_user(comment)
- next if !user
- article_data = {
- from: "#{user.firstname} #{user.lastname}",
- body: comment['message'],
- message_id: comment['id'],
- type_id: Ticket::Article::Type.find_by(name: 'facebook feed comment').id,
- in_reply_to: in_reply_to
- }
- result.push(article_data)
- sub_comments = @client.get_object("#{comment['id']}/comments", fields: 'id,from,to,message,created_time')
- sub_articles = nested_comments(sub_comments, comment['id'])
- result += sub_articles
- end
- result
- end
- end
|