diff --git a/app/assets/javascripts/app/controllers/_application_controller_table.coffee b/app/assets/javascripts/app/controllers/_application_controller_table.coffee index f2b51dcc6..b7c38d97f 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_table.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_table.coffee @@ -1,15 +1,25 @@ class App.ControllerTable extends App.Controller - minColWidth: 20 constructor: (params) -> for key, value of params @[key] = value - @table = @tableGen(params) + # apply personal preferences + data = @preferencesGet() + if data['order'] + for key, value of data['order'] + @[key] = value - if @el - @el.append( @table ) + @headerWidth = {} + if data['headerWidth'] + for key, value of data['headerWidth'] + @headerWidth[key] = value + + @render() + + render: => + @html(@tableGen()) ### @@ -51,6 +61,7 @@ class App.ControllerTable extends App.Controller value new App.ControllerTable( + table_id: 'some_id_to_idientify_user_based_table_preferences' el: element overview: ['host', 'user', 'adapter', 'active'] model: App.Channel @@ -98,38 +109,38 @@ class App.ControllerTable extends App.Controller ### - tableGen: (data) -> - if !data.model - data.model = {} - overview = data.overview || data.model.configure_overview || [] - attributes = data.attributes || data.model.configure_attributes || {} + tableGen: => + if !@model + @model = {} + overview = @overview || @model.configure_overview || [] + attributes = @attributes || @model.configure_attributes || {} attributes = App.Model.attributesGet(false, attributes) - destroy = data.model.configure_delete + destroy = @model.configure_delete # check if table is empty - if _.isEmpty(data.objects) + if _.isEmpty(@objects) table = App.view('generic/admin/empty') - explanation: data.explanation + explanation: @explanation return $(table) # group by - if data.groupBy + if @groupBy # remove group by attribute from header overview = _.filter( overview (item) -> - return item if item isnt data.groupBy + return item if item isnt @groupBy return ) # get new order groupObjects = _.groupBy( - data.objects + @objects (item) -> - return '' if !item[data.groupBy] - return item[data.groupBy].displayName() if item[data.groupBy].displayName - item[data.groupBy] + return '' if !item[@groupBy] + return item[@groupBy].displayName() if item[@groupBy].displayName + item[@groupBy] ) groupOrder = [] for group, value of groupObjects @@ -143,41 +154,71 @@ class App.ControllerTable extends App.Controller ) # create new data array - data.objects = [] + @objects = [] for group in groupOrder - data.objects = data.objects.concat groupObjects[group] + @objects = @objects.concat groupObjects[group] groupObjects[group] = [] # release old array # get header data - header = [] + headers = [] for item in overview headerFound = false for attributeName, attribute of attributes if attributeName is item headerFound = true - header.push attribute + if @headerWidth[attribute.name] + attribute.style = "width: #{@headerWidth[attribute.name]}px" + headers.push attribute else rowWithoutId = item + '_id' if attributeName is rowWithoutId headerFound = true - header.push attribute + if @headerWidth[attribute.name] + attribute.style = "width: #{@headerWidth[attribute.name]}px" + headers.push attribute + + if @orderDirection && @orderBy + for header in headers + if header.name is @orderBy + @objects = _.sortBy( + @objects + (item) -> + # if we need to sort translated col. + if header.translate + App.i18n.translateInline(item[header.name]) + # if we need to sort a relation + if header.relation + if item[header.name] + App[header.relation].find(item[header.name]).displayName() + else + '' + else + item[header.name] + ) + if @orderDirection is 'DESC' + header.sortOrderIcon = ['arrow-down', 'table-sort-arrow'] + @objects = @objects.reverse() + else + header.sortOrderIcon = ['arrow-up', 'table-sort-arrow'] + else + header.sortOrderIcon = undefined # execute header callback - if data.callbackHeader - for callback in data.callbackHeader - header = callback(header) + if @callbackHeader + for callback in @callbackHeader + headers = callback(headers) # get content - @log 'debug', 'table', 'header', header, 'overview', 'objects', data.objects + @log 'debug', 'table', 'header', headers, 'overview', 'objects', @objects table = App.view('generic/table')( - header: header - objects: data.objects - checkbox: data.checkbox - radio: data.radio - groupBy: data.groupBy - class: data.class + header: headers + objects: @objects + checkbox: @checkbox + radio: @radio + groupBy: @groupBy + class: @class destroy: destroy - callbacks: data.callbackAttributes + callbacks: @callbackAttributes ) # convert to jquery object @@ -189,15 +230,15 @@ class App.ControllerTable extends App.Controller #mouseover: 'alias' # bind col. - if data.bindCol - for name, item of data.bindCol + if @bindCol + for name, item of @bindCol if item.events position = 0 - if data.checkbox + if @checkbox position += 1 hit = false - for headerName in header + for headerName in headers if !hit position += 1 if headerName.name is name || headerName.name is "#{name}_id" @@ -216,9 +257,9 @@ class App.ControllerTable extends App.Controller ) # bind row - if data.bindRow - if data.bindRow.events - for event, callback of data.bindRow.events + if @bindRow + if @bindRow.events + for event, callback of @bindRow.events do (table, event, callback) -> if cursorMap[event] table.find('tbody > tr').css( 'cursor', cursorMap[event] ) @@ -229,9 +270,9 @@ class App.ControllerTable extends App.Controller ) # bind bindCheckbox - if data.bindCheckbox - if data.bindCheckbox.events - for event, callback of data.bindCheckbox.events + if @bindCheckbox + if @bindCheckbox.events + for event, callback of @bindCheckbox.events do (table, event, callback) -> table.delegate('input[name="bulk"]', event, (e) -> e.stopPropagation() @@ -241,27 +282,30 @@ class App.ControllerTable extends App.Controller ) # bind on delete dialog - if data.model && destroy + if @model && destroy table.delegate('[data-type="destroy"]', 'click', (e) => e.stopPropagation() e.preventDefault() itemId = $(e.target).parents('tr').data('id') - item = data.model.find(itemId) + item = @model.find(itemId) new App.ControllerGenericDestroyConfirm( item: item container: @container ) ) - # enable resize column - table.on 'mousedown', '.js-col-resize', @onColResizeMousedown - table.on 'click', '.js-col-resize', @stopPropagation + # if we have a personalised table + if @table_id - # enable sort column - table.on 'click', '.js-sort', @sortByColumn + # enable resize column + table.on 'mousedown', '.js-col-resize', @onColResizeMousedown + table.on 'click', '.js-col-resize', @stopPropagation + + # enable sort column + table.on 'click', '.js-sort', @sortByColumn # enable checkbox bulk selection - if data.checkbox + if @checkbox # click first tr>td, catch click table.delegate('tr > td:nth-child(1)', event, (e) -> @@ -285,7 +329,7 @@ class App.ControllerTable extends App.Controller ) ) - return table + table stopPropagation: (event) => event.stopPropagation() @@ -304,7 +348,7 @@ class App.ControllerTable extends App.Controller # use pixels while moving for max precision difference = event.pageX - @resizeStartX - if @resizeLeftStartWidth + difference < @minColWidth or + if @resizeLeftStartWidth + difference < @minColWidth or @resizeRightStartWidth - difference < @minColWidth return @@ -316,17 +360,53 @@ class App.ControllerTable extends App.Controller # switch to percentage resizeBaseWidth = @resizeTargetLeft.parents('table').width() leftWidth = @resizeTargetLeft.outerWidth() - rightWidth= @resizeTargetRight.outerWidth() + rightWidth = @resizeTargetRight.outerWidth() leftColumnKey = @resizeTargetLeft.attr('data-column-key') rightColumnKey = @resizeTargetRight.attr('data-column-key') # save table changed widths - # @storeColWidths [ - # { key: leftColumnKey, width: leftWidth } - # { key: rightColumnKey, width: rightWidth } - # ] + storeColWidths = [ + { key: leftColumnKey, width: leftWidth } + { key: rightColumnKey, width: rightWidth } + ] + + @log 'error', @table_id, 'leftColumnKey', leftColumnKey, leftWidth, 'rightColumnKey', rightColumnKey, rightWidth + @preferencesStore('headerWidth', leftColumnKey, leftWidth) + @preferencesStore('headerWidth', rightColumnKey, rightWidth) sortByColumn: (event) => column = $(event.currentTarget).closest('[data-column-key]').attr('data-column-key') - # sort \ No newline at end of file + + # sort + if @orderBy isnt column + @orderBy = column + @orderDirection = 'ASC' + else + if @orderDirection is 'ASC' + @orderDirection = 'DESC' + else + @orderDirection = 'ASC' + + @log 'debug', @table_id, 'sortByColumn', @orderBy, 'direction', @orderDirection + @preferencesStore('order', 'orderBy', @orderBy) + @preferencesStore('order', 'orderDirection', @orderDirection) + @render() + + preferencesStore: (type, key, value) -> + data = @preferencesGet() + if !data[type] + data[type] = {} + if !data[type][key] + data[type][key] = {} + data[type][key] = value + localStorage.setItem(@preferencesStoreKey(), JSON.stringify(data)) + + preferencesGet: => + storeKey = @preferencesStoreKey() + data = localStorage.getItem(storeKey) + return {} if !data + JSON.parse(data) + + preferencesStoreKey: => + "tablePreferences:#{@table_id}" diff --git a/app/assets/javascripts/app/controllers/ticket_overview.coffee b/app/assets/javascripts/app/controllers/ticket_overview.coffee index 203325128..0cf8839a8 100644 --- a/app/assets/javascripts/app/controllers/ticket_overview.coffee +++ b/app/assets/javascripts/app/controllers/ticket_overview.coffee @@ -273,19 +273,6 @@ class Table extends App.Controller headers.unshift(0) headers[0] = attribute headers - callbackSortOrderHeader = (headers) => - return headers if !@overview - return headers if !@overview.order - return headers if !@overview.order.by - for header in headers - if header.name is @overview.order.by - if @overview.order.direction is 'DESC' - header.sortOrderIcon = ['arrow-down', 'table-sort-arrow'] - else - header.sortOrderIcon = ['arrow-up', 'table-sort-arrow'] - else - header.sortOrderIcon = undefined - headers callbackIcon = (value, object, attribute, header, refObject) -> value = ' ' attribute.class = object.iconClass() @@ -294,12 +281,15 @@ class Table extends App.Controller value new App.ControllerTable( - overview: @overview.view.s - el: @$('.table-overview') - model: App.Ticket - objects: ticket_list_show - checkbox: checkbox - groupBy: @overview.group_by + table_id: "ticket_overview_#{@overview_id}" + overview: @overview.view.s + el: @$('.table-overview') + model: App.Ticket + objects: ticket_list_show + checkbox: checkbox + groupBy: @overview.group_by + orderBy: @overview.order.by + orderDirection: @overview.order.direction bindRow: events: 'click': openTicket @@ -307,7 +297,7 @@ class Table extends App.Controller # customer_id: # events: # 'mouseover': popOver - callbackHeader: [ callbackIconHeader, callbackSortOrderHeader ] + callbackHeader: [ callbackIconHeader ] callbackAttributes: icon: [ callbackIcon ] diff --git a/app/assets/javascripts/app/controllers/ticket_zoom.coffee b/app/assets/javascripts/app/controllers/ticket_zoom.coffee index 20b7d9ce3..5d9a188f6 100644 --- a/app/assets/javascripts/app/controllers/ticket_zoom.coffee +++ b/app/assets/javascripts/app/controllers/ticket_zoom.coffee @@ -547,6 +547,15 @@ class App.TicketZoom extends App.Controller # validate article articleParams = @formParam( @$('.article-add') ) console.log 'submit article', articleParams + + # check if attachment exists but no body + attachmentCount = @$('.article-add .textBubble .attachments .attachment').length + if !articleParams['body'] && attachmentCount > 0 + if !confirm( App.i18n.translateContent('Please fill also some text in!') ) + @formEnable(e) + @autosaveStart() + return + if articleParams['body'] articleParams.from = @Session.get().displayName() articleParams.ticket_id = ticket.id @@ -590,12 +599,11 @@ class App.TicketZoom extends App.Controller # check attachment if articleParams['body'] - if App.Utils.checkAttachmentReference( articleParams['body'] ) - if @$('.article-add .textBubble .attachments .attachment').length < 1 - if !confirm( App.i18n.translateContent('You use attachment in text but no attachment is attached. Do you want to continue?') ) - @formEnable(e) - @autosaveStart() - return + if App.Utils.checkAttachmentReference( articleParams['body'] ) && attachmentCount < 1 + if !confirm( App.i18n.translateContent('You use attachment in text but no attachment is attached. Do you want to continue?') ) + @formEnable(e) + @autosaveStart() + return article.load(articleParams) errors = article.validate() diff --git a/app/assets/javascripts/app/views/generic/table.jst.eco b/app/assets/javascripts/app/views/generic/table.jst.eco index af5a8a533..5da2fab2d 100644 --- a/app/assets/javascripts/app/views/generic/table.jst.eco +++ b/app/assets/javascripts/app/views/generic/table.jst.eco @@ -15,8 +15,8 @@ <% end %> <% for item, i in @header: %> <%= " style='#{ item.style }'" if item.style %> data-column-key="<%= item.name %>"> -
-
+
+
<%- @T( item.display ) %>
diff --git a/app/models/user.rb b/app/models/user.rb index 3c76b8c40..83a4be3c6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -536,6 +536,7 @@ returns return if !email return if email.empty? + return if email !~ /@/ # save/update avatar avatar = Avatar.auto_detection( diff --git a/test/browser/agent_ticket_actions_level6_test.rb b/test/browser/agent_ticket_actions_level6_test.rb index 8b5b5f9e5..096b44d3d 100644 --- a/test/browser/agent_ticket_actions_level6_test.rb +++ b/test/browser/agent_ticket_actions_level6_test.rb @@ -107,6 +107,44 @@ class AgentTicketActionLevel6Test < TestCase value: 'test 6 - ticket 1-1', ) + # add attachment without body + @browser.execute_script( "App.TestHelper.attachmentUploadFake('.active .article-add .textBubble .attachments')" ) + + # submit form + click( + css: '.active .js-submit', + ) + sleep 2 + + # check warning + alert = @browser.switch_to.alert + alert.dismiss() + + ticket_update( + data: { + body: 'now submit should work', + }, + do_not_submit: true, + ) + + # submit form + click( + css: '.active .js-submit', + ) + sleep 2 + + # discard changes should gone away + watch_for_disappear( + css: '.content.active .js-reset', + value: '(Discard your unsaved changes.|Verwerfen der)', + no_quote: true, + ) + ticket_verify( + data: { + body: '', + }, + ) + # # ticket customer change checks # diff --git a/test/browser_test_helper.rb b/test/browser_test_helper.rb index eba1b6ed7..31768a43f 100644 --- a/test/browser_test_helper.rb +++ b/test/browser_test_helper.rb @@ -1076,7 +1076,7 @@ wait untill text in selector disabppears element.clear # workaround, sometimes focus is not triggered - element.send_keys( data[:customer] ) + element.send_keys( data[:customer] + '*' ) sleep 3.5 # check if pulldown is open, it's not working stable via selenium diff --git a/test/fixtures/mail35.box b/test/fixtures/mail35.box new file mode 100644 index 000000000..c2ebe04e4 --- /dev/null +++ b/test/fixtures/mail35.box @@ -0,0 +1,63 @@ +From MAILER-DAEMON Wed Oct 21 14:42:20 2015 +Return-Path: <> +X-Original-To: info@example.com +Delivered-To: znuny-sales@arber.example.com +Received-SPF: pass (emea01-am1-obe.outbound.protection.example.com: Sender is authorized to use 'emea01-am1-obe.outbound.protection.example.com' in 'helo' identity (mechanism 'include:spf.protection.example.com' matched)) receiver=arber.example.com; identity=helo; helo=emea01-am1-obe.outbound.protection.example.com; client-ip=7.5.1.1 +Received: from emea01-am1-obe.outbound.protection.example.com (mail-am1hn0251.outbound.protection.example.com [7.5.1.1]) + by arber.example.com (Postfix) with ESMTPS id C45775FE6A + for ; Wed, 21 Oct 2015 14:42:20 +0200 (CEST) +Received: from DB5PR07MB1224.eurprd07.example.com (10.164.41.30) by + DB5PR07MB1271.eurprd07.example.com (10.164.41.149) with Microsoft SMTP + Server (TLS) id 15.1.306.13; Wed, 21 Oct 2015 12:42:19 +0000 +Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=<>; +Received: from [10.254.48.3] (7.1.5.1) by + DB5PR07MB1224.eurprd07.example.com (10.164.41.30) with Microsoft SMTP + Server (TLS) id 15.1.306.13; Wed, 21 Oct 2015 12:42:17 +0000 +Content-Type: text/plain; charset="iso-8859-1" +MIME-Version: 1.0 +Content-Transfer-Encoding: quoted-printable +Content-Description: Mail message body +Subject: Darlehen bieten jetzt bewerben +To: Recipients +From: "finances8@firstfinanceloanfirm.example.com" +Date: Wed, 21 Oct 2015 13:42:12 +0100 +Reply-To: +X-Originating-IP: [7.1.5.1] +X-ClientProxiedBy: HE1PR08CA0021.eurprd08.example.com (2.1.1.3) To + DB5PR07MB1224.eurprd07.example.com (2.1.1.3) +Message-ID: +X-Microsoft-Exchange-Diagnostics: 1;DB5PR07MB1224;2:DvCxn5dPPr2amttb4PujSx7+t6AMFJ+bMPumYN+Dk+H69oto3H01nPU6iR11JyZqjYuc39aPa1k5lilg1WbAYYC0kHdc2mKQP3cz6inS9RukNIIjp80dpFcfU8yflVZsNY8ZgQpWUUY7t8/8kVwNIk4irQFGZXQoXvabUNTR0WE=;3:cJIJTbFfruxjzzq+oDnnGOByaWjKlJGDX3cpo5L+mAR1hw2L5a0fZMkF3wYG+q+GZ8gm2Ylq6Mqhfe6fE0w4uQLvzgqAmKpB3fRRKpApA2W/raC1ervusTDeQp52bwLkuFDfafHeNQyk2ZKMsnFPdQ==;25:ZG++cyGnY1E1dIVYBdN/Zy/fWvaRwl1E1dSpIYrR18AaPp28qkBntNH1fJG8RZLm/ZyOXWGw9Yj6u9ycoyUSCUKmNWSPdSSUfbAoKlwBnZLbzpwmYToJzorzroT+EVXsCkCrGkfMfok+gjpl9H+9az4RQrW8rhwMhSIdA/Ilc3Kd+rNgBJ4sOSqGS7nTbtZHBbW81iXT++s4ab0Jh5KvMc43ue6tDVfHYc3rd1Trr7bBGV+iyE0wtgg164SEMp+3mOaFVMI6UmnL+IDj+bOZGA== +X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:DB5PR07MB1224; +X-Microsoft-Antispam-PRVS: +X-Exchange-Antispam-Report-Test: UriScan:; +X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(601004)(2401047)(5005006)(520078)(8121501046)(3002001)(102115026)(6004014)(6003046);SRVR:DB5PR07MB1224;BCL:0;PCL:0;RULEID:;SRVR:DB5PR07MB1224; +X-Microsoft-Exchange-Diagnostics: 1;DB5PR07MB1224;4:nnPVuJcrP/HGkCckgwKl7aJvC3EaZ0krj8ntX+WiSR1I+giYX9zPNwiki/7fIAWLYxxG0/aIQ//rReEVZrd/V2EH+PiNIDAHyVGNKBrGHB2R8P4vyh1fHBs8j1bEKNxn+t+4cFXEs7HYuSej9JY/BnQ34PnAsyViJtlWyibsUufjDNziP9JprRSgQf5zcSyffl73Ut0tY6pbX0v9ACVplnon07EhYYRfiBeu2cl6omrPINzMKDUt0BHunryPvXPOMl59CjTavddWiX0aJp/6ZwjF9R7nmgg9hS265qdEUOVhUPEe7cXjC8J3MLvq0auhgaJJVzNtmif56p4CW4eq2XMFbLthte3ORVmY9D8dhcR7tnHh/k9DLTx4zxUrFQWQPx86GNoo4mNssG4uGzUnHtetiDh9OtJbEL6s0aDZQVg=;23:0DFgc9QSh0ZIGritIv/KheEacJ7MAOinGXlKMABgvrIv9kljhHyju2F3owCE3OSUEedBv1vFu2s8OZnJ4m39lvMSxNIrow2MI29QxsoczYojmWHTECeAvkzJ4BYOhR4V0+iv1k1j4jDPFc9eVVY1Wel/ZJuS5DUIdNND9DnUwA2Zyzjm7ng7LF0znPz49lTbW/dkVCg6w4poryjMKWF3+xxT8Wefz7IonyAj+rI666JjaHVgk4puOoRAnDMHdvBF;5:P3QUjzpnvXNdNhdd5ZBd2CjBrl8LjhhxuAV/rMzKVdJCZh8FW6/ILeucXd8JU98DA8RrICLmdb1hbv2KBz4KexXoUD/VQYTn2qAjNqeIChjcjflvgsf6PwlPh4bs9HD+VK8NUSzGd21NkCznQFJaAQ==;24:JiXy13k+O7JUOG7IkzPwFd4RbRutN4QyGqlwL0SWbYsF86ynPrmE0/MLL0JCRqEzzED4KqdqJ2pQ1w86dG0EcA== +X-Forefront-PRVS: 073631BD3D +X-Forefront-Antispam-Report: SFV:SPM;SFS:(10019020)(6009001)(6049001)(5005620100007);DIR:OUT;SFP:1501;SCL:9;SRVR:DB5PR07MB1224;H:[10.254.48.3];FPR:;SPF:None;PTR:InfoNoRecords;LANG:de; +Received-SPF: None (protection.example.com: [10.254.48.3] does not designate + permitted sender hosts) +SpamDiagnosticOutput: 1:22 +SpamDiagnosticMetadata: 00000000%2D0000%2D0000%2D0000%2D000000000000 +X-Microsoft-Exchange-Diagnostics: 1;DB5PR07MB1224;20:zTAZboReXzFThEimKWUfvgFhjfgaw9a0rToyXCe6+Kb8dHZcQ9EjKmYZWkE62uOnvD4VLpAKakk1FJwRcDxBBA== +X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Oct 2015 12:42:17.1900 + (UTC) +X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted +X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB5PR07MB1224 +X-Microsoft-Exchange-Diagnostics: 1;DB5PR07MB1271;2:5HuMfuoIxYZexWzVgqBch/cN+KXYALcB840unggr+hi7mPMTcPb63gD0Z0sgz1HuRne2t9tCnGlWIfcn7XCzXAAHvuIYuHjTHbFaj/WV0iy94Ehgo6XuM5GfqRlGTuUa/LyJi/BcfZ0jchcBrVjVt0Izn4+UB09P6yRq1/A0YjA=;23:mJyNLyB8E9W7POa18G8yfp1BVI8DgT6RzrItoW2V7KLBKMxiHx443g93/0YeXjBYWpeaIaMy5B9GA5i17vOeCKJZs+LimKbls83Ia+npZB7SXdJj6mBaWAdGwmW9lJ8ePnh1YjSS2oNXepT+uy7E6FZPxqWh3HDN8GJ8u/LJzupxeISrRds+T9crHSexnyVz +X-OriginatorOrg: firstfinanceloanfirm.example.com +X-UID: 3783 +Status: RO +Content-Length: 397 +Lines: 10 + +Beantworten :firstfinancelender@example.com + +Ich Mr.Squires Peter ist eine zuverl=E4ssige Kreditangebot mit einer +Rate von 1.5% f=FCr den Zeitraum von 1 bis 40yrs nur, von der minimalen +von 5,000.00euro sie an die maximale Menge an 150,000.000.00euro, so +dass f=FCr mehr Details, wenn interessiert kontaktieren Sie mich unter + +firstfinancelender@example.com + +Beantworten :firstfinancelender@example.com + diff --git a/test/unit/email_process_test.rb b/test/unit/email_process_test.rb index ab2996246..77460ee25 100644 --- a/test/unit/email_process_test.rb +++ b/test/unit/email_process_test.rb @@ -1953,6 +1953,30 @@ Some Text', ], } }, + { + data: IO.read('test/fixtures/mail35.box'), + success: true, + result: { + 0 => { + priority: '2 normal', + title: 'Darlehen bieten jetzt bewerben', + }, + 1 => { + sender: 'Customer', + type: 'email', + }, + }, + verify: { + users: [ + { + firstname: '', + lastname: '', + fullname: '"finances8@firstfinanceloanfirm.example.com"', + email: '"finances8@firstfinanceloanfirm.example.com"', + }, + ], + } + }, ] process(files) end