diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_actions.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_actions.coffee index 86526cc86..083402a39 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/article_actions.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_actions.coffee @@ -1,9 +1,11 @@ class App.TicketZoomArticleActions extends App.Controller events: - 'click [data-type=public]': 'publicInternal' - 'click [data-type=internal]': 'publicInternal' - 'click [data-type=reply]': 'reply' - 'click [data-type=replyAll]': 'replyAll' + 'click [data-type=public]': 'publicInternal' + 'click [data-type=internal]': 'publicInternal' + 'click [data-type=emailReply]': 'emailReply' + 'click [data-type=emailReplyAll]': 'emailReplyAll' + 'click [data-type=twitterStatusReply]': 'twitterStatusReply' + 'click [data-type=twitterDirectMessageReply]': 'twitterDirectMessageReply' constructor: -> super @@ -68,7 +70,7 @@ class App.TicketZoomArticleActions extends App.Controller if article.type.name is 'email' || article.type.name is 'phone' || article.type.name is 'web' actions.push { name: 'reply' - type: 'reply' + type: 'emailReply' icon: 'reply' href: '#' } @@ -90,10 +92,18 @@ class App.TicketZoomArticleActions extends App.Controller if recipients.length > 1 actions.push { name: 'reply all' - type: 'replyAll' + type: 'emailReplyAll' icon: 'reply-all' href: '#' } + if article.type.name is 'twitter status' + actions.push { + name: 'reply' + type: 'twitterStatusReply' + icon: 'reply' + href: '#' + } + actions.push { name: 'split' type: 'split' @@ -102,19 +112,83 @@ class App.TicketZoomArticleActions extends App.Controller } actions - replyAll: (e) => - @reply(e, true) - - reply: (e, all = false) => + twitterStatusReply: (e) => e.preventDefault() # get reference article article_id = $(e.target).parents('[data-id]').data('id') - article = App.TicketArticle.fullLocal( article_id ) - type = App.TicketArticleType.find( article.type_id ) - customer = App.User.find( article.created_by_id ) + article = App.TicketArticle.fullLocal(article_id) + type = App.TicketArticleType.find(article.type_id) + customer = App.User.find(article.created_by_id) - @el.closest('.article-add').ScrollTo() + @scrollToCompose() + + # empty form + articleNew = { + to: '' + cc: '' + body: '' + in_reply_to: '' + } + + if article.message_id + articleNew.in_reply_to = article.message_id + + # get current body + body = @el.closest('.ticketZoom').find('.article-add [data-name="body"]').html() || '' + articleNew.body = body + + to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid + recipient = "@#{to} " + + if !body + articleNew.body = recipient + + if body && !body.match("@#{to}") + articleNew.body = "#{recipient}#{articleNew.body}" + + + App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew } ) + + twitterDirectMessageReply: (e) => + e.preventDefault() + + # get reference article + article_id = $(e.target).parents('[data-id]').data('id') + article = App.TicketArticle.fullLocal(article_id) + type = App.TicketArticleType.find(article.type_id) + customer = App.User.find(article.created_by_id) + + @scrollToCompose() + + # empty form + articleNew = { + to: '' + cc: '' + body: '' + in_reply_to: '' + } + + if article.message_id + articleNew.in_reply_to = article.message_id + + articleNew.to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid + + App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew } ) + + emailReplyAll: (e) => + @emailReply(e, true) + + emailReply: (e, all = false) => + e.preventDefault() + + # get reference article + article_id = $(e.target).parents('[data-id]').data('id') + article = App.TicketArticle.fullLocal(article_id) + type = App.TicketArticleType.find(article.type_id) + customer = App.User.find(article.created_by_id) + + @scrollToCompose() # empty form articleNew = { @@ -129,19 +203,7 @@ class App.TicketZoomArticleActions extends App.Controller if article.message_id articleNew.in_reply_to = article.message_id - if type.name is 'twitter status' - - # set to in body - to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid - articleNew.body = '@' + to - - else if type.name is 'twitter direct-message' - - # show to - to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid - articleNew.to = to - - else if type.name is 'email' || type.name is 'phone' || type.name is 'web' + if type.name is 'email' || type.name is 'phone' || type.name is 'web' if article.sender.name is 'Agent' articleNew.to = article.to @@ -198,10 +260,10 @@ class App.TicketZoomArticleActions extends App.Controller if selectedText # clean selection - selectedText = App.Utils.textCleanup( selectedText ) + selectedText = App.Utils.textCleanup(selectedText) # convert to html - selectedText = App.Utils.text2html( selectedText ) + selectedText = App.Utils.text2html(selectedText) if selectedText selectedText = "


#{selectedText}

" @@ -210,4 +272,10 @@ class App.TicketZoomArticleActions extends App.Controller articleNew.body = body + type = App.TicketArticleType.findByAttribute(name:'email') + App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew } ) + + scrollToCompose: => + @el.closest('.content').find('.article-add').ScrollTo() + diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee index 9ccba0fd3..92a05b5ff 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee @@ -84,7 +84,6 @@ class App.TicketZoomArticleNew extends App.Controller # set article type and expand text area @bind('ui::ticket::setArticleType', (data) => return if data.ticket.id isnt @ticket_id - #@setArticleType(data.type.name) @openTextarea(null, true) for key, value of data.article @@ -94,7 +93,7 @@ class App.TicketZoomArticleNew extends App.Controller @$('[name="' + key + '"]').val(value) # preselect article type - @setArticleType('email') + @setArticleType(data.type.name) ) # reset new article screen diff --git a/app/models/avatar.rb b/app/models/avatar.rb index 42630c8e0..c4e6a8af6 100644 --- a/app/models/avatar.rb +++ b/app/models/avatar.rb @@ -8,12 +8,11 @@ class Avatar < ApplicationModel add an avatar based on auto detection (email address) Avatar.auto_detection( - :object => 'User', - :o_id => user.id, - :url => 'somebody@example.com', - :source => 'web', - :updated_by_id => 1, - :created_by_id => 1, + object: 'User', + o_id: user.id, + url: 'somebody@example.com', + updated_by_id: 1, + created_by_id: 1, ) =end @@ -41,20 +40,20 @@ add an avatar based on auto detection (email address) add a avatar Avatar.add( - :object => 'User', - :o_id => user.id, - :default => true, - :full => { - :content => '...', - :mime_type => 'image/png', + object: 'User', + o_id: user.id, + default: true, + full: { + content: '...', + mime_type: 'image/png', }, - :resize => { - :content => '...', - :mime_type => 'image/png', + resize: { + content: '...', + mime_type: 'image/png', }, - :source => 'web', - :updated_by_id => 1, - :created_by_id => 1, + source: 'web', + updated_by_id: 1, + created_by_id: 1, ) =end @@ -214,7 +213,7 @@ add a avatar set avatars as default - Avatar.set_default( 'User', 123, avatar_id ) + Avatar.set_default('User', 123, avatar_id) =end @@ -238,12 +237,12 @@ set avatars as default remove all avatars of an object - Avatar.remove( 'User', 123 ) + Avatar.remove('User', 123) =end - def self.remove( object_name, o_id ) - object_id = ObjectLookup.by_name( object_name ) + def self.remove(object_name, o_id) + object_id = ObjectLookup.by_name(object_name) Avatar.where( object_lookup_id: object_id, o_id: o_id, @@ -264,12 +263,12 @@ remove all avatars of an object remove one avatars of an object - Avatar.remove_one( 'User', 123, avatar_id ) + Avatar.remove_one('User', 123, avatar_id) =end - def self.remove_one( object_name, o_id, avatar_id ) - object_id = ObjectLookup.by_name( object_name ) + def self.remove_one(object_name, o_id, avatar_id) + object_id = ObjectLookup.by_name(object_name) Avatar.where( object_lookup_id: object_id, o_id: o_id, @@ -281,16 +280,16 @@ remove one avatars of an object return all avatars of an user - avatars = Avatar.list( 'User', 123 ) + avatars = Avatar.list('User', 123) =end def self.list(object_name, o_id) - object_id = ObjectLookup.by_name( object_name ) + object_id = ObjectLookup.by_name(object_name) avatars = Avatar.where( object_lookup_id: object_id, o_id: o_id, - ).order( 'initial DESC, deletable ASC, created_at ASC, id DESC' ) + ).order('initial DESC, deletable ASC, created_at ASC, id DESC') # add initial avatar add_init_avatar(object_id, o_id) @@ -300,7 +299,7 @@ return all avatars of an user data = avatar.attributes if avatar.store_resize_id file = Store.find(avatar.store_resize_id) - data['content'] = "data:#{file.preferences['Mime-Type']};base64,#{Base64.strict_encode64( file.content )}" + data['content'] = "data:#{file.preferences['Mime-Type']};base64,#{Base64.strict_encode64(file.content)}" end avatar_list.push data end @@ -311,7 +310,7 @@ return all avatars of an user get default avatar image of user by hash - store = Avatar.get_by_hash( hash ) + store = Avatar.get_by_hash(hash) returns: @@ -331,7 +330,7 @@ returns: get default avatar of user by user id - avatar = Avatar.get_default( 'User', user_id ) + avatar = Avatar.get_default('User', user_id) returns: @@ -340,7 +339,7 @@ returns: =end def self.get_default(object_name, o_id) - object_id = ObjectLookup.by_name( object_name ) + object_id = ObjectLookup.by_name(object_name) Avatar.find_by( object_lookup_id: object_id, o_id: o_id, @@ -352,7 +351,7 @@ returns: avatars = Avatar.where( object_lookup_id: object_id, o_id: o_id, - ).order( 'created_at ASC, id DESC' ) + ).order('created_at ASC, id DESC') avatars.each do |avatar| next if avatar.id == avatar_id avatar.default = false diff --git a/app/models/observer/ticket/article/communicate_twitter.rb b/app/models/observer/ticket/article/communicate_twitter.rb index 68eba6067..1c2e7b29a 100644 --- a/app/models/observer/ticket/article/communicate_twitter.rb +++ b/app/models/observer/ticket/article/communicate_twitter.rb @@ -1,8 +1,5 @@ # 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/driver/twitter' - class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer observe 'ticket::_article' @@ -28,9 +25,26 @@ class Observer::Ticket::Article::CommunicateTwitter < ActiveRecord::Observer tweet = channel.deliver( type: type['name'], to: record.to, - body: record.body, + body: record.body.html2text, in_reply_to: record.in_reply_to ) + + # fill article with tweet info + record.from = tweet.user.screen_name + if tweet.user_mentions + to = '' + twitter_mention_ids = [] + tweet.user_mentions.each {|user| + if to != '' + to += ' ' + end + to += "@#{user.screen_name}" + twitter_mention_ids.push user.id + } + record.to = to + record.preferences[:twitter_mention_ids] = twitter_mention_ids + end + record.message_id = tweet.id record.save end diff --git a/lib/tweet.rb b/lib/tweet.rb index 289546091..8b8c91293 100644 --- a/lib/tweet.rb +++ b/lib/tweet.rb @@ -68,6 +68,24 @@ class Tweet 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: 'twitter', + 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 or update authorization auth_data = { uid: tweet_user.id, @@ -81,8 +99,6 @@ class Tweet Authorization.create(auth_data) end - UserInfo.current_user_id = user.id - user end @@ -112,6 +128,8 @@ class Tweet end end + UserInfo.current_user_id = user.id + Ticket.create( customer_id: user.id, title: "#{tweet.text[0, 37]}...", @@ -148,12 +166,14 @@ class Tweet from = tweet.sender.screen_name elsif tweet.class == Twitter::Tweet article_type = 'twitter status' - from = tweet.in_reply_to_screen_name + from = tweet.user.screen_name in_reply_to = tweet.in_reply_to_status_id else fail "Unknown tweet type '#{tweet.class}'" end + UserInfo.current_user_id = user.id + Ticket::Article.create( from: from, to: to, diff --git a/test/browser/agent_ticket_actions_level5_test.rb b/test/browser/agent_ticket_actions_level5_test.rb index 06a852e3e..c8a1109c6 100644 --- a/test/browser/agent_ticket_actions_level5_test.rb +++ b/test/browser/agent_ticket_actions_level5_test.rb @@ -243,7 +243,7 @@ class AgentTicketActionLevel5Test < TestCase # execute reply click( - css: '.active [data-type="reply"]', + css: '.active [data-type="emailReply"]', ) # check if signature exists @@ -267,7 +267,7 @@ class AgentTicketActionLevel5Test < TestCase # execute reply sleep 5 # time to recognice form changes click( - css: '.active [data-type="reply"]', + css: '.active [data-type="emailReply"]', ) # check if signature exists diff --git a/test/browser/agent_ticket_actions_level7_test.rb b/test/browser/agent_ticket_actions_level7_test.rb index 905206131..d41d9625f 100644 --- a/test/browser/agent_ticket_actions_level7_test.rb +++ b/test/browser/agent_ticket_actions_level7_test.rb @@ -35,11 +35,11 @@ class AgentTicketActionLevel7Test < TestCase # scroll to reply - needed for chrome scroll_to( position: 'botton', - css: '.content.active [data-type="reply"]', + css: '.content.active [data-type="emailReply"]', ) # click reply - click( css: '.content.active [data-type="reply"]' ) + click( css: '.content.active [data-type="emailReply"]' ) # check body watch_for( @@ -58,11 +58,11 @@ class AgentTicketActionLevel7Test < TestCase # scroll to reply - needed for chrome scroll_to( position: 'botton', - css: '.content.active [data-type="reply"]', + css: '.content.active [data-type="emailReply"]', ) # click reply - click( css: '.content.active [data-type="reply"]' ) + click( css: '.content.active [data-type="emailReply"]' ) # check body watch_for(