Split of article actions into separate backends.
This commit is contained in:
parent
ab189f46ec
commit
f3ff650bfe
9 changed files with 460 additions and 371 deletions
|
@ -0,0 +1,34 @@
|
||||||
|
class Delete
|
||||||
|
@action: (actions, ticket, article, ui) ->
|
||||||
|
return actions if ui.permissionCheck('ticket.customer')
|
||||||
|
|
||||||
|
if article.type.name is 'note'
|
||||||
|
user = undefined
|
||||||
|
if App.Session.get('id') == article.created_by_id
|
||||||
|
user = App.User.find(App.Session.get('id'))
|
||||||
|
if user.permission('ticket.agent')
|
||||||
|
actions.push {
|
||||||
|
name: 'delete'
|
||||||
|
type: 'delete'
|
||||||
|
icon: 'trash'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
|
||||||
|
actions
|
||||||
|
|
||||||
|
@perform: (articleContainer, type, ticket, article, ui) ->
|
||||||
|
return true if type isnt 'delete'
|
||||||
|
|
||||||
|
callback = ->
|
||||||
|
article = App.TicketArticle.find(article.id)
|
||||||
|
article.destroy()
|
||||||
|
|
||||||
|
new App.ControllerConfirm(
|
||||||
|
message: 'Sure?'
|
||||||
|
callback: callback
|
||||||
|
container: ui.el.closest('.content')
|
||||||
|
)
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
App.Config.set('900-Delete', Delete, 'TicketZoomArticleAction')
|
|
@ -0,0 +1,135 @@
|
||||||
|
class EmailReply extends App.Controller
|
||||||
|
@action: (actions, ticket, article, ui) ->
|
||||||
|
return actions if ui.permissionCheck('ticket.customer')
|
||||||
|
|
||||||
|
group = ticket.group
|
||||||
|
if group.email_address_id && (article.type.name is 'email' || article.type.name is 'web')
|
||||||
|
actions.push {
|
||||||
|
name: 'reply'
|
||||||
|
type: 'emailReply'
|
||||||
|
icon: 'reply'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
recipients = []
|
||||||
|
if article.sender.name is 'Customer'
|
||||||
|
if article.from
|
||||||
|
localRecipients = emailAddresses.parseAddressList(article.from)
|
||||||
|
if localRecipients
|
||||||
|
recipients = recipients.concat localRecipients
|
||||||
|
if article.to
|
||||||
|
localRecipients = emailAddresses.parseAddressList(article.to)
|
||||||
|
if localRecipients
|
||||||
|
recipients = recipients.concat localRecipients
|
||||||
|
if article.cc
|
||||||
|
localRecipients = emailAddresses.parseAddressList(article.cc)
|
||||||
|
if localRecipients
|
||||||
|
recipients = recipients.concat localRecipients
|
||||||
|
|
||||||
|
# remove system addresses
|
||||||
|
localAddresses = App.EmailAddress.all()
|
||||||
|
forgeinRecipients = []
|
||||||
|
recipientUsed = {}
|
||||||
|
for recipient in recipients
|
||||||
|
if !_.isEmpty(recipient.address)
|
||||||
|
localRecipientAddress = recipient.address.toString().toLowerCase()
|
||||||
|
if !recipientUsed[localRecipientAddress]
|
||||||
|
recipientUsed[localRecipientAddress] = true
|
||||||
|
localAddress = false
|
||||||
|
for address in localAddresses
|
||||||
|
if localRecipientAddress is address.email.toString().toLowerCase()
|
||||||
|
recipientUsed[localRecipientAddress] = true
|
||||||
|
localAddress = true
|
||||||
|
if !localAddress
|
||||||
|
forgeinRecipients.push recipient
|
||||||
|
|
||||||
|
# check if reply all is neede
|
||||||
|
if forgeinRecipients.length > 1
|
||||||
|
actions.push {
|
||||||
|
name: 'reply all'
|
||||||
|
type: 'emailReplyAll'
|
||||||
|
icon: 'reply-all'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
if article.sender.name is 'Customer' && article.type.name is 'phone'
|
||||||
|
actions.push {
|
||||||
|
name: 'reply'
|
||||||
|
type: 'emailReply'
|
||||||
|
icon: 'reply'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
if article.sender.name is 'Agent' && article.type.name is 'phone'
|
||||||
|
actions.push {
|
||||||
|
name: 'reply'
|
||||||
|
type: 'emailReply'
|
||||||
|
icon: 'reply'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
|
||||||
|
actions
|
||||||
|
|
||||||
|
@perform: (articleContainer, type, ticket, article, ui) ->
|
||||||
|
return true if type isnt 'emailReply' && type isnt 'emailReplyAll'
|
||||||
|
|
||||||
|
if type isnt 'emailReply'
|
||||||
|
@emailReply(true, ticket, article, ui)
|
||||||
|
|
||||||
|
else if type isnt 'emailReplyAll'
|
||||||
|
@emailReply(false, ticket, article, ui)
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
@emailReply: (all = false, ticket, article, ui) ->
|
||||||
|
|
||||||
|
# get reference article
|
||||||
|
type = App.TicketArticleType.find(article.type_id)
|
||||||
|
article_created_by = App.User.find(article.created_by_id)
|
||||||
|
email_addresses = App.EmailAddress.all()
|
||||||
|
|
||||||
|
ui.scrollToCompose()
|
||||||
|
|
||||||
|
# empty form
|
||||||
|
articleNew = App.Utils.getRecipientArticle(ticket, article, article_created_by, type, email_addresses, all)
|
||||||
|
|
||||||
|
# get current body
|
||||||
|
body = ui.el.closest('.ticketZoom').find('.article-add [data-name="body"]').html() || ''
|
||||||
|
|
||||||
|
# check if quote need to be added
|
||||||
|
signaturePosition = 'bottom'
|
||||||
|
selected = App.ClipBoard.getSelected('html')
|
||||||
|
if selected
|
||||||
|
selected = App.Utils.htmlCleanup(selected).html()
|
||||||
|
if !selected
|
||||||
|
selected = App.ClipBoard.getSelected('text')
|
||||||
|
if selected
|
||||||
|
selected = App.Utils.textCleanup(selected)
|
||||||
|
selected = App.Utils.text2html(selected)
|
||||||
|
|
||||||
|
# full quote, if needed
|
||||||
|
if !selected && article && App.Config.get('ui_ticket_zoom_article_email_full_quote')
|
||||||
|
signaturePosition = 'top'
|
||||||
|
if article.content_type.match('html')
|
||||||
|
selected = App.Utils.textCleanup(article.body)
|
||||||
|
if article.content_type.match('plain')
|
||||||
|
selected = App.Utils.textCleanup(article.body)
|
||||||
|
selected = App.Utils.text2html(selected)
|
||||||
|
|
||||||
|
if selected
|
||||||
|
selected = "<div><br><br/></div><div><blockquote type=\"cite\">#{selected}</blockquote></div><div><br></div>"
|
||||||
|
|
||||||
|
# add selected text to body
|
||||||
|
body = selected + body
|
||||||
|
|
||||||
|
articleNew.body = body
|
||||||
|
|
||||||
|
type = App.TicketArticleType.findByAttribute(name:'email')
|
||||||
|
|
||||||
|
App.Event.trigger('ui::ticket::setArticleType', {
|
||||||
|
ticket: ticket
|
||||||
|
type: type
|
||||||
|
article: articleNew
|
||||||
|
signaturePosition: signaturePosition
|
||||||
|
})
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
App.Config.set('200-EmailReply', EmailReply, 'TicketZoomArticleAction')
|
|
@ -0,0 +1,37 @@
|
||||||
|
class FacebookReply
|
||||||
|
@action: (actions, ticket, article, ui) ->
|
||||||
|
return actions if ui.permissionCheck('ticket.customer')
|
||||||
|
|
||||||
|
if article.type.name is 'facebook feed post' || article.type.name is 'facebook feed comment'
|
||||||
|
actions.push {
|
||||||
|
name: 'reply'
|
||||||
|
type: 'facebookFeedReply'
|
||||||
|
icon: 'reply'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
|
||||||
|
actions
|
||||||
|
|
||||||
|
@perform: (articleContainer, type, ticket, article, ui) ->
|
||||||
|
return true if type isnt 'facebookFeedReply'
|
||||||
|
|
||||||
|
ui.scrollToCompose()
|
||||||
|
|
||||||
|
type = App.TicketArticleType.findByAttribute('name', 'facebook feed comment')
|
||||||
|
|
||||||
|
articleNew = {
|
||||||
|
to: ''
|
||||||
|
cc: ''
|
||||||
|
body: ''
|
||||||
|
in_reply_to: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
App.Event.trigger('ui::ticket::setArticleType', {
|
||||||
|
ticket: ticket
|
||||||
|
type: type
|
||||||
|
article: articleNew
|
||||||
|
})
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
App.Config.set('300-FacebookReply', FacebookReply, 'TicketZoomArticleAction')
|
|
@ -0,0 +1,40 @@
|
||||||
|
class Internal
|
||||||
|
@action: (actions, ticket, article, ui) ->
|
||||||
|
return actions if ui.permissionCheck('ticket.customer')
|
||||||
|
|
||||||
|
if article.internal is true
|
||||||
|
actions.push {
|
||||||
|
name: 'set to public'
|
||||||
|
type: 'public'
|
||||||
|
icon: 'lock-open'
|
||||||
|
}
|
||||||
|
else
|
||||||
|
actions.push {
|
||||||
|
name: 'set to internal'
|
||||||
|
type: 'internal'
|
||||||
|
icon: 'lock'
|
||||||
|
}
|
||||||
|
|
||||||
|
actions
|
||||||
|
|
||||||
|
@perform: (articleContainer, type, ticket, article, ui) ->
|
||||||
|
return true if type isnt 'internal' && type isnt 'public'
|
||||||
|
|
||||||
|
# storage update
|
||||||
|
internal = true
|
||||||
|
if article.internal == true
|
||||||
|
internal = false
|
||||||
|
ui.lastAttributres.internal = internal
|
||||||
|
article.updateAttributes(internal: internal)
|
||||||
|
|
||||||
|
# runtime update
|
||||||
|
if internal
|
||||||
|
articleContainer.addClass('is-internal')
|
||||||
|
else
|
||||||
|
articleContainer.removeClass('is-internal')
|
||||||
|
|
||||||
|
ui.render()
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
App.Config.set('100-Internal', Internal, 'TicketZoomArticleAction')
|
|
@ -0,0 +1,18 @@
|
||||||
|
class Split
|
||||||
|
@action: (actions, ticket, article, ui) ->
|
||||||
|
return actions if ui.permissionCheck('ticket.customer')
|
||||||
|
|
||||||
|
actions.push {
|
||||||
|
name: 'split'
|
||||||
|
type: 'split'
|
||||||
|
icon: 'split'
|
||||||
|
href: "#ticket/create/#{article.ticket_id}/#{article.id}"
|
||||||
|
}
|
||||||
|
actions
|
||||||
|
|
||||||
|
@perform: (articleContainer, type, ticket, article, ui) ->
|
||||||
|
return true if type isnt 'split'
|
||||||
|
ui.navigate "#ticket/create/#{article.ticket_id}/#{article.id}"
|
||||||
|
true
|
||||||
|
|
||||||
|
App.Config.set('700-Split', Split, 'TicketZoomArticleAction')
|
|
@ -0,0 +1,45 @@
|
||||||
|
class TelegramReply
|
||||||
|
@action: (actions, ticket, article, ui) ->
|
||||||
|
return actions if ui.permissionCheck('ticket.customer')
|
||||||
|
|
||||||
|
if article.sender.name is 'Customer' && article.type.name is 'telegram personal-message'
|
||||||
|
actions.push {
|
||||||
|
name: 'reply'
|
||||||
|
type: 'telegramPersonalMessageReply'
|
||||||
|
icon: 'reply'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
|
||||||
|
actions
|
||||||
|
|
||||||
|
@perform: (articleContainer, type, ticket, article, ui) ->
|
||||||
|
return true if type isnt 'telegramPersonalMessageReply'
|
||||||
|
|
||||||
|
ui.scrollToCompose()
|
||||||
|
|
||||||
|
# get reference article
|
||||||
|
type = App.TicketArticleType.find(article.type_id)
|
||||||
|
|
||||||
|
articleNew = {
|
||||||
|
to: ''
|
||||||
|
cc: ''
|
||||||
|
body: ''
|
||||||
|
in_reply_to: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if article.message_id
|
||||||
|
articleNew.in_reply_to = article.message_id
|
||||||
|
|
||||||
|
# get current body
|
||||||
|
articleNew.body = ui.el.closest('.ticketZoom').find('.article-add [data-name="body"]').html().trim() || ''
|
||||||
|
|
||||||
|
App.Event.trigger('ui::ticket::setArticleType', {
|
||||||
|
ticket: ticket
|
||||||
|
type: type
|
||||||
|
article: articleNew
|
||||||
|
position: 'end'
|
||||||
|
})
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
App.Config.set('300-TelegramReply', TelegramReply, 'TicketZoomArticleAction')
|
|
@ -0,0 +1,128 @@
|
||||||
|
class TwitterReply
|
||||||
|
@action: (actions, ticket, article, ui) ->
|
||||||
|
return actions if ui.permissionCheck('ticket.customer')
|
||||||
|
|
||||||
|
if article.type.name is 'twitter status'
|
||||||
|
actions.push {
|
||||||
|
name: 'reply'
|
||||||
|
type: 'twitterStatusReply'
|
||||||
|
icon: 'reply'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
if article.type.name is 'twitter direct-message'
|
||||||
|
actions.push {
|
||||||
|
name: 'reply'
|
||||||
|
type: 'twitterDirectMessageReply'
|
||||||
|
icon: 'reply'
|
||||||
|
href: '#'
|
||||||
|
}
|
||||||
|
|
||||||
|
actions
|
||||||
|
|
||||||
|
@perform: (articleContainer, type, ticket, article, ui) ->
|
||||||
|
return true if type isnt 'twitterStatusReply' && type isnt 'twitterDirectMessageReply'
|
||||||
|
|
||||||
|
if type is 'twitterStatusReply'
|
||||||
|
@twitterStatusReply(ticket, article, ui)
|
||||||
|
|
||||||
|
else if type is 'twitterDirectMessageReply'
|
||||||
|
@twitterDirectMessageReply(ticket, article, ui)
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
@twitterStatusReply: (ticket, article, ui) ->
|
||||||
|
|
||||||
|
ui.scrollToCompose()
|
||||||
|
|
||||||
|
# get reference article
|
||||||
|
type = App.TicketArticleType.find(article.type_id)
|
||||||
|
|
||||||
|
# empty form
|
||||||
|
articleNew = {
|
||||||
|
to: ''
|
||||||
|
cc: ''
|
||||||
|
body: ''
|
||||||
|
in_reply_to: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if article.message_id
|
||||||
|
articleNew.in_reply_to = article.message_id
|
||||||
|
|
||||||
|
# get current body
|
||||||
|
body = ui.el.closest('.ticketZoom').find('.article-add [data-name="body"]').html().trim() || ''
|
||||||
|
articleNew.body = body
|
||||||
|
|
||||||
|
recipients = article.from
|
||||||
|
if article.to
|
||||||
|
if recipients
|
||||||
|
recipients += ', '
|
||||||
|
recipients += article.to
|
||||||
|
|
||||||
|
if recipients
|
||||||
|
recipientString = ''
|
||||||
|
recipientScreenNames = recipients.split(',')
|
||||||
|
for recipientScreenName in recipientScreenNames
|
||||||
|
if recipientScreenName
|
||||||
|
recipientScreenName = recipientScreenName.trim().toLowerCase()
|
||||||
|
|
||||||
|
# exclude already listed screen name
|
||||||
|
exclude = false
|
||||||
|
if body && body.toLowerCase().match(recipientScreenName)
|
||||||
|
exclude = true
|
||||||
|
|
||||||
|
# exclude own screen_name
|
||||||
|
if recipientScreenName is "@#{@ticket.preferences.channel_screen_name}".toLowerCase()
|
||||||
|
exclude = true
|
||||||
|
|
||||||
|
if exclude is false
|
||||||
|
if recipientString isnt ''
|
||||||
|
recipientString += ' '
|
||||||
|
recipientString += recipientScreenName
|
||||||
|
|
||||||
|
if body
|
||||||
|
articleNew.body = "#{recipientString} #{body} "
|
||||||
|
else
|
||||||
|
articleNew.body = "#{recipientString} "
|
||||||
|
|
||||||
|
App.Event.trigger('ui::ticket::setArticleType', {
|
||||||
|
ticket: ticket
|
||||||
|
type: type
|
||||||
|
article: articleNew
|
||||||
|
position: 'end'
|
||||||
|
})
|
||||||
|
|
||||||
|
@twitterDirectMessageReply: (ticket, article, ui) ->
|
||||||
|
|
||||||
|
# get reference article
|
||||||
|
type = App.TicketArticleType.find(article.type_id)
|
||||||
|
sender = App.TicketArticleSender.find(article.sender_id)
|
||||||
|
customer = App.User.find(article.created_by_id)
|
||||||
|
|
||||||
|
ui.scrollToCompose()
|
||||||
|
|
||||||
|
# empty form
|
||||||
|
articleNew = {
|
||||||
|
to: ''
|
||||||
|
cc: ''
|
||||||
|
body: ''
|
||||||
|
in_reply_to: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
if article.message_id
|
||||||
|
articleNew.in_reply_to = article.message_id
|
||||||
|
|
||||||
|
if sender.name is 'Agent'
|
||||||
|
articleNew.to = article.to
|
||||||
|
else
|
||||||
|
articleNew.to = article.from
|
||||||
|
|
||||||
|
if !articleNew.to
|
||||||
|
articleNew.to = customer.accounts['twitter'].username || customer.accounts['twitter'].uid
|
||||||
|
|
||||||
|
App.Event.trigger('ui::ticket::setArticleType', {
|
||||||
|
ticket: ticket
|
||||||
|
type: type
|
||||||
|
article: articleNew
|
||||||
|
})
|
||||||
|
|
||||||
|
App.Config.set('300-TwitterReply', TwitterReply, 'TicketZoomArticleAction')
|
|
@ -1,21 +1,13 @@
|
||||||
class App.TicketZoomArticleActions extends App.Controller
|
class App.TicketZoomArticleActions extends App.Controller
|
||||||
events:
|
events:
|
||||||
'click [data-type=public]': 'publicInternal'
|
'click .js-ArticleAction': 'actionPerform'
|
||||||
'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'
|
|
||||||
'click [data-type=facebookFeedReply]': 'facebookFeedReply'
|
|
||||||
'click [data-type=telegramPersonalMessageReply]': 'telegramPersonalMessageReply'
|
|
||||||
'click [data-type=delete]': 'delete'
|
|
||||||
|
|
||||||
constructor: ->
|
constructor: ->
|
||||||
super
|
super
|
||||||
@render()
|
@render()
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
actions = @actionRow(@article)
|
actions = @actionRow(@ticket, @article)
|
||||||
|
|
||||||
if actions
|
if actions
|
||||||
@html App.view('ticket_zoom/article_view_actions')(
|
@html App.view('ticket_zoom/article_view_actions')(
|
||||||
|
@ -25,371 +17,31 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||||
else
|
else
|
||||||
@html ''
|
@html ''
|
||||||
|
|
||||||
publicInternal: (e) =>
|
actionRow: (ticket, article) ->
|
||||||
e.preventDefault()
|
actionConfig = App.Config.get('TicketZoomArticleAction')
|
||||||
articleContainer = $(e.target).closest('.ticket-article-item')
|
keys = _.keys(actionConfig).sort()
|
||||||
article_id = $(e.target).parents('[data-id]').data('id')
|
|
||||||
|
|
||||||
# storage update
|
|
||||||
article = App.TicketArticle.find(article_id)
|
|
||||||
internal = true
|
|
||||||
if article.internal == true
|
|
||||||
internal = false
|
|
||||||
@lastAttributres.internal = internal
|
|
||||||
article.updateAttributes(internal: internal)
|
|
||||||
|
|
||||||
# runntime update
|
|
||||||
if internal
|
|
||||||
articleContainer.addClass('is-internal')
|
|
||||||
else
|
|
||||||
articleContainer.removeClass('is-internal')
|
|
||||||
|
|
||||||
@render()
|
|
||||||
|
|
||||||
actionRow: (article) ->
|
|
||||||
if @permissionCheck('ticket.customer')
|
|
||||||
return []
|
|
||||||
|
|
||||||
actions = []
|
actions = []
|
||||||
if article.internal is true
|
for key in keys
|
||||||
actions = [
|
config = actionConfig[key]
|
||||||
{
|
if config
|
||||||
name: 'set to public'
|
actions = config.action(actions, ticket, article, @)
|
||||||
type: 'public'
|
|
||||||
icon: 'lock-open'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
else
|
|
||||||
actions = [
|
|
||||||
{
|
|
||||||
name: 'set to internal'
|
|
||||||
type: 'internal'
|
|
||||||
icon: 'lock'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
#if @article.type.name is 'note'
|
|
||||||
# actions.push []
|
|
||||||
group = @ticket.group
|
|
||||||
if group.email_address_id && (article.type.name is 'email' || article.type.name is 'web')
|
|
||||||
actions.push {
|
|
||||||
name: 'reply'
|
|
||||||
type: 'emailReply'
|
|
||||||
icon: 'reply'
|
|
||||||
href: '#'
|
|
||||||
}
|
|
||||||
recipients = []
|
|
||||||
if article.sender.name is 'Customer'
|
|
||||||
if article.from
|
|
||||||
localRecipients = emailAddresses.parseAddressList(article.from)
|
|
||||||
if localRecipients
|
|
||||||
recipients = recipients.concat localRecipients
|
|
||||||
if article.to
|
|
||||||
localRecipients = emailAddresses.parseAddressList(article.to)
|
|
||||||
if localRecipients
|
|
||||||
recipients = recipients.concat localRecipients
|
|
||||||
if article.cc
|
|
||||||
localRecipients = emailAddresses.parseAddressList(article.cc)
|
|
||||||
if localRecipients
|
|
||||||
recipients = recipients.concat localRecipients
|
|
||||||
|
|
||||||
# remove system addresses
|
|
||||||
localAddresses = App.EmailAddress.all()
|
|
||||||
forgeinRecipients = []
|
|
||||||
recipientUsed = {}
|
|
||||||
for recipient in recipients
|
|
||||||
if !_.isEmpty(recipient.address)
|
|
||||||
localRecipientAddress = recipient.address.toString().toLowerCase()
|
|
||||||
if !recipientUsed[localRecipientAddress]
|
|
||||||
recipientUsed[localRecipientAddress] = true
|
|
||||||
localAddress = false
|
|
||||||
for address in localAddresses
|
|
||||||
if localRecipientAddress is address.email.toString().toLowerCase()
|
|
||||||
recipientUsed[localRecipientAddress] = true
|
|
||||||
localAddress = true
|
|
||||||
if !localAddress
|
|
||||||
forgeinRecipients.push recipient
|
|
||||||
|
|
||||||
# check if reply all is neede
|
|
||||||
if forgeinRecipients.length > 1
|
|
||||||
actions.push {
|
|
||||||
name: 'reply all'
|
|
||||||
type: 'emailReplyAll'
|
|
||||||
icon: 'reply-all'
|
|
||||||
href: '#'
|
|
||||||
}
|
|
||||||
if article.sender.name is 'Customer' && article.type.name is 'phone'
|
|
||||||
actions.push {
|
|
||||||
name: 'reply'
|
|
||||||
type: 'emailReply'
|
|
||||||
icon: 'reply'
|
|
||||||
href: '#'
|
|
||||||
}
|
|
||||||
if article.sender.name is 'Agent' && article.type.name is 'phone'
|
|
||||||
actions.push {
|
|
||||||
name: 'reply'
|
|
||||||
type: 'emailReply'
|
|
||||||
icon: 'reply'
|
|
||||||
href: '#'
|
|
||||||
}
|
|
||||||
if article.type.name is 'twitter status'
|
|
||||||
actions.push {
|
|
||||||
name: 'reply'
|
|
||||||
type: 'twitterStatusReply'
|
|
||||||
icon: 'reply'
|
|
||||||
href: '#'
|
|
||||||
}
|
|
||||||
if article.type.name is 'twitter direct-message'
|
|
||||||
actions.push {
|
|
||||||
name: 'reply'
|
|
||||||
type: 'twitterDirectMessageReply'
|
|
||||||
icon: 'reply'
|
|
||||||
href: '#'
|
|
||||||
}
|
|
||||||
if article.type.name is 'facebook feed post' || article.type.name is 'facebook feed comment'
|
|
||||||
actions.push {
|
|
||||||
name: 'reply'
|
|
||||||
type: 'facebookFeedReply'
|
|
||||||
icon: 'reply'
|
|
||||||
href: '#'
|
|
||||||
}
|
|
||||||
if article.sender.name is 'Customer' && article.type.name is 'telegram personal-message'
|
|
||||||
actions.push {
|
|
||||||
name: 'reply'
|
|
||||||
type: 'telegramPersonalMessageReply'
|
|
||||||
icon: 'reply'
|
|
||||||
href: '#'
|
|
||||||
}
|
|
||||||
|
|
||||||
actions.push {
|
|
||||||
name: 'split'
|
|
||||||
type: 'split'
|
|
||||||
icon: 'split'
|
|
||||||
href: '#ticket/create/' + article.ticket_id + '/' + article.id
|
|
||||||
}
|
|
||||||
|
|
||||||
if article.type.name is 'note'
|
|
||||||
user = undefined
|
|
||||||
if App.Session.get('id') == article.created_by_id
|
|
||||||
user = App.User.find(App.Session.get('id'))
|
|
||||||
if user.permission('ticket.agent')
|
|
||||||
actions.push {
|
|
||||||
name: 'delete'
|
|
||||||
type: 'delete'
|
|
||||||
icon: 'trash'
|
|
||||||
href: '#'
|
|
||||||
}
|
|
||||||
actions
|
actions
|
||||||
|
|
||||||
facebookFeedReply: (e) =>
|
actionPerform: (e) =>
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
type = App.TicketArticleType.findByAttribute('name', 'facebook feed comment')
|
articleContainer = $(e.target).closest('.ticket-article-item')
|
||||||
@scrollToCompose()
|
type = $(e.currentTarget).attr('data-type')
|
||||||
|
ticket = App.Ticket.fullLocal(@ticket.id)
|
||||||
|
article = App.TicketArticle.fullLocal(@article.id)
|
||||||
|
|
||||||
# empty form
|
actionConfig = App.Config.get('TicketZoomArticleAction')
|
||||||
articleNew = {
|
keys = _.keys(actionConfig).sort()
|
||||||
to: ''
|
actions = []
|
||||||
cc: ''
|
for key in keys
|
||||||
body: ''
|
config = actionConfig[key]
|
||||||
in_reply_to: ''
|
if config
|
||||||
}
|
return if !config.perform(articleContainer, type, ticket, article, @)
|
||||||
|
|
||||||
App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew } )
|
|
||||||
|
|
||||||
twitterStatusReply: (e) =>
|
|
||||||
e.preventDefault()
|
|
||||||
|
|
||||||
# get reference article
|
|
||||||
article_id = $(e.target).parents('[data-id]').data('id')
|
|
||||||
article = App.TicketArticle.fullLocal(article_id)
|
|
||||||
sender = App.TicketArticleSender.find(article.sender_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
|
|
||||||
|
|
||||||
# get current body
|
|
||||||
body = @el.closest('.ticketZoom').find('.article-add [data-name="body"]').html().trim() || ''
|
|
||||||
articleNew.body = body
|
|
||||||
|
|
||||||
recipients = article.from
|
|
||||||
if article.to
|
|
||||||
if recipients
|
|
||||||
recipients += ', '
|
|
||||||
recipients += article.to
|
|
||||||
|
|
||||||
if recipients
|
|
||||||
recipientString = ''
|
|
||||||
recipientScreenNames = recipients.split(',')
|
|
||||||
for recipientScreenName in recipientScreenNames
|
|
||||||
if recipientScreenName
|
|
||||||
recipientScreenName = recipientScreenName.trim().toLowerCase()
|
|
||||||
|
|
||||||
# exclude already listed screen name
|
|
||||||
exclude = false
|
|
||||||
if body && body.toLowerCase().match(recipientScreenName)
|
|
||||||
exclude = true
|
|
||||||
|
|
||||||
# exclude own screen_name
|
|
||||||
if recipientScreenName is "@#{@ticket.preferences.channel_screen_name}".toLowerCase()
|
|
||||||
exclude = true
|
|
||||||
|
|
||||||
if exclude is false
|
|
||||||
if recipientString isnt ''
|
|
||||||
recipientString += ' '
|
|
||||||
recipientString += recipientScreenName
|
|
||||||
|
|
||||||
if body
|
|
||||||
articleNew.body = "#{recipientString} #{body} "
|
|
||||||
else
|
|
||||||
articleNew.body = "#{recipientString} "
|
|
||||||
|
|
||||||
App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew, position: 'end' } )
|
|
||||||
|
|
||||||
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)
|
|
||||||
sender = App.TicketArticleSender.find(article.sender_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
|
|
||||||
|
|
||||||
if sender.name is 'Agent'
|
|
||||||
articleNew.to = article.to
|
|
||||||
else
|
|
||||||
articleNew.to = article.from
|
|
||||||
|
|
||||||
if !articleNew.to
|
|
||||||
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)
|
|
||||||
ticket = App.Ticket.fullLocal(article.ticket_id)
|
|
||||||
type = App.TicketArticleType.find(article.type_id)
|
|
||||||
article_created_by = App.User.find(article.created_by_id)
|
|
||||||
email_addresses = App.EmailAddress.all()
|
|
||||||
|
|
||||||
@scrollToCompose()
|
|
||||||
|
|
||||||
# empty form
|
|
||||||
articleNew = App.Utils.getRecipientArticle(ticket, article, article_created_by, type, email_addresses, all)
|
|
||||||
|
|
||||||
# get current body
|
|
||||||
body = @el.closest('.ticketZoom').find('.article-add [data-name="body"]').html() || ''
|
|
||||||
|
|
||||||
# check if quote need to be added
|
|
||||||
signaturePosition = 'bottom'
|
|
||||||
selected = App.ClipBoard.getSelected('html')
|
|
||||||
if selected
|
|
||||||
selected = App.Utils.htmlCleanup(selected).html()
|
|
||||||
if !selected
|
|
||||||
selected = App.ClipBoard.getSelected('text')
|
|
||||||
if selected
|
|
||||||
selected = App.Utils.textCleanup(selected)
|
|
||||||
selected = App.Utils.text2html(selected)
|
|
||||||
|
|
||||||
# full quote, if needed
|
|
||||||
if !selected && article && App.Config.get('ui_ticket_zoom_article_email_full_quote')
|
|
||||||
signaturePosition = 'top'
|
|
||||||
if article.content_type.match('html')
|
|
||||||
selected = App.Utils.textCleanup(article.body)
|
|
||||||
if article.content_type.match('plain')
|
|
||||||
selected = App.Utils.textCleanup(article.body)
|
|
||||||
selected = App.Utils.text2html(selected)
|
|
||||||
|
|
||||||
if selected
|
|
||||||
selected = "<div><br><br/></div><div><blockquote type=\"cite\">#{selected}</blockquote></div><div><br></div>"
|
|
||||||
|
|
||||||
# add selected text to body
|
|
||||||
body = selected + body
|
|
||||||
|
|
||||||
articleNew.body = body
|
|
||||||
|
|
||||||
type = App.TicketArticleType.findByAttribute(name:'email')
|
|
||||||
|
|
||||||
App.Event.trigger('ui::ticket::setArticleType', {
|
|
||||||
ticket: @ticket
|
|
||||||
type: type
|
|
||||||
article: articleNew
|
|
||||||
signaturePosition: signaturePosition
|
|
||||||
})
|
|
||||||
|
|
||||||
telegramPersonalMessageReply: (e) =>
|
|
||||||
e.preventDefault()
|
|
||||||
|
|
||||||
# get reference article
|
|
||||||
article_id = $(e.target).parents('[data-id]').data('id')
|
|
||||||
article = App.TicketArticle.fullLocal(article_id)
|
|
||||||
sender = App.TicketArticleSender.find(article.sender_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
|
|
||||||
|
|
||||||
# get current body
|
|
||||||
articleNew.body = @el.closest('.ticketZoom').find('.article-add [data-name="body"]').html().trim() || ''
|
|
||||||
|
|
||||||
App.Event.trigger('ui::ticket::setArticleType', { ticket: @ticket, type: type, article: articleNew, position: 'end' } )
|
|
||||||
|
|
||||||
delete: (e) =>
|
|
||||||
e.preventDefault()
|
|
||||||
|
|
||||||
callback = ->
|
|
||||||
article_id = $(e.target).parents('[data-id]').data('id')
|
|
||||||
article = App.TicketArticle.find(article_id)
|
|
||||||
article.destroy()
|
|
||||||
|
|
||||||
new App.ControllerConfirm(
|
|
||||||
message: 'Sure?'
|
|
||||||
callback: callback
|
|
||||||
container: @el.closest('.content')
|
|
||||||
)
|
|
||||||
|
|
||||||
scrollToCompose: =>
|
scrollToCompose: =>
|
||||||
@el.closest('.content').find('.article-add').ScrollTo()
|
@el.closest('.content').find('.article-add').ScrollTo()
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="article-content article-actions horizontal stretch">
|
<div class="article-content article-actions horizontal stretch">
|
||||||
<% for action in @actions: %>
|
<% for action in @actions: %>
|
||||||
<a href="<%= action.href %>" data-type="<%= action.type %>" class="article-action u-clickable<% if action.class: %> <%= action.class %><% end %>">
|
<a href="<%= action.href %>" data-type="<%= action.type %>" class="article-action js-ArticleAction u-clickable<% if action.class: %> <%= action.class %><% end %>">
|
||||||
<%- @Icon(action.icon, 'article-action-icon') %><%- @T( action.name ) %>
|
<%- @Icon(action.icon, 'article-action-icon') %><%- @T(action.name) %>
|
||||||
</a>
|
</a>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
Loading…
Reference in a new issue