diff --git a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee
index 62262e123..5347ddd79 100644
--- a/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee
+++ b/app/assets/javascripts/app/controllers/agent_ticket_create.js.coffee
@@ -3,10 +3,10 @@ class App.TicketCreate extends App.Controller
'.tabsSidebar' : 'sidebar'
events:
- 'click .type-tabs .tab': 'changeFormType'
- 'submit form': 'submit'
- 'click .submit': 'submit'
- 'click .cancel': 'cancel'
+ 'click .type-tabs .tab': 'changeFormType'
+ 'submit form': 'submit'
+ 'click .submit': 'submit'
+ 'click .cancel': 'cancel'
constructor: (params) ->
super
@@ -87,6 +87,9 @@ class App.TicketCreate extends App.Controller
# update form
@el.find('[name="formSenderType"]').val(type)
+ # force changing signature
+ @el.find('[name="group_id"]').trigger('change')
+
meta: =>
text = ''
if @articleAttributes
@@ -167,10 +170,10 @@ class App.TicketCreate extends App.Controller
a = App.TicketArticle.find( params.article_id )
# reset owner
- t.owner_id = 0
- t.customer_id_autocompletion = a.from
- t.subject = a.subject || t.title
- t.body = a.body
+ t.owner_id = 0
+ t.customer_id_completion = a.from
+ t.subject = a.subject || t.title
+ t.body = a.body
# render page
@render( options: t )
@@ -191,10 +194,10 @@ class App.TicketCreate extends App.Controller
@form_id = App.ControllerForm.formId()
@html App.view('agent_ticket_create')(
- head: 'New Ticket'
- agent: @isRole('Agent')
- admin: @isRole('Admin')
- form_id: @form_id
+ head: 'New Ticket'
+ agent: @isRole('Agent')
+ admin: @isRole('Admin')
+ form_id: @form_id
)
formChanges = (params, attribute, attributes, classname, form, ui) =>
@@ -220,6 +223,44 @@ class App.TicketCreate extends App.Controller
# replace new option list
form.find('[name="' + fieldNameToChange + '"]').closest('.form-group').replaceWith( newElement )
+ signatureChanges = (params, attribute, attributes, classname, form, ui) =>
+ if attribute && attribute.name is 'group_id'
+ signature = undefined
+ if params['group_id']
+ group = App.Group.find( params['group_id'] )
+ if group && group.signature_id
+ signature = App.Signature.find( group.signature_id )
+
+ # check if signature need to be added
+ type = @$('[name="formSenderType"]').val()
+
+ if signature isnt undefined && signature.body && type is 'email-out'
+ signatureFinished = App.Utils.text2html(
+ App.Utils.replaceTags( signature.body, { user: App.Session.get() } )
+ )
+
+ # get current body
+ body = @$('[data-name="body"]').html() || ''
+ if App.Utils.signatureCheck( body, signatureFinished )
+
+ # if signature has changed, replace it
+ signature_id = @$('[data-signature=true]').data('signature-id')
+ if signature_id && signature_id.toString() isnt signature.id.toString()
+
+ # remove old signature
+ @$('[data-signature="true"]').remove()
+ body = @$('[data-name="body"]').html() || ''
+
+ if !App.Utils.lastLineEmpty(body)
+ body = body + '
'
+ body = body + "
#{signatureFinished}
"
+
+ @$('[data-name="body"]').html(body)
+
+ # remove old signature
+ else
+ @$('[data-name="body"]').find('[data-signature=true]').remove()
+
new App.ControllerForm(
el: @el.find('.ticket-form-top')
form_id: @form_id
@@ -228,7 +269,8 @@ class App.TicketCreate extends App.Controller
events:
'change [name=customer_id]': @localUserInfo
handlers: [
- formChanges
+ formChanges,
+ signatureChanges,
]
filter: @form_meta.filter
autofocus: true
@@ -236,21 +278,22 @@ class App.TicketCreate extends App.Controller
)
new App.ControllerForm(
- el: @el.find('.article-form-top')
- form_id: @form_id
- model: App.TicketArticle
- screen: 'create_top'
- params: params
+ el: @el.find('.article-form-top')
+ form_id: @form_id
+ model: App.TicketArticle
+ screen: 'create_top'
+ params: params
)
new App.ControllerForm(
- el: @el.find('.ticket-form-middle')
- form_id: @form_id
- model: App.Ticket
- screen: 'create_middle'
+ el: @el.find('.ticket-form-middle')
+ form_id: @form_id
+ model: App.Ticket
+ screen: 'create_middle'
events:
'change [name=customer_id]': @localUserInfo
handlers: [
- formChanges
+ formChanges,
+ signatureChanges,
]
filter: @form_meta.filter
params: params
@@ -264,7 +307,8 @@ class App.TicketCreate extends App.Controller
events:
'change [name=customer_id]': @localUserInfo
handlers: [
- formChanges
+ formChanges,
+ signatureChanges,
]
filter: @form_meta.filter
params: params
@@ -330,7 +374,7 @@ class App.TicketCreate extends App.Controller
if sender.name is 'Customer'
params['article'] = {
to: (group && group.name) || ''
- from: params.customer_id_autocompletion
+ from: params.customer_id_completion
cc: params.cc
subject: params.subject
body: params.body
@@ -342,7 +386,7 @@ class App.TicketCreate extends App.Controller
else
params['article'] = {
from: (group && group.name) || ''
- to: params.customer_id_autocompletion
+ to: params.customer_id_completion
cc: params.cc
subject: params.subject
body: params.body
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee
index 85f897f11..c4e523d1c 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom.js.coffee
@@ -18,10 +18,9 @@ class App.TicketZoom extends App.Controller
@navupdate '#'
- @form_meta = undefined
- @ticket_id = params.ticket_id
- @article_id = params.article_id
- @signature = undefined
+ @form_meta = undefined
+ @ticket_id = params.ticket_id
+ @article_id = params.article_id
@key = 'ticket::' + @ticket_id
cache = App.Store.get( @key )
@@ -137,9 +136,6 @@ class App.TicketZoom extends App.Controller
# get edit form attributes
@form_meta = data.form_meta
- # get signature
- @signature = data.signature
-
# load assets
App.Collection.loadAssets( data.assets )
@@ -860,14 +856,15 @@ class Edit extends App.Controller
if data.ticket.id is @ticket.id
#@setArticleType(data.type.name)
- # preselect article type
- @setArticleType( 'email' )
@open_textarea(null, true)
for key, value of data.article
if key is 'body'
@$('[data-name="' + key + '"]').html(value)
else
@$('[name="' + key + '"]').val(value)
+
+ # preselect article type
+ @setArticleType( 'email' )
)
isIE10: ->
@@ -905,7 +902,7 @@ class Edit extends App.Controller
@$('[data-name="body"]').ce({
mode: 'richtext'
multiline: true
- maxlength: 2500
+ maxlength: 5000
})
html5Upload.initialize(
@@ -1075,10 +1072,29 @@ class Edit extends App.Controller
# show/hide attributes
for articleType in @articleTypes
if articleType.name is type
- @$(".form-group").addClass('hide')
+ @$('.form-group').addClass('hide')
for name in articleType.attributes
@$("[name=#{name}]").closest('.form-group').removeClass('hide')
+ # check if signature need to be added
+ body = @$('[data-name="body"]').html() || ''
+ signature = undefined
+ if @ticket.group.signature_id
+ signature = App.Signature.find( @ticket.group.signature_id )
+ if signature && signature.body && @type is 'email'
+ signatureFinished = App.Utils.text2html(
+ App.Utils.replaceTags( signature.body, { user: App.Session.get(), ticket: @ticket } )
+ )
+ if App.Utils.signatureCheck( body, signatureFinished )
+ if !App.Utils.lastLineEmpty(body)
+ body = body + '
'
+ body = body + "#{signatureFinished}
"
+ @$('[data-name="body"]').html(body)
+
+ # remove old signature
+ else
+ @$('[data-name="body"]').find("[data-signature=true]").remove()
+
detect_empty_textarea: =>
if !@textarea.text().trim()
@add_textarea_catcher()
@@ -1246,7 +1262,7 @@ class ArticleView extends App.Controller
'click .show_toogle': 'show_toogle'
'click [data-type=reply]': 'reply'
'click [data-type=replyAll]': 'replyAll'
- 'click .text-bubble': 'toggle_meta'
+ 'click .text-bubble': 'toggle_meta_with_delay'
'click .text-bubble a': 'stopPropagation'
constructor: ->
@@ -1311,7 +1327,17 @@ class ArticleView extends App.Controller
stopPropagation: (e) ->
e.stopPropagation()
- toggle_meta: (e) ->
+ toggle_meta_with_delay: (e) =>
+ # allow double click select
+ # by adding a delay to the toggle
+
+ if @lastClick and +new Date - @lastClick < 150
+ clearTimeout(@toggleMetaTimeout)
+ else
+ @toggleMetaTimeout = setTimeout(@toggle_meta, 150, e)
+ @lastClick = +new Date
+
+ toggle_meta: (e) =>
e.preventDefault()
animSpeed = 300
@@ -1488,12 +1514,6 @@ class ArticleView extends App.Controller
# get current body
body = @ui.el.find('[data-name="body"]').html() || ''
- # check if signature need to be added
- if @ui.signature && @ui.signature.body && type.name is 'email'
- signature = App.Utils.text2html( @ui.signature.body )
- if App.Utils.signatureCheck( body, signature )
- body = body + signature
-
# check if quote need to be added
selectedText = App.ClipBoard.getSelected()
if selectedText
diff --git a/app/assets/javascripts/app/lib/app_post/utils.js.coffee b/app/assets/javascripts/app/lib/app_post/utils.js.coffee
index 5f576a74f..6690bf4e7 100644
--- a/app/assets/javascripts/app/lib/app_post/utils.js.coffee
+++ b/app/assets/javascripts/app/lib/app_post/utils.js.coffee
@@ -166,3 +166,27 @@ class App.Utils
else
true
+ # textReplaced = App.Utils.replaceTags( template, { user: { firstname: 'Bob', lastname: 'Smith' } } )
+ @replaceTags: (template, objects) ->
+ template = template.replace( /#\{\s{0,2}(.+?)\s{0,2}\}/g, ( index, key ) ->
+ levels = key.split(/\./)
+ dataRef = objects
+ for level in levels
+ if dataRef[level]
+ dataRef = dataRef[level]
+ if typeof dataRef is 'function'
+ value = dataRef()
+ else if typeof dataRef is 'string'
+ value = dataRef
+ else
+ value = ''
+ #console.log( "tag replacement #{key}, #{value} env: ", objects)
+ value
+ )
+
+ # true|false = App.Utils.lastLineEmpty( message )
+ @lastLineEmpty: (message) ->
+ messageCleanup = message.replace(/>\s+<').replace(/(\n|\r|\t)/g, '').trim()
+ return true if messageCleanup.match(/<(br|\s+?|\/)>$/im)
+ return true if messageCleanup.match(/<\/div>$/im)
+ false
diff --git a/app/assets/stylesheets/zammad.css.scss b/app/assets/stylesheets/zammad.css.scss
index ccb71dbb5..992376e41 100644
--- a/app/assets/stylesheets/zammad.css.scss
+++ b/app/assets/stylesheets/zammad.css.scss
@@ -2041,10 +2041,6 @@ footer {
text-decoration: none;
}
- .task .modified.priority.icon {
- margin-right: 8px;
- }
-
.task.active {
background: #389ed9;
}
@@ -2106,7 +2102,7 @@ footer {
.level-3 .modified.priority.icon:after {
background-color: #faab00;
border-color: #faab00;
- }
+ }
.task .closeTask {
position: absolute;
diff --git a/app/controllers/long_polling_controller.rb b/app/controllers/long_polling_controller.rb
index 5512175e8..fa5a99b6b 100644
--- a/app/controllers/long_polling_controller.rb
+++ b/app/controllers/long_polling_controller.rb
@@ -59,7 +59,7 @@ class LongPollingController < ApplicationController
user_id = session[:user_id]
user = {}
if user_id
- user = User.find( user_id )
+ user = User.find( user_id ).attributes
end
log 'notice', "send auth login (user_id #{user_id})", client_id
Sessions.create( client_id, user, { :type => 'ajax' } )
diff --git a/app/controllers/tickets_controller.rb b/app/controllers/tickets_controller.rb
index 696181dbd..b8fc5b27b 100644
--- a/app/controllers/tickets_controller.rb
+++ b/app/controllers/tickets_controller.rb
@@ -228,22 +228,6 @@ class TicketsController < ApplicationController
ticket = Ticket.find( params[:id] )
return if !ticket_permission( ticket )
- # get signature
- signature = {}
- if ticket.group.signature
- signature = ticket.group.signature.attributes
-
- # replace tags
- signature['body'] = NotificationFactory.build(
- :locale => current_user.preferences[:locale],
- :string => signature['body'],
- :objects => {
- :ticket => ticket,
- :user => current_user,
- }
- )
- end
-
# get attributes to update
attributes_to_change = Ticket::ScreenOptions.attributes_to_change( :user => current_user, :ticket => ticket )
@@ -292,7 +276,6 @@ class TicketsController < ApplicationController
render :json => {
:ticket_id => ticket.id,
:ticket_article_ids => article_ids,
- :signature => signature,
:assets => assets,
:links => link_list,
:tags => tags,
diff --git a/lib/sessions.rb b/lib/sessions.rb
index 7d299ee7e..0962312d9 100644
--- a/lib/sessions.rb
+++ b/lib/sessions.rb
@@ -37,7 +37,7 @@ returns
:user => session,
:meta => meta,
}
- file.write Marshal.dump(data)
+ file.write data.to_json
}
# send update to browser
@@ -195,7 +195,7 @@ returns
path = @path + '/' + client_id.to_s
data[:meta][:last_ping] = Time.new.to_i.to_s
File.open( path + '/session', 'wb' ) { |file|
- file.write Marshal.dump(data)
+ file.write data.to_json
}
true
end
@@ -234,7 +234,11 @@ returns
file.flock( File::LOCK_EX )
all = file.read
file.flock( File::LOCK_UN )
- data = Marshal.load( all )
+ dataJSON = JSON.parse( all )
+ if dataJSON
+ data = self.symbolize_keys(dataJSON)
+ data[:user] = dataJSON['user'] # for compat. reasons
+ end
}
rescue Exception => e
puts e.inspect
@@ -567,4 +571,19 @@ returns
puts "/LOOP #{client_id} - #{try_count}"
end
-end
+ def self.symbolize_keys(hash)
+ hash.inject({}){|result, (key, value)|
+ new_key = case key
+ when String then key.to_sym
+ else key
+ end
+ new_value = case value
+ when Hash then symbolize_keys(value)
+ else value
+ end
+ result[new_key] = new_value
+ result
+ }
+ end
+
+end
\ No newline at end of file
diff --git a/public/assets/images/sprite.svg b/public/assets/images/sprite.svg
index 992dec70f..654d819c3 100644
--- a/public/assets/images/sprite.svg
+++ b/public/assets/images/sprite.svg
@@ -48,11 +48,11 @@
-
-
-
-
-
+
+
+
+
+
diff --git a/public/assets/tests/html-utils.js b/public/assets/tests/html-utils.js
index 392e7febb..fff291fe2 100644
--- a/public/assets/tests/html-utils.js
+++ b/public/assets/tests/html-utils.js
@@ -439,4 +439,92 @@ test( "check signature", function() {
});
+// replace tags
+test( "check replace tags", function() {
+
+ var message = "#{user.firstname} #{user.lastname}
"
+ var result = 'Bob Smith
'
+ var data = {
+ user: {
+ firstname: 'Bob',
+ lastname: 'Smith',
+ },
+ }
+ var verify = App.Utils.replaceTags( message, data )
+ equal( verify, result )
+
+ message = "#{user.firstname} #{user.lastname}
"
+ result = 'Bob Smith
'
+ data = {
+ user: {
+ firstname: function() { return 'Bob' },
+ lastname: function() { return 'Smith' },
+ },
+ }
+ verify = App.Utils.replaceTags( message, data )
+ equal( verify, result )
+
+ message = "#{user.firstname} #{user.lastname}
"
+ result = 'Bob
'
+ data = {
+ user: {
+ firstname: 'Bob',
+ },
+ }
+ verify = App.Utils.replaceTags( message, data )
+ equal( verify, result )
+
+});
+
+// check if last line is a empty line
+test( "check if last line is a empty line", function() {
+
+ var message = "123"
+ var result = false
+ var verify = App.Utils.lastLineEmpty( message )
+ equal( verify, result, message )
+
+ message = "123
"
+ result = false
+ verify = App.Utils.lastLineEmpty( message )
+ equal( verify, result, message )
+
+ message = "123
"
+ result = false
+ verify = App.Utils.lastLineEmpty( message )
+ equal( verify, result, message )
+
+ message = ""
+ result = true
+ verify = App.Utils.lastLineEmpty( message )
+ equal( verify, result, message )
+
+ message = ""
+ result = true
+ verify = App.Utils.lastLineEmpty( message )
+ equal( verify, result, message )
+
+ message = " "
+ result = true
+ verify = App.Utils.lastLineEmpty( message )
+ equal( verify, result, message )
+
+ message = " \n \n\t"
+ result = true
+ verify = App.Utils.lastLineEmpty( message )
+ equal( verify, result, message )
+
+ message = "
\n \n\t"
+ result = true
+ verify = App.Utils.lastLineEmpty( message )
+ equal( verify, result, message )
+
+ message = " \n
\n \n\t"
+ result = true
+ verify = App.Utils.lastLineEmpty( message )
+ equal( verify, result, message )
+
+
+});
+
}
\ No newline at end of file
diff --git a/script/websocket-server.rb b/script/websocket-server.rb
index 7d784c31d..749261950 100755
--- a/script/websocket-server.rb
+++ b/script/websocket-server.rb
@@ -295,7 +295,7 @@ EventMachine.run {
idle_time_in_min = 4
- # web sockets
+ # close unused web socket sessions
@clients.each { |client_id, client|
if ( client[:last_ping] + ( 60 * idle_time_in_min ) ) < Time.now
log 'notice', "closing idle websocket connection", client_id
@@ -312,10 +312,10 @@ EventMachine.run {
end
}
- # close unused sessions
+ # close unused ajax long polling sessions
clients = Sessions.destory_idle_sessions(idle_time_in_min)
clients.each { |client_id|
- log 'notice', "closing idle connection", client_id
+ log 'notice', "closing idle long polling connection", client_id
}
end
@@ -327,4 +327,4 @@ EventMachine.run {
# puts "#{Time.now}:#{ level }:client(#{ client_id }) #{ data }"
end
-}
+}
\ No newline at end of file
diff --git a/test/unit/email_process_test.rb b/test/unit/email_process_test.rb
index 9bead59fb..4cd6a3072 100644
--- a/test/unit/email_process_test.rb
+++ b/test/unit/email_process_test.rb
@@ -2050,6 +2050,28 @@ Some Text',
},
},
},
+ {
+ :data => 'From: Some Body
+To: Bob
+Cc: any@example.com
+Subject: some subject
+
+Some Text',
+ :trusted => false,
+ :success => true,
+ :result => {
+ 0 => {
+ :group => group2.name,
+ :priority => '2 normal',
+ :title => 'some subject',
+ },
+ 1 => {
+ :sender => 'Customer',
+ :type => 'email',
+ :internal => true,
+ },
+ },
+ },
]
process(files)
PostmasterFilter.destroy_all