diff --git a/app/assets/javascripts/app/controllers/_application_controller_form.coffee b/app/assets/javascripts/app/controllers/_application_controller_form.coffee index aeeb9de0a..0b170b2cc 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_form.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_form.coffee @@ -410,8 +410,8 @@ class App.ControllerForm extends App.Controller for key in array # check if item is-hidden and should not be used - if lookupForm.find('[name="' + key.name + '"]').hasClass('is-hidden') - param[key.name] = undefined + if lookupForm.find('[name="' + key.name + '"]').hasClass('is-hidden') || lookupForm.find('div[data-name="' + key.name + '"]').hasClass('is-hidden') + delete param[key.name] continue # collect all params, push it to an array if already exists diff --git a/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee b/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee index b12765ee8..7aaef98a4 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/ticket_perform_action.coffee @@ -1,6 +1,6 @@ # coffeelint: disable=camel_case_classes class App.UiElement.ticket_perform_action - @defaults: -> + @defaults: (attribute) -> defaults = ['ticket.state_id'] groups = @@ -8,31 +8,40 @@ class App.UiElement.ticket_perform_action name: 'Ticket' model: 'Ticket' + if attribute.notification + groups.notification = + name: 'Notification' + model: 'Notification' + # megre config elements = {} for groupKey, groupMeta of groups - for row in App[groupMeta.model].configure_attributes + if !App[groupMeta.model] + elements["#{groupKey}.email"] = { name: 'email', display: 'Email' } + else - # ignore passwords and relations - if row.type isnt 'password' && row.name.substr(row.name.length-4,4) isnt '_ids' + for row in App[groupMeta.model].configure_attributes - # ignore readonly attributes - if !row.readonly - config = _.clone(row) - if config.tag is 'tag' - config.operator = ['add', 'remove'] - elements["#{groupKey}.#{config.name}"] = config + # ignore passwords and relations + if row.type isnt 'password' && row.name.substr(row.name.length-4,4) isnt '_ids' + + # ignore readonly attributes + if !row.readonly + config = _.clone(row) + if config.tag is 'tag' + config.operator = ['add', 'remove'] + elements["#{groupKey}.#{config.name}"] = config [defaults, groups, elements] @render: (attribute, params = {}) -> - [defaults, groups, elements] = @defaults() + [defaults, groups, elements] = @defaults(attribute) selector = @buildAttributeSelector(groups, elements) # return item - item = $( App.view('generic/ticket_perform_action')( attribute: attribute ) ) + item = $( App.view('generic/ticket_perform_action/index')( attribute: attribute ) ) item.find('.js-attributeSelector').prepend(selector) # add filter @@ -65,8 +74,6 @@ class App.UiElement.ticket_perform_action selectorExists = false for groupAndAttribute, meta of params[attribute.name] selectorExists = true - value = meta.value - operator = meta.operator # get selector rows elementFirst = item.find('.js-filterElement').first() @@ -149,7 +156,19 @@ class App.UiElement.ticket_perform_action if groupAndAttribute elementRow.find('.js-attributeSelector select').val(groupAndAttribute) - @buildOperator(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + if groupAndAttribute is 'notification.email' + elementRow.find('.js-setAttribute').html('') + @buildRecipientList(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) + else + elementRow.find('.js-setNotification').html('') + if !elementRow.find('.js-setAttribute div').get(0) + attributeSelectorElement = $( App.view('generic/ticket_perform_action/attribute_selector')( + attribute: attribute + name: name + meta: meta || {} + )) + elementRow.find('.js-setAttribute').html(attributeSelectorElement) + @buildOperator(elementFull, elementRow, groupAndAttribute, elements, meta, attribute) @buildOperator: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) -> currentOperator = elementRow.find('.js-operator option:selected').attr('value') @@ -160,9 +179,7 @@ class App.UiElement.ticket_perform_action name = "#{attribute.name}::#{groupAndAttribute}::operator" selection = $("") - attributeConfig = elements[groupAndAttribute] - if !attributeConfig.operator elementRow.find('.js-operator').addClass('hide') else @@ -282,7 +299,36 @@ class App.UiElement.ticket_perform_action elementRow.find('.js-value').removeClass('hide').html(item) + @buildRecipientList: (elementFull, elementRow, groupAndAttribute, elements, meta, attribute) -> + return if elementRow.find('.js-setNotification .js-body').get(0) + + options = + 'ticket_owner': 'Owner' + 'ticket_customer': 'Customer' + 'ticket_agents': 'All Agents' + + name = "#{attribute.name}::notification.email" + + selection = $("") + for key, value of options + selected = '' + if key is meta.recipient + selected = 'selected="selected"' + selection.append("") + + notificationElement = $( App.view('generic/ticket_perform_action/notification_email')( + attribute: attribute + name: name + meta: meta || {} + )) + notificationElement.find('.js-recipient select').replaceWith(selection) + notificationElement.find('.js-body div[contenteditable="true"]').ce( + mode: 'richtext' + placeholder: 'message' + maxlength: 2000 + ) + elementRow.find('.js-setNotification').html(notificationElement) @humanText: (condition) -> none = App.i18n.translateContent('No filter.') diff --git a/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee b/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee index 05a822959..18a0e6f2e 100644 --- a/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee +++ b/app/assets/javascripts/app/controllers/_ui_element/ticket_selector.coffee @@ -1,12 +1,15 @@ # coffeelint: disable=camel_case_classes class App.UiElement.ticket_selector - @defaults: -> + @defaults: (attribute) -> defaults = ['ticket.state_id'] groups = ticket: name: 'Ticket' model: 'Ticket' + #article: + # name: 'Article' + # model: 'TicketArticle' customer: name: 'Customer' model: 'User' @@ -25,13 +28,25 @@ class App.UiElement.ticket_selector '_id$': ['is', 'is not'] '_ids$': ['is', 'is not'] - # megre config + # merge config elements = {} + + if attribute.action + elements['ticket.action'] = + name: 'action' + display: 'Action' + tag: 'select' + null: false + options: + create: 'created' + update: 'updated' + operator: ['is', 'is not'] + for groupKey, groupMeta of groups for row in App[groupMeta.model].configure_attributes # ignore passwords and relations - if row.type isnt 'password' && row.name.substr(row.name.length-4,4) isnt '_ids' + if row.type isnt 'password' && row.name.substr(row.name.length-4,4) isnt '_ids' && row.searchable isnt false config = _.clone(row) for operatorRegEx, operator of operators_type myRegExp = new RegExp(operatorRegEx, 'i') @@ -47,15 +62,12 @@ class App.UiElement.ticket_selector @render: (attribute, params = {}) -> - [defaults, groups, elements] = @defaults() + [defaults, groups, elements] = @defaults(attribute) selector = @buildAttributeSelector(groups, elements) - search = => - @preview(item) - # return item - item = $( App.view('generic/ticket_selector')( attribute: attribute ) ) + item = $( App.view('generic/ticket_selector')(attribute: attribute) ) item.find('.js-attributeSelector').prepend(selector) # add filter @@ -65,7 +77,8 @@ class App.UiElement.ticket_selector element.after(elementClone) elementClone.find('.js-attributeSelector select').trigger('change') @updateAttributeSelectors(item) - @preview(item) + if attribute.preview isnt false + @preview(item) ) # remove filter @@ -73,7 +86,8 @@ class App.UiElement.ticket_selector return if $(e.currentTarget).hasClass('is-disabled') $(e.target).closest('.js-filterElement').remove() @updateAttributeSelectors(item) - @preview(item) + if attribute.preview isnt false + @preview(item) ) # build inital params @@ -108,23 +122,6 @@ class App.UiElement.ticket_selector elementLast.after(elementClone) item.find('.js-filterElement').first().remove() - triggerSearch = -> - item.find('.js-previewCounterContainer').addClass('hide') - item.find('.js-previewLoader').removeClass('hide') - App.Delay.set( - search, - 600, - 'preview', - ) - - # bind for preview - item.on('change', 'select.form-control', (e) -> - triggerSearch() - ) - item.on('change keyup', 'input.form-control', (e) -> - triggerSearch() - ) - # change attribute selector item.find('.js-attributeSelector select').bind('change', (e) => elementRow = $(e.target).closest('.js-filterElement') @@ -140,6 +137,27 @@ class App.UiElement.ticket_selector @buildOperator(item, elementRow, groupAndAttribute, elements, {}, attribute) ) + # bind for preview + if attribute.preview isnt false + search = => + @preview(item) + + triggerSearch = -> + item.find('.js-previewCounterContainer').addClass('hide') + item.find('.js-previewLoader').removeClass('hide') + App.Delay.set( + search, + 600, + 'preview', + ) + + item.on('change', 'select', (e) -> + triggerSearch() + ) + item.on('change keyup', 'input', (e) -> + triggerSearch() + ) + item @preview: (item) -> diff --git a/app/assets/javascripts/app/controllers/trigger.coffee b/app/assets/javascripts/app/controllers/trigger.coffee index 4376f2d6f..251143ccf 100644 --- a/app/assets/javascripts/app/controllers/trigger.coffee +++ b/app/assets/javascripts/app/controllers/trigger.coffee @@ -10,7 +10,6 @@ class Index extends App.ControllerContent id: @id genericObject: 'Trigger' defaultSortBy: 'name' - #groupBy: 'role' pageData: title: 'Triggers' home: 'triggers' diff --git a/app/assets/javascripts/app/models/trigger.coffee b/app/assets/javascripts/app/models/trigger.coffee index 2c9352d60..94f2d1d48 100644 --- a/app/assets/javascripts/app/models/trigger.coffee +++ b/app/assets/javascripts/app/models/trigger.coffee @@ -4,9 +4,8 @@ class App.Trigger extends App.Model @url: @apiPath + '/triggers' @configure_attributes = [ { name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false }, - { name: 'condition', display: 'Conditions for effected objects', tag: 'ticket_selector', null: false }, - { name: 'perform', display: 'Execute changes on objects', tag: 'ticket_perform_action', null: true }, - { name: 'disable_notiifcation', display: 'Disable Notifications', tag: 'boolean', default: true }, + { name: 'condition', display: 'Conditions for effected objects', tag: 'ticket_selector', null: false, preview: false, action: 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: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 }, ] @@ -14,8 +13,9 @@ class App.Trigger extends App.Model @configure_overview = [ 'name', ] - + ### @description = ''' Trigger are.... -''' \ No newline at end of file +''' + ### diff --git a/app/assets/javascripts/app/views/generic/ticket_perform_action/attribute_selector.jst.eco b/app/assets/javascripts/app/views/generic/ticket_perform_action/attribute_selector.jst.eco new file mode 100644 index 000000000..2dc95049a --- /dev/null +++ b/app/assets/javascripts/app/views/generic/ticket_perform_action/attribute_selector.jst.eco @@ -0,0 +1,15 @@ +
+
+
+ + <%- @Icon('arrow-down', 'dropdown-arrow') %> +
+
+
+
+ + <%- @Icon('arrow-down', 'dropdown-arrow') %> +
+
+
+
\ No newline at end of file diff --git a/app/assets/javascripts/app/views/generic/ticket_perform_action.jst.eco b/app/assets/javascripts/app/views/generic/ticket_perform_action/index.jst.eco similarity index 60% rename from app/assets/javascripts/app/views/generic/ticket_perform_action.jst.eco rename to app/assets/javascripts/app/views/generic/ticket_perform_action/index.jst.eco index 6c292e5f3..d2bb37cbd 100644 --- a/app/assets/javascripts/app/views/generic/ticket_perform_action.jst.eco +++ b/app/assets/javascripts/app/views/generic/ticket_perform_action/index.jst.eco @@ -6,19 +6,8 @@ <%- @Icon('arrow-down', 'dropdown-arrow') %> -
-
- - <%- @Icon('arrow-down', 'dropdown-arrow') %> -
-
-
-
- - <%- @Icon('arrow-down', 'dropdown-arrow') %> -
-
-
+
+
diff --git a/app/assets/javascripts/app/views/generic/ticket_perform_action/notification_email.jst.eco b/app/assets/javascripts/app/views/generic/ticket_perform_action/notification_email.jst.eco new file mode 100644 index 000000000..72ad0c5c7 --- /dev/null +++ b/app/assets/javascripts/app/views/generic/ticket_perform_action/notification_email.jst.eco @@ -0,0 +1,8 @@ +
+
+ + <%- @Icon('arrow-down', 'dropdown-arrow') %> +
+
+
<%- @meta.body %>
+
diff --git a/app/assets/javascripts/app/views/generic/ticket_selector.jst.eco b/app/assets/javascripts/app/views/generic/ticket_selector.jst.eco index 1b2eb9285..87176147c 100644 --- a/app/assets/javascripts/app/views/generic/ticket_selector.jst.eco +++ b/app/assets/javascripts/app/views/generic/ticket_selector.jst.eco @@ -30,7 +30,7 @@
-
+

<%- @T('Preview') %> ? <%- @T('matches') %>

\ No newline at end of file diff --git a/app/models/job.rb b/app/models/job.rb index 3eedc75ff..dff007a82 100644 --- a/app/models/job.rb +++ b/app/models/job.rb @@ -44,21 +44,7 @@ class Job < ApplicationModel # use transaction ActiveRecord::Base.transaction do UserInfo.current_user_id = 1 - - logger.debug "Perform job #{job.perform.inspect} in Ticket.find(#{ticket.id})" - changed = false - job.perform.each do |key, value| - (object_name, attribute) = key.split('.', 2) - raise "Unable to update object #{object_name}.#{attribute}, only can update tickets!" if object_name != 'ticket' - - next if ticket[attribute].to_s == value['value'].to_s - changed = true - - ticket[attribute] = value['value'] - logger.debug "set #{object_name}.#{attribute} = #{value['value'].inspect}" - end - next if !changed - ticket.save + ticket.perform_changes(job.perform, 'job') # execute object transaction Observer::Transaction.commit( diff --git a/app/models/observer/ticket/article/communicate_email/background_job.rb b/app/models/observer/ticket/article/communicate_email/background_job.rb index 5c9933793..9ba80b313 100644 --- a/app/models/observer/ticket/article/communicate_email/background_job.rb +++ b/app/models/observer/ticket/article/communicate_email/background_job.rb @@ -19,6 +19,12 @@ class Observer::Ticket::Article::CommunicateEmail::BackgroundJob channel = ticket.group.email_address.channel + notification = false + sender = Ticket::Article::Sender.lookup(id: record.sender_id) + if sender['name'] == 'System' + notification = true + end + # get linked channel and send message = channel.deliver( { @@ -32,7 +38,8 @@ class Observer::Ticket::Article::CommunicateEmail::BackgroundJob content_type: record.content_type, body: record.body, attachments: record.attachments - } + }, + notification ) # store mail plain diff --git a/app/models/observer/ticket/article/fillup_from_email.rb b/app/models/observer/ticket/article/fillup_from_email.rb index 01f4927ea..d28fa108a 100644 --- a/app/models/observer/ticket/article/fillup_from_email.rb +++ b/app/models/observer/ticket/article/fillup_from_email.rb @@ -41,7 +41,7 @@ class Observer::Ticket::Article::FillupFromEmail < ActiveRecord::Observer raise "No email address found for group '#{ticket.group.name}'" end system_sender = "#{email_address.realname} <#{email_address.email}>" - if Setting.get('ticket_define_email_from') == 'AgentNameSystemAddressName' + if record.created_by_id != 1 && Setting.get('ticket_define_email_from') == 'AgentNameSystemAddressName' seperator = Setting.get('ticket_define_email_from_seperator') sender = User.find(record.created_by_id) record.from = "#{sender.firstname} #{sender.lastname} #{seperator} #{system_sender}" diff --git a/app/models/observer/transaction.rb b/app/models/observer/transaction.rb index 26437c192..2c2d2a1bd 100644 --- a/app/models/observer/transaction.rb +++ b/app/models/observer/transaction.rb @@ -26,15 +26,41 @@ class Observer::Transaction < ActiveRecord::Observer # reset buffer EventBuffer.reset('transaction') + # get asyn backends + sync_backends = [] + Setting.where(area: 'Transaction::Backend::Sync').order(:name).each {|setting| + backend = Setting.get(setting.name) + sync_backends.push Kernel.const_get(backend) + } + # get uniq objects list_objects = get_uniq_changes(list) list_objects.each {|_object, objects| objects.each {|_id, item| + + # execute sync backends + sync_backends.each {|backend| + execute_singel_backend(backend, item, params) + } + + # execute async backends Delayed::Job.enqueue(Transaction::BackgroundJob.new(item, params)) } } end + def self.execute_singel_backend(backend, item, params) + Rails.logger.error "Execute singel backend #{backend}" + begin + UserInfo.current_user_id = nil + integration = backend.new(item, params) + integration.perform + rescue => e + Rails.logger.error 'ERROR: ' + backend.inspect + Rails.logger.error 'ERROR: ' + e.inspect + end + end + =begin result = get_uniq_changes(events) diff --git a/app/models/tag.rb b/app/models/tag.rb index 0efb6a876..2dc08abcc 100644 --- a/app/models/tag.rb +++ b/app/models/tag.rb @@ -13,12 +13,16 @@ class Tag < ApplicationModel # lookups if data[:object] - tag_object_id = tag_object_lookup( data[:object] ) + tag_object_id = tag_object_lookup(data[:object]) end if data[:item] - tag_item_id = tag_item_lookup( data[:item] ) + tag_item_id = tag_item_lookup(data[:item].strip) end + # return in duplicate + current_tags = tag_list(data) + return true if current_tags.include?(data[:item].downcase.strip) + # create history Tag.create( tag_object_id: tag_object_id, @@ -33,10 +37,10 @@ class Tag < ApplicationModel # lookups if data[:object] - tag_object_id = tag_object_lookup( data[:object] ) + tag_object_id = tag_object_lookup(data[:object]) end if data[:item] - tag_item_id = tag_item_lookup( data[:item] ) + tag_item_id = tag_item_lookup(data[:item].strip) end # create history @@ -49,80 +53,76 @@ class Tag < ApplicationModel true end - def self.tag_list( data ) - tag_object_id_requested = tag_object_lookup( data[:object] ) + def self.tag_list(data) + tag_object_id_requested = tag_object_lookup(data[:object]) tag_search = Tag.where( tag_object_id: tag_object_id_requested, o_id: data[:o_id], ) tags = [] tag_search.each {|tag| - tags.push tag_item_lookup_id( tag.tag_item_id ) + tags.push tag_item_lookup_id(tag.tag_item_id) } tags end - def self.tag_item_lookup_id( id ) + def self.tag_item_lookup_id(id) # use cache - return @@cache_item[ id ] if @@cache_item[ id ] + return @@cache_item[id] if @@cache_item[id] # lookup tag_item = Tag::Item.find(id) - @@cache_item[ id ] = tag_item.name + @@cache_item[id] = tag_item.name tag_item.name end - def self.tag_item_lookup( name ) + def self.tag_item_lookup(name) name = name.downcase # use cache - return @@cache_item[ name ] if @@cache_item[ name ] + return @@cache_item[name] if @@cache_item[name] # lookup - tag_item = Tag::Item.find_by( name: name ) + tag_item = Tag::Item.find_by(name: name) if tag_item - @@cache_item[ name ] = tag_item.id + @@cache_item[name] = tag_item.id return tag_item.id end # create - tag_item = Tag::Item.create( - name: name - ) - @@cache_item[ name ] = tag_item.id + tag_item = Tag::Item.create(name: name) + @@cache_item[name] = tag_item.id tag_item.id end - def self.tag_object_lookup_id( id ) + def self.tag_object_lookup_id(id) # use cache - return @@cache_object[ id ] if @@cache_object[ id ] + return @@cache_object[id] if @@cache_object[id] # lookup tag_object = Tag::Object.find(id) - @@cache_object[ id ] = tag_object.name + @@cache_object[id] = tag_object.name tag_object.name end - def self.tag_object_lookup( name ) + def self.tag_object_lookup(name) # use cache - return @@cache_object[ name ] if @@cache_object[ name ] + return @@cache_object[name] if @@cache_object[name] # lookup - tag_object = Tag::Object.find_by( name: name ) + tag_object = Tag::Object.find_by(name: name) if tag_object - @@cache_object[ name ] = tag_object.id + @@cache_object[name] = tag_object.id return tag_object.id end # create - tag_object = Tag::Object.create( - name: name - ) - @@cache_object[ name ] = tag_object.id + tag_object = Tag::Object.create(name: name) + @@cache_object[name] = tag_object.id tag_object.id end diff --git a/app/models/ticket.rb b/app/models/ticket.rb index 2f390f26d..22b0053bb 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -457,6 +457,9 @@ condition example elsif selector[0] == 'owner' tables += ', users owners' query += 'tickets.owner_id = owners.id' + elsif selector[0] == 'article' + tables += ', ticket_articles articles' + query += 'tickets.id = articles.ticket_id' else raise "invalid selector #{attribute.inspect}->#{selector.inspect}" end @@ -630,6 +633,129 @@ condition example =begin +perform changes on ticket + + ticket.perform_changes({}, 'trigger') + +=end + + def perform_changes(perform, log) + logger.debug "Perform #{log} #{perform.inspect} on Ticket.find(#{id})" + changed = false + perform.each do |key, value| + (object_name, attribute) = key.split('.', 2) + raise "Unable to update object #{object_name}.#{attribute}, only can update tickets and send notifications!" if object_name != 'ticket' && object_name != 'notification' + + # send notification + if object_name == 'notification' + recipients = [] + if value['recipient'] == 'ticket_customer' + recipients.push User.lookup(id: customer_id) + elsif value['recipient'] == 'ticket_owner' + recipients.push User.lookup(id: owner_id) + elsif value['recipient'] == 'ticket_agents' + recipients = recipients.concat(agent_of_group) + else + logger.error "Unknown email notification recipient '#{value['recipient']}'" + next + end + recipient_string = '' + recipient_already = {} + recipients.each {|user| + next if !user.email + next if user.email !~ /@/ + email = user.email.downcase.strip + next if recipient_already[email] + recipient_already[email] = true + if recipient_string != '' + recipient_string += ', ' + end + recipient_string += email + } + next if recipient_string == '' + group = self.group + next if !group + email_address = group.email_address + next if !email_address + next if !email_address.channel_id + + objects = { + ticket: self, + article: articles.last, + #recipient: user, + #changes: changes, + } + + # get subject + value['subject'].gsub!(/\#\{(.+?)\}/, '<%= d "\\1", false %>') + subject = NotificationFactory::Mailer.template( + templateInline: value['subject'], + locale: 'en-en', + objects: objects, + ) + subject = subject_build(subject) + + value['body'].gsub!(/\#\{(.+?)\}/, '<%= d "\\1", true %>') + body = NotificationFactory::Mailer.template( + templateInline: value['body'], + locale: 'en-en', + objects: objects, + ) + Ticket::Article.create( + ticket_id: id, + #from: 'some_sender@example.com', + to: recipient_string, + subject: subject, + content_type: 'text/html', + body: body, + internal: false, + sender: Ticket::Article::Sender.find_by(name: 'System'), + type: Ticket::Article::Type.find_by(name: 'email'), + updated_by_id: 1, + created_by_id: 1, + ) + next + end + + # update tags + if key == 'ticket.tags' + next if value['value'].empty? + tags = value['value'].split(/,/) + if value['operator'] == 'add' + tags.each {|tag| + Tag.tag_add( + object: 'Ticket', + o_id: id, + item: tag, + ) + } + elsif value['operator'] == 'remove' + tags.each {|tag| + Tag.tag_remove( + object: 'Ticket', + o_id: id, + item: tag, + ) + } + else + logger.error "Unknown #{attribute} operator #{value['operator']}" + end + next + end + + # update ticket + next if self[attribute].to_s == value['value'].to_s + changed = true + + self[attribute] = value['value'] + logger.debug "set #{object_name}.#{attribute} = #{value['value'].inspect}" + end + return if !changed + save + end + +=begin + get all email references headers of a ticket, to exclude some, parse it as array into method references = ticket.get_references diff --git a/app/models/ticket/subject.rb b/app/models/ticket/subject.rb index 4c946891a..fb0044219 100644 --- a/app/models/ticket/subject.rb +++ b/app/models/ticket/subject.rb @@ -29,7 +29,7 @@ returns # right position if Setting.get('ticket_hook_position') == 'right' - return subject + " [#{ticket_hook}#{ticket_hook_divider}#{number}] " + return subject + " [#{ticket_hook}#{ticket_hook_divider}#{number}]" end # left position diff --git a/app/models/transaction/background_job.rb b/app/models/transaction/background_job.rb index 9bde30da4..488bd271e 100644 --- a/app/models/transaction/background_job.rb +++ b/app/models/transaction/background_job.rb @@ -22,16 +22,9 @@ class Transaction::BackgroundJob end def perform - Setting.where(area: 'Transaction::Backend').order(:name).each {|setting| - backend = Setting.get(setting.name) - begin - UserInfo.current_user_id = nil - integration = Kernel.const_get(backend).new(@item, @params) - integration.perform - rescue => e - Rails.logger.error 'ERROR: ' + setting.inspect - Rails.logger.error 'ERROR: ' + e.inspect - end + Setting.where(area: 'Transaction::Backend::Async').order(:name).each {|setting| + backend = Kernel.const_get(Setting.get(setting.name)) + Observer::Transaction.execute_singel_backend(backend, @item, @params) } end diff --git a/app/models/transaction/trigger.rb b/app/models/transaction/trigger.rb new file mode 100644 index 000000000..1824097b8 --- /dev/null +++ b/app/models/transaction/trigger.rb @@ -0,0 +1,77 @@ +# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ + +class Transaction::Trigger + +=begin + { + object: 'Ticket', + type: 'update', + object_id: 123, + via_web: true, + changes: { + 'attribute1' => [before, now], + 'attribute2' => [before, now], + } + user_id: 123, + }, +=end + + def initialize(item, params = {}) + @item = item + @params = params + end + + def perform + + # return if we run import mode + return if Setting.get('import_mode') + + return if @item[:object] != 'Ticket' + + triggers = Trigger.where(active: true) + return if triggers.empty? + + ticket = Ticket.lookup(id: @item[:object_id]) + return if !ticket + if @item[:article_id] + article = Ticket::Article.lookup(id: @item[:article_id]) + end + + UserInfo.current_user_id = 1 + + triggers.each {|trigger| + condition = trigger.condition + + # check action + if condition['ticket.action'] + 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') + end + + condition['ticket.id'] = { + operator: 'is', + value: ticket.id, + } + ticket_count, tickets = Ticket.selectors(condition, 1) + next if ticket_count == 0 + next if tickets.first.id != ticket.id + + # check in min one attribute has changed + if @item[:type] == 'update' + match = false + trigger.condition.each do |key, _value| + (object_name, attribute) = key.split('.', 2) + next if object_name != 'ticket' + next if !@item[:changes][attribute] + match = true + break + end + next if !match + end + + ticket.perform_changes(trigger.perform, 'trigger') + } + end + +end diff --git a/app/models/trigger.rb b/app/models/trigger.rb index 4d5c948a3..63be32c7b 100644 --- a/app/models/trigger.rb +++ b/app/models/trigger.rb @@ -1,4 +1,7 @@ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ -class Trigger < ActiveRecord::Base +class Trigger < ApplicationModel + store :condition + store :perform + validates :name, presence: true end diff --git a/db/migrate/20160501000001_update_transaction.rb b/db/migrate/20160501000001_update_transaction.rb new file mode 100644 index 000000000..c1f6fe4ba --- /dev/null +++ b/db/migrate/20160501000001_update_transaction.rb @@ -0,0 +1,63 @@ +class UpdateTransaction < ActiveRecord::Migration + def up + + # return if it's a new setup + return if !Setting.find_by(name: 'system_init_done') + + Setting.create_or_update( + title: 'Define sync transaction backend.', + name: '0100_trigger', + area: 'Transaction::Backend::Sync', + description: 'Define the transaction backend to execute triggers.', + options: {}, + state: 'Transaction::Trigger', + frontend: false + ) + Setting.create_or_update( + title: 'Define transaction backend.', + name: '0100_notification', + area: 'Transaction::Backend::Async', + description: 'Define the transaction backend to send agent notifications.', + options: {}, + state: 'Transaction::Notification', + frontend: false + ) + Setting.create_or_update( + title: 'Define transaction backend.', + name: '1000_signature_detection', + area: 'Transaction::Backend::Async', + description: 'Define the transaction backend to detect customers signature in email.', + options: {}, + state: 'Transaction::SignatureDetection', + frontend: false + ) + Setting.create_or_update( + title: 'Define transaction backend.', + name: '6000_slack_webhook', + area: 'Transaction::Backend::Async', + description: 'Define the transaction backend which posts messages to (http://www.slack.com).', + options: {}, + state: 'Transaction::Slack', + frontend: false + ) + Setting.create_or_update( + title: 'Define transaction backend.', + name: '9000_clearbit_enrichment', + area: 'Transaction::Backend::Async', + description: 'Define the transaction backend which will enrich customer and organization informations from (http://www.clearbit.com).', + options: {}, + state: 'Transaction::ClearbitEnrichment', + frontend: false + ) + Setting.create_or_update( + title: 'Define transaction backend.', + name: '9100_cti_caller_id_detection', + area: 'Transaction::Backend::Async', + description: 'Define the transaction backend which detects caller ids in objects and store them for cti lookups.', + options: {}, + state: 'Transaction::CtiCallerIdDetection', + frontend: false + ) + + end +end diff --git a/db/seeds.rb b/db/seeds.rb index c4b824775..b4a90f59b 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1769,10 +1769,19 @@ Setting.create_if_not_exists( preferences: { prio: 4 }, frontend: false ) +Setting.create_if_not_exists( + title: 'Define sync transaction backend.', + name: '0100_trigger', + area: 'Transaction::Backend::Sync', + description: 'Define the transaction backend to execute triggers.', + options: {}, + state: 'Transaction::Trigger', + frontend: false +) Setting.create_if_not_exists( title: 'Define transaction backend.', name: '0100_notification', - area: 'Transaction::Backend', + area: 'Transaction::Backend::Async', description: 'Define the transaction backend to send agent notifications.', options: {}, state: 'Transaction::Notification', @@ -1781,7 +1790,7 @@ Setting.create_if_not_exists( Setting.create_if_not_exists( title: 'Define transaction backend.', name: '1000_signature_detection', - area: 'Transaction::Backend', + area: 'Transaction::Backend::Async', description: 'Define the transaction backend to detect customers signature in email.', options: {}, state: 'Transaction::SignatureDetection', @@ -1790,7 +1799,7 @@ Setting.create_if_not_exists( Setting.create_if_not_exists( title: 'Define transaction backend.', name: '6000_slack_webhook', - area: 'Transaction::Backend', + area: 'Transaction::Backend::Async', description: 'Define the transaction backend which posts messages to (http://www.slack.com).', options: {}, state: 'Transaction::Slack', @@ -1900,7 +1909,7 @@ Setting.create_if_not_exists( Setting.create_if_not_exists( title: 'Define transaction backend.', name: '9000_clearbit_enrichment', - area: 'Transaction::Backend', + area: 'Transaction::Backend::Async', description: 'Define the transaction backend which will enrich customer and organization informations from (http://www.clearbit.com).', options: {}, state: 'Transaction::ClearbitEnrichment', @@ -1909,7 +1918,7 @@ Setting.create_if_not_exists( Setting.create_if_not_exists( title: 'Define transaction backend.', name: '9100_cti_caller_id_detection', - area: 'Transaction::Backend', + area: 'Transaction::Backend::Async', description: 'Define the transaction backend which detects caller ids in objects and store them for cti lookups.', options: {}, state: 'Transaction::CtiCallerIdDetection', diff --git a/public/assets/tests/form.js b/public/assets/tests/form.js index e2c0337f3..8c6e54863 100644 --- a/public/assets/tests/form.js +++ b/public/assets/tests/form.js @@ -474,7 +474,6 @@ test("form dependend fields check", function() { var test_params = { input1: "", input2: "some used default", - input3: undefined, select1: "false", select2: "false", selectmulti2: [ "true", "false" ], @@ -503,7 +502,6 @@ test("form dependend fields check", function() { params = App.ControllerForm.params(el) test_params = { input1: "", - input2: undefined, input3: "some used default", select1: "true", select2: "false", @@ -853,7 +851,6 @@ test("form required_if + shown_if", function() { input1: "some not used default33", input2: "some name66", input3: "some name77", - input4: undefined, active: true, }; params = App.ControllerForm.params(el) @@ -868,9 +865,6 @@ test("form required_if + shown_if", function() { el.find('[name="{boolean}active"]').val('false').trigger('change') test_params = { input1: "some not used default33", - input2: undefined, - input3: undefined, - input4: undefined, active: false, }; params = App.ControllerForm.params(el) @@ -886,7 +880,6 @@ test("form required_if + shown_if", function() { input1: "some not used default33", input2: "some name66", input3: "some name77", - input4: undefined, active: true, }; params = App.ControllerForm.params(el) diff --git a/public/assets/tests/form_extended.js b/public/assets/tests/form_extended.js index 5068daf65..f3ae9aeab 100644 --- a/public/assets/tests/form_extended.js +++ b/public/assets/tests/form_extended.js @@ -268,7 +268,7 @@ test('form checks', function() { model: { configure_attributes: [ { name: 'condition', display: 'Conditions', tag: 'ticket_selector', null: true }, - { name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true }, + { name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true, notification: true }, ] }, autofocus: true @@ -290,7 +290,7 @@ test('form checks', function() { deepEqual(params, test_params, 'form param check'); /* with params or defaults */ - $('#forms').append('

form time check

') + $('#forms').append('

form 3

') var el = $('#form3') var defaults = { condition: { @@ -342,6 +342,11 @@ test('form checks', function() { operator: 'remove', value: 'tag1, tag2', }, + 'notification.email': { + recipient: 'ticket_customer', + subject: 'some subject', + body: "some
\nbody", + }, }, } new App.ControllerForm({ @@ -349,7 +354,7 @@ test('form checks', function() { model: { configure_attributes: [ { name: 'condition', display: 'Conditions', tag: 'ticket_selector', null: true }, - { name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true }, + { name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true, notification: true }, ] }, params: defaults, @@ -409,6 +414,11 @@ test('form checks', function() { operator: 'remove', value: 'tag1, tag2', }, + 'notification.email': { + recipient: 'ticket_customer', + subject: 'some subject', + body: "some
\nbody", + }, }, } deepEqual(params, test_params, 'form param check') @@ -464,12 +474,172 @@ test('form checks', function() { operator: 'remove', value: 'tag1, tag2', }, + 'notification.email': { + recipient: 'ticket_customer', + subject: 'some subject', + body: "some
\nbody", + }, }, } deepEqual(params, test_params, 'form param check') - //deepEqual(el.find('[name="times::days"]').val(), ['mon', 'wed'], 'check times::days value') - //equal(el.find('[name="times::hours"]').val(), 2, 'check times::hours value') - //equal(el.find('[name="times::minutes"]').val(), null, 'check times::minutes value') + // change selector + el.find('[name="executions::notification.email::subject"]').closest('.js-filterElement').find('.js-remove').click() + + var params = App.ControllerForm.params(el) + var test_params = { + condition: { + 'ticket.title': { + operator: 'contains', + value: 'some title', + }, + 'ticket.created_at': { + operator: 'before (absolute)', + value: '2015-09-20T03:41:00.000Z', + }, + 'ticket.updated_at': { + operator: 'within last (relative)', + range: 'year', + value: '2', + }, + 'ticket.organization_id': { + operator: 'is not', + pre_condition: 'specific', + value: '12', + }, + 'ticket.owner_id': { + operator: 'is', + pre_condition: 'specific', + value: '47', + value_completion: 'Bob Smith ', + }, + 'ticket.created_by_id': { + operator: 'is', + pre_condition: 'current_user.id', + value: '', + value_completion: '' + }, + }, + executions: { + 'ticket.priority_id': { + value: '3', + }, + 'ticket.owner_id': { + pre_condition: 'specific', + value: '47', + value_completion: 'Bob Smith ' + }, + 'ticket.tags': { + operator: 'remove', + value: 'tag1, tag2', + }, + }, + } + deepEqual(params, test_params, 'form param check') + + // change selector + el.find('.js-attributeSelector').last().find('select').val('notification.email').trigger('change') + el.find('[name="executions::notification.email::subject"]').val('some subject') + el.find('[data-name="executions::notification.email::body"]').html('lala') + + var params = App.ControllerForm.params(el) + var test_params = { + condition: { + 'ticket.title': { + operator: 'contains', + value: 'some title', + }, + 'ticket.created_at': { + operator: 'before (absolute)', + value: '2015-09-20T03:41:00.000Z', + }, + 'ticket.updated_at': { + operator: 'within last (relative)', + range: 'year', + value: '2', + }, + 'ticket.organization_id': { + operator: 'is not', + pre_condition: 'specific', + value: '12', + }, + 'ticket.owner_id': { + operator: 'is', + pre_condition: 'specific', + value: '47', + value_completion: 'Bob Smith ', + }, + 'ticket.created_by_id': { + operator: 'is', + pre_condition: 'current_user.id', + value: '', + value_completion: '' + }, + }, + executions: { + 'ticket.priority_id': { + value: '3', + }, + 'ticket.owner_id': { + pre_condition: 'specific', + value: '47', + value_completion: 'Bob Smith ' + }, + 'notification.email': { + recipient: 'ticket_owner', + subject: 'some subject', + body: 'lala', + }, + }, + } + deepEqual(params, test_params, 'form param check') + + /* with params or defaults */ + $('#forms').append('

form 4

') + var el = $('#form4') + var defaults = { + condition: { + 'ticket.title': { + operator: 'contains', + value: 'some title', + }, + }, + executions: { + 'notification.email': { + recipient: 'ticket_customer', + subject: 'some subject', + body: "some
\nbody", + }, + }, + } + new App.ControllerForm({ + el: el, + model: { + configure_attributes: [ + { name: 'condition', display: 'Conditions', tag: 'ticket_selector', null: true }, + { name: 'executions', display: 'Executions', tag: 'ticket_perform_action', null: true, notification: true }, + ] + }, + params: defaults, + autofocus: true + }) + var params = App.ControllerForm.params(el) + var test_params = { + condition: { + 'ticket.title': { + operator: 'contains', + value: 'some title', + }, + }, + executions: { + + 'notification.email': { + recipient: 'ticket_customer', + subject: 'some subject', + body: "some
\nbody", + }, + }, + } + deepEqual(params, test_params, 'form param check') }); \ No newline at end of file diff --git a/test/fixtures/seeds.rb b/test/fixtures/seeds.rb index 5ef8d7f9f..c58a66cab 100644 --- a/test/fixtures/seeds.rb +++ b/test/fixtures/seeds.rb @@ -1,6 +1,9 @@ # encoding: utf-8 # inital data set as extention to db/seeds.rb +Trigger.destroy_all +Job.destroy_all + # create email address and apply it to all groups channel_id = nil channel = Channel.find_by(area: 'Email::Notification', active: true) diff --git a/test/unit/ticket_trigger_test.rb b/test/unit/ticket_trigger_test.rb new file mode 100644 index 000000000..c1e0209eb --- /dev/null +++ b/test/unit/ticket_trigger_test.rb @@ -0,0 +1,337 @@ +# encoding: utf-8 +require 'test_helper' + +class TicketTriggerTest < ActiveSupport::TestCase + test '1 basic' do + trigger1 = Trigger.create_or_update( + name: 'auto reply', + condition: { + 'ticket.state_id' => { + 'operator' => 'is', + 'value' => Ticket::State.lookup(name: 'new').id.to_s, + } + }, + perform: { + 'notification.email' => { + 'body' => 'some text
#{ticket.customer.lastname}
#{ticket.title}', + 'recipient' => 'ticket_customer', + 'subject' => 'Thanks for your inquery (#{ticket.title})!', + }, + 'ticket.priority_id' => { + 'value' => Ticket::Priority.lookup(name: '3 high').id.to_s, + }, + 'ticket.tags' => { + 'operator' => 'add', + 'value' => 'aa, kk', + }, + }, + disable_notification: true, + active: true, + created_by_id: 1, + updated_by_id: 1, + ) + + trigger2 = Trigger.create_or_update( + name: 'not matching', + condition: { + 'ticket.state_id' => { + 'operator' => 'is', + 'value' => Ticket::State.lookup(name: 'closed').id.to_s, + } + }, + perform: { + 'ticket.priority_id' => { + 'value' => Ticket::Priority.lookup(name: '3 high').id.to_s, + }, + }, + disable_notification: true, + active: true, + created_by_id: 1, + updated_by_id: 1, + ) + + ticket1 = Ticket.create( + title: "some title\n äöüß", + group: Group.lookup(name: 'Users'), + customer_id: 2, + state: Ticket::State.lookup(name: 'new'), + priority: Ticket::Priority.lookup(name: '2 normal'), + updated_by_id: 1, + created_by_id: 1, + ) + assert(ticket1, 'ticket1 created') + + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(0, ticket1.articles.count, 'ticket1.articles verify') + assert_equal([], Tag.tag_list(object: 'Ticket', o_id: ticket1.id)) + + Observer::Transaction.commit + + ticket1 = Ticket.lookup(id: ticket1.id) + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('3 high', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(1, ticket1.articles.count, 'ticket1.articles verify') + assert_equal(%w(aa kk), Tag.tag_list(object: 'Ticket', o_id: ticket1.id)) + article1 = ticket1.articles.last + assert_match('Thanks for your inquery (some title äöüß)!', article1.subject) + assert_match('Braun
some <b>title</b>', article1.body) + assert_equal('text/html', article1.content_type) + + ticket1.priority = Ticket::Priority.lookup(name: '2 normal') + ticket1.save + + Observer::Transaction.commit + + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(1, ticket1.articles.count, 'ticket1.articles verify') + assert_equal(%w(aa kk), Tag.tag_list(object: 'Ticket', o_id: ticket1.id)) + + ticket1.state = Ticket::State.lookup(name: 'open') + ticket1.save + + Observer::Transaction.commit + + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('open', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(1, ticket1.articles.count, 'ticket1.articles verify') + assert_equal(%w(aa kk), Tag.tag_list(object: 'Ticket', o_id: ticket1.id)) + + ticket1.state = Ticket::State.lookup(name: 'new') + ticket1.save + + Observer::Transaction.commit + + ticket1 = Ticket.lookup(id: ticket1.id) + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('3 high', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(2, ticket1.articles.count, 'ticket1.articles verify') + assert_equal(%w(aa kk), Tag.tag_list(object: 'Ticket', o_id: ticket1.id)) + + ticket2 = Ticket.create( + title: "some title\n äöüß", + group: Group.lookup(name: 'Users'), + customer_id: 2, + state: Ticket::State.lookup(name: 'open'), + priority: Ticket::Priority.lookup(name: '2 normal'), + updated_by_id: 1, + created_by_id: 1, + ) + assert(ticket2, 'ticket2 created') + + assert_equal('some title äöüß', ticket2.title, 'ticket2.title verify') + assert_equal('Users', ticket2.group.name, 'ticket2.group verify') + assert_equal('open', ticket2.state.name, 'ticket2.state verify') + assert_equal('2 normal', ticket2.priority.name, 'ticket2.priority verify') + assert_equal(0, ticket2.articles.count, 'ticket2.articles verify') + assert_equal([], Tag.tag_list(object: 'Ticket', o_id: ticket2.id)) + + Observer::Transaction.commit + + ticket2 = Ticket.lookup(id: ticket2.id) + assert_equal('some title äöüß', ticket2.title, 'ticket2.title verify') + assert_equal('Users', ticket2.group.name, 'ticket2.group verify') + assert_equal('open', ticket2.state.name, 'ticket2.state verify') + assert_equal('2 normal', ticket2.priority.name, 'ticket2.priority verify') + assert_equal(0, ticket2.articles.count, 'ticket2.articles verify') + assert_equal([], Tag.tag_list(object: 'Ticket', o_id: ticket2.id)) + + Trigger.destroy_all + end + + test '2 actions - create' do + trigger1 = Trigger.create_or_update( + name: 'auto reply', + condition: { + 'ticket.action' => { + 'operator' => 'is', + 'value' => 'create', + }, + 'ticket.state_id' => { + 'operator' => 'is', + 'value' => Ticket::State.lookup(name: 'new').id.to_s, + } + }, + perform: { + 'notification.email' => { + 'body' => 'dasdasdasd', + 'recipient' => 'ticket_customer', + 'subject' => 'asdasdas', + }, + 'ticket.priority_id' => { + 'value' => Ticket::Priority.lookup(name: '3 high').id.to_s, + }, + }, + disable_notification: true, + active: true, + created_by_id: 1, + updated_by_id: 1, + ) + + ticket1 = Ticket.create( + title: "some title\n äöüß", + group: Group.lookup(name: 'Users'), + customer_id: 2, + state: Ticket::State.lookup(name: 'new'), + priority: Ticket::Priority.lookup(name: '2 normal'), + updated_by_id: 1, + created_by_id: 1, + ) + assert(ticket1, 'ticket1 created') + + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(0, ticket1.articles.count, 'ticket1.articles verify') + + Observer::Transaction.commit + + ticket1 = Ticket.lookup(id: ticket1.id) + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('3 high', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(1, ticket1.articles.count, 'ticket1.articles verify') + + ticket1.priority = Ticket::Priority.lookup(name: '2 normal') + ticket1.save + + Observer::Transaction.commit + + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(1, ticket1.articles.count, 'ticket1.articles verify') + + ticket1.state = Ticket::State.lookup(name: 'open') + ticket1.save + + Observer::Transaction.commit + + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('open', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(1, ticket1.articles.count, 'ticket1.articles verify') + + ticket1.state = Ticket::State.lookup(name: 'new') + ticket1.save + + Observer::Transaction.commit + + ticket1 = Ticket.lookup(id: ticket1.id) + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(1, ticket1.articles.count, 'ticket1.articles verify') + + Trigger.destroy_all + end + + test '2 actions - update' do + trigger1 = Trigger.create_or_update( + name: 'auto reply', + condition: { + 'ticket.action' => { + 'operator' => 'is', + 'value' => 'update', + }, + 'ticket.state_id' => { + 'operator' => 'is', + 'value' => Ticket::State.lookup(name: 'new').id.to_s, + } + }, + perform: { + 'notification.email' => { + 'body' => 'dasdasdasd', + 'recipient' => 'ticket_customer', + 'subject' => 'asdasdas', + }, + 'ticket.priority_id' => { + 'value' => Ticket::Priority.lookup(name: '3 high').id.to_s, + }, + }, + disable_notification: true, + active: true, + created_by_id: 1, + updated_by_id: 1, + ) + + ticket1 = Ticket.create( + title: "some title\n äöüß", + group: Group.lookup(name: 'Users'), + customer_id: 2, + state: Ticket::State.lookup(name: 'new'), + priority: Ticket::Priority.lookup(name: '2 normal'), + updated_by_id: 1, + created_by_id: 1, + ) + assert(ticket1, 'ticket1 created') + + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(0, ticket1.articles.count, 'ticket1.articles verify') + + Observer::Transaction.commit + + ticket1 = Ticket.lookup(id: ticket1.id) + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(0, ticket1.articles.count, 'ticket1.articles verify') + + ticket1.priority = Ticket::Priority.lookup(name: '2 normal') + ticket1.save + + Observer::Transaction.commit + + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(0, ticket1.articles.count, 'ticket1.articles verify') + + ticket1.state = Ticket::State.lookup(name: 'open') + ticket1.save + + Observer::Transaction.commit + + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('open', ticket1.state.name, 'ticket1.state verify') + assert_equal('2 normal', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(0, ticket1.articles.count, 'ticket1.articles verify') + + ticket1.state = Ticket::State.lookup(name: 'new') + ticket1.save + + Observer::Transaction.commit + + ticket1 = Ticket.lookup(id: ticket1.id) + assert_equal('some title äöüß', ticket1.title, 'ticket1.title verify') + assert_equal('Users', ticket1.group.name, 'ticket1.group verify') + assert_equal('new', ticket1.state.name, 'ticket1.state verify') + assert_equal('3 high', ticket1.priority.name, 'ticket1.priority verify') + assert_equal(1, ticket1.articles.count, 'ticket1.articles verify') + + Trigger.destroy_all + end + +end