diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 7bc833f35..24a77506f 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -6,6 +6,8 @@ Hi there - thanks for filling an issue. Please ensure the following things befor - Add the `log/production.log` file from your system. Attention: Make sure no confidential data is in it! - Please write the issue in english +Note: We always do our best. Unfortunately, sometimes the requests are too much and we can't handle everything at once. If you want to prioritize/escalate your issue, you can do so by means of a support contract (see https://zammad.com/pricing#selfhosted). + * The upper textblock will be removed automatically when you submit your issue * --> diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8ce7141b6..e03893101 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -278,6 +278,18 @@ test:integration:telegram: - ruby -I test test/integration/telegram_controller_test.rb - rake db:drop +test:integration:idoit: + stage: test + tags: + - core + script: + - export RAILS_ENV=test + - rake db:create + - rake db:migrate + - rake db:seed + - ruby -I test test/integration/idoit_controller_test.rb + - rake db:drop + test:integration:es_mysql: stage: test tags: diff --git a/Gemfile b/Gemfile index 356bc0c67..81955ce14 100644 --- a/Gemfile +++ b/Gemfile @@ -2,7 +2,7 @@ source 'https://rubygems.org' ruby '2.4.1' -gem 'rails', '5.0.5' +gem 'rails', '5.1.4' gem 'rails-observers' gem 'activerecord-session_store' @@ -53,7 +53,8 @@ gem 'mime-types' gem 'biz' -gem 'composite_primary_keys' +# temporary till pull request gets merged: https://github.com/composite-primary-keys/composite_primary_keys/pull/404 +gem 'composite_primary_keys', git: 'https://github.com/jkowens/composite_primary_keys.git', branch: 'rails-5_1' gem 'delayed_job_active_record' gem 'daemons' diff --git a/Gemfile.lock b/Gemfile.lock index 81c5c7655..2e8065d0f 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,11 @@ +GIT + remote: https://github.com/jkowens/composite_primary_keys.git + revision: 7f4670b54b3c6e94992161b4efe2c8717d7c0e71 + branch: rails-5_1 + specs: + composite_primary_keys (9.0.7) + activerecord (~> 5.1.0) + GIT remote: https://github.com/thorsteneckel/autodiscover.git revision: 29d713ee0c8c25fcf74c4292ff13fe1fa4d0d827 @@ -17,38 +25,38 @@ GIT GEM remote: https://rubygems.org/ specs: - actioncable (5.0.5) - actionpack (= 5.0.5) - nio4r (>= 1.2, < 3.0) + actioncable (5.1.4) + actionpack (= 5.1.4) + nio4r (~> 2.0) websocket-driver (~> 0.6.1) - actionmailer (5.0.5) - actionpack (= 5.0.5) - actionview (= 5.0.5) - activejob (= 5.0.5) + actionmailer (5.1.4) + actionpack (= 5.1.4) + actionview (= 5.1.4) + activejob (= 5.1.4) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.0.5) - actionview (= 5.0.5) - activesupport (= 5.0.5) + actionpack (5.1.4) + actionview (= 5.1.4) + activesupport (= 5.1.4) rack (~> 2.0) - rack-test (~> 0.6.3) + rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.0.5) - activesupport (= 5.0.5) + actionview (5.1.4) + activesupport (= 5.1.4) builder (~> 3.1) - erubis (~> 2.7.0) + erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (5.0.5) - activesupport (= 5.0.5) + activejob (5.1.4) + activesupport (= 5.1.4) globalid (>= 0.3.6) - activemodel (5.0.5) - activesupport (= 5.0.5) - activerecord (5.0.5) - activemodel (= 5.0.5) - activesupport (= 5.0.5) - arel (~> 7.0) + activemodel (5.1.4) + activesupport (= 5.1.4) + activerecord (5.1.4) + activemodel (= 5.1.4) + activesupport (= 5.1.4) + arel (~> 8.0) activerecord-nulldb-adapter (0.3.7) activerecord (>= 2.0.0) activerecord-session_store (1.1.0) @@ -57,14 +65,14 @@ GEM multi_json (~> 1.11, >= 1.11.2) rack (>= 1.5.2, < 3) railties (>= 4.0, < 5.2) - activesupport (5.0.5) + activesupport (5.1.4) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (~> 0.7) minitest (~> 5.1) tzinfo (~> 1.1) addressable (2.5.2) public_suffix (>= 2.0.2, < 4.0) - arel (7.1.4) + arel (8.0.0) argon2 (1.1.3) ffi (~> 1.9) ffi-compiler (~> 0.1) @@ -94,8 +102,6 @@ GEM coffee-script execjs json - composite_primary_keys (9.0.7) - activerecord (~> 5.0.0) concurrent-ruby (1.0.5) coveralls (0.8.21) json (>= 1.8, < 3) @@ -127,7 +133,7 @@ GEM eventmachine (>= 0.12.9) http_parser.rb (~> 0.6.0) equalizer (0.0.11) - erubis (2.7.0) + erubi (1.6.1) eventmachine (1.2.5) execjs (2.7.0) factory_girl (4.8.0) @@ -219,7 +225,7 @@ GEM thread_safe (~> 0.3, >= 0.3.1) method_source (0.8.2) mime-types (2.99.3) - mini_portile2 (2.2.0) + mini_portile2 (2.3.0) minitest (5.10.3) multi_json (1.12.1) multi_xml (0.6.0) @@ -231,8 +237,8 @@ GEM net-ldap (0.16.0) netrc (0.11.0) nio4r (2.1.0) - nokogiri (1.8.0) - mini_portile2 (~> 2.2.0) + nokogiri (1.8.1) + mini_portile2 (~> 2.3.0) nori (2.6.0) notiffany (0.1.1) nenv (~> 0.1) @@ -279,7 +285,7 @@ GEM rack parser (2.4.0.0) ast (~> 2.2) - pg (0.20.0) + pg (0.21.0) pluginator (1.5.0) power_assert (1.1.0) powerpack (0.1.1) @@ -294,19 +300,19 @@ GEM rack (2.0.3) rack-livereload (0.3.16) rack - rack-test (0.6.3) - rack (>= 1.0) - rails (5.0.5) - actioncable (= 5.0.5) - actionmailer (= 5.0.5) - actionpack (= 5.0.5) - actionview (= 5.0.5) - activejob (= 5.0.5) - activemodel (= 5.0.5) - activerecord (= 5.0.5) - activesupport (= 5.0.5) + rack-test (0.7.0) + rack (>= 1.0, < 3) + rails (5.1.4) + actioncable (= 5.1.4) + actionmailer (= 5.1.4) + actionpack (= 5.1.4) + actionview (= 5.1.4) + activejob (= 5.1.4) + activemodel (= 5.1.4) + activerecord (= 5.1.4) + activesupport (= 5.1.4) bundler (>= 1.3.0) - railties (= 5.0.5) + railties (= 5.1.4) sprockets-rails (>= 2.0.0) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) @@ -315,16 +321,16 @@ GEM loofah (~> 2.0) rails-observers (0.1.5) activemodel (>= 4.0) - railties (5.0.5) - actionpack (= 5.0.5) - activesupport (= 5.0.5) + railties (5.1.4) + actionpack (= 5.1.4) + activesupport (= 5.1.4) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) rainbow (2.2.2) rake raindrops (0.19.0) - rake (12.0.0) + rake (12.1.0) rb-fsevent (0.10.2) rb-inotify (0.9.10) ffi (>= 0.5.0, < 2) @@ -476,7 +482,7 @@ DEPENDENCIES coffee-rails coffee-script-source coffeelint - composite_primary_keys + composite_primary_keys! coveralls daemons delayed_job_active_record @@ -516,7 +522,7 @@ DEPENDENCIES pre-commit puma rack-livereload - rails (= 5.0.5) + rails (= 5.1.4) rails-observers rb-fsevent rspec-rails diff --git a/app/assets/javascripts/app/controllers/_application_controller_generic.coffee b/app/assets/javascripts/app/controllers/_application_controller_generic.coffee index f764e5c57..71789f94c 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_generic.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_generic.coffee @@ -1162,7 +1162,7 @@ class App.ObserverController extends App.Controller @log 'debug', 'new', @object_id, @model if App[@model].exists(@object_id) - @maybeRender( App[@model].fullLocal(@object_id) ) + @maybeRender(App[@model].fullLocal(@object_id)) else App[@model].full(@object_id, @maybeRender) @@ -1170,7 +1170,8 @@ class App.ObserverController extends App.Controller if @globalRerender @bind('ui:rerender', => @lastAttributres = undefined - @maybeRender( App[@model].fullLocal(@object_id) ) + console.log('aaaa', @model, @template) + @maybeRender(App[@model].fullLocal(@object_id)) ) subscribe: (object, typeOfChange) => diff --git a/app/assets/javascripts/app/controllers/_application_controller_table.coffee b/app/assets/javascripts/app/controllers/_application_controller_table.coffee index 429624b1b..1779c7d43 100644 --- a/app/assets/javascripts/app/controllers/_application_controller_table.coffee +++ b/app/assets/javascripts/app/controllers/_application_controller_table.coffee @@ -1,3 +1,94 @@ +### + + # table based on model + + rowClick = (id, e) -> + e.preventDefault() + console.log('rowClick', id) + rowMouseover = (id, e) -> + e.preventDefault() + console.log('rowMouseover', id) + rowMouseout = (id, e) -> + e.preventDefault() + console.log('rowMouseout', id) + rowDblClick = (id, e) -> + e.preventDefault() + console.log('rowDblClick', id) + + colClick = (id, e) -> + e.preventDefault() + console.log('colClick', e.target) + + checkboxClick = (id, e) -> + e.preventDefault() + console.log('checkboxClick', e.target) + + callbackHeader = (headers) -> + console.log('current header is', headers) + # add new header item + attribute = + name: 'some name' + display: 'Some Name' + headers.push attribute + console.log('new header is', headers) + headers + + callbackAttributes = (value, object, attribute, header) -> + console.log('data of item col', value, object, attribute, header) + value = 'New Data To Show' + value + + new App.ControllerTable( + tableId: 'some_id_to_idientify_user_based_table_preferences' + el: element + overview: ['host', 'user', 'adapter', 'active'] + model: App.Channel + objects: data + groupBy: 'adapter' + checkbox: false + radio: false + class: 'some-css-class' + bindRow: + events: + 'click': rowClick + 'mouseover': rowMouseover + 'mouseout': rowMouseout + 'dblclick': rowDblClick + bindCol: + host: + events: + 'click': colClick + bindCheckbox: + events: + 'click': rowClick + 'mouseover': rowMouseover + 'mouseout': rowMouseout + 'dblclick': rowDblClick + callbackHeader: [callbackHeader] + callbackAttributes: + attributeName: [ + callbackAttributes + ] + dndCallback: => + items = @el.find('table > tbody > tr') + console.log('all effected items', items) + ) + + new App.ControllerTable( + el: element + overview: ['time', 'area', 'level', 'browser', 'location', 'data'] + attribute_list: [ + { name: 'time', display: 'Time', tag: 'datetime' }, + { name: 'area', display: 'Area', type: 'text' }, + { name: 'level', display: 'Level', type: 'text' }, + { name: 'browser', display: 'Browser', type: 'text' }, + { name: 'location', display: 'Location', type: 'text' }, + { name: 'data', display: 'Data', type: 'text' }, + ] + objects: data + ) + +### class App.ControllerTable extends App.Controller minColWidth: 40 baseColWidth: 130 @@ -10,9 +101,53 @@ class App.ControllerTable extends App.Controller elements: '.js-tableHead': 'tableHead' - constructor: (params) -> + events: + 'click .js-sort': 'sortByColumn' + + overviewAttributes: undefined + #model: App.TicketPriority, + objects: [] + checkbox: false + radio: false + renderState: undefined + groupBy: undefined + + destroy: false + + columnsLength: undefined + headers: undefined + headerWidth: {} + + currentRows: [] + + orderDirection: 'ASC' + orderBy: undefined + + lastOrderDirection: undefined + lastOrderBy: undefined + lastOverview: undefined + + customOrderDirection: undefined + customOrderBy: undefined + + bindCol: {} + bindRow: {} + + constructor: -> super + if !@model + @model = {} + @overviewAttributes ||= @overview || @model.configure_overview || [] + @attributesListRaw ||= @attribute_list || @model.configure_attributes || {} + @attributesList = App.Model.attributesGet(false, @attributesListRaw) + console.log('Table', @overviewAttributes, @overview) + #@setHeaderWidths = App.Model.setHeaderWidthsGet(false, @attributesList) + @destroy = @model.configure_delete + + throw 'overviewAttributes needed' if _.isEmpty(@overviewAttributes) + throw 'attributesList needed' if _.isEmpty(@attributesList) + # apply personal preferences data = {} if @tableId @@ -21,20 +156,218 @@ class App.ControllerTable extends App.Controller for key, value of data.order @[key] = value - @headerWidth = {} if data.headerWidth for key, value of data.headerWidth @headerWidth[key] = value @availableWidth = @el.width() - @render() - $(window).on 'resize.table', @onResize + + @renderQueue() release: => $(window).off 'resize.table', @onResize + update: (params) => + console.log('params', params) + for key, value of params + @[key] = value + + if params.sync is true + return @render() + @renderQueue() + + renderQueue: => + App.QueueManager.add('tableRender', @render) + App.QueueManager.run('tableRender') + render: => - @html @tableGen() + if @renderState is undefined + + # check if table is empty + if _.isEmpty(@objects) + @renderState = 'emptyList' + @el.html(@renderEmptyList()) + $(window).on 'resize.table', @onResize + return ['emptyList.new'] + else + @renderState = 'List' + @renderTableFull() + $(window).on 'resize.table', @onResize + return ['fullRender.new'] + else if @renderState is 'emptyList' && !_.isEmpty(@objects) + @renderState = 'List' + @renderTableFull() + return ['fullRender'] + else if @renderState isnt 'emptyList' && _.isEmpty(@objects) + @renderState = 'emptyList' + @el.html(@renderEmptyList()) + return ['emptyList'] + else + + # check if header has changed + if @tableHeadersHasChanged() + @renderTableFull() + return ['fullRender.overviewAttributesChanged'] + + # check for changes + newRows = @renderTableRows(true) + removedRows = _.difference(@currentRows, newRows) + addedRows = _.difference(newRows, @currentRows) + + # if only rows are removed + if _.isEmpty(addedRows) && !_.isEmpty(removedRows) && removedRows.length < 15 && !_.isEmpty(newRows) + newCurrentRows = [] + removePositions = [] + for position in [0..@currentRows.length-1] + if _.contains(removedRows, @currentRows[position]) + removePositions.push position + else + newCurrentRows.push @currentRows[position] + + # check if order is still correct + if @_isSame(newRows, newCurrentRows) is true + for position in removePositions + @$("tbody > tr:nth-child(#{position+1})").remove() + @currentRows = newCurrentRows + console.log('fullRender.contentRemoved', removePositions) + return ['fullRender.contentRemoved', removePositions] + + if newRows.length isnt @currentRows.length + result = ['fullRender.lenghtChanged', @currentRows.length, newRows.length] + @renderTableFull(newRows) + console.log('result', result) + return result + + # compare rows + result = @_isSame(newRows, @currentRows) + if result isnt true + @renderTableFull(newRows) + console.log('result', "fullRender.contentChanged|row(#{result})") + return ['fullRender.contentChanged', result] + + console.log('result', 'noChanges') + return ['noChanges'] + + renderEmptyList: => + App.view('generic/admin/empty')( + explanation: @explanation + ) + + renderTableFull: (rows) => + console.log('renderTableFull', @orderBy, @orderDirection) + @tableHeaders() + @sortList() + bulkIds = @getBulkSelected() + container = @renderTableContainer() + if !rows + rows = @renderTableRows() + @currentRows = clone(rows) + else + @currentRows = clone(rows) + container.find('.js-tableBody').html(rows) + + cursorMap = + click: 'pointer' + dblclick: 'pointer' + #mouseover: 'alias' + + # bind col. + if !_.isEmpty(@bindCol) + for name, item of @bindCol + if item.events + position = 0 + if @dndCallback + position += 1 + if @checkbox + position += 1 + hit = false + + for headerName in @headers + if !hit + position += 1 + if headerName.name is name || headerName.name is "#{name}_id" || headerName.name is "#{name}_bulkIds" + hit = true + + if hit + for event, callback of item.events + do (container, event, callback) -> + if cursorMap[event] + container.find("tbody > tr > td:nth-child(#{position})").css('cursor', cursorMap[event]) + container.on( event, "tbody > tr > td:nth-child(#{position})", + (e) -> + e.stopPropagation() + id = $(e.target).parents('tr').data('id') + callback(id, e) + ) + + # bind row + if !_.isEmpty(@bindRow) + if @bindRow.events + for event, callback of @bindRow.events + do (container, event, callback) -> + if cursorMap[event] + container.find('tbody > tr').css( 'cursor', cursorMap[event] ) + container.on( event, 'tbody > tr', + (e) -> + id = $(e.target).parents('tr').data('id') + callback(id, e) + ) + + # bind bindCheckbox + if @bindCheckbox + if @bindCheckbox.events + for event, callback of @bindCheckbox.events + do (container, event, callback) -> + container.delegate('input[name="bulk"]', event, (e) -> + e.stopPropagation() + id = $(e.currentTarget).parents('tr').data('id') + checked = $(e.currentTarget).prop('checked') + callback(id, checked, e) + ) + + # if we have a personalised table + if @tableId + + # enable resize column + container.on 'mousedown', '.js-col-resize', @onColResizeMousedown + container.on 'click', '.js-col-resize', @stopPropagation + + # enable checkbox bulk selection + if @checkbox + + # click first tr>td, catch click + container.delegate('tr > td:nth-child(1)', 'click', (e) -> + e.stopPropagation() + ) + + # bind on full bulk click + container.delegate('input[name="bulk_all"]', 'change', (e) => + e.stopPropagation() + clicks = [] + if $(e.currentTarget).prop('checked') + $(e.currentTarget).parents('table').find('[name="bulk"]').each( -> + $element = $(@) + return if $element.prop('checked') + $element.prop('checked', true) + id = $element.parents('tr').data('id') + clicks.push [id, true] + ) + else + $(e.currentTarget).parents('table').find('[name="bulk"]').each( -> + $element = $(@) + return if !$element.prop('checked') + $element.prop('checked', false) + id = $element.parents('tr').data('id') + clicks.push [id, false] + ) + return if !@bindCheckbox + return if !@bindCheckbox.events + return if _.isEmpty(clicks) + for event, callback of @bindCheckbox.events + if event == 'click' || event == 'change' + for click in clicks + callback(click..., e) + ) if @dndCallback dndOptions = @@ -50,121 +383,79 @@ class App.ControllerTable extends App.Controller # Set helper cell sizes to match the original sizes $(@).width( originals.eq(index).outerWidth() ) return helper - update: @dndCallback - @el.find('table > tbody').sortable(dndOptions) + update: @dndCallback + container.find('tbody').sortable(dndOptions) - ### + @el.html(container) + @setBulkSelected(bulkIds) - # table based on model + renderTableContainer: => + $(App.view('generic/table')( + tableId: @tableId + headers: @headers + checkbox: @checkbox + radio: @radio + class: @class + sortable: @dndCallback + )) - rowClick = (id, e) -> - e.preventDefault() - console.log('rowClick', id) - rowMouseover = (id, e) -> - e.preventDefault() - console.log('rowMouseover', id) - rowMouseout = (id, e) -> - e.preventDefault() - console.log('rowMouseout', id) - rowDblClick = (id, e) -> - e.preventDefault() - console.log('rowDblClick', id) + renderTableRows: (sort = false) => + if sort is true + @sortList() + position = 0 + columnsLength = @headers.length + if @checkbox || @radio + columnsLength++ + groupLast = '' + tableBody = [] + for object in @objects + position++ + if @groupBy + groupByName = App.viewPrint(object, @groupBy, @attributesList) + if groupLast isnt groupByName + groupLast = groupByName + tableBody.push @renderTableGroupByRow(object, position, groupByName) + tableBody.push @renderTableRow(object, position) + tableBody - colClick = (id, e) -> - e.preventDefault() - console.log('colClick', e.target) - - checkboxClick = (id, e) -> - e.preventDefault() - console.log('checkboxClick', e.target) - - callbackHeader = (headers) -> - console.log('current header is', headers) - # add new header item - attribute = - name: 'some name' - display: 'Some Name' - headers.push attribute - console.log('new header is', headers) - headers - - callbackAttributes = (value, object, attribute, header) -> - console.log('data of item col', value, object, attribute, header) - value = 'New Data To Show' - value - - new App.ControllerTable( - tableId: 'some_id_to_idientify_user_based_table_preferences' - el: element - overview: ['host', 'user', 'adapter', 'active'] - model: App.Channel - objects: data - groupBy: 'adapter' - checkbox: false - radio: false - class: 'some-css-class' - bindRow: - events: - 'click': rowClick - 'mouseover': rowMouseover - 'mouseout': rowMouseout - 'dblclick': rowDblClick - bindCol: - host: - events: - 'click': colClick - bindCheckbox: - events: - 'click': rowClick - 'mouseover': rowMouseover - 'mouseout': rowMouseout - 'dblclick': rowDblClick - callbackHeader: [callbackHeader] - callbackAttributes: - attributeName: [ - callbackAttributes - ] - dndCallback: => - items = @el.find('table > tbody > tr') - console.log('all effected items', items) + renderTableGroupByRow: (object, position, groupByName) => + App.view('generic/table_row_group_by')( + position: position + groupByName: groupByName + columnsLength: @columnsLength ) - new App.ControllerTable( - el: element - overview: ['time', 'area', 'level', 'browser', 'location', 'data'] - attribute_list: [ - { name: 'time', display: 'Time', tag: 'datetime' }, - { name: 'area', display: 'Area', type: 'text' }, - { name: 'level', display: 'Level', type: 'text' }, - { name: 'browser', display: 'Browser', type: 'text' }, - { name: 'location', display: 'Location', type: 'text' }, - { name: 'data', display: 'Data', type: 'text' }, - ] - objects: data + renderTableRow: (object, position) => + App.view('generic/table_row')( + headers: @headers + attributes: @attributesList + checkbox: @checkbox + radio: @radio + callbacks: @callbackAttributes + sortable: @dndCallback + position: position + object: object ) - ### + tableHeadersHasChanged: => + return true if @overviewAttributes isnt @lastOverview + false - tableGen: => - if !@model - @model = {} - overview = @overview || @model.configure_overview || [] - attributes = @attribute_list || @model.configure_attributes || {} - attributes = App.Model.attributesGet(false, attributes) - destroy = @model.configure_delete + tableHeaders: => + orderBy = @customOrderBy || @orderBy + orderDirection = @customOrderDirection || @orderDirection - # check if table is empty - if _.isEmpty(@objects) - table = App.view('generic/admin/empty')( - explanation: @explanation - ) - return $(table) + #console.log('LLL', @lastOrderBy, @orderBy, @lastOrderDirection, @orderDirection, @overviewAttributes, @lastOverview) + if @headers && @lastOrderBy is orderBy && @lastOrderDirection is orderDirection && !@tableHeadersHasChanged() + console.log('tableHeaders: same overviewAttributes just return headers', @headers) + return ['headers are the same', @headers] + @lastOverview = @overviewAttributes # get header data @headers = [] - for item in overview + for item in @overviewAttributes headerFound = false - for attributeName, attribute of attributes + for attributeName, attribute of @attributesList # remove group by attribute from header if !@groupBy || @groupBy isnt item @@ -208,8 +499,19 @@ class App.ControllerTable extends App.Controller attribute.displayWidth = value @headers.push attribute + + # execute header callback + if @callbackHeader + for callback in @callbackHeader + @headers = callback(@headers) + + if @tableId + @calculateHeaderWidths() + + throw 'no headers found' if _.isEmpty(@headers) + # add destroy header and col binding - if destroy + if @destroy @headers.push name: 'destroy' display: 'Delete' @@ -219,14 +521,63 @@ class App.ControllerTable extends App.Controller parentClass: 'js-delete' icon: 'trash' - if !@bindCol - @bindCol = {} @bindCol['destroy'] = events: click: @deleteRow - if @orderDirection && @orderBy && !@groupBy - @objects = @sortList(@objects) + @columnsLength = @headers.length + if @checkbox || @radio + @columnsLength++ + console.log('tableHeaders: new headers', @headers) + ['new headers', @headers] + + sortList: => + return if _.isEmpty(@objects) + + + orderBy = @customOrderBy || @orderBy + orderDirection = @customOrderDirection || @orderDirection + + console.log('order', @orderBy, @orderDirection) + console.log('customOrder', @customOrderBy, @customOrderDirection) + + return if _.isEmpty(orderBy) && _.isEmpty(@groupBy) + + return if @lastSortedobjects is @objects && @lastOrderDirection is orderDirection && @lastOrderBy is orderBy + @lastOrderDirection = orderDirection + @lastOrderBy = orderBy + + if orderBy + for header in @headers + if header.name is orderBy || "#{header.name}_id" is orderBy# || header.name.substring(0, header.name.length - 3) is orderBy + localObjects = _.sortBy( + @objects + (item) -> + # if we need to sort translated col. + if header.translate + return App.i18n.translateInline(item[header.name]) + + # if we need to sort by relation name + if header.relation + if item[header.name] + localItem = App[header.relation].findNative(item[header.name]) + if localItem + if localItem.displayName + localItem = localItem.displayName().toLowerCase() + if localItem.name + localItem = localItem.name.toLowerCase() + return localItem + return '' + item[header.name] + ) + if orderDirection is 'DESC' + header.sortOrderIcon = ['arrow-down', 'table-sort-arrow'] + localObjects = localObjects.reverse() + else + header.sortOrderIcon = ['arrow-up', 'table-sort-arrow'] + else + header.sortOrderIcon = undefined + @objects = localObjects # group by if @groupBy @@ -237,14 +588,19 @@ class App.ControllerTable extends App.Controller group = object[@groupBy] if !group withId = "#{@groupBy}_id" - - if object[withId] && attributes[withId] && attributes[withId].relation - if App[attributes[withId].relation].exists(object[withId]) - item = App[attributes[withId].relation].findNative(object[withId]) + if object[withId] && @attributesList[withId] && @attributesList[withId].relation + if App[@attributesList[withId].relation].exists(object[withId]) + item = App[@attributesList[withId].relation].findNative(object[withId]) if item && item.displayName group = item.displayName().toLowerCase() + else if item.name + group = item.name.toLowerCase() if _.isEmpty(group) group = '' + if group.displayName + group = group.displayName().toLowerCase() + else if group.name + group = group.name.toLowerCase() groupObjects[group] ||= [] groupObjects[group].push object @@ -254,198 +610,15 @@ class App.ControllerTable extends App.Controller groupsSorted = groupsSorted.sort() # get new order - @objects = [] + localObjects = [] for group in groupsSorted - localObjects = @sortList(groupObjects[group]) - @objects = @objects.concat localObjects + localObjects = localObjects.concat groupObjects[group] groupObjects[group] = [] # release old array - # execute header callback - if @callbackHeader - for callback in @callbackHeader - @headers = callback(@headers) + @objects = localObjects + @lastSortedobjects = localObjects - if @tableId - @calculateHeaderWidths() - - # generate content - position = 0 - columnsLength = @headers.length - if @checkbox || @radio - columnsLength++ - groupLast = '' - tableBody = '' - for object in @objects - if @groupBy - groupByName = App.viewPrint(object, @groupBy, attributes) - if groupLast isnt groupByName - groupLast = groupByName - tableBody += App.view('generic/table_row_group_by')( - position: position - groupByName: groupByName - columnsLength: columnsLength - ) - position++ - tableBody += App.view('generic/table_row')( - headers: @headers - attributes: attributes - checkbox: @checkbox - radio: @radio - callbacks: @callbackAttributes - sortable: @dndCallback - position: position - object: object - ) - - # generate full table - table = App.view('generic/table')( - tableId: @tableId - headers: @headers - checkbox: @checkbox - radio: @radio - class: @class - sortable: @dndCallback - tableBody: tableBody - ) - - # convert to jquery object - table = $(table) - - cursorMap = - click: 'pointer' - dblclick: 'pointer' - #mouseover: 'alias' - - # bind col. - if @bindCol - for name, item of @bindCol - if item.events - position = 0 - if @dndCallback - position += 1 - if @checkbox - position += 1 - hit = false - - for headerName in @headers - if !hit - position += 1 - if headerName.name is name || headerName.name is "#{name}_id" || headerName.name is "#{name}_ids" - hit = true - - if hit - for event, callback of item.events - do (table, event, callback) -> - if cursorMap[event] - table.find("tbody > tr > td:nth-child(#{position})").css('cursor', cursorMap[event]) - table.on( event, "tbody > tr > td:nth-child(#{position})", - (e) -> - e.stopPropagation() - id = $(e.target).parents('tr').data('id') - callback(id, e) - ) - - # bind row - 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] ) - table.on( event, 'tbody > tr', - (e) -> - id = $(e.target).parents('tr').data('id') - callback(id, e) - ) - - # bind bindCheckbox - if @bindCheckbox - if @bindCheckbox.events - for event, callback of @bindCheckbox.events - do (table, event, callback) -> - table.delegate('input[name="bulk"]', event, (e) -> - e.stopPropagation() - id = $(e.currentTarget).parents('tr').data('id') - checked = $(e.currentTarget).prop('checked') - callback(id, checked, e) - ) - - # if we have a personalised table - if @tableId - # 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 @checkbox - - # click first tr>td, catch click - table.delegate('tr > td:nth-child(1)', 'click', (e) -> - e.stopPropagation() - ) - - # bind on full bulk click - table.delegate('input[name="bulk_all"]', 'change', (e) => - e.stopPropagation() - clicks = [] - if $(e.currentTarget).prop('checked') - $(e.currentTarget).parents('table').find('[name="bulk"]').each( -> - $element = $(@) - return if $element.prop('checked') - $element.prop('checked', true) - id = $element.parents('tr').data('id') - clicks.push [id, true] - ) - else - $(e.currentTarget).parents('table').find('[name="bulk"]').each( -> - $element = $(@) - return if !$element.prop('checked') - $element.prop('checked', false) - id = $element.parents('tr').data('id') - clicks.push [id, false] - ) - return if !@bindCheckbox - return if !@bindCheckbox.events - return if _.isEmpty(clicks) - for event, callback of @bindCheckbox.events - if event == 'click' || event == 'change' - for click in clicks - callback(click..., e) - ) - table - - sortList: (objects) => - - for header in @headers - if header.name is @orderBy - objects = _.sortBy( - objects - (item) -> - # if we need to sort translated col. - if header.translate - return App.i18n.translateInline(item[header.name]) - - # if we need to sort by relation name - if header.relation - if item[header.name] - localItem = App[header.relation].findNative(item[header.name]) - if localItem && localItem.displayName - localItem = localItem.displayName().toLowerCase() - return localItem - return '' - 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 - objects + localObjects # bind on delete dialog deleteRow: (id, e) => @@ -559,30 +732,43 @@ class App.ControllerTable extends App.Controller # update store and runtime @headerWidth @preferencesStore('headerWidth', leftColumnKey, leftWidth) + @headerWidth[leftColumnKey] = leftWidth _.find(@headers, (column) -> column.name is leftColumnKey).displayWidth = leftWidth # update store and runtime @headerWidth if rightColumnKey @preferencesStore('headerWidth', rightColumnKey, rightWidth) + @headerWidth[rightColumnKey] = rightWidth _.find(@headers, (column) -> column.name is rightColumnKey).displayWidth = rightWidth sortByColumn: (event) => column = $(event.currentTarget).closest('[data-column-key]').attr('data-column-key') + orderBy = @customOrderBy || @orderBy + orderDirection = @customOrderDirection || @orderDirection + # sort, update runtime @orderBy and @orderDirection - if @orderBy isnt column - @orderBy = column - @orderDirection = 'ASC' + if orderBy isnt column + orderBy = column + orderDirection = 'ASC' else - if @orderDirection is 'ASC' - @orderDirection = 'DESC' + if orderDirection is 'ASC' + orderDirection = 'DESC' else - @orderDirection = 'ASC' + orderDirection = 'ASC' + + @orderBy = orderBy + @orderDirection = orderDirection + @customOrderBy = orderBy + @customOrderDirection = orderDirection # update store - @preferencesStore('order', 'orderBy', @orderBy) - @preferencesStore('order', 'orderDirection', @orderDirection) - @render() + @preferencesStore('order', 'customOrderBy', @orderBy) + @preferencesStore('order', 'customOrderDirection', @orderDirection) + render = => + @renderTableFull() + App.QueueManager.add('tableRender', render) + App.QueueManager.run('tableRender') preferencesStore: (type, key, value) -> data = @preferencesGet() @@ -601,3 +787,25 @@ class App.ControllerTable extends App.Controller preferencesStoreKey: => "tablePrefs:#{@tableId}" + + getBulkSelected: => + ids = [] + @$('[name="bulk"]:checked').each( (index, element) -> + id = $(element).val() + ids.push id + ) + ids + + setBulkSelected: (ids) -> + @$('[name="bulk"]').each( (index, element) -> + id = $(element).val() + for idSelected in ids + if idSelected is id + $(element).prop('checked', true) + ) + + _isSame: (array1, array2) -> + for position in [0..array1.length-1] + if array1[position] isnt array2[position] + return position + true \ No newline at end of file diff --git a/app/assets/javascripts/app/controllers/ticket_overview.coffee b/app/assets/javascripts/app/controllers/ticket_overview.coffee index 39f1c4e9a..da11a230f 100644 --- a/app/assets/javascripts/app/controllers/ticket_overview.coffee +++ b/app/assets/javascripts/app/controllers/ticket_overview.coffee @@ -540,20 +540,23 @@ class App.TicketOverview extends App.Controller render: -> elLocal = $(App.view('ticket_overview/index')()) - @navBarControllerVertical = new Navbar + @navBarControllerVertical = new Navbar( el: elLocal.find('.overview-header') view: @view vertical: true + ) - @navBarController = new Navbar + @navBarController = new Navbar( el: elLocal.filter('.sidebar') view: @view + ) - @contentController = new Table + @contentController = new Table( el: elLocal.find('.overview-table') view: @view keyboardOn: @keyboardOn keyboardOff: @keyboardOff + ) @renderBatchOverlay(elLocal.filter('.js-batch-overlay')) @@ -662,10 +665,12 @@ class App.TicketOverview extends App.Controller @viewLast = @view # build content - if @contentController - @contentController.update( - view: @view - ) + @contentController = new Table( + el: @$('.overview-table') + view: @view + keyboardOn: @keyboardOn + keyboardOff: @keyboardOff + ) hide: => @keyboardOff() @@ -908,7 +913,7 @@ class Table extends App.Controller super if @view - @bindId = App.OverviewListCollection.bind(@view, @render) + @bindId = App.OverviewListCollection.bind(@view, @updateTable) # rerender view, e. g. on langauge change @bind 'ui:rerender', => @@ -924,18 +929,17 @@ class Table extends App.Controller for key, value of params @[key] = value - @view_mode = App.LocalStorage.get("mode:#{@view}", @Session.get('id')) || 's' - @log 'notice', 'view:', @view, @view_mode - return if !@view if @view if @bindId App.OverviewListCollection.unbind(@bindId) - @bindId = App.OverviewListCollection.bind(@view, @render) + @bindId = App.OverviewListCollection.bind(@view, @updateTable) - render: (data) => - return if !data + updateTable: (data) => + if !@table + @render(data) + return # use cache overview = data.overview @@ -943,6 +947,33 @@ class Table extends App.Controller return if !overview && !tickets + # get ticket list + ticketListShow = [] + for ticket in tickets + ticketListShow.push App.Ticket.find(ticket.id) + console.log('overview', overview) + @overview = App.Overview.find(overview.id) + console.log('TTT', @overview.view.s) + @table.update( + overviewAttributes: @overview.view.s + objects: ticketListShow + groupBy: @overview.group_by + orderBy: @overview.order.by + orderDirection: @overview.order.direction + ) + + render: (data) => + return if !data + + # use cache + overview = data.overview + tickets = data.tickets + + return if !overview && !tickets + + @view_mode = App.LocalStorage.get("mode:#{@view}", @Session.get('id')) || 's' + console.log 'notice', 'view:', @view, @view_mode + # get ticket list ticketListShow = [] for ticket in tickets @@ -953,8 +984,6 @@ class Table extends App.Controller @html App.view('customer_not_ticket_exists')() return - @selected = @getSelected() - # set page title @overview = App.Overview.find(overview.id) @@ -1086,7 +1115,7 @@ class Table extends App.Controller attribute.title = object.iconTitle() value - new App.ControllerTable( + @table = new App.ControllerTable( tableId: "ticket_overview_#{@overview.id}" overview: @overview.view.s el: @$('.table-overview') @@ -1123,8 +1152,6 @@ class Table extends App.Controller 'click': callbackCheckbox ) - @setSelected(@selected) - # start user popups @userPopups() @@ -1166,22 +1193,6 @@ class Table extends App.Controller bulkAll.prop('indeterminate', true) ) - getSelected: -> - @ticketIDs = [] - @$('.table-overview').find('[name="bulk"]:checked').each( (index, element) => - ticketId = $(element).val() - @ticketIDs.push ticketId - ) - @ticketIDs - - setSelected: (ticketIDs) -> - @$('.table-overview').find('[name="bulk"]').each( (index, element) -> - ticketId = $(element).val() - for ticketIdSelected in ticketIDs - if ticketIdSelected is ticketId - $(element).prop('checked', true) - ) - viewmode: (e) => e.preventDefault() @view_mode = $(e.target).data('mode') @@ -1497,6 +1508,7 @@ class App.OverviewSettings extends App.ControllerModal App.OverviewListCollection.fetch(@overview.link) else App.OverviewIndexCollection.trigger() + console.log('TRIGGER', @overview.link) App.OverviewListCollection.trigger(@overview.link) # close modal diff --git a/app/assets/javascripts/app/controllers/widget/user_signup_check.coffee b/app/assets/javascripts/app/controllers/widget/user_signup_check.coffee index 59fe9f770..d1f69529c 100644 --- a/app/assets/javascripts/app/controllers/widget/user_signup_check.coffee +++ b/app/assets/javascripts/app/controllers/widget/user_signup_check.coffee @@ -23,6 +23,7 @@ class Widget extends App.Controller verify: (userId) -> return if !userId + return if !App.User.exists(userId) user = App.User.find(userId) return if user.source isnt 'signup' return if user.verified is true diff --git a/app/assets/javascripts/app/lib/app_init/session.coffee b/app/assets/javascripts/app/lib/app_init/session.coffee index 2a670e8d7..87bf31d2d 100644 --- a/app/assets/javascripts/app/lib/app_init/session.coffee +++ b/app/assets/javascripts/app/lib/app_init/session.coffee @@ -5,12 +5,12 @@ class App.Session _instance ?= new _sessionSingleton _instance.clear() - @get: ( key ) -> + @get: (key) -> if _instance == undefined _instance ?= new _sessionSingleton _instance.get(key) - @set: ( user ) -> + @set: (user) -> if _instance == undefined _instance ?= new _sessionSingleton _instance.set(user) @@ -24,11 +24,11 @@ class _sessionSingleton extends Spine.Module clear: -> @user = undefined - get: ( key ) -> + get: (key) -> return if !@user if key return @user[key] @user - set: ( user ) -> - @user = user \ No newline at end of file + set: (user) -> + @user = user diff --git a/app/assets/javascripts/app/lib/app_post/_collection_base.coffee b/app/assets/javascripts/app/lib/app_post/_collection_base.coffee index d031dfa11..ddd758914 100644 --- a/app/assets/javascripts/app/lib/app_post/_collection_base.coffee +++ b/app/assets/javascripts/app/lib/app_post/_collection_base.coffee @@ -6,6 +6,7 @@ class App._CollectionSingletonBase @callbacks = {} @counter = 0 @key = "collection-#{@event}" + # read from cache cache = App.SessionStorage.get(@key) if cache @@ -16,6 +17,9 @@ class App._CollectionSingletonBase @set(data) @callback(data) + App.Event.bind 'auth:logout', (data) => + @clear(data) + get: => @collectionData @@ -79,3 +83,6 @@ class App._CollectionSingletonBase delete @callbacks[counter] App.QueueManager.add(@key, callback) App.QueueManager.run(@key) + + clear: => + @collectionData = undefined diff --git a/app/assets/javascripts/app/lib/app_post/auth.coffee b/app/assets/javascripts/app/lib/app_post/auth.coffee index 7e02cd79a..f46c8c6e3 100644 --- a/app/assets/javascripts/app/lib/app_post/auth.coffee +++ b/app/assets/javascripts/app/lib/app_post/auth.coffee @@ -76,11 +76,7 @@ class App.Auth App.Session.init() # update model definition (needed for not authenticated areas like wizard) - if data.models - for model, attributes of data.models - for attribute in attributes - App[model].attributes.push attribute.name - App[model].configure_attributes.push attribute + @_updateModelAttributes(data.models) # set locale locale = window.navigator.userLanguage || window.navigator.language || 'en-us' @@ -98,11 +94,7 @@ class App.Auth App.Event.trigger('clearStore') # update model definition - if data.models - for model, attributes of data.models - for attribute in attributes - App[model].attributes.push attribute.name - App[model].configure_attributes.push attribute + @_updateModelAttributes(data.models) # update config for key, value of data.config @@ -135,6 +127,14 @@ class App.Auth App.Event.trigger('ui:rerender') App.TaskManager.tasksInitial() + @_updateModelAttributes: (models) -> + return if _.isEmpty(models) + + for model, attributes of models + if App[model] + if _.isFunction(App[model].updateAttributes) + App[model].updateAttributes(attributes) + @_logout: (rerender = true) -> App.Log.debug 'Auth', '_logout' @@ -149,6 +149,15 @@ class App.Auth App.Event.trigger('ui:rerender') App.Event.trigger('clearStore') + # clear all in-memory data of all App.Model's + for model_key, model_object of App + if _.isFunction(model_object.resetCallbacks) + model_object.resetCallbacks() + if _.isFunction(model_object.resetAttributes) + model_object.resetAttributes() + if _.isFunction(model_object.clearInMemory) + model_object.clearInMemory() + @_loginError: -> App.Log.debug 'Auth', '_loginError:error' diff --git a/app/assets/javascripts/app/lib/app_post/overview_list_collection.coffee b/app/assets/javascripts/app/lib/app_post/overview_list_collection.coffee index b605f5503..871f8b660 100644 --- a/app/assets/javascripts/app/lib/app_post/overview_list_collection.coffee +++ b/app/assets/javascripts/app/lib/app_post/overview_list_collection.coffee @@ -14,6 +14,9 @@ class _Singleton @overview[data.overview.view] = data @callback(data.overview.view, data) + App.Event.bind 'auth:logout', (data) => + @clear(data) + get: (view) -> @overview[view] @@ -76,6 +79,12 @@ class _Singleton App.QueueManager.add('ticket_overviews', callback) App.QueueManager.run('ticket_overviews') + clear: => + @overview = {} + @callbacks = {} + @fetchActive = {} + @counter = 0 + class App.OverviewListCollection _instance = new _Singleton diff --git a/app/assets/javascripts/app/models/_application_model.coffee b/app/assets/javascripts/app/models/_application_model.coffee index 49ad8aac9..b6a3e62ce 100644 --- a/app/assets/javascripts/app/models/_application_model.coffee +++ b/app/assets/javascripts/app/models/_application_model.coffee @@ -812,3 +812,29 @@ set new attributes of model (remove already available attributes) item: item processData: true ) + + @clearInMemory: -> + return if !@className + + # reset attributes to prevent cached forms on relogin + if !_.isEmpty(App[@className].org_configure_attributes) + App[@className].configure_attributes = App[@className].org_configure_attributes + + # reset cached values of model + App[@className].deleteAll() + + @updateAttributes: (attributes) -> + return if !@className + if _.isEmpty(@org_configure_attributes) + @org_configure_attributes = clone(@configure_attributes) + for attribute in attributes + @attributes.push attribute.name + @configure_attributes.push attribute + + @resetAttributes: -> + return if _.isEmpty(@org_configure_attributes) + @configure_attributes = @org_configure_attributes + + @resetCallbacks: -> + @SUBSCRIPTION_ITEM = {} + @SUBSCRIPTION_COLLECTION = {} diff --git a/app/assets/javascripts/app/models/user.coffee b/app/assets/javascripts/app/models/user.coffee index fd93b1c62..b55d9c695 100644 --- a/app/assets/javascripts/app/models/user.coffee +++ b/app/assets/javascripts/app/models/user.coffee @@ -25,7 +25,7 @@ class App.User extends App.Model ] uiUrl: -> - '#user/profile/' + @id + "#user/profile/#{@id}" icon: -> 'user' diff --git a/app/assets/javascripts/app/views/generic/table.jst.eco b/app/assets/javascripts/app/views/generic/table.jst.eco index 7bfdcbe4c..a9aa675ec 100644 --- a/app/assets/javascripts/app/views/generic/table.jst.eco +++ b/app/assets/javascripts/app/views/generic/table.jst.eco @@ -20,9 +20,7 @@ <% for header, i in @headers: %> <%= " align-#{ header.align }" if header.align %>" style="<% if header.displayWidth: %>width:<%= header.displayWidth %>px<% end %>" data-column-key="<%= header.name %>">
-
- <%- @T(header.display) %> -
+
<%- @T(header.display) %>
<% if header.sortOrderIcon: %> <%- @Icon(header.sortOrderIcon[0], header.sortOrderIcon[1]) %> @@ -36,5 +34,5 @@ <% end %> - <%- @tableBody %> + <%- @tableBody %> \ No newline at end of file diff --git a/app/assets/javascripts/app/views/generic/table_row.jst.eco b/app/assets/javascripts/app/views/generic/table_row.jst.eco index ca85df9d7..1aa07f841 100644 --- a/app/assets/javascripts/app/views/generic/table_row.jst.eco +++ b/app/assets/javascripts/app/views/generic/table_row.jst.eco @@ -1,4 +1,4 @@ - + <% if @sortable: %> <%- @Icon('draggable') %> <% end %> diff --git a/app/controllers/integration/exchange_controller.rb b/app/controllers/integration/exchange_controller.rb index cdb3fa427..1e31e0874 100644 --- a/app/controllers/integration/exchange_controller.rb +++ b/app/controllers/integration/exchange_controller.rb @@ -11,7 +11,7 @@ class Integration::ExchangeController < ApplicationController email: params[:user], password: params[:password], ) - + client.http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE { endpoint: client.try(:autodiscover).try(:ews_url), } diff --git a/app/controllers/integration/idoit_controller.rb b/app/controllers/integration/idoit_controller.rb index ee4960c5e..c217de073 100644 --- a/app/controllers/integration/idoit_controller.rb +++ b/app/controllers/integration/idoit_controller.rb @@ -1,8 +1,9 @@ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ class Integration::IdoitController < ApplicationController - prepend_before_action -> { authentication_check(permission: ['agent.integration.idoit', 'admin.integration.idoit']) }, except: [:verify] + prepend_before_action -> { authentication_check(permission: ['agent.integration.idoit', 'admin.integration.idoit']) }, except: [:verify, :query, :update] prepend_before_action -> { authentication_check(permission: ['admin.integration.idoit']) }, only: [:verify] + prepend_before_action -> { authentication_check(permission: ['ticket.agent']) }, only: [:query, :update] def verify response = ::Idoit.verify(params[:api_token], params[:endpoint], params[:client_id]) diff --git a/app/controllers/long_polling_controller.rb b/app/controllers/long_polling_controller.rb index d52fda49d..f1ef6554e 100644 --- a/app/controllers/long_polling_controller.rb +++ b/app/controllers/long_polling_controller.rb @@ -1,7 +1,7 @@ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ class LongPollingController < ApplicationController - skip_action_callback :session_update # prevent race conditions + skip_before_action :session_update # prevent race conditions # GET /api/v1/message_send def message_send diff --git a/app/models/application_model/can_lookup_search_index_attributes.rb b/app/models/application_model/can_lookup_search_index_attributes.rb index d2d906f6e..96cff5e8f 100644 --- a/app/models/application_model/can_lookup_search_index_attributes.rb +++ b/app/models/application_model/can_lookup_search_index_attributes.rb @@ -55,7 +55,7 @@ returns } ignored_attributes = self.class.instance_variable_get(:@search_index_attributes_ignored) || [] - return attributes if ignored_attributes.empty? + return attributes if ignored_attributes.blank? ignored_attributes.each { |attribute| attributes.delete(attribute.to_s) diff --git a/app/models/application_model/has_cache.rb b/app/models/application_model/has_cache.rb index aea7ef61e..4ba51ddb3 100644 --- a/app/models/application_model/has_cache.rb +++ b/app/models/application_model/has_cache.rb @@ -41,14 +41,14 @@ module ApplicationModel::HasCache } # delete old name / login caches - if changed? - if changes.key?('name') - name = changes['name'][0] + if saved_changes? + if saved_changes.key?('name') + name = saved_changes['name'][0] key = "#{self.class}::#{name}" Cache.delete(key) end - if changes.key?('login') - name = changes['login'][0] + if saved_changes.key?('login') + name = saved_changes['login'][0] key = "#{self.class}::#{name}" Cache.delete(key) end diff --git a/app/models/channel/email_parser.rb b/app/models/channel/email_parser.rb index 98d3edddd..9b59f8c21 100644 --- a/app/models/channel/email_parser.rb +++ b/app/models/channel/email_parser.rb @@ -475,7 +475,7 @@ returns # check ignore header if mail['x-zammad-ignore'.to_sym] == 'true' || mail['x-zammad-ignore'.to_sym] == true Rails.logger.info "ignored email with msgid '#{mail[:message_id]}' from '#{mail[:from]}' because of x-zammad-ignore header" - return true + return end # set interface handle @@ -514,7 +514,7 @@ returns set_attributes_by_x_headers(ticket, 'ticket', mail, 'followup') # save changes set by x-zammad-ticket-followup-* headers - ticket.save if ticket.changed? + ticket.save! if ticket.has_changes_to_save? state = Ticket::State.find(ticket.state_id) state_type = Ticket::StateType.find(state.state_type_id) @@ -650,7 +650,7 @@ returns def self.sender_properties(from) data = {} - + return data if from.blank? begin list = Mail::AddressList.new(from) list.addresses.each { |address| diff --git a/app/models/channel/filter/monitoring_base.rb b/app/models/channel/filter/monitoring_base.rb index c1370d02b..565ef90c0 100644 --- a/app/models/channel/filter/monitoring_base.rb +++ b/app/models/channel/filter/monitoring_base.rb @@ -18,7 +18,8 @@ class Channel::Filter::MonitoringBase sender = Setting.get("#{integration}_sender") auto_close = Setting.get("#{integration}_auto_close") auto_close_state_id = Setting.get("#{integration}_auto_close_state_id") - state_recovery_match = '(OK|UP)' + state_ignore_match = Setting.get("#{integration}_ignore_match") || '' + state_recovery_match = Setting.get("#{integration}_recovery_match") || '(OK|UP)' return if mail[:from].blank? return if mail[:body].blank? @@ -26,7 +27,7 @@ class Channel::Filter::MonitoringBase return if !session_user_id # check if sender is monitoring - return if !mail[:from].match(/#{Regexp.quote(sender)}/i) + return if !Channel::Filter::Database.match(mail[:from], sender, true, true) # get mail attibutes like host and state result = {} @@ -91,5 +92,18 @@ class Channel::Filter::MonitoringBase mail[ 'x-zammad-ticket-preferences'.to_sym ][key] = value } end + + # ignorte states + if state_ignore_match.present? && result['state'].present? && result['state'].match(/#{state_ignore_match}/i) + mail[ 'x-zammad-ignore'.to_sym ] = true + return true + end + + # if now problem exists, just ignore the email + if result['state'].present? && result['state'].match(/#{state_recovery_match}/i) + mail[ 'x-zammad-ignore'.to_sym ] = true + return true + end + end end diff --git a/app/models/concerns/has_activity_stream_log.rb b/app/models/concerns/has_activity_stream_log.rb index d921945ea..95bd65c29 100644 --- a/app/models/concerns/has_activity_stream_log.rb +++ b/app/models/concerns/has_activity_stream_log.rb @@ -32,13 +32,13 @@ log object update activity stream, if configured - will be executed automaticall =end def activity_stream_update - return true if !changed? + return true if !saved_changes? ignored_attributes = self.class.instance_variable_get(:@activity_stream_attributes_ignored) || [] ignored_attributes += %i(created_at updated_at created_by_id updated_by_id) log = false - changes.each { |key, _value| + saved_changes.each { |key, _value| next if ignored_attributes.include?(key.to_sym) log = true diff --git a/app/models/concerns/has_history.rb b/app/models/concerns/has_history.rb index 10eeb1128..4aa09a73c 100644 --- a/app/models/concerns/has_history.rb +++ b/app/models/concerns/has_history.rb @@ -33,13 +33,13 @@ log object update history with all updated attributes, if configured - will be e =end def history_update - return if !changed? + return if !saved_changes? # return if it's no update return if new_record? # new record also triggers update, so ignore new records - changes = self.changes + changes = saved_changes if history_changes_last_done history_changes_last_done.each { |key, value| if changes.key?(key) && changes[key] == value diff --git a/app/models/locale.rb b/app/models/locale.rb index 854fd75ce..9381ba46a 100644 --- a/app/models/locale.rb +++ b/app/models/locale.rb @@ -99,6 +99,8 @@ all: }, { json: true, + open_timeout: 8, + read_timeout: 24, } ) diff --git a/app/models/observer/sla/ticket_rebuild_escalation.rb b/app/models/observer/sla/ticket_rebuild_escalation.rb index 9ee2f71c0..c267718ec 100644 --- a/app/models/observer/sla/ticket_rebuild_escalation.rb +++ b/app/models/observer/sla/ticket_rebuild_escalation.rb @@ -27,7 +27,7 @@ class Observer::Sla::TicketRebuildEscalation < ActiveRecord::Observer def _check(record) # return if we run import mode - return if Setting.get('import_mode') && !Setting.get('import_ignore_sla') + return true if Setting.get('import_mode') && !Setting.get('import_ignore_sla') # check if condition has changed changed = false @@ -38,11 +38,11 @@ class Observer::Sla::TicketRebuildEscalation < ActiveRecord::Observer %w(timezone business_hours default ical_url public_holidays) end fields_to_check.each { |item| - next if !record.changes[item] - next if record.changes[item][0] == record.changes[item][1] + next if !record.saved_change_to_attribute(item) + next if record.saved_change_to_attribute(item)[0] == record.saved_change_to_attribute(item)[1] changed = true } - return if !changed + return true if !changed _rebuild(record) end diff --git a/app/models/observer/ticket/last_owner_update.rb b/app/models/observer/ticket/last_owner_update.rb index ab100ba50..e96b5712d 100644 --- a/app/models/observer/ticket/last_owner_update.rb +++ b/app/models/observer/ticket/last_owner_update.rb @@ -20,7 +20,7 @@ class Observer::Ticket::LastOwnerUpdate < ActiveRecord::Observer # check if owner has changed if type == 'update' - return true if record.changes['owner_id'].blank? + return true if record.changes_to_save['owner_id'].blank? end # check if owner is nobody diff --git a/app/models/observer/ticket/online_notification_seen.rb b/app/models/observer/ticket/online_notification_seen.rb index dee1774ef..04d3a3285 100644 --- a/app/models/observer/ticket/online_notification_seen.rb +++ b/app/models/observer/ticket/online_notification_seen.rb @@ -19,8 +19,8 @@ class Observer::Ticket::OnlineNotificationSeen < ActiveRecord::Observer return false if Setting.get('import_mode') # set seen only if state has changes - return false if record.changes.blank? - return false if record.changes['state_id'].blank? + return false if !record.saved_changes? + return false if record.saved_changes['state_id'].blank? # check if existing online notifications for this ticket should be set to seen return true if !record.online_notification_seen_state diff --git a/app/models/observer/ticket/ref_object_touch.rb b/app/models/observer/ticket/ref_object_touch.rb index bd8007d4c..242de0ed9 100644 --- a/app/models/observer/ticket/ref_object_touch.rb +++ b/app/models/observer/ticket/ref_object_touch.rb @@ -18,10 +18,10 @@ class Observer::Ticket::RefObjectTouch < ActiveRecord::Observer def ref_object_touch(record) # return if we run import mode - return if Setting.get('import_mode') + return true if Setting.get('import_mode') # touch old customer if changed - cutomer_id_changed = record.changes['customer_id'] + cutomer_id_changed = record.saved_changes['customer_id'] if cutomer_id_changed && cutomer_id_changed[0] != cutomer_id_changed[1] if cutomer_id_changed[0] User.find(cutomer_id_changed[0]).touch @@ -34,7 +34,7 @@ class Observer::Ticket::RefObjectTouch < ActiveRecord::Observer end # touch old organization if changed - organization_id_changed = record.changes['organization_id'] + organization_id_changed = record.saved_changes['organization_id'] if organization_id_changed && organization_id_changed[0] != organization_id_changed[1] if organization_id_changed[0] Organization.find(organization_id_changed[0]).touch @@ -42,7 +42,7 @@ class Observer::Ticket::RefObjectTouch < ActiveRecord::Observer end # touch new/current organization - return if !record.organization + return true if !record.organization record.organization.touch end diff --git a/app/models/observer/ticket/stats_reopen.rb b/app/models/observer/ticket/stats_reopen.rb index ca363f012..408e3cd48 100644 --- a/app/models/observer/ticket/stats_reopen.rb +++ b/app/models/observer/ticket/stats_reopen.rb @@ -19,6 +19,6 @@ class Observer::Ticket::StatsReopen < ActiveRecord::Observer # return if we run import mode return if Setting.get('import_mode') - Stats::TicketReopen.log('Ticket', record.id, record.changes, record.updated_by_id) + Stats::TicketReopen.log('Ticket', record.id, record.saved_changes, record.updated_by_id) end end diff --git a/app/models/observer/transaction.rb b/app/models/observer/transaction.rb index 97651de8f..74754a4b8 100644 --- a/app/models/observer/transaction.rb +++ b/app/models/observer/transaction.rb @@ -201,7 +201,7 @@ class Observer::Transaction < ActiveRecord::Observer # ignore certain attributes real_changes = {} - record.changes.each { |key, value| + record.changes_to_save.each { |key, value| next if key == 'updated_at' next if key == 'first_response_at' next if key == 'close_at' diff --git a/app/models/observer/user/ref_object_touch.rb b/app/models/observer/user/ref_object_touch.rb index 8aa92c765..53352b677 100644 --- a/app/models/observer/user/ref_object_touch.rb +++ b/app/models/observer/user/ref_object_touch.rb @@ -22,7 +22,7 @@ class Observer::User::RefObjectTouch < ActiveRecord::Observer # touch old organization if changed member_ids = [] - organization_id_changed = record.changes['organization_id'] + organization_id_changed = record.saved_changes['organization_id'] if organization_id_changed && organization_id_changed[0] != organization_id_changed[1] if organization_id_changed[0] diff --git a/app/models/observer/user/ticket_organization.rb b/app/models/observer/user/ticket_organization.rb index ee238750a..fe3d155da 100644 --- a/app/models/observer/user/ticket_organization.rb +++ b/app/models/observer/user/ticket_organization.rb @@ -15,7 +15,7 @@ class Observer::User::TicketOrganization < ActiveRecord::Observer def check_organization(record) # check if organization has changed - return if !record.changes['organization_id'] + return true if !record.saved_change_to_attribute?('organization_id') # update last 100 tickets of user tickets = Ticket.where(customer_id: record.id).limit(100) diff --git a/app/models/scheduler.rb b/app/models/scheduler.rb index 844fe5f84..0c5db3386 100644 --- a/app/models/scheduler.rb +++ b/app/models/scheduler.rb @@ -12,10 +12,8 @@ class Scheduler < ApplicationModel Thread.abort_on_exception = true # reconnect in case db connection is lost - # See issue #1080 begin ActiveRecord::Base.connection.reconnect! - rescue PG::UnableToSend => e # rubocop:disable Lint/HandleExceptions rescue => e logger.error "Can't reconnect to database #{e.inspect}" end diff --git a/app/models/taskbar.rb b/app/models/taskbar.rb index cfe9f486e..120abaf12 100644 --- a/app/models/taskbar.rb +++ b/app/models/taskbar.rb @@ -104,7 +104,7 @@ class Taskbar < ApplicationModel end def notify_clients - return true if !changes['preferences'] + return true if !saved_change_to_attribute?('preferences') data = { event: 'taskbar:preferences', data: { diff --git a/app/models/ticket.rb b/app/models/ticket.rb index 814949465..2389b0b91 100644 --- a/app/models/ticket.rb +++ b/app/models/ticket.rb @@ -1160,7 +1160,7 @@ result def reset_pending_time # ignore if no state has changed - return true if !changes['state_id'] + return true if !changes_to_save['state_id'] # ignore if new state is blank and # let handle ActiveRecord the error diff --git a/app/models/ticket/escalation.rb b/app/models/ticket/escalation.rb index 4f2f22585..810d72e3b 100644 --- a/app/models/ticket/escalation.rb +++ b/app/models/ticket/escalation.rb @@ -76,10 +76,10 @@ returns # if no escalation is enabled if !sla || !calendar - preferences[:escalation_calculation] = {} # nothing to change return false if !escalation_at && !first_response_escalation_at && !update_escalation_at && !close_escalation_at + preferences['escalation_calculation'] = {} self.escalation_at = nil self.first_response_escalation_at = nil self.escalation_at = nil @@ -122,7 +122,7 @@ returns first_response_at_changed = false end last_update_at_changed = true - if escalation_calculation['last_update_at'] == last_update_at && !changes['state_id'] + if escalation_calculation['last_update_at'] == last_update_at && !saved_change_to_attribute('state_id') last_update_at_changed = false end close_at_changed = true @@ -352,7 +352,7 @@ returns ).map(&:name) # add state changes till now - if add_current && changes['state_id'] && changes['state_id'][0] && changes['state_id'][1] + if add_current && saved_change_to_attribute('state_id') && saved_change_to_attribute('state_id')[0] && saved_change_to_attribute('state_id')[1] last_history_state = nil history_list.each { |history_item| next if !history_item['attribute'] @@ -361,14 +361,14 @@ returns last_history_state = history_item } local_updated_at = updated_at - if changes['updated_at'] && changes['updated_at'][1] - local_updated_at = changes['updated_at'][1] + if saved_change_to_attribute('updated_at') && saved_change_to_attribute('updated_at')[1] + local_updated_at = saved_change_to_attribute('updated_at')[1] end history_item = { 'attribute' => 'state', 'created_at' => local_updated_at, - 'value_from' => Ticket::State.find(changes['state_id'][0]).name, - 'value_to' => Ticket::State.find(changes['state_id'][1]).name, + 'value_from' => Ticket::State.find(saved_change_to_attribute('state_id')[0]).name, + 'value_to' => Ticket::State.find(saved_change_to_attribute('state_id')[1]).name, } if last_history_state last_history_state = history_item diff --git a/app/models/translation.rb b/app/models/translation.rb index 3cea271b7..dde80442a 100644 --- a/app/models/translation.rb +++ b/app/models/translation.rb @@ -81,8 +81,8 @@ push translations to online }, { json: true, - open_timeout: 6, - read_timeout: 16, + open_timeout: 8, + read_timeout: 24, } ) raise "Can't push translations to #{url}: #{result.error}" if !result.success? diff --git a/app/models/user.rb b/app/models/user.rb index 8cdbc49a3..0a2cc5dfd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1055,7 +1055,7 @@ raise 'Minimum one user need to have admin permissions' def avatar_for_email_check return true if email.blank? return true if email !~ /@/ - return true if !changes['email'] && updated_at > Time.zone.now - 10.days + return true if !saved_change_to_attribute?('email') && updated_at > Time.zone.now - 10.days # save/update avatar avatar = Avatar.auto_detection( @@ -1106,8 +1106,7 @@ raise 'Minimum one user need to have admin permissions' # reset login_failed if password is changed def reset_login_failed - return true if !changes - return true if !changes['password'] + return true if !will_save_change_to_attribute?('password') self.login_failed = 0 true end diff --git a/app/views/tests/table_extended.html.erb b/app/views/tests/table_extended.html.erb new file mode 100644 index 000000000..eefb9c49e --- /dev/null +++ b/app/views/tests/table_extended.html.erb @@ -0,0 +1,17 @@ + + + + + + + + + +
+ +
\ No newline at end of file diff --git a/config/routes/test.rb b/config/routes/test.rb index 91d738b21..8ccccd6f6 100644 --- a/config/routes/test.rb +++ b/config/routes/test.rb @@ -14,6 +14,7 @@ Zammad::Application.routes.draw do match '/tests_form_column_select', to: 'tests#form_column_select', via: :get match '/tests_form_searchable_select', to: 'tests#form_searchable_select', via: :get match '/tests_table', to: 'tests#table', via: :get + match '/tests_table_extended', to: 'tests#table_extended', via: :get match '/tests_html_utils', to: 'tests#html_utils', via: :get match '/tests_ticket_selector', to: 'tests#ticket_selector', via: :get match '/tests_taskbar', to: 'tests#taskbar', via: :get diff --git a/contrib/cleanup.sh b/contrib/cleanup.sh index 10efac1e9..a4287ae7f 100755 --- a/contrib/cleanup.sh +++ b/contrib/cleanup.sh @@ -5,7 +5,3 @@ set -ex rm app/assets/javascripts/app/controllers/layout_ref.coffee rm -rf app/assets/javascripts/app/views/layout_ref/ rm app/assets/javascripts/app/controllers/karma.coffee -rm app/assets/javascripts/app/controllers/report.coffee -rm app/assets/javascripts/app/controllers/report_profile.coffee -rm app/assets/javascripts/app/controllers/_integration/check_mk.coffee -rm app/assets/javascripts/app/controllers/_integration/idoit.coffee diff --git a/contrib/nginx/zammad.conf b/contrib/nginx/zammad.conf index 279d35f51..c039880a8 100644 --- a/contrib/nginx/zammad.conf +++ b/contrib/nginx/zammad.conf @@ -43,7 +43,7 @@ server { proxy_set_header CLIENT_IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; - proxy_read_timeout 180; + proxy_read_timeout 300; proxy_pass http://zammad; gzip on; diff --git a/contrib/nginx/zammad_ssl.conf b/contrib/nginx/zammad_ssl.conf index de55f36ed..316d65287 100644 --- a/contrib/nginx/zammad_ssl.conf +++ b/contrib/nginx/zammad_ssl.conf @@ -134,7 +134,7 @@ server { proxy_set_header CLIENT_IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; - proxy_read_timeout 180; + proxy_read_timeout 300; proxy_pass http://zammad; gzip on; diff --git a/lib/idoit.rb b/lib/idoit.rb index f1fe7f379..271211bf4 100644 --- a/lib/idoit.rb +++ b/lib/idoit.rb @@ -42,7 +42,7 @@ returns "container": "0", "const": "C__OBJTYPE__SERVICE", "color": "987384", - "image": "https://demo.panic.at/i-doit/images/objecttypes/service.jpg", + "image": "https://demo.example.com/i-doit/images/objecttypes/service.jpg", "icon": "images/icons/silk/application_osx_terminal.png", "cats": "4", "tree_group": "1", @@ -56,7 +56,7 @@ returns "container": "0", "const": "C__OBJTYPE__APPLICATION", "color": "E4B9D7", - "image": "https://demo.panic.at/i-doit/images/objecttypes/application.jpg", + "image": "https://demo.example.com/i-doit/images/objecttypes/application.jpg", "icon": "images/icons/silk/application_xp.png", "cats": "20", "tree_group": "1", @@ -71,7 +71,7 @@ or with filter: "result": [ { "id": "26", - "title": "demo.panic.at", + "title": "demo.example.com", "sysid": "SYSID_1485512390", "type": "59", "created": "2017-01-27 11:19:24", @@ -81,7 +81,7 @@ or with filter: "status": "2", "cmdb_status": "6", "cmdb_status_title": "in operation", - "image": "https://demo.panic.at/i-doit/images/objecttypes/empty.png" + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png" }, ], @@ -135,6 +135,8 @@ or with filter: end def self._url_cleanup(url) + url.gsub!(/^[[:space:]]+/, '') + url.gsub!(/[[:space:]]+$/, '') raise "Invalid endpoint '#{url}', need to start with http:// or https://" if url !~ %r{^http(s|)://}i url = _url_cleanup_baseurl(url) url = "#{url}/src/jsonrpc.php" @@ -142,6 +144,8 @@ or with filter: end def self._url_cleanup_baseurl(url) + url.gsub!(/^[[:space:]]+/, '') + url.gsub!(/[[:space:]]+$/, '') raise "Invalid endpoint '#{url}', need to start with http:// or https://" if url !~ %r{^http(s|)://}i url.gsub!(%r{src/jsonrpc.php}, '') url.gsub(%r{([^:])//+}, '\\1/') diff --git a/lib/import/base_resource.rb b/lib/import/base_resource.rb index 70761c75b..f96a2aeda 100644 --- a/lib/import/base_resource.rb +++ b/lib/import/base_resource.rb @@ -37,7 +37,7 @@ module Import def changed_attributes return if @resource.blank? # dry run - return @resource.changes if @resource.changed? + return @resource.changes_to_save if @resource.has_changes_to_save? # live run @resource.previous_changes end diff --git a/lib/sequencer/unit/import/common/model/update.rb b/lib/sequencer/unit/import/common/model/update.rb index fa0947317..1a110a9ef 100644 --- a/lib/sequencer/unit/import/common/model/update.rb +++ b/lib/sequencer/unit/import/common/model/update.rb @@ -39,9 +39,9 @@ class Sequencer def changes @changes ||= begin - if instance.changed? + if instance.has_changes_to_save? # dry run - instance.changes + instance.changes_to_save else # live run instance.previous_changes diff --git a/lib/service/geo_ip/zammad.rb b/lib/service/geo_ip/zammad.rb index 973879da9..0be67ca54 100644 --- a/lib/service/geo_ip/zammad.rb +++ b/lib/service/geo_ip/zammad.rb @@ -4,6 +4,8 @@ require 'cache' class Service::GeoIp::Zammad def self.location(address) + return {} if address == '127.0.0.1' + return {} if address == '::1' # check cache cache_key = "zammadgeoip::#{address}" diff --git a/public/assets/tests/table.js b/public/assets/tests/table.js index d9aaa7cfd..afc73b58c 100644 --- a/public/assets/tests/table.js +++ b/public/assets/tests/table.js @@ -1,5 +1,5 @@ // form -test( "table test", function() { +test('table test', function() { App.i18n.set('de-de') $('#table').append('

table simple I

') @@ -85,18 +85,18 @@ test( "table test", function() { } }, }) - equal( el.find('table > thead > tr').length, 1, 'row count') - equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') - equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') - equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') - equal( el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') - equal( el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2') + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2') $('#table').append('

table simple II

') el = $('#table2') @@ -108,18 +108,18 @@ test( "table test", function() { checkbox: false, radio: false, }) - equal( el.find('table > thead > tr').length, 1, 'row count') - equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') - equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') - equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') - equal( el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '2 normal', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'false', 'check row 1') - equal( el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '1 niedrig', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'true', 'check row 2') + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '2 normal', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'false', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '1 niedrig', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'true', 'check row 2') $('#table').append('

table simple III

') el = $('#table3') @@ -130,16 +130,16 @@ test( "table test", function() { checkbox: false, radio: false, }) - equal( el.find('table > thead > tr').length, 1, 'row count') - equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') notEqual( el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') notEqual( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') - equal( el.find('tbody > tr:nth-child(2) > td').length, 1, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td').length, 1, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2') notEqual( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '?', 'check row 2') notEqual( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'true', 'check row 2') - equal( el.find('tbody > tr:nth-child(1) > td').length, 1, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td').length, 1, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') notEqual( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '?', 'check row 1') notEqual( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'false', 'check row 1') @@ -236,60 +236,60 @@ test( "table test", function() { objects: App.Ticket.search({sortBy:'created_at', order: 'DESC'}), checkbox: true, }) - equal( el.find('table > thead > tr').length, 1, 'row count') - equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), '', 'check header') - equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), '#', 'check header') - equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Titel', 'check header') - equal( el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Besitzer', 'check header') - equal( el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Kunde', 'check header') - equal( el.find('table > thead > tr > th:nth-child(6)').text().trim(), 'Priorität', 'check header') - equal( el.find('table > thead > tr > th:nth-child(7)').text().trim(), 'Gruppe', 'check header') - equal( el.find('table > thead > tr > th:nth-child(8)').text().trim(), 'Status', 'check header') - equal( el.find('table > thead > tr > th:nth-child(9)').text().trim(), 'Erstellt am', 'check header') - equal( el.find('tbody > tr:nth-child(1) > td').length, 9, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').val(), '3', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').prop('checked'), '', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), '', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '4713', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'some title 3', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'firstname56 lastname56', 'check row 2') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(5)').text().trim(), '-', 'check row 2') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(6)').text().trim(), '2 normal', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(7)').text().trim(), 'group 2', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(8)').text().trim(), 'neu', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(9)').text().trim(), '11.07.2014', 'check row 1') - equal( el.find('tbody > tr:nth-child(2) > td').length, 9, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), '', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '4712', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'some title 2', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), '-', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '-', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(7)').text().trim(), 'group 1', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), 'offen', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 2') - equal( el.find('tbody > tr:nth-child(3) > td').length, 9, 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').val(), '1', 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').prop('checked'), '', 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1)').text().trim(), '', 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '4711', 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(3)').text().trim(), 'some title 1', 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(4)').text().trim(), 'firstname55 lastname55', 'check row 2') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(5)').text().trim(), 'firstname56 lastname56', 'check row 2') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(7)').text().trim(), 'group 2', 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(8)').text().trim(), 'neu', 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 3') + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), '', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), '#', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Titel', 'check header') + equal(el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Besitzer', 'check header') + equal(el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Kunde', 'check header') + equal(el.find('table > thead > tr > th:nth-child(6)').text().trim(), 'Priorität', 'check header') + equal(el.find('table > thead > tr > th:nth-child(7)').text().trim(), 'Gruppe', 'check header') + equal(el.find('table > thead > tr > th:nth-child(8)').text().trim(), 'Status', 'check header') + equal(el.find('table > thead > tr > th:nth-child(9)').text().trim(), 'Erstellt am', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 9, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').val(), '3', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').prop('checked'), '', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), '', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '4713', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'some title 3', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'firstname56 lastname56', 'check row 2') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(5)').text().trim(), '-', 'check row 2') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(6)').text().trim(), '2 normal', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(7)').text().trim(), 'group 2', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(8)').text().trim(), 'neu', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(9)').text().trim(), '11.07.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 9, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), '', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '4712', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'some title 2', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), '-', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '-', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(7)').text().trim(), 'group 1', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), 'offen', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 2') + equal(el.find('tbody > tr:nth-child(3) > td').length, 9, 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').val(), '1', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').prop('checked'), '', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1)').text().trim(), '', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '4711', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(3)').text().trim(), 'some title 1', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(4)').text().trim(), 'firstname55 lastname55', 'check row 2') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(5)').text().trim(), 'firstname56 lastname56', 'check row 2') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(7)').text().trim(), 'group 2', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(8)').text().trim(), 'neu', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 3') el.find('input[name="bulk_all"]').click() - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').prop('checked'), true, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').val(), '3', 'check row 1') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), true, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').prop('checked'), true, 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').val(), '1', 'check row 3') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').prop('checked'), true, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').val(), '3', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), true, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').prop('checked'), true, 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').val(), '1', 'check row 3') $('#table').append('

table complex II

') el = $('#table5') @@ -309,55 +309,55 @@ test( "table test", function() { } }, }) - equal( el.find('table > thead > tr').length, 1, 'row count') - equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), '', 'check header') - equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), '#', 'check header') - equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Titel', 'check header') - equal( el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Besitzer', 'check header') - equal( el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Kunde', 'check header') - equal( el.find('table > thead > tr > th:nth-child(6)').text().trim(), 'Priorität', 'check header') - equal( el.find('table > thead > tr > th:nth-child(7)').text().trim(), 'Status', 'check header') - equal( el.find('table > thead > tr > th:nth-child(8)').text().trim(), 'Erstellt am', 'check header') - equal( el.find('tbody > tr:nth-child(1) > td').length, 1, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'group 1', 'check row 1') - equal( el.find('tbody > tr:nth-child(2) > td').length, 8, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), '', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '4712', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'some title 2', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), '-', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '-', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(7)').text().trim(), 'offen', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), '10.06.2014', 'check row 2') - equal( el.find('tbody > tr:nth-child(3) > td').length, 1, 'check row 3') - equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1)').text().trim(), 'group 2', 'check row 4') - equal( el.find('tbody > tr:nth-child(4) > td').length, 8, 'check row 4') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').val(), '3', 'check row 4') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').prop('checked'), '', 'check row 4') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(1)').text().trim(), '', 'check row 4') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(2)').text().trim(), '4713', 'check row 4') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(3)').text().trim(), 'some title 3', 'check row 4') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(4)').text().trim(), 'firstname56 lastname56', 'check row 2') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(5)').text().trim(), '-', 'check row 2') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(6)').text().trim(), '2 normal', 'check row 4') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(7)').text().trim(), 'neu', 'check row 4') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(8)').text().trim(), '11.07.2014', 'check row 4') + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), '', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), '#', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Titel', 'check header') + equal(el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Besitzer', 'check header') + equal(el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Kunde', 'check header') + equal(el.find('table > thead > tr > th:nth-child(6)').text().trim(), 'Priorität', 'check header') + equal(el.find('table > thead > tr > th:nth-child(7)').text().trim(), 'Status', 'check header') + equal(el.find('table > thead > tr > th:nth-child(8)').text().trim(), 'Erstellt am', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 1, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'group 1', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 8, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), '', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '4712', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'some title 2', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), '-', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '-', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(7)').text().trim(), 'offen', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), '10.06.2014', 'check row 2') + equal(el.find('tbody > tr:nth-child(3) > td').length, 1, 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1)').text().trim(), 'group 2', 'check row 4') + equal(el.find('tbody > tr:nth-child(4) > td').length, 8, 'check row 4') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').val(), '3', 'check row 4') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').prop('checked'), '', 'check row 4') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(1)').text().trim(), '', 'check row 4') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(2)').text().trim(), '4713', 'check row 4') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(3)').text().trim(), 'some title 3', 'check row 4') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(4)').text().trim(), 'firstname56 lastname56', 'check row 2') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(5)').text().trim(), '-', 'check row 2') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(6)').text().trim(), '2 normal', 'check row 4') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(7)').text().trim(), 'neu', 'check row 4') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(8)').text().trim(), '11.07.2014', 'check row 4') el.find('input[name="bulk"]:eq(1)').click() - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 1') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').prop('checked'), true, 'check row 4') - equal( el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').val(), '3', 'check row 4') - equal( el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').prop('checked'), '', 'check row 5') - equal( el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').val(), '1', 'check row 5') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 1') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').prop('checked'), true, 'check row 4') + equal(el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').val(), '3', 'check row 4') + equal(el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').prop('checked'), '', 'check row 5') + equal(el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').val(), '1', 'check row 5') el.find('tbody > tr:nth-child(5) > td:nth-child(1) label').click() - equal( el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').prop('checked'), true, 'check row 5') - equal( el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').val(), '1', 'check row 5') + equal(el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').prop('checked'), true, 'check row 5') + equal(el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').val(), '1', 'check row 5') }); -test( "table test 2", function() { +test('table test 2', function() { App.i18n.set('de-de') $('#table').append('

table with hash

') @@ -413,27 +413,27 @@ test( "table test 2", function() { model: App.Channel, objects: App.Channel.search({sortBy:'adapter', order: 'ASC'}), }) - equal( el.find('table > thead > tr').length, 1, 'row count') - equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Typ', 'check header') - equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Host', 'check header') - equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Benutzer', 'check header') - equal( el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Aktiv', 'check header') - equal( el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Löschen', 'check header') - equal( el.find('tbody > tr:nth-child(1) > td').length, 5, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'adapter1', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'host1', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'user1', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'ja', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(5)').text().trim(), '', 'check row 1') - equal( el.find('tbody > tr:nth-child(2) > td').length, 5, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), 'adapter2', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'host2', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'user2', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), 'ja', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '', 'check row 2') + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Typ', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Host', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Benutzer', 'check header') + equal(el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Aktiv', 'check header') + equal(el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Löschen', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 5, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'adapter1', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'host1', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'user1', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'ja', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(5)').text().trim(), '', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 5, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), 'adapter2', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'host2', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'user2', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), 'ja', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '', 'check row 2') }); -test( "table test 3", function() { +test('table test 3', function() { App.i18n.set('de-de') $('#table').append('

table with link

') @@ -508,31 +508,31 @@ test( "table test 3", function() { }, }, }) - equal( el.find('table > thead > tr').length, 1, 'row count') - equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'richtiger Name', 'check header') - equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Some Name', 'check header') - equal( el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'realname 55', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'email 55', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), '', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').hasClass('glyphicon-user'), true, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').hasClass('glyphicon'), true, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').attr('title'), 'Umschalten zu', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').data('some'), 'value55', 'check row 2') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').data('xxx'), '55', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), 'realname 56', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'email 56', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), '', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').hasClass('glyphicon-user'), true, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').hasClass('glyphicon'), true, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').attr('title'), 'Umschalten zu', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').data('some'), 'value56', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').data('xxx'), '56', 'check row 2') + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'richtiger Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Some Name', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'realname 55', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'email 55', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), '', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').hasClass('glyphicon-user'), true, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').hasClass('glyphicon'), true, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').attr('title'), 'Umschalten zu', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').data('some'), 'value55', 'check row 2') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').data('xxx'), '55', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), 'realname 56', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'email 56', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), '', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').hasClass('glyphicon-user'), true, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').hasClass('glyphicon'), true, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').attr('title'), 'Umschalten zu', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').data('some'), 'value56', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').data('xxx'), '56', 'check row 2') }); -test( "table test 4", function() { +test('table test 4', function() { App.i18n.set('de-de') $('#table').append('

table with data

') @@ -554,16 +554,16 @@ test( "table test 4", function() { objects: data }); - equal( el.find('table > thead > tr').length, 1, 'row count') - equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') - equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Data', 'check header') - equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') - equal( el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:first').text().trim(), 'some name 1', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'some data 1', 'check row 1') - equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') - equal( el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:first').text().trim(), 'some name 2', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'some data 2', 'check row 2') - equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2') + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Data', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), 'some name 1', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'some data 1', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), 'some name 2', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'some data 2', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2') }); diff --git a/public/assets/tests/table_extended.js b/public/assets/tests/table_extended.js new file mode 100644 index 000000000..fb8f38834 --- /dev/null +++ b/public/assets/tests/table_extended.js @@ -0,0 +1,274 @@ +// initial list +test('table new - initial list', function() { + App.i18n.set('de-de') + + $('#table').append('

table with data

') + var el = $('#table-new1') + + App.TicketPriority.refresh([ + { + id: 1, + name: '1 low', + note: 'some note 1', + active: true, + created_at: '2014-06-10T11:17:34.000Z', + }, + { + id: 2, + name: '2 normal', + note: 'some note 2', + active: false, + created_at: '2014-06-10T10:17:34.000Z', + }, + ], {clear: true}) + + var table = new App.ControllerTable({ + el: el, + overviewAttributes: ['name', 'created_at', 'active'], + model: App.TicketPriority, + objects: App.TicketPriority.search({sortBy:'name', order: 'ASC'}), + checkbox: false, + radio: false, + }) + //equal(el.find('table').length, 0, 'row count') + //table.render() + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2') + equal(el.find('tbody > tr:nth-child(3) > td').length, 0, 'check row 3') + + result = table.update({sync: true, objects: App.TicketPriority.search({sortBy:'name', order: 'ASC'})}) + equal(result[0], 'noChanges') + + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2') + + App.TicketPriority.refresh([ + { + id: 1, + name: 'Priority', + note: 'some note 1', + active: true, + created_at: '2014-06-10T11:17:34.000Z', + }, + ], {clear: true}) + + result = table.update({sync: true, objects: App.TicketPriority.search({sortBy:'name', order: 'ASC'})}) + equal(result[0], 'fullRender.lenghtChanged') + equal(result[1], 2) + equal(result[2], 1) + + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), 'Priorität', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 0, 'check row 2') + + App.TicketPriority.refresh([], {clear: true}) + + result = table.update({sync: true, objects: App.TicketPriority.search({sortBy:'name', order: 'ASC'})}) + equal(result[0], 'emptyList') + + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Keine Einträge', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 0, 'check row 1') + + App.TicketPriority.refresh([ + { + id: 1, + name: '1 low', + note: 'some note 1', + active: true, + created_at: '2014-06-10T11:17:34.000Z', + }, + { + id: 2, + name: '2 normal', + note: 'some note 2', + active: false, + created_at: '2014-06-10T10:17:34.000Z', + }, + ], {clear: true}) + + result = table.update({sync: true, objects: App.TicketPriority.search({sortBy:'name', order: 'ASC'})}) + equal(result[0], 'fullRender') + + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2') + equal(el.find('tbody > tr:nth-child(3) > td').length, 0, 'check row 3') + + App.TicketPriority.refresh([ + { + id: 1, + name: '1 low', + note: 'some note 1', + active: true, + created_at: '2014-06-10T11:17:34.000Z', + }, + { + id: 2, + name: '2 normal', + note: 'some note 2', + active: false, + created_at: '2014-06-10T10:17:34.000Z', + }, + { + id: 3, + name: '3 high', + note: 'some note 3', + active: false, + created_at: '2014-06-10T10:17:38.000Z', + }, + ], {clear: true}) + + result = table.update({sync: true, objects: App.TicketPriority.search({sortBy:'name', order: 'ASC'})}) + equal(result[0], 'fullRender.lenghtChanged') + equal(result[1], 2) + equal(result[2], 3) + + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2') + equal(el.find('tbody > tr:nth-child(3) > td').length, 3, 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:first').text().trim(), '3 hoch', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3') + equal(el.find('tbody > tr:nth-child(4) > td').length, 0, 'check row 4') + + result = table.update({sync: true, orderDirection: 'DESC', orderBy: 'name'}) + equal(result[0], 'fullRender.contentChanged') + equal(result[1], 0) + + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '3 hoch', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2') + equal(el.find('tbody > tr:nth-child(3) > td').length, 3, 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:first').text().trim(), '1 niedrig', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(3)').text().trim(), 'true', 'check row 3') + equal(el.find('tbody > tr:nth-child(4) > td').length, 0, 'check row 4') + + result = table.update({sync: true, orderDirection: 'ASC', orderBy: 'name'}) + equal(result[0], 'fullRender.contentChanged') + equal(result[1], 0) + + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2') + equal(el.find('tbody > tr:nth-child(3) > td').length, 3, 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:first').text().trim(), '3 hoch', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3') + equal(el.find('tbody > tr:nth-child(4) > td').length, 0, 'check row 4') + + App.TicketPriority.refresh([ + { + id: 1, + name: '1 low', + note: 'some note 1', + active: true, + created_at: '2014-06-10T11:17:34.000Z', + }, + { + id: 3, + name: '3 high', + note: 'some note 3', + active: false, + created_at: '2014-06-10T10:17:38.000Z', + }, + ], {clear: true}) + + result = table.update({sync: true, objects: App.TicketPriority.search({sortBy:'name', order: 'ASC'})}) + equal(result[0], 'fullRender.contentRemoved') + equal(result[1], 1) + notOk(result[2]) + + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '3 hoch', 'check row 3') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td').length, 0, 'check row 3') + + result = table.update({sync: true, overviewAttributes: ['name', 'created_at']}) + equal(result[0], 'fullRender.overviewAttributesChanged') + + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header') + equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header') + equal(el.find('table > thead > tr > th').length, 2, 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 2, 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1') + equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1') + equal(el.find('tbody > tr:nth-child(2) > td').length, 2, 'check row 2') + equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '3 hoch', 'check row 3') + equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3') + equal(el.find('tbody > tr:nth-child(3) > td').length, 0, 'check row 3') + + App.TicketPriority.refresh([], {clear: true}) + + result = table.update({sync: true, objects: App.TicketPriority.search({sortBy:'name', order: 'ASC'})}) + equal(result[0], 'emptyList') + + equal(el.find('table > thead > tr').length, 1, 'row count') + equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Keine Einträge', 'check header') + equal(el.find('tbody > tr:nth-child(1) > td').length, 0, 'check row 1') + +}) diff --git a/public/assets/tests/ui.js b/public/assets/tests/ui.js index 10277383d..b01307a63 100644 --- a/public/assets/tests/ui.js +++ b/public/assets/tests/ui.js @@ -109,4 +109,8 @@ test("check pretty date", function() { result = App.PrettyDate.humanTime(current.getTime() + (60050 * 60 * 24 * 30.5)); equal(result, 'in 30 days', 'in 30.5 days') + // + + + }); diff --git a/script/build/test_slice_tests.sh b/script/build/test_slice_tests.sh index 00f5b7e2f..34e837538 100755 --- a/script/build/test_slice_tests.sh +++ b/script/build/test_slice_tests.sh @@ -60,6 +60,7 @@ if [ "$LEVEL" == '1' ]; then # test/browser/taskbar_session_test.rb # test/browser/taskbar_task_test.rb # test/browser/translation_test.rb + rm test/browser/user_switch_cache_test.rb elif [ "$LEVEL" == '2' ]; then echo "slicing level 2" @@ -117,6 +118,7 @@ elif [ "$LEVEL" == '2' ]; then rm test/browser/taskbar_session_test.rb rm test/browser/taskbar_task_test.rb rm test/browser/translation_test.rb + #rm test/browser/user_switch_cache_test.rb elif [ "$LEVEL" == '3' ]; then echo "slicing level 3" @@ -174,6 +176,7 @@ elif [ "$LEVEL" == '3' ]; then rm test/browser/taskbar_session_test.rb rm test/browser/taskbar_task_test.rb rm test/browser/translation_test.rb + rm test/browser/user_switch_cache_test.rb elif [ "$LEVEL" == '4' ]; then echo "slicing level 4" @@ -231,6 +234,7 @@ elif [ "$LEVEL" == '4' ]; then rm test/browser/taskbar_session_test.rb rm test/browser/taskbar_task_test.rb rm test/browser/translation_test.rb + rm test/browser/user_switch_cache_test.rb elif [ "$LEVEL" == '5' ]; then echo "slicing level 5" @@ -287,6 +291,7 @@ elif [ "$LEVEL" == '5' ]; then rm test/browser/taskbar_session_test.rb rm test/browser/taskbar_task_test.rb rm test/browser/translation_test.rb + rm test/browser/user_switch_cache_test.rb elif [ "$LEVEL" == '6' ]; then echo "slicing level 6" @@ -346,6 +351,7 @@ elif [ "$LEVEL" == '6' ]; then rm test/browser/taskbar_session_test.rb rm test/browser/taskbar_task_test.rb rm test/browser/translation_test.rb + rm test/browser/user_switch_cache_test.rb else echo "ERROR: Invalid level $LEVEL - 1, 2, 3, 4, 5 or 6 is available" diff --git a/script/scheduler.rb b/script/scheduler.rb index 5be7db8c3..fdd2e8523 100755 --- a/script/scheduler.rb +++ b/script/scheduler.rb @@ -16,6 +16,12 @@ require 'daemons' def before_fork + # clear all connections before for, reconnect later ActiveRecord::Base.connection.reconnect! + # issue #1405 - Scheduler not running because of Bad file descriptor in PGConsumeInput() + # https://github.com/zammad/zammad/issues/1405 + # see also https://bitbucket.org/ged/ruby-pg/issues/260/frequent-crashes-with-multithreading + ActiveRecord::Base.clear_all_connections! + # remember open file handles @files_to_reopen = [] ObjectSpace.each_object(File) do |file| diff --git a/spec/lib/external_sync_spec.rb b/spec/lib/external_sync_spec.rb index b4f6d973d..14f4b4cd0 100644 --- a/spec/lib/external_sync_spec.rb +++ b/spec/lib/external_sync_spec.rb @@ -15,8 +15,8 @@ RSpec.describe ExternalSync do current_changes: current_changes, ) - expect(result).to be false - expect(object.changed?).to be false + expect(result).to be false + expect(object.has_changes_to_save?).to be false end it 'keeps ActiveRecord instance unchanged on local and remote changes' do @@ -30,8 +30,8 @@ RSpec.describe ExternalSync do current_changes: current_changes, ) - expect(result).to be false - expect(object.changed?).to be false + expect(result).to be false + expect(object.has_changes_to_save?).to be false end it 'changes ActiveRecord instance attribute(s) for remote changes' do @@ -45,8 +45,8 @@ RSpec.describe ExternalSync do current_changes: current_changes, ) - expect(result).to be true - expect(object.changed?).to be true + expect(result).to be true + expect(object.has_changes_to_save?).to be true end it 'prevents ActiveRecord method calls' do @@ -61,9 +61,9 @@ RSpec.describe ExternalSync do current_changes: current_changes, ) - expect(result).to be false - expect(object.changed?).to be false - expect(object.destroyed?).to be false + expect(result).to be false + expect(object.has_changes_to_save?).to be false + expect(object.destroyed?).to be false end end diff --git a/test/browser/aab_unit_test.rb b/test/browser/aab_unit_test.rb index 6191dfa85..94a960793 100644 --- a/test/browser/aab_unit_test.rb +++ b/test/browser/aab_unit_test.rb @@ -118,6 +118,13 @@ class AAbUnitTest < TestCase value: '0', ) + location(url: browser_url + '/tests_table_extended') + sleep 4 + match( + css: '.result .failed', + value: '0', + ) + location(url: browser_url + '/tests_html_utils') sleep 4 match( diff --git a/test/browser/user_switch_cache_test.rb b/test/browser/user_switch_cache_test.rb new file mode 100644 index 000000000..7b700c7ab --- /dev/null +++ b/test/browser/user_switch_cache_test.rb @@ -0,0 +1,83 @@ +# encoding: utf-8 +require 'browser_test_helper' + +class UserSwitchCache < TestCase + def test_re_login + + # login as agent and create one ticket + @browser = browser_instance + login( + username: 'agent1@example.com', + password: 'test', + url: browser_url, + ) + tasks_close_all() + ticket1 = ticket_create( + data: { + customer: 'nico', + group: 'Users', + title: 'some subject 123äöü - reply test', + body: 'some body 123äöü - reply test', + }, + ) + + logout() + + # login as customer and verify ticket create screen + login( + username: 'nicole.braun@zammad.org', + password: 'test', + url: browser_url, + ) + click(css: 'a[href="#new"]') + click(css: 'a[href="#customer_ticket_new"]') + sleep 4 + + match( + css: '#content', + value: 'Priority', + should_not_match: true, + ) + + match( + css: '#content', + value: 'Owner', + should_not_match: true, + ) + + match( + css: '#content', + value: 'State', + ) + + logout() + + # login again as customer and verify ticket create screen + login( + username: 'nicole.braun@zammad.org', + password: 'test', + url: browser_url, + ) + click(css: 'a[href="#new"]') + click(css: 'a[href="#customer_ticket_new"]') + sleep 4 + + match( + css: '#content', + value: 'Priority', + should_not_match: true, + ) + + match( + css: '#content', + value: 'Owner', + should_not_match: true, + ) + + match( + css: '#content', + value: 'State', + ) + + end +end diff --git a/test/fixtures/idoit/object_types_filter_response.json b/test/fixtures/idoit/object_types_filter_response.json new file mode 100644 index 000000000..ea22a92b7 --- /dev/null +++ b/test/fixtures/idoit/object_types_filter_response.json @@ -0,0 +1,18 @@ +{ + "jsonrpc": "2.0", + "result": [{ + "id": "26", + "title": "demo.example.com", + "sysid": "SYSID_1485512390", + "type": "59", + "created": "2017-01-27 11:19:24", + "updated": "2017-01-27 11:19:49", + "type_title": "Virtual server", + "type_group_title": "Infrastructure", + "status": "2", + "cmdb_status": "6", + "cmdb_status_title": "in operation", + "image": "https://idoit.example.com/i-doit/images/objecttypes/empty.png" + }], + "id": 1 +} \ No newline at end of file diff --git a/test/fixtures/idoit/object_types_response.json b/test/fixtures/idoit/object_types_response.json new file mode 100644 index 000000000..5910e6ba9 --- /dev/null +++ b/test/fixtures/idoit/object_types_response.json @@ -0,0 +1,945 @@ +{ + "jsonrpc": "2.0", + "result": [{ + "id": "1", + "title": "System service", + "container": "0", + "const": "C__OBJTYPE__SERVICE", + "color": "987384", + "image": "https://demo.example.com/i-doit/images/objecttypes/service.jpg", + "icon": "images/icons/silk/application_osx_terminal.png", + "cats": "4", + "tree_group": "1", + "status": "2", + "type_group": "1", + "type_group_title": "Software" + }, { + "id": "2", + "title": "Application", + "container": "0", + "const": "C__OBJTYPE__APPLICATION", + "color": "E4B9D7", + "image": "https://demo.example.com/i-doit/images/objecttypes/application.jpg", + "icon": "images/icons/silk/application_xp.png", + "cats": "20", + "tree_group": "1", + "status": "2", + "type_group": "1", + "type_group_title": "Software" + }, { + "id": "33", + "title": "Licenses", + "container": "0", + "const": "C__OBJTYPE__LICENCE", + "color": "EADEAC", + "image": "https://demo.example.com/i-doit/images/objecttypes/licence.png", + "icon": "images/icons/silk/key.png", + "cats": "24", + "tree_group": "1", + "status": "2", + "type_group": "1", + "type_group_title": "Software" + }, { + "id": "35", + "title": "Operating System", + "container": "0", + "const": "C__OBJTYPE__OPERATING_SYSTEM", + "color": "838683", + "image": "https://demo.example.com/i-doit/images/objecttypes/application.jpg", + "icon": "images/icons/silk/application_osx.png", + "cats": "20", + "tree_group": "1", + "status": "2", + "type_group": "1", + "type_group_title": "Software" + }, { + "id": "56", + "title": "Cluster services", + "container": "0", + "const": "C__OBJTYPE__CLUSTER_SERVICE", + "color": "B6BFC9", + "image": "https://demo.example.com/i-doit/images/objecttypes/application.jpg", + "icon": "images/icons/silk/application_cascade.png", + "cats": "58", + "tree_group": "1", + "status": "2", + "type_group": "1", + "type_group_title": "Software" + }, { + "id": "61", + "title": "DBMS", + "container": "0", + "const": "C__OBJTYPE__DBMS", + "color": "AAAAAA", + "image": "https://demo.example.com/i-doit/images/objecttypes/san.png", + "icon": "images/icons/silk/database.png", + "cats": "62", + "tree_group": "1", + "status": "2", + "type_group": "1", + "type_group_title": "Software" + }, { + "id": "62", + "title": "Database schema", + "container": "0", + "const": "C__OBJTYPE__DATABASE_SCHEMA", + "color": "B0C4DE", + "image": "https://demo.example.com/i-doit/images/objecttypes/application.jpg", + "icon": "images/icons/silk/database_table.png", + "cats": "60", + "tree_group": "1", + "status": "2", + "type_group": "1", + "type_group_title": "Software" + }, { + "id": "65", + "title": "Database instance", + "container": "0", + "const": "C__OBJTYPE__DATABASE_INSTANCE", + "color": "61C384", + "image": "https://demo.example.com/i-doit/images/objecttypes/service.jpg", + "icon": "images/icons/silk/database_connect.png", + "cats": "63", + "tree_group": "1", + "status": "2", + "type_group": "1", + "type_group_title": "Software" + }, { + "id": "66", + "title": "Middleware", + "container": "0", + "const": "C__OBJTYPE__MIDDLEWARE", + "color": "EEFFDE", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "middleware.png", + "cats": "75", + "tree_group": "1", + "status": "2", + "type_group": "1", + "type_group_title": "Software" + }, { + "id": "3", + "title": "Building", + "container": "1", + "const": "C__OBJTYPE__BUILDING", + "color": "D1695E", + "image": "https://demo.example.com/i-doit/images/objecttypes/building.png", + "icon": "images/icons/silk/building.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "4", + "title": "Rack", + "container": "1", + "const": "C__OBJTYPE__ENCLOSURE", + "color": "D3E3FA", + "image": "https://demo.example.com/i-doit/images/objecttypes/enclosure.png", + "icon": "images/icons/silk/timeline_marker_rotated.png", + "cats": "1", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "5", + "title": "Server", + "container": "0", + "const": "C__OBJTYPE__SERVER", + "color": "A2BCFA", + "image": "https://demo.example.com/i-doit/images/objecttypes/server.png", + "icon": "images/icons/silk/server.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "6", + "title": "Switch", + "container": "0", + "const": "C__OBJTYPE__SWITCH", + "color": "B8BED1", + "image": "https://demo.example.com/i-doit/images/objecttypes/switch.png", + "icon": "images/icons/silk/drive_network.png", + "cats": "5", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "7", + "title": "Router", + "container": "0", + "const": "C__OBJTYPE__ROUTER", + "color": "97D414", + "image": "https://demo.example.com/i-doit/images/objecttypes/router.png", + "icon": "images/icons/silk/drive_web.png", + "cats": "17", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "8", + "title": "FC switch", + "container": "0", + "const": "C__OBJTYPE__FC_SWITCH", + "color": "9FC380", + "image": "https://demo.example.com/i-doit/images/objecttypes/fcswitch.png", + "icon": "images/icons/silk/drive_network.png", + "cats": "16", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "9", + "title": "Storage system", + "container": "0", + "const": "C__OBJTYPE__SAN", + "color": "F0F0E3", + "image": "https://demo.example.com/i-doit/images/objecttypes/san.png", + "icon": "images/icons/silk/drive_cd_empty.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "10", + "title": "Client", + "container": "0", + "const": "C__OBJTYPE__CLIENT", + "color": "B9E1BE", + "image": "https://demo.example.com/i-doit/images/objecttypes/client.png", + "icon": "images/icons/silk/computer.png", + "cats": "15", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "11", + "title": "Printer", + "container": "0", + "const": "C__OBJTYPE__PRINTER", + "color": "4E93BE", + "image": "https://demo.example.com/i-doit/images/objecttypes/printer.png", + "icon": "images/icons/silk/printer.png", + "cats": "18", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "12", + "title": "Air Condition System", + "container": "0", + "const": "C__OBJTYPE__AIR_CONDITION_SYSTEM", + "color": "A88AA7", + "image": "https://demo.example.com/i-doit/images/objecttypes/aircond.png", + "icon": "klima.gif", + "cats": "9", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "19", + "title": "KVM switch", + "container": "0", + "const": "C__OBJTYPE__KVM_SWITCH", + "color": "7EDF8D", + "image": "https://demo.example.com/i-doit/images/objecttypes/router.png", + "icon": "images/icons/silk/image_link.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "22", + "title": "Monitor", + "container": "0", + "const": "C__OBJTYPE__MONITOR", + "color": "DCE0D7", + "image": "https://demo.example.com/i-doit/images/objecttypes/monitor.png", + "icon": "images/icons/silk/monitor.png", + "cats": "14", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "23", + "title": "Appliance", + "container": "0", + "const": "C__OBJTYPE__APPLIANCE", + "color": "6EAEBF", + "image": "https://demo.example.com/i-doit/images/objecttypes/appliances.png", + "icon": "images/icons/silk/drive_disk.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "24", + "title": "Telephone system", + "container": "0", + "const": "C__OBJTYPE__TELEPHONE_SYSTEM", + "color": "DDEFFC", + "image": "https://demo.example.com/i-doit/images/objecttypes/phonesys.png", + "icon": "images/icons/silk/telephone_link.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "25", + "title": "Printbox", + "container": "0", + "const": "C__OBJTYPE__PRINTBOX", + "color": "90AD8B", + "image": "https://demo.example.com/i-doit/images/objecttypes/printerbox.png", + "icon": "images/icons/silk/printer_empty.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "26", + "title": "Room", + "container": "1", + "const": "C__OBJTYPE__ROOM", + "color": "E4FF9E", + "image": "https://demo.example.com/i-doit/images/objecttypes/room.png", + "icon": "room.gif", + "cats": "3", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "27", + "title": "Wireless Access Point", + "container": "0", + "const": "C__OBJTYPE__ACCESS_POINT", + "color": "C5C8B4", + "image": "https://demo.example.com/i-doit/images/objecttypes/wlan.jpg", + "icon": "images/icons/silk/television.png", + "cats": "13", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "38", + "title": "Phone", + "container": "0", + "const": "C__OBJTYPE__PHONE", + "color": "6886B4", + "image": "https://demo.example.com/i-doit/images/objecttypes/phone.png", + "icon": "images/icons/silk/telephone.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "39", + "title": "Host", + "container": "0", + "const": "C__OBJTYPE__HOST", + "color": "DADA5E", + "image": "https://demo.example.com/i-doit/images/objecttypes/server.png", + "icon": "images/icons/silk/server.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "40", + "title": "Cable", + "container": "0", + "const": "C__OBJTYPE__CABLE", + "color": "B39E92", + "image": "https://demo.example.com/i-doit/images/objecttypes/fcswitch.png", + "icon": "kabel.gif", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "41", + "title": "Converter", + "container": "0", + "const": "C__OBJTYPE__CONVERTER", + "color": "CAB97D", + "image": "https://demo.example.com/i-doit/images/objecttypes/fcswitch.png", + "icon": "images/icons/silk/connect.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "42", + "title": "Wiring System", + "container": "0", + "const": "C__OBJTYPE__WIRING_SYSTEM", + "color": "D1695E", + "image": "https://demo.example.com/i-doit/images/objecttypes/fcswitch.png", + "icon": "images/icons/silk/text_letter_omega.png", + "cats": "40", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "43", + "title": "Patch Panel", + "container": "0", + "const": "C__OBJTYPE__PATCH_PANEL", + "color": "BCDCB9", + "image": "https://demo.example.com/i-doit/images/objecttypes/switch.png", + "icon": "images/icons/silk/drive_rename_dotted.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "44", + "title": "Amplifier", + "container": "0", + "const": "C__OBJTYPE__AMPLIFIER", + "color": "AF7FF1", + "image": "https://demo.example.com/i-doit/images/objecttypes/appliances.png", + "icon": "verstaerker.gif", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "46", + "title": "Electric power company", + "container": "0", + "const": "C__OBJTYPE__ESC", + "color": "EB8348", + "image": "https://demo.example.com/i-doit/images/objecttypes/power.jpg", + "icon": "images/icons/silk/lightbulb.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "47", + "title": "Emergency power supply", + "container": "0", + "const": "C__OBJTYPE__EPS", + "color": "E1E79E", + "image": "https://demo.example.com/i-doit/images/objecttypes/power.jpg", + "icon": "nea.gif", + "cats": "43", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "48", + "title": "Distribution box", + "container": "0", + "const": "C__OBJTYPE__DISTRIBUTION_BOX", + "color": "A5EEA0", + "image": "https://demo.example.com/i-doit/images/objecttypes/power.jpg", + "icon": "verteiler.gif", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "49", + "title": "Power distribution unit", + "container": "0", + "const": "C__OBJTYPE__PDU", + "color": "43CBE1", + "image": "https://demo.example.com/i-doit/images/objecttypes/power.jpg", + "icon": "pdu.gif", + "cats": "64", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "50", + "title": "Uninterruptible power supply", + "container": "0", + "const": "C__OBJTYPE__UPS", + "color": "FDD84E", + "image": "https://demo.example.com/i-doit/images/objecttypes/power.jpg", + "icon": "images/icons/silk/lightning.png", + "cats": "42", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "57", + "title": "Virtual client", + "container": "0", + "const": "C__OBJTYPE__VIRTUAL_CLIENT", + "color": "9FAA7C", + "image": "https://demo.example.com/i-doit/images/objecttypes/client.png", + "icon": "images/icons/silk/computer_link.png", + "cats": "15", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "58", + "title": "Virtual host", + "container": "0", + "const": "C__OBJTYPE__VIRTUAL_HOST", + "color": "E6E9DC", + "image": "https://demo.example.com/i-doit/images/objecttypes/server.png", + "icon": "images/icons/silk/server_database.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "59", + "title": "Virtual server", + "container": "0", + "const": "C__OBJTYPE__VIRTUAL_SERVER", + "color": "6D7F92", + "image": "https://demo.example.com/i-doit/images/objecttypes/server.png", + "icon": "images/icons/silk/server_chart.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "64", + "title": "Replication object", + "container": "0", + "const": "C__OBJTYPE__REPLICATION", + "color": "C9BAEF", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "images/icons/silk/arrow_branch.png", + "cats": "71", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "71", + "title": "Workplace", + "container": "0", + "const": "C__OBJTYPE__WORKSTATION", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/client.png", + "icon": "images/icons/silk/drive_user.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "73", + "title": "Switch chassis", + "container": "1", + "const": "C__OBJTYPE__SWITCH_CHASSIS", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/enclosure.png", + "icon": "images/icons/silk/timeline_marker.png", + "cats": "84", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "74", + "title": "Blade chassis", + "container": "1", + "const": "C__OBJTYPE__BLADE_CHASSIS", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/enclosure.png", + "icon": "images/icons/silk/timeline_marker.png", + "cats": "84", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "75", + "title": "Blade server", + "container": "0", + "const": "C__OBJTYPE__BLADE_SERVER", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/server.png", + "icon": "images/icons/silk/drive.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "76", + "title": "VoIP telephone", + "container": "0", + "const": "C__OBJTYPE__VOIP_PHONE", + "color": "FF8800", + "image": "https://demo.example.com/i-doit/images/objecttypes/phone.png", + "icon": "images/icons/silk/phone_sound.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "84", + "title": "Country", + "container": "1", + "const": "C__OBJTYPE__COUNTRY", + "color": "ACE177", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "images/icons/silk/map.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "85", + "title": "City", + "container": "1", + "const": "C__OBJTYPE__CITY", + "color": "DFB0E1", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "images/icons/city.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "88", + "title": "Remote Management Controller", + "container": "0", + "const": "C__OBJTYPE__RM_CONTROLLER", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/", + "icon": "images/icons/silk/bullet_picture.png", + "tree_group": "2", + "status": "2", + "type_group": "2", + "type_group_title": "Infrastructure" + }, { + "id": "13", + "title": "WAN", + "container": "0", + "const": "C__OBJTYPE__WAN", + "color": "BAE1D2", + "image": "https://demo.example.com/i-doit/images/objecttypes/router.png", + "icon": "images/icons/silk/weather_clouds.png", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "14", + "title": "Emergency plan", + "container": "0", + "const": "C__OBJTYPE__EMERGENCY_PLAN", + "color": "C4FFF9", + "image": "https://demo.example.com/i-doit/images/objecttypes/emergency.jpg", + "icon": "images/icons/silk/text_horizontalrule.png", + "cats": "8", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "28", + "title": "Contract", + "container": "0", + "const": "C__OBJTYPE__MAINTENANCE", + "color": "7AD3C6", + "image": "https://demo.example.com/i-doit/images/objecttypes/maintenance.jpg", + "icon": "images/icons/silk/text_signature.png", + "cats": "81", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "29", + "title": "File", + "container": "0", + "const": "C__OBJTYPE__FILE", + "color": "CDFCF6", + "image": "https://demo.example.com/i-doit/images/objecttypes/application.jpg", + "icon": "images/icons/silk/disk.png", + "cats": "19", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "31", + "title": "Layer 3-Net", + "container": "0", + "const": "C__OBJTYPE__LAYER3_NET", + "color": "7EE0EB", + "image": "https://demo.example.com/i-doit/images/objecttypes/wlan.jpg", + "icon": "images/icons/silk/world_link.png", + "cats": "22", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "32", + "title": "Cellular Phone", + "container": "0", + "const": "C__OBJTYPE__CELL_PHONE_CONTRACT", + "color": "F2F3BA", + "image": "https://demo.example.com/i-doit/images/objecttypes/appliances.png", + "icon": "images/icons/silk/phone.png", + "cats": "23", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "36", + "title": "Object group", + "container": "0", + "const": "C__OBJECT_TYPE__GROUP", + "color": "E1B9DC", + "image": "https://demo.example.com/i-doit/images/objecttypes/printerbox.jpg", + "icon": "images/icons/silk/sitemap_color.png", + "cats": "25", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "45", + "title": "Service", + "container": "0", + "const": "C__OBJTYPE__IT_SERVICE", + "color": "C7F464", + "image": "https://demo.example.com/i-doit/images/objecttypes/service.jpg", + "icon": "images/icons/silk/chart_pie.png", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "51", + "title": "SAN Zoning", + "container": "0", + "const": "C__OBJTYPE__SAN_ZONING", + "color": "DDE143", + "image": "https://demo.example.com/i-doit/images/objecttypes/san.png", + "icon": "images/icons/silk/layers.png", + "cats": "44", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "55", + "title": "Cluster", + "container": "0", + "const": "C__OBJTYPE__CLUSTER", + "color": "9FAAB7", + "image": "https://demo.example.com/i-doit/images/objecttypes/server.png", + "icon": "images/icons/silk/application_cascade.png", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "68", + "title": "Crypto card", + "container": "0", + "const": "C__OBJTYPE__KRYPTO_CARD", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/application.jpg", + "icon": "images/icons/silk/page_white_key.png", + "cats": "76", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "69", + "title": "SIM card", + "container": "0", + "const": "C__OBJTYPE__SIM_CARD", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/application.jpg", + "icon": "images/icons/silk/page_white_database.png", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "70", + "title": "Layer 2 Net", + "container": "0", + "const": "C__OBJTYPE__LAYER2_NET", + "color": "7EE0EB", + "image": "https://demo.example.com/i-doit/images/objecttypes/fcswitch.png", + "icon": "images/icons/silk/page_white_gear.png", + "cats": "79", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "77", + "title": "Supernet", + "container": "1", + "const": "C__OBJTYPE__SUPERNET", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/wlan.jpg", + "icon": "images/icons/silk/world.png", + "cats": "22", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "81", + "title": "Vehicle", + "container": "0", + "const": "C__OBJTYPE__VEHICLE", + "color": "83C5E1", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "images/icons/silk/car.png", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "82", + "title": "Aircraft", + "container": "0", + "const": "C__OBJTYPE__AIRCRAFT", + "color": "479FC4", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "images/icons/airplane.png", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "83", + "title": "VRRP/HSRP Cluster", + "container": "0", + "const": "C__OBJTYPE__CLUSTER_VRRP_HSRP", + "color": "9FAAB7", + "image": "https://demo.example.com/i-doit/images/objecttypes/server.png", + "icon": "images/icons/silk/application_cascade.png", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "89", + "title": "VRRP", + "container": "0", + "const": "C__OBJTYPE__VRRP", + "color": "ABCDEF", + "image": "https://demo.example.com/i-doit/images/objecttypes/switch.png", + "icon": "images/icons/silk/disconnect.png", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "90", + "title": "Stacking", + "container": "0", + "const": "C__OBJTYPE__STACKING", + "color": "FEDCBA", + "image": "https://demo.example.com/i-doit/images/objecttypes/switch.png", + "icon": "images/icons/silk/drive_stack.png", + "tree_group": "3", + "status": "2", + "type_group": "3", + "type_group_title": "Other" + }, { + "id": "52", + "title": "Organization", + "container": "0", + "const": "C__OBJTYPE__ORGANIZATION", + "color": "82E27E", + "image": "https://demo.example.com/i-doit/images/objecttypes/building.png", + "icon": "images/icons/silk/sitemap.png", + "cats": "45", + "tree_group": "1000", + "status": "2", + "type_group": "1000", + "type_group_title": "Contact" + }, { + "id": "53", + "title": "Persons", + "container": "0", + "const": "C__OBJTYPE__PERSON", + "color": "EFAA43", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "images/tree/person_intern.gif", + "cats": "48", + "tree_group": "1000", + "status": "2", + "type_group": "1000", + "type_group_title": "Contact" + }, { + "id": "54", + "title": "Person groups", + "container": "0", + "const": "C__OBJTYPE__PERSON_GROUP", + "color": "F3FFEF", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "images/tree/group.gif", + "cats": "52", + "tree_group": "1000", + "status": "2", + "type_group": "1000", + "type_group_title": "Contact" + }, { + "id": "78", + "title": "Nagios service", + "container": "0", + "const": "C__OBJTYPE__NAGIOS_SERVICE", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "images/icons/silk/database.png", + "tree_group": "1001", + "status": "2", + "type_group": "1001", + "type_group_title": "Nagios" + }, { + "id": "79", + "title": "Nagios service-template", + "container": "0", + "const": "C__OBJTYPE__NAGIOS_SERVICE_TPL", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "images/icons/silk/database.png", + "tree_group": "1001", + "status": "2", + "type_group": "1001", + "type_group_title": "Nagios" + }, { + "id": "80", + "title": "Nagios host-template", + "container": "0", + "const": "C__OBJTYPE__NAGIOS_HOST_TPL", + "color": "FFFFFF", + "image": "https://demo.example.com/i-doit/images/objecttypes/empty.png", + "icon": "images/icons/silk/database.png", + "tree_group": "1001", + "status": "2", + "type_group": "1001", + "type_group_title": "Nagios" + }], + "id": 1 +} \ No newline at end of file diff --git a/test/integration/email_helper_test.rb b/test/integration/email_helper_test.rb index 683ef8bc0..745e6c130 100644 --- a/test/integration/email_helper_test.rb +++ b/test/integration/email_helper_test.rb @@ -209,7 +209,7 @@ class EmailHelperTest < ActiveSupport::TestCase } ) assert_equal('invalid', result[:result]) - assert_equal('Authentication failed, username incorrect!', result[:message_human]) + assert_match(/Authentication failed, username incorrect|Authentication failed, invalid credentials/, result[:message_human]) assert_equal('imap.gmail.com', result[:settings][:options][:host]) result = EmailHelper::Probe.inbound( @@ -225,8 +225,8 @@ class EmailHelperTest < ActiveSupport::TestCase assert_equal('invalid', result[:result]) # if we have to many failed logins, we need to handle another error message - if result[:message_human] && !result[:message_human].empty? - assert_equal('Authentication failed, invalid credentials!', result[:message_human]) + if result[:message_human].present? + assert_match(/Authentication failed, username incorrect|Authentication failed, invalid credentials/, result[:message_human]) else assert_match(/Web login required/, result[:message]) end @@ -457,7 +457,7 @@ class EmailHelperTest < ActiveSupport::TestCase email: mailbox_user, password: mailbox_password, ) - assert_equal(nil, result[:reason]) + assert_nil(result[:reason]) assert_equal('ok', result[:result]) assert_equal('pop.gmail.com', result[:setting][:inbound][:options][:host]) assert_equal('smtp.gmail.com', result[:setting][:outbound][:options][:host]) diff --git a/test/integration/idoit_controller_test.rb b/test/integration/idoit_controller_test.rb new file mode 100644 index 000000000..f7d376066 --- /dev/null +++ b/test/integration/idoit_controller_test.rb @@ -0,0 +1,191 @@ +# encoding: utf-8 +require 'test_helper' +require 'webmock/minitest' + +class IdoitControllerTest < ActionDispatch::IntegrationTest + setup do + + stub_request(:any, 'https://images.zammad.com/api/v1/person/image') + .to_return(status: 404, body: '', headers: {}) + + @token = 'some_token' + @endpoint = 'https://idoit.example.com/i-doit/' + + @headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' } + + Setting.set('idoit_integration', true) + Setting.set('idoit_config', { + api_token: @token, + endpoint: @endpoint, + client_id: '', + }) + groups = Group.where(name: 'Users') + roles = Role.where(name: %w(Agent)) + agent = User.create_or_update( + login: 'idoit-agent@example.com', + firstname: 'E', + lastname: 'S', + email: 'idoit-agent@example.com', + password: 'agentpw', + active: true, + roles: roles, + groups: groups, + updated_by_id: 1, + created_by_id: 1, + ) + roles = Role.where(name: %w(Agent Admin)) + admin = User.create_or_update( + login: 'idoit-admin@example.com', + firstname: 'E', + lastname: 'S', + email: 'idoit-admin@example.com', + password: 'adminpw', + active: true, + roles: roles, + groups: groups, + updated_by_id: 1, + created_by_id: 1, + ) + + customer1 = User.create_or_update( + login: 'ticket-idoit-customer1@example.com', + firstname: 'CallerId', + lastname: 'Customer1', + email: 'ticket-idoit-customer1@example.com', + password: 'customerpw', + active: true, + updated_by_id: 1, + created_by_id: 1, + ) + + end + + test 'unclear urls' do + + agent_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-agent@example.com', 'agentpw') + params = { + api_token: @token, + endpoint: @endpoint, + client_id: '', + } + post '/api/v1/integration/idoit/verify', params: params.to_json, headers: @headers.merge('Authorization' => agent_credentials) + assert_response(401) + result = JSON.parse(@response.body) + assert_equal(Hash, result.class) + assert_not(result.blank?) + assert_equal('Not authorized (user)!', result['error']) + + stub_request(:post, "#{@endpoint}src/jsonrpc.php") + .with(body: "{\"method\":\"cmdb.object_types\",\"params\":{\"apikey\":\"#{@token}\"},\"version\":\"2.0\"}") + .to_return(status: 200, body: read_messaage('object_types_response'), headers: {}) + + admin_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-admin@example.com', 'adminpw') + params = { + api_token: @token, + endpoint: @endpoint, + client_id: '', + } + post '/api/v1/integration/idoit/verify', params: params.to_json, headers: @headers.merge('Authorization' => admin_credentials) + assert_response(200) + result = JSON.parse(@response.body) + assert_equal(Hash, result.class) + assert_not(result.blank?) + assert_equal('ok', result['result']) + assert(result['response']) + assert_equal('2.0', result['response']['jsonrpc']) + assert(result['response']['result']) + + params = { + api_token: @token, + endpoint: " #{@endpoint}/", + client_id: '', + } + post '/api/v1/integration/idoit/verify', params: params.to_json, headers: @headers.merge('Authorization' => admin_credentials) + assert_response(200) + result = JSON.parse(@response.body) + assert_equal(Hash, result.class) + assert_not(result.blank?) + assert_equal('ok', result['result']) + assert(result['response']) + assert_equal('2.0', result['response']['jsonrpc']) + assert(result['response']['result']) + + end + + test 'list all object types' do + + stub_request(:post, "#{@endpoint}src/jsonrpc.php") + .with(body: "{\"method\":\"cmdb.object_types\",\"params\":{\"apikey\":\"#{@token}\"},\"version\":\"2.0\"}") + .to_return(status: 200, body: read_messaage('object_types_response'), headers: {}) + + agent_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-agent@example.com', 'agentpw') + params = { + method: 'cmdb.object_types', + } + post '/api/v1/integration/idoit', params: params.to_json, headers: @headers.merge('Authorization' => agent_credentials) + assert_response(200) + + result = JSON.parse(@response.body) + assert_equal(Hash, result.class) + assert_not(result.blank?) + assert_equal('ok', result['result']) + assert(result['response']) + assert_equal('2.0', result['response']['jsonrpc']) + assert(result['response']['result']) + assert_equal('1', result['response']['result'][0]['id']) + assert_equal('System service', result['response']['result'][0]['title']) + + admin_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-admin@example.com', 'adminpw') + params = { + method: 'cmdb.object_types', + } + post '/api/v1/integration/idoit', params: params.to_json, headers: @headers.merge('Authorization' => admin_credentials) + assert_response(200) + + result = JSON.parse(@response.body) + assert_equal(Hash, result.class) + assert_not(result.blank?) + assert_equal('ok', result['result']) + assert(result['response']) + assert_equal('2.0', result['response']['jsonrpc']) + assert(result['response']['result']) + assert_equal('1', result['response']['result'][0]['id']) + assert_equal('System service', result['response']['result'][0]['title']) + + end + + test 'query objects' do + + stub_request(:post, "#{@endpoint}src/jsonrpc.php") + .with(body: "{\"method\":\"cmdb.objects\",\"params\":{\"apikey\":\"#{@token}\",\"filter\":{\"ids\":[\"33\"]}},\"version\":\"2.0\"}") + .to_return(status: 200, body: read_messaage('object_types_filter_response'), headers: {}) + + agent_credentials = ActionController::HttpAuthentication::Basic.encode_credentials('idoit-agent@example.com', 'agentpw') + params = { + method: 'cmdb.objects', + filter: { + ids: ['33'] + }, + } + post '/api/v1/integration/idoit', params: params.to_json, headers: @headers.merge('Authorization' => agent_credentials) + assert_response(200) + + result = JSON.parse(@response.body) + assert_equal(Hash, result.class) + assert_not(result.blank?) + assert_equal('ok', result['result']) + assert(result['response']) + assert_equal('2.0', result['response']['jsonrpc']) + assert(result['response']['result']) + assert_equal('26', result['response']['result'][0]['id']) + assert_equal('demo.example.com', result['response']['result'][0]['title']) + assert_equal('Virtual server', result['response']['result'][0]['type_title']) + assert_equal('in operation', result['response']['result'][0]['cmdb_status_title']) + + end + + def read_messaage(file) + File.read("test/fixtures/idoit/#{file}.json") + end + +end diff --git a/test/integration/user_device_controller_test.rb b/test/integration/user_device_controller_test.rb index 2f193237f..25611dd26 100644 --- a/test/integration/user_device_controller_test.rb +++ b/test/integration/user_device_controller_test.rb @@ -61,7 +61,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) params = { without_fingerprint: 'none', username: 'user-device-admin', password: 'adminpw' } - post '/api/v1/signin', params.to_json, @headers + post '/api/v1/signin', params: params.to_json, headers: @headers assert_response(422) result = JSON.parse(@response.body) @@ -85,7 +85,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) params = { fingerprint: 'my_finger_print', username: 'user-device-admin', password: 'adminpw' } - post '/api/v1/signin', params.to_json, @headers + post '/api/v1/signin', params: params.to_json, headers: @headers assert_response(201) result = JSON.parse(@response.body) assert_equal(result.class, Hash) @@ -102,7 +102,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest sleep 2 params = {} - get '/api/v1/users', params.to_json, @headers + get '/api/v1/users', params: params.to_json, headers: @headers assert_response(200) result = JSON.parse(@response.body) assert_equal(result.class, Array) @@ -117,7 +117,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest assert_equal(user_device_last.updated_at.to_s, user_device_first.updated_at.to_s) params = { fingerprint: 'my_finger_print' } - get '/api/v1/signshow', params, @headers + get '/api/v1/signshow', params: params, headers: @headers assert_response(200) result = JSON.parse(@response.body) assert_equal(result.class, Hash) @@ -135,7 +135,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest ENV['USER_DEVICE_UPDATED_AT'] = (Time.zone.now - 4.hours).to_s params = {} - get '/api/v1/users', params.to_json, @headers + get '/api/v1/users', params: params.to_json, headers: @headers assert_response(200) result = JSON.parse(@response.body) assert_equal(result.class, Array) @@ -153,7 +153,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch params = {} - get '/api/v1/users', params.to_json, @headers + get '/api/v1/users', params: params.to_json, headers: @headers assert_response(200) result = JSON.parse(@response.body) @@ -171,7 +171,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest test '04 - login index with admin with fingerprint - II' do params = { fingerprint: 'my_finger_print_II', username: 'user-device-admin', password: 'adminpw' } - post '/api/v1/signin', params.to_json, @headers + post '/api/v1/signin', params: params.to_json, headers: @headers assert_response(201) result = JSON.parse(@response.body) @@ -185,7 +185,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest assert(result['config']) assert('my_finger_print_II', controller.session[:user_device_fingerprint]) - get '/api/v1/users', params.to_json, @headers + get '/api/v1/users', params: params.to_json, headers: @headers assert_response(200) result = JSON.parse(@response.body) assert_equal(result.class, Array) @@ -197,7 +197,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) params = { fingerprint: 'my_finger_print_II' } - get '/api/v1/signshow', params, @headers + get '/api/v1/signshow', params: params, headers: @headers assert_response(200) result = JSON.parse(@response.body) assert_equal(result.class, Hash) @@ -214,7 +214,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch params = {} - get '/api/v1/users', params.to_json, @headers + get '/api/v1/users', params: params.to_json, headers: @headers assert_response(200) result = JSON.parse(@response.body) @@ -232,7 +232,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest test '05 - login index with admin with fingerprint - II' do params = { fingerprint: 'my_finger_print_II', username: 'user-device-admin', password: 'adminpw' } - post '/api/v1/signin', params.to_json, @headers + post '/api/v1/signin', params: params.to_json, headers: @headers assert_response(201) result = JSON.parse(@response.body) @@ -253,7 +253,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-admin', 'adminpw') params = {} - get '/api/v1/users', params.to_json, @headers.merge('Authorization' => credentials) + get '/api/v1/users', params: params.to_json, headers: @headers.merge('Authorization' => credentials) assert_response(200) result = JSON.parse(@response.body) @@ -267,7 +267,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest sleep 2 params = {} - get '/api/v1/users', params.to_json, @headers.merge('Authorization' => credentials) + get '/api/v1/users', params: params.to_json, headers: @headers.merge('Authorization' => credentials) assert_response(200) result = JSON.parse(@response.body) @@ -285,7 +285,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest user_device_last.save! params = {} - get '/api/v1/users', params, @headers.merge('Authorization' => credentials) + get '/api/v1/users', params: params, headers: @headers.merge('Authorization' => credentials) assert_response(200) result = JSON.parse(@response.body) @@ -307,7 +307,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-admin', 'adminpw') params = {} - get '/api/v1/users', params.to_json, @headers.merge('Authorization' => credentials) + get '/api/v1/users', params: params.to_json, headers: @headers.merge('Authorization' => credentials) assert_response(200) result = JSON.parse(@response.body) @@ -330,7 +330,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-agent', 'agentpw') params = {} - get '/api/v1/users', params.to_json, @headers.merge('Authorization' => credentials) + get '/api/v1/users', params: params.to_json, headers: @headers.merge('Authorization' => credentials) assert_response(200) result = JSON.parse(@response.body) @@ -353,7 +353,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-agent', 'agentpw') params = {} - get '/api/v1/users', params.to_json, @headers.merge('Authorization' => credentials) + get '/api/v1/users', params: params.to_json, headers: @headers.merge('Authorization' => credentials) assert_response(200) result = JSON.parse(@response.body) @@ -375,7 +375,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest ENV['SWITCHED_FROM_USER_ID'] = @admin.id.to_s params = { fingerprint: 'my_finger_print_II', username: 'user-device-agent', password: 'agentpw' } - post '/api/v1/signin', params.to_json, @headers + post '/api/v1/signin', params: params.to_json, headers: @headers assert_response(201) result = JSON.parse(@response.body) @@ -397,7 +397,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest ENV['USER_DEVICE_UPDATED_AT'] = (Time.zone.now - 4.hours).to_s params = {} - get '/api/v1/users', params.to_json, @headers + get '/api/v1/users', params: params.to_json, headers: @headers assert_response(200) result = JSON.parse(@response.body) assert_equal(result.class, Array) @@ -412,7 +412,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch params = {} - get '/api/v1/users', params.to_json, @headers + get '/api/v1/users', params: params.to_json, headers: @headers assert_response(200) result = JSON.parse(@response.body) diff --git a/test/test_helper.rb b/test/test_helper.rb index 5410c0174..cd46de640 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -62,6 +62,8 @@ class ActiveSupport::TestCase PostmasterFilter.destroy_all Ticket.destroy_all Taskbar.destroy_all + Sla.destroy_all + Calendar.destroy_all # reset settings Setting.all.pluck(:name).each { |name| diff --git a/test/unit/assets_test.rb b/test/unit/assets_test.rb index 526144336..6e30b9007 100644 --- a/test/unit/assets_test.rb +++ b/test/unit/assets_test.rb @@ -446,7 +446,21 @@ class AssetsTest < ActiveSupport::TestCase roles: roles, ) - calendar1 = Calendar.first + calendar1 = Calendar.create_or_update( + name: 'US 1', + timezone: 'America/Los_Angeles', + business_hours: { + mon: { '09:00' => '17:00' }, + tue: { '09:00' => '17:00' }, + wed: { '09:00' => '17:00' }, + thu: { '09:00' => '17:00' }, + fri: { '09:00' => '17:00' } + }, + default: true, + ical_url: nil, + updated_by_id: 1, + created_by_id: 1, + ) ticket_state1 = Ticket::State.find_by(name: 'new') ticket_state2 = Ticket::State.find_by(name: 'open') sla = Sla.create_or_update( diff --git a/test/unit/calendar_test.rb b/test/unit/calendar_test.rb index 6561e3569..0b33fa1b2 100644 --- a/test/unit/calendar_test.rb +++ b/test/unit/calendar_test.rb @@ -61,7 +61,7 @@ class CalendarTest < ActiveSupport::TestCase assert_equal(true, calendar3.default) calendar2.default = true - calendar2.save + calendar2.save! calendar1 = Calendar.find_by(name: 'US 1') calendar2 = Calendar.find_by(name: 'US 2') @@ -72,7 +72,7 @@ class CalendarTest < ActiveSupport::TestCase assert_equal(false, calendar3.default) calendar2.default = false - calendar2.save + calendar2.save! calendar1 = Calendar.find_by(name: 'US 1') calendar2 = Calendar.find_by(name: 'US 2') @@ -82,12 +82,16 @@ class CalendarTest < ActiveSupport::TestCase assert_equal(false, calendar2.default) assert_equal(false, calendar3.default) - calendar1.destroy + calendar1.destroy! calendar2 = Calendar.find_by(name: 'US 2') calendar3 = Calendar.find_by(name: 'US 3') assert_equal(true, calendar2.default) assert_equal(false, calendar3.default) + + calendar2.destroy! + calendar3.destroy! + travel_back end @@ -237,6 +241,8 @@ class CalendarTest < ActiveSupport::TestCase assert_equal('Christmas1', calendar1.public_holidays['2019-12-24']['summary']) assert_nil(calendar1.public_holidays['2020-12-24']) + calendar1.destroy! + travel_back end diff --git a/test/unit/integration_icinga_test.rb b/test/unit/integration_icinga_test.rb index b10e656ff..2a32377ef 100644 --- a/test/unit/integration_icinga_test.rb +++ b/test/unit/integration_icinga_test.rb @@ -8,40 +8,12 @@ class IntegrationIcingaTest < ActiveSupport::TestCase # http://docs.icinga.org/icinga2/latest/doc/module/icinga2/chapter/monitoring-basics#host-states # http://docs.icinga.org/icinga2/latest/doc/module/icinga2/chapter/monitoring-basics#service-states - test 'base tests' do - + setup do Setting.set('icinga_integration', true) + Setting.set('icinga_sender', 'icinga2@monitoring.example.com') + end - # not matching sender - email_raw_string = "To: support@example.com -Subject: PROBLEM - host.internal.loc - CPU Load is WARNING -User-Agent: Heirloom mailx 12.5 7/5/10 -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Transfer-Encoding: quoted-printable -Message-Id: <20160131094621.29ECD400F29C-icinga-1-0@monitoring.znuny.com> -From: icinga_not_matching@monitoring.example.com (icinga) - -***** Icinga ***** - -Notification Type: PROBLEM - -Service: CPU Load -Host: host.internal.loc -Address:=20 -State: WARNING - -Date/Time: 2016-01-31 10:46:20 +0100 - -Additional Info: WARNING - load average: 3.44, 0.99, 0.35 - -Comment: [] = -" - - ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) - assert_equal('new', ticket_p.state.name) - assert(ticket_p.preferences) - assert_not(ticket_p.preferences['icinga']) + test 'base tests' do # RBL check email_raw_string = "To: support@example.com @@ -51,7 +23,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-icinga-1-1@monitoring.znuny.com> -From: icinga@monitoring.example.com (icinga) +From: icinga2@monitoring.example.com (icinga) ***** Icinga 2 Service Monitoring on apn4711.dc.example.com ***** @@ -82,7 +54,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-icinga-1-2@monitoring.znuny.com> -From: icinga@monitoring.example.com (icinga) +From: icinga2@monitoring.example.com (icinga) ***** Icinga 2 Service Monitoring on apn4711.dc.example.com ***** @@ -113,7 +85,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-icinga-1-2@monitoring.znuny.com> -From: icinga@monitoring.example.com (icinga) +From: icinga2@monitoring.example.com (icinga) ***** Icinga 2 Service Monitoring on apn4711.dc.example.com ***** @@ -145,7 +117,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-icinga-2@monitoring.znuny.com> -From: icinga@monitoring.example.com (icinga) +From: icinga2@monitoring.example.com (icinga) ***** Icinga ***** @@ -179,7 +151,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-icinga-3@monitoring.znuny.com> -From: icinga@monitoring.example.com (icinga) +From: icinga2@monitoring.example.com (icinga) ***** Icinga ***** @@ -214,7 +186,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-icinga-4@monitoring.znuny.com> -From: icinga@monitoring.example.com (icinga) +From: icinga2@monitoring.example.com (icinga) ***** Icinga ***** @@ -249,7 +221,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com> -From: icinga@monitoring.example.com (icinga) +From: icinga2@monitoring.example.com (icinga) ***** Icinga ***** @@ -284,7 +256,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com> -From: icinga@monitoring.example.com (icinga) +From: icinga2@monitoring.example.com (icinga) ***** Icinga ***** @@ -317,7 +289,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com> -From: icinga@monitoring.example.com (icinga) +From: icinga2@monitoring.example.com (icinga) ***** Icinga ***** @@ -341,9 +313,246 @@ Comment: [] = assert_equal('apn4711.dc.example.com', ticket_3.preferences['icinga']['host']) assert_nil(ticket_3_1.preferences['icinga']['service']) assert_equal('DOWN', ticket_3_1.preferences['icinga']['state']) + end - #Setting.set('icinga_integration', false) + test 'not matching sender tests' do + + # not matching sender + email_raw_string = "To: support@example.com +Subject: PROBLEM - host.internal.loc - CPU Load is WARNING +User-Agent: Heirloom mailx 12.5 7/5/10 +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-icinga-1-0@monitoring.znuny.com> +From: icinga_not_matching@monitoring.example.com (icinga) + +***** Icinga ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host.internal.loc +Address:=20 +State: WARNING + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: WARNING - load average: 3.44, 0.99, 0.35 + +Comment: [] = +" + + ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_p.state.name) + assert(ticket_p.preferences) + assert_not(ticket_p.preferences['icinga']) + + Setting.set('icinga_sender', 'regex:icinga2@monitoring.example.com') + + # not matching sender + email_raw_string = "To: support@example.com +Subject: PROBLEM - host.internal.loc - CPU Load is WARNING +User-Agent: Heirloom mailx 12.5 7/5/10 +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-icinga-1-0@monitoring.znuny.com> +From: icinga_not_matching@monitoring.example.com (icinga) + +***** Icinga ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host.internal.loc +Address:=20 +State: WARNING + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: WARNING - load average: 3.44, 0.99, 0.35 + +Comment: [] = +" + + ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_p.state.name) + assert(ticket_p.preferences) + assert_not(ticket_p.preferences['icinga']) + + # not matching sender + email_raw_string = "To: support@example.com +Subject: PROBLEM - host.internal.loc - CPU Load is WARNING +User-Agent: Heirloom mailx 12.5 7/5/10 +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-icinga-1-0@monitoring.znuny.com> +Return-Path: bob@example.com + +***** Icinga ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host.internal.loc +Address:=20 +State: WARNING + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: WARNING - load average: 3.44, 0.99, 0.35 + +Comment: [] = +" + + ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_p.state.name) + assert(ticket_p.preferences) + assert_not(ticket_p.preferences['icinga']) + end + + test 'matching sender tests' do + + # matching sender - follow up - CPU Load/host.internal.loc + email_raw_string = "To: support@example.com +Subject: PROBLEM - host.internal.loc - CPU Load is WARNING +User-Agent: Heirloom mailx 12.5 7/5/10 +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-icinga-4@monitoring.znuny.com> +From: icinga2@monitoring.example.com (icinga) + +***** Icinga ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host.internal.loc +Address:=20 +State: WARNING + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: WARNING - load average: 3.44, 0.99, 0.35 + +Comment: [] = +" + + ticket_1_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_1_1.state.name) + assert(ticket_1_1.preferences) + assert(ticket_1_1.preferences['icinga']) + assert_equal('host.internal.loc', ticket_1_1.preferences['icinga']['host']) + assert_equal('CPU Load', ticket_1_1.preferences['icinga']['service']) + assert_equal('WARNING', ticket_1_1.preferences['icinga']['state']) + + Setting.set('icinga_sender', 'regex:icinga2@monitoring.example.com') + + # matching sender I + email_raw_string = "To: support@example.com +Subject: PROBLEM - host1.internal.loc - CPU Load is WARNING +User-Agent: Heirloom mailx 12.5 7/5/10 +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-icinga-4@monitoring.znuny.com> +From: icinga2@monitoring.example.com (icinga) + +***** Icinga ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host1.internal.loc +Address:=20 +State: WARNING + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: WARNING - load average: 3.44, 0.99, 0.35 + +Comment: [] = +" + + ticket_1_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_1_1.state.name) + assert(ticket_1_1.preferences) + assert(ticket_1_1.preferences['icinga']) + assert_equal('host1.internal.loc', ticket_1_1.preferences['icinga']['host']) + assert_equal('CPU Load', ticket_1_1.preferences['icinga']['service']) + assert_equal('WARNING', ticket_1_1.preferences['icinga']['state']) + + # matching sender I + Setting.set('icinga_sender', 'regex:(icinga2|abc123)@monitoring.example.com') + + email_raw_string = "To: support@example.com +Subject: PROBLEM - host2.internal.loc - CPU Load is WARNING +User-Agent: Heirloom mailx 12.5 7/5/10 +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-icinga-4@monitoring.znuny.com> +From: icinga2@monitoring.example.com (icinga) + +***** Icinga ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host2.internal.loc +Address:=20 +State: WARNING + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: WARNING - load average: 3.44, 0.99, 0.35 + +Comment: [] = +" + + ticket_1_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_1_1.state.name) + assert(ticket_1_1.preferences) + assert(ticket_1_1.preferences['icinga']) + assert_equal('host2.internal.loc', ticket_1_1.preferences['icinga']['host']) + assert_equal('CPU Load', ticket_1_1.preferences['icinga']['service']) + assert_equal('WARNING', ticket_1_1.preferences['icinga']['state']) end + test 'recover without problem tests' do + + # host up without problem + email_raw_string = "To: support@example.com +Subject: RECOVERY - apn4711.dc.example.com is UP +User-Agent: Heirloom mailx 12.5 7/5/10 +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com> +From: icinga2@monitoring.example.com (icinga) + +***** Icinga ***** + +Notification Type: RECOVERY + +Host: apn4711.dc.example.com +Address: 127.0.0.1 +State: UP + +Date/Time: 2017-01-14 12:07:11 +0100 + +Additional Info: PING OK - Packet loss = 0%, RTA = 21.37 ms + +Comment: [] = +" + ticket_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + ticket_count = Ticket.count + assert_not(ticket_1) + assert_equal(ticket_count, Ticket.count) + end + end diff --git a/test/unit/integration_nagios_test.rb b/test/unit/integration_nagios_test.rb index e4ef19189..4e33aa405 100644 --- a/test/unit/integration_nagios_test.rb +++ b/test/unit/integration_nagios_test.rb @@ -6,38 +6,12 @@ class IntegrationNagiosTest < ActiveSupport::TestCase # according # https://github.com/NagiosEnterprises/nagioscore/blob/754218e67653929a58938b99ef6b6039b6474fe4/sample-config/template-object/commands.cfg.in#L35 - test 'base tests' do - + setup do Setting.set('nagios_integration', true) + Setting.set('nagios_sender', 'nagios2@monitoring.example.com') + end - # not matching sender - email_raw_string = "To: support@example.com -Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING ** -MIME-Version: 1.0 -Content-Type: text/plain; charset=us-ascii -Content-Transfer-Encoding: quoted-printable -Message-Id: <20160131094621.29ECD400F29C-nagios-1@monitoring.znuny.com> -From: nagios_not_matching@monitoring.example.com (nagios) - -***** Nagios ***** - -Notification Type: PROBLEM - -Service: CPU Load -Host: host.internal.loc -Address: 1.1.1.1 -State: PROBLEM - -Date/Time: 2016-01-31 10:46:20 +0100 - -Additional Info: -WARNING - load average: 3.44, 0.99, 0.35 -" - - ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) - assert_equal('new', ticket_p.state.name) - assert(ticket_p.preferences) - assert_not(ticket_p.preferences['nagios']) + test 'base tests' do # matching sender - CPU Load/host.internal.loc email_raw_string = "To: support@example.com @@ -46,7 +20,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-nagios-2@monitoring.znuny.com> -From: nagios@monitoring.example.com (nagios) +From: nagios2@monitoring.example.com (nagios) ***** Nagios ***** @@ -78,7 +52,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-nagios-3@monitoring.znuny.com> -From: nagios@monitoring.example.com (nagios) +From: nagios2@monitoring.example.com (nagios) ***** Nagios ***** @@ -111,7 +85,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-nagios-4@monitoring.znuny.com> -From: nagios@monitoring.example.com (nagios) +From: nagios2@monitoring.example.com (nagios) ***** Nagios ***** @@ -144,7 +118,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com> -From: nagios@monitoring.example.com (nagios) +From: nagios2@monitoring.example.com (nagios) ***** Nagios ***** @@ -176,7 +150,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com> -From: nagios@monitoring.example.com (nagios) +From: nagios2@monitoring.example.com (nagios) ***** Nagios ***** @@ -209,7 +183,7 @@ MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: quoted-printable Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com> -From: nagios@monitoring.example.com (nagios) +From: nagios2@monitoring.example.com (nagios) ***** Nagios ***** @@ -238,4 +212,232 @@ Comment: [] = end + test 'not matching sender tests' do + + # not matching sender + email_raw_string = "To: support@example.com +Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING ** +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-nagios-1@monitoring.znuny.com> +From: nagios_not_matching@monitoring.example.com (nagios) + +***** Nagios ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host.internal.loc +Address: 1.1.1.1 +State: PROBLEM + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: +WARNING - load average: 3.44, 0.99, 0.35 +" + + ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_p.state.name) + assert(ticket_p.preferences) + assert_not(ticket_p.preferences['nagios']) + + Setting.set('nagios_sender', 'regex:icinga2@monitoring.example.com') + + # not matching sender + email_raw_string = "To: support@example.com +Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING ** +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-nagios-1@monitoring.znuny.com> +From: nagios_not_matching@monitoring.example.com (nagios) + +***** Nagios ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host.internal.loc +Address: 1.1.1.1 +State: PROBLEM + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: +WARNING - load average: 3.44, 0.99, 0.35 +" + + ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_p.state.name) + assert(ticket_p.preferences) + assert_not(ticket_p.preferences['nagios']) + + # not matching sender + email_raw_string = "To: support@example.com +Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING ** +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-nagios-1@monitoring.znuny.com> +Return-Path: bob@example.com + +***** Nagios ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host.internal.loc +Address: 1.1.1.1 +State: PROBLEM + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: +WARNING - load average: 3.44, 0.99, 0.35 +" + + ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_p.state.name) + assert(ticket_p.preferences) + assert_not(ticket_p.preferences['nagios']) + end + + test 'matching sender tests' do + + # matching sender - follow up - CPU Load/host.internal.loc + email_raw_string = "To: support@example.com +Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING ** +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-nagios-2@monitoring.znuny.com> +From: nagios2@monitoring.example.com (nagios) + +***** Nagios ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host.internal.loc +Address: 1.1.1.1 +State: WARNING + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: +WARNING - load average: 3.44, 0.99, 0.35 +" + + ticket_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_1.state.name) + assert(ticket_1.preferences) + assert(ticket_1.preferences['nagios']) + assert_equal('host.internal.loc', ticket_1.preferences['nagios']['host']) + assert_equal('CPU Load', ticket_1.preferences['nagios']['service']) + assert_equal('WARNING', ticket_1.preferences['nagios']['state']) + + Setting.set('icinga_sender', 'regex:icinga2@monitoring.example.com') + + # matching sender I + email_raw_string = "To: support@example.com +Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING ** +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-nagios-2@monitoring.znuny.com> +From: nagios2@monitoring.example.com (nagios) + +***** Nagios ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host1.internal.loc +Address: 1.1.1.1 +State: WARNING + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: +WARNING - load average: 3.44, 0.99, 0.35 +" + + ticket_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_1.state.name) + assert(ticket_1.preferences) + assert(ticket_1.preferences['nagios']) + assert_equal('host1.internal.loc', ticket_1.preferences['nagios']['host']) + assert_equal('CPU Load', ticket_1.preferences['nagios']['service']) + assert_equal('WARNING', ticket_1.preferences['nagios']['state']) + + # matching sender I + Setting.set('icinga_sender', 'regex:(icinga2|abc123)@monitoring.example.com') + + email_raw_string = "To: support@example.com +Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING ** +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-nagios-2@monitoring.znuny.com> +From: nagios2@monitoring.example.com (nagios) + +***** Nagios ***** + +Notification Type: PROBLEM + +Service: CPU Load +Host: host2.internal.loc +Address: 1.1.1.1 +State: WARNING + +Date/Time: 2016-01-31 10:46:20 +0100 + +Additional Info: +WARNING - load average: 3.44, 0.99, 0.35 +" + + ticket_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + assert_equal('new', ticket_1.state.name) + assert(ticket_1.preferences) + assert(ticket_1.preferences['nagios']) + assert_equal('host2.internal.loc', ticket_1.preferences['nagios']['host']) + assert_equal('CPU Load', ticket_1.preferences['nagios']['service']) + assert_equal('WARNING', ticket_1.preferences['nagios']['state']) + + end + + test 'recover without problem tests' do + + # host up without problem + email_raw_string = "To: support@example.com +Subject: ** RECOVERY Host Alert: apn4711.dc.example.com is UP ** +User-Agent: Heirloom mailx 12.5 7/5/10 +MIME-Version: 1.0 +Content-Type: text/plain; charset=us-ascii +Content-Transfer-Encoding: quoted-printable +Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com> +From: nagios2@monitoring.example.com (nagios) + +***** Nagios ***** + +Notification Type: RECOVERY + +Host: apn4711.dc.example.com +Address: 127.0.0.1 +State: UP + +Date/Time: 2017-01-14 12:07:11 +0100 + +Additional Info: PING OK - Packet loss = 0%, RTA = 21.37 ms + +Comment: [] = +" + ticket_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string) + ticket_count = Ticket.count + assert_not(ticket_1) + assert_equal(ticket_count, Ticket.count) + end + end diff --git a/test/unit/karma_test.rb b/test/unit/karma_test.rb index fff87bf49..c53bd09ed 100644 --- a/test/unit/karma_test.rb +++ b/test/unit/karma_test.rb @@ -91,7 +91,7 @@ class KarmaTest < ActiveSupport::TestCase ticket1.updated_by_id = agent1.id ticket1.updated_at = Time.zone.now - 9.hours ticket1.created_at = Time.zone.now - 9.hours - ticket1.save + ticket1.save! # execute object transaction Observer::Transaction.commit @@ -113,7 +113,7 @@ class KarmaTest < ActiveSupport::TestCase ticket1.updated_by_id = agent1.id ticket1.updated_at = Time.zone.now - 9.hours ticket1.created_at = Time.zone.now - 9.hours - ticket1.save + ticket1.save! # execute object transaction Observer::Transaction.commit @@ -127,7 +127,7 @@ class KarmaTest < ActiveSupport::TestCase ticket1.updated_by_id = agent2.id ticket1.updated_at = Time.zone.now - 9.hours ticket1.created_at = Time.zone.now - 9.hours - ticket1.save + ticket1.save! # execute object transaction Observer::Transaction.commit @@ -138,7 +138,7 @@ class KarmaTest < ActiveSupport::TestCase assert_equal(0, Karma.score_by_user(customer1)) ticket1.state = Ticket::State.lookup(name: 'open') - ticket1.save + ticket1.save! Ticket::Article.create( ticket_id: ticket1.id, @@ -169,7 +169,7 @@ class KarmaTest < ActiveSupport::TestCase Scheduler.worker(true) ticket1.state = Ticket::State.lookup(name: 'closed') - ticket1.save + ticket1.save! # execute object transaction Observer::Transaction.commit @@ -385,7 +385,7 @@ class KarmaTest < ActiveSupport::TestCase ticket2.state = Ticket::State.lookup(name: 'pending reminder') ticket2.pending_time = Time.zone.now - 1.day - ticket2.save + ticket2.save! Ticket.process_pending @@ -395,7 +395,7 @@ class KarmaTest < ActiveSupport::TestCase ticket2.state = Ticket::State.lookup(name: 'pending reminder') ticket2.pending_time = Time.zone.now - 3.days - ticket2.save + ticket2.save! Ticket.process_pending @@ -459,7 +459,7 @@ class KarmaTest < ActiveSupport::TestCase created_by_id: 1, ) ticket2.state = Ticket::State.lookup(name: 'open') - ticket2.save + ticket2.save! Observer::Transaction.commit Scheduler.worker(true) @@ -511,10 +511,10 @@ class KarmaTest < ActiveSupport::TestCase assert_equal('Hero', Karma::User.level_by_score(50_000)) # cleanup - ticket1.destroy - ticket2.destroy - calendar1.destroy - sla1.destroy + ticket1.destroy! + ticket2.destroy! + calendar1.destroy! + sla1.destroy! end diff --git a/test/unit/package_test.rb b/test/unit/package_test.rb index 036f8a285..4ba9d4d59 100644 --- a/test/unit/package_test.rb +++ b/test/unit/package_test.rb @@ -33,7 +33,7 @@ class PackageTest < ActiveSupport::TestCase { "permission": "644", "location": "db/addon/unit_test_sample/20121212000001_create_base.rb", - "content": "Y2xhc3MgQ3JlYXRlQmFzZSA8IEFjdGl2ZVJlY29yZDo6TWlncmF0aW9uDQogIGRlZiBzZWxmLnVw\nDQogICBjcmVhdGVfdGFibGUgOnNhbXBsZV90YWJsZXMgZG8gfHR8DQogICAgICB0LmNvbHVtbiA6\nbmFtZSwgICAgICAgICAgIDpzdHJpbmcsIDpsaW1pdCA9PiAxNTAsICA6bnVsbCA9PiB0cnVlDQog\nICAgICB0LmNvbHVtbiA6ZGF0YSwgICAgICAgICAgIDpzdHJpbmcsIDpsaW1pdCA9PiA1MDAwLCA6\nbnVsbCA9PiB0cnVlDQogICAgZW5kDQogIGVuZA0KDQogIGRlZiBzZWxmLmRvd24NCiAgICBkcm9w\nX3RhYmxlIDpzYW1wbGVfdGFibGVzDQogIGVuZA0KZW5k" + "content": "Y2xhc3MgQ3JlYXRlQmFzZSA8IEFjdGl2ZVJlY29yZDo6TWlncmF0aW9uWzQuMl0NCiAgZGVmIHNlbGYudXANCiAgIGNyZWF0ZV90YWJsZSA6c2FtcGxlX3RhYmxlcyBkbyB8dHwNCiAgICAgIHQuY29sdW1uIDpuYW1lLCAgICAgICAgICAgOnN0cmluZywgOmxpbWl0ID0+IDE1MCwgIDpudWxsID0+IHRydWUNCiAgICAgIHQuY29sdW1uIDpkYXRhLCAgICAgICAgICAgOnN0cmluZywgOmxpbWl0ID0+IDUwMDAsIDpudWxsID0+IHRydWUNCiAgICBlbmQNCiAgZW5kDQoNCiAgZGVmIHNlbGYuZG93bg0KICAgIGRyb3BfdGFibGUgOnNhbXBsZV90YWJsZXMNCiAgZW5kDQplbmQ=" } ] }', @@ -168,7 +168,7 @@ class PackageTest < ActiveSupport::TestCase { "permission": "644", "location": "db/addon/unit_test_sample/20121212000001_create_base.rb", - "content": "Y2xhc3MgQ3JlYXRlQmFzZSA8IEFjdGl2ZVJlY29yZDo6TWlncmF0aW9uDQogIGRlZiBzZWxmLnVw\nDQogICBjcmVhdGVfdGFibGUgOnNhbXBsZV90YWJsZXMgZG8gfHR8DQogICAgICB0LmNvbHVtbiA6\nbmFtZSwgICAgICAgICAgIDpzdHJpbmcsIDpsaW1pdCA9PiAxNTAsICA6bnVsbCA9PiB0cnVlDQog\nICAgICB0LmNvbHVtbiA6ZGF0YSwgICAgICAgICAgIDpzdHJpbmcsIDpsaW1pdCA9PiA1MDAwLCA6\nbnVsbCA9PiB0cnVlDQogICAgZW5kDQogIGVuZA0KDQogIGRlZiBzZWxmLmRvd24NCiAgICBkcm9w\nX3RhYmxlIDpzYW1wbGVfdGFibGVzDQogIGVuZA0KZW5k" + "content": "Y2xhc3MgQ3JlYXRlQmFzZSA8IEFjdGl2ZVJlY29yZDo6TWlncmF0aW9uWzQuMl0NCiAgZGVmIHNlbGYudXANCiAgIGNyZWF0ZV90YWJsZSA6c2FtcGxlX3RhYmxlcyBkbyB8dHwNCiAgICAgIHQuY29sdW1uIDpuYW1lLCAgICAgICAgICAgOnN0cmluZywgOmxpbWl0ID0+IDE1MCwgIDpudWxsID0+IHRydWUNCiAgICAgIHQuY29sdW1uIDpkYXRhLCAgICAgICAgICAgOnN0cmluZywgOmxpbWl0ID0+IDUwMDAsIDpudWxsID0+IHRydWUNCiAgICBlbmQNCiAgZW5kDQoNCiAgZGVmIHNlbGYuZG93bg0KICAgIGRyb3BfdGFibGUgOnNhbXBsZV90YWJsZXMNCiAgZW5kDQplbmQ=" } ] }', @@ -248,7 +248,7 @@ class PackageTest < ActiveSupport::TestCase { "permission": "644", "location": "db/addon/unit_test_sample/20121212000001_create_base.rb", - "content": "Y2xhc3MgQ3JlYXRlQmFzZSA8IEFjdGl2ZVJlY29yZDo6TWlncmF0aW9uDQogIGRlZiBzZWxmLnVw\nDQogICBjcmVhdGVfdGFibGUgOnNhbXBsZV90YWJsZXMgZG8gfHR8DQogICAgICB0LmNvbHVtbiA6\nbmFtZSwgICAgICAgICAgIDpzdHJpbmcsIDpsaW1pdCA9PiAxNTAsICA6bnVsbCA9PiB0cnVlDQog\nICAgICB0LmNvbHVtbiA6ZGF0YSwgICAgICAgICAgIDpzdHJpbmcsIDpsaW1pdCA9PiA1MDAwLCA6\nbnVsbCA9PiB0cnVlDQogICAgZW5kDQogIGVuZA0KDQogIGRlZiBzZWxmLmRvd24NCiAgICBkcm9w\nX3RhYmxlIDpzYW1wbGVfdGFibGVzDQogIGVuZA0KZW5k" + "content": "Y2xhc3MgQ3JlYXRlQmFzZSA8IEFjdGl2ZVJlY29yZDo6TWlncmF0aW9uWzQuMl0NCiAgZGVmIHNlbGYudXANCiAgIGNyZWF0ZV90YWJsZSA6c2FtcGxlX3RhYmxlcyBkbyB8dHwNCiAgICAgIHQuY29sdW1uIDpuYW1lLCAgICAgICAgICAgOnN0cmluZywgOmxpbWl0ID0+IDE1MCwgIDpudWxsID0+IHRydWUNCiAgICAgIHQuY29sdW1uIDpkYXRhLCAgICAgICAgICAgOnN0cmluZywgOmxpbWl0ID0+IDUwMDAsIDpudWxsID0+IHRydWUNCiAgICBlbmQNCiAgZW5kDQoNCiAgZGVmIHNlbGYuZG93bg0KICAgIGRyb3BfdGFibGUgOnNhbXBsZV90YWJsZXMNCiAgZW5kDQplbmQ=" } ] }', @@ -304,57 +304,57 @@ class PackageTest < ActiveSupport::TestCase tests.each { |test| if test[:action] == 'install' begin - package = Package.install( string: test[:zpm] ) + package = Package.install(string: test[:zpm]) rescue => e puts 'ERROR: ' + e.inspect end if test[:result] - assert( package, 'install package not successful' ) + assert(package, 'install package not successful') issues = package.verify - assert( !issues, 'package verify not successful' ) + assert(!issues, 'package verify not successful') else - assert( !package, 'install package successful but should not' ) + assert(!package, 'install package successful but should not') end elsif test[:action] == 'reinstall' begin - package = Package.reinstall( test[:name] ) + package = Package.reinstall(test[:name]) rescue package = false end if test[:result] - assert( package, 'reinstall package not successful' ) + assert(package, 'reinstall package not successful') issues = package.verify - assert( !issues, 'package verify not successful' ) + assert(!issues, 'package verify not successful') else - assert( !package, 'reinstall package successful but should not' ) + assert(!package, 'reinstall package successful but should not') end elsif test[:action] == 'uninstall' if test[:zpm] begin - package = Package.uninstall( string: test[:zpm] ) + package = Package.uninstall(string: test[:zpm]) rescue package = false end else begin - package = Package.uninstall( name: test[:name], version: test[:version] ) + package = Package.uninstall(name: test[:name], version: test[:version]) rescue package = false end end if test[:result] - assert( package, 'uninstall package not successful' ) + assert(package, 'uninstall package not successful') else - assert( !package, 'uninstall package successful but should not' ) + assert(!package, 'uninstall package successful but should not') end elsif test[:action] == 'auto_install' if test[:zpm] - if !File.exist?( Rails.root.to_s + '/auto_install/' ) - Dir.mkdir( Rails.root.to_s + '/auto_install/', 0o755) + if !File.exist?(Rails.root.to_s + '/auto_install/') + Dir.mkdir(Rails.root.to_s + '/auto_install/', 0o755) end location = Rails.root.to_s + '/auto_install/unittest.zpm' - file = File.new( location, 'wb' ) - file.write( test[:zpm] ) + file = File.new(location, 'wb') + file.write(test[:zpm]) file.close end begin @@ -363,22 +363,22 @@ class PackageTest < ActiveSupport::TestCase success = false end if test[:zpm] - File.delete( location ) + File.delete(location ) end end if test[:verify] && test[:verify][:package] - exists = Package.where( name: test[:verify][:package][:name], version: test[:verify][:package][:version] ).first - assert( exists, "package '#{test[:verify][:package][:name]}' is not installed" ) + exists = Package.where(name: test[:verify][:package][:name], version: test[:verify][:package][:version]).first + assert(exists, "package '#{test[:verify][:package][:name]}' is not installed" ) end next if !test[:verify] next if !test[:verify][:check_files] test[:verify][:check_files].each { |item| - exists = File.exist?( item[:location] ) + exists = File.exist?(item[:location]) if item[:result] - assert( exists, "'#{item[:location]}' exists" ) + assert(exists, "'#{item[:location]}' exists" ) else - assert( !exists, "'#{item[:location]}' doesn't exists" ) + assert(!exists, "'#{item[:location]}' doesn't exists" ) end } } diff --git a/test/unit/ticket_escalation_test.rb b/test/unit/ticket_escalation_test.rb new file mode 100644 index 000000000..a79be51ca --- /dev/null +++ b/test/unit/ticket_escalation_test.rb @@ -0,0 +1,129 @@ +# encoding: utf-8 +require 'test_helper' + +class TicketEscalationTest < ActiveSupport::TestCase + test 'ticket create' do + ticket = Ticket.new( + title: 'some value 123', + group: Group.lookup(name: 'Users'), + customer_id: 2, + updated_by_id: 1, + created_by_id: 1, + ) + ticket.save! + assert(ticket, 'ticket created') + assert_not(ticket.escalation_at) + assert_not(ticket.has_changes_to_save?) + + article = Ticket::Article.create!( + ticket_id: ticket.id, + type_id: Ticket::Article::Type.find_by(name: 'note').id, + sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id, + body: 'some body', + internal: false, + updated_by_id: 1, + created_by_id: 1, + ) + assert_not(article.has_changes_to_save?) + assert_not(ticket.has_changes_to_save?) + + calendar = Calendar.create_or_update( + name: 'Escalation Test', + timezone: 'Europe/Berlin', + business_hours: { + mon: { + active: true, + timeframes: [ ['00:00', '23:59'] ] + }, + tue: { + active: true, + timeframes: [ ['00:00', '23:59'] ] + }, + wed: { + active: true, + timeframes: [ ['00:00', '23:59'] ] + }, + thu: { + active: true, + timeframes: [ ['00:00', '23:59'] ] + }, + fri: { + active: true, + timeframes: [ ['00:00', '23:59'] ] + }, + sat: { + active: true, + timeframes: [ ['00:00', '23:59'] ] + }, + sun: { + active: true, + timeframes: [ ['00:00', '23:59'] ] + }, + }, + default: true, + ical_url: nil, + updated_by_id: 1, + created_by_id: 1, + ) + + sla = Sla.create_or_update( + name: 'test sla 1', + condition: { + 'ticket.title' => { + operator: 'contains', + value: 'some value 123', + }, + }, + first_response_time: 60, + update_time: 180, + solution_time: 240, + calendar_id: calendar.id, + updated_by_id: 1, + created_by_id: 1, + ) + + ticket = Ticket.new( + title: 'some value 123', + group: Group.lookup(name: 'Users'), + customer_id: 2, + updated_by_id: 1, + created_by_id: 1, + ) + ticket.save! + assert(ticket, 'ticket created') + ticket_escalation_at = ticket.escalation_at + assert(ticket.escalation_at) + assert_not(ticket.has_changes_to_save?) + + article = Ticket::Article.create!( + ticket_id: ticket.id, + type_id: Ticket::Article::Type.find_by(name: 'note').id, + sender_id: Ticket::Article::Sender.find_by(name: 'Customer').id, + body: 'some body', + internal: false, + updated_by_id: 1, + created_by_id: 1, + ) + assert_not(article.has_changes_to_save?) + assert_not(ticket.has_changes_to_save?) + + travel 1.second + + sla.first_response_time = 30 + sla.save! + + ticket.save! + assert_not(ticket.has_changes_to_save?) + assert(ticket.escalation_at) + assert_not_equal(ticket_escalation_at.to_s, ticket.escalation_at.to_s) + + sla.destroy! + calendar.destroy! + + ticket.save! + assert_not(ticket.has_changes_to_save?) + assert_not(ticket.escalation_at) + + end + +end diff --git a/test/unit/ticket_overview_out_of_office_test.rb b/test/unit/ticket_overview_out_of_office_test.rb index bbd7ca464..f1901f628 100644 --- a/test/unit/ticket_overview_out_of_office_test.rb +++ b/test/unit/ticket_overview_out_of_office_test.rb @@ -224,8 +224,6 @@ class TicketOverviewOutOfOfficeTest < ActiveSupport::TestCase @agent1.out_of_office_replacement_id = @agent2.id @agent1.save! - p User.where(active: true, out_of_office: true, out_of_office_replacement_id: @agent2.id) - p User.where(active: true, out_of_office: true, out_of_office_replacement_id: @agent2.id).where('out_of_office_start_at <= ? AND out_of_office_end_at >= ?', Time.zone.today, Time.zone.today) assert_equal(@agent2.out_of_office_agent_of.count, 1) assert(@agent2.out_of_office_agent_of[0]) assert_equal(@agent2.out_of_office_agent_of[0].id, @agent1.id) diff --git a/test/unit/ticket_sla_test.rb b/test/unit/ticket_sla_test.rb index 3f0c45454..fa17d4eb9 100644 --- a/test/unit/ticket_sla_test.rb +++ b/test/unit/ticket_sla_test.rb @@ -497,6 +497,8 @@ class TicketSlaTest < ActiveSupport::TestCase assert_equal(ticket.last_contact_agent_at.to_s, article_outbound.created_at.to_s, 'ticket.last_contact_agent_at verify - inbound') assert_equal(ticket.first_response_at.to_s, article_outbound.created_at.to_s, 'ticket.first_response_at verify - inbound') assert_nil(ticket.close_at, 'ticket.close_at verify - inbound') + calendar1.destroy! + calendar2.destroy! end test 'ticket sla + selector' do @@ -605,6 +607,7 @@ class TicketSlaTest < ActiveSupport::TestCase assert_nil(ticket.close_in_min, 'ticket.close_in_min') assert_nil(ticket.close_diff_in_min, 'ticket.close_diff_in_min') + calendar1.destroy! end test 'ticket sla + timezone + holiday' do @@ -849,12 +852,13 @@ class TicketSlaTest < ActiveSupport::TestCase assert_equal(ticket.update_escalation_at.gmtime.to_s, '2015-09-23 08:30:00 UTC', 'ticket.update_escalation_at verify 1') assert_equal(ticket.close_escalation_at.gmtime.to_s, '2015-09-23 09:30:00 UTC', 'ticket.close_escalation_at verify 1') - delete = sla.destroy + delete = sla.destroy! assert(delete, 'sla destroy') - delete = ticket.destroy + delete = ticket.destroy! assert(delete, 'ticket destroy') + calendar.destroy! end test 'ticket escalation suspend close reopen bug' do @@ -1043,13 +1047,15 @@ class TicketSlaTest < ActiveSupport::TestCase assert_nil(ticket2.first_response_in_min, 'ticket2.first_response_in_min verify 3') assert_nil(ticket2.first_response_diff_in_min, 'ticket2.first_response_diff_in_min verify 3') - delete = sla.destroy + delete = sla.destroy! assert(delete, 'sla destroy') - delete = ticket1.destroy + delete = ticket1.destroy! assert(delete, 'ticket1 destroy') - delete = ticket2.destroy + delete = ticket2.destroy! assert(delete, 'ticket2 destroy') + + calendar.destroy! end test 'ticket escalation suspend' do @@ -1552,12 +1558,13 @@ class TicketSlaTest < ActiveSupport::TestCase assert_equal(ticket.close_in_min, 60, 'ticket.close_in_min verify 3') assert_equal(ticket.close_diff_in_min, 180, 'ticket.close_diff_in_min# verify 3') - delete = sla.destroy + delete = sla.destroy! assert(delete, 'sla destroy') - delete = ticket.destroy + delete = ticket.destroy! assert(delete, 'ticket destroy') + calendar.destroy! end test 'ticket ticket.title and article.subject' do @@ -1718,12 +1725,13 @@ class TicketSlaTest < ActiveSupport::TestCase assert_nil(ticket.close_in_min, 'ticket.close_in_min verify 3') assert_nil(ticket.close_diff_in_min, 'ticket.close_diff_in_min# verify 3') - delete = sla.destroy + delete = sla.destroy! assert(delete, 'sla destroy') - delete = ticket.destroy + delete = ticket.destroy! assert(delete, 'ticket destroy') + calendar.destroy! end test 'ticket sla + holiday 222' do @@ -1943,11 +1951,13 @@ class TicketSlaTest < ActiveSupport::TestCase assert_equal(ticket.update_escalation_at.gmtime.to_s, '2016-11-09 10:26:36 UTC', 'ticket.update_escalation_at verify 1') assert_nil(ticket.close_escalation_at, 'ticket.close_escalation_at verify 1') - delete = sla.destroy + delete = sla.destroy! assert(delete, 'sla destroy') - delete = ticket.destroy + delete = ticket.destroy! assert(delete, 'ticket destroy') + + calendar.destroy! end test 'ticket sla + observer check' do @@ -2124,11 +2134,13 @@ class TicketSlaTest < ActiveSupport::TestCase assert_equal(ticket.update_escalation_at.gmtime.to_s, '2016-11-07 15:26:36 UTC', 'ticket.update_escalation_at verify 1') assert_nil(ticket.close_escalation_at, 'ticket.close_escalation_at verify 1') - delete = sla.destroy + delete = sla.destroy! assert(delete, 'sla destroy') - delete = ticket.destroy + delete = ticket.destroy! assert(delete, 'ticket destroy') + + calendar.destroy! end end