Added generic use of all X-headers. Improved ui for postmaster filter.

This commit is contained in:
Martin Edenhofer 2014-06-08 05:11:21 +02:00
parent eb48ac0e4f
commit d436872bc7
4 changed files with 187 additions and 54 deletions

View file

@ -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 = $("<div>#{ App.i18n.translateInline(displayName) }: <input name=\"#{ key }\" type=\"input\" value=\"#{ defaultValue }\" class=\"form-control\" required/><a href=\"#\" class=\"glyphicon glyphicon-minus remove\"></a></div>")
add = { name: key, display: displayName, tag: 'input', null: false, default: defaultValue }
itemInput = $( @formGenItem( add ).append('<a href=\"#\" class=\"glyphicon glyphicon-minus remove\"></a>' ) )
# 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 = $('
<div class="postmaster_match" style="margin-left: 40px;">
<div class="postmaster_match">
<hr>
<div class="list"></div>
<hr>
<div>
@ -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 = $("<div>#{ App.i18n.translateInline(displayName) }: <input name=\"#{ key }\" type=\"input\" value=\"#{ defaultValue }\" class=\"form-control\"/><a href=\"#\" class=\"glyphicon glyphicon-minus remove\"></a></div>")
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('<a href=\"#\" class=\"glyphicon glyphicon-minus remove\"></a>' ) )
# 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 = $('
<div class="perform_set" style="margin-left: 40px;">
<div class="perform_set">
<hr>
<div class="list"></div>
<hr>
<div>
@ -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) ->

View file

@ -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,16 +456,52 @@ 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)

View file

@ -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('<hr><h1>form postmaster filter</h1><form id="form5"></form>')
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' );

View file

@ -2,7 +2,7 @@
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