diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
index f233d2bb2..4845d1e98 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
@@ -1,15 +1,18 @@
class EmailReply extends App.Controller
@action: (actions, ticket, article, ui) ->
- return actions if ui.permissionCheck('ticket.customer')
-
+ return actions if !ui.permissionCheck('ticket.agent')
group = ticket.group
- if group.email_address_id && (article.type.name is 'email' || article.type.name is 'web')
+ return actions if !group.email_address_id
+
+ if article.type.name is 'email' || article.type.name is 'web'
actions.push {
name: 'reply'
type: 'emailReply'
icon: 'reply'
href: '#'
}
+
+ # check if reply all need to be shown
recipients = []
if article.sender.name is 'Customer'
if article.from
@@ -51,6 +54,7 @@ class EmailReply extends App.Controller
href: '#'
}
+ # always show forward
actions.push {
name: 'forward'
type: 'emailForward'
@@ -113,6 +117,12 @@ class EmailReply extends App.Controller
# empty form
articleNew = App.Utils.getRecipientArticle(ticket, article, article_created_by, type, email_addresses, all)
+ if ui.Config.get('ui_ticket_zoom_article_email_subject')
+ if _.isEmpty(article.subject)
+ articleNew.subject = ticket.title
+ else
+ articleNew.subject = article.subject
+
# get current body
body = ui.el.closest('.ticketZoom').find('.article-add [data-name="body"]').html() || ''
@@ -172,6 +182,12 @@ class EmailReply extends App.Controller
articleNew = {}
articleNew.body = body
+ if ui.Config.get('ui_ticket_zoom_article_email_subject')
+ if _.isEmpty(article.subject)
+ articleNew.subject = "FW: #{ticket.title}"
+ else
+ articleNew.subject = "FW: #{article.subject}"
+
type = App.TicketArticleType.findByAttribute(name:'email')
App.Event.trigger('ui::ticket::setArticleType', {
@@ -200,4 +216,100 @@ class EmailReply extends App.Controller
true
+ @articleTypes: (articleTypes, ticket, ui) ->
+ return articleTypes if !ui.permissionCheck('ticket.agent')
+ group = ticket.group
+ return articleTypes if !group.email_address_id
+
+ attributes = ['to', 'cc', 'subject']
+ if !ui.Config.get('ui_ticket_zoom_article_email_subject')
+ attributes = ['to', 'cc']
+ articleTypes.push {
+ name: 'email'
+ icon: 'email'
+ attributes: attributes
+ internal: false,
+ features: ['attachment']
+ }
+
+ articleTypes
+
+ @setArticleType: (type, ticket, ui, signaturePosition) ->
+
+ # detect current signature (use current group_id, if not set, use ticket.group_id)
+ ticketCurrent = App.Ticket.fullLocal(ticket.id)
+ group_id = ticketCurrent.group_id
+ task = App.TaskManager.get(ui.taskKey)
+ if task && task.state && task.state.ticket && task.state.ticket.group_id
+ group_id = task.state.ticket.group_id
+ group = App.Group.find(group_id)
+ signature = undefined
+ if group && group.signature_id
+ signature = App.Signature.find(group.signature_id)
+
+ # add/replace signature
+ if signature && signature.body && type is 'email'
+
+ # if signature has changed, remove it
+ signature_id = ui.$('[data-signature=true]').data('signature-id')
+ if signature_id && signature_id.toString() isnt signature.id.toString()
+ ui.$('[data-name=body] [data-signature="true"]').remove()
+
+ # apply new signature
+ signatureFinished = App.Utils.replaceTags(signature.body, { user: App.Session.get(), ticket: ticketCurrent, config: App.Config.all() })
+
+ body = ui.$('[data-name=body]')
+ if App.Utils.signatureCheck(body.html() || '', signatureFinished)
+ if !App.Utils.htmlLastLineEmpty(body)
+ body.append('
')
+ signature = $("
#{signatureFinished}
")
+ App.Utils.htmlStrip(signature)
+ if signaturePosition is 'top'
+ body.prepend(signature)
+ else
+ body.append(signature)
+ ui.$('[data-name=body]').replaceWith(body)
+
+ # remove old signature
+ else
+ ui.$('[data-name=body] [data-signature=true]').remove()
+
+ if type isnt 'email'
+ ui.$('[name=to]').val('')
+ ui.$('[name=cc]').val('')
+ ui.$('[name=subject]').val('')
+
+ @validation: (type, params, ui) ->
+ return true if type isnt 'email'
+
+ # check if recipient exists
+ if _.isEmpty(params.to) && _.isEmpty(params.cc)
+ new App.ControllerModal(
+ head: 'Text missing'
+ buttonCancel: 'Cancel'
+ buttonCancelClass: 'btn--danger'
+ buttonSubmit: false
+ message: 'Need recipient in "To" or "Cc".'
+ shown: true
+ small: true
+ container: ui.el.closest('.content')
+ )
+ return false
+
+ # check if message exists
+ if _.isEmpty(params.body)
+ new App.ControllerModal(
+ head: 'Text missing'
+ buttonCancel: 'Cancel'
+ buttonCancelClass: 'btn--danger'
+ buttonSubmit: false
+ message: 'Text needed'
+ shown: true
+ small: true
+ container: ui.el.closest('.content')
+ )
+ return false
+
+ true
+
App.Config.set('200-EmailReply', EmailReply, 'TicketZoomArticleAction')
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/facebook_reply.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/facebook_reply.coffee
index 41c9ad4e8..e5cfc598d 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/facebook_reply.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/facebook_reply.coffee
@@ -34,4 +34,28 @@ class FacebookReply
true
+ @articleTypes: (articleTypes, ticket, ui) ->
+ return articleTypes if !ui.permissionCheck('ticket.agent')
+
+ return articleTypes if !ticket || !ticket.create_article_type_id
+
+ articleTypeCreate = App.TicketArticleType.find(ticket.create_article_type_id).name
+ if articleTypeCreate is 'facebook feed post'
+ articleTypes.push {
+ name: 'facebook feed comment'
+ icon: 'facebook'
+ attributes: []
+ internal: false,
+ features: []
+ }
+ articleTypes
+
+ @params: (type, params, ui) ->
+ if type is 'facebook feed comment'
+ App.Utils.htmlRemoveRichtext(ui.$('[data-name=body]'), false)
+ params.content_type = 'text/plain'
+ params.body = App.Utils.html2text(params.body, true)
+
+ params
+
App.Config.set('300-FacebookReply', FacebookReply, 'TicketZoomArticleAction')
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/note.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/note.coffee
new file mode 100644
index 000000000..e5b775056
--- /dev/null
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/note.coffee
@@ -0,0 +1,23 @@
+class Note
+ @action: (actions, ticket, article, ui) ->
+ actions
+
+ @perform: (articleContainer, type, ticket, article, ui) ->
+ true
+
+ @articleTypes: (articleTypes, ticket, ui) ->
+ internal = false
+ if ui.permissionCheck('ticket.agent')
+ internal = ui.Config.get('ui_ticket_zoom_article_note_new_internal')
+
+ articleTypes.push {
+ name: 'note'
+ icon: 'note'
+ attributes: []
+ internal: internal,
+ features: ['attachment']
+ }
+
+ articleTypes
+
+App.Config.set('100-Note', Note, 'TicketZoomArticleAction')
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/phone_reply.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/phone_reply.coffee
new file mode 100644
index 000000000..b2f35e2fd
--- /dev/null
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/phone_reply.coffee
@@ -0,0 +1,19 @@
+class PhoneReply
+ @action: (actions, ticket, article, ui) ->
+ actions
+
+ @perform: (articleContainer, type, ticket, article, ui) ->
+ true
+
+ @articleTypes: (articleTypes, ticket, ui) ->
+ return articleTypes if !ui.permissionCheck('ticket.agent')
+ articleTypes.push {
+ name: 'phone'
+ icon: 'phone'
+ attributes: []
+ internal: false,
+ features: ['attachment']
+ }
+ articleTypes
+
+App.Config.set('100-PhoneReply', PhoneReply, 'TicketZoomArticleAction')
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/telegram.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/telegram.coffee
index 6f18a172d..edba450f8 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/telegram.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/telegram.coffee
@@ -42,4 +42,38 @@ class TelegramReply
true
+ @articleTypes: (articleTypes, ticket, ui) ->
+ return articleTypes if !ui.permissionCheck('ticket.agent')
+
+ return articleTypes if !ticket || !ticket.create_article_type_id
+
+ articleTypeCreate = App.TicketArticleType.find(ticket.create_article_type_id).name
+
+ return articleTypes if articleTypeCreate isnt 'telegram personal-message'
+ articleTypes.push {
+ name: 'telegram personal-message'
+ icon: 'telegram'
+ attributes: []
+ internal: false,
+ features: ['attachment']
+ maxTextLength: 10000
+ warningTextLength: 5000
+ }
+ articleTypes
+
+ @setArticleType: (type, ticket, ui) ->
+ return if type isnt 'telegram personal-message'
+ rawHTML = ui.$('[data-name=body]').html()
+ cleanHTML = App.Utils.htmlRemoveRichtext(rawHTML)
+ if cleanHTML && cleanHTML.html() != rawHTML
+ ui.$('[data-name=body]').html(cleanHTML)
+
+ @params: (type, params, ui) ->
+ if type is 'telegram personal-message'
+ App.Utils.htmlRemoveRichtext(ui.$('[data-name=body]'), false)
+ params.content_type = 'text/plain'
+ params.body = App.Utils.html2text(params.body, true)
+
+ params
+
App.Config.set('300-TelegramReply', TelegramReply, 'TicketZoomArticleAction')
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/twitter_reply.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/twitter_reply.coffee
index 6ce871868..1a39dd606 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/twitter_reply.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/twitter_reply.coffee
@@ -125,4 +125,70 @@ class TwitterReply
article: articleNew
})
+ @articleTypes: (articleTypes, ticket, ui) ->
+ return articleTypes if !ui.permissionCheck('ticket.agent')
+
+ return articleTypes if !ticket || !ticket.create_article_type_id
+
+ articleTypeCreate = App.TicketArticleType.find(ticket.create_article_type_id).name
+ if articleTypeCreate is 'twitter status'
+ attributes = ['body:limit', 'body:initials']
+ if !ui.Config.get('ui_ticket_zoom_article_twitter_initials')
+ attributes = ['body:limit']
+ articleTypes.push {
+ name: 'twitter status'
+ icon: 'twitter'
+ attributes: []
+ internal: false,
+ features: attributes
+ maxTextLength: 280
+ warningTextLength: 30
+ }
+ else if articleTypeCreate is 'twitter direct-message'
+ attributes = ['body:limit', 'body:initials']
+ if !ui.Config.get('ui_ticket_zoom_article_twitter_initials')
+ attributes = ['body:limit']
+ articleTypes.push {
+ name: 'twitter direct-message'
+ icon: 'twitter'
+ attributes: ['to']
+ internal: false,
+ features: attributes
+ maxTextLength: 10000
+ warningTextLength: 500
+ }
+
+ articleTypes
+
+ @validation: (type, params, ui) ->
+ if type is 'twitter status'
+ textLength = ui.maxTextLength - App.Utils.textLengthWithUrl(params.body)
+ return false if textLength < 0
+
+ if params.type is 'twitter direct-message'
+ textLength = ui.maxTextLength - App.Utils.textLengthWithUrl(params.body)
+ return false if textLength < 0
+
+ true
+
+ @setArticleType: (type, ticket, ui) ->
+ return if type isnt 'twitter status' && type isnt 'twitter direct-message'
+ rawHTML = ui.$('[data-name=body]').html()
+ cleanHTML = App.Utils.htmlRemoveRichtext(rawHTML)
+ if cleanHTML && cleanHTML.html() != rawHTML
+ ui.$('[data-name=body]').html(cleanHTML)
+
+ @params: (type, params, ui) ->
+ if type is 'twitter status'
+ App.Utils.htmlRemoveRichtext(ui.$('[data-name=body]'), false)
+ params.content_type = 'text/plain'
+ params.body = App.Utils.html2text(params.body, true)
+
+ if type is 'twitter direct-message'
+ App.Utils.htmlRemoveRichtext(ui.$('[data-name=body]'), false)
+ params.content_type = 'text/plain'
+ params.body = App.Utils.html2text(params.body, true)
+
+ params
+
App.Config.set('300-TwitterReply', TwitterReply, 'TicketZoomArticleAction')
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 2795d7e46..9c0b3d070 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_new.coffee
@@ -92,112 +92,13 @@ class App.TicketZoomArticleNew extends App.Controller
)
setPossibleArticleTypes: =>
- possibleArticleType =
- note: true
- phone: true
- if @ticket && @ticket.create_article_type_id
- articleTypeCreate = App.TicketArticleType.find(@ticket.create_article_type_id).name
- if articleTypeCreate is 'twitter status'
- possibleArticleType['twitter status'] = true
- else if articleTypeCreate is 'twitter direct-message'
- possibleArticleType['twitter direct-message'] = true
- else if articleTypeCreate is 'email'
- possibleArticleType['email'] = true
- else if articleTypeCreate is 'facebook feed post'
- possibleArticleType['facebook feed comment'] = true
- else if articleTypeCreate is 'telegram personal-message'
- possibleArticleType['telegram personal-message'] = true
- if @ticket && @ticket.customer_id
- customer = App.User.find(@ticket.customer_id)
- if customer.email
- possibleArticleType['email'] = true
-
- # gets referenced in @setArticleType
+ actionConfig = App.Config.get('TicketZoomArticleAction')
+ keys = _.keys(actionConfig).sort()
@articleTypes = []
- if possibleArticleType.note
- internal = @Config.get('ui_ticket_zoom_article_note_new_internal')
- @articleTypes.push {
- name: 'note'
- icon: 'note'
- attributes: []
- internal: internal,
- features: ['attachment']
- }
- if possibleArticleType.email
- attributes = ['to', 'cc', 'subject']
- if !@Config.get('ui_ticket_zoom_article_email_subject')
- attributes = ['to', 'cc']
- @articleTypes.push {
- name: 'email'
- icon: 'email'
- attributes: attributes
- internal: false,
- features: ['attachment']
- }
- if possibleArticleType['facebook feed comment']
- @articleTypes.push {
- name: 'facebook feed comment'
- icon: 'facebook'
- attributes: []
- internal: false,
- features: []
- }
- if possibleArticleType['twitter status']
- attributes = ['body:limit', 'body:initials']
- if !@Config.get('ui_ticket_zoom_article_twitter_initials')
- attributes = ['body:limit']
- @articleTypes.push {
- name: 'twitter status'
- icon: 'twitter'
- attributes: []
- internal: false,
- features: attributes
- maxTextLength: 280
- warningTextLength: 30
- }
- if possibleArticleType['twitter direct-message']
- attributes = ['body:limit', 'body:initials']
- if !@Config.get('ui_ticket_zoom_article_twitter_initials')
- attributes = ['body:limit']
- @articleTypes.push {
- name: 'twitter direct-message'
- icon: 'twitter'
- attributes: ['to']
- internal: false,
- features: attributes
- maxTextLength: 10000
- warningTextLength: 500
- }
- if possibleArticleType.phone
- @articleTypes.push {
- name: 'phone'
- icon: 'phone'
- attributes: []
- internal: false,
- features: ['attachment']
- }
- if possibleArticleType['telegram personal-message']
- @articleTypes.push {
- name: 'telegram personal-message'
- icon: 'telegram'
- attributes: []
- internal: false,
- features: ['attachment']
- maxTextLength: 10000
- warningTextLength: 5000
- }
-
- if @permissionCheck('ticket.customer')
- @type = 'note'
- @articleTypes = [
- {
- name: 'note'
- icon: 'note'
- attributes: []
- internal: false,
- features: ['attachment']
- },
- ]
+ for key in keys
+ config = actionConfig[key]
+ if config && config.articleTypes
+ @articleTypes = config.articleTypes(@articleTypes, @ticket, @)
placeCaretAtEnd: (el) ->
el.focus()
@@ -356,25 +257,13 @@ class App.TicketZoomArticleNew extends App.Controller
else
params.internal = false
- if params.type is 'twitter status'
- App.Utils.htmlRemoveRichtext(@$('[data-name=body]'), false)
- params.content_type = 'text/plain'
- params.body = App.Utils.html2text(params.body, true)
-
- if params.type is 'twitter direct-message'
- App.Utils.htmlRemoveRichtext(@$('[data-name=body]'), false)
- params.content_type = 'text/plain'
- params.body = App.Utils.html2text(params.body, true)
-
- if params.type is 'facebook feed comment'
- App.Utils.htmlRemoveRichtext(@$('[data-name=body]'), false)
- params.content_type = 'text/plain'
- params.body = App.Utils.html2text(params.body, true)
-
- if params.type is 'telegram personal-message'
- App.Utils.htmlRemoveRichtext(@$('[data-name=body]'), false)
- params.content_type = 'text/plain'
- params.body = App.Utils.html2text(params.body, true)
+ # backend based validation
+ actionConfig = App.Config.get('TicketZoomArticleAction')
+ keys = _.keys(actionConfig).sort()
+ for key in keys
+ config = actionConfig[key]
+ if config && config.params
+ params = config.params(params.type, params, @)
# add initals?
for articleType in @articleTypes
@@ -406,37 +295,6 @@ class App.TicketZoomArticleNew extends App.Controller
)
return false
- # validate email params
- if params.type is 'email'
-
- # check if recipient exists
- if !params.to && !params.cc
- new App.ControllerModal(
- head: 'Text missing'
- buttonCancel: 'Cancel'
- buttonCancelClass: 'btn--danger'
- buttonSubmit: false
- message: 'Need recipient in "To" or "Cc".'
- shown: true
- small: true
- container: @el.closest('.content')
- )
- return false
-
- # check if message exists
- if !params.body
- new App.ControllerModal(
- head: 'Text missing'
- buttonCancel: 'Cancel'
- buttonCancelClass: 'btn--danger'
- buttonSubmit: false
- message: 'Text needed'
- shown: true
- small: true
- container: @el.closest('.content')
- )
- return false
-
# check attachment
if params.body && attachmentCount < 1
matchingWord = App.Utils.checkAttachmentReference(params.body)
@@ -444,13 +302,13 @@ class App.TicketZoomArticleNew extends App.Controller
if !confirm(App.i18n.translateContent('You use %s in text but no attachment is attached. Do you want to continue?', matchingWord))
return false
- if params.type is 'twitter status'
- textLength = @maxTextLength - App.Utils.textLengthWithUrl(params.body)
- return false if textLength < 0
-
- if params.type is 'twitter direct-message'
- textLength = @maxTextLength - App.Utils.textLengthWithUrl(params.body)
- return false if textLength < 0
+ # backend based validation
+ actionConfig = App.Config.get('TicketZoomArticleAction')
+ keys = _.keys(actionConfig).sort()
+ for key in keys
+ config = actionConfig[key]
+ if config && config.validation
+ return false if !config.validation(params.type, params, @)
true
@@ -516,50 +374,12 @@ class App.TicketZoomArticleNew extends App.Controller
else
@setArticleInternal(false)
- # detect current signature (use current group_id, if not set, use ticket.group_id)
- ticketCurrent = App.Ticket.fullLocal(@ticket_id)
- group_id = ticketCurrent.group_id
- task = App.TaskManager.get(@taskKey)
- if task && task.state && task.state.ticket && task.state.ticket.group_id
- group_id = task.state.ticket.group_id
- group = App.Group.find(group_id)
- signature = undefined
- if group && group.signature_id
- signature = App.Signature.find(group.signature_id)
-
- # add/replace signature
- if signature && signature.body && @type is 'email'
-
- # if signature has changed, remove it
- signature_id = @$('[data-signature=true]').data('signature-id')
- if signature_id && signature_id.toString() isnt signature.id.toString()
- @$('[data-name=body] [data-signature="true"]').remove()
-
- # apply new signature
- signatureFinished = App.Utils.replaceTags(signature.body, { user: App.Session.get(), ticket: ticketCurrent, config: App.Config.all() })
-
- body = @$('[data-name=body]')
- if App.Utils.signatureCheck(body.html() || '', signatureFinished)
- if !App.Utils.htmlLastLineEmpty(body)
- body.append('
')
- signature = $("#{signatureFinished}
")
- App.Utils.htmlStrip(signature)
- if signaturePosition is 'top'
- body.prepend(signature)
- else
- body.append(signature)
- @$('[data-name=body]').replaceWith(body)
-
- # remove old signature
- else
- @$('[data-name=body] [data-signature=true]').remove()
-
- # remove richtext
- if @type is 'twitter status' || @type is 'twitter direct-message' || @type is 'telegram personal-message'
- rawHTML = @$('[data-name=body]').html()
- cleanHTML = App.Utils.htmlRemoveRichtext(rawHTML)
- if cleanHTML && cleanHTML.html() != rawHTML
- @$('[data-name=body]').html(cleanHTML)
+ actionConfig = App.Config.get('TicketZoomArticleAction')
+ keys = _.keys(actionConfig).sort()
+ for key in keys
+ localConfig = actionConfig[key]
+ if localConfig && localConfig.setArticleType
+ localConfig.setArticleType(@type, @ticket, @, signaturePosition)
# show/hide attributes/features
@maxTextLength = undefined