Merge branch 'develop' of git.znuny.com:zammad/zammad into develop

This commit is contained in:
Felix Niklas 2017-09-26 09:26:43 +02:00
commit 17f48b5335
72 changed files with 3262 additions and 830 deletions

View file

@ -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! - Add the `log/production.log` file from your system. Attention: Make sure no confidential data is in it!
- Please write the issue in english - 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 * * The upper textblock will be removed automatically when you submit your issue *
--> -->

View file

@ -278,6 +278,18 @@ test:integration:telegram:
- ruby -I test test/integration/telegram_controller_test.rb - ruby -I test test/integration/telegram_controller_test.rb
- rake db:drop - 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: test:integration:es_mysql:
stage: test stage: test
tags: tags:

View file

@ -2,7 +2,7 @@ source 'https://rubygems.org'
ruby '2.4.1' ruby '2.4.1'
gem 'rails', '5.0.5' gem 'rails', '5.1.4'
gem 'rails-observers' gem 'rails-observers'
gem 'activerecord-session_store' gem 'activerecord-session_store'
@ -53,7 +53,8 @@ gem 'mime-types'
gem 'biz' 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 'delayed_job_active_record'
gem 'daemons' gem 'daemons'

View file

@ -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 GIT
remote: https://github.com/thorsteneckel/autodiscover.git remote: https://github.com/thorsteneckel/autodiscover.git
revision: 29d713ee0c8c25fcf74c4292ff13fe1fa4d0d827 revision: 29d713ee0c8c25fcf74c4292ff13fe1fa4d0d827
@ -17,38 +25,38 @@ GIT
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (5.0.5) actioncable (5.1.4)
actionpack (= 5.0.5) actionpack (= 5.1.4)
nio4r (>= 1.2, < 3.0) nio4r (~> 2.0)
websocket-driver (~> 0.6.1) websocket-driver (~> 0.6.1)
actionmailer (5.0.5) actionmailer (5.1.4)
actionpack (= 5.0.5) actionpack (= 5.1.4)
actionview (= 5.0.5) actionview (= 5.1.4)
activejob (= 5.0.5) activejob (= 5.1.4)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
actionpack (5.0.5) actionpack (5.1.4)
actionview (= 5.0.5) actionview (= 5.1.4)
activesupport (= 5.0.5) activesupport (= 5.1.4)
rack (~> 2.0) rack (~> 2.0)
rack-test (~> 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (5.0.5) actionview (5.1.4)
activesupport (= 5.0.5) activesupport (= 5.1.4)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubi (~> 1.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3) rails-html-sanitizer (~> 1.0, >= 1.0.3)
activejob (5.0.5) activejob (5.1.4)
activesupport (= 5.0.5) activesupport (= 5.1.4)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (5.0.5) activemodel (5.1.4)
activesupport (= 5.0.5) activesupport (= 5.1.4)
activerecord (5.0.5) activerecord (5.1.4)
activemodel (= 5.0.5) activemodel (= 5.1.4)
activesupport (= 5.0.5) activesupport (= 5.1.4)
arel (~> 7.0) arel (~> 8.0)
activerecord-nulldb-adapter (0.3.7) activerecord-nulldb-adapter (0.3.7)
activerecord (>= 2.0.0) activerecord (>= 2.0.0)
activerecord-session_store (1.1.0) activerecord-session_store (1.1.0)
@ -57,14 +65,14 @@ GEM
multi_json (~> 1.11, >= 1.11.2) multi_json (~> 1.11, >= 1.11.2)
rack (>= 1.5.2, < 3) rack (>= 1.5.2, < 3)
railties (>= 4.0, < 5.2) railties (>= 4.0, < 5.2)
activesupport (5.0.5) activesupport (5.1.4)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7) i18n (~> 0.7)
minitest (~> 5.1) minitest (~> 5.1)
tzinfo (~> 1.1) tzinfo (~> 1.1)
addressable (2.5.2) addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0) public_suffix (>= 2.0.2, < 4.0)
arel (7.1.4) arel (8.0.0)
argon2 (1.1.3) argon2 (1.1.3)
ffi (~> 1.9) ffi (~> 1.9)
ffi-compiler (~> 0.1) ffi-compiler (~> 0.1)
@ -94,8 +102,6 @@ GEM
coffee-script coffee-script
execjs execjs
json json
composite_primary_keys (9.0.7)
activerecord (~> 5.0.0)
concurrent-ruby (1.0.5) concurrent-ruby (1.0.5)
coveralls (0.8.21) coveralls (0.8.21)
json (>= 1.8, < 3) json (>= 1.8, < 3)
@ -127,7 +133,7 @@ GEM
eventmachine (>= 0.12.9) eventmachine (>= 0.12.9)
http_parser.rb (~> 0.6.0) http_parser.rb (~> 0.6.0)
equalizer (0.0.11) equalizer (0.0.11)
erubis (2.7.0) erubi (1.6.1)
eventmachine (1.2.5) eventmachine (1.2.5)
execjs (2.7.0) execjs (2.7.0)
factory_girl (4.8.0) factory_girl (4.8.0)
@ -219,7 +225,7 @@ GEM
thread_safe (~> 0.3, >= 0.3.1) thread_safe (~> 0.3, >= 0.3.1)
method_source (0.8.2) method_source (0.8.2)
mime-types (2.99.3) mime-types (2.99.3)
mini_portile2 (2.2.0) mini_portile2 (2.3.0)
minitest (5.10.3) minitest (5.10.3)
multi_json (1.12.1) multi_json (1.12.1)
multi_xml (0.6.0) multi_xml (0.6.0)
@ -231,8 +237,8 @@ GEM
net-ldap (0.16.0) net-ldap (0.16.0)
netrc (0.11.0) netrc (0.11.0)
nio4r (2.1.0) nio4r (2.1.0)
nokogiri (1.8.0) nokogiri (1.8.1)
mini_portile2 (~> 2.2.0) mini_portile2 (~> 2.3.0)
nori (2.6.0) nori (2.6.0)
notiffany (0.1.1) notiffany (0.1.1)
nenv (~> 0.1) nenv (~> 0.1)
@ -279,7 +285,7 @@ GEM
rack rack
parser (2.4.0.0) parser (2.4.0.0)
ast (~> 2.2) ast (~> 2.2)
pg (0.20.0) pg (0.21.0)
pluginator (1.5.0) pluginator (1.5.0)
power_assert (1.1.0) power_assert (1.1.0)
powerpack (0.1.1) powerpack (0.1.1)
@ -294,19 +300,19 @@ GEM
rack (2.0.3) rack (2.0.3)
rack-livereload (0.3.16) rack-livereload (0.3.16)
rack rack
rack-test (0.6.3) rack-test (0.7.0)
rack (>= 1.0) rack (>= 1.0, < 3)
rails (5.0.5) rails (5.1.4)
actioncable (= 5.0.5) actioncable (= 5.1.4)
actionmailer (= 5.0.5) actionmailer (= 5.1.4)
actionpack (= 5.0.5) actionpack (= 5.1.4)
actionview (= 5.0.5) actionview (= 5.1.4)
activejob (= 5.0.5) activejob (= 5.1.4)
activemodel (= 5.0.5) activemodel (= 5.1.4)
activerecord (= 5.0.5) activerecord (= 5.1.4)
activesupport (= 5.0.5) activesupport (= 5.1.4)
bundler (>= 1.3.0) bundler (>= 1.3.0)
railties (= 5.0.5) railties (= 5.1.4)
sprockets-rails (>= 2.0.0) sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3) rails-dom-testing (2.0.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
@ -315,16 +321,16 @@ GEM
loofah (~> 2.0) loofah (~> 2.0)
rails-observers (0.1.5) rails-observers (0.1.5)
activemodel (>= 4.0) activemodel (>= 4.0)
railties (5.0.5) railties (5.1.4)
actionpack (= 5.0.5) actionpack (= 5.1.4)
activesupport (= 5.0.5) activesupport (= 5.1.4)
method_source method_source
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (2.2.2) rainbow (2.2.2)
rake rake
raindrops (0.19.0) raindrops (0.19.0)
rake (12.0.0) rake (12.1.0)
rb-fsevent (0.10.2) rb-fsevent (0.10.2)
rb-inotify (0.9.10) rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2) ffi (>= 0.5.0, < 2)
@ -476,7 +482,7 @@ DEPENDENCIES
coffee-rails coffee-rails
coffee-script-source coffee-script-source
coffeelint coffeelint
composite_primary_keys composite_primary_keys!
coveralls coveralls
daemons daemons
delayed_job_active_record delayed_job_active_record
@ -516,7 +522,7 @@ DEPENDENCIES
pre-commit pre-commit
puma puma
rack-livereload rack-livereload
rails (= 5.0.5) rails (= 5.1.4)
rails-observers rails-observers
rb-fsevent rb-fsevent
rspec-rails rspec-rails

View file

@ -1162,7 +1162,7 @@ class App.ObserverController extends App.Controller
@log 'debug', 'new', @object_id, @model @log 'debug', 'new', @object_id, @model
if App[@model].exists(@object_id) if App[@model].exists(@object_id)
@maybeRender( App[@model].fullLocal(@object_id) ) @maybeRender(App[@model].fullLocal(@object_id))
else else
App[@model].full(@object_id, @maybeRender) App[@model].full(@object_id, @maybeRender)
@ -1170,7 +1170,8 @@ class App.ObserverController extends App.Controller
if @globalRerender if @globalRerender
@bind('ui:rerender', => @bind('ui:rerender', =>
@lastAttributres = undefined @lastAttributres = undefined
@maybeRender( App[@model].fullLocal(@object_id) ) console.log('aaaa', @model, @template)
@maybeRender(App[@model].fullLocal(@object_id))
) )
subscribe: (object, typeOfChange) => subscribe: (object, typeOfChange) =>

View file

@ -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 class App.ControllerTable extends App.Controller
minColWidth: 40 minColWidth: 40
baseColWidth: 130 baseColWidth: 130
@ -10,9 +101,53 @@ class App.ControllerTable extends App.Controller
elements: elements:
'.js-tableHead': 'tableHead' '.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 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 # apply personal preferences
data = {} data = {}
if @tableId if @tableId
@ -21,20 +156,218 @@ class App.ControllerTable extends App.Controller
for key, value of data.order for key, value of data.order
@[key] = value @[key] = value
@headerWidth = {}
if data.headerWidth if data.headerWidth
for key, value of data.headerWidth for key, value of data.headerWidth
@headerWidth[key] = value @headerWidth[key] = value
@availableWidth = @el.width() @availableWidth = @el.width()
@render()
$(window).on 'resize.table', @onResize @renderQueue()
release: => release: =>
$(window).off 'resize.table', @onResize $(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: => 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 if @dndCallback
dndOptions = dndOptions =
@ -50,121 +383,79 @@ class App.ControllerTable extends App.Controller
# Set helper cell sizes to match the original sizes # Set helper cell sizes to match the original sizes
$(@).width( originals.eq(index).outerWidth() ) $(@).width( originals.eq(index).outerWidth() )
return helper return helper
update: @dndCallback update: @dndCallback
@el.find('table > tbody').sortable(dndOptions) 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) -> renderTableRows: (sort = false) =>
e.preventDefault() if sort is true
console.log('rowClick', id) @sortList()
rowMouseover = (id, e) -> position = 0
e.preventDefault() columnsLength = @headers.length
console.log('rowMouseover', id) if @checkbox || @radio
rowMouseout = (id, e) -> columnsLength++
e.preventDefault() groupLast = ''
console.log('rowMouseout', id) tableBody = []
rowDblClick = (id, e) -> for object in @objects
e.preventDefault() position++
console.log('rowDblClick', id) 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) -> renderTableGroupByRow: (object, position, groupByName) =>
e.preventDefault() App.view('generic/table_row_group_by')(
console.log('colClick', e.target) position: position
groupByName: groupByName
checkboxClick = (id, e) -> columnsLength: @columnsLength
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( renderTableRow: (object, position) =>
el: element App.view('generic/table_row')(
overview: ['time', 'area', 'level', 'browser', 'location', 'data'] headers: @headers
attribute_list: [ attributes: @attributesList
{ name: 'time', display: 'Time', tag: 'datetime' }, checkbox: @checkbox
{ name: 'area', display: 'Area', type: 'text' }, radio: @radio
{ name: 'level', display: 'Level', type: 'text' }, callbacks: @callbackAttributes
{ name: 'browser', display: 'Browser', type: 'text' }, sortable: @dndCallback
{ name: 'location', display: 'Location', type: 'text' }, position: position
{ name: 'data', display: 'Data', type: 'text' }, object: object
]
objects: data
) )
### tableHeadersHasChanged: =>
return true if @overviewAttributes isnt @lastOverview
false
tableGen: => tableHeaders: =>
if !@model orderBy = @customOrderBy || @orderBy
@model = {} orderDirection = @customOrderDirection || @orderDirection
overview = @overview || @model.configure_overview || []
attributes = @attribute_list || @model.configure_attributes || {}
attributes = App.Model.attributesGet(false, attributes)
destroy = @model.configure_delete
# check if table is empty #console.log('LLL', @lastOrderBy, @orderBy, @lastOrderDirection, @orderDirection, @overviewAttributes, @lastOverview)
if _.isEmpty(@objects) if @headers && @lastOrderBy is orderBy && @lastOrderDirection is orderDirection && !@tableHeadersHasChanged()
table = App.view('generic/admin/empty')( console.log('tableHeaders: same overviewAttributes just return headers', @headers)
explanation: @explanation return ['headers are the same', @headers]
) @lastOverview = @overviewAttributes
return $(table)
# get header data # get header data
@headers = [] @headers = []
for item in overview for item in @overviewAttributes
headerFound = false headerFound = false
for attributeName, attribute of attributes for attributeName, attribute of @attributesList
# remove group by attribute from header # remove group by attribute from header
if !@groupBy || @groupBy isnt item if !@groupBy || @groupBy isnt item
@ -208,8 +499,19 @@ class App.ControllerTable extends App.Controller
attribute.displayWidth = value attribute.displayWidth = value
@headers.push attribute @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 # add destroy header and col binding
if destroy if @destroy
@headers.push @headers.push
name: 'destroy' name: 'destroy'
display: 'Delete' display: 'Delete'
@ -219,14 +521,63 @@ class App.ControllerTable extends App.Controller
parentClass: 'js-delete' parentClass: 'js-delete'
icon: 'trash' icon: 'trash'
if !@bindCol
@bindCol = {}
@bindCol['destroy'] = @bindCol['destroy'] =
events: events:
click: @deleteRow click: @deleteRow
if @orderDirection && @orderBy && !@groupBy @columnsLength = @headers.length
@objects = @sortList(@objects) 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 # group by
if @groupBy if @groupBy
@ -237,14 +588,19 @@ class App.ControllerTable extends App.Controller
group = object[@groupBy] group = object[@groupBy]
if !group if !group
withId = "#{@groupBy}_id" withId = "#{@groupBy}_id"
if object[withId] && @attributesList[withId] && @attributesList[withId].relation
if object[withId] && attributes[withId] && attributes[withId].relation if App[@attributesList[withId].relation].exists(object[withId])
if App[attributes[withId].relation].exists(object[withId]) item = App[@attributesList[withId].relation].findNative(object[withId])
item = App[attributes[withId].relation].findNative(object[withId])
if item && item.displayName if item && item.displayName
group = item.displayName().toLowerCase() group = item.displayName().toLowerCase()
else if item.name
group = item.name.toLowerCase()
if _.isEmpty(group) if _.isEmpty(group)
group = '' group = ''
if group.displayName
group = group.displayName().toLowerCase()
else if group.name
group = group.name.toLowerCase()
groupObjects[group] ||= [] groupObjects[group] ||= []
groupObjects[group].push object groupObjects[group].push object
@ -254,198 +610,15 @@ class App.ControllerTable extends App.Controller
groupsSorted = groupsSorted.sort() groupsSorted = groupsSorted.sort()
# get new order # get new order
@objects = [] localObjects = []
for group in groupsSorted for group in groupsSorted
localObjects = @sortList(groupObjects[group]) localObjects = localObjects.concat groupObjects[group]
@objects = @objects.concat localObjects
groupObjects[group] = [] # release old array groupObjects[group] = [] # release old array
# execute header callback @objects = localObjects
if @callbackHeader @lastSortedobjects = localObjects
for callback in @callbackHeader
@headers = callback(@headers)
if @tableId localObjects
@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
# bind on delete dialog # bind on delete dialog
deleteRow: (id, e) => deleteRow: (id, e) =>
@ -559,30 +732,43 @@ class App.ControllerTable extends App.Controller
# update store and runtime @headerWidth # update store and runtime @headerWidth
@preferencesStore('headerWidth', leftColumnKey, leftWidth) @preferencesStore('headerWidth', leftColumnKey, leftWidth)
@headerWidth[leftColumnKey] = leftWidth
_.find(@headers, (column) -> column.name is leftColumnKey).displayWidth = leftWidth _.find(@headers, (column) -> column.name is leftColumnKey).displayWidth = leftWidth
# update store and runtime @headerWidth # update store and runtime @headerWidth
if rightColumnKey if rightColumnKey
@preferencesStore('headerWidth', rightColumnKey, rightWidth) @preferencesStore('headerWidth', rightColumnKey, rightWidth)
@headerWidth[rightColumnKey] = rightWidth
_.find(@headers, (column) -> column.name is rightColumnKey).displayWidth = rightWidth _.find(@headers, (column) -> column.name is rightColumnKey).displayWidth = rightWidth
sortByColumn: (event) => sortByColumn: (event) =>
column = $(event.currentTarget).closest('[data-column-key]').attr('data-column-key') column = $(event.currentTarget).closest('[data-column-key]').attr('data-column-key')
orderBy = @customOrderBy || @orderBy
orderDirection = @customOrderDirection || @orderDirection
# sort, update runtime @orderBy and @orderDirection # sort, update runtime @orderBy and @orderDirection
if @orderBy isnt column if orderBy isnt column
@orderBy = column orderBy = column
@orderDirection = 'ASC' orderDirection = 'ASC'
else else
if @orderDirection is 'ASC' if orderDirection is 'ASC'
@orderDirection = 'DESC' orderDirection = 'DESC'
else else
@orderDirection = 'ASC' orderDirection = 'ASC'
@orderBy = orderBy
@orderDirection = orderDirection
@customOrderBy = orderBy
@customOrderDirection = orderDirection
# update store # update store
@preferencesStore('order', 'orderBy', @orderBy) @preferencesStore('order', 'customOrderBy', @orderBy)
@preferencesStore('order', 'orderDirection', @orderDirection) @preferencesStore('order', 'customOrderDirection', @orderDirection)
@render() render = =>
@renderTableFull()
App.QueueManager.add('tableRender', render)
App.QueueManager.run('tableRender')
preferencesStore: (type, key, value) -> preferencesStore: (type, key, value) ->
data = @preferencesGet() data = @preferencesGet()
@ -601,3 +787,25 @@ class App.ControllerTable extends App.Controller
preferencesStoreKey: => preferencesStoreKey: =>
"tablePrefs:#{@tableId}" "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

View file

@ -540,20 +540,23 @@ class App.TicketOverview extends App.Controller
render: -> render: ->
elLocal = $(App.view('ticket_overview/index')()) elLocal = $(App.view('ticket_overview/index')())
@navBarControllerVertical = new Navbar @navBarControllerVertical = new Navbar(
el: elLocal.find('.overview-header') el: elLocal.find('.overview-header')
view: @view view: @view
vertical: true vertical: true
)
@navBarController = new Navbar @navBarController = new Navbar(
el: elLocal.filter('.sidebar') el: elLocal.filter('.sidebar')
view: @view view: @view
)
@contentController = new Table @contentController = new Table(
el: elLocal.find('.overview-table') el: elLocal.find('.overview-table')
view: @view view: @view
keyboardOn: @keyboardOn keyboardOn: @keyboardOn
keyboardOff: @keyboardOff keyboardOff: @keyboardOff
)
@renderBatchOverlay(elLocal.filter('.js-batch-overlay')) @renderBatchOverlay(elLocal.filter('.js-batch-overlay'))
@ -662,10 +665,12 @@ class App.TicketOverview extends App.Controller
@viewLast = @view @viewLast = @view
# build content # build content
if @contentController @contentController = new Table(
@contentController.update( el: @$('.overview-table')
view: @view view: @view
) keyboardOn: @keyboardOn
keyboardOff: @keyboardOff
)
hide: => hide: =>
@keyboardOff() @keyboardOff()
@ -908,7 +913,7 @@ class Table extends App.Controller
super super
if @view if @view
@bindId = App.OverviewListCollection.bind(@view, @render) @bindId = App.OverviewListCollection.bind(@view, @updateTable)
# rerender view, e. g. on langauge change # rerender view, e. g. on langauge change
@bind 'ui:rerender', => @bind 'ui:rerender', =>
@ -924,18 +929,17 @@ class Table extends App.Controller
for key, value of params for key, value of params
@[key] = value @[key] = value
@view_mode = App.LocalStorage.get("mode:#{@view}", @Session.get('id')) || 's'
@log 'notice', 'view:', @view, @view_mode
return if !@view return if !@view
if @view if @view
if @bindId if @bindId
App.OverviewListCollection.unbind(@bindId) App.OverviewListCollection.unbind(@bindId)
@bindId = App.OverviewListCollection.bind(@view, @render) @bindId = App.OverviewListCollection.bind(@view, @updateTable)
render: (data) => updateTable: (data) =>
return if !data if !@table
@render(data)
return
# use cache # use cache
overview = data.overview overview = data.overview
@ -943,6 +947,33 @@ class Table extends App.Controller
return if !overview && !tickets 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 # get ticket list
ticketListShow = [] ticketListShow = []
for ticket in tickets for ticket in tickets
@ -953,8 +984,6 @@ class Table extends App.Controller
@html App.view('customer_not_ticket_exists')() @html App.view('customer_not_ticket_exists')()
return return
@selected = @getSelected()
# set page title # set page title
@overview = App.Overview.find(overview.id) @overview = App.Overview.find(overview.id)
@ -1086,7 +1115,7 @@ class Table extends App.Controller
attribute.title = object.iconTitle() attribute.title = object.iconTitle()
value value
new App.ControllerTable( @table = new App.ControllerTable(
tableId: "ticket_overview_#{@overview.id}" tableId: "ticket_overview_#{@overview.id}"
overview: @overview.view.s overview: @overview.view.s
el: @$('.table-overview') el: @$('.table-overview')
@ -1123,8 +1152,6 @@ class Table extends App.Controller
'click': callbackCheckbox 'click': callbackCheckbox
) )
@setSelected(@selected)
# start user popups # start user popups
@userPopups() @userPopups()
@ -1166,22 +1193,6 @@ class Table extends App.Controller
bulkAll.prop('indeterminate', true) 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) => viewmode: (e) =>
e.preventDefault() e.preventDefault()
@view_mode = $(e.target).data('mode') @view_mode = $(e.target).data('mode')
@ -1497,6 +1508,7 @@ class App.OverviewSettings extends App.ControllerModal
App.OverviewListCollection.fetch(@overview.link) App.OverviewListCollection.fetch(@overview.link)
else else
App.OverviewIndexCollection.trigger() App.OverviewIndexCollection.trigger()
console.log('TRIGGER', @overview.link)
App.OverviewListCollection.trigger(@overview.link) App.OverviewListCollection.trigger(@overview.link)
# close modal # close modal

View file

@ -23,6 +23,7 @@ class Widget extends App.Controller
verify: (userId) -> verify: (userId) ->
return if !userId return if !userId
return if !App.User.exists(userId)
user = App.User.find(userId) user = App.User.find(userId)
return if user.source isnt 'signup' return if user.source isnt 'signup'
return if user.verified is true return if user.verified is true

View file

@ -5,12 +5,12 @@ class App.Session
_instance ?= new _sessionSingleton _instance ?= new _sessionSingleton
_instance.clear() _instance.clear()
@get: ( key ) -> @get: (key) ->
if _instance == undefined if _instance == undefined
_instance ?= new _sessionSingleton _instance ?= new _sessionSingleton
_instance.get(key) _instance.get(key)
@set: ( user ) -> @set: (user) ->
if _instance == undefined if _instance == undefined
_instance ?= new _sessionSingleton _instance ?= new _sessionSingleton
_instance.set(user) _instance.set(user)
@ -24,11 +24,11 @@ class _sessionSingleton extends Spine.Module
clear: -> clear: ->
@user = undefined @user = undefined
get: ( key ) -> get: (key) ->
return if !@user return if !@user
if key if key
return @user[key] return @user[key]
@user @user
set: ( user ) -> set: (user) ->
@user = user @user = user

View file

@ -6,6 +6,7 @@ class App._CollectionSingletonBase
@callbacks = {} @callbacks = {}
@counter = 0 @counter = 0
@key = "collection-#{@event}" @key = "collection-#{@event}"
# read from cache # read from cache
cache = App.SessionStorage.get(@key) cache = App.SessionStorage.get(@key)
if cache if cache
@ -16,6 +17,9 @@ class App._CollectionSingletonBase
@set(data) @set(data)
@callback(data) @callback(data)
App.Event.bind 'auth:logout', (data) =>
@clear(data)
get: => get: =>
@collectionData @collectionData
@ -79,3 +83,6 @@ class App._CollectionSingletonBase
delete @callbacks[counter] delete @callbacks[counter]
App.QueueManager.add(@key, callback) App.QueueManager.add(@key, callback)
App.QueueManager.run(@key) App.QueueManager.run(@key)
clear: =>
@collectionData = undefined

View file

@ -76,11 +76,7 @@ class App.Auth
App.Session.init() App.Session.init()
# update model definition (needed for not authenticated areas like wizard) # update model definition (needed for not authenticated areas like wizard)
if data.models @_updateModelAttributes(data.models)
for model, attributes of data.models
for attribute in attributes
App[model].attributes.push attribute.name
App[model].configure_attributes.push attribute
# set locale # set locale
locale = window.navigator.userLanguage || window.navigator.language || 'en-us' locale = window.navigator.userLanguage || window.navigator.language || 'en-us'
@ -98,11 +94,7 @@ class App.Auth
App.Event.trigger('clearStore') App.Event.trigger('clearStore')
# update model definition # update model definition
if data.models @_updateModelAttributes(data.models)
for model, attributes of data.models
for attribute in attributes
App[model].attributes.push attribute.name
App[model].configure_attributes.push attribute
# update config # update config
for key, value of data.config for key, value of data.config
@ -135,6 +127,14 @@ class App.Auth
App.Event.trigger('ui:rerender') App.Event.trigger('ui:rerender')
App.TaskManager.tasksInitial() 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) -> @_logout: (rerender = true) ->
App.Log.debug 'Auth', '_logout' App.Log.debug 'Auth', '_logout'
@ -149,6 +149,15 @@ class App.Auth
App.Event.trigger('ui:rerender') App.Event.trigger('ui:rerender')
App.Event.trigger('clearStore') 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: -> @_loginError: ->
App.Log.debug 'Auth', '_loginError:error' App.Log.debug 'Auth', '_loginError:error'

View file

@ -14,6 +14,9 @@ class _Singleton
@overview[data.overview.view] = data @overview[data.overview.view] = data
@callback(data.overview.view, data) @callback(data.overview.view, data)
App.Event.bind 'auth:logout', (data) =>
@clear(data)
get: (view) -> get: (view) ->
@overview[view] @overview[view]
@ -76,6 +79,12 @@ class _Singleton
App.QueueManager.add('ticket_overviews', callback) App.QueueManager.add('ticket_overviews', callback)
App.QueueManager.run('ticket_overviews') App.QueueManager.run('ticket_overviews')
clear: =>
@overview = {}
@callbacks = {}
@fetchActive = {}
@counter = 0
class App.OverviewListCollection class App.OverviewListCollection
_instance = new _Singleton _instance = new _Singleton

View file

@ -812,3 +812,29 @@ set new attributes of model (remove already available attributes)
item: item item: item
processData: true 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 = {}

View file

@ -25,7 +25,7 @@ class App.User extends App.Model
] ]
uiUrl: -> uiUrl: ->
'#user/profile/' + @id "#user/profile/#{@id}"
icon: -> icon: ->
'user' 'user'

View file

@ -20,9 +20,7 @@
<% for header, i in @headers: %> <% for header, i in @headers: %>
<th class="js-tableHead<%= " #{ header.className }" if header.className %><%= " align-#{ header.align }" if header.align %>" style="<% if header.displayWidth: %>width:<%= header.displayWidth %>px<% end %>" data-column-key="<%= header.name %>"> <th class="js-tableHead<%= " #{ header.className }" if header.className %><%= " align-#{ header.align }" if header.align %>" style="<% if header.displayWidth: %>width:<%= header.displayWidth %>px<% end %>" data-column-key="<%= header.name %>">
<div class="table-column-head<%= ' js-sort' if @tableId %>"> <div class="table-column-head<%= ' js-sort' if @tableId %>">
<div class="table-column-title"> <div class="table-column-title"><%- @T(header.display) %></div>
<%- @T(header.display) %>
</div>
<div class="table-column-sortIcon"> <div class="table-column-sortIcon">
<% if header.sortOrderIcon: %> <% if header.sortOrderIcon: %>
<%- @Icon(header.sortOrderIcon[0], header.sortOrderIcon[1]) %> <%- @Icon(header.sortOrderIcon[0], header.sortOrderIcon[1]) %>
@ -36,5 +34,5 @@
<% end %> <% end %>
</tr> </tr>
</thead> </thead>
<tbody><%- @tableBody %></tbody> <tbody class="js-tableBody"><%- @tableBody %></tbody>
</table> </table>

View file

@ -1,4 +1,4 @@
<tr class="item<%= ' is-inactive' if @object.active is false %>" data-id="<%= @object.id %>" data-position="<%= @position %>"> <tr class="item<%= ' is-inactive' if @object.active is false %>" data-id="<%= @object.id %>">
<% if @sortable: %> <% if @sortable: %>
<td class="table-draggable"><%- @Icon('draggable') %></td> <td class="table-draggable"><%- @Icon('draggable') %></td>
<% end %> <% end %>

View file

@ -11,7 +11,7 @@ class Integration::ExchangeController < ApplicationController
email: params[:user], email: params[:user],
password: params[:password], password: params[:password],
) )
client.http.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
{ {
endpoint: client.try(:autodiscover).try(:ews_url), endpoint: client.try(:autodiscover).try(:ews_url),
} }

View file

@ -1,8 +1,9 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class Integration::IdoitController < ApplicationController 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: ['admin.integration.idoit']) }, only: [:verify]
prepend_before_action -> { authentication_check(permission: ['ticket.agent']) }, only: [:query, :update]
def verify def verify
response = ::Idoit.verify(params[:api_token], params[:endpoint], params[:client_id]) response = ::Idoit.verify(params[:api_token], params[:endpoint], params[:client_id])

View file

@ -1,7 +1,7 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class LongPollingController < ApplicationController class LongPollingController < ApplicationController
skip_action_callback :session_update # prevent race conditions skip_before_action :session_update # prevent race conditions
# GET /api/v1/message_send # GET /api/v1/message_send
def message_send def message_send

View file

@ -55,7 +55,7 @@ returns
} }
ignored_attributes = self.class.instance_variable_get(:@search_index_attributes_ignored) || [] 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| ignored_attributes.each { |attribute|
attributes.delete(attribute.to_s) attributes.delete(attribute.to_s)

View file

@ -41,14 +41,14 @@ module ApplicationModel::HasCache
} }
# delete old name / login caches # delete old name / login caches
if changed? if saved_changes?
if changes.key?('name') if saved_changes.key?('name')
name = changes['name'][0] name = saved_changes['name'][0]
key = "#{self.class}::#{name}" key = "#{self.class}::#{name}"
Cache.delete(key) Cache.delete(key)
end end
if changes.key?('login') if saved_changes.key?('login')
name = changes['login'][0] name = saved_changes['login'][0]
key = "#{self.class}::#{name}" key = "#{self.class}::#{name}"
Cache.delete(key) Cache.delete(key)
end end

View file

@ -475,7 +475,7 @@ returns
# check ignore header # check ignore header
if mail['x-zammad-ignore'.to_sym] == 'true' || mail['x-zammad-ignore'.to_sym] == true 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" Rails.logger.info "ignored email with msgid '#{mail[:message_id]}' from '#{mail[:from]}' because of x-zammad-ignore header"
return true return
end end
# set interface handle # set interface handle
@ -514,7 +514,7 @@ returns
set_attributes_by_x_headers(ticket, 'ticket', mail, 'followup') set_attributes_by_x_headers(ticket, 'ticket', mail, 'followup')
# save changes set by x-zammad-ticket-followup-* headers # 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 = Ticket::State.find(ticket.state_id)
state_type = Ticket::StateType.find(state.state_type_id) state_type = Ticket::StateType.find(state.state_type_id)
@ -650,7 +650,7 @@ returns
def self.sender_properties(from) def self.sender_properties(from)
data = {} data = {}
return data if from.blank?
begin begin
list = Mail::AddressList.new(from) list = Mail::AddressList.new(from)
list.addresses.each { |address| list.addresses.each { |address|

View file

@ -18,7 +18,8 @@ class Channel::Filter::MonitoringBase
sender = Setting.get("#{integration}_sender") sender = Setting.get("#{integration}_sender")
auto_close = Setting.get("#{integration}_auto_close") auto_close = Setting.get("#{integration}_auto_close")
auto_close_state_id = Setting.get("#{integration}_auto_close_state_id") 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[:from].blank?
return if mail[:body].blank? return if mail[:body].blank?
@ -26,7 +27,7 @@ class Channel::Filter::MonitoringBase
return if !session_user_id return if !session_user_id
# check if sender is monitoring # 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 # get mail attibutes like host and state
result = {} result = {}
@ -91,5 +92,18 @@ class Channel::Filter::MonitoringBase
mail[ 'x-zammad-ticket-preferences'.to_sym ][key] = value mail[ 'x-zammad-ticket-preferences'.to_sym ][key] = value
} }
end 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
end end

View file

@ -32,13 +32,13 @@ log object update activity stream, if configured - will be executed automaticall
=end =end
def activity_stream_update 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 = self.class.instance_variable_get(:@activity_stream_attributes_ignored) || []
ignored_attributes += %i(created_at updated_at created_by_id updated_by_id) ignored_attributes += %i(created_at updated_at created_by_id updated_by_id)
log = false log = false
changes.each { |key, _value| saved_changes.each { |key, _value|
next if ignored_attributes.include?(key.to_sym) next if ignored_attributes.include?(key.to_sym)
log = true log = true

View file

@ -33,13 +33,13 @@ log object update history with all updated attributes, if configured - will be e
=end =end
def history_update def history_update
return if !changed? return if !saved_changes?
# return if it's no update # return if it's no update
return if new_record? return if new_record?
# new record also triggers update, so ignore new records # new record also triggers update, so ignore new records
changes = self.changes changes = saved_changes
if history_changes_last_done if history_changes_last_done
history_changes_last_done.each { |key, value| history_changes_last_done.each { |key, value|
if changes.key?(key) && changes[key] == value if changes.key?(key) && changes[key] == value

View file

@ -99,6 +99,8 @@ all:
}, },
{ {
json: true, json: true,
open_timeout: 8,
read_timeout: 24,
} }
) )

View file

@ -27,7 +27,7 @@ class Observer::Sla::TicketRebuildEscalation < ActiveRecord::Observer
def _check(record) def _check(record)
# return if we run import mode # 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 # check if condition has changed
changed = false changed = false
@ -38,11 +38,11 @@ class Observer::Sla::TicketRebuildEscalation < ActiveRecord::Observer
%w(timezone business_hours default ical_url public_holidays) %w(timezone business_hours default ical_url public_holidays)
end end
fields_to_check.each { |item| fields_to_check.each { |item|
next if !record.changes[item] next if !record.saved_change_to_attribute(item)
next if record.changes[item][0] == record.changes[item][1] next if record.saved_change_to_attribute(item)[0] == record.saved_change_to_attribute(item)[1]
changed = true changed = true
} }
return if !changed return true if !changed
_rebuild(record) _rebuild(record)
end end

View file

@ -20,7 +20,7 @@ class Observer::Ticket::LastOwnerUpdate < ActiveRecord::Observer
# check if owner has changed # check if owner has changed
if type == 'update' if type == 'update'
return true if record.changes['owner_id'].blank? return true if record.changes_to_save['owner_id'].blank?
end end
# check if owner is nobody # check if owner is nobody

View file

@ -19,8 +19,8 @@ class Observer::Ticket::OnlineNotificationSeen < ActiveRecord::Observer
return false if Setting.get('import_mode') return false if Setting.get('import_mode')
# set seen only if state has changes # set seen only if state has changes
return false if record.changes.blank? return false if !record.saved_changes?
return false if record.changes['state_id'].blank? return false if record.saved_changes['state_id'].blank?
# check if existing online notifications for this ticket should be set to seen # check if existing online notifications for this ticket should be set to seen
return true if !record.online_notification_seen_state return true if !record.online_notification_seen_state

View file

@ -18,10 +18,10 @@ class Observer::Ticket::RefObjectTouch < ActiveRecord::Observer
def ref_object_touch(record) def ref_object_touch(record)
# return if we run import mode # return if we run import mode
return if Setting.get('import_mode') return true if Setting.get('import_mode')
# touch old customer if changed # 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 && cutomer_id_changed[0] != cutomer_id_changed[1]
if cutomer_id_changed[0] if cutomer_id_changed[0]
User.find(cutomer_id_changed[0]).touch User.find(cutomer_id_changed[0]).touch
@ -34,7 +34,7 @@ class Observer::Ticket::RefObjectTouch < ActiveRecord::Observer
end end
# touch old organization if changed # 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 && organization_id_changed[0] != organization_id_changed[1]
if organization_id_changed[0] if organization_id_changed[0]
Organization.find(organization_id_changed[0]).touch Organization.find(organization_id_changed[0]).touch
@ -42,7 +42,7 @@ class Observer::Ticket::RefObjectTouch < ActiveRecord::Observer
end end
# touch new/current organization # touch new/current organization
return if !record.organization return true if !record.organization
record.organization.touch record.organization.touch
end end

View file

@ -19,6 +19,6 @@ class Observer::Ticket::StatsReopen < ActiveRecord::Observer
# return if we run import mode # return if we run import mode
return if Setting.get('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
end end

View file

@ -201,7 +201,7 @@ class Observer::Transaction < ActiveRecord::Observer
# ignore certain attributes # ignore certain attributes
real_changes = {} real_changes = {}
record.changes.each { |key, value| record.changes_to_save.each { |key, value|
next if key == 'updated_at' next if key == 'updated_at'
next if key == 'first_response_at' next if key == 'first_response_at'
next if key == 'close_at' next if key == 'close_at'

View file

@ -22,7 +22,7 @@ class Observer::User::RefObjectTouch < ActiveRecord::Observer
# touch old organization if changed # touch old organization if changed
member_ids = [] 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 && organization_id_changed[0] != organization_id_changed[1]
if organization_id_changed[0] if organization_id_changed[0]

View file

@ -15,7 +15,7 @@ class Observer::User::TicketOrganization < ActiveRecord::Observer
def check_organization(record) def check_organization(record)
# check if organization has changed # 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 # update last 100 tickets of user
tickets = Ticket.where(customer_id: record.id).limit(100) tickets = Ticket.where(customer_id: record.id).limit(100)

View file

@ -12,10 +12,8 @@ class Scheduler < ApplicationModel
Thread.abort_on_exception = true Thread.abort_on_exception = true
# reconnect in case db connection is lost # reconnect in case db connection is lost
# See issue #1080
begin begin
ActiveRecord::Base.connection.reconnect! ActiveRecord::Base.connection.reconnect!
rescue PG::UnableToSend => e # rubocop:disable Lint/HandleExceptions
rescue => e rescue => e
logger.error "Can't reconnect to database #{e.inspect}" logger.error "Can't reconnect to database #{e.inspect}"
end end

View file

@ -104,7 +104,7 @@ class Taskbar < ApplicationModel
end end
def notify_clients def notify_clients
return true if !changes['preferences'] return true if !saved_change_to_attribute?('preferences')
data = { data = {
event: 'taskbar:preferences', event: 'taskbar:preferences',
data: { data: {

View file

@ -1160,7 +1160,7 @@ result
def reset_pending_time def reset_pending_time
# ignore if no state has changed # 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 # ignore if new state is blank and
# let handle ActiveRecord the error # let handle ActiveRecord the error

View file

@ -76,10 +76,10 @@ returns
# if no escalation is enabled # if no escalation is enabled
if !sla || !calendar if !sla || !calendar
preferences[:escalation_calculation] = {}
# nothing to change # nothing to change
return false if !escalation_at && !first_response_escalation_at && !update_escalation_at && !close_escalation_at return false if !escalation_at && !first_response_escalation_at && !update_escalation_at && !close_escalation_at
preferences['escalation_calculation'] = {}
self.escalation_at = nil self.escalation_at = nil
self.first_response_escalation_at = nil self.first_response_escalation_at = nil
self.escalation_at = nil self.escalation_at = nil
@ -122,7 +122,7 @@ returns
first_response_at_changed = false first_response_at_changed = false
end end
last_update_at_changed = true 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 last_update_at_changed = false
end end
close_at_changed = true close_at_changed = true
@ -352,7 +352,7 @@ returns
).map(&:name) ).map(&:name)
# add state changes till now # 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 last_history_state = nil
history_list.each { |history_item| history_list.each { |history_item|
next if !history_item['attribute'] next if !history_item['attribute']
@ -361,14 +361,14 @@ returns
last_history_state = history_item last_history_state = history_item
} }
local_updated_at = updated_at local_updated_at = updated_at
if changes['updated_at'] && changes['updated_at'][1] if saved_change_to_attribute('updated_at') && saved_change_to_attribute('updated_at')[1]
local_updated_at = changes['updated_at'][1] local_updated_at = saved_change_to_attribute('updated_at')[1]
end end
history_item = { history_item = {
'attribute' => 'state', 'attribute' => 'state',
'created_at' => local_updated_at, 'created_at' => local_updated_at,
'value_from' => Ticket::State.find(changes['state_id'][0]).name, 'value_from' => Ticket::State.find(saved_change_to_attribute('state_id')[0]).name,
'value_to' => Ticket::State.find(changes['state_id'][1]).name, 'value_to' => Ticket::State.find(saved_change_to_attribute('state_id')[1]).name,
} }
if last_history_state if last_history_state
last_history_state = history_item last_history_state = history_item

View file

@ -81,8 +81,8 @@ push translations to online
}, },
{ {
json: true, json: true,
open_timeout: 6, open_timeout: 8,
read_timeout: 16, read_timeout: 24,
} }
) )
raise "Can't push translations to #{url}: #{result.error}" if !result.success? raise "Can't push translations to #{url}: #{result.error}" if !result.success?

View file

@ -1055,7 +1055,7 @@ raise 'Minimum one user need to have admin permissions'
def avatar_for_email_check def avatar_for_email_check
return true if email.blank? return true if email.blank?
return true if email !~ /@/ 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 # save/update avatar
avatar = Avatar.auto_detection( avatar = Avatar.auto_detection(
@ -1106,8 +1106,7 @@ raise 'Minimum one user need to have admin permissions'
# reset login_failed if password is changed # reset login_failed if password is changed
def reset_login_failed def reset_login_failed
return true if !changes return true if !will_save_change_to_attribute?('password')
return true if !changes['password']
self.login_failed = 0 self.login_failed = 0
true true
end end

View file

@ -0,0 +1,17 @@
<link rel="stylesheet" href="/assets/tests/qunit-1.21.0.css">
<script src="/assets/tests/qunit-1.21.0.js"></script>
<script src="/assets/tests/table_extended.js"></script>
<style type="text/css">
body {
padding-top: 0px;
}
</style>
<script type="text/javascript">
</script>
<div id="qunit" class="u-dontfold"></div>
<div id="table"></div>

View file

@ -14,6 +14,7 @@ Zammad::Application.routes.draw do
match '/tests_form_column_select', to: 'tests#form_column_select', via: :get 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_form_searchable_select', to: 'tests#form_searchable_select', via: :get
match '/tests_table', to: 'tests#table', 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_html_utils', to: 'tests#html_utils', via: :get
match '/tests_ticket_selector', to: 'tests#ticket_selector', via: :get match '/tests_ticket_selector', to: 'tests#ticket_selector', via: :get
match '/tests_taskbar', to: 'tests#taskbar', via: :get match '/tests_taskbar', to: 'tests#taskbar', via: :get

View file

@ -5,7 +5,3 @@ set -ex
rm app/assets/javascripts/app/controllers/layout_ref.coffee rm app/assets/javascripts/app/controllers/layout_ref.coffee
rm -rf app/assets/javascripts/app/views/layout_ref/ rm -rf app/assets/javascripts/app/views/layout_ref/
rm app/assets/javascripts/app/controllers/karma.coffee 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

View file

@ -43,7 +43,7 @@ server {
proxy_set_header CLIENT_IP $remote_addr; proxy_set_header CLIENT_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 180; proxy_read_timeout 300;
proxy_pass http://zammad; proxy_pass http://zammad;
gzip on; gzip on;

View file

@ -134,7 +134,7 @@ server {
proxy_set_header CLIENT_IP $remote_addr; proxy_set_header CLIENT_IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 180; proxy_read_timeout 300;
proxy_pass http://zammad; proxy_pass http://zammad;
gzip on; gzip on;

View file

@ -42,7 +42,7 @@ returns
"container": "0", "container": "0",
"const": "C__OBJTYPE__SERVICE", "const": "C__OBJTYPE__SERVICE",
"color": "987384", "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", "icon": "images/icons/silk/application_osx_terminal.png",
"cats": "4", "cats": "4",
"tree_group": "1", "tree_group": "1",
@ -56,7 +56,7 @@ returns
"container": "0", "container": "0",
"const": "C__OBJTYPE__APPLICATION", "const": "C__OBJTYPE__APPLICATION",
"color": "E4B9D7", "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", "icon": "images/icons/silk/application_xp.png",
"cats": "20", "cats": "20",
"tree_group": "1", "tree_group": "1",
@ -71,7 +71,7 @@ or with filter:
"result": [ "result": [
{ {
"id": "26", "id": "26",
"title": "demo.panic.at", "title": "demo.example.com",
"sysid": "SYSID_1485512390", "sysid": "SYSID_1485512390",
"type": "59", "type": "59",
"created": "2017-01-27 11:19:24", "created": "2017-01-27 11:19:24",
@ -81,7 +81,7 @@ or with filter:
"status": "2", "status": "2",
"cmdb_status": "6", "cmdb_status": "6",
"cmdb_status_title": "in operation", "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 end
def self._url_cleanup(url) 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 raise "Invalid endpoint '#{url}', need to start with http:// or https://" if url !~ %r{^http(s|)://}i
url = _url_cleanup_baseurl(url) url = _url_cleanup_baseurl(url)
url = "#{url}/src/jsonrpc.php" url = "#{url}/src/jsonrpc.php"
@ -142,6 +144,8 @@ or with filter:
end end
def self._url_cleanup_baseurl(url) 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 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{src/jsonrpc.php}, '')
url.gsub(%r{([^:])//+}, '\\1/') url.gsub(%r{([^:])//+}, '\\1/')

View file

@ -37,7 +37,7 @@ module Import
def changed_attributes def changed_attributes
return if @resource.blank? return if @resource.blank?
# dry run # dry run
return @resource.changes if @resource.changed? return @resource.changes_to_save if @resource.has_changes_to_save?
# live run # live run
@resource.previous_changes @resource.previous_changes
end end

View file

@ -39,9 +39,9 @@ class Sequencer
def changes def changes
@changes ||= begin @changes ||= begin
if instance.changed? if instance.has_changes_to_save?
# dry run # dry run
instance.changes instance.changes_to_save
else else
# live run # live run
instance.previous_changes instance.previous_changes

View file

@ -4,6 +4,8 @@ require 'cache'
class Service::GeoIp::Zammad class Service::GeoIp::Zammad
def self.location(address) def self.location(address)
return {} if address == '127.0.0.1'
return {} if address == '::1'
# check cache # check cache
cache_key = "zammadgeoip::#{address}" cache_key = "zammadgeoip::#{address}"

View file

@ -1,5 +1,5 @@
// form // form
test( "table test", function() { test('table test', function() {
App.i18n.set('de-de') App.i18n.set('de-de')
$('#table').append('<hr><h1>table simple I</h1><div id="table1"></div>') $('#table').append('<hr><h1>table simple I</h1><div id="table1"></div>')
@ -85,18 +85,18 @@ test( "table test", function() {
} }
}, },
}) })
equal( el.find('table > thead > tr').length, 1, 'row count') 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(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(2)').text().trim(), 'Erstellt', 'check header')
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', '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').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: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(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(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').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: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(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('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2')
$('#table').append('<hr><h1>table simple II</h1><div id="table2"></div>') $('#table').append('<hr><h1>table simple II</h1><div id="table2"></div>')
el = $('#table2') el = $('#table2')
@ -108,18 +108,18 @@ test( "table test", function() {
checkbox: false, checkbox: false,
radio: false, radio: false,
}) })
equal( el.find('table > thead > tr').length, 1, 'row count') 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(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(2)').text().trim(), 'Erstellt', 'check header')
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', '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').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: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(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(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').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: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(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('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'true', 'check row 2')
$('#table').append('<hr><h1>table simple III</h1><div id="table3"></div>') $('#table').append('<hr><h1>table simple III</h1><div id="table3"></div>')
el = $('#table3') el = $('#table3')
@ -130,16 +130,16 @@ test( "table test", function() {
checkbox: false, checkbox: false,
radio: false, radio: false,
}) })
equal( el.find('table > thead > tr').length, 1, 'row count') 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(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(2)').text().trim(), 'Erstellt', 'check header')
notEqual( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', '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').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: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(2)').text().trim(), '?', 'check row 2')
notEqual( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'true', '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').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: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(2)').text().trim(), '?', 'check row 1')
notEqual( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'false', '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'}), objects: App.Ticket.search({sortBy:'created_at', order: 'DESC'}),
checkbox: true, checkbox: true,
}) })
equal( el.find('table > thead > tr').length, 1, 'row count') 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(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(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(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(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(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(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(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(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('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').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').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) 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(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(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(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(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(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(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(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(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(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').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').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) 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(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(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(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(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(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(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(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(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(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').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').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) 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(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(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(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(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(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(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(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(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('tbody > tr:nth-child(3) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 3')
el.find('input[name="bulk_all"]').click() 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').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(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').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(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').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(3) > td:nth-child(1) input').val(), '1', 'check row 3')
$('#table').append('<hr><h1>table complex II</h1><div id="table5"></div>') $('#table').append('<hr><h1>table complex II</h1><div id="table5"></div>')
el = $('#table5') 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').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(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(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(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(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(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(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(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('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').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(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').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').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) 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(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(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(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(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(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(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(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(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').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(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').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').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) 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(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(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(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(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(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(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(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('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() 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').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(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').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(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').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(5) > td:nth-child(1) input').val(), '1', 'check row 5')
el.find('tbody > tr:nth-child(5) > td:nth-child(1) label').click() 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').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').val(), '1', 'check row 5')
}); });
test( "table test 2", function() { test('table test 2', function() {
App.i18n.set('de-de') App.i18n.set('de-de')
$('#table').append('<hr><h1>table with hash</h1><div id="table-hash1"></div>') $('#table').append('<hr><h1>table with hash</h1><div id="table-hash1"></div>')
@ -413,27 +413,27 @@ test( "table test 2", function() {
model: App.Channel, model: App.Channel,
objects: App.Channel.search({sortBy:'adapter', order: 'ASC'}), objects: App.Channel.search({sortBy:'adapter', order: 'ASC'}),
}) })
equal( el.find('table > thead > tr').length, 1, 'row count') 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(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(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(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(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('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').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(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(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(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(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(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').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(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(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(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(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('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') App.i18n.set('de-de')
$('#table').append('<hr><h1>table with link</h1><div id="table-link1"></div>') $('#table').append('<hr><h1>table with link</h1><div id="table-link1"></div>')
@ -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').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(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('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').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(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(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)').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-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) > 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)').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('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(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').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(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(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)').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-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) > 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)').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('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('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') App.i18n.set('de-de')
$('#table').append('<hr><h1>table with data</h1><div id="table-data1"></div>') $('#table').append('<hr><h1>table with data</h1><div id="table-data1"></div>')
@ -554,16 +554,16 @@ test( "table test 4", function() {
objects: data objects: data
}); });
equal( el.find('table > thead > tr').length, 1, 'row count') 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(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(2)').text().trim(), 'Data', 'check header')
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', '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').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: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(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(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').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: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(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('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2')
}); });

View file

@ -0,0 +1,274 @@
// initial list
test('table new - initial list', function() {
App.i18n.set('de-de')
$('#table').append('<hr><h1>table with data</h1><div id="table-new1"></div>')
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')
})

View file

@ -109,4 +109,8 @@ test("check pretty date", function() {
result = App.PrettyDate.humanTime(current.getTime() + (60050 * 60 * 24 * 30.5)); result = App.PrettyDate.humanTime(current.getTime() + (60050 * 60 * 24 * 30.5));
equal(result, 'in 30 days', 'in 30.5 days') equal(result, 'in 30 days', 'in 30.5 days')
//
}); });

View file

@ -60,6 +60,7 @@ if [ "$LEVEL" == '1' ]; then
# test/browser/taskbar_session_test.rb # test/browser/taskbar_session_test.rb
# test/browser/taskbar_task_test.rb # test/browser/taskbar_task_test.rb
# test/browser/translation_test.rb # test/browser/translation_test.rb
rm test/browser/user_switch_cache_test.rb
elif [ "$LEVEL" == '2' ]; then elif [ "$LEVEL" == '2' ]; then
echo "slicing level 2" echo "slicing level 2"
@ -117,6 +118,7 @@ elif [ "$LEVEL" == '2' ]; then
rm test/browser/taskbar_session_test.rb rm test/browser/taskbar_session_test.rb
rm test/browser/taskbar_task_test.rb rm test/browser/taskbar_task_test.rb
rm test/browser/translation_test.rb rm test/browser/translation_test.rb
#rm test/browser/user_switch_cache_test.rb
elif [ "$LEVEL" == '3' ]; then elif [ "$LEVEL" == '3' ]; then
echo "slicing level 3" echo "slicing level 3"
@ -174,6 +176,7 @@ elif [ "$LEVEL" == '3' ]; then
rm test/browser/taskbar_session_test.rb rm test/browser/taskbar_session_test.rb
rm test/browser/taskbar_task_test.rb rm test/browser/taskbar_task_test.rb
rm test/browser/translation_test.rb rm test/browser/translation_test.rb
rm test/browser/user_switch_cache_test.rb
elif [ "$LEVEL" == '4' ]; then elif [ "$LEVEL" == '4' ]; then
echo "slicing level 4" echo "slicing level 4"
@ -231,6 +234,7 @@ elif [ "$LEVEL" == '4' ]; then
rm test/browser/taskbar_session_test.rb rm test/browser/taskbar_session_test.rb
rm test/browser/taskbar_task_test.rb rm test/browser/taskbar_task_test.rb
rm test/browser/translation_test.rb rm test/browser/translation_test.rb
rm test/browser/user_switch_cache_test.rb
elif [ "$LEVEL" == '5' ]; then elif [ "$LEVEL" == '5' ]; then
echo "slicing level 5" echo "slicing level 5"
@ -287,6 +291,7 @@ elif [ "$LEVEL" == '5' ]; then
rm test/browser/taskbar_session_test.rb rm test/browser/taskbar_session_test.rb
rm test/browser/taskbar_task_test.rb rm test/browser/taskbar_task_test.rb
rm test/browser/translation_test.rb rm test/browser/translation_test.rb
rm test/browser/user_switch_cache_test.rb
elif [ "$LEVEL" == '6' ]; then elif [ "$LEVEL" == '6' ]; then
echo "slicing level 6" echo "slicing level 6"
@ -346,6 +351,7 @@ elif [ "$LEVEL" == '6' ]; then
rm test/browser/taskbar_session_test.rb rm test/browser/taskbar_session_test.rb
rm test/browser/taskbar_task_test.rb rm test/browser/taskbar_task_test.rb
rm test/browser/translation_test.rb rm test/browser/translation_test.rb
rm test/browser/user_switch_cache_test.rb
else else
echo "ERROR: Invalid level $LEVEL - 1, 2, 3, 4, 5 or 6 is available" echo "ERROR: Invalid level $LEVEL - 1, 2, 3, 4, 5 or 6 is available"

View file

@ -16,6 +16,12 @@ require 'daemons'
def before_fork 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 # remember open file handles
@files_to_reopen = [] @files_to_reopen = []
ObjectSpace.each_object(File) do |file| ObjectSpace.each_object(File) do |file|

View file

@ -15,8 +15,8 @@ RSpec.describe ExternalSync do
current_changes: current_changes, current_changes: current_changes,
) )
expect(result).to be false expect(result).to be false
expect(object.changed?).to be false expect(object.has_changes_to_save?).to be false
end end
it 'keeps ActiveRecord instance unchanged on local and remote changes' do it 'keeps ActiveRecord instance unchanged on local and remote changes' do
@ -30,8 +30,8 @@ RSpec.describe ExternalSync do
current_changes: current_changes, current_changes: current_changes,
) )
expect(result).to be false expect(result).to be false
expect(object.changed?).to be false expect(object.has_changes_to_save?).to be false
end end
it 'changes ActiveRecord instance attribute(s) for remote changes' do it 'changes ActiveRecord instance attribute(s) for remote changes' do
@ -45,8 +45,8 @@ RSpec.describe ExternalSync do
current_changes: current_changes, current_changes: current_changes,
) )
expect(result).to be true expect(result).to be true
expect(object.changed?).to be true expect(object.has_changes_to_save?).to be true
end end
it 'prevents ActiveRecord method calls' do it 'prevents ActiveRecord method calls' do
@ -61,9 +61,9 @@ RSpec.describe ExternalSync do
current_changes: current_changes, current_changes: current_changes,
) )
expect(result).to be false expect(result).to be false
expect(object.changed?).to be false expect(object.has_changes_to_save?).to be false
expect(object.destroyed?).to be false expect(object.destroyed?).to be false
end end
end end

View file

@ -118,6 +118,13 @@ class AAbUnitTest < TestCase
value: '0', value: '0',
) )
location(url: browser_url + '/tests_table_extended')
sleep 4
match(
css: '.result .failed',
value: '0',
)
location(url: browser_url + '/tests_html_utils') location(url: browser_url + '/tests_html_utils')
sleep 4 sleep 4
match( match(

View file

@ -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

View file

@ -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
}

View file

@ -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
}

View file

@ -209,7 +209,7 @@ class EmailHelperTest < ActiveSupport::TestCase
} }
) )
assert_equal('invalid', result[:result]) 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]) assert_equal('imap.gmail.com', result[:settings][:options][:host])
result = EmailHelper::Probe.inbound( result = EmailHelper::Probe.inbound(
@ -225,8 +225,8 @@ class EmailHelperTest < ActiveSupport::TestCase
assert_equal('invalid', result[:result]) assert_equal('invalid', result[:result])
# if we have to many failed logins, we need to handle another error message # if we have to many failed logins, we need to handle another error message
if result[:message_human] && !result[:message_human].empty? if result[:message_human].present?
assert_equal('Authentication failed, invalid credentials!', result[:message_human]) assert_match(/Authentication failed, username incorrect|Authentication failed, invalid credentials/, result[:message_human])
else else
assert_match(/Web login required/, result[:message]) assert_match(/Web login required/, result[:message])
end end
@ -457,7 +457,7 @@ class EmailHelperTest < ActiveSupport::TestCase
email: mailbox_user, email: mailbox_user,
password: mailbox_password, password: mailbox_password,
) )
assert_equal(nil, result[:reason]) assert_nil(result[:reason])
assert_equal('ok', result[:result]) assert_equal('ok', result[:result])
assert_equal('pop.gmail.com', result[:setting][:inbound][:options][:host]) assert_equal('pop.gmail.com', result[:setting][:inbound][:options][:host])
assert_equal('smtp.gmail.com', result[:setting][:outbound][:options][:host]) assert_equal('smtp.gmail.com', result[:setting][:outbound][:options][:host])

View file

@ -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

View file

@ -61,7 +61,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
assert_equal(0, email_notification_count('user_device_new_location', @admin.email)) assert_equal(0, email_notification_count('user_device_new_location', @admin.email))
params = { without_fingerprint: 'none', username: 'user-device-admin', password: 'adminpw' } 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) assert_response(422)
result = JSON.parse(@response.body) 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)) assert_equal(0, email_notification_count('user_device_new_location', @admin.email))
params = { fingerprint: 'my_finger_print', username: 'user-device-admin', password: 'adminpw' } 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) assert_response(201)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
assert_equal(result.class, Hash) assert_equal(result.class, Hash)
@ -102,7 +102,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
sleep 2 sleep 2
params = {} params = {}
get '/api/v1/users', params.to_json, @headers get '/api/v1/users', params: params.to_json, headers: @headers
assert_response(200) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
assert_equal(result.class, Array) 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) assert_equal(user_device_last.updated_at.to_s, user_device_first.updated_at.to_s)
params = { fingerprint: 'my_finger_print' } params = { fingerprint: 'my_finger_print' }
get '/api/v1/signshow', params, @headers get '/api/v1/signshow', params: params, headers: @headers
assert_response(200) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
assert_equal(result.class, Hash) 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 ENV['USER_DEVICE_UPDATED_AT'] = (Time.zone.now - 4.hours).to_s
params = {} params = {}
get '/api/v1/users', params.to_json, @headers get '/api/v1/users', params: params.to_json, headers: @headers
assert_response(200) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
assert_equal(result.class, Array) assert_equal(result.class, Array)
@ -153,7 +153,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch
params = {} params = {}
get '/api/v1/users', params.to_json, @headers get '/api/v1/users', params: params.to_json, headers: @headers
assert_response(200) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
@ -171,7 +171,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
test '04 - login index with admin with fingerprint - II' do test '04 - login index with admin with fingerprint - II' do
params = { fingerprint: 'my_finger_print_II', username: 'user-device-admin', password: 'adminpw' } 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) assert_response(201)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
@ -185,7 +185,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
assert(result['config']) assert(result['config'])
assert('my_finger_print_II', controller.session[:user_device_fingerprint]) 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) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
assert_equal(result.class, Array) 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)) assert_equal(0, email_notification_count('user_device_new_location', @admin.email))
params = { fingerprint: 'my_finger_print_II' } params = { fingerprint: 'my_finger_print_II' }
get '/api/v1/signshow', params, @headers get '/api/v1/signshow', params: params, headers: @headers
assert_response(200) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
assert_equal(result.class, Hash) assert_equal(result.class, Hash)
@ -214,7 +214,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch
params = {} params = {}
get '/api/v1/users', params.to_json, @headers get '/api/v1/users', params: params.to_json, headers: @headers
assert_response(200) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
@ -232,7 +232,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
test '05 - login index with admin with fingerprint - II' do test '05 - login index with admin with fingerprint - II' do
params = { fingerprint: 'my_finger_print_II', username: 'user-device-admin', password: 'adminpw' } 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) assert_response(201)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
@ -253,7 +253,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-admin', 'adminpw') credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-admin', 'adminpw')
params = {} 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) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
@ -267,7 +267,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
sleep 2 sleep 2
params = {} 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) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
@ -285,7 +285,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
user_device_last.save! user_device_last.save!
params = {} params = {}
get '/api/v1/users', params, @headers.merge('Authorization' => credentials) get '/api/v1/users', params: params, headers: @headers.merge('Authorization' => credentials)
assert_response(200) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
@ -307,7 +307,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-admin', 'adminpw') credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-admin', 'adminpw')
params = {} 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) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
@ -330,7 +330,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-agent', 'agentpw') credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-agent', 'agentpw')
params = {} 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) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
@ -353,7 +353,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-agent', 'agentpw') credentials = ActionController::HttpAuthentication::Basic.encode_credentials('user-device-agent', 'agentpw')
params = {} 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) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
@ -375,7 +375,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
ENV['SWITCHED_FROM_USER_ID'] = @admin.id.to_s ENV['SWITCHED_FROM_USER_ID'] = @admin.id.to_s
params = { fingerprint: 'my_finger_print_II', username: 'user-device-agent', password: 'agentpw' } 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) assert_response(201)
result = JSON.parse(@response.body) 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 ENV['USER_DEVICE_UPDATED_AT'] = (Time.zone.now - 4.hours).to_s
params = {} params = {}
get '/api/v1/users', params.to_json, @headers get '/api/v1/users', params: params.to_json, headers: @headers
assert_response(200) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)
assert_equal(result.class, Array) assert_equal(result.class, Array)
@ -412,7 +412,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch ENV['TEST_REMOTE_IP'] = '195.65.29.254' # ch
params = {} params = {}
get '/api/v1/users', params.to_json, @headers get '/api/v1/users', params: params.to_json, headers: @headers
assert_response(200) assert_response(200)
result = JSON.parse(@response.body) result = JSON.parse(@response.body)

View file

@ -62,6 +62,8 @@ class ActiveSupport::TestCase
PostmasterFilter.destroy_all PostmasterFilter.destroy_all
Ticket.destroy_all Ticket.destroy_all
Taskbar.destroy_all Taskbar.destroy_all
Sla.destroy_all
Calendar.destroy_all
# reset settings # reset settings
Setting.all.pluck(:name).each { |name| Setting.all.pluck(:name).each { |name|

View file

@ -446,7 +446,21 @@ class AssetsTest < ActiveSupport::TestCase
roles: roles, 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_state1 = Ticket::State.find_by(name: 'new')
ticket_state2 = Ticket::State.find_by(name: 'open') ticket_state2 = Ticket::State.find_by(name: 'open')
sla = Sla.create_or_update( sla = Sla.create_or_update(

View file

@ -61,7 +61,7 @@ class CalendarTest < ActiveSupport::TestCase
assert_equal(true, calendar3.default) assert_equal(true, calendar3.default)
calendar2.default = true calendar2.default = true
calendar2.save calendar2.save!
calendar1 = Calendar.find_by(name: 'US 1') calendar1 = Calendar.find_by(name: 'US 1')
calendar2 = Calendar.find_by(name: 'US 2') calendar2 = Calendar.find_by(name: 'US 2')
@ -72,7 +72,7 @@ class CalendarTest < ActiveSupport::TestCase
assert_equal(false, calendar3.default) assert_equal(false, calendar3.default)
calendar2.default = false calendar2.default = false
calendar2.save calendar2.save!
calendar1 = Calendar.find_by(name: 'US 1') calendar1 = Calendar.find_by(name: 'US 1')
calendar2 = Calendar.find_by(name: 'US 2') calendar2 = Calendar.find_by(name: 'US 2')
@ -82,12 +82,16 @@ class CalendarTest < ActiveSupport::TestCase
assert_equal(false, calendar2.default) assert_equal(false, calendar2.default)
assert_equal(false, calendar3.default) assert_equal(false, calendar3.default)
calendar1.destroy calendar1.destroy!
calendar2 = Calendar.find_by(name: 'US 2') calendar2 = Calendar.find_by(name: 'US 2')
calendar3 = Calendar.find_by(name: 'US 3') calendar3 = Calendar.find_by(name: 'US 3')
assert_equal(true, calendar2.default) assert_equal(true, calendar2.default)
assert_equal(false, calendar3.default) assert_equal(false, calendar3.default)
calendar2.destroy!
calendar3.destroy!
travel_back travel_back
end end
@ -237,6 +241,8 @@ class CalendarTest < ActiveSupport::TestCase
assert_equal('Christmas1', calendar1.public_holidays['2019-12-24']['summary']) assert_equal('Christmas1', calendar1.public_holidays['2019-12-24']['summary'])
assert_nil(calendar1.public_holidays['2020-12-24']) assert_nil(calendar1.public_holidays['2020-12-24'])
calendar1.destroy!
travel_back travel_back
end end

View file

@ -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#host-states
# http://docs.icinga.org/icinga2/latest/doc/module/icinga2/chapter/monitoring-basics#service-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_integration', true)
Setting.set('icinga_sender', 'icinga2@monitoring.example.com')
end
# not matching sender test 'base tests' do
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'])
# RBL check # RBL check
email_raw_string = "To: support@example.com email_raw_string = "To: support@example.com
@ -51,7 +23,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-1-1@monitoring.znuny.com> 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 ***** ***** 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-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-1-2@monitoring.znuny.com> 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 ***** ***** 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-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-1-2@monitoring.znuny.com> 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 ***** ***** 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-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-2@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-icinga-2@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga) From: icinga2@monitoring.example.com (icinga)
***** Icinga ***** ***** Icinga *****
@ -179,7 +151,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-3@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-icinga-3@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga) From: icinga2@monitoring.example.com (icinga)
***** Icinga ***** ***** Icinga *****
@ -214,7 +186,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-4@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-icinga-4@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga) From: icinga2@monitoring.example.com (icinga)
***** Icinga ***** ***** Icinga *****
@ -249,7 +221,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga) From: icinga2@monitoring.example.com (icinga)
***** Icinga ***** ***** Icinga *****
@ -284,7 +256,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga) From: icinga2@monitoring.example.com (icinga)
***** Icinga ***** ***** Icinga *****
@ -317,7 +289,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga) From: icinga2@monitoring.example.com (icinga)
***** Icinga ***** ***** Icinga *****
@ -341,9 +313,246 @@ Comment: [] =
assert_equal('apn4711.dc.example.com', ticket_3.preferences['icinga']['host']) assert_equal('apn4711.dc.example.com', ticket_3.preferences['icinga']['host'])
assert_nil(ticket_3_1.preferences['icinga']['service']) assert_nil(ticket_3_1.preferences['icinga']['service'])
assert_equal('DOWN', ticket_3_1.preferences['icinga']['state']) 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 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 end

View file

@ -6,38 +6,12 @@ class IntegrationNagiosTest < ActiveSupport::TestCase
# according # according
# https://github.com/NagiosEnterprises/nagioscore/blob/754218e67653929a58938b99ef6b6039b6474fe4/sample-config/template-object/commands.cfg.in#L35 # 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_integration', true)
Setting.set('nagios_sender', 'nagios2@monitoring.example.com')
end
# not matching sender test 'base tests' do
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'])
# matching sender - CPU Load/host.internal.loc # matching sender - CPU Load/host.internal.loc
email_raw_string = "To: support@example.com email_raw_string = "To: support@example.com
@ -46,7 +20,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-2@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-nagios-2@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios) From: nagios2@monitoring.example.com (nagios)
***** Nagios ***** ***** Nagios *****
@ -78,7 +52,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-3@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-nagios-3@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios) From: nagios2@monitoring.example.com (nagios)
***** Nagios ***** ***** Nagios *****
@ -111,7 +85,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-4@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-nagios-4@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios) From: nagios2@monitoring.example.com (nagios)
***** Nagios ***** ***** Nagios *****
@ -144,7 +118,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios) From: nagios2@monitoring.example.com (nagios)
***** Nagios ***** ***** Nagios *****
@ -176,7 +150,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios) From: nagios2@monitoring.example.com (nagios)
***** Nagios ***** ***** Nagios *****
@ -209,7 +183,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com> Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios) From: nagios2@monitoring.example.com (nagios)
***** Nagios ***** ***** Nagios *****
@ -238,4 +212,232 @@ Comment: [] =
end 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 end

View file

@ -91,7 +91,7 @@ class KarmaTest < ActiveSupport::TestCase
ticket1.updated_by_id = agent1.id ticket1.updated_by_id = agent1.id
ticket1.updated_at = Time.zone.now - 9.hours ticket1.updated_at = Time.zone.now - 9.hours
ticket1.created_at = Time.zone.now - 9.hours ticket1.created_at = Time.zone.now - 9.hours
ticket1.save ticket1.save!
# execute object transaction # execute object transaction
Observer::Transaction.commit Observer::Transaction.commit
@ -113,7 +113,7 @@ class KarmaTest < ActiveSupport::TestCase
ticket1.updated_by_id = agent1.id ticket1.updated_by_id = agent1.id
ticket1.updated_at = Time.zone.now - 9.hours ticket1.updated_at = Time.zone.now - 9.hours
ticket1.created_at = Time.zone.now - 9.hours ticket1.created_at = Time.zone.now - 9.hours
ticket1.save ticket1.save!
# execute object transaction # execute object transaction
Observer::Transaction.commit Observer::Transaction.commit
@ -127,7 +127,7 @@ class KarmaTest < ActiveSupport::TestCase
ticket1.updated_by_id = agent2.id ticket1.updated_by_id = agent2.id
ticket1.updated_at = Time.zone.now - 9.hours ticket1.updated_at = Time.zone.now - 9.hours
ticket1.created_at = Time.zone.now - 9.hours ticket1.created_at = Time.zone.now - 9.hours
ticket1.save ticket1.save!
# execute object transaction # execute object transaction
Observer::Transaction.commit Observer::Transaction.commit
@ -138,7 +138,7 @@ class KarmaTest < ActiveSupport::TestCase
assert_equal(0, Karma.score_by_user(customer1)) assert_equal(0, Karma.score_by_user(customer1))
ticket1.state = Ticket::State.lookup(name: 'open') ticket1.state = Ticket::State.lookup(name: 'open')
ticket1.save ticket1.save!
Ticket::Article.create( Ticket::Article.create(
ticket_id: ticket1.id, ticket_id: ticket1.id,
@ -169,7 +169,7 @@ class KarmaTest < ActiveSupport::TestCase
Scheduler.worker(true) Scheduler.worker(true)
ticket1.state = Ticket::State.lookup(name: 'closed') ticket1.state = Ticket::State.lookup(name: 'closed')
ticket1.save ticket1.save!
# execute object transaction # execute object transaction
Observer::Transaction.commit Observer::Transaction.commit
@ -385,7 +385,7 @@ class KarmaTest < ActiveSupport::TestCase
ticket2.state = Ticket::State.lookup(name: 'pending reminder') ticket2.state = Ticket::State.lookup(name: 'pending reminder')
ticket2.pending_time = Time.zone.now - 1.day ticket2.pending_time = Time.zone.now - 1.day
ticket2.save ticket2.save!
Ticket.process_pending Ticket.process_pending
@ -395,7 +395,7 @@ class KarmaTest < ActiveSupport::TestCase
ticket2.state = Ticket::State.lookup(name: 'pending reminder') ticket2.state = Ticket::State.lookup(name: 'pending reminder')
ticket2.pending_time = Time.zone.now - 3.days ticket2.pending_time = Time.zone.now - 3.days
ticket2.save ticket2.save!
Ticket.process_pending Ticket.process_pending
@ -459,7 +459,7 @@ class KarmaTest < ActiveSupport::TestCase
created_by_id: 1, created_by_id: 1,
) )
ticket2.state = Ticket::State.lookup(name: 'open') ticket2.state = Ticket::State.lookup(name: 'open')
ticket2.save ticket2.save!
Observer::Transaction.commit Observer::Transaction.commit
Scheduler.worker(true) Scheduler.worker(true)
@ -511,10 +511,10 @@ class KarmaTest < ActiveSupport::TestCase
assert_equal('Hero', Karma::User.level_by_score(50_000)) assert_equal('Hero', Karma::User.level_by_score(50_000))
# cleanup # cleanup
ticket1.destroy ticket1.destroy!
ticket2.destroy ticket2.destroy!
calendar1.destroy calendar1.destroy!
sla1.destroy sla1.destroy!
end end

View file

@ -33,7 +33,7 @@ class PackageTest < ActiveSupport::TestCase
{ {
"permission": "644", "permission": "644",
"location": "db/addon/unit_test_sample/20121212000001_create_base.rb", "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", "permission": "644",
"location": "db/addon/unit_test_sample/20121212000001_create_base.rb", "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", "permission": "644",
"location": "db/addon/unit_test_sample/20121212000001_create_base.rb", "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| tests.each { |test|
if test[:action] == 'install' if test[:action] == 'install'
begin begin
package = Package.install( string: test[:zpm] ) package = Package.install(string: test[:zpm])
rescue => e rescue => e
puts 'ERROR: ' + e.inspect puts 'ERROR: ' + e.inspect
end end
if test[:result] if test[:result]
assert( package, 'install package not successful' ) assert(package, 'install package not successful')
issues = package.verify issues = package.verify
assert( !issues, 'package verify not successful' ) assert(!issues, 'package verify not successful')
else else
assert( !package, 'install package successful but should not' ) assert(!package, 'install package successful but should not')
end end
elsif test[:action] == 'reinstall' elsif test[:action] == 'reinstall'
begin begin
package = Package.reinstall( test[:name] ) package = Package.reinstall(test[:name])
rescue rescue
package = false package = false
end end
if test[:result] if test[:result]
assert( package, 'reinstall package not successful' ) assert(package, 'reinstall package not successful')
issues = package.verify issues = package.verify
assert( !issues, 'package verify not successful' ) assert(!issues, 'package verify not successful')
else else
assert( !package, 'reinstall package successful but should not' ) assert(!package, 'reinstall package successful but should not')
end end
elsif test[:action] == 'uninstall' elsif test[:action] == 'uninstall'
if test[:zpm] if test[:zpm]
begin begin
package = Package.uninstall( string: test[:zpm] ) package = Package.uninstall(string: test[:zpm])
rescue rescue
package = false package = false
end end
else else
begin begin
package = Package.uninstall( name: test[:name], version: test[:version] ) package = Package.uninstall(name: test[:name], version: test[:version])
rescue rescue
package = false package = false
end end
end end
if test[:result] if test[:result]
assert( package, 'uninstall package not successful' ) assert(package, 'uninstall package not successful')
else else
assert( !package, 'uninstall package successful but should not' ) assert(!package, 'uninstall package successful but should not')
end end
elsif test[:action] == 'auto_install' elsif test[:action] == 'auto_install'
if test[:zpm] if test[:zpm]
if !File.exist?( Rails.root.to_s + '/auto_install/' ) if !File.exist?(Rails.root.to_s + '/auto_install/')
Dir.mkdir( Rails.root.to_s + '/auto_install/', 0o755) Dir.mkdir(Rails.root.to_s + '/auto_install/', 0o755)
end end
location = Rails.root.to_s + '/auto_install/unittest.zpm' location = Rails.root.to_s + '/auto_install/unittest.zpm'
file = File.new( location, 'wb' ) file = File.new(location, 'wb')
file.write( test[:zpm] ) file.write(test[:zpm])
file.close file.close
end end
begin begin
@ -363,22 +363,22 @@ class PackageTest < ActiveSupport::TestCase
success = false success = false
end end
if test[:zpm] if test[:zpm]
File.delete( location ) File.delete(location )
end end
end end
if test[:verify] && test[:verify][:package] if test[:verify] && test[:verify][:package]
exists = Package.where( name: test[:verify][:package][:name], version: test[:verify][:package][:version] ).first exists = Package.where(name: test[:verify][:package][:name], version: test[:verify][:package][:version]).first
assert( exists, "package '#{test[:verify][:package][:name]}' is not installed" ) assert(exists, "package '#{test[:verify][:package][:name]}' is not installed" )
end end
next if !test[:verify] next if !test[:verify]
next if !test[:verify][:check_files] next if !test[:verify][:check_files]
test[:verify][:check_files].each { |item| test[:verify][:check_files].each { |item|
exists = File.exist?( item[:location] ) exists = File.exist?(item[:location])
if item[:result] if item[:result]
assert( exists, "'#{item[:location]}' exists" ) assert(exists, "'#{item[:location]}' exists" )
else else
assert( !exists, "'#{item[:location]}' doesn't exists" ) assert(!exists, "'#{item[:location]}' doesn't exists" )
end end
} }
} }

View file

@ -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

View file

@ -224,8 +224,6 @@ class TicketOverviewOutOfOfficeTest < ActiveSupport::TestCase
@agent1.out_of_office_replacement_id = @agent2.id @agent1.out_of_office_replacement_id = @agent2.id
@agent1.save! @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_equal(@agent2.out_of_office_agent_of.count, 1)
assert(@agent2.out_of_office_agent_of[0]) assert(@agent2.out_of_office_agent_of[0])
assert_equal(@agent2.out_of_office_agent_of[0].id, @agent1.id) assert_equal(@agent2.out_of_office_agent_of[0].id, @agent1.id)

View file

@ -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.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_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') assert_nil(ticket.close_at, 'ticket.close_at verify - inbound')
calendar1.destroy!
calendar2.destroy!
end end
test 'ticket sla + selector' do 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_in_min, 'ticket.close_in_min')
assert_nil(ticket.close_diff_in_min, 'ticket.close_diff_in_min') assert_nil(ticket.close_diff_in_min, 'ticket.close_diff_in_min')
calendar1.destroy!
end end
test 'ticket sla + timezone + holiday' do 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.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') 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') assert(delete, 'sla destroy')
delete = ticket.destroy delete = ticket.destroy!
assert(delete, 'ticket destroy') assert(delete, 'ticket destroy')
calendar.destroy!
end end
test 'ticket escalation suspend close reopen bug' do 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_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') 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') assert(delete, 'sla destroy')
delete = ticket1.destroy delete = ticket1.destroy!
assert(delete, 'ticket1 destroy') assert(delete, 'ticket1 destroy')
delete = ticket2.destroy delete = ticket2.destroy!
assert(delete, 'ticket2 destroy') assert(delete, 'ticket2 destroy')
calendar.destroy!
end end
test 'ticket escalation suspend' do 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_in_min, 60, 'ticket.close_in_min verify 3')
assert_equal(ticket.close_diff_in_min, 180, 'ticket.close_diff_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') assert(delete, 'sla destroy')
delete = ticket.destroy delete = ticket.destroy!
assert(delete, 'ticket destroy') assert(delete, 'ticket destroy')
calendar.destroy!
end end
test 'ticket ticket.title and article.subject' do 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_in_min, 'ticket.close_in_min verify 3')
assert_nil(ticket.close_diff_in_min, 'ticket.close_diff_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') assert(delete, 'sla destroy')
delete = ticket.destroy delete = ticket.destroy!
assert(delete, 'ticket destroy') assert(delete, 'ticket destroy')
calendar.destroy!
end end
test 'ticket sla + holiday 222' do 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_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') assert_nil(ticket.close_escalation_at, 'ticket.close_escalation_at verify 1')
delete = sla.destroy delete = sla.destroy!
assert(delete, 'sla destroy') assert(delete, 'sla destroy')
delete = ticket.destroy delete = ticket.destroy!
assert(delete, 'ticket destroy') assert(delete, 'ticket destroy')
calendar.destroy!
end end
test 'ticket sla + observer check' do 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_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') assert_nil(ticket.close_escalation_at, 'ticket.close_escalation_at verify 1')
delete = sla.destroy delete = sla.destroy!
assert(delete, 'sla destroy') assert(delete, 'sla destroy')
delete = ticket.destroy delete = ticket.destroy!
assert(delete, 'ticket destroy') assert(delete, 'ticket destroy')
calendar.destroy!
end end
end end