Added has changed filter to triggers.

This commit is contained in:
Martin Edenhofer 2016-07-16 23:43:08 +02:00
parent 0da7a322f9
commit e2bb6cce56
13 changed files with 402 additions and 28 deletions

View file

@ -24,10 +24,23 @@ class App.UiElement.ticket_selector
'^input$': ['contains', 'contains not'] '^input$': ['contains', 'contains not']
'^textarea$': ['contains', 'contains not'] '^textarea$': ['contains', 'contains not']
if attribute.hasChanged
operators_type =
'^datetime$': ['before (absolute)', 'after (absolute)', 'before (relative)', 'within next (relative)', 'within last (relative)', 'after (relative)', 'has changed']
'^timestamp$': ['before (absolute)', 'after (absolute)', 'before (relative)', 'within next (relative)', 'within last (relative)', 'after (relative)', 'has changed']
'boolean$': ['is', 'is not', 'has changed']
'^input$': ['contains', 'contains not', 'has changed']
'^textarea$': ['contains', 'contains not', 'has changed']
operators_name = operators_name =
'_id$': ['is', 'is not'] '_id$': ['is', 'is not']
'_ids$': ['is', 'is not'] '_ids$': ['is', 'is not']
if attribute.hasChanged
operators_name =
'_id$': ['is', 'is not', 'has changed']
'_ids$': ['is', 'is not', 'has changed']
# merge config # merge config
elements = {} elements = {}
@ -37,9 +50,10 @@ class App.UiElement.ticket_selector
display: 'Action' display: 'Action'
tag: 'select' tag: 'select'
null: false null: false
translate: true
options: options:
create: 'Created' create: 'created'
update: 'Updated' update: 'updated'
operator: ['is', 'is not'] operator: ['is', 'is not']
for groupKey, groupMeta of groups for groupKey, groupMeta of groups
@ -226,18 +240,34 @@ class App.UiElement.ticket_selector
@buildOperator: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) -> @buildOperator: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) ->
currentOperator = elementRow.find('.js-operator option:selected').attr('value') currentOperator = elementRow.find('.js-operator option:selected').attr('value')
if !meta.operator
meta.operator = currentOperator
name = "#{attribute.name}::#{groupAndAttribute}::operator" name = "#{attribute.name}::#{groupAndAttribute}::operator"
if !meta.operator && currentOperator
meta.operator = currentOperator
selection = $("<select class=\"form-control\" name=\"#{name}\"></select>") selection = $("<select class=\"form-control\" name=\"#{name}\"></select>")
attributeConfig = elements[groupAndAttribute] attributeConfig = elements[groupAndAttribute]
if attributeConfig.operator if attributeConfig.operator
# check if operator exists
operatorExists = false
for operator in attributeConfig.operator
if meta.operator is operator
operatorExists = true
break
if !operatorExists
for operator in attributeConfig.operator
meta.operator = operator
break
for operator in attributeConfig.operator for operator in attributeConfig.operator
operatorName = App.i18n.translateInline(operator) operatorName = App.i18n.translateInline(operator)
selected = '' selected = ''
if !groupAndAttribute.match(/^ticket/) && operator is 'has changed'
# do nothing, only show "has changed" in ticket attributes
else
if meta.operator is operator if meta.operator is operator
selected = 'selected="selected"' selected = 'selected="selected"'
selection.append("<option value=\"#{operator}\" #{selected}>#{operatorName}</option>") selection.append("<option value=\"#{operator}\" #{selected}>#{operatorName}</option>")
@ -355,6 +385,11 @@ class App.UiElement.ticket_selector
item = App.UiElement['time_range'].render(config, {}) item = App.UiElement['time_range'].render(config, {})
elementRow.find('.js-value').removeClass('hide').html(item) elementRow.find('.js-value').removeClass('hide').html(item)
if meta.operator is 'has changed'
elementRow.find('.js-value').addClass('hide')
elementRow.find('.js-preCondition').addClass('hide')
else
elementRow.find('.js-value').removeClass('hide')
@humanText: (condition) -> @humanText: (condition) ->
none = App.i18n.translateContent('No filter.') none = App.i18n.translateContent('No filter.')

View file

@ -590,6 +590,10 @@ class App.Model extends Spine.Model
[ array of objects ] [ array of objects ]
examples:
list = App.Model.search({sortBy:'updated_at', order:'DESC'})
### ###
@search: (params) -> @search: (params) ->

View file

@ -4,7 +4,7 @@ class App.Trigger extends App.Model
@url: @apiPath + '/triggers' @url: @apiPath + '/triggers'
@configure_attributes = [ @configure_attributes = [
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false }, { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
{ name: 'condition', display: 'Conditions for effected objects', tag: 'ticket_selector', null: false, preview: false, action: true }, { name: 'condition', display: 'Conditions for effected objects', tag: 'ticket_selector', null: false, preview: false, action: true, hasChanged: true },
{ name: 'perform', display: 'Execute changes on objects', tag: 'ticket_perform_action', null: true, notification: true }, { name: 'perform', display: 'Execute changes on objects', tag: 'ticket_perform_action', null: true, notification: true },
{ name: 'active', display: 'Active', tag: 'active', default: true }, { name: 'active', display: 'Active', tag: 'active', default: true },
{ name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 }, { name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },

View file

@ -76,6 +76,8 @@ returns
subject = subject[ 0, ticket_subject_size.to_i ] + '[...]' subject = subject[ 0, ticket_subject_size.to_i ] + '[...]'
end end
subject.gsub!(/^[[:space:]]+/, '')
subject.gsub!(/[[:space:]]+$/, '')
subject subject
end end
end end

View file

@ -12,7 +12,8 @@ class Transaction::BackgroundJob
changes: { changes: {
'attribute1' => [before,now], 'attribute1' => [before,now],
'attribute2' => [before,now], 'attribute2' => [before,now],
} },
created_at: Time.zone.now,
user_id: 123, user_id: 123,
}, },
=end =end

View file

@ -10,7 +10,8 @@ class Transaction::ClearbitEnrichment
changes: { changes: {
'attribute1' => [before, now], 'attribute1' => [before, now],
'attribute2' => [before, now], 'attribute2' => [before, now],
} },
created_at: Time.zone.now,
user_id: 123, user_id: 123,
}, },
=end =end

View file

@ -10,6 +10,7 @@ class Transaction::CtiCallerIdDetection
object_id: 123, object_id: 123,
via_web: true, via_web: true,
user_id: 123, user_id: 123,
created_at: Time.zone.now,
}, },
{ {
object: 'User', object: 'User',
@ -20,6 +21,7 @@ class Transaction::CtiCallerIdDetection
'attribute1' => [before, now], 'attribute1' => [before, now],
'attribute2' => [before, now], 'attribute2' => [before, now],
} }
created_at: Time.zone.now,
user_id: 123, user_id: 123,
}, },
=end =end

View file

@ -11,7 +11,8 @@ class Transaction::Notification
changes: { changes: {
'attribute1' => [before, now], 'attribute1' => [before, now],
'attribute2' => [before, now], 'attribute2' => [before, now],
} },
created_at: Time.zone.now,
user_id: 123, user_id: 123,
}, },
=end =end

View file

@ -12,7 +12,8 @@ class Transaction::SignatureDetection
changes: { changes: {
'attribute1' => [before, now], 'attribute1' => [before, now],
'attribute2' => [before, now], 'attribute2' => [before, now],
} },
created_at: Time.zone.now,
user_id: 123, user_id: 123,
}, },
=end =end

View file

@ -8,6 +8,7 @@ backend = Transaction::Slack.new(
type: 'create', type: 'create',
object_id: 1, object_id: 1,
user_id: 123, user_id: 123,
created_at: Time.zone.now,
) )
backend.perform backend.perform
@ -19,7 +20,8 @@ backend.perform
changes: { changes: {
'attribute1' => [before, now], 'attribute1' => [before, now],
'attribute2' => [before, now], 'attribute2' => [before, now],
} },
created_at: Time.zone.now,
user_id: 123, user_id: 123,
}, },
=end =end

View file

@ -11,7 +11,8 @@ class Transaction::Trigger
changes: { changes: {
'attribute1' => [before, now], 'attribute1' => [before, now],
'attribute2' => [before, now], 'attribute2' => [before, now],
} },
created_at: Time.zone.now,
user_id: 123, user_id: 123,
}, },
=end =end
@ -49,28 +50,30 @@ class Transaction::Trigger
next if condition['ticket.action']['operator'] != 'is' && condition['ticket.action']['value'] == @item[:type] next if condition['ticket.action']['operator'] != 'is' && condition['ticket.action']['value'] == @item[:type]
condition.delete('ticket.action') condition.delete('ticket.action')
end end
=begin
# check "has changed" options # check "has changed" options
has_changed = true has_changed_condition_exists = false
trigger.condition.each do |key, value| has_changed = false
condition.each do |key, value|
next if !value next if !value
next if !value['operator'] next if !value['operator']
next if !value['operator']['has changed'] next if !value['operator']['has changed']
has_changed_condition_exists = true
# next if has changed? && !@item[:changes][attribute] # next if has changed? && !@item[:changes][attribute]
(object_name, attribute) = key.split('.', 2) (object_name, attribute) = key.split('.', 2)
# remove condition item, because it has changed # remove condition item, because it has changed
if @item[:changes][attribute] if @item[:changes][attribute]
#condition.delete(key) has_changed = true
condition.delete(key)
next next
end end
has_changed = false
break break
#{"ticket.state_id"=>{"operator"=>"has changed"
end end
next if !has_changed
=end next if has_changed_condition_exists && !has_changed
# check if selector is matching # check if selector is matching
condition['ticket.id'] = { condition['ticket.id'] = {
operator: 'is', operator: 'is',
@ -99,6 +102,9 @@ class Transaction::Trigger
# check in min one attribute has changed # check in min one attribute has changed
if @item[:type] == 'update' && !article_selector if @item[:type] == 'update' && !article_selector
match = false match = false
if has_changed_condition_exists && has_changed
match = true
else
trigger.condition.each do |key, _value| trigger.condition.each do |key, _value|
(object_name, attribute) = key.split('.', 2) (object_name, attribute) = key.split('.', 2)
next if object_name != 'ticket' next if object_name != 'ticket'
@ -106,6 +112,7 @@ class Transaction::Trigger
match = true match = true
break break
end end
end
next if !match next if !match
end end

View file

@ -278,6 +278,8 @@ class TicketTest < ActiveSupport::TestCase
assert_equal('subject test 1', ticket1.title) assert_equal('subject test 1', ticket1.title)
assert_equal("ABC subject test 1 [Ticket##{ticket1.number}]", ticket1.subject_build('ABC subject test 1')) assert_equal("ABC subject test 1 [Ticket##{ticket1.number}]", ticket1.subject_build('ABC subject test 1'))
assert_equal("RE: ABC subject test 1 [Ticket##{ticket1.number}]", ticket1.subject_build('ABC subject test 1', true)) assert_equal("RE: ABC subject test 1 [Ticket##{ticket1.number}]", ticket1.subject_build('ABC subject test 1', true))
assert_equal("RE: ABC subject test 1 [Ticket##{ticket1.number}]", ticket1.subject_build(' ABC subject test 1', true))
assert_equal("RE: ABC subject test 1 [Ticket##{ticket1.number}]", ticket1.subject_build('ABC subject test 1 ', true))
ticket1.destroy ticket1.destroy
end end

View file

@ -614,4 +614,320 @@ class TicketTriggerTest < ActiveSupport::TestCase
Trigger.destroy_all Trigger.destroy_all
end end
test '4 has changed' do
roles = Role.where(name: 'Customer')
customer1 = User.create_or_update(
login: 'postmaster@example.com',
firstname: 'Notification',
lastname: 'Customer1',
email: 'postmaster@example.com',
password: 'customerpw',
active: true,
roles: roles,
updated_at: '2015-02-05 16:37:00',
updated_by_id: 1,
created_by_id: 1,
)
customer2 = User.create_or_update(
login: 'ticket-has-changed-customer2@example.com',
firstname: 'Notification',
lastname: 'Customer2',
email: 'ticket-has-changed-customer2@example.com',
password: 'customerpw',
active: true,
organization_id: nil,
roles: roles,
updated_at: '2015-02-05 16:37:00',
updated_by_id: 1,
created_by_id: 1,
)
roles = Role.where(name: 'Agent')
agent1 = User.create_or_update(
login: 'agent-has-changed@example.com',
firstname: 'Has Changed',
lastname: 'Agent1',
email: 'agent-has-changed@example.com',
password: 'agentpw',
active: true,
roles: roles,
updated_at: '2015-02-05 16:37:00',
updated_by_id: 1,
created_by_id: 1,
)
trigger1 = Trigger.create_or_update(
name: 'owner update - to customer',
condition: {
'ticket.owner_id' => {
'operator' => 'has changed',
'pre_condition' => 'current_user.id',
'value' => '',
'value_completion' => '',
}
},
perform: {
'notification.email' => {
'body' => '<p>The owner of ticket (Ticket##{ticket.number}) has changed.<p>
<br/>
<p>To provide additional information, please reply to this email or click on the following link:
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}">#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}</a>
</p>
<br/>
<p><i><a href="http://zammad.com">Zammad</a>, your customer support system</i></p>',
'recipient' => 'ticket_customer',
'subject' => 'Owner has changed (#{ticket.title})',
},
},
disable_notification: true,
active: true,
created_by_id: 1,
updated_by_id: 1,
)
# process mail without Precedence header
content = IO.binread('test/fixtures/ticket_trigger/mail1.box')
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, content)
assert_equal('aaäöüßad asd', ticket_p.title)
assert_equal('Users', ticket_p.group.name)
assert_equal('new', ticket_p.state.name)
assert_equal(1, ticket_p.articles.count)
article_p = ticket_p.articles.last
Observer::Transaction.commit
ticket_p.owner = agent1
ticket_p.save
Observer::Transaction.commit
assert_equal('aaäöüßad asd', ticket_p.title, 'ticket_p.title verify')
assert_equal('Users', ticket_p.group.name, 'ticket_p.group verify')
assert_equal('new', ticket_p.state.name, 'ticket_p.state verify')
assert_equal('2 normal', ticket_p.priority.name, 'ticket_p.priority verify')
assert_equal(2, ticket_p.articles.count, 'ticket_p.articles verify')
p ticket_p.articles.last.inspect
article_p = ticket_p.articles.last
assert_match('Owner has changed', article_p.subject)
assert_match('Zammad <zammad@localhost>', article_p.from)
assert_match('martin@example.com', article_p.to)
assert_no_match('config\.', article_p.body)
assert_match('http://zammad.example.com', article_p.body)
assert_no_match('ticket.', article_p.body)
assert_match(ticket_p.number, article_p.body)
assert_equal('text/html', article_p.content_type)
trigger1 = Trigger.create_or_update(
name: 'owner update - to customer',
condition: {
'ticket.owner_id' => {
'operator' => 'has changed',
'pre_condition' => 'current_user.id',
'value' => '',
'value_completion' => '',
},
'ticket.priority_id' => {
'operator' => 'is',
'value' => Ticket::Priority.lookup(name: '3 high').id.to_s,
},
},
perform: {
'notification.email' => {
'body' => '<p>The owner of ticket (Ticket##{ticket.number}) has changed.<p>
<br/>
<p>To provide additional information, please reply to this email or click on the following link:
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}">#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}</a>
</p>
<br/>
<p><i><a href="http://zammad.com">Zammad</a>, your customer support system</i></p>',
'recipient' => 'ticket_customer',
'subject' => 'Owner has changed (#{ticket.title})',
},
},
disable_notification: true,
active: true,
created_by_id: 1,
updated_by_id: 1,
)
# process mail without Precedence header
content = IO.binread('test/fixtures/ticket_trigger/mail1.box')
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, content)
assert_equal('aaäöüßad asd', ticket_p.title)
assert_equal('Users', ticket_p.group.name)
assert_equal('new', ticket_p.state.name)
assert_equal(1, ticket_p.articles.count)
article_p = ticket_p.articles.last
Observer::Transaction.commit
assert_equal(1, ticket_p.articles.count)
ticket_p.priority = Ticket::Priority.lookup(name: '1 low')
ticket_p.save
Observer::Transaction.commit
assert_equal(1, ticket_p.articles.count)
ticket_p.priority = Ticket::Priority.lookup(name: '3 high')
ticket_p.save
Observer::Transaction.commit
assert_equal(1, ticket_p.articles.count)
ticket_p.owner = agent1
ticket_p.save
Observer::Transaction.commit
assert_equal('aaäöüßad asd', ticket_p.title, 'ticket_p.title verify')
assert_equal('Users', ticket_p.group.name, 'ticket_p.group verify')
assert_equal('new', ticket_p.state.name, 'ticket_p.state verify')
assert_equal('3 high', ticket_p.priority.name, 'ticket_p.priority verify')
assert_equal(2, ticket_p.articles.count, 'ticket_p.articles verify')
p ticket_p.articles.last.inspect
article_p = ticket_p.articles.last
assert_match('Owner has changed', article_p.subject)
assert_match('Zammad <zammad@localhost>', article_p.from)
assert_match('martin@example.com', article_p.to)
assert_no_match('config\.', article_p.body)
assert_match('http://zammad.example.com', article_p.body)
assert_no_match('ticket.', article_p.body)
assert_match(ticket_p.number, article_p.body)
assert_equal('text/html', article_p.content_type)
# should trigger
trigger1 = Trigger.create_or_update(
name: 'owner update - to customer',
condition: {
'ticket.owner_id' => {
'operator' => 'has changed',
'pre_condition' => 'current_user.id',
'value' => '',
'value_completion' => '',
},
'ticket.priority_id' => {
'operator' => 'is',
'value' => Ticket::Priority.lookup(name: '3 high').id.to_s,
},
'ticket.action' => {
'operator' => 'is not',
'value' => 'create',
},
},
perform: {
'notification.email' => {
'body' => '<p>The owner of ticket (Ticket##{ticket.number}) has changed.<p>
<br/>
<p>To provide additional information, please reply to this email or click on the following link:
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}">#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}</a>
</p>
<br/>
<p><i><a href="http://zammad.com">Zammad</a>, your customer support system</i></p>',
'recipient' => 'ticket_customer',
'subject' => 'Owner has changed (#{ticket.title})',
},
},
disable_notification: true,
active: true,
created_by_id: 1,
updated_by_id: 1,
)
# process mail without Precedence header
content = IO.binread('test/fixtures/ticket_trigger/mail1.box')
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, content)
assert_equal('aaäöüßad asd', ticket_p.title)
assert_equal('Users', ticket_p.group.name)
assert_equal('new', ticket_p.state.name)
assert_equal(1, ticket_p.articles.count)
article_p = ticket_p.articles.last
Observer::Transaction.commit
assert_equal(1, ticket_p.articles.count)
ticket_p.priority = Ticket::Priority.lookup(name: '1 low')
ticket_p.save
Observer::Transaction.commit
assert_equal(1, ticket_p.articles.count)
ticket_p.priority = Ticket::Priority.lookup(name: '3 high')
ticket_p.save
Observer::Transaction.commit
assert_equal(1, ticket_p.articles.count)
ticket_p.owner = agent1
ticket_p.save
Observer::Transaction.commit
assert_equal('aaäöüßad asd', ticket_p.title, 'ticket_p.title verify')
assert_equal('Users', ticket_p.group.name, 'ticket_p.group verify')
assert_equal('new', ticket_p.state.name, 'ticket_p.state verify')
assert_equal('3 high', ticket_p.priority.name, 'ticket_p.priority verify')
assert_equal(2, ticket_p.articles.count, 'ticket_p.articles verify')
p ticket_p.articles.last.inspect
article_p = ticket_p.articles.last
assert_match('Owner has changed', article_p.subject)
assert_match('Zammad <zammad@localhost>', article_p.from)
assert_match('martin@example.com', article_p.to)
assert_no_match('config\.', article_p.body)
assert_match('http://zammad.example.com', article_p.body)
assert_no_match('ticket.', article_p.body)
assert_match(ticket_p.number, article_p.body)
assert_equal('text/html', article_p.content_type)
# should not trigger
trigger1 = Trigger.create_or_update(
name: 'owner update - to customer',
condition: {
'ticket.owner_id' => {
'operator' => 'has changed',
'pre_condition' => 'current_user.id',
'value' => '',
'value_completion' => '',
},
'ticket.action' => {
'operator' => 'is',
'value' => 'create',
},
},
perform: {
'notification.email' => {
'body' => '<p>The owner of ticket (Ticket##{ticket.number}) has changed.<p>
<br/>
<p>To provide additional information, please reply to this email or click on the following link:
<a href="#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}">#{config.http_type}://#{config.fqdn}/#ticket/zoom/#{ticket.id}</a>
</p>
<br/>
<p><i><a href="http://zammad.com">Zammad</a>, your customer support system</i></p>',
'recipient' => 'ticket_customer',
'subject' => 'Owner has changed (#{ticket.title})',
},
},
disable_notification: true,
active: true,
created_by_id: 1,
updated_by_id: 1,
)
# process mail without Precedence header
content = IO.binread('test/fixtures/ticket_trigger/mail1.box')
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, content)
assert_equal(1, ticket_p.articles.count)
Observer::Transaction.commit
assert_equal(1, ticket_p.articles.count)
ticket_p.owner = agent1
ticket_p.save
Observer::Transaction.commit
assert_equal(1, ticket_p.articles.count)
Trigger.destroy_all
end
end end