Init version of scheduler.
This commit is contained in:
parent
32d404def9
commit
51d485670e
15 changed files with 687 additions and 159 deletions
|
@ -923,18 +923,286 @@ class App.ControllerForm extends App.Controller
|
|||
item.find( "[name=\"#{attribute.name}::count\"]").find("option[value=\"#{attribute.value.count}\"]").attr( 'selected', 'selected' )
|
||||
item.find( "[name=\"#{attribute.name}::area\"]").find("option[value=\"#{attribute.value.area}\"]").attr( 'selected', 'selected' )
|
||||
|
||||
# ticket attribute selection
|
||||
else if attribute.tag is 'ticket_attribute_selection'
|
||||
# ticket attribute set
|
||||
else if attribute.tag is 'ticket_attribute_set'
|
||||
|
||||
# list of possible attributes
|
||||
item = $(
|
||||
App.view('generic/ticket_attribute_selection')(
|
||||
App.view('generic/ticket_attribute_manage')(
|
||||
attribute: attribute
|
||||
)
|
||||
)
|
||||
|
||||
addShownAttribute = ( key, value ) =>
|
||||
parts = key.split(/::/)
|
||||
key = parts[0]
|
||||
type = parts[1]
|
||||
if key is 'tickets.title'
|
||||
attribute_config = {
|
||||
name: attribute.name + '::tickets.title'
|
||||
display: 'Title'
|
||||
tag: 'input'
|
||||
type: 'text'
|
||||
null: false
|
||||
value: value
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.group_id'
|
||||
attribute_config = {
|
||||
name: attribute.name + '::tickets.group_id'
|
||||
display: 'Group'
|
||||
tag: 'select'
|
||||
multiple: false
|
||||
null: false
|
||||
nulloption: false
|
||||
relation: 'Group'
|
||||
value: value
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.owner_id' || key is 'tickets.customer_id'
|
||||
display = 'Owner'
|
||||
name = 'owner_id'
|
||||
if key is 'customer_id'
|
||||
display = 'Customer'
|
||||
name = 'customer_id'
|
||||
attribute_config = {
|
||||
name: attribute.name + '::tickets.' + name
|
||||
display: display
|
||||
tag: 'select'
|
||||
multiple: false
|
||||
null: false
|
||||
nulloption: false
|
||||
relation: 'User'
|
||||
value: value || null
|
||||
remove: true
|
||||
filter: ( all, type ) ->
|
||||
return all if type isnt 'collection'
|
||||
all = _.filter( all, (item) ->
|
||||
return if item.id is 1
|
||||
return item
|
||||
)
|
||||
all.unshift( {
|
||||
id: ''
|
||||
name: '--'
|
||||
} )
|
||||
all.unshift( {
|
||||
id: 1
|
||||
name: '*** not set ***'
|
||||
} )
|
||||
all.unshift( {
|
||||
id: 'current_user.id'
|
||||
name: '*** current user ***'
|
||||
} )
|
||||
all
|
||||
}
|
||||
else if key is 'tickets.organization_id'
|
||||
attribute_config = {
|
||||
name: attribute.name + '::tickets.organization_id'
|
||||
display: 'Organization'
|
||||
tag: 'select'
|
||||
multiple: false
|
||||
null: false
|
||||
nulloption: false
|
||||
relation: 'Organization'
|
||||
value: value || null
|
||||
remove: true
|
||||
filter: ( all, type ) ->
|
||||
return all if type isnt 'collection'
|
||||
all.unshift( {
|
||||
id: ''
|
||||
name: '--'
|
||||
} )
|
||||
all.unshift( {
|
||||
id: 'current_user.organization_id'
|
||||
name: '*** organization of current user ***'
|
||||
} )
|
||||
all
|
||||
}
|
||||
else if key is 'tickets.state_id'
|
||||
attribute_config = {
|
||||
name: attribute.name + '::tickets.state_id'
|
||||
display: 'State'
|
||||
tag: 'select'
|
||||
multiple: false
|
||||
null: false
|
||||
nulloption: false
|
||||
relation: 'TicketState'
|
||||
value: value
|
||||
translate: true
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.priority_id'
|
||||
attribute_config = {
|
||||
name: attribute.name + '::tickets.priority_id'
|
||||
display: 'Priority'
|
||||
tag: 'select'
|
||||
multiple: false
|
||||
null: false
|
||||
nulloption: false
|
||||
relation: 'TicketPriority'
|
||||
value: value
|
||||
translate: true
|
||||
remove: true
|
||||
}
|
||||
else
|
||||
attribute_config = {
|
||||
name: attribute.name + '::' + key
|
||||
display: 'FIXME!'
|
||||
tag: 'input'
|
||||
type: 'text'
|
||||
value: value
|
||||
remove: true
|
||||
}
|
||||
item.find('select[name=ticket_attribute_list] option[value="' + key + '"]').hide().prop('disabled', true)
|
||||
|
||||
itemSub = @formGenItem( attribute_config )
|
||||
itemSub.find('.glyphicon-minus').bind('click', (e) ->
|
||||
e.preventDefault()
|
||||
value = $(e.target).closest('.controls').find('[name]').attr('name')
|
||||
if value
|
||||
value = value.replace("#{attribute.name}::", '')
|
||||
$(e.target).closest('.sub_attribute').find('select[name=ticket_attribute_list] option[value="' + value + '"]').show().prop('disabled', false)
|
||||
$(@).parent().parent().parent().remove()
|
||||
)
|
||||
# itemSub.append('<a href=\"#\" class=\"icon-minus\"></a>')
|
||||
item.find('.ticket_attribute_item').append( itemSub )
|
||||
|
||||
# list of existing attributes
|
||||
attribute_config = {
|
||||
name: 'ticket_attribute_list'
|
||||
display: 'Add Attribute'
|
||||
tag: 'select'
|
||||
multiple: false
|
||||
null: false
|
||||
# nulloption: true
|
||||
options: [
|
||||
{
|
||||
value: ''
|
||||
name: '-- Ticket --'
|
||||
selected: false
|
||||
disable: true
|
||||
},
|
||||
{
|
||||
value: 'tickets.title'
|
||||
name: 'Title'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'tickets.group_id'
|
||||
name: 'Group'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'tickets.state_id'
|
||||
name: 'State'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'tickets.priority_id'
|
||||
name: 'Priority'
|
||||
selected: true
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'tickets.owner_id'
|
||||
name: 'Owner'
|
||||
selected: true
|
||||
disable: false
|
||||
},
|
||||
# # {
|
||||
# value: 'tag'
|
||||
# name: 'Tag'
|
||||
# selected: true
|
||||
# disable: false
|
||||
# },
|
||||
# {
|
||||
# value: '-a'
|
||||
# name: '-- ' + App.i18n.translateInline('Article') + ' --'
|
||||
# selected: false
|
||||
# disable: true
|
||||
# },
|
||||
# {
|
||||
# value: 'ticket_articles.from'
|
||||
# name: 'From'
|
||||
# selected: true
|
||||
# disable: false
|
||||
# },
|
||||
# {
|
||||
# value: 'ticket_articles.to'
|
||||
# name: 'To'
|
||||
# selected: true
|
||||
# disable: false
|
||||
# },
|
||||
# {
|
||||
# value: 'ticket_articles.cc'
|
||||
# name: 'Cc'
|
||||
# selected: true
|
||||
# disable: false
|
||||
# },
|
||||
# {
|
||||
# value: 'ticket_articles.subject'
|
||||
# name: 'Subject'
|
||||
# selected: true
|
||||
# disable: false
|
||||
# },
|
||||
# {
|
||||
# value: 'ticket_articles.body'
|
||||
# name: 'Text'
|
||||
# selected: true
|
||||
# disable: false
|
||||
# },
|
||||
{
|
||||
value: '-c'
|
||||
name: '-- ' + App.i18n.translateInline('Customer') + ' --'
|
||||
selected: false
|
||||
disable: true
|
||||
},
|
||||
{
|
||||
value: 'customers.id'
|
||||
name: 'Customer'
|
||||
selected: true
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'organization.id'
|
||||
name: 'Organization'
|
||||
selected: true
|
||||
disable: false
|
||||
},
|
||||
]
|
||||
default: ''
|
||||
translate: true
|
||||
class: 'medium'
|
||||
add: true
|
||||
}
|
||||
list = @formGenItem( attribute_config )
|
||||
list.find('.glyphicon-plus').bind('click', (e) ->
|
||||
e.preventDefault()
|
||||
value = $(e.target).closest('.controls').find('[name=ticket_attribute_list]').val()
|
||||
addShownAttribute( value, '' )
|
||||
)
|
||||
item.find('.ticket_attribute_list').prepend( list )
|
||||
|
||||
# list of shown attributes
|
||||
show = []
|
||||
if attribute.value
|
||||
for key, value of attribute.value
|
||||
addShownAttribute( key, value )
|
||||
|
||||
# ticket attribute selection
|
||||
else if attribute.tag is 'ticket_attribute_selection'
|
||||
|
||||
# list of possible attributes
|
||||
item = $(
|
||||
App.view('generic/ticket_attribute_manage')(
|
||||
attribute: attribute
|
||||
)
|
||||
)
|
||||
|
||||
addShownAttribute = ( key, value ) =>
|
||||
console.log( 'addShownAttribute', key, value )
|
||||
parts = key.split(/::/)
|
||||
key = parts[0]
|
||||
type = parts[1]
|
||||
|
@ -946,7 +1214,6 @@ class App.ControllerForm extends App.Controller
|
|||
type: 'text'
|
||||
null: false
|
||||
value: value
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.title'
|
||||
|
@ -957,7 +1224,6 @@ class App.ControllerForm extends App.Controller
|
|||
type: 'text'
|
||||
null: false
|
||||
value: value
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.group_id'
|
||||
|
@ -970,7 +1236,6 @@ class App.ControllerForm extends App.Controller
|
|||
nulloption: false
|
||||
relation: 'Group'
|
||||
value: value
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.owner_id' || key is 'tickets.customer_id'
|
||||
|
@ -988,7 +1253,6 @@ class App.ControllerForm extends App.Controller
|
|||
nulloption: false
|
||||
relation: 'User'
|
||||
value: value || null
|
||||
class: 'medium'
|
||||
remove: true
|
||||
filter: ( all, type ) ->
|
||||
return all if type isnt 'collection'
|
||||
|
@ -1020,7 +1284,6 @@ class App.ControllerForm extends App.Controller
|
|||
nulloption: false
|
||||
relation: 'Organization'
|
||||
value: value || null
|
||||
class: 'medium'
|
||||
remove: true
|
||||
filter: ( all, type ) ->
|
||||
return all if type isnt 'collection'
|
||||
|
@ -1045,7 +1308,6 @@ class App.ControllerForm extends App.Controller
|
|||
relation: 'TicketState'
|
||||
value: value
|
||||
translate: true
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.priority_id'
|
||||
|
@ -1059,7 +1321,6 @@ class App.ControllerForm extends App.Controller
|
|||
relation: 'TicketPriority'
|
||||
value: value
|
||||
translate: true
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.created_at' && ( type is '<>' || value.count )
|
||||
|
@ -1069,7 +1330,6 @@ class App.ControllerForm extends App.Controller
|
|||
tag: 'time_before_last'
|
||||
value: value
|
||||
translate: true
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.created_at' && ( type is '><' || 0 )
|
||||
|
@ -1079,7 +1339,6 @@ class App.ControllerForm extends App.Controller
|
|||
tag: 'time_range'
|
||||
value: value
|
||||
translate: true
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.close_time' && ( type is '<>' || value.count )
|
||||
|
@ -1089,7 +1348,6 @@ class App.ControllerForm extends App.Controller
|
|||
tag: 'time_before_last'
|
||||
value: value
|
||||
translate: true
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.close_time' && ( type is '><' || 0 )
|
||||
|
@ -1099,7 +1357,6 @@ class App.ControllerForm extends App.Controller
|
|||
tag: 'time_range'
|
||||
value: value
|
||||
translate: true
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.updated_at' && ( type is '<>' || value.count )
|
||||
|
@ -1109,7 +1366,6 @@ class App.ControllerForm extends App.Controller
|
|||
tag: 'time_before_last'
|
||||
value: value
|
||||
translate: true
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.updated_at' && ( type is '><' || 0 )
|
||||
|
@ -1119,7 +1375,6 @@ class App.ControllerForm extends App.Controller
|
|||
tag: 'time_range'
|
||||
value: value
|
||||
translate: true
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.escalation_time' && ( type is '<>' || value.count )
|
||||
|
@ -1129,7 +1384,6 @@ class App.ControllerForm extends App.Controller
|
|||
tag: 'time_before_last'
|
||||
value: value
|
||||
translate: true
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else if key is 'tickets.escalation_time' && ( type is '><' || 0 )
|
||||
|
@ -1139,7 +1393,6 @@ class App.ControllerForm extends App.Controller
|
|||
tag: 'time_range'
|
||||
value: value
|
||||
translate: true
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
else
|
||||
|
@ -1149,24 +1402,23 @@ class App.ControllerForm extends App.Controller
|
|||
tag: 'input'
|
||||
type: 'text'
|
||||
value: value
|
||||
class: 'medium'
|
||||
remove: true
|
||||
}
|
||||
|
||||
item.find('select[name=ticket_attribute_list] option[value="' + key + '"]').hide().prop('disabled', true)
|
||||
|
||||
itemSub = @formGenItem( attribute_config )
|
||||
itemSub.find('.glyphicon-minus').bind('click', (e) ->
|
||||
e.preventDefault()
|
||||
value = $(e.target).closest('.controls').find('[name]').attr('name')
|
||||
if value
|
||||
value = value.replace("#{attribute.name}::", '')
|
||||
$(e.target).closest('.sub_attribute').find('select[name=ticket_attribute_list] option[value="' + value + '"]').show().prop('disabled', false)
|
||||
$(@).parent().parent().parent().remove()
|
||||
)
|
||||
# itemSub.append('<a href=\"#\" class=\"icon-minus\"></a>')
|
||||
item.find('.ticket_attribute_item').append( itemSub )
|
||||
|
||||
|
||||
# list of shown attributes
|
||||
show = []
|
||||
if attribute.value
|
||||
for key, value of attribute.value
|
||||
addShownAttribute( key, value )
|
||||
|
||||
# list of existing attributes
|
||||
attribute_config = {
|
||||
name: 'ticket_attribute_list'
|
||||
|
@ -1182,19 +1434,18 @@ class App.ControllerForm extends App.Controller
|
|||
selected: false
|
||||
disable: true
|
||||
},
|
||||
#
|
||||
#{
|
||||
# value: 'tickets.number'
|
||||
# name: 'Number'
|
||||
# selected: true
|
||||
# disable: false
|
||||
#},
|
||||
#{
|
||||
# value: 'tickets.title'
|
||||
# name: 'Title'
|
||||
# selected: true
|
||||
# disable: false
|
||||
#},
|
||||
{
|
||||
value: 'tickets.number'
|
||||
name: 'Number'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'tickets.title'
|
||||
name: 'Title'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'tickets.group_id'
|
||||
name: 'Group'
|
||||
|
@ -1373,12 +1624,100 @@ class App.ControllerForm extends App.Controller
|
|||
|
||||
list.find('.glyphicon-plus').bind('click', (e) ->
|
||||
e.preventDefault()
|
||||
|
||||
value = $(e.target).parents().find('[name=ticket_attribute_list]').val()
|
||||
value = $(e.target).closest('.controls').find('[name=ticket_attribute_list]').val()
|
||||
addShownAttribute( value, '' )
|
||||
)
|
||||
item.find('.ticket_attribute_list').prepend( list )
|
||||
|
||||
# list of shown attributes
|
||||
show = []
|
||||
if attribute.value
|
||||
for key, value of attribute.value
|
||||
addShownAttribute( key, value )
|
||||
|
||||
# timeplan
|
||||
else if attribute.tag is 'timeplan'
|
||||
item = $( App.view('generic/timeplan')( attribute: attribute ) )
|
||||
attribute_config = {
|
||||
name: "#{attribute.name}::days"
|
||||
tag: 'select'
|
||||
multiple: true
|
||||
null: false
|
||||
options: [
|
||||
{
|
||||
value: 'mon'
|
||||
name: 'Monday'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'tue'
|
||||
name: 'Tuesday'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'wed'
|
||||
name: 'Wednesday'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'thu'
|
||||
name: 'Thursday'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'fri'
|
||||
name: 'Friday'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'sat'
|
||||
name: 'Saturday'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
{
|
||||
value: 'sun'
|
||||
name: 'Sunday'
|
||||
selected: false
|
||||
disable: false
|
||||
},
|
||||
]
|
||||
default: attribute.default?.days
|
||||
}
|
||||
item.find('.days').append( @formGenItem( attribute_config ) )
|
||||
|
||||
hours = {}
|
||||
for hour in [0..23]
|
||||
localHour = "0#{hour}"
|
||||
hours[hour] = localHour.substr(localHour.length-2,2)
|
||||
attribute_config = {
|
||||
name: "#{attribute.name}::hours"
|
||||
tag: 'select'
|
||||
multiple: true
|
||||
null: false
|
||||
options: hours
|
||||
default: attribute.default?.hours
|
||||
}
|
||||
item.find('.hours').append( @formGenItem( attribute_config ) )
|
||||
|
||||
minutes = {}
|
||||
for minute in [0..5]
|
||||
minutes["#{minute}0"] = "#{minute}0"
|
||||
attribute_config = {
|
||||
name: "#{attribute.name}::minutes"
|
||||
tag: 'select'
|
||||
multiple: true
|
||||
null: false
|
||||
options: minutes
|
||||
default: attribute.default?.miuntes
|
||||
}
|
||||
item.find('.minutes').append( @formGenItem( attribute_config ) )
|
||||
|
||||
# input
|
||||
else
|
||||
item = $( App.view('generic/input')( attribute: attribute ) )
|
||||
|
|
|
@ -5,17 +5,23 @@ class Index extends App.ControllerContent
|
|||
# check authentication
|
||||
return if !@authenticate()
|
||||
|
||||
# set title
|
||||
@title 'Scheduler'
|
||||
@navupdate '#scheduler'
|
||||
|
||||
# render page
|
||||
@render()
|
||||
|
||||
render: ->
|
||||
|
||||
@html App.view('scheduler')(
|
||||
head: 'some header'
|
||||
new App.ControllerGenericIndex(
|
||||
el: @el,
|
||||
id: @id,
|
||||
genericObject: 'Job',
|
||||
pageData: {
|
||||
title: 'Schedulers',
|
||||
home: 'schedulers',
|
||||
object: 'Scheduler',
|
||||
objects: 'Schedulers',
|
||||
navupdate: '#schedulers',
|
||||
notes: [
|
||||
'Scheduler are ...'
|
||||
],
|
||||
buttons: [
|
||||
{ name: 'New Scheduler', 'data-type': 'new', class: 'btn--success' },
|
||||
],
|
||||
},
|
||||
)
|
||||
|
||||
App.Config.set( 'Scheduler', { prio: 2000, name: 'Schedulers', parent: '#manage', target: '#manage/schedulers', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
|
||||
App.Config.set( 'Scheduler', { prio: 3000, name: 'Schedulers', parent: '#manage', target: '#manage/schedulers', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
|
|
@ -18,8 +18,4 @@ class Index extends App.ControllerContent
|
|||
head: 'some header'
|
||||
)
|
||||
|
||||
#App.Config.set( 'trigger', Index, 'Routes' )
|
||||
#App.Config.set( 'Trigger', { prio: 3000, parent: '#admin', name: 'Trigger', target: '#trigger', role: ['Admin'] }, 'NavBar' )
|
||||
|
||||
App.Config.set( 'Trigger', { prio: 3000, name: 'Triggers', target: '#manage/triggers', controller: Index, role: ['Admin'] }, 'NavBarLevel2' )
|
||||
|
||||
App.Config.set( 'Trigger', { prio: 3100, name: 'Triggers', parent: '#manage', target: '#manage/triggers', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
|
27
app/assets/javascripts/app/models/job.js.coffee
Normal file
27
app/assets/javascripts/app/models/job.js.coffee
Normal file
|
@ -0,0 +1,27 @@
|
|||
class App.Job extends App.Model
|
||||
@configure 'Job', 'name', 'timeplan', 'condition', 'execute', 'note', 'active'
|
||||
@extend Spine.Model.Ajax
|
||||
@url: @apiPath + '/jobs'
|
||||
@configure_attributes = [
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
|
||||
{ name: 'timeplan', display: 'The times where the job should run.', tag: 'timeplan', null: true },
|
||||
{ name: 'condition', display: 'Conditions for matching objects.', tag: 'ticket_attribute_selection', null: true },
|
||||
{ name: 'execute', display: 'Execute changes on objects.', tag: 'ticket_attribute_set', null: true },
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', note: 'Notes are visible to agents only, never to customers.', limit: 250, null: true },
|
||||
{ name: 'active', display: 'Active', tag: 'boolean', note: 'boolean', 'default': true, null: false },
|
||||
{ name: 'matching', display: 'Matching', readonly: 1 },
|
||||
{ name: 'processed', display: 'Processed', readonly: 1 },
|
||||
{ name: 'last_run_at', display: 'Last run', type: 'time', readonly: 1 },
|
||||
{ name: 'running', display: 'Running', tag: 'boolean', readonly: 1 },
|
||||
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
|
||||
{ name: 'created_at', display: 'Created', type: 'time', readonly: 1 },
|
||||
{ name: 'updated_by_id', display: 'Updated by', relation: 'User', readonly: 1 },
|
||||
{ name: 'updated_at', display: 'Updated', type: 'time', readonly: 1 },
|
||||
]
|
||||
@configure_delete = true
|
||||
@configure_overview = [
|
||||
'name',
|
||||
'last_run_at',
|
||||
'matching',
|
||||
'processed',
|
||||
]
|
|
@ -2,5 +2,4 @@
|
|||
<div class="ticket_attribute_item"></div>
|
||||
<hr>
|
||||
<div class="ticket_attribute_list"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
11
app/assets/javascripts/app/views/generic/timeplan.jst.eco
Normal file
11
app/assets/javascripts/app/views/generic/timeplan.jst.eco
Normal file
|
@ -0,0 +1,11 @@
|
|||
<div>
|
||||
<label><%- @T('Days') %>
|
||||
<div class="days"></div>
|
||||
</label>
|
||||
<label><%- @T('Hours') %>
|
||||
<div class="hours"></div>
|
||||
</label>
|
||||
<label><%- @T('Minutes') %>
|
||||
<div class="minutes"></div>
|
||||
</label>
|
||||
</div>
|
|
@ -1,91 +0,0 @@
|
|||
<div class="page-header-title">
|
||||
<h1>Scheduler <small>Management</small></h1>
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-tabs nav-stacked">
|
||||
<li><a href="#">Jobs</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="table-overview">
|
||||
<div class="tabbable">
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a href="#channel-inbound" data-toggle="tab">Times</a></li>
|
||||
<li><a href="#channel-outbound" data-toggle="tab">Properties</a></li>
|
||||
<li><a href="#channel-filter" data-toggle="tab">Message</a></li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="channel-inbound">
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Host</th>
|
||||
<th>User</th>
|
||||
<th>Type</th>
|
||||
<th>Active</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>lalal.example.com</td>
|
||||
<td>wpt234rwr</td>
|
||||
<td>IMAP</td>
|
||||
<td>true</td>
|
||||
<td>x</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>l31alal.example.com</td>
|
||||
<td>wpt23dd4rwr</td>
|
||||
<td>POP3</td>
|
||||
<td>true</td>
|
||||
<td>x</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab-pane" id="channel-outbound">
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Host</th>
|
||||
<th>User</th>
|
||||
<th>Type</th>
|
||||
<th>Active</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>lalal.example.com</td>
|
||||
<td>wpt234rwr</td>
|
||||
<td>SMTP</td>
|
||||
<td>true</td>
|
||||
<td>x</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>l31alal.example.com</td>
|
||||
<td>wpt23dd4rwr</td>
|
||||
<td>Sendmail</td>
|
||||
<td>true</td>
|
||||
<td>x</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab-pane" id="channel-filter">
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Active</th>
|
||||
<th>Last Run</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>lalal.example.com</td>
|
||||
<td>true</td>
|
||||
<td>true</td>
|
||||
<td>x</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>wpt23dd4rwr</td>
|
||||
<td>true</td>
|
||||
<td>true</td>
|
||||
<td>x</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -23,6 +23,13 @@ class TestsController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# GET /tests/from_extended
|
||||
def form
|
||||
respond_to do |format|
|
||||
format.html # index.html.erb
|
||||
end
|
||||
end
|
||||
|
||||
# GET /tests/table
|
||||
def table
|
||||
respond_to do |format|
|
||||
|
|
88
app/models/job.rb
Normal file
88
app/models/job.rb
Normal file
|
@ -0,0 +1,88 @@
|
|||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class Job < ApplicationModel
|
||||
store :timeplan
|
||||
store :condition
|
||||
store :execute
|
||||
validates :name, :presence => true
|
||||
|
||||
before_create :updated_matching
|
||||
before_update :updated_matching
|
||||
|
||||
after_create :notify_clients_after_create
|
||||
after_update :notify_clients_after_update
|
||||
after_destroy :notify_clients_after_destroy
|
||||
|
||||
def self.run
|
||||
time = Time.new
|
||||
day_map = {
|
||||
0 => 'sun',
|
||||
1 => 'mon',
|
||||
2 => 'tue',
|
||||
3 => 'wed',
|
||||
4 => 'thu',
|
||||
5 => 'fri',
|
||||
6 => 'sat',
|
||||
}
|
||||
jobs = Job.where( :active => true )
|
||||
jobs.each do |job|
|
||||
|
||||
# only execute jobs, older then 2 min, to give admin posibility to change
|
||||
next if job.updated_at > Time.now - 2.minutes
|
||||
|
||||
# check if jobs need to be executed
|
||||
# ignore if job was running within last 10 min.
|
||||
next if job.last_run_at > Time.now - 10.minutes
|
||||
|
||||
# check day
|
||||
next if !job.timeplan['days'].include?( day_map[time.wday] )
|
||||
|
||||
# check hour
|
||||
next if !job.timeplan['hours'].include?( time.hour.to_s )
|
||||
|
||||
# check min
|
||||
next if !job.timeplan['minutes'].include?( match_minutes(time.min.to_s) )
|
||||
|
||||
# find tickets to change
|
||||
tickets = Ticket.where( job.condition.permit! ).
|
||||
order( '`tickets`.`created_at` DESC' ).
|
||||
limit( 1_000 )
|
||||
job.processed = tickets.count
|
||||
tickets.each do |ticket|
|
||||
#puts "CHANGE #{job.execute.inspect}"
|
||||
changed = false
|
||||
job.execute.each do |key, value|
|
||||
changed = true
|
||||
attribute = key.split('.', 2).last
|
||||
#puts "-- #{Ticket.columns_hash[ attribute ].type.to_s}"
|
||||
#value = 4
|
||||
#if Ticket.columns_hash[ attribute ].type == :integer
|
||||
# puts "to i #{attribute}/#{value.inspect}/#{value.to_i.inspect}"
|
||||
# #value = value.to_i
|
||||
#end
|
||||
ticket[attribute] = value
|
||||
#puts "set #{attribute} = #{value.inspect}"
|
||||
end
|
||||
next if !changed
|
||||
ticket.updated_by_id = 1
|
||||
ticket.save
|
||||
end
|
||||
|
||||
job.last_run_at = Time.now
|
||||
job.save
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def updated_matching
|
||||
count = Ticket.where( self.condition.permit! ).count
|
||||
self.matching = count
|
||||
end
|
||||
|
||||
def self.match_minutes(minutes)
|
||||
minutes.gsub!(/(\d)\d/, "\\1")
|
||||
minutes.to_s + '0'
|
||||
end
|
||||
end
|
|
@ -7,4 +7,4 @@ class Overview < ApplicationModel
|
|||
validates :name, :presence => true
|
||||
validates :prio, :presence => true
|
||||
validates :link, :presence => true
|
||||
end
|
||||
end
|
11
config/routes/job.rb
Normal file
11
config/routes/job.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
Zammad::Application.routes.draw do
|
||||
api_path = Rails.configuration.api_path
|
||||
|
||||
# jobs
|
||||
match api_path + '/jobs', :to => 'jobs#index', :via => :get
|
||||
match api_path + '/jobs/:id', :to => 'jobs#show', :via => :get
|
||||
match api_path + '/jobs', :to => 'jobs#create', :via => :post
|
||||
match api_path + '/jobs/:id', :to => 'jobs#update', :via => :put
|
||||
match api_path + '/jobs/:id', :to => 'jobs#destroy', :via => :delete
|
||||
|
||||
end
|
|
@ -1,10 +1,11 @@
|
|||
Zammad::Application.routes.draw do
|
||||
|
||||
match '/tests-core', :to => 'tests#core', :via => :get
|
||||
match '/tests-ui', :to => 'tests#ui', :via => :get
|
||||
match '/tests-model', :to => 'tests#model', :via => :get
|
||||
match '/tests-form', :to => 'tests#form', :via => :get
|
||||
match '/tests-table', :to => 'tests#table', :via => :get
|
||||
match '/tests/wait/:sec', :to => 'tests#wait', :via => :get
|
||||
match '/tests-core', :to => 'tests#core', :via => :get
|
||||
match '/tests-ui', :to => 'tests#ui', :via => :get
|
||||
match '/tests-model', :to => 'tests#model', :via => :get
|
||||
match '/tests-form', :to => 'tests#form', :via => :get
|
||||
match '/tests-form-extended', :to => 'tests#form_extended', :via => :get
|
||||
match '/tests-table', :to => 'tests#table', :via => :get
|
||||
match '/tests/wait/:sec', :to => 'tests#wait', :via => :get
|
||||
|
||||
end
|
25
db/migrate/20141221000001_create_job.rb
Normal file
25
db/migrate/20141221000001_create_job.rb
Normal file
|
@ -0,0 +1,25 @@
|
|||
class CreateJob < ActiveRecord::Migration
|
||||
def up
|
||||
create_table :jobs do |t|
|
||||
t.column :name, :string, :limit => 250, :null => false
|
||||
t.column :timeplan, :string, :limit => 500, :null => false
|
||||
t.column :condition, :string, :limit => 2500, :null => false
|
||||
t.column :execute, :string, :limit => 2500, :null => false
|
||||
t.column :last_run_at, :timestamp, :null => true
|
||||
t.column :running, :boolean, :null => false, :default => false
|
||||
t.column :processed, :integer, :null => false, :default => 0
|
||||
t.column :matching, :integer, :null => false
|
||||
t.column :pid, :string, :limit => 250, :null => true
|
||||
t.column :note, :string, :limit => 250, :null => true
|
||||
t.column :active, :boolean, :null => false, :default => false
|
||||
t.column :updated_by_id, :integer, :null => false
|
||||
t.column :created_by_id, :integer, :null => false
|
||||
t.timestamps
|
||||
end
|
||||
add_index :jobs, [:name], :unique => true
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :jobs
|
||||
end
|
||||
end
|
87
public/assets/tests/form-extended.js
Normal file
87
public/assets/tests/form-extended.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
|
||||
// form
|
||||
test( "form simple checks", function() {
|
||||
|
||||
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: true,
|
||||
created_at: '2014-06-10T10:17:44.000Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: '4 very high',
|
||||
note: 'some note 4',
|
||||
active: true,
|
||||
created_at: '2014-06-10T10:17:54.000Z',
|
||||
},
|
||||
] )
|
||||
|
||||
// timeplan
|
||||
$('#forms').append('<hr><h1>form time check</h1><form id="form1"></form>')
|
||||
|
||||
var el = $('#form1')
|
||||
var defaults = {
|
||||
times: {
|
||||
days: ['mon', 'wed'],
|
||||
hours: [2],
|
||||
},
|
||||
conditions: {
|
||||
'tickets.title': 'some title',
|
||||
'tickets.priority_id': [1,2,3],
|
||||
},
|
||||
executions: {
|
||||
'tickets.title': 'some title new',
|
||||
'tickets.priority_id': 3,
|
||||
},
|
||||
}
|
||||
new App.ControllerForm({
|
||||
el: el,
|
||||
model: {
|
||||
configure_attributes: [
|
||||
{ name: 'times', display: 'Times', tag: 'timeplan', null: true, default: defaults['times'] },
|
||||
{ name: 'conditions', display: 'Conditions', tag: 'ticket_attribute_selection', null: true, default: defaults['conditions'] },
|
||||
{ name: 'executions', display: 'Executions', tag: 'ticket_attribute_set', null: true, default: defaults['executions'] },
|
||||
]
|
||||
},
|
||||
autofocus: true
|
||||
});
|
||||
deepEqual( el.find('[name="times::days"]').val(), ['mon', 'wed'], 'check times::days value')
|
||||
equal( el.find('[name="times::hours"]').val(), 2, 'check times::hours value')
|
||||
equal( el.find('[name="times::minutes"]').val(), null, 'check times::minutes value')
|
||||
|
||||
var params = App.ControllerForm.params( el )
|
||||
var test_params = {
|
||||
times: {
|
||||
days: ['mon', 'wed'],
|
||||
hours: '2',
|
||||
},
|
||||
conditions: {
|
||||
'tickets.title': 'some title',
|
||||
'tickets.priority_id': ['1','3'],
|
||||
},
|
||||
executions: {
|
||||
'tickets.title': 'some title new',
|
||||
'tickets.priority_id': '3',
|
||||
},
|
||||
}
|
||||
deepEqual( params, test_params, 'form param check' );
|
||||
|
||||
|
||||
});
|
|
@ -90,6 +90,28 @@ class AAbUnitTest < TestCase
|
|||
]
|
||||
browser_single_test(tests)
|
||||
end
|
||||
def test_form_extended
|
||||
tests = [
|
||||
{
|
||||
:name => 'start',
|
||||
:instance => browser_instance,
|
||||
:url => browser_url + '/tests-form-extended',
|
||||
:action => [
|
||||
{
|
||||
:execute => 'wait',
|
||||
:value => 8,
|
||||
},
|
||||
{
|
||||
:execute => 'match',
|
||||
:css => '.result .failed',
|
||||
:value => '0',
|
||||
:match_result => true,
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
browser_single_test(tests)
|
||||
end
|
||||
def test_table
|
||||
tests = [
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue