Browse Source

Moved to current channel api.

Martin Edenhofer 9 years ago
parent
commit
1d4e1310d1

+ 1 - 1
app/models/channel/driver/mail_stdin.rb

@@ -15,6 +15,6 @@ process emails from STDIN
 
     msg = ARGF.read
 
-    process( {}, msg )
+    process({}, msg)
   end
 end

+ 9 - 5
app/models/channel/driver/smtp.rb

@@ -6,11 +6,15 @@ class Channel::Driver::Smtp
 
   instance = Channel::Driver::Smtp.new
   instance.send(
-    host:                 'some.host',
-    port:                 25,
-    enable_starttls_auto: true, # optional
-    user:                 'someuser',
-    password:             'somepass'
+    {
+      host:                 'some.host',
+      port:                 25,
+      enable_starttls_auto: true, # optional
+      user:                 'someuser',
+      password:             'somepass'
+    },
+    mail_attributes,
+    notification
   )
 
 =end

+ 77 - 11
app/models/channel/driver/twitter.rb

@@ -1,12 +1,55 @@
 # Copyright (C) 2012-2015 Zammad Foundation, http://zammad-foundation.org/
 
+=begin
+
+fetch tweets from twitter account
+
+  options = {
+    adapter: 'twitter',
+    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_id: 2,
+        },
+        {
+          term: '#citheo24',
+          group_id: 1,
+        },
+      ],
+      mentions: {
+        group_id: 2,
+      },
+      direct_messages: {
+        group_id: 2,
+      }
+    }
+  }
+
+  instance = Channel::Driver::Twitter.new
+  result = instance.fetch(options, channel)
+
+returns
+
+  {
+    result: 'ok',
+  }
+
+=end
+
 class Channel::Driver::Twitter
 
-  def fetch (_adapter_options, channel)
+  def fetch (options, channel)
 
+    @tweet   = Tweet.new(options[:auth])
+    @sync    = options[:sync]
     @channel = channel
-    @tweet   = Tweet.new(@channel[:options][:auth])
-    @sync    = @channel[:options][:sync]
 
     Rails.logger.debug 'twitter fetch started'
 
@@ -17,16 +60,39 @@ class Channel::Driver::Twitter
     disconnect
 
     Rails.logger.debug 'twitter fetch completed'
+
+    {
+      result: 'ok',
+    }
   end
 
-  def send(article, _notification = false)
+=begin
 
-    @channel = Channel.find_by(area: 'Twitter::Account', active: true)
-    @tweet   = Tweet.new(@channel[:options][:auth])
+  instance = Channel::Driver::Twitter.new
+  instance.send(
+    {
+      adapter: 'twitter',
+      auth: {
+        consumer_key:       consumer_key,
+        consumer_secret:    consumer_secret,
+        oauth_token:        armin_theo_token,
+        oauth_token_secret: armin_theo_token_secret,
+      },
+    },
+    twitter_attributes,
+    notification
+  )
 
-    tweet = @tweet.from_article(article)
-    disconnect
+=end
 
+  def send(options, article, _notification = false)
+
+    # return if we run import mode
+    return if Setting.get('import_mode')
+
+    @tweet = Tweet.new(options[:auth])
+    tweet  = @tweet.from_article(article)
+    disconnect
     tweet
   end
 
@@ -54,7 +120,7 @@ class Channel::Driver::Twitter
         break if search[:limit] && search[:limit] <= counter
         break if Ticket::Article.find_by(message_id: tweet.id)
 
-        @tweet.to_group(tweet, search[:group_id])
+        @tweet.to_group(tweet, search[:group_id], @channel)
 
         counter += 1
       }
@@ -74,7 +140,7 @@ class Channel::Driver::Twitter
       break if @sync[:mentions][:limit] && @sync[:mentions][:limit] <= counter
       break if Ticket::Article.find_by(message_id: tweet.id)
 
-      @tweet.to_group(tweet, @sync[:mentions][:group_id])
+      @tweet.to_group(tweet, @sync[:mentions][:group_id], @channel)
 
       counter += 1
     }
@@ -93,7 +159,7 @@ class Channel::Driver::Twitter
       break if @sync[:direct_messages][:limit] && @sync[:direct_messages][:limit] <= counter
       break if Ticket::Article.find_by(message_id: tweet.id)
 
-      @tweet.to_group(tweet, @sync[:direct_messages][:group_id])
+      @tweet.to_group(tweet, @sync[:direct_messages][:group_id], @channel)
 
       counter += 1
     }

+ 53 - 46
app/models/channel/email_parser.rb

@@ -9,7 +9,7 @@ class Channel::EmailParser
 
 =begin
 
-  mail = parse( msg_as_string )
+  mail = parse(msg_as_string)
 
   mail = {
     from:              'Some Name <some@example.com>',
@@ -60,9 +60,9 @@ class Channel::EmailParser
 
 =end
 
-  def parse (msg)
+  def parse(msg)
     data = {}
-    mail = Mail.new( msg )
+    mail = Mail.new(msg)
 
     # set all headers
     mail.header.fields.each { |field|
@@ -70,7 +70,7 @@ class Channel::EmailParser
       next if !field.name
 
       # full line, encode, ready for storage
-      data[field.name.to_s.downcase.to_sym] = Encode.conv( 'utf8', field.to_s )
+      data[field.name.to_s.downcase.to_sym] = Encode.conv('utf8', field.to_s)
 
       # if we need to access the lines by objects later again
       data[ "raw-#{field.name.downcase}".to_sym ] = field
@@ -101,11 +101,11 @@ class Channel::EmailParser
 
     # set extra headers
     begin
-      data[:from_email]        = Mail::Address.new( from ).address
-      data[:from_local]        = Mail::Address.new( from ).local
-      data[:from_domain]       = Mail::Address.new( from ).domain
-      data[:from_display_name] = Mail::Address.new( from ).display_name ||
-                                 ( Mail::Address.new( from ).comments && Mail::Address.new( from ).comments[0] )
+      data[:from_email]        = Mail::Address.new(from).address
+      data[:from_local]        = Mail::Address.new(from).local
+      data[:from_domain]       = Mail::Address.new(from).domain
+      data[:from_display_name] = Mail::Address.new(from).display_name ||
+                                 (Mail::Address.new(from).comments && Mail::Address.new(from).comments[0])
     rescue
       data[:from_email]  = from
       data[:from_local]  = from
@@ -113,7 +113,7 @@ class Channel::EmailParser
     end
 
     # do extra decoding because we needed to use field.value
-    data[:from_display_name] = Mail::Field.new( 'X-From', data[:from_display_name] ).to_s
+    data[:from_display_name] = Mail::Field.new('X-From', data[:from_display_name]).to_s
 
     # compat headers
     data[:message_id] = data['message-id'.to_sym]
@@ -129,7 +129,7 @@ class Channel::EmailParser
       # text attachment/body exists
       if mail.text_part
         data[:body] = mail.text_part.body.decoded
-        data[:body] = Encode.conv( mail.text_part.charset, data[:body] )
+        data[:body] = Encode.conv(mail.text_part.charset, data[:body])
 
         if !data[:body].valid_encoding?
           data[:body] = data[:body].encode('utf-8', 'binary', invalid: :replace, undef: :replace, replace: '?')
@@ -142,7 +142,7 @@ class Channel::EmailParser
         if mail.html_part && mail.html_part.body
           filename = 'message.html'
           data[:body] = mail.html_part.body.to_s
-          data[:body] = Encode.conv( mail.html_part.charset.to_s, data[:body] )
+          data[:body] = Encode.conv(mail.html_part.charset.to_s, data[:body])
           data[:body] = data[:body].html2text.to_s.force_encoding('utf-8')
 
           if !data[:body].force_encoding('UTF-8').valid_encoding?
@@ -181,11 +181,11 @@ class Channel::EmailParser
 
           # protect process to work fine with spam emails, see test/fixtures/mail15.box
           begin
-            attachs = _get_attachment( part, data[:attachments], mail )
-            data[:attachments].concat( attachs )
+            attachs = _get_attachment(part, data[:attachments], mail)
+            data[:attachments].concat(attachs)
           rescue
-            attachs = _get_attachment( part, data[:attachments], mail )
-            data[:attachments].concat( attachs )
+            attachs = _get_attachment(part, data[:attachments], mail)
+            data[:attachments].concat(attachs)
           end
         }
       end
@@ -196,7 +196,7 @@ class Channel::EmailParser
       # text part only
       if !mail.mime_type || mail.mime_type.to_s == '' || mail.mime_type.to_s.downcase == 'text/plain'
         data[:body] = mail.body.decoded
-        data[:body] = Encode.conv( mail.charset, data[:body] )
+        data[:body] = Encode.conv(mail.charset, data[:body])
 
         if !data[:body].force_encoding('UTF-8').valid_encoding?
           data[:body] = data[:body].encode('utf-8', 'binary', invalid: :replace, undef: :replace, replace: '?')
@@ -208,7 +208,7 @@ class Channel::EmailParser
         if mail.mime_type.to_s.downcase == 'text/html'
           filename = 'message.html'
           data[:body] = mail.body.decoded
-          data[:body] = Encode.conv( mail.charset, data[:body] )
+          data[:body] = Encode.conv(mail.charset, data[:body])
           data[:body] = data[:body].html2text.to_s.force_encoding('utf-8')
 
           if !data[:body].valid_encoding?
@@ -240,9 +240,9 @@ class Channel::EmailParser
     end
 
     # strip not wanted chars
-    data[:body].gsub!( /\n\r/, "\n" )
-    data[:body].gsub!( /\r\n/, "\n" )
-    data[:body].gsub!( /\r/, "\n" )
+    data[:body].gsub!(/\n\r/, "\n")
+    data[:body].gsub!(/\r\n/, "\n")
+    data[:body].gsub!(/\r/, "\n")
 
     # remember original mail instance
     data[:mail_instance] = mail
@@ -250,14 +250,14 @@ class Channel::EmailParser
     data
   end
 
-  def _get_attachment( file, attachments, mail )
+  def _get_attachment(file, attachments, mail)
 
     # check if sub parts are available
     if !file.parts.empty?
       a = []
       file.parts.each {|p|
-        attachment = _get_attachment( p, attachments, mail )
-        a.concat( attachment )
+        attachment = _get_attachment(p, attachments, mail)
+        a.concat(attachment)
       }
       return a
     end
@@ -341,7 +341,7 @@ retrns
 =end
 
   def process(channel, msg)
-    mail = parse( msg )
+    mail = parse(msg)
 
     # run postmaster pre filter
     filters = {
@@ -353,7 +353,7 @@ retrns
       '1000' => Channel::Filter::Database,
     }
 
-    # filter( channel, mail )
+    # filter(channel, mail)
     filters.each {|_prio, backend|
       begin
         backend.run(channel, mail)
@@ -379,10 +379,10 @@ retrns
 
       # create sender
       if mail[ 'x-zammad-customer-login'.to_sym ]
-        user = User.find_by( login: mail[ 'x-zammad-customer-login'.to_sym ] )
+        user = User.find_by(login: mail[ 'x-zammad-customer-login'.to_sym ])
       end
       if !user
-        user = User.find_by( email: mail[ 'x-zammad-customer-email'.to_sym ] || mail[:from_email] )
+        user = User.find_by(email: mail[ 'x-zammad-customer-email'.to_sym ] || mail[:from_email])
       end
       if !user
         user = user_create(
@@ -422,8 +422,8 @@ retrns
 
       # set ticket state to open if not new
       if ticket
-        state      = Ticket::State.find( ticket.state_id )
-        state_type = Ticket::StateType.find( state.state_type_id )
+        state      = Ticket::State.find(ticket.state_id)
+        state_type = Ticket::StateType.find(state.state_type_id)
 
         # if tickte is merged, find linked ticket
         if state_type.name == 'merged'
@@ -440,16 +440,23 @@ retrns
       # create new ticket
       if !ticket
 
-        # set attributes
+        preferences = {}
+        if channel[:id]
+          preferences = {
+            channel_id: channel[:id]
+          }
+        end
+
         ticket = Ticket.new(
           group_id: channel[:group_id] || 1,
           customer_id: user.id,
           title: mail[:subject] || '',
-          state_id: Ticket::State.find_by( name: 'new' ).id,
-          priority_id: Ticket::Priority.find_by( name: '2 normal' ).id,
+          state_id: Ticket::State.find_by(name: 'new').id,
+          priority_id: Ticket::Priority.find_by(name: '2 normal').id,
+          preferences: preferences,
         )
 
-        set_attributes_by_x_headers( ticket, 'ticket', mail )
+        set_attributes_by_x_headers(ticket, 'ticket', mail)
 
         # create ticket
         ticket.save
@@ -460,8 +467,8 @@ retrns
       # set attributes
       article = Ticket::Article.new(
         ticket_id: ticket.id,
-        type_id: Ticket::Article::Type.find_by( name: 'email' ).id,
-        sender_id: Ticket::Article::Sender.find_by( name: 'Customer' ).id,
+        type_id: Ticket::Article::Type.find_by(name: 'email').id,
+        sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id,
         body: mail[:body],
         from: mail[:from],
         to: mail[:to],
@@ -472,7 +479,7 @@ retrns
       )
 
       # x-headers lookup
-      set_attributes_by_x_headers( article, 'article', mail )
+      set_attributes_by_x_headers(article, 'article', mail)
 
       # create article
       article.save
@@ -505,13 +512,13 @@ retrns
 
     # run postmaster post filter
     filters = {
-      #      '0010' => Channel::Filter::Trusted,
+      # '0010' => Channel::Filter::Trusted,
     }
 
     # filter( channel, mail )
     filters.each {|_prio, backend|
       begin
-        backend.run( channel, mail, ticket, article, user )
+        backend.run(channel, mail, ticket, article, user)
       rescue => e
         Rails.logger.error "can't run postmaster post filter #{backend}"
         Rails.logger.error e.inspect
@@ -525,11 +532,11 @@ retrns
   def user_create(data)
 
     # return existing
-    user = User.find_by( login: data[:email].downcase )
+    user = User.find_by(login: data[:email].downcase)
     return user if user
 
     # create new user
-    roles = Role.where( name: 'Customer' )
+    roles = Role.where(name: 'Customer')
 
     # fillup
     %w(firstname lastname).each { |item|
@@ -551,7 +558,7 @@ retrns
     user
   end
 
-  def set_attributes_by_x_headers( item_object, header_name, mail )
+  def set_attributes_by_x_headers(item_object, header_name, mail)
 
     # loop all x-zammad-hedaer-* headers
     item_object.attributes.each {|key, _value|
@@ -577,12 +584,12 @@ retrns
             item = assoc.class_name.constantize
 
             if item.respond_to?(:name)
-              if item.lookup( name: mail[ header.to_sym ] )
-                item_object[key] = item.lookup( name: mail[ header.to_sym ] ).id
+              if item.lookup(name: mail[ header.to_sym ])
+                item_object[key] = item.lookup(name: mail[ header.to_sym ]).id
               end
             elsif item.respond_to?(:login)
-              if item.lookup( login: mail[ header.to_sym ] )
-                item_object[key] = item.lookup( login: mail[ header.to_sym ] ).id
+              if item.lookup(login: mail[ header.to_sym ])
+                item_object[key] = item.lookup(login: mail[ header.to_sym ]).id
               end
             end
           }

+ 16 - 11
app/models/observer/ticket/article/communicate_twitter.rb

@@ -12,22 +12,27 @@ class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer
     return if Setting.get('import_mode')
 
     # if sender is customer, do not communication
-    sender = Ticket::Article::Sender.lookup( id: record.sender_id )
+    sender = Ticket::Article::Sender.lookup(id: record.sender_id)
     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'] !~ /\Atwitter/
-
-    twitter = Channel::Driver::Twitter.new
-    tweet   = twitter.send({
-                             type:        type['name'],
-                             to:          record.to,
-                             body:        record.body,
-                             in_reply_to: record.in_reply_to
-                           })
+    type = Ticket::Article::Type.lookup(id: record.type_id)
+    return if type['name'] !~ /\Atwitter/i
+
+    ticket = Ticket.lookup(id: record.ticket_id)
+    fail "Can't find ticket.preferences for Ticket.find(#{record.ticket_id})" if !ticket.preferences
+    fail "Can't find ticket.preferences['channel_id'] for Ticket.find(#{record.ticket_id})" if !ticket.preferences['channel_id']
+    channel = Channel.lookup(id: ticket.preferences['channel_id'])
+    fail "Channel.find(#{channel.id}) isn't a twitter channel!" if channel.options[:adapter] !~ /\Atwitter/i
+    tweet = channel.deliver(
+      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

+ 1 - 0
app/models/ticket.rb

@@ -14,6 +14,7 @@ class Ticket < ApplicationModel
   include Ticket::SearchIndex
   extend Ticket::Search
 
+  store           :preferences
   before_create   :check_generate, :check_defaults, :check_title
   before_update   :check_defaults, :check_title, :reset_pending_time
   before_destroy  :destroy_dependencies

+ 5 - 0
db/migrate/20151213000001_update_ticket_preferences.rb

@@ -0,0 +1,5 @@
+class UpdateTicketPreferences < ActiveRecord::Migration
+  def up
+    add_column :tickets, :preferences, :text, limit: 500.kilobytes + 1, null: true
+  end
+end

+ 9 - 6
lib/tweet.rb

@@ -86,7 +86,7 @@ class Tweet
     user
   end
 
-  def to_ticket(tweet, user, group_id)
+  def to_ticket(tweet, user, group_id, channel)
 
     Rails.logger.debug 'Create ticket from tweet...'
     Rails.logger.debug tweet.inspect
@@ -118,6 +118,9 @@ class Tweet
       group_id:    group_id,
       state_id:    Ticket::State.find_by(name: 'new').id,
       priority_id: Ticket::Priority.find_by(name: '2 normal').id,
+      preferences: {
+        channel_id: channel.id
+      },
     )
   end
 
@@ -164,7 +167,7 @@ class Tweet
     )
   end
 
-  def to_group(tweet, group_id)
+  def to_group(tweet, group_id, channel)
 
     Rails.logger.debug 'import tweet'
 
@@ -177,19 +180,19 @@ class Tweet
       # check if parent exists
       user = to_user(tweet)
       if tweet.class == Twitter::DirectMessage
-        ticket = to_ticket(tweet, user, group_id)
+        ticket = to_ticket(tweet, user, group_id, channel)
         to_article(tweet, user, ticket)
       elsif tweet.class == Twitter::Tweet
-        if tweet.in_reply_to_status_id
+        if 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)
           if existing_article
             ticket = existing_article.ticket
           else
             parent_tweet = @client.status(tweet.in_reply_to_status_id)
-            ticket       = to_group(parent_tweet, group_id)
+            ticket       = to_group(parent_tweet, group_id, channel)
           end
         else
-          ticket = to_ticket(tweet, user, group_id)
+          ticket = to_ticket(tweet, user, group_id, channel)
         end
         to_article(tweet, user, ticket)
       else

+ 8 - 4
test/integration/twitter_test.rb

@@ -48,7 +48,7 @@ class TwitterTest < ActiveSupport::TestCase
   # add channel
   current = Channel.where(area: 'Twitter::Account')
   current.each(&:destroy)
-  Channel.create(
+  channel = Channel.create(
     area: 'Twitter::Account',
     options: {
       adapter: 'twitter',
@@ -93,6 +93,9 @@ class TwitterTest < ActiveSupport::TestCase
       group_id:      2,
       state:         Ticket::State.find_by(name: 'new'),
       priority:      Ticket::Priority.find_by(name: '2 normal'),
+      preferences: {
+        channel_id: channel.id,
+      },
       updated_by_id: 1,
       created_by_id: 1,
     )
@@ -173,7 +176,7 @@ class TwitterTest < ActiveSupport::TestCase
     tweet = client.update(
       text,
     )
-    sleep 10
+    sleep 15
 
     # fetch check system account
     article = nil
@@ -243,7 +246,7 @@ class TwitterTest < ActiveSupport::TestCase
       text,
     )
     assert(dm, "dm with ##{hash} created")
-    sleep 10
+    sleep 15
 
     # fetch check system account
     article = nil
@@ -288,7 +291,7 @@ class TwitterTest < ActiveSupport::TestCase
       text,
     )
     assert(dm, "second dm with ##{hash} created")
-    sleep 10
+    sleep 15
 
     # fetch check system account
     article = nil
@@ -321,6 +324,7 @@ class TwitterTest < ActiveSupport::TestCase
       text,
     )
     assert(dm, "third dm with ##{hash} created")
+    sleep 15
 
     # fetch check system account
     article = nil