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!
- 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 *
-->

View file

@ -278,6 +278,18 @@ test:integration:telegram:
- ruby -I test test/integration/telegram_controller_test.rb
- rake db:drop
test:integration:idoit:
stage: test
tags:
- core
script:
- export RAILS_ENV=test
- rake db:create
- rake db:migrate
- rake db:seed
- ruby -I test test/integration/idoit_controller_test.rb
- rake db:drop
test:integration:es_mysql:
stage: test
tags:

View file

@ -2,7 +2,7 @@ source 'https://rubygems.org'
ruby '2.4.1'
gem 'rails', '5.0.5'
gem 'rails', '5.1.4'
gem 'rails-observers'
gem 'activerecord-session_store'
@ -53,7 +53,8 @@ gem 'mime-types'
gem 'biz'
gem 'composite_primary_keys'
# temporary till pull request gets merged: https://github.com/composite-primary-keys/composite_primary_keys/pull/404
gem 'composite_primary_keys', git: 'https://github.com/jkowens/composite_primary_keys.git', branch: 'rails-5_1'
gem 'delayed_job_active_record'
gem 'daemons'

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

View file

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

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
minColWidth: 40
baseColWidth: 130
@ -10,9 +101,53 @@ class App.ControllerTable extends App.Controller
elements:
'.js-tableHead': 'tableHead'
constructor: (params) ->
events:
'click .js-sort': 'sortByColumn'
overviewAttributes: undefined
#model: App.TicketPriority,
objects: []
checkbox: false
radio: false
renderState: undefined
groupBy: undefined
destroy: false
columnsLength: undefined
headers: undefined
headerWidth: {}
currentRows: []
orderDirection: 'ASC'
orderBy: undefined
lastOrderDirection: undefined
lastOrderBy: undefined
lastOverview: undefined
customOrderDirection: undefined
customOrderBy: undefined
bindCol: {}
bindRow: {}
constructor: ->
super
if !@model
@model = {}
@overviewAttributes ||= @overview || @model.configure_overview || []
@attributesListRaw ||= @attribute_list || @model.configure_attributes || {}
@attributesList = App.Model.attributesGet(false, @attributesListRaw)
console.log('Table', @overviewAttributes, @overview)
#@setHeaderWidths = App.Model.setHeaderWidthsGet(false, @attributesList)
@destroy = @model.configure_delete
throw 'overviewAttributes needed' if _.isEmpty(@overviewAttributes)
throw 'attributesList needed' if _.isEmpty(@attributesList)
# apply personal preferences
data = {}
if @tableId
@ -21,20 +156,218 @@ class App.ControllerTable extends App.Controller
for key, value of data.order
@[key] = value
@headerWidth = {}
if data.headerWidth
for key, value of data.headerWidth
@headerWidth[key] = value
@availableWidth = @el.width()
@render()
$(window).on 'resize.table', @onResize
@renderQueue()
release: =>
$(window).off 'resize.table', @onResize
update: (params) =>
console.log('params', params)
for key, value of params
@[key] = value
if params.sync is true
return @render()
@renderQueue()
renderQueue: =>
App.QueueManager.add('tableRender', @render)
App.QueueManager.run('tableRender')
render: =>
@html @tableGen()
if @renderState is undefined
# check if table is empty
if _.isEmpty(@objects)
@renderState = 'emptyList'
@el.html(@renderEmptyList())
$(window).on 'resize.table', @onResize
return ['emptyList.new']
else
@renderState = 'List'
@renderTableFull()
$(window).on 'resize.table', @onResize
return ['fullRender.new']
else if @renderState is 'emptyList' && !_.isEmpty(@objects)
@renderState = 'List'
@renderTableFull()
return ['fullRender']
else if @renderState isnt 'emptyList' && _.isEmpty(@objects)
@renderState = 'emptyList'
@el.html(@renderEmptyList())
return ['emptyList']
else
# check if header has changed
if @tableHeadersHasChanged()
@renderTableFull()
return ['fullRender.overviewAttributesChanged']
# check for changes
newRows = @renderTableRows(true)
removedRows = _.difference(@currentRows, newRows)
addedRows = _.difference(newRows, @currentRows)
# if only rows are removed
if _.isEmpty(addedRows) && !_.isEmpty(removedRows) && removedRows.length < 15 && !_.isEmpty(newRows)
newCurrentRows = []
removePositions = []
for position in [0..@currentRows.length-1]
if _.contains(removedRows, @currentRows[position])
removePositions.push position
else
newCurrentRows.push @currentRows[position]
# check if order is still correct
if @_isSame(newRows, newCurrentRows) is true
for position in removePositions
@$("tbody > tr:nth-child(#{position+1})").remove()
@currentRows = newCurrentRows
console.log('fullRender.contentRemoved', removePositions)
return ['fullRender.contentRemoved', removePositions]
if newRows.length isnt @currentRows.length
result = ['fullRender.lenghtChanged', @currentRows.length, newRows.length]
@renderTableFull(newRows)
console.log('result', result)
return result
# compare rows
result = @_isSame(newRows, @currentRows)
if result isnt true
@renderTableFull(newRows)
console.log('result', "fullRender.contentChanged|row(#{result})")
return ['fullRender.contentChanged', result]
console.log('result', 'noChanges')
return ['noChanges']
renderEmptyList: =>
App.view('generic/admin/empty')(
explanation: @explanation
)
renderTableFull: (rows) =>
console.log('renderTableFull', @orderBy, @orderDirection)
@tableHeaders()
@sortList()
bulkIds = @getBulkSelected()
container = @renderTableContainer()
if !rows
rows = @renderTableRows()
@currentRows = clone(rows)
else
@currentRows = clone(rows)
container.find('.js-tableBody').html(rows)
cursorMap =
click: 'pointer'
dblclick: 'pointer'
#mouseover: 'alias'
# bind col.
if !_.isEmpty(@bindCol)
for name, item of @bindCol
if item.events
position = 0
if @dndCallback
position += 1
if @checkbox
position += 1
hit = false
for headerName in @headers
if !hit
position += 1
if headerName.name is name || headerName.name is "#{name}_id" || headerName.name is "#{name}_bulkIds"
hit = true
if hit
for event, callback of item.events
do (container, event, callback) ->
if cursorMap[event]
container.find("tbody > tr > td:nth-child(#{position})").css('cursor', cursorMap[event])
container.on( event, "tbody > tr > td:nth-child(#{position})",
(e) ->
e.stopPropagation()
id = $(e.target).parents('tr').data('id')
callback(id, e)
)
# bind row
if !_.isEmpty(@bindRow)
if @bindRow.events
for event, callback of @bindRow.events
do (container, event, callback) ->
if cursorMap[event]
container.find('tbody > tr').css( 'cursor', cursorMap[event] )
container.on( event, 'tbody > tr',
(e) ->
id = $(e.target).parents('tr').data('id')
callback(id, e)
)
# bind bindCheckbox
if @bindCheckbox
if @bindCheckbox.events
for event, callback of @bindCheckbox.events
do (container, event, callback) ->
container.delegate('input[name="bulk"]', event, (e) ->
e.stopPropagation()
id = $(e.currentTarget).parents('tr').data('id')
checked = $(e.currentTarget).prop('checked')
callback(id, checked, e)
)
# if we have a personalised table
if @tableId
# enable resize column
container.on 'mousedown', '.js-col-resize', @onColResizeMousedown
container.on 'click', '.js-col-resize', @stopPropagation
# enable checkbox bulk selection
if @checkbox
# click first tr>td, catch click
container.delegate('tr > td:nth-child(1)', 'click', (e) ->
e.stopPropagation()
)
# bind on full bulk click
container.delegate('input[name="bulk_all"]', 'change', (e) =>
e.stopPropagation()
clicks = []
if $(e.currentTarget).prop('checked')
$(e.currentTarget).parents('table').find('[name="bulk"]').each( ->
$element = $(@)
return if $element.prop('checked')
$element.prop('checked', true)
id = $element.parents('tr').data('id')
clicks.push [id, true]
)
else
$(e.currentTarget).parents('table').find('[name="bulk"]').each( ->
$element = $(@)
return if !$element.prop('checked')
$element.prop('checked', false)
id = $element.parents('tr').data('id')
clicks.push [id, false]
)
return if !@bindCheckbox
return if !@bindCheckbox.events
return if _.isEmpty(clicks)
for event, callback of @bindCheckbox.events
if event == 'click' || event == 'change'
for click in clicks
callback(click..., e)
)
if @dndCallback
dndOptions =
@ -50,121 +383,79 @@ class App.ControllerTable extends App.Controller
# Set helper cell sizes to match the original sizes
$(@).width( originals.eq(index).outerWidth() )
return helper
update: @dndCallback
@el.find('table > tbody').sortable(dndOptions)
update: @dndCallback
container.find('tbody').sortable(dndOptions)
###
@el.html(container)
@setBulkSelected(bulkIds)
# table based on model
renderTableContainer: =>
$(App.view('generic/table')(
tableId: @tableId
headers: @headers
checkbox: @checkbox
radio: @radio
class: @class
sortable: @dndCallback
))
rowClick = (id, e) ->
e.preventDefault()
console.log('rowClick', id)
rowMouseover = (id, e) ->
e.preventDefault()
console.log('rowMouseover', id)
rowMouseout = (id, e) ->
e.preventDefault()
console.log('rowMouseout', id)
rowDblClick = (id, e) ->
e.preventDefault()
console.log('rowDblClick', id)
renderTableRows: (sort = false) =>
if sort is true
@sortList()
position = 0
columnsLength = @headers.length
if @checkbox || @radio
columnsLength++
groupLast = ''
tableBody = []
for object in @objects
position++
if @groupBy
groupByName = App.viewPrint(object, @groupBy, @attributesList)
if groupLast isnt groupByName
groupLast = groupByName
tableBody.push @renderTableGroupByRow(object, position, groupByName)
tableBody.push @renderTableRow(object, position)
tableBody
colClick = (id, e) ->
e.preventDefault()
console.log('colClick', e.target)
checkboxClick = (id, e) ->
e.preventDefault()
console.log('checkboxClick', e.target)
callbackHeader = (headers) ->
console.log('current header is', headers)
# add new header item
attribute =
name: 'some name'
display: 'Some Name'
headers.push attribute
console.log('new header is', headers)
headers
callbackAttributes = (value, object, attribute, header) ->
console.log('data of item col', value, object, attribute, header)
value = 'New Data To Show'
value
new App.ControllerTable(
tableId: 'some_id_to_idientify_user_based_table_preferences'
el: element
overview: ['host', 'user', 'adapter', 'active']
model: App.Channel
objects: data
groupBy: 'adapter'
checkbox: false
radio: false
class: 'some-css-class'
bindRow:
events:
'click': rowClick
'mouseover': rowMouseover
'mouseout': rowMouseout
'dblclick': rowDblClick
bindCol:
host:
events:
'click': colClick
bindCheckbox:
events:
'click': rowClick
'mouseover': rowMouseover
'mouseout': rowMouseout
'dblclick': rowDblClick
callbackHeader: [callbackHeader]
callbackAttributes:
attributeName: [
callbackAttributes
]
dndCallback: =>
items = @el.find('table > tbody > tr')
console.log('all effected items', items)
renderTableGroupByRow: (object, position, groupByName) =>
App.view('generic/table_row_group_by')(
position: position
groupByName: groupByName
columnsLength: @columnsLength
)
new App.ControllerTable(
el: element
overview: ['time', 'area', 'level', 'browser', 'location', 'data']
attribute_list: [
{ name: 'time', display: 'Time', tag: 'datetime' },
{ name: 'area', display: 'Area', type: 'text' },
{ name: 'level', display: 'Level', type: 'text' },
{ name: 'browser', display: 'Browser', type: 'text' },
{ name: 'location', display: 'Location', type: 'text' },
{ name: 'data', display: 'Data', type: 'text' },
]
objects: data
renderTableRow: (object, position) =>
App.view('generic/table_row')(
headers: @headers
attributes: @attributesList
checkbox: @checkbox
radio: @radio
callbacks: @callbackAttributes
sortable: @dndCallback
position: position
object: object
)
###
tableHeadersHasChanged: =>
return true if @overviewAttributes isnt @lastOverview
false
tableGen: =>
if !@model
@model = {}
overview = @overview || @model.configure_overview || []
attributes = @attribute_list || @model.configure_attributes || {}
attributes = App.Model.attributesGet(false, attributes)
destroy = @model.configure_delete
tableHeaders: =>
orderBy = @customOrderBy || @orderBy
orderDirection = @customOrderDirection || @orderDirection
# check if table is empty
if _.isEmpty(@objects)
table = App.view('generic/admin/empty')(
explanation: @explanation
)
return $(table)
#console.log('LLL', @lastOrderBy, @orderBy, @lastOrderDirection, @orderDirection, @overviewAttributes, @lastOverview)
if @headers && @lastOrderBy is orderBy && @lastOrderDirection is orderDirection && !@tableHeadersHasChanged()
console.log('tableHeaders: same overviewAttributes just return headers', @headers)
return ['headers are the same', @headers]
@lastOverview = @overviewAttributes
# get header data
@headers = []
for item in overview
for item in @overviewAttributes
headerFound = false
for attributeName, attribute of attributes
for attributeName, attribute of @attributesList
# remove group by attribute from header
if !@groupBy || @groupBy isnt item
@ -208,8 +499,19 @@ class App.ControllerTable extends App.Controller
attribute.displayWidth = value
@headers.push attribute
# execute header callback
if @callbackHeader
for callback in @callbackHeader
@headers = callback(@headers)
if @tableId
@calculateHeaderWidths()
throw 'no headers found' if _.isEmpty(@headers)
# add destroy header and col binding
if destroy
if @destroy
@headers.push
name: 'destroy'
display: 'Delete'
@ -219,14 +521,63 @@ class App.ControllerTable extends App.Controller
parentClass: 'js-delete'
icon: 'trash'
if !@bindCol
@bindCol = {}
@bindCol['destroy'] =
events:
click: @deleteRow
if @orderDirection && @orderBy && !@groupBy
@objects = @sortList(@objects)
@columnsLength = @headers.length
if @checkbox || @radio
@columnsLength++
console.log('tableHeaders: new headers', @headers)
['new headers', @headers]
sortList: =>
return if _.isEmpty(@objects)
orderBy = @customOrderBy || @orderBy
orderDirection = @customOrderDirection || @orderDirection
console.log('order', @orderBy, @orderDirection)
console.log('customOrder', @customOrderBy, @customOrderDirection)
return if _.isEmpty(orderBy) && _.isEmpty(@groupBy)
return if @lastSortedobjects is @objects && @lastOrderDirection is orderDirection && @lastOrderBy is orderBy
@lastOrderDirection = orderDirection
@lastOrderBy = orderBy
if orderBy
for header in @headers
if header.name is orderBy || "#{header.name}_id" is orderBy# || header.name.substring(0, header.name.length - 3) is orderBy
localObjects = _.sortBy(
@objects
(item) ->
# if we need to sort translated col.
if header.translate
return App.i18n.translateInline(item[header.name])
# if we need to sort by relation name
if header.relation
if item[header.name]
localItem = App[header.relation].findNative(item[header.name])
if localItem
if localItem.displayName
localItem = localItem.displayName().toLowerCase()
if localItem.name
localItem = localItem.name.toLowerCase()
return localItem
return ''
item[header.name]
)
if orderDirection is 'DESC'
header.sortOrderIcon = ['arrow-down', 'table-sort-arrow']
localObjects = localObjects.reverse()
else
header.sortOrderIcon = ['arrow-up', 'table-sort-arrow']
else
header.sortOrderIcon = undefined
@objects = localObjects
# group by
if @groupBy
@ -237,14 +588,19 @@ class App.ControllerTable extends App.Controller
group = object[@groupBy]
if !group
withId = "#{@groupBy}_id"
if object[withId] && attributes[withId] && attributes[withId].relation
if App[attributes[withId].relation].exists(object[withId])
item = App[attributes[withId].relation].findNative(object[withId])
if object[withId] && @attributesList[withId] && @attributesList[withId].relation
if App[@attributesList[withId].relation].exists(object[withId])
item = App[@attributesList[withId].relation].findNative(object[withId])
if item && item.displayName
group = item.displayName().toLowerCase()
else if item.name
group = item.name.toLowerCase()
if _.isEmpty(group)
group = ''
if group.displayName
group = group.displayName().toLowerCase()
else if group.name
group = group.name.toLowerCase()
groupObjects[group] ||= []
groupObjects[group].push object
@ -254,198 +610,15 @@ class App.ControllerTable extends App.Controller
groupsSorted = groupsSorted.sort()
# get new order
@objects = []
localObjects = []
for group in groupsSorted
localObjects = @sortList(groupObjects[group])
@objects = @objects.concat localObjects
localObjects = localObjects.concat groupObjects[group]
groupObjects[group] = [] # release old array
# execute header callback
if @callbackHeader
for callback in @callbackHeader
@headers = callback(@headers)
@objects = localObjects
@lastSortedobjects = localObjects
if @tableId
@calculateHeaderWidths()
# generate content
position = 0
columnsLength = @headers.length
if @checkbox || @radio
columnsLength++
groupLast = ''
tableBody = ''
for object in @objects
if @groupBy
groupByName = App.viewPrint(object, @groupBy, attributes)
if groupLast isnt groupByName
groupLast = groupByName
tableBody += App.view('generic/table_row_group_by')(
position: position
groupByName: groupByName
columnsLength: columnsLength
)
position++
tableBody += App.view('generic/table_row')(
headers: @headers
attributes: attributes
checkbox: @checkbox
radio: @radio
callbacks: @callbackAttributes
sortable: @dndCallback
position: position
object: object
)
# generate full table
table = App.view('generic/table')(
tableId: @tableId
headers: @headers
checkbox: @checkbox
radio: @radio
class: @class
sortable: @dndCallback
tableBody: tableBody
)
# convert to jquery object
table = $(table)
cursorMap =
click: 'pointer'
dblclick: 'pointer'
#mouseover: 'alias'
# bind col.
if @bindCol
for name, item of @bindCol
if item.events
position = 0
if @dndCallback
position += 1
if @checkbox
position += 1
hit = false
for headerName in @headers
if !hit
position += 1
if headerName.name is name || headerName.name is "#{name}_id" || headerName.name is "#{name}_ids"
hit = true
if hit
for event, callback of item.events
do (table, event, callback) ->
if cursorMap[event]
table.find("tbody > tr > td:nth-child(#{position})").css('cursor', cursorMap[event])
table.on( event, "tbody > tr > td:nth-child(#{position})",
(e) ->
e.stopPropagation()
id = $(e.target).parents('tr').data('id')
callback(id, e)
)
# bind row
if @bindRow
if @bindRow.events
for event, callback of @bindRow.events
do (table, event, callback) ->
if cursorMap[event]
table.find('tbody > tr').css( 'cursor', cursorMap[event] )
table.on( event, 'tbody > tr',
(e) ->
id = $(e.target).parents('tr').data('id')
callback(id, e)
)
# bind bindCheckbox
if @bindCheckbox
if @bindCheckbox.events
for event, callback of @bindCheckbox.events
do (table, event, callback) ->
table.delegate('input[name="bulk"]', event, (e) ->
e.stopPropagation()
id = $(e.currentTarget).parents('tr').data('id')
checked = $(e.currentTarget).prop('checked')
callback(id, checked, e)
)
# if we have a personalised table
if @tableId
# enable resize column
table.on 'mousedown', '.js-col-resize', @onColResizeMousedown
table.on 'click', '.js-col-resize', @stopPropagation
# enable sort column
table.on 'click', '.js-sort', @sortByColumn
# enable checkbox bulk selection
if @checkbox
# click first tr>td, catch click
table.delegate('tr > td:nth-child(1)', 'click', (e) ->
e.stopPropagation()
)
# bind on full bulk click
table.delegate('input[name="bulk_all"]', 'change', (e) =>
e.stopPropagation()
clicks = []
if $(e.currentTarget).prop('checked')
$(e.currentTarget).parents('table').find('[name="bulk"]').each( ->
$element = $(@)
return if $element.prop('checked')
$element.prop('checked', true)
id = $element.parents('tr').data('id')
clicks.push [id, true]
)
else
$(e.currentTarget).parents('table').find('[name="bulk"]').each( ->
$element = $(@)
return if !$element.prop('checked')
$element.prop('checked', false)
id = $element.parents('tr').data('id')
clicks.push [id, false]
)
return if !@bindCheckbox
return if !@bindCheckbox.events
return if _.isEmpty(clicks)
for event, callback of @bindCheckbox.events
if event == 'click' || event == 'change'
for click in clicks
callback(click..., e)
)
table
sortList: (objects) =>
for header in @headers
if header.name is @orderBy
objects = _.sortBy(
objects
(item) ->
# if we need to sort translated col.
if header.translate
return App.i18n.translateInline(item[header.name])
# if we need to sort by relation name
if header.relation
if item[header.name]
localItem = App[header.relation].findNative(item[header.name])
if localItem && localItem.displayName
localItem = localItem.displayName().toLowerCase()
return localItem
return ''
item[header.name]
)
if @orderDirection is 'DESC'
header.sortOrderIcon = ['arrow-down', 'table-sort-arrow']
objects = objects.reverse()
else
header.sortOrderIcon = ['arrow-up', 'table-sort-arrow']
else
header.sortOrderIcon = undefined
objects
localObjects
# bind on delete dialog
deleteRow: (id, e) =>
@ -559,30 +732,43 @@ class App.ControllerTable extends App.Controller
# update store and runtime @headerWidth
@preferencesStore('headerWidth', leftColumnKey, leftWidth)
@headerWidth[leftColumnKey] = leftWidth
_.find(@headers, (column) -> column.name is leftColumnKey).displayWidth = leftWidth
# update store and runtime @headerWidth
if rightColumnKey
@preferencesStore('headerWidth', rightColumnKey, rightWidth)
@headerWidth[rightColumnKey] = rightWidth
_.find(@headers, (column) -> column.name is rightColumnKey).displayWidth = rightWidth
sortByColumn: (event) =>
column = $(event.currentTarget).closest('[data-column-key]').attr('data-column-key')
orderBy = @customOrderBy || @orderBy
orderDirection = @customOrderDirection || @orderDirection
# sort, update runtime @orderBy and @orderDirection
if @orderBy isnt column
@orderBy = column
@orderDirection = 'ASC'
if orderBy isnt column
orderBy = column
orderDirection = 'ASC'
else
if @orderDirection is 'ASC'
@orderDirection = 'DESC'
if orderDirection is 'ASC'
orderDirection = 'DESC'
else
@orderDirection = 'ASC'
orderDirection = 'ASC'
@orderBy = orderBy
@orderDirection = orderDirection
@customOrderBy = orderBy
@customOrderDirection = orderDirection
# update store
@preferencesStore('order', 'orderBy', @orderBy)
@preferencesStore('order', 'orderDirection', @orderDirection)
@render()
@preferencesStore('order', 'customOrderBy', @orderBy)
@preferencesStore('order', 'customOrderDirection', @orderDirection)
render = =>
@renderTableFull()
App.QueueManager.add('tableRender', render)
App.QueueManager.run('tableRender')
preferencesStore: (type, key, value) ->
data = @preferencesGet()
@ -601,3 +787,25 @@ class App.ControllerTable extends App.Controller
preferencesStoreKey: =>
"tablePrefs:#{@tableId}"
getBulkSelected: =>
ids = []
@$('[name="bulk"]:checked').each( (index, element) ->
id = $(element).val()
ids.push id
)
ids
setBulkSelected: (ids) ->
@$('[name="bulk"]').each( (index, element) ->
id = $(element).val()
for idSelected in ids
if idSelected is id
$(element).prop('checked', true)
)
_isSame: (array1, array2) ->
for position in [0..array1.length-1]
if array1[position] isnt array2[position]
return position
true

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -812,3 +812,29 @@ set new attributes of model (remove already available attributes)
item: item
processData: true
)
@clearInMemory: ->
return if !@className
# reset attributes to prevent cached forms on relogin
if !_.isEmpty(App[@className].org_configure_attributes)
App[@className].configure_attributes = App[@className].org_configure_attributes
# reset cached values of model
App[@className].deleteAll()
@updateAttributes: (attributes) ->
return if !@className
if _.isEmpty(@org_configure_attributes)
@org_configure_attributes = clone(@configure_attributes)
for attribute in attributes
@attributes.push attribute.name
@configure_attributes.push attribute
@resetAttributes: ->
return if _.isEmpty(@org_configure_attributes)
@configure_attributes = @org_configure_attributes
@resetCallbacks: ->
@SUBSCRIPTION_ITEM = {}
@SUBSCRIPTION_COLLECTION = {}

View file

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

View file

@ -20,9 +20,7 @@
<% 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 %>">
<div class="table-column-head<%= ' js-sort' if @tableId %>">
<div class="table-column-title">
<%- @T(header.display) %>
</div>
<div class="table-column-title"><%- @T(header.display) %></div>
<div class="table-column-sortIcon">
<% if header.sortOrderIcon: %>
<%- @Icon(header.sortOrderIcon[0], header.sortOrderIcon[1]) %>
@ -36,5 +34,5 @@
<% end %>
</tr>
</thead>
<tbody><%- @tableBody %></tbody>
<tbody class="js-tableBody"><%- @tableBody %></tbody>
</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: %>
<td class="table-draggable"><%- @Icon('draggable') %></td>
<% end %>

View file

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

View file

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

View file

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

View file

@ -55,7 +55,7 @@ returns
}
ignored_attributes = self.class.instance_variable_get(:@search_index_attributes_ignored) || []
return attributes if ignored_attributes.empty?
return attributes if ignored_attributes.blank?
ignored_attributes.each { |attribute|
attributes.delete(attribute.to_s)

View file

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

View file

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

View file

@ -18,7 +18,8 @@ class Channel::Filter::MonitoringBase
sender = Setting.get("#{integration}_sender")
auto_close = Setting.get("#{integration}_auto_close")
auto_close_state_id = Setting.get("#{integration}_auto_close_state_id")
state_recovery_match = '(OK|UP)'
state_ignore_match = Setting.get("#{integration}_ignore_match") || ''
state_recovery_match = Setting.get("#{integration}_recovery_match") || '(OK|UP)'
return if mail[:from].blank?
return if mail[:body].blank?
@ -26,7 +27,7 @@ class Channel::Filter::MonitoringBase
return if !session_user_id
# check if sender is monitoring
return if !mail[:from].match(/#{Regexp.quote(sender)}/i)
return if !Channel::Filter::Database.match(mail[:from], sender, true, true)
# get mail attibutes like host and state
result = {}
@ -91,5 +92,18 @@ class Channel::Filter::MonitoringBase
mail[ 'x-zammad-ticket-preferences'.to_sym ][key] = value
}
end
# ignorte states
if state_ignore_match.present? && result['state'].present? && result['state'].match(/#{state_ignore_match}/i)
mail[ 'x-zammad-ignore'.to_sym ] = true
return true
end
# if now problem exists, just ignore the email
if result['state'].present? && result['state'].match(/#{state_recovery_match}/i)
mail[ 'x-zammad-ignore'.to_sym ] = true
return true
end
end
end

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -19,6 +19,6 @@ class Observer::Ticket::StatsReopen < ActiveRecord::Observer
# return if we run import mode
return if Setting.get('import_mode')
Stats::TicketReopen.log('Ticket', record.id, record.changes, record.updated_by_id)
Stats::TicketReopen.log('Ticket', record.id, record.saved_changes, record.updated_by_id)
end
end

View file

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

View file

@ -22,7 +22,7 @@ class Observer::User::RefObjectTouch < ActiveRecord::Observer
# touch old organization if changed
member_ids = []
organization_id_changed = record.changes['organization_id']
organization_id_changed = record.saved_changes['organization_id']
if organization_id_changed && organization_id_changed[0] != organization_id_changed[1]
if organization_id_changed[0]

View file

@ -15,7 +15,7 @@ class Observer::User::TicketOrganization < ActiveRecord::Observer
def check_organization(record)
# check if organization has changed
return if !record.changes['organization_id']
return true if !record.saved_change_to_attribute?('organization_id')
# update last 100 tickets of user
tickets = Ticket.where(customer_id: record.id).limit(100)

View file

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

View file

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

View file

@ -1160,7 +1160,7 @@ result
def reset_pending_time
# ignore if no state has changed
return true if !changes['state_id']
return true if !changes_to_save['state_id']
# ignore if new state is blank and
# let handle ActiveRecord the error

View file

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

View file

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

View file

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

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_searchable_select', to: 'tests#form_searchable_select', via: :get
match '/tests_table', to: 'tests#table', via: :get
match '/tests_table_extended', to: 'tests#table_extended', via: :get
match '/tests_html_utils', to: 'tests#html_utils', via: :get
match '/tests_ticket_selector', to: 'tests#ticket_selector', via: :get
match '/tests_taskbar', to: 'tests#taskbar', via: :get

View file

@ -5,7 +5,3 @@ set -ex
rm app/assets/javascripts/app/controllers/layout_ref.coffee
rm -rf app/assets/javascripts/app/views/layout_ref/
rm app/assets/javascripts/app/controllers/karma.coffee
rm app/assets/javascripts/app/controllers/report.coffee
rm app/assets/javascripts/app/controllers/report_profile.coffee
rm app/assets/javascripts/app/controllers/_integration/check_mk.coffee
rm app/assets/javascripts/app/controllers/_integration/idoit.coffee

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,5 +1,5 @@
// form
test( "table test", function() {
test('table test', function() {
App.i18n.set('de-de')
$('#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 > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal( el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal( el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2')
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2')
$('#table').append('<hr><h1>table simple II</h1><div id="table2"></div>')
el = $('#table2')
@ -108,18 +108,18 @@ test( "table test", function() {
checkbox: false,
radio: false,
})
equal( el.find('table > thead > tr').length, 1, 'row count')
equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal( el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '2 normal', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'false', 'check row 1')
equal( el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '1 niedrig', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'true', 'check row 2')
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '2 normal', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'false', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '1 niedrig', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'true', 'check row 2')
$('#table').append('<hr><h1>table simple III</h1><div id="table3"></div>')
el = $('#table3')
@ -130,16 +130,16 @@ test( "table test", function() {
checkbox: false,
radio: false,
})
equal( el.find('table > thead > tr').length, 1, 'row count')
equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
notEqual( el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
notEqual( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal( el.find('tbody > tr:nth-child(2) > td').length, 1, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td').length, 1, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
notEqual( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '?', 'check row 2')
notEqual( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'true', 'check row 2')
equal( el.find('tbody > tr:nth-child(1) > td').length, 1, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td').length, 1, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1')
notEqual( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '?', 'check row 1')
notEqual( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'false', 'check row 1')
@ -236,60 +236,60 @@ test( "table test", function() {
objects: App.Ticket.search({sortBy:'created_at', order: 'DESC'}),
checkbox: true,
})
equal( el.find('table > thead > tr').length, 1, 'row count')
equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), '', 'check header')
equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), '#', 'check header')
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Titel', 'check header')
equal( el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Besitzer', 'check header')
equal( el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Kunde', 'check header')
equal( el.find('table > thead > tr > th:nth-child(6)').text().trim(), 'Priorität', 'check header')
equal( el.find('table > thead > tr > th:nth-child(7)').text().trim(), 'Gruppe', 'check header')
equal( el.find('table > thead > tr > th:nth-child(8)').text().trim(), 'Status', 'check header')
equal( el.find('table > thead > tr > th:nth-child(9)').text().trim(), 'Erstellt am', 'check header')
equal( el.find('tbody > tr:nth-child(1) > td').length, 9, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').val(), '3', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').prop('checked'), '', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), '', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '4713', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'some title 3', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'firstname56 lastname56', 'check row 2')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(5)').text().trim(), '-', 'check row 2')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(6)').text().trim(), '2 normal', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(7)').text().trim(), 'group 2', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(8)').text().trim(), 'neu', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(9)').text().trim(), '11.07.2014', 'check row 1')
equal( el.find('tbody > tr:nth-child(2) > td').length, 9, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), '', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '4712', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'some title 2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), '-', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '-', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(7)').text().trim(), 'group 1', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), 'offen', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 2')
equal( el.find('tbody > tr:nth-child(3) > td').length, 9, 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').val(), '1', 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').prop('checked'), '', 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1)').text().trim(), '', 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '4711', 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(3)').text().trim(), 'some title 1', 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(4)').text().trim(), 'firstname55 lastname55', 'check row 2')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(5)').text().trim(), 'firstname56 lastname56', 'check row 2')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(7)').text().trim(), 'group 2', 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(8)').text().trim(), 'neu', 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 3')
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), '', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), '#', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Titel', 'check header')
equal(el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Besitzer', 'check header')
equal(el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Kunde', 'check header')
equal(el.find('table > thead > tr > th:nth-child(6)').text().trim(), 'Priorität', 'check header')
equal(el.find('table > thead > tr > th:nth-child(7)').text().trim(), 'Gruppe', 'check header')
equal(el.find('table > thead > tr > th:nth-child(8)').text().trim(), 'Status', 'check header')
equal(el.find('table > thead > tr > th:nth-child(9)').text().trim(), 'Erstellt am', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 9, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').val(), '3', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').prop('checked'), '', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), '', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '4713', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'some title 3', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'firstname56 lastname56', 'check row 2')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(5)').text().trim(), '-', 'check row 2')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(6)').text().trim(), '2 normal', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(7)').text().trim(), 'group 2', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(8)').text().trim(), 'neu', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(9)').text().trim(), '11.07.2014', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 9, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), '', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '4712', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'some title 2', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), '-', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '-', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(7)').text().trim(), 'group 1', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), 'offen', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td').length, 9, 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').val(), '1', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').prop('checked'), '', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1)').text().trim(), '', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '4711', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(3)').text().trim(), 'some title 1', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(4)').text().trim(), 'firstname55 lastname55', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(5)').text().trim(), 'firstname56 lastname56', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(7)').text().trim(), 'group 2', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(8)').text().trim(), 'neu', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(9)').text().trim(), '10.06.2014', 'check row 3')
el.find('input[name="bulk_all"]').click()
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').prop('checked'), true, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').val(), '3', 'check row 1')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), true, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').prop('checked'), true, 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').val(), '1', 'check row 3')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').prop('checked'), true, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1) input').val(), '3', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), true, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').prop('checked'), true, 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1) input').val(), '1', 'check row 3')
$('#table').append('<hr><h1>table complex II</h1><div id="table5"></div>')
el = $('#table5')
@ -309,55 +309,55 @@ test( "table test", function() {
}
},
})
equal( el.find('table > thead > tr').length, 1, 'row count')
equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), '', 'check header')
equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), '#', 'check header')
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Titel', 'check header')
equal( el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Besitzer', 'check header')
equal( el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Kunde', 'check header')
equal( el.find('table > thead > tr > th:nth-child(6)').text().trim(), 'Priorität', 'check header')
equal( el.find('table > thead > tr > th:nth-child(7)').text().trim(), 'Status', 'check header')
equal( el.find('table > thead > tr > th:nth-child(8)').text().trim(), 'Erstellt am', 'check header')
equal( el.find('tbody > tr:nth-child(1) > td').length, 1, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'group 1', 'check row 1')
equal( el.find('tbody > tr:nth-child(2) > td').length, 8, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), '', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '4712', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'some title 2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), '-', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '-', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(7)').text().trim(), 'offen', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), '10.06.2014', 'check row 2')
equal( el.find('tbody > tr:nth-child(3) > td').length, 1, 'check row 3')
equal( el.find('tbody > tr:nth-child(3) > td:nth-child(1)').text().trim(), 'group 2', 'check row 4')
equal( el.find('tbody > tr:nth-child(4) > td').length, 8, 'check row 4')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').val(), '3', 'check row 4')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').prop('checked'), '', 'check row 4')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(1)').text().trim(), '', 'check row 4')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(2)').text().trim(), '4713', 'check row 4')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(3)').text().trim(), 'some title 3', 'check row 4')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(4)').text().trim(), 'firstname56 lastname56', 'check row 2')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(5)').text().trim(), '-', 'check row 2')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(6)').text().trim(), '2 normal', 'check row 4')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(7)').text().trim(), 'neu', 'check row 4')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(8)').text().trim(), '11.07.2014', 'check row 4')
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), '', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), '#', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Titel', 'check header')
equal(el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Besitzer', 'check header')
equal(el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Kunde', 'check header')
equal(el.find('table > thead > tr > th:nth-child(6)').text().trim(), 'Priorität', 'check header')
equal(el.find('table > thead > tr > th:nth-child(7)').text().trim(), 'Status', 'check header')
equal(el.find('table > thead > tr > th:nth-child(8)').text().trim(), 'Erstellt am', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 1, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'group 1', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 8, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), '', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '4712', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'some title 2', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), '-', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '-', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(6)').text().trim(), '1 niedrig', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(7)').text().trim(), 'offen', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(8)').text().trim(), '10.06.2014', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td').length, 1, 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(1)').text().trim(), 'group 2', 'check row 4')
equal(el.find('tbody > tr:nth-child(4) > td').length, 8, 'check row 4')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').val(), '3', 'check row 4')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').prop('checked'), '', 'check row 4')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(1)').text().trim(), '', 'check row 4')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(2)').text().trim(), '4713', 'check row 4')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(3)').text().trim(), 'some title 3', 'check row 4')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(4)').text().trim(), 'firstname56 lastname56', 'check row 2')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(5)').text().trim(), '-', 'check row 2')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(6)').text().trim(), '2 normal', 'check row 4')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(7)').text().trim(), 'neu', 'check row 4')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(8)').text().trim(), '11.07.2014', 'check row 4')
el.find('input[name="bulk"]:eq(1)').click()
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 1')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').prop('checked'), true, 'check row 4')
equal( el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').val(), '3', 'check row 4')
equal( el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').prop('checked'), '', 'check row 5')
equal( el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').val(), '1', 'check row 5')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').prop('checked'), '', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1) input').val(), '2', 'check row 1')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').prop('checked'), true, 'check row 4')
equal(el.find('tbody > tr:nth-child(4) > td:nth-child(1) input').val(), '3', 'check row 4')
equal(el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').prop('checked'), '', 'check row 5')
equal(el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').val(), '1', 'check row 5')
el.find('tbody > tr:nth-child(5) > td:nth-child(1) label').click()
equal( el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').prop('checked'), true, 'check row 5')
equal( el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').val(), '1', 'check row 5')
equal(el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').prop('checked'), true, 'check row 5')
equal(el.find('tbody > tr:nth-child(5) > td:nth-child(1) input').val(), '1', 'check row 5')
});
test( "table test 2", function() {
test('table test 2', function() {
App.i18n.set('de-de')
$('#table').append('<hr><h1>table with hash</h1><div id="table-hash1"></div>')
@ -413,27 +413,27 @@ test( "table test 2", function() {
model: App.Channel,
objects: App.Channel.search({sortBy:'adapter', order: 'ASC'}),
})
equal( el.find('table > thead > tr').length, 1, 'row count')
equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Typ', 'check header')
equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Host', 'check header')
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Benutzer', 'check header')
equal( el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Aktiv', 'check header')
equal( el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Löschen', 'check header')
equal( el.find('tbody > tr:nth-child(1) > td').length, 5, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'adapter1', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'host1', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'user1', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'ja', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(5)').text().trim(), '', 'check row 1')
equal( el.find('tbody > tr:nth-child(2) > td').length, 5, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), 'adapter2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'host2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'user2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), 'ja', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '', 'check row 2')
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Typ', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Host', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Benutzer', 'check header')
equal(el.find('table > thead > tr > th:nth-child(4)').text().trim(), 'Aktiv', 'check header')
equal(el.find('table > thead > tr > th:nth-child(5)').text().trim(), 'Löschen', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 5, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'adapter1', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'host1', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'user1', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(4)').text().trim(), 'ja', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(5)').text().trim(), '', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 5, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), 'adapter2', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'host2', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'user2', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(4)').text().trim(), 'ja', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(5)').text().trim(), '', 'check row 2')
});
test( "table test 3", function() {
test('table test 3', function() {
App.i18n.set('de-de')
$('#table').append('<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 > th:nth-child(1)').text().trim(), 'richtiger Name', 'check header')
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Some Name', 'check header')
equal( el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'realname 55', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'email 55', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), '', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').hasClass('glyphicon-user'), true, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').hasClass('glyphicon'), true, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').attr('title'), 'Umschalten zu', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').data('some'), 'value55', 'check row 2')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').data('xxx'), '55', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), 'realname 56', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'email 56', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), '', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').hasClass('glyphicon-user'), true, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').hasClass('glyphicon'), true, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').attr('title'), 'Umschalten zu', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').data('some'), 'value56', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').data('xxx'), '56', 'check row 2')
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'richtiger Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Some Name', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(1)').text().trim(), 'realname 55', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'email 55', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), '', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').hasClass('glyphicon-user'), true, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').hasClass('glyphicon'), true, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').attr('title'), 'Umschalten zu', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').data('some'), 'value55', 'check row 2')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3) > a > span').data('xxx'), '55', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(1)').text().trim(), 'realname 56', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'email 56', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), '', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').hasClass('glyphicon-user'), true, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').hasClass('glyphicon'), true, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').attr('title'), 'Umschalten zu', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').data('some'), 'value56', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3) > a > span').data('xxx'), '56', 'check row 2')
});
test( "table test 4", function() {
test('table test 4', function() {
App.i18n.set('de-de')
$('#table').append('<hr><h1>table with data</h1><div id="table-data1"></div>')
@ -554,16 +554,16 @@ test( "table test 4", function() {
objects: data
});
equal( el.find('table > thead > tr').length, 1, 'row count')
equal( el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal( el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Data', 'check header')
equal( el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal( el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:first').text().trim(), 'some name 1', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'some data 1', 'check row 1')
equal( el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal( el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:first').text().trim(), 'some name 2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'some data 2', 'check row 2')
equal( el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2')
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Data', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), 'some name 1', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), 'some data 1', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), 'some name 2', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), 'some data 2', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(3)').text().trim(), 'false', 'check row 2')
});

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

View file

@ -16,6 +16,12 @@ require 'daemons'
def before_fork
# clear all connections before for, reconnect later ActiveRecord::Base.connection.reconnect!
# issue #1405 - Scheduler not running because of Bad file descriptor in PGConsumeInput()
# https://github.com/zammad/zammad/issues/1405
# see also https://bitbucket.org/ged/ruby-pg/issues/260/frequent-crashes-with-multithreading
ActiveRecord::Base.clear_all_connections!
# remember open file handles
@files_to_reopen = []
ObjectSpace.each_object(File) do |file|

View file

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

View file

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

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

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

View file

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

View file

@ -446,7 +446,21 @@ class AssetsTest < ActiveSupport::TestCase
roles: roles,
)
calendar1 = Calendar.first
calendar1 = Calendar.create_or_update(
name: 'US 1',
timezone: 'America/Los_Angeles',
business_hours: {
mon: { '09:00' => '17:00' },
tue: { '09:00' => '17:00' },
wed: { '09:00' => '17:00' },
thu: { '09:00' => '17:00' },
fri: { '09:00' => '17:00' }
},
default: true,
ical_url: nil,
updated_by_id: 1,
created_by_id: 1,
)
ticket_state1 = Ticket::State.find_by(name: 'new')
ticket_state2 = Ticket::State.find_by(name: 'open')
sla = Sla.create_or_update(

View file

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

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#service-states
test 'base tests' do
setup do
Setting.set('icinga_integration', true)
Setting.set('icinga_sender', 'icinga2@monitoring.example.com')
end
# not matching sender
email_raw_string = "To: support@example.com
Subject: PROBLEM - host.internal.loc - CPU Load is WARNING
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-1-0@monitoring.znuny.com>
From: icinga_not_matching@monitoring.example.com (icinga)
***** Icinga *****
Notification Type: PROBLEM
Service: CPU Load
Host: host.internal.loc
Address:=20
State: WARNING
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info: WARNING - load average: 3.44, 0.99, 0.35
Comment: [] =
"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_p.state.name)
assert(ticket_p.preferences)
assert_not(ticket_p.preferences['icinga'])
test 'base tests' do
# RBL check
email_raw_string = "To: support@example.com
@ -51,7 +23,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-1-1@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga)
From: icinga2@monitoring.example.com (icinga)
***** Icinga 2 Service Monitoring on apn4711.dc.example.com *****
@ -82,7 +54,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-1-2@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga)
From: icinga2@monitoring.example.com (icinga)
***** Icinga 2 Service Monitoring on apn4711.dc.example.com *****
@ -113,7 +85,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-1-2@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga)
From: icinga2@monitoring.example.com (icinga)
***** Icinga 2 Service Monitoring on apn4711.dc.example.com *****
@ -145,7 +117,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-2@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga)
From: icinga2@monitoring.example.com (icinga)
***** Icinga *****
@ -179,7 +151,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-3@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga)
From: icinga2@monitoring.example.com (icinga)
***** Icinga *****
@ -214,7 +186,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-4@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga)
From: icinga2@monitoring.example.com (icinga)
***** Icinga *****
@ -249,7 +221,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga)
From: icinga2@monitoring.example.com (icinga)
***** Icinga *****
@ -284,7 +256,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga)
From: icinga2@monitoring.example.com (icinga)
***** Icinga *****
@ -317,7 +289,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com>
From: icinga@monitoring.example.com (icinga)
From: icinga2@monitoring.example.com (icinga)
***** Icinga *****
@ -341,9 +313,246 @@ Comment: [] =
assert_equal('apn4711.dc.example.com', ticket_3.preferences['icinga']['host'])
assert_nil(ticket_3_1.preferences['icinga']['service'])
assert_equal('DOWN', ticket_3_1.preferences['icinga']['state'])
end
#Setting.set('icinga_integration', false)
test 'not matching sender tests' do
# not matching sender
email_raw_string = "To: support@example.com
Subject: PROBLEM - host.internal.loc - CPU Load is WARNING
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-1-0@monitoring.znuny.com>
From: icinga_not_matching@monitoring.example.com (icinga)
***** Icinga *****
Notification Type: PROBLEM
Service: CPU Load
Host: host.internal.loc
Address:=20
State: WARNING
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info: WARNING - load average: 3.44, 0.99, 0.35
Comment: [] =
"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_p.state.name)
assert(ticket_p.preferences)
assert_not(ticket_p.preferences['icinga'])
Setting.set('icinga_sender', 'regex:icinga2@monitoring.example.com')
# not matching sender
email_raw_string = "To: support@example.com
Subject: PROBLEM - host.internal.loc - CPU Load is WARNING
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-1-0@monitoring.znuny.com>
From: icinga_not_matching@monitoring.example.com (icinga)
***** Icinga *****
Notification Type: PROBLEM
Service: CPU Load
Host: host.internal.loc
Address:=20
State: WARNING
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info: WARNING - load average: 3.44, 0.99, 0.35
Comment: [] =
"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_p.state.name)
assert(ticket_p.preferences)
assert_not(ticket_p.preferences['icinga'])
# not matching sender
email_raw_string = "To: support@example.com
Subject: PROBLEM - host.internal.loc - CPU Load is WARNING
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-1-0@monitoring.znuny.com>
Return-Path: bob@example.com
***** Icinga *****
Notification Type: PROBLEM
Service: CPU Load
Host: host.internal.loc
Address:=20
State: WARNING
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info: WARNING - load average: 3.44, 0.99, 0.35
Comment: [] =
"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_p.state.name)
assert(ticket_p.preferences)
assert_not(ticket_p.preferences['icinga'])
end
test 'matching sender tests' do
# matching sender - follow up - CPU Load/host.internal.loc
email_raw_string = "To: support@example.com
Subject: PROBLEM - host.internal.loc - CPU Load is WARNING
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-4@monitoring.znuny.com>
From: icinga2@monitoring.example.com (icinga)
***** Icinga *****
Notification Type: PROBLEM
Service: CPU Load
Host: host.internal.loc
Address:=20
State: WARNING
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info: WARNING - load average: 3.44, 0.99, 0.35
Comment: [] =
"
ticket_1_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_1_1.state.name)
assert(ticket_1_1.preferences)
assert(ticket_1_1.preferences['icinga'])
assert_equal('host.internal.loc', ticket_1_1.preferences['icinga']['host'])
assert_equal('CPU Load', ticket_1_1.preferences['icinga']['service'])
assert_equal('WARNING', ticket_1_1.preferences['icinga']['state'])
Setting.set('icinga_sender', 'regex:icinga2@monitoring.example.com')
# matching sender I
email_raw_string = "To: support@example.com
Subject: PROBLEM - host1.internal.loc - CPU Load is WARNING
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-4@monitoring.znuny.com>
From: icinga2@monitoring.example.com (icinga)
***** Icinga *****
Notification Type: PROBLEM
Service: CPU Load
Host: host1.internal.loc
Address:=20
State: WARNING
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info: WARNING - load average: 3.44, 0.99, 0.35
Comment: [] =
"
ticket_1_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_1_1.state.name)
assert(ticket_1_1.preferences)
assert(ticket_1_1.preferences['icinga'])
assert_equal('host1.internal.loc', ticket_1_1.preferences['icinga']['host'])
assert_equal('CPU Load', ticket_1_1.preferences['icinga']['service'])
assert_equal('WARNING', ticket_1_1.preferences['icinga']['state'])
# matching sender I
Setting.set('icinga_sender', 'regex:(icinga2|abc123)@monitoring.example.com')
email_raw_string = "To: support@example.com
Subject: PROBLEM - host2.internal.loc - CPU Load is WARNING
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-4@monitoring.znuny.com>
From: icinga2@monitoring.example.com (icinga)
***** Icinga *****
Notification Type: PROBLEM
Service: CPU Load
Host: host2.internal.loc
Address:=20
State: WARNING
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info: WARNING - load average: 3.44, 0.99, 0.35
Comment: [] =
"
ticket_1_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_1_1.state.name)
assert(ticket_1_1.preferences)
assert(ticket_1_1.preferences['icinga'])
assert_equal('host2.internal.loc', ticket_1_1.preferences['icinga']['host'])
assert_equal('CPU Load', ticket_1_1.preferences['icinga']['service'])
assert_equal('WARNING', ticket_1_1.preferences['icinga']['state'])
end
test 'recover without problem tests' do
# host up without problem
email_raw_string = "To: support@example.com
Subject: RECOVERY - apn4711.dc.example.com is UP
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-icinga-5@monitoring.znuny.com>
From: icinga2@monitoring.example.com (icinga)
***** Icinga *****
Notification Type: RECOVERY
Host: apn4711.dc.example.com
Address: 127.0.0.1
State: UP
Date/Time: 2017-01-14 12:07:11 +0100
Additional Info: PING OK - Packet loss = 0%, RTA = 21.37 ms
Comment: [] =
"
ticket_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket_count = Ticket.count
assert_not(ticket_1)
assert_equal(ticket_count, Ticket.count)
end
end

View file

@ -6,38 +6,12 @@ class IntegrationNagiosTest < ActiveSupport::TestCase
# according
# https://github.com/NagiosEnterprises/nagioscore/blob/754218e67653929a58938b99ef6b6039b6474fe4/sample-config/template-object/commands.cfg.in#L35
test 'base tests' do
setup do
Setting.set('nagios_integration', true)
Setting.set('nagios_sender', 'nagios2@monitoring.example.com')
end
# not matching sender
email_raw_string = "To: support@example.com
Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING **
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-1@monitoring.znuny.com>
From: nagios_not_matching@monitoring.example.com (nagios)
***** Nagios *****
Notification Type: PROBLEM
Service: CPU Load
Host: host.internal.loc
Address: 1.1.1.1
State: PROBLEM
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info:
WARNING - load average: 3.44, 0.99, 0.35
"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_p.state.name)
assert(ticket_p.preferences)
assert_not(ticket_p.preferences['nagios'])
test 'base tests' do
# matching sender - CPU Load/host.internal.loc
email_raw_string = "To: support@example.com
@ -46,7 +20,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-2@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios)
From: nagios2@monitoring.example.com (nagios)
***** Nagios *****
@ -78,7 +52,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-3@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios)
From: nagios2@monitoring.example.com (nagios)
***** Nagios *****
@ -111,7 +85,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-4@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios)
From: nagios2@monitoring.example.com (nagios)
***** Nagios *****
@ -144,7 +118,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios)
From: nagios2@monitoring.example.com (nagios)
***** Nagios *****
@ -176,7 +150,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios)
From: nagios2@monitoring.example.com (nagios)
***** Nagios *****
@ -209,7 +183,7 @@ MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com>
From: nagios@monitoring.example.com (nagios)
From: nagios2@monitoring.example.com (nagios)
***** Nagios *****
@ -238,4 +212,232 @@ Comment: [] =
end
test 'not matching sender tests' do
# not matching sender
email_raw_string = "To: support@example.com
Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING **
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-1@monitoring.znuny.com>
From: nagios_not_matching@monitoring.example.com (nagios)
***** Nagios *****
Notification Type: PROBLEM
Service: CPU Load
Host: host.internal.loc
Address: 1.1.1.1
State: PROBLEM
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info:
WARNING - load average: 3.44, 0.99, 0.35
"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_p.state.name)
assert(ticket_p.preferences)
assert_not(ticket_p.preferences['nagios'])
Setting.set('nagios_sender', 'regex:icinga2@monitoring.example.com')
# not matching sender
email_raw_string = "To: support@example.com
Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING **
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-1@monitoring.znuny.com>
From: nagios_not_matching@monitoring.example.com (nagios)
***** Nagios *****
Notification Type: PROBLEM
Service: CPU Load
Host: host.internal.loc
Address: 1.1.1.1
State: PROBLEM
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info:
WARNING - load average: 3.44, 0.99, 0.35
"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_p.state.name)
assert(ticket_p.preferences)
assert_not(ticket_p.preferences['nagios'])
# not matching sender
email_raw_string = "To: support@example.com
Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING **
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-1@monitoring.znuny.com>
Return-Path: bob@example.com
***** Nagios *****
Notification Type: PROBLEM
Service: CPU Load
Host: host.internal.loc
Address: 1.1.1.1
State: PROBLEM
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info:
WARNING - load average: 3.44, 0.99, 0.35
"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_p.state.name)
assert(ticket_p.preferences)
assert_not(ticket_p.preferences['nagios'])
end
test 'matching sender tests' do
# matching sender - follow up - CPU Load/host.internal.loc
email_raw_string = "To: support@example.com
Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING **
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-2@monitoring.znuny.com>
From: nagios2@monitoring.example.com (nagios)
***** Nagios *****
Notification Type: PROBLEM
Service: CPU Load
Host: host.internal.loc
Address: 1.1.1.1
State: WARNING
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info:
WARNING - load average: 3.44, 0.99, 0.35
"
ticket_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_1.state.name)
assert(ticket_1.preferences)
assert(ticket_1.preferences['nagios'])
assert_equal('host.internal.loc', ticket_1.preferences['nagios']['host'])
assert_equal('CPU Load', ticket_1.preferences['nagios']['service'])
assert_equal('WARNING', ticket_1.preferences['nagios']['state'])
Setting.set('icinga_sender', 'regex:icinga2@monitoring.example.com')
# matching sender I
email_raw_string = "To: support@example.com
Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING **
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-2@monitoring.znuny.com>
From: nagios2@monitoring.example.com (nagios)
***** Nagios *****
Notification Type: PROBLEM
Service: CPU Load
Host: host1.internal.loc
Address: 1.1.1.1
State: WARNING
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info:
WARNING - load average: 3.44, 0.99, 0.35
"
ticket_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_1.state.name)
assert(ticket_1.preferences)
assert(ticket_1.preferences['nagios'])
assert_equal('host1.internal.loc', ticket_1.preferences['nagios']['host'])
assert_equal('CPU Load', ticket_1.preferences['nagios']['service'])
assert_equal('WARNING', ticket_1.preferences['nagios']['state'])
# matching sender I
Setting.set('icinga_sender', 'regex:(icinga2|abc123)@monitoring.example.com')
email_raw_string = "To: support@example.com
Subject: ** PROBLEM Service Alert: host.internal.loc/CPU Load is WARNING **
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-2@monitoring.znuny.com>
From: nagios2@monitoring.example.com (nagios)
***** Nagios *****
Notification Type: PROBLEM
Service: CPU Load
Host: host2.internal.loc
Address: 1.1.1.1
State: WARNING
Date/Time: 2016-01-31 10:46:20 +0100
Additional Info:
WARNING - load average: 3.44, 0.99, 0.35
"
ticket_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal('new', ticket_1.state.name)
assert(ticket_1.preferences)
assert(ticket_1.preferences['nagios'])
assert_equal('host2.internal.loc', ticket_1.preferences['nagios']['host'])
assert_equal('CPU Load', ticket_1.preferences['nagios']['service'])
assert_equal('WARNING', ticket_1.preferences['nagios']['state'])
end
test 'recover without problem tests' do
# host up without problem
email_raw_string = "To: support@example.com
Subject: ** RECOVERY Host Alert: apn4711.dc.example.com is UP **
User-Agent: Heirloom mailx 12.5 7/5/10
MIME-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: quoted-printable
Message-Id: <20160131094621.29ECD400F29C-nagios-5@monitoring.znuny.com>
From: nagios2@monitoring.example.com (nagios)
***** Nagios *****
Notification Type: RECOVERY
Host: apn4711.dc.example.com
Address: 127.0.0.1
State: UP
Date/Time: 2017-01-14 12:07:11 +0100
Additional Info: PING OK - Packet loss = 0%, RTA = 21.37 ms
Comment: [] =
"
ticket_1, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket_count = Ticket.count
assert_not(ticket_1)
assert_equal(ticket_count, Ticket.count)
end
end

View file

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

View file

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

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.save!
p User.where(active: true, out_of_office: true, out_of_office_replacement_id: @agent2.id)
p User.where(active: true, out_of_office: true, out_of_office_replacement_id: @agent2.id).where('out_of_office_start_at <= ? AND out_of_office_end_at >= ?', Time.zone.today, Time.zone.today)
assert_equal(@agent2.out_of_office_agent_of.count, 1)
assert(@agent2.out_of_office_agent_of[0])
assert_equal(@agent2.out_of_office_agent_of[0].id, @agent1.id)

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.first_response_at.to_s, article_outbound.created_at.to_s, 'ticket.first_response_at verify - inbound')
assert_nil(ticket.close_at, 'ticket.close_at verify - inbound')
calendar1.destroy!
calendar2.destroy!
end
test 'ticket sla + selector' do
@ -605,6 +607,7 @@ class TicketSlaTest < ActiveSupport::TestCase
assert_nil(ticket.close_in_min, 'ticket.close_in_min')
assert_nil(ticket.close_diff_in_min, 'ticket.close_diff_in_min')
calendar1.destroy!
end
test 'ticket sla + timezone + holiday' do
@ -849,12 +852,13 @@ class TicketSlaTest < ActiveSupport::TestCase
assert_equal(ticket.update_escalation_at.gmtime.to_s, '2015-09-23 08:30:00 UTC', 'ticket.update_escalation_at verify 1')
assert_equal(ticket.close_escalation_at.gmtime.to_s, '2015-09-23 09:30:00 UTC', 'ticket.close_escalation_at verify 1')
delete = sla.destroy
delete = sla.destroy!
assert(delete, 'sla destroy')
delete = ticket.destroy
delete = ticket.destroy!
assert(delete, 'ticket destroy')
calendar.destroy!
end
test 'ticket escalation suspend close reopen bug' do
@ -1043,13 +1047,15 @@ class TicketSlaTest < ActiveSupport::TestCase
assert_nil(ticket2.first_response_in_min, 'ticket2.first_response_in_min verify 3')
assert_nil(ticket2.first_response_diff_in_min, 'ticket2.first_response_diff_in_min verify 3')
delete = sla.destroy
delete = sla.destroy!
assert(delete, 'sla destroy')
delete = ticket1.destroy
delete = ticket1.destroy!
assert(delete, 'ticket1 destroy')
delete = ticket2.destroy
delete = ticket2.destroy!
assert(delete, 'ticket2 destroy')
calendar.destroy!
end
test 'ticket escalation suspend' do
@ -1552,12 +1558,13 @@ class TicketSlaTest < ActiveSupport::TestCase
assert_equal(ticket.close_in_min, 60, 'ticket.close_in_min verify 3')
assert_equal(ticket.close_diff_in_min, 180, 'ticket.close_diff_in_min# verify 3')
delete = sla.destroy
delete = sla.destroy!
assert(delete, 'sla destroy')
delete = ticket.destroy
delete = ticket.destroy!
assert(delete, 'ticket destroy')
calendar.destroy!
end
test 'ticket ticket.title and article.subject' do
@ -1718,12 +1725,13 @@ class TicketSlaTest < ActiveSupport::TestCase
assert_nil(ticket.close_in_min, 'ticket.close_in_min verify 3')
assert_nil(ticket.close_diff_in_min, 'ticket.close_diff_in_min# verify 3')
delete = sla.destroy
delete = sla.destroy!
assert(delete, 'sla destroy')
delete = ticket.destroy
delete = ticket.destroy!
assert(delete, 'ticket destroy')
calendar.destroy!
end
test 'ticket sla + holiday 222' do
@ -1943,11 +1951,13 @@ class TicketSlaTest < ActiveSupport::TestCase
assert_equal(ticket.update_escalation_at.gmtime.to_s, '2016-11-09 10:26:36 UTC', 'ticket.update_escalation_at verify 1')
assert_nil(ticket.close_escalation_at, 'ticket.close_escalation_at verify 1')
delete = sla.destroy
delete = sla.destroy!
assert(delete, 'sla destroy')
delete = ticket.destroy
delete = ticket.destroy!
assert(delete, 'ticket destroy')
calendar.destroy!
end
test 'ticket sla + observer check' do
@ -2124,11 +2134,13 @@ class TicketSlaTest < ActiveSupport::TestCase
assert_equal(ticket.update_escalation_at.gmtime.to_s, '2016-11-07 15:26:36 UTC', 'ticket.update_escalation_at verify 1')
assert_nil(ticket.close_escalation_at, 'ticket.close_escalation_at verify 1')
delete = sla.destroy
delete = sla.destroy!
assert(delete, 'sla destroy')
delete = ticket.destroy
delete = ticket.destroy!
assert(delete, 'ticket destroy')
calendar.destroy!
end
end