diff --git a/app/controllers/channels_controller.rb b/app/controllers/channels_controller.rb index 154058096..f1b5f08c0 100644 --- a/app/controllers/channels_controller.rb +++ b/app/controllers/channels_controller.rb @@ -30,32 +30,40 @@ Example: { "id":1, "area":"Twitter::Inbound", - "adapter":"Twitter2", + "adapter":"Twitter", "group_id:": 1, "options":{ - "consumer_key":"PJ4c3dYYRtSZZZdOKo8ow", - "consumer_secret":"ggAdnJE2Al1Vv0cwwvX5bdvKOieFs0vjCIh5M8Dxk", - "oauth_token":"293437546-xxRa9g74CercnU5AvY1uQwLLGIYrV1ezYtpX8oKW", - "oauth_token_secret":"ju0E4l9OdY2Lh1iTKMymAu6XVfOaU2oGxmcbIMRZQK4", - "search":[ - { - "item":"#otrs", - "group_id":1, - }, - { - "item":"#zombie42", - "group_id":1, - }, - { - "item":"#otterhub", - "group_id":1, - } - ], - "mentions" { - "group_id":1, + auth: { + "consumer_key":"PJ4c3dYYRtSZZZdOKo8ow", + "consumer_secret":"ggAdnJE2Al1Vv0cwwvX5bdvKOieFs0vjCIh5M8Dxk", + "oauth_token":"293437546-xxRa9g74CercnU5AvY1uQwLLGIYrV1ezYtpX8oKW", + "oauth_token_secret":"ju0E4l9OdY2Lh1iTKMymAu6XVfOaU2oGxmcbIMRZQK4", }, - "direct_messages": { - "group_id":1, + "sync":{ + "search":[ + { + "item":"#otrs", + "type": "mixed", # optional, possible 'mixed' (default), 'recent', 'popular' + "group": "OTRS", + "limit": 1, # optional + }, + { + "item":"#zombie23", + "group": "Zombie Apocalypse Early Warning System", + }, + { + "item":"#otterhub", + "group": "Community", + } + ], + "mentions" { + "group": "Twitter", + "limit": 100, # optional + }, + "direct_messages": { + "group": "Twitter", + "limit": 1, # optional + } } }, "active":true, diff --git a/app/models/channel/twitter.rb b/app/models/channel/twitter.rb new file mode 100644 index 000000000..4ec1bea2c --- /dev/null +++ b/app/models/channel/twitter.rb @@ -0,0 +1,100 @@ +# Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/ + +class Channel::Twitter + + def fetch (channel) + + @channel = channel + @tweet = Tweet.new( @channel[:options][:auth] ) + @sync = @channel[:options][:sync] + + Rails.logger.debug "twitter fetch started" + + fetch_search + fetch_mentions + fetch_direct_messages + + disconnect + + Rails.logger.debug 'twitter fetch completed' + end + + def send(article, _notification = false) + + @channel = Channel.find_by( area: 'Twitter::Inbound', active: true ) + @tweet = Tweet.new( @channel[:options][:auth] ) + @sync = @channel[:options][:sync] + + tweet = @tweet.from_article(article) + disconnect + + tweet + end + + def disconnect + @tweet.disconnect + end + + private + + def fetch_search + + return if !@sync[:search] + return if @sync[:search].length == 0 + + # search results + @sync[:search].each { |search| + + result_type = search[:type] || 'mixed' + + Rails.logger.debug " - searching for '#{search[:term]}'" + + counter = 0 + @tweet.client.search( search[:term], result_type: result_type ).collect{ |tweet| + + break if search[:limit] && search[:limit] <= counter + break if Ticket::Article.find_by( message_id: tweet.id.to_s ) + + @tweet.to_group( tweet, search[:group] ) + + counter += 1 + } + } + end + + def fetch_mentions + + return if !@sync[:mentions] + + Rails.logger.debug ' - searching for mentions' + + counter = 0 + @tweet.client.mentions_timeline.each { |tweet| + + break if @sync[:mentions][:limit] && @sync[:mentions][:limit] <= counter + break if Ticket::Article.find_by( message_id: tweet.id.to_s ) + + @tweet.to_group( tweet, @sync[:mentions][:group] ) + + counter += 1 + } + end + + def fetch_direct_messages + + return if !@sync[:direct_messages] + + Rails.logger.debug ' - searching for direct_messages' + + counter = 0 + @tweet.client.direct_messages.each { |tweet| + + break if @sync[:direct_messages][:limit] && @sync[:direct_messages][:limit] <= counter + break if Ticket::Article.find_by( message_id: tweet.id.to_s ) + + @tweet.to_group( tweet, @sync[:direct_messages][:group] ) + + counter += 1 + } + end +end diff --git a/app/models/channel/twitter2.rb b/app/models/channel/twitter2.rb deleted file mode 100644 index 331d8160c..000000000 --- a/app/models/channel/twitter2.rb +++ /dev/null @@ -1,303 +0,0 @@ -# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ - -require 'twitter' - -class Channel::TWITTER2 - def connect(channel) - @client = Twitter::REST::Client.new do |config| - config.consumer_key = channel[:options][:consumer_key] - config.consumer_secret = channel[:options][:consumer_secret] - config.access_token = channel[:options][:oauth_token] - config.access_token_secret = channel[:options][:oauth_token_secret] - end - end - - def disconnect - - return if !@client - - @client = nil - end - - def fetch (channel) - - Rails.logger.info "fetching tweets (oauth_token#{channel[:options][:oauth_token]})" - @client = connect(channel) - - # search results - if channel[:options][:search] - channel[:options][:search].each { |search| - Rails.logger.info " - searching for #{search[:item]}" - tweets = [] - @client.search( search[:item], count: 50, result_type: 'recent' ).collect do |tweet| - tweets.push tweet - end - @article_type = 'twitter status' - fetch_loop( tweets, channel, search[:group] ) - } - end - - # mentions - if channel[:options][:mentions] - Rails.logger.info ' - searching for mentions' - tweets = @client.mentions_timeline - @article_type = 'twitter status' - fetch_loop( tweets, channel, channel[:options][:mentions][:group] ) - end - - # direct messages - if channel[:options][:direct_messages] - Rails.logger.info ' - searching for direct_messages' - tweets = @client.direct_messages - @article_type = 'twitter direct-message' - fetch_loop( tweets, channel, channel[:options][:direct_messages][:group] ) - end - Rails.logger.info 'done' - disconnect - end - - def fetch_loop( tweets, channel, group ) - - # get all tweets - all_tweets = [] - result_class = tweets.class - if result_class.to_s == 'Array' - all_tweets = tweets - elsif result_class.to_s == 'Twitter::SearchResults' - tweets.results.map do |tweet| - all_tweets.push tweet - end - else - Rails.logger.error 'UNKNOWN: ' + result_class.to_s - end - - # find tweets - all_tweets.each do |tweet| - - # check if tweet is already imported - article = Ticket::Article.find_by( message_id: tweet.id.to_s ) - - # check if sender already exists - next if article - - # use transaction - ActiveRecord::Base.transaction do - - # reset current_user - UserInfo.current_user_id = 1 - - Rails.logger.info 'import tweet' - fetch_import( tweet, channel, group ) - end - - # execute ticket events - Observer::Ticket::Notification.transaction - end - end - - def fetch_import(tweet, channel, group) - - # do sender lockup if needed - sender = nil - - # status (full user data is included) - if tweet.respond_to?('user') - sender = tweet.user - - # direct message (full user data is included) - elsif tweet.respond_to?('sender') - sender = tweet.sender - - # search (no user data is included, do extra lookup) - elsif tweet.respond_to?('from_user_id') - begin - sender = @client.user(tweet.from_user_id) - rescue => e - Rails.logger.error 'Exception: twitter: ' + e.inspect - return - end - end - - # check if parent exists - user = nil, ticket = nil, article = nil - if tweet.respond_to?('in_reply_to_status_id') && tweet.in_reply_to_status_id && tweet.in_reply_to_status_id.to_s != '' - Rails.logger.info 'import in_reply_tweet ' + tweet.in_reply_to_status_id.to_s - tweet_sub = @client.status( tweet.in_reply_to_status_id ) - #Rails.logger.debug tweet_sub.inspect - (user, ticket, article) = fetch_import(tweet_sub, channel, group) - end - - # create stuff - user = fetch_user_create(tweet, sender) - if !ticket - Rails.logger.info 'create new ticket...' - ticket = fetch_ticket_create(user, tweet, sender, channel, group) - end - article = fetch_article_create(user, ticket, tweet, sender) - [user, ticket, article] - end - - def fetch_user_create(_tweet, sender) - # create sender in db - # puts tweet.inspect - # user = User.where( :login => tweet.sender.screen_name ).first - auth = Authorization.find_by( uid: sender.id, provider: 'twitter' ) - user = nil - if auth - Rails.logger.info 'user_id', auth.user_id - user = User.find_by( id: auth.user_id ) - end - if !user - Rails.logger.info 'create user...' - roles = Role.where( name: 'Customer' ) - user = User.create( - login: sender.screen_name, - firstname: sender.name, - lastname: '', - email: '', - password: '', - image_source: sender.profile_image_url.to_s, - note: sender.description, - active: true, - roles: roles, - updated_by_id: 1, - created_by_id: 1 - ) - Rails.logger.info 'autentication create...' - authentication = Authorization.create( - uid: sender.id, - username: sender.screen_name, - user_id: user.id, - provider: 'twitter' - ) - else - Rails.logger.info 'user exists' - end - - # set current user - UserInfo.current_user_id = user.id - - user - end - - def fetch_ticket_create(user, tweet, _sender, _channel, group) - - #Rails.logger.info '+++++++++++++++++++++++++++' + tweet.inspect - # check if ticket exists - if tweet.respond_to?('in_reply_to_status_id') && tweet.in_reply_to_status_id && tweet.in_reply_to_status_id.to_s != '' - Rails.logger.info 'tweet.in_reply_to_status_id found: ' + tweet.in_reply_to_status_id.to_s - article = Ticket::Article.find_by( message_id: tweet.in_reply_to_status_id.to_s ) - if article - Rails.logger.info 'article with id found tweet.in_reply_to_status_id found: ' + tweet.in_reply_to_status_id.to_s - return article.ticket - end - end - - # find if record already exists - article = Ticket::Article.find_by( message_id: tweet.id.to_s ) - if article - return article.ticket - end - - ticket = nil - if @article_type == 'twitter direct-message' - ticket = Ticket.find_by( customer_id: user.id ) - if ticket - state_type = Ticket::StateType.where( ticket.state.state_type_id ) - if state_type.name == 'closed' || state_type.name == 'closed' - ticket = nil - end - end - end - if !ticket - group = Group.find_by( name: group ) - group_id = 1 - if group - group_id = group.id - end - state = Ticket::State.find_by( name: 'new' ) - state_id = 1 - if state - state_id = state.id - end - priority = Ticket::Priority.find_by( name: '2 normal' ) - priority_id = 1 - if priority - priority_id = priority.id - end - ticket = Ticket.create( - group_id: group_id, - customer_id: user.id, - title: tweet.text[0, 40], - state_id: state_id, - priority_id: priority_id, - ) - end - - ticket - end - - def fetch_article_create( _user, ticket, tweet, sender ) - - # find if record already exists - article = Ticket::Article.find_by( message_id: tweet.id.to_s ) - return article if article - - # set ticket state to open if not new - if ticket.state.name != 'new' - ticket.state = Ticket::State.find_by( name: 'open' ) - ticket.save - end - - # import tweet - to = nil - if tweet.respond_to?('recipient') - to = tweet.recipient.name - end - - article = Ticket::Article.create( - ticket_id: ticket.id, - type_id: Ticket::Article::Type.find_by( name: @article_type ).id, - sender_id: Ticket::Article::Sender.find_by( name: 'Customer' ).id, - body: tweet.text, - from: sender.name, - to: to, - message_id: tweet.id, - internal: false, - ) - - end - - def send(attr, _notification = false) - # Rails.logger.debug('tweeeeettttt!!!!!!') - channel = Channel.find_by( area: 'Twitter::Inbound', active: true ) - - client = Twitter::REST::Client.new do |config| - config.consumer_key = channel[:options][:consumer_key] - config.consumer_secret = channel[:options][:consumer_secret] - config.access_token = channel[:options][:oauth_token] - config.access_token_secret = channel[:options][:oauth_token_secret] - end - if attr[:type] == 'twitter direct-message' - Rails.logger.info 'to:' + attr[:to].to_s - dm = client.create_direct_message( - attr[:to].to_s, - attr[:body].to_s, - {} - ) - # Rails.logger.info dm.inspect - return dm - end - - return if attr[:type] != 'twitter status' - - message = client.update( - attr[:body].to_s, - { - in_reply_to_status_id: attr[:in_reply_to] - } - ) - # Rails.logger.debug message.inspect - message - end -end diff --git a/app/models/observer/ticket/article/communicate_twitter.rb b/app/models/observer/ticket/article/communicate_twitter.rb index 9a59b989a..3ef62d485 100644 --- a/app/models/observer/ticket/article/communicate_twitter.rb +++ b/app/models/observer/ticket/article/communicate_twitter.rb @@ -1,5 +1,8 @@ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ +# http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html +require 'channel/twitter' + class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer observe 'ticket::_article' @@ -10,24 +13,21 @@ class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer # if sender is customer, do not communication sender = Ticket::Article::Sender.lookup( id: record.sender_id ) - return 1 if sender.nil? - return 1 if sender['name'] == 'Customer' + return if sender.nil? + return if sender['name'] == 'Customer' # only apply on tweets type = Ticket::Article::Type.lookup( id: record.type_id ) - return if type['name'] != 'twitter direct-message' && type['name'] != 'twitter status' + return if type['name'] !~ /\Atwitter/ - a = Channel::TWITTER2.new - message = a.send( - { - type: type['name'], - to: record.to, - body: record.body, - in_reply_to: record.in_reply_to - }, - #Rails.application.config.channel_twitter - ) - record.message_id = message.id + twitter = Channel::Twitter.new + tweet = twitter.send({ + type: type['name'], + to: record.to, + body: record.body, + in_reply_to: record.in_reply_to + }) + record.message_id = tweet.id record.save end end diff --git a/lib/tweet.rb b/lib/tweet.rb new file mode 100644 index 000000000..171b1b0bb --- /dev/null +++ b/lib/tweet.rb @@ -0,0 +1,226 @@ +# Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/ + +require 'twitter' + +class Tweet + + attr_accessor :client + + def initialize(auth) + + @client = Twitter::REST::Client.new do |config| + config.consumer_key = auth[:consumer_key] + config.consumer_secret = auth[:consumer_secret] + config.access_token = auth[:oauth_token] + config.access_token_secret = auth[:oauth_token_secret] + end + end + + def disconnect + + return if !@client + + @client = nil + end + + def user(tweet) + + # status (full user data is included) + return tweet.user if tweet.respond_to?('user') + + # direct message (full user data is included) + return tweet.sender if tweet.respond_to?('sender') + + # search (no user data is included, do extra lookup) + begin + return @client.user(tweet.from_user_id) if tweet.respond_to?('from_user_id') + rescue => e + Rails.logger.error "Twitter (#{tweet.id}): 'from_user_id' lookup error '#{e.inspect}'" + end + + Rails.logger.error "Twitter (#{tweet.id}): unknown user source" + + return + end + + def to_user(tweet) + + Rails.logger.debug "Create user from tweet..." + Rails.logger.debug tweet.inspect + + # do tweet_user lookup + tweet_user = user(tweet) + + return if !tweet_user + + auth = Authorization.find_by( uid: tweet_user.id, provider: 'twitter' ) + + # create or update user + user_data = { + login: tweet_user.screen_name, + firstname: tweet_user.name, + lastname: '', + email: '', + password: '', + image_source: tweet_user.profile_image_url.to_s, + note: tweet_user.description, + 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: tweet_user.id, + username: tweet_user.screen_name, + user_id: user.id, + provider: 'twitter' + } + if auth + auth.update_attributes( auth_data ) + else + Authorization.new( auth_data ) + end + + UserInfo.current_user_id = user.id + + user + end + + def to_ticket(tweet, user, group) + + Rails.logger.debug "Create ticket from tweet..." + Rails.logger.debug tweet.inspect + Rails.logger.debug user.inspect + Rails.logger.debug group.inspect + + if tweet.class.to_s == 'Twitter::DirectMessage' + ticket = Ticket.find_by( + customer_id: user.id, + state: Ticket::State.where( + state_type_id: Ticket::StateType.where( + name: 'closed', + ) + ) + ) + return ticket if ticket + end + + Ticket.create( + customer_id: user.id, + title: "#{tweet.text[0, 37]}...", + group: Group.find_by( name: group ), + state: Ticket::State.find_by( name: 'new' ), + priority: Ticket::Priority.find_by( name: '2 normal' ), + ) + end + + def to_article(tweet, user, ticket) + + Rails.logger.debug "Create article from tweet..." + Rails.logger.debug tweet.inspect + Rails.logger.debug user.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 + + # import tweet + to = nil + if tweet.respond_to?('recipient') + to = tweet.recipient.name + end + + article_type = 'twitter status' + if tweet.class.to_s == 'Twitter::DirectMessage' + article_type = 'twitter direct-message' + end + + Ticket::Article.create( + from: user.login, + to: to, + body: tweet.text, + message_id: tweet.id, + ticket_id: ticket.id, + type: Ticket::Article::Type.find_by( name: article_type ), + sender: Ticket::Article::Sender.find_by( name: 'Customer' ), + internal: false, + ) + end + + def to_group(tweet, group) + + Rails.logger.debug 'import tweet' + + ticket = nil + # use transaction + ActiveRecord::Base.transaction do + + UserInfo.current_user_id = 1 + + # check if parent exists + user = to_user(tweet) + + return if !user + + if tweet.respond_to?('in_reply_to_status_id') && tweet.in_reply_to_status_id && tweet.in_reply_to_status_id.to_s != '' + + existing_article = Ticket::Article.find_by( message_id: tweet.in_reply_to_status_id.to_s ) + if existing_article + ticket = existing_article.ticket + else + Rails.logger.debug 'import in_reply_tweet ' + tweet.in_reply_to_status_id.to_s + + parent_tweet = @client.status( tweet.in_reply_to_status_id ) + ticket = to_group( parent_tweet, group ) + end + else + ticket = to_ticket(tweet, user, group) + end + + to_article(tweet, user, ticket) + + # execute ticket events + Observer::Ticket::Notification.transaction + end + + ticket + end + + def from_article(article) + + + tweet = nil + if article[:type] == 'twitter direct-message' + + Rails.logger.debug "Create twitter direct message from article to '#{article[:to]}'..." + + tweet = @client.create_direct_message( + article[:to], + article[:body], + {} + ) + + elsif article[:type] == 'twitter status' + + Rails.logger.debug "Create tweet from article..." + + tweet = @client.update( + article[:body], + { + in_reply_to_status_id: article[:in_reply_to] + } + ) + end + + Rails.logger.debug tweet.inspect + tweet + end + +end diff --git a/test/integration/twitter_test.rb b/test/integration/twitter_test.rb index 6537ab385..b369cbaf1 100644 --- a/test/integration/twitter_test.rb +++ b/test/integration/twitter_test.rb @@ -20,40 +20,44 @@ class TwitterTest < ActiveSupport::TestCase consumer_key = 'd2zoZBmMXmT7KLPgEHSzpw' consumer_secret = 'QMUrlyDlqjITCkWdrOgsTxMVVLxr4A4IW3DIgtIg' - # user1: armin_theo (is system and is following marion_bauer) - user1_token = '1405469528-WQ6XHizgrbYasUwjp0I0TUONhftNkrfrpgFLrdc' - user1_token_secret = '0LHChGFlQx9jSxM8tkBsuDOMhbJMSXTL2zKJJO5Xk' + # armin_theo (is system and is following marion_bauer) + armin_theo_token = '1405469528-WQ6XHizgrbYasUwjp0I0TUONhftNkrfrpgFLrdc' + armin_theo_token_secret = '0LHChGFlQx9jSxM8tkBsuDOMhbJMSXTL2zKJJO5Xk' - # user2: me_bauer (is following armin_theo) - user2_token = '1406098795-XQTjg1Zj5uVW0C11NNpNA4xopyclRJJoriWis0I' - user2_token_secret = 'T8ph5afeSDjGDA9X1ZBlzEvoSiXfN266ZZUMj5UaY' + # me_bauer (is following armin_theo) + me_bauer_token = '1406098795-XQTjg1Zj5uVW0C11NNpNA4xopyclRJJoriWis0I' + me_bauer_token_secret = 'T8ph5afeSDjGDA9X1ZBlzEvoSiXfN266ZZUMj5UaY' # add channel - current = Channel.where( adapter: 'Twitter2' ) + current = Channel.where( adapter: 'Twitter' ) current.each(&:destroy) Channel.create( - adapter: 'Twitter2', + adapter: 'Twitter', area: 'Twitter::Inbound', options: { - consumer_key: consumer_key, - consumer_secret: consumer_secret, - oauth_token: user1_token, - oauth_token_secret: user1_token_secret, - search: [ - { - item: '#citheo42', + auth: { + consumer_key: consumer_key, + consumer_secret: consumer_secret, + oauth_token: armin_theo_token, + oauth_token_secret: armin_theo_token_secret, + }, + sync: { + search: [ + { + term: '#citheo42', + group: 'Twitter', + }, + { + term: '#citheo24', + group: 'Users', + }, + ], + mentions: { group: 'Twitter', }, - { - item: '#citheo24', - group: 'Users', - }, - ], - mentions: { - group: 'Twitter', - }, - direct_messages: { - group: 'Twitter', + direct_messages: { + group: 'Twitter', + } } }, active: true, @@ -63,51 +67,49 @@ class TwitterTest < ActiveSupport::TestCase test 'new outbound and reply' do - user = User.find(2) - group = Group.where( name: 'Twitter' ).first - state = Ticket::State.where( name: 'new' ).first - priority = Ticket::Priority.where( name: '2 normal' ).first - hash = '#citheo42' + rand(9999).to_s - text = 'Today the weather is really nice... ' + hash + hash = '#citheo42' + rand(9999).to_s + user = User.find(2) + text = "Today the weather is really nice... #{hash}" ticket = Ticket.create( - group_id: group.id, - customer_id: user.id, - title: text[0, 40], - state_id: state.id, - priority_id: priority.id, + title: text[0, 40], + customer_id: user.id, + group: Group.find_by( name: 'Twitter' ), + state: Ticket::State.find_by( name: 'new' ), + priority: Ticket::Priority.find_by( name: '2 normal' ), updated_by_id: 1, created_by_id: 1, ) - assert( ticket, 'outbound ticket created' ) + assert( ticket, "outbound ticket created, text: #{text}" ) + article = Ticket::Article.create( - ticket_id: ticket.id, - type_id: Ticket::Article::Type.where( name: 'twitter status' ).first.id, - sender_id: Ticket::Article::Sender.where( name: 'Agent' ).first.id, - body: text, - #:from => sender.name, - #:to => to, - #:message_id => tweet.id, - internal: false, + ticket_id: ticket.id, + body: text, + type: Ticket::Article::Type.find_by( name: 'twitter status' ), + sender: Ticket::Article::Sender.find_by( name: 'Agent' ), + internal: false, updated_by_id: 1, created_by_id: 1, ) - assert( article, 'outbound article created' ) - assert_equal( article.ticket.articles.count, 1 ) - sleep 10 + assert( article, "outbound article created, text: #{text}" ) # reply by me_bauer client = Twitter::REST::Client.new do |config| config.consumer_key = consumer_key config.consumer_secret = consumer_secret - config.access_token = user2_token - config.access_token_secret = user2_token_secret - end - client.search(hash, count: 50, result_type: 'recent').collect do |tweet| - assert_equal( tweet.id, article.message_id ) + config.access_token = me_bauer_token + config.access_token_secret = me_bauer_token_secret end - reply_hash = '#weather' + rand(9999).to_s - reply_text = '@armin_theo on my side the weather is also nice! 😍😍😍 ' + reply_hash + tweet_found = false + client.user_timeline('armin_theo').each { |tweet| + + next if tweet.id != article.message_id + tweet_found = true + break + } + assert( tweet_found, "found outbound '#{text}' tweet '#{article.message_id}'" ) + + reply_text = '@armin_theo on my side the weather is nice, too! 😍😍😍 #weather' + rand(9999).to_s tweet = client.update( reply_text, { @@ -115,43 +117,40 @@ class TwitterTest < ActiveSupport::TestCase } ) - sleep 10 - # fetch check system account Channel.fetch # check if follow up article has been created - assert_equal( article.ticket.articles.count, 2 ) - reply_article = article.ticket.articles.last - assert_equal( reply_article.body, reply_text.utf8_to_3bytesutf8 ) + article = Ticket::Article.find_by( message_id: tweet.id ) + assert( article, "article tweet '#{tweet.id}' imported" ) + assert_equal( 2, article.ticket.articles.count, 'ticket article inbound count' ) + assert_equal( reply_text.utf8_to_3bytesutf8, ticket.articles.last.body, 'ticket article inbound body' ) end test 'new by direct message inbound' do + # cleanup direct messages of system client = Twitter::REST::Client.new do |config| config.consumer_key = consumer_key config.consumer_secret = consumer_secret - config.access_token = user1_token - config.access_token_secret = user1_token_secret + config.access_token = armin_theo_token + config.access_token_secret = armin_theo_token_secret end dms = client.direct_messages( count: 200 ) dms.each {|dm| client.destroy_direct_message(dm.id) } - - # direct message to @armin_theo client = Twitter::REST::Client.new( consumer_key: consumer_key, consumer_secret: consumer_secret, - access_token: user2_token, - access_token_secret: user2_token_secret + access_token: me_bauer_token, + access_token_secret: me_bauer_token_secret ) dms = client.direct_messages( count: 200 ) dms.each {|dm| client.destroy_direct_message(dm.id) } - sleep 10 hash = '#citheo44' + rand(9999).to_s text = 'How about the details? ' + hash @@ -164,43 +163,35 @@ class TwitterTest < ActiveSupport::TestCase # fetch check system account article = nil (1..4).each { - next if article - sleep 25 - Channel.fetch # check if ticket and article has been created - article = Ticket::Article.where( message_id: dm.id ).last + article = Ticket::Article.find_by( message_id: dm.id ) + + break if article + + sleep 5 } - puts '----------------------------------------' - puts 'DM: ' + dm.inspect - puts 'AT: ' + article.inspect - puts '----------------------------------------' assert( article, 'inbound article created' ) - #ticket = Ticket.find( article.ticket.id ) ticket = article.ticket assert( ticket, 'ticket of inbound article exists' ) assert( ticket.articles, 'ticket.articles exists' ) - article_count = ticket.articles.count - assert( article_count ) - #assert_equal( ticket.state.name, 'new' ) + assert_equal( ticket.articles.count, 1, 'ticket article inbound count' ) + assert_equal( ticket.state.name, 'new' ) # reply via ticket outbound_article = Ticket::Article.create( - ticket_id: ticket.id, - type_id: Ticket::Article::Type.where( name: 'twitter direct-message' ).first.id, - sender_id: Ticket::Article::Sender.where( name: 'Agent' ).first.id, - body: text, - #:from => sender.name, - to: 'me_bauer', - internal: false, + ticket_id: ticket.id, + to: 'me_bauer', + body: text, + type: Ticket::Article::Type.find_by( name: 'twitter direct-message' ), + sender: Ticket::Article::Sender.find_by( name: 'Agent' ), + internal: false, updated_by_id: 1, created_by_id: 1, ) assert( outbound_article, 'outbound article created' ) - assert_equal( outbound_article.ticket.articles.count, article_count + 1 ) - sleep 10 - + assert_equal( outbound_article.ticket.articles.count, 2, 'ticket article outbound count' ) end end