diff --git a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee index 96a048597..9e6aebc5d 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_form.js.coffee @@ -258,25 +258,29 @@ class App.ControllerForm extends App.Controller # postmaster_match else if attribute.tag is 'postmaster_match' addItem = (key, displayName, el, defaultValue = '') => - itemInput = $("
#{ App.i18n.translateInline(displayName) }:
") + add = { name: key, display: displayName, tag: 'input', null: false, default: defaultValue } + itemInput = $( @formGenItem( add ).append('' ) ) # remove on click itemInput.find('.remove').bind('click', (e) -> e.preventDefault() - key = $(e.target).prev().attr('name') + key = $(e.target).parent().find('select, input').attr('name') return if !key $(e.target).parent().parent().parent().find('.addSelection select option[value="' + key + '"]').show() - $(e.target).parent().parent().parent().find('.list [name="' + key + '"]').parent().remove() + $(e.target).parent().parent().parent().find('.addSelection select option[value="' + key + '"]').prop('disabled', false) + $(e.target).parent().parent().parent().find('.list [name="' + key + '"]').parent().parent().remove() ) # add new item el.parent().parent().parent().find('.list').append(itemInput) el.parent().parent().parent().find('.addSelection select').val('') + el.parent().parent().parent().find('.addSelection select option[value="' + key + '"]').prop('disabled', true) el.parent().parent().parent().find('.addSelection select option[value="' + key + '"]').hide() # scaffold of match elements item = $(' -
+
+

@@ -408,7 +412,7 @@ class App.ControllerForm extends App.Controller ] for listItem in loopData listItem.value = "#{ attribute.name }::#{listItem.value}" - add = { name: '', display: '', tag: 'select', multiple: false, null: false, nulloption: true, options: loopData, translate: true } + add = { name: '', display: '', tag: 'select', multiple: false, null: false, nulloption: true, options: loopData, translate: true, required: false } item.find('.addSelection').append( @formGenItem( add ) ) # bind add click @@ -432,25 +436,39 @@ class App.ControllerForm extends App.Controller # postmaster_set else if attribute.tag is 'postmaster_set' addItem = (key, displayName, el, defaultValue = '') => - itemInput = $("
#{ App.i18n.translateInline(displayName) }:
") + collection = undefined + for listItem in loopData + if listItem.value is key + collection = listItem + if collection.relation + add = { name: key, display: displayName, tag: 'select', multiple: false, null: false, nulloption: true, relation: collection.relation, translate: true, default: defaultValue } + else if collection.options + add = { name: key, display: displayName, tag: 'select', multiple: false, null: false, nulloption: true, options: collection.options, translate: true, default: defaultValue } + else + add = { name: key, display: displayName, tag: 'input', null: false, default: defaultValue } + itemInput = $( @formGenItem( add ).append('' ) ) # remove on click itemInput.find('.remove').bind('click', (e) -> e.preventDefault() - key = $(e.target).prev().attr('name') + key = $(e.target).parent().find('select, input').attr('name') return if !key $(e.target).parent().parent().parent().find('.addSelection select option[value="' + key + '"]').show() - $(e.target).parent().parent().parent().find('.list [name="' + key + '"]').parent().remove() + $(e.target).parent().parent().parent().find('.addSelection select option[value="' + key + '"]').prop('disabled', false) + $(e.target).parent().parent().parent().find('.list [name="' + key + '"]').parent().parent().remove() ) # add new item + console.log(1111222, key, el, el.parent().parent().parent().find('.addSelection select')) el.parent().parent().parent().find('.list').append(itemInput) el.parent().parent().parent().find('.addSelection select').val('') + el.parent().parent().parent().find('.addSelection select option[value="' + key + '"]').prop('disabled', true) el.parent().parent().parent().find('.addSelection select option[value="' + key + '"]').hide() # scaffold of perform elements item = $(' -
+
+

@@ -463,20 +481,23 @@ class App.ControllerForm extends App.Controller # select shown attributes loopData = [ { - value: 'x-zammad-ticket-priority' + value: 'x-zammad-ticket-ticket_priority_id' name: 'Ticket Priority' + relation: 'TicketPriority' }, { - value: 'x-zammad-ticket-state' + value: 'x-zammad-ticket-ticket_state_id' name: 'Ticket State' + relation: 'TicketState' }, { value: 'x-zammad-ticket-customer' name: 'Ticket Customer' }, { - value: 'x-zammad-ticket-group' + value: 'x-zammad-ticket-group_id' name: 'Ticket Group' + relation: 'Group' }, { value: 'x-zammad-ticket-owner' @@ -488,16 +509,18 @@ class App.ControllerForm extends App.Controller disable: true }, { - value: 'x-zammad-article-visibility' - name: 'Article Visibility' + value: 'x-zammad-article-ticket_article_internal' + name: 'Article Internal' }, { - value: 'x-zammad-article-type' + value: 'x-zammad-article-ticket_article_type_id' name: 'Article Type' + relation: 'TicketArticleType' }, { - value: 'x-zammad-article-sender' + value: 'x-zammad-article-ticket_article_sender_id' name: 'Article Sender' + relation: 'TicketArticleSender' }, { value: '' @@ -507,11 +530,12 @@ class App.ControllerForm extends App.Controller { value: 'x-zammad-ignore' name: 'Ignore Message' + options: { true: 'Yes', false: 'No'} }, ] for listItem in loopData listItem.value = "#{ attribute.name }::#{listItem.value}" - add = { name: '', display: '', tag: 'select', multiple: false, null: false, nulloption: true, options: loopData, translate: true } + add = { name: '', display: '', tag: 'select', multiple: false, null: false, nulloption: true, options: loopData, translate: true, required: false } item.find('.addSelection').append( @formGenItem( add ) ) item.find('.add').bind('click', (e) -> diff --git a/app/models/channel/email_parser.rb b/app/models/channel/email_parser.rb index 174793566..f47427ab9 100644 --- a/app/models/channel/email_parser.rb +++ b/app/models/channel/email_parser.rb @@ -371,25 +371,18 @@ class Channel::EmailParser if !ticket # set attributes - ticket_attributes = { + ticket = Ticket.new( :group_id => channel[:group_id] || 1, :customer_id => user.id, :title => mail[:subject] || '', :ticket_state_id => Ticket::State.where( :name => 'new' ).first.id, :ticket_priority_id => Ticket::Priority.where( :name => '2 normal' ).first.id, - } + ) - # x-headers lookup - map = [ - [ 'x-zammad-ticket-group', Group, 'group_id', 'name' ], - [ 'x-zammad-ticket-state', Ticket::State, 'ticket_state_id', 'name' ], - [ 'x-zammad-ticket-priority', Ticket::Priority, 'ticket_priority_id', 'name' ], - [ 'x-zammad-ticket-owner', User, 'owner_id', 'login' ], - ] - object_lookup( ticket_attributes, map, mail ) + object_lookup( ticket, 'ticket', mail ) # create ticket - ticket = Ticket.create( ticket_attributes ) + ticket.save end # import mail @@ -399,7 +392,7 @@ class Channel::EmailParser if mail[ 'X-Zammad-Article-Visibility'.to_sym ] && mail[ 'X-Zammad-Article-Visibility'.to_sym ] == 'internal' internal = true end - article_attributes = { + article = Ticket::Article.new( :ticket_id => ticket.id, :ticket_article_type_id => Ticket::Article::Type.where( :name => 'email' ).first.id, :ticket_article_sender_id => Ticket::Article::Sender.where( :name => 'Customer' ).first.id, @@ -410,17 +403,13 @@ class Channel::EmailParser :subject => mail[:subject], :message_id => mail[:message_id], :internal => internal, - } + ) # x-headers lookup - map = [ - [ 'x-zammad-article-type', Ticket::Article::Type, 'ticket_article_type_id', 'name' ], - [ 'x-zammad-article-sender', Ticket::Article::Sender, 'ticket_article_sender_id', 'name' ], - ] - object_lookup( article_attributes, map, mail ) + object_lookup( article, 'article', mail ) # create article - article = Ticket::Article.create(article_attributes) + article.save # store mail plain Store.add( @@ -467,15 +456,51 @@ class Channel::EmailParser return ticket, article, user end - def object_lookup( attributes, map, mail ) - map.each { |item| - if mail[ item[0].to_sym ] - new_object = item[1].where( "lower(#{item[3]}) = ?", mail[ item[0].to_sym ].downcase ).first - if new_object - attributes[ item[2].to_sym ] = new_object.id + def object_lookup( item_object, header_name, mail ) + + # loop all x-zammad-hedaer-* headers + item_object.attributes.each{|key,value| + + # ignore read only attributes + next if key == 'updated_at' + next if key == 'created_at' + next if key == 'updated_by_id' + next if key == 'created_by_id' + + # check if id exists + key_short = key[ key.length-3 , key.length ] + if key_short == '_id' + key_short = key[ 0, key.length-3 ] + header = "x-zammad-#{header_name}-#{key_short}" + if mail[ header.to_sym ] + puts "NOTICE: header #{header} found #{mail[ header.to_sym ]}" + item_object.class.reflect_on_all_associations.map { |assoc| + if assoc.name.to_s == key_short + puts "NOTICE: ASSOC found #{assoc.class_name} lookup #{mail[ header.to_sym ]}" + 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 + 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 + end + end + end + } end end + + # check if attribute exists + header = "x-zammad-#{header_name}-#{key}" + if mail[ header.to_sym ] + puts "NOTICE: header #{header} found #{mail[ header.to_sym ]}" + item_object[key] = mail[ header.to_sym ] + end } + end def html2ascii(string) diff --git a/public/assets/tests/form.js b/public/assets/tests/form.js index bb756f177..7d3b7b7ab 100644 --- a/public/assets/tests/form.js +++ b/public/assets/tests/form.js @@ -376,6 +376,26 @@ test( "form postmaster filter", function() { // add match rule // add set rule + App.TicketPriority.refresh( [ + { + id: 1, + name: 'prio 1', + }, + { + id: 2, + name: 'prio 2', + }, + ] ) + App.Group.refresh( [ + { + id: 1, + name: 'group 1', + }, + { + id: 2, + name: 'group 2', + }, + ] ) $('#forms').append('

form postmaster filter

') var el = $('#form5') @@ -386,8 +406,10 @@ test( "form postmaster filter", function() { subject: 'some subject', }, set: { - 'x-zammad-ticket-priority': '3 high', - 'x-zammad-ticket-group': 'some group', + 'x-zammad-ticket-owner': 'owner', + 'x-zammad-ticket-customer': 'customer', + 'x-zammad-ticket-ticket_priority_id': 2, + 'x-zammad-ticket-group_id': 1, }, } new App.ControllerForm({ @@ -411,12 +433,15 @@ test( "form postmaster filter", function() { subject: 'some subject', }, set: { - 'x-zammad-ticket-priority': '3 high', - 'x-zammad-ticket-group': 'some group', + 'x-zammad-ticket-owner': 'owner', + 'x-zammad-ticket-customer': 'customer', + 'x-zammad-ticket-ticket_priority_id': "2", + 'x-zammad-ticket-group_id': "1", }, }; deepEqual( params, test_params, 'form param check' ); - el.find('[name="set::x-zammad-ticket-priority"]').next().click() + el.find('[name="set::x-zammad-ticket-ticket_priority_id"]').parent().next().click() + el.find('[name="set::x-zammad-ticket-customer"]').parent().next().click() App.Delay.set( function() { test( "form param check after remove click", function() { params = App.ControllerForm.params( el ) @@ -428,7 +453,8 @@ test( "form postmaster filter", function() { subject: 'some subject', }, set: { - 'x-zammad-ticket-group': 'some group', + 'x-zammad-ticket-owner': 'owner', + 'x-zammad-ticket-group_id': "1", }, }; deepEqual( params, test_params, 'form param check' ); diff --git a/test/unit/email_process_test.rb b/test/unit/email_process_test.rb index 71a3704b4..8e4f6f1cf 100644 --- a/test/unit/email_process_test.rb +++ b/test/unit/email_process_test.rb @@ -1,8 +1,8 @@ # encoding: utf-8 require 'test_helper' - + class EmailProcessTest < ActiveSupport::TestCase - test 'process' do + test 'process trusted' do files = [ { :data => 'From: me@example.com @@ -25,9 +25,10 @@ Some Text', :data => 'From: me@example.com To: customer@example.com Subject: some subject -X-Zammad-Ticket-Priority: 3 high -X-Zammad-Article-Sender: system -x-Zammad-Article-Type: phone +X-Zammad-Ticket-Ticket_Priority: 3 high +X-Zammad-Article-Ticket_Article_Sender: System +x-Zammad-Article-Ticket_Article_Type: phone +x-Zammad-Article-Internal: true Some Text', :success => true, @@ -39,6 +40,7 @@ Some Text', 1 => { :ticket_article_sender => 'System', :ticket_article_type => 'phone', + :internal => true, }, }, }, @@ -58,6 +60,7 @@ Some Textäöü", :body => 'Some Textäöü', :ticket_article_sender => 'Customer', :ticket_article_type => 'email', + :internal => false, }, }, }, @@ -77,6 +80,7 @@ Some Textäöü".encode("ISO-8859-1"), :body => 'Some Textäöü', :ticket_article_sender => 'Customer', :ticket_article_type => 'email', + :internal => false, }, }, }, @@ -168,7 +172,61 @@ Some Text", if result[level].send(key).respond_to?('name') assert_equal( result[level].send(key).name, value.to_s) else - assert_equal( result[level].send(key), value.to_s) + assert_equal( result[level].send(key), value) + end + } + end + } + end + elsif !file[:success] && result == true + assert( true ) + elsif !file[:success] && result[1] + assert( false, 'ticket should not be created' ) + else + assert( false, 'UNKNOWN!' ) + end + } + end + + test 'process not trusted' do + files = [ + { + :data => 'From: me@example.com +To: customer@example.com +Subject: some subject +X-Zammad-Ticket-Ticket_Priority: 3 high +X-Zammad-Article-Ticket_Article_Sender: System +x-Zammad-Article-Ticket_Article_Type: phone +x-Zammad-Article-Internal: true + +Some Text', + :success => true, + :result => { + 0 => { + :ticket_priority => '2 normal', + :title => 'some subject', + }, + 1 => { + :ticket_article_sender => 'Customer', + :ticket_article_type => 'email', + :internal => false, + }, + }, + }, + ] + files.each { |file| + parser = Channel::EmailParser.new + result = parser.process( { :trusted => false }, file[:data] ) + if file[:success] && result[1] + assert( true ) + if file[:result] + [ 0, 1, 2 ].each { |level| + if file[:result][level] + file[:result][level].each { |key, value| + if result[level].send(key).respond_to?('name') + assert_equal( result[level].send(key).name, value.to_s) + else + assert_equal( result[level].send(key), value) end } end