Init version.
This commit is contained in:
parent
5327445d44
commit
76637f55a2
17 changed files with 1457 additions and 5 deletions
488
app/assets/javascripts/app/controllers/report.js.coffee
Normal file
488
app/assets/javascripts/app/controllers/report.js.coffee
Normal file
|
@ -0,0 +1,488 @@
|
|||
class Index extends App.ControllerContent
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# check authentication
|
||||
return if !@authenticate()
|
||||
|
||||
@title 'Reporting'
|
||||
@navupdate '#report'
|
||||
@startLoading()
|
||||
@ajax(
|
||||
type: 'GET',
|
||||
url: @apiPath + '/reports/config',
|
||||
processData: true,
|
||||
success: (data) =>
|
||||
@stopLoading()
|
||||
@config = data.config
|
||||
App.Collection.load( type: 'ReportProfile', data: data.profiles )
|
||||
@render()
|
||||
)
|
||||
|
||||
getParams: =>
|
||||
return @params if @params
|
||||
|
||||
@params = {}
|
||||
@params.timeRange = 'year'
|
||||
current = new Date()
|
||||
currentDay = current.getDate()
|
||||
currentMonth = current.getMonth() + 1
|
||||
currentYear = current.getFullYear()
|
||||
currentWeek = current.getWeek()
|
||||
@params.day = currentDay
|
||||
@params.month = currentMonth
|
||||
@params.week = currentWeek
|
||||
@params.year = currentYear
|
||||
if !@params.metric
|
||||
for key, config of @config.metric
|
||||
if config.default
|
||||
@params.metric = config.name
|
||||
if !@params.backendSelected
|
||||
@params.backendSelected = {}
|
||||
for key, config of @config.metric
|
||||
for backend in config.backend
|
||||
if backend.selected
|
||||
@params.backendSelected[backend.name] = true
|
||||
if !@params.profileSelected
|
||||
@params.profileSelected = {}
|
||||
for profile in App.ReportProfile.all()
|
||||
if _.isEmpty( @params.profileSelected )
|
||||
@params.profileSelected[ profile.id ] = true
|
||||
@params
|
||||
|
||||
render: (data = {}) =>
|
||||
|
||||
@params = @getParams()
|
||||
|
||||
@html App.view('report/main')(
|
||||
params: @params
|
||||
)
|
||||
|
||||
new TimeRangePicker(
|
||||
el: @el.find('.js-timeRangePicker')
|
||||
params: @params
|
||||
ui: @
|
||||
)
|
||||
|
||||
new TimePicker(
|
||||
el: @el.find('.js-timePicker')
|
||||
params: @params
|
||||
ui: @
|
||||
)
|
||||
|
||||
new Sidebar(
|
||||
el: @el.find('.sidebar')
|
||||
config: @config
|
||||
params: @params
|
||||
)
|
||||
|
||||
new Graph(
|
||||
el: @el
|
||||
config: @config
|
||||
params: @params
|
||||
ui: @
|
||||
)
|
||||
|
||||
class Graph extends App.ControllerContent
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# rerender view
|
||||
@bind 'ui:report:rerender', =>
|
||||
@render()
|
||||
|
||||
@render()
|
||||
|
||||
render: =>
|
||||
|
||||
update = (data) =>
|
||||
@draw(data.data)
|
||||
t = new Date
|
||||
@el.find('#download-chart').html(t.toString())
|
||||
new Download(
|
||||
el: @el.find('.js-dataDownload')
|
||||
config: @config
|
||||
params: @params
|
||||
ui: @ui
|
||||
)
|
||||
|
||||
url = @apiPath + '/reports/generate'
|
||||
interval = 60000
|
||||
if @params.timeRange is 'year'
|
||||
interval = 30000
|
||||
if @params.timeRange is 'month'
|
||||
interval = 20000
|
||||
if @params.timeRange is 'week'
|
||||
interval = 20000
|
||||
if @params.timeRange is 'day'
|
||||
interval = 20000
|
||||
if @params.timeRange is 'realtime'
|
||||
interval = 10000
|
||||
|
||||
@ajax(
|
||||
type: 'POST'
|
||||
url: url
|
||||
data: JSON.stringify(
|
||||
metric: @params.metric
|
||||
year: @params.year
|
||||
month: @params.month
|
||||
week: @params.week
|
||||
day: @params.day
|
||||
timeRange: @params.timeRange
|
||||
profiles: @params.profileSelected
|
||||
backends: @params.backendSelected
|
||||
)
|
||||
processData: true
|
||||
success: (data) =>
|
||||
update(data)
|
||||
@delay( @render, interval, 'report-update', 'page' )
|
||||
)
|
||||
|
||||
draw: (data) =>
|
||||
@log('draw', data)
|
||||
$('#placeholder').empty()
|
||||
|
||||
# create xaxis
|
||||
xaxis = []
|
||||
if @params.timeRange is 'realtime'
|
||||
for minute in [0..59]
|
||||
xaxis.push [minute, '']
|
||||
else if @params.timeRange is 'day'
|
||||
for hour in [0..23]
|
||||
xaxis.push [hour, hour]
|
||||
else if @params.timeRange is 'month'
|
||||
for day in [1..31]
|
||||
xaxis.push [day, day]
|
||||
else if @params.timeRange is 'week'
|
||||
xaxis = [[1, 'Mon'], [2, 'Tue'], [3, 'Wed'], [4, 'Thr'], [5, 'Fri'], [6, 'Sat'], [7, 'Sun'] ]
|
||||
else
|
||||
xaxis = [[1, 'Jan'], [2, 'Feb'], [3, 'Mar'], [4, 'Apr'], [5, 'Mai'], [6, 'Jun'], [7, 'Jul'], [8, 'Aug'], [9, 'Sep'], [10, 'Oct'], [11, 'Nov'], [12, 'Dec']]
|
||||
|
||||
dataPlot = []
|
||||
for key, value of data
|
||||
dataPlot.push {
|
||||
data: value
|
||||
label: key
|
||||
}
|
||||
# plot
|
||||
$.plot( $('#placeholder'), dataPlot, {
|
||||
yaxis: { min: 0 },
|
||||
xaxis: { ticks: xaxis }
|
||||
} )
|
||||
|
||||
|
||||
class Download extends App.Controller
|
||||
events:
|
||||
'click .js-dataDownloadBackendSelector': 'tableUpdate'
|
||||
|
||||
constructor: (data) ->
|
||||
|
||||
# unbind existing click binds
|
||||
data.el.unbind('click .js-dataDownloadBackendSelector')
|
||||
|
||||
super
|
||||
@render()
|
||||
|
||||
render: ->
|
||||
|
||||
reports = []
|
||||
$('.js-backendSelector:checked').each( (index, element) ->
|
||||
if $(element).hasClass('download')
|
||||
value = $(element).val()
|
||||
reports.push value
|
||||
)
|
||||
|
||||
profiles = []
|
||||
for key, value of @params.profileSelected
|
||||
profiles.push App.ReportProfile.find(key)
|
||||
console.log('reports', reports, 'profiles', profiles, @config.metric, @params.metric, @config.metric[@params.metric])
|
||||
@html App.view('report/download_header')(
|
||||
reports: reports
|
||||
profiles: profiles
|
||||
metric: @config.metric[@params.metric]
|
||||
)
|
||||
|
||||
@profileSelected = ''
|
||||
@backendSelected = ''
|
||||
active = false
|
||||
@el.find('.js-dataDownloadBackendSelector').each( (index, element) ->
|
||||
if $(element).parent().hasClass('active')
|
||||
active = true
|
||||
)
|
||||
if !active
|
||||
@el.find('.js-dataDownloadBackendSelector').first().parent().addClass('active')
|
||||
|
||||
@el.find('.js-dataDownloadBackendSelector').each( (index, element) =>
|
||||
if $(element).parent().hasClass('active')
|
||||
@profileSelected = $(element).data('profile')
|
||||
@backendSelected = $(element).data('report')
|
||||
)
|
||||
|
||||
@tableUpdate()
|
||||
|
||||
tableUpdate: (e) =>
|
||||
if e
|
||||
e.preventDefault()
|
||||
@el.find('.js-dataDownloadBackendSelector').parent().removeClass('active')
|
||||
$(e.target).parent().addClass('active')
|
||||
@profileSelected = $(e.target).data('profile')
|
||||
@backendSelected = $(e.target).data('backend')
|
||||
|
||||
table = (tickets, count) =>
|
||||
url = '#ticket/zoom/'
|
||||
if App.Config.get('import_mode')
|
||||
url = App.Config.get('import_otrs_endpoint') + '/index.pl?Action=AgentTicketZoom;TicketID='
|
||||
if _.isEmpty(tickets)
|
||||
@el.find('js-dataDownloadTable').html('')
|
||||
else
|
||||
html = App.view('report/download_list')(
|
||||
tickets: tickets
|
||||
count: count
|
||||
url: url
|
||||
download: @apiPath + '/reports/csvforset/' + name
|
||||
)
|
||||
@el.find('js-dataDownloadTable').html(html)
|
||||
|
||||
@startLoading()
|
||||
@ajax(
|
||||
type: 'POST'
|
||||
url: @apiPath + '/reports/sets'
|
||||
data: JSON.stringify(
|
||||
metric: @params.metric
|
||||
year: @params.year
|
||||
month: @params.month
|
||||
week: @params.week
|
||||
day: @params.day
|
||||
timeRange: @params.timeRange
|
||||
profiles: @params.profileSelected
|
||||
|
||||
)
|
||||
processData: true
|
||||
success: (data) =>
|
||||
@stopLoading()
|
||||
|
||||
# load ticket collection / do not save in localStorage
|
||||
App.Collection.load( type: 'TicketReport', data: data.tickets, localStorage: true )
|
||||
ticket_collection = []
|
||||
|
||||
if data.tickets
|
||||
for record in data.tickets
|
||||
ticket = App.TicketReport.fullLocal( record.id )
|
||||
ticket_collection.push ticket
|
||||
|
||||
table( ticket_collection, data.count )
|
||||
)
|
||||
|
||||
class TimeRangePicker extends App.Controller
|
||||
events:
|
||||
'click .js-timeRange': 'select'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# rerender view
|
||||
@bind 'ui:report:rerender', =>
|
||||
@render()
|
||||
|
||||
@render()
|
||||
|
||||
render: =>
|
||||
@html App.view('report/time_range_picker')()
|
||||
|
||||
# select time slot
|
||||
@el.find('.js-timeRange').removeClass('active')
|
||||
@el.find('.js-timeRange[data-type="' + @ui.params.timeRange + '"]').addClass('active')
|
||||
|
||||
select: (e) =>
|
||||
console.log('TS click')
|
||||
e.preventDefault()
|
||||
@ui.params.timeRange = $(e.target).data('type')
|
||||
console.log 'SLOT', @ui.params.timeRange
|
||||
App.Event.trigger( 'ui:report:rerender' )
|
||||
|
||||
|
||||
class TimePicker extends App.Controller
|
||||
events:
|
||||
'click .js-timePickerDay': 'selectTimeDay'
|
||||
'click .js-timePickerYear': 'selectTimeYear'
|
||||
'click .js-timePickerMonth': 'selectTimeMonth'
|
||||
'click .js-timePickerWeek': 'selectTimeWeek'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
@_timeSlotPicker()
|
||||
|
||||
# rerender view
|
||||
@bind 'ui:report:rerender', =>
|
||||
@render()
|
||||
|
||||
@render()
|
||||
|
||||
render: =>
|
||||
@html App.view('report/time_picker')(
|
||||
params: @ui.params
|
||||
timeRangeDay: @timeRangeDay
|
||||
timeRangeMonth: @timeRangeMonth
|
||||
timeRangeWeek: @timeRangeWeek
|
||||
timeRangeYear: @timeRangeYear
|
||||
)
|
||||
|
||||
# select time slot
|
||||
@el.find('.time-slot').removeClass('active')
|
||||
@el.find('.time-slot[data-type="' + @ui.params.timeRange + '"]').addClass('active')
|
||||
|
||||
selectTimeDay: (e) =>
|
||||
e.preventDefault()
|
||||
@ui.params.day = $(e.target).data('type')
|
||||
$(e.target).parent().parent().find('li').removeClass('active')
|
||||
$(e.target).parent().addClass('active')
|
||||
App.Event.trigger( 'ui:report:rerender' )
|
||||
|
||||
selectTimeMonth: (e) =>
|
||||
e.preventDefault()
|
||||
@ui.params.month = $(e.target).data('type')
|
||||
$(e.target).parent().parent().find('li').removeClass('active')
|
||||
$(e.target).parent().addClass('active')
|
||||
App.Event.trigger( 'ui:report:rerender' )
|
||||
|
||||
selectTimeWeek: (e) =>
|
||||
e.preventDefault()
|
||||
@ui.params.week = $(e.target).data('type')
|
||||
$(e.target).parent().parent().find('li').removeClass('active')
|
||||
$(e.target).parent().addClass('active')
|
||||
App.Event.trigger( 'ui:report:rerender' )
|
||||
|
||||
selectTimeYear: (e) =>
|
||||
e.preventDefault()
|
||||
@ui.params.year = $(e.target).data('type')
|
||||
$(e.target).parent().parent().find('li').removeClass('active')
|
||||
$(e.target).parent().addClass('active')
|
||||
App.Event.trigger( 'ui:report:rerender' )
|
||||
|
||||
_timeSlotPicker: ->
|
||||
@timeRangeYear = []
|
||||
year = new Date().getFullYear()
|
||||
for item in [year-2..year]
|
||||
record = {
|
||||
display: item
|
||||
value: item
|
||||
}
|
||||
@timeRangeYear.push record
|
||||
|
||||
@timeRangeMonth = [
|
||||
{
|
||||
display: 'Jan'
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
display: 'Feb'
|
||||
value: 2
|
||||
},
|
||||
{
|
||||
display: 'Mar'
|
||||
value: 3
|
||||
},
|
||||
{
|
||||
display: 'Apr'
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
display: 'Mai'
|
||||
value: 5,
|
||||
},
|
||||
{
|
||||
display: 'Jun'
|
||||
value: 6,
|
||||
},
|
||||
{
|
||||
display: 'Jul'
|
||||
value: 7,
|
||||
},
|
||||
{
|
||||
display: 'Aug'
|
||||
value: 8,
|
||||
},
|
||||
{
|
||||
display: 'Sep'
|
||||
value: 9,
|
||||
},
|
||||
{
|
||||
display: 'Oct'
|
||||
value: 10,
|
||||
},
|
||||
{
|
||||
display: 'Nov'
|
||||
value: 11,
|
||||
},
|
||||
{
|
||||
display: 'Dec'
|
||||
value: 12,
|
||||
},
|
||||
]
|
||||
|
||||
@timeRangeWeek = []
|
||||
for item in [1..52]
|
||||
record = {
|
||||
display: item
|
||||
value: item
|
||||
}
|
||||
@timeRangeWeek.push record
|
||||
|
||||
@timeRangeDay = []
|
||||
for item in [1..31]
|
||||
record = {
|
||||
display: item
|
||||
value: item
|
||||
}
|
||||
@timeRangeDay.push record
|
||||
|
||||
|
||||
class Sidebar extends App.Controller
|
||||
events:
|
||||
'click .js-profileSelector': 'selectProfile'
|
||||
'click .js-backendSelector': 'selectBackend'
|
||||
'click .panel-title': 'selectMetric'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
@render()
|
||||
|
||||
render: =>
|
||||
|
||||
metrics = @config.metric
|
||||
profiles = App.ReportProfile.all()
|
||||
console.log('Si', @params)
|
||||
@html App.view('report/sidebar')(
|
||||
metrics: metrics
|
||||
params: @params
|
||||
profiles: profiles
|
||||
)
|
||||
|
||||
selectMetric: (e) =>
|
||||
return if $(e.target).closest('.panel').find('.collapse.in').get(0)
|
||||
metric = $(e.target).closest('.panel').data('metric')
|
||||
return if @params.metric is metric
|
||||
@params.metric = metric
|
||||
App.Event.trigger( 'ui:report:rerender' )
|
||||
|
||||
selectProfile: (e) =>
|
||||
profile_id = $(e.target).val()
|
||||
active = $(e.target).prop('checked')
|
||||
if active
|
||||
@params.profileSelected[profile_id] = true
|
||||
else
|
||||
delete @params.profileSelected[profile_id]
|
||||
App.Event.trigger( 'ui:report:rerender' )
|
||||
|
||||
selectBackend: (e) =>
|
||||
backend = $(e.target).val()
|
||||
active = $(e.target).prop('checked')
|
||||
if active
|
||||
@params.backendSelected[backend] = true
|
||||
else
|
||||
delete @params.backendSelected[backend]
|
||||
App.Event.trigger( 'ui:report:rerender' )
|
||||
|
||||
App.Config.set( 'report', Index, 'Routes' )
|
||||
App.Config.set( 'Reporting', { prio: 8000, parent: '', name: 'Reporing', translate: true, target: '#report', icon: 'report', role: ['Admin'] }, 'NavBarRight' )
|
|
@ -0,0 +1,27 @@
|
|||
class Index extends App.ControllerContent
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
# check authentication
|
||||
return if !@authenticate()
|
||||
|
||||
new App.ControllerGenericIndex(
|
||||
el: @el
|
||||
id: @id
|
||||
genericObject: 'ReportProfile'
|
||||
pageData:
|
||||
title: 'Report Profile'
|
||||
home: 'report_profiles'
|
||||
object: 'Report Profile'
|
||||
objects: 'Report Profiles'
|
||||
navupdate: '#report_profiles'
|
||||
notes: [
|
||||
# 'Report Profile are ...'
|
||||
]
|
||||
buttons: [
|
||||
{ name: 'New Profile', 'data-type': 'new', class: 'primary' }
|
||||
]
|
||||
container: @el.closest('.content')
|
||||
)
|
||||
|
||||
App.Config.set( 'ReportProfile', { prio: 8000, name: 'Report Profiles', parent: '#manage', target: '#manage/report_profiles', controller: Index, role: ['Admin'] }, 'NavBarAdmin' )
|
14
app/assets/javascripts/app/models/report_profile.js.coffee
Normal file
14
app/assets/javascripts/app/models/report_profile.js.coffee
Normal file
|
@ -0,0 +1,14 @@
|
|||
class App.ReportProfile extends App.Model
|
||||
@configure 'ReportProfile', 'name', 'condition', 'active'
|
||||
@extend Spine.Model.Ajax
|
||||
@url: @apiPath + '/report_profiles'
|
||||
@configure_attributes = [
|
||||
{ name: 'name', display: 'Name', tag: 'input', type: 'text', limit: 100, null: false },
|
||||
{ name: 'condition', display: 'Filter', tag: 'ticket_selector', null: true },
|
||||
{ name: 'updated_at', display: 'Updated', tag: 'datetime', readonly: 1 },
|
||||
{ name: 'active', display: 'Active', tag: 'active', default: true },
|
||||
]
|
||||
@configure_delete = true
|
||||
@configure_overview = [
|
||||
'name',
|
||||
]
|
|
@ -0,0 +1,14 @@
|
|||
<div>
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
<% for profile in @profiles: %>
|
||||
<% for backend in @metric.backend: %>
|
||||
<% if backend.dataDownload: %>
|
||||
<li><a href="#" class="js-dataDownloadBackendSelector" data-toggle="tab" data-profile="<%= profile.id %>" data-backend="<%= backend.name %>"><%= @T(backend.display) %></a></li>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
<div class="js-dataDownloadTable"></div>
|
||||
</div>
|
|
@ -0,0 +1,26 @@
|
|||
<i><%- @T('%s records', @count) %></i>
|
||||
<a href="<%-@download%>" target="_blank" data-type="attachment" id="downloadsetascsv">
|
||||
<i class="glyphicon glyphicon-download" title="<%- @Ti('Download') %>"></i>
|
||||
</a>
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<td><%- @T('Number') %></td>
|
||||
<td><%- @T('Title') %></td>
|
||||
<td><%- @T('State') %></td>
|
||||
<td><%- @T('Queue') %></td>
|
||||
<td><%- @T('Created') %></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% for ticket in @tickets: %>
|
||||
<tr>
|
||||
<td><a target="_blank" href="<%= @url %><%= ticket.id %>"><%- @P(ticket, 'number') %></a></td>
|
||||
<td><%- @P(ticket, 'title') %></td>
|
||||
<td><%- @P(ticket, 'state') %></td>
|
||||
<td><%- @P(ticket, 'group') %></td>
|
||||
<td><%- @P(ticket, 'created_at') %></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
29
app/assets/javascripts/app/views/report/main.jst.eco
Normal file
29
app/assets/javascripts/app/views/report/main.jst.eco
Normal file
|
@ -0,0 +1,29 @@
|
|||
<div class="sidebar"></div>
|
||||
|
||||
<div class="main flex">
|
||||
|
||||
<div class="page-header clearfix">
|
||||
<h1 class="pull-left"><%- @T( 'Reporting' ) %> <small></small></h1>
|
||||
<div class="js-timeRangePicker pull-right" style="margin-top: 20px;"></div>
|
||||
</div>
|
||||
|
||||
<div class="page-content"></div>
|
||||
|
||||
<div id="placeholder" class="" style="width:710px;height:450px;"></div>
|
||||
|
||||
<br>
|
||||
<span class=" muted" id="download-chart" style="font-size: 8px;"></span>
|
||||
<!--
|
||||
<a href="<%-@download%>" target="_blank" data-type="attachment" class="pull-right" id="download-chart">
|
||||
<i class="icon-download" title="<%- @Ti('Download') %>"></i>
|
||||
</a>
|
||||
-->
|
||||
<!--
|
||||
<div id="overview" style="margin-left:50px;margin-top:20px;width:400px;height:50px"></div>
|
||||
-->
|
||||
|
||||
<div class="js-timePicker"></div>
|
||||
<br>
|
||||
<div class="js-dataDownload"></div>
|
||||
</div>
|
||||
</div>
|
33
app/assets/javascripts/app/views/report/sidebar.jst.eco
Normal file
33
app/assets/javascripts/app/views/report/sidebar.jst.eco
Normal file
|
@ -0,0 +1,33 @@
|
|||
<div class="panel-group" id="accordion">
|
||||
<% for key, metric of @metrics: %>
|
||||
<div class="panel panel-default" data-metric="<%= metric.name %>">
|
||||
<div class="panel-heading">
|
||||
<div class="panel-title">
|
||||
<a data-toggle="collapse" data-parent="#accordion" href="#collapse-<%= metric.name %>">
|
||||
<%- @T(metric.display) %>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="collapse-<%= metric.name %>" class="panel-collapse collapse <% if metric.name is @params.metric: %>in<% end %>">
|
||||
<div class="panel-body">
|
||||
<ul class="type area_select">
|
||||
<% for backend in metric.backend: %>
|
||||
<li style="display: block; margin-left: -12px;"><input class="js-backendSelector" type="checkbox" value="<%= backend.name %>" <% if @params.backendSelected[backend.name]: %>checked<% end %>/>
|
||||
<%- @T(backend.display) %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<h3><%- @T('Profiles') %></h3>
|
||||
<ul>
|
||||
<% for profile in @profiles: %>
|
||||
<li style="display: block; margin-left: -12px;"><input class="js-profileSelector" type="radio" name="profile" value="<%= profile.id %>" <% if @params.profileSelected[profile.id]: %>checked<% end %>/>
|
||||
<%= profile.name %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
36
app/assets/javascripts/app/views/report/time_picker.jst.eco
Normal file
36
app/assets/javascripts/app/views/report/time_picker.jst.eco
Normal file
|
@ -0,0 +1,36 @@
|
|||
<div class="">
|
||||
<% if @params.timeRange is 'day': %>
|
||||
<div class="btn-group" role="group" aria-label="">
|
||||
<% for item in @timeRangeDay: %>
|
||||
<button type="button" class="btn btn-default js-timePickerDay <% if @params.day is item.value: %>active<% end %>" data-id="<%= @params.timeRange %>" data-type="<%= item.value %>"><%= item.display %></button>
|
||||
<% end %>
|
||||
</div>
|
||||
<br>
|
||||
<% end %>
|
||||
|
||||
<% if @params.timeRange is 'day' || @params.timeRange is 'month': %>
|
||||
<div class="btn-group" role="group" aria-label="">
|
||||
<% for item in @timeRangeMonth: %>
|
||||
<button type="button" class="btn btn-default js-timePickerMonth <% if @params.month is item.value: %>active<% end %>" data-id="<%= @params.timeRange %>" data-type="<%= item.value %>"><%= item.display %></button>
|
||||
<% end %>
|
||||
</div>
|
||||
<br>
|
||||
<% end %>
|
||||
|
||||
<% if @params.timeRange is 'week': %>
|
||||
<div class="btn-group" role="group" aria-label="">
|
||||
<% for item in @timeRangeWeek: %>
|
||||
<button type="button" class="btn btn-default js-timePickerWeek <% if @params.week is item.value: %>active<% end %>" data-id="<%= @params.timeRange %>" data-type="<%= item.value %>"><%= item.display %></button>
|
||||
<% end %>
|
||||
</div>
|
||||
<br>
|
||||
<% end %>
|
||||
|
||||
<% if @params.timeRange isnt 'realtime': %>
|
||||
<div class="btn-group" role="group" aria-label="">
|
||||
<% for item in @timeRangeYear: %>
|
||||
<button type="button" class="btn btn-default js-timePickerYear <% if @params.year is item.value: %>active<% end %>" data-id="<%= @params.timeRange %>" data-type="<%= item.value %>"><%= item.display %></button>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
|
@ -0,0 +1,7 @@
|
|||
<div class="btn-group">
|
||||
<button type="button" class="btn js-timeRange" data-type="year"><%- @T('Year') %></button>
|
||||
<button type="button" class="btn js-timeRange" data-type="month"><%- @T('Month') %></button>
|
||||
<button type="button" class="btn js-timeRange" data-type="week"><%- @T('Week') %></button>
|
||||
<button type="button" class="btn js-timeRange" data-type="day"><%- @T('Day') %></button>
|
||||
<button type="button" class="btn js-timeRange" data-type="realtime"><%- @T('Realtime') %></button>
|
||||
</div>
|
|
@ -151,7 +151,7 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
def authentication_check_only(auth_param)
|
||||
|
||||
logger.debug 'authentication_check'
|
||||
#logger.debug 'authentication_check'
|
||||
#logger.debug params.inspect
|
||||
#logger.debug session.inspect
|
||||
#logger.debug cookies.inspect
|
||||
|
|
141
app/controllers/report_profiles_controller.rb
Normal file
141
app/controllers/report_profiles_controller.rb
Normal file
|
@ -0,0 +1,141 @@
|
|||
class ReportProfilesController < ApplicationController
|
||||
before_action :authentication_check
|
||||
|
||||
=begin
|
||||
|
||||
Format:
|
||||
JSON
|
||||
|
||||
Example:
|
||||
{
|
||||
"id":1,
|
||||
"name":"some report_profile",
|
||||
"condition":{"c_a":1,"c_b":2},
|
||||
"updated_at":"2012-09-14T17:51:53Z",
|
||||
"created_at":"2012-09-14T17:51:53Z",
|
||||
"updated_by_id":2.
|
||||
"created_by_id":2,
|
||||
}
|
||||
|
||||
=end
|
||||
|
||||
=begin
|
||||
|
||||
Resource:
|
||||
GET /api/report_profiles.json
|
||||
|
||||
Response:
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "some_name1",
|
||||
...
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "some_name2",
|
||||
...
|
||||
}
|
||||
]
|
||||
|
||||
Test:
|
||||
curl http://localhost/api/report_profiles.json -v -u #{login}:#{password}
|
||||
|
||||
=end
|
||||
|
||||
def index
|
||||
model_index_render(Report::Profile, params)
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
Resource:
|
||||
GET /api/report_profiles/#{id}.json
|
||||
|
||||
Response:
|
||||
{
|
||||
"id": 1,
|
||||
"name": "name_1",
|
||||
...
|
||||
}
|
||||
|
||||
Test:
|
||||
curl http://localhost/api/report_profiles/#{id}.json -v -u #{login}:#{password}
|
||||
|
||||
=end
|
||||
|
||||
def show
|
||||
model_show_render(Report::Profile, params)
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
Resource:
|
||||
POST /api/report_profiles.json
|
||||
|
||||
Payload:
|
||||
{
|
||||
"name":"some report_profile",
|
||||
"condition":{"c_a":1,"c_b":2},
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"id": 1,
|
||||
"name": "some_name",
|
||||
...
|
||||
}
|
||||
|
||||
Test:
|
||||
curl http://localhost/api/report_profiles.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST -d '{"name": "some_name","active": true, "note": "some note"}'
|
||||
|
||||
=end
|
||||
|
||||
def create
|
||||
model_create_render(Report::Profile, params)
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
Resource:
|
||||
PUT /api/report_profiles/{id}.json
|
||||
|
||||
Payload:
|
||||
{
|
||||
"name":"some report_profile",
|
||||
"condition":{"c_a":1,"c_b":2},
|
||||
}
|
||||
|
||||
Response:
|
||||
{
|
||||
"id": 1,
|
||||
"name": "some_name",
|
||||
...
|
||||
}
|
||||
|
||||
Test:
|
||||
curl http://localhost/api/report_profiles.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X PUT -d '{"name": "some_name","active": true, "note": "some note"}'
|
||||
|
||||
=end
|
||||
|
||||
def update
|
||||
model_update_render(Report::Profile, params)
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
Resource:
|
||||
DELETE /api/report_profiles/{id}.json
|
||||
|
||||
Response:
|
||||
{}
|
||||
|
||||
Test:
|
||||
curl http://localhost/api/report_profiles.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X DELETE
|
||||
|
||||
=end
|
||||
|
||||
def destroy
|
||||
model_destory_render(Report::Profile, params)
|
||||
end
|
||||
end
|
152
app/controllers/reports_controller.rb
Normal file
152
app/controllers/reports_controller.rb
Normal file
|
@ -0,0 +1,152 @@
|
|||
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
|
||||
|
||||
class ReportsController < ApplicationController
|
||||
before_action :authentication_check
|
||||
|
||||
# GET /api/reports/config
|
||||
def config
|
||||
return if deny_if_not_role('Report')
|
||||
render json: {
|
||||
config: Report.config,
|
||||
profiles: Report::Profile.list,
|
||||
}
|
||||
end
|
||||
|
||||
# GET /api/reports/generate
|
||||
def generate
|
||||
return if deny_if_not_role('Report')
|
||||
|
||||
#{"metric"=>"count", "year"=>2015, "month"=>10, "week"=>43, "day"=>20, "timeSlot"=>"year", "report"=>{"metric"=>"count", "year"=>2015, "month"=>10, "week"=>43, "day"=>20, "timeSlot"=>"year"}}
|
||||
if params[:timeRange] == 'realtime'
|
||||
start = (Time.zone.now - 60.minutes).iso8601
|
||||
stop = Time.zone.now.iso8601
|
||||
created = aggs(start, stop, 'minute', 'created_at')
|
||||
closed = aggs(start, stop, 'minute', 'close_time')
|
||||
elsif params[:timeRange] == 'day'
|
||||
start = Date.parse("#{params[:year]}-#{params[:month]}-#{params[:day]}").iso8601
|
||||
start = "#{start}T00:00:00Z"
|
||||
stop = "#{start}T23:59:59Z"
|
||||
created = aggs(start, stop, 'hour', 'created_at')
|
||||
closed = aggs(start, stop, 'hour', 'close_time')
|
||||
elsif params[:timeRange] == 'week'
|
||||
start = Date.commercial(params[:year], params[:week]).iso8601
|
||||
stop = Date.parse(start).end_of_week
|
||||
created = aggs(start, stop, 'week', 'created_at')
|
||||
closed = aggs(start, stop, 'week', 'close_time')
|
||||
elsif params[:timeRange] == 'month'
|
||||
start = Date.parse("#{params[:year]}-#{params[:month]}-01}").iso8601
|
||||
stop = Date.parse(start).end_of_month
|
||||
created = aggs(start, stop, 'day', 'created_at')
|
||||
closed = aggs(start, stop, 'day', 'close_time')
|
||||
else
|
||||
start = "#{params[:year]}-01-01"
|
||||
stop = "#{params[:year]}-12-31"
|
||||
created = aggs(start, stop, 'month', 'created_at')
|
||||
closed = aggs(start, stop, 'month', 'close_time')
|
||||
end
|
||||
render json: {
|
||||
data: {
|
||||
created: created,
|
||||
closed: closed,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
# GET /api/reports/sets
|
||||
def sets
|
||||
return if deny_if_not_role('Report')
|
||||
|
||||
#{"metric"=>"count", "year"=>2015, "month"=>10, "week"=>43, "day"=>20, "timeSlot"=>"year", "report"=>{"metric"=>"count", "year"=>2015, "month"=>10, "week"=>43, "day"=>20, "timeSlot"=>"year"}}
|
||||
if params[:timeRange] == 'realtime'
|
||||
start = (Time.zone.now - 60.minutes).iso8601
|
||||
stop = Time.zone.now.iso8601
|
||||
elsif params[:timeRange] == 'day'
|
||||
start = Date.parse("#{params[:year]}-#{params[:month]}-#{params[:day]}").iso8601
|
||||
start = "#{start}T00:00:00Z"
|
||||
stop = "#{start}T23:59:59Z"
|
||||
elsif params[:timeRange] == 'week'
|
||||
start = Date.commercial(params[:year], params[:week]).iso8601
|
||||
stop = Date.parse(start).end_of_week
|
||||
elsif params[:timeRange] == 'month'
|
||||
start = Date.parse("#{params[:year]}-#{params[:month]}-01}").iso8601
|
||||
stop = Date.parse(start).end_of_month
|
||||
else
|
||||
start = "#{params[:year]}-01-01"
|
||||
stop = "#{params[:year]}-12-31"
|
||||
end
|
||||
|
||||
# get data
|
||||
|
||||
render json: {
|
||||
data: {
|
||||
start: start,
|
||||
stop: stop,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def aggs(range_start, range_end, interval, field)
|
||||
result = SearchIndexBackend.aggs(
|
||||
{
|
||||
},
|
||||
[range_start, range_end, field, interval],
|
||||
['Ticket'],
|
||||
)
|
||||
data = []
|
||||
if interval == 'month'
|
||||
start = Date.parse(range_start)
|
||||
stop_interval = 12
|
||||
elsif interval == 'week'
|
||||
start = Date.parse(range_start)
|
||||
stop_interval = 7
|
||||
elsif interval == 'day'
|
||||
start = Date.parse(range_start)
|
||||
stop_interval = 31
|
||||
elsif interval == 'hour'
|
||||
start = Time.zone.parse(range_start)
|
||||
stop_interval = 24
|
||||
elsif interval == 'minute'
|
||||
start = Time.zone.parse(range_start)
|
||||
stop_interval = 60
|
||||
end
|
||||
(1..stop_interval).each {|counter|
|
||||
match = false
|
||||
result['aggregations']['time_buckets']['buckets'].each {|item|
|
||||
if interval == 'minute'
|
||||
start_string = start.iso8601.sub(/:\d\d.+?$/, '')
|
||||
else
|
||||
start_string = start.iso8601.sub(/:\d\d:\d\d.+?$/, '')
|
||||
end
|
||||
next if !item['doc_count']
|
||||
next if item['key_as_string'] !~ /#{start_string}/
|
||||
match = true
|
||||
data.push [counter, item['doc_count']]
|
||||
if interval == 'month'
|
||||
start = start.next_month
|
||||
elsif interval == 'week'
|
||||
start = start.next_week
|
||||
elsif interval == 'day'
|
||||
start = start.next_day
|
||||
elsif interval == 'hour'
|
||||
start = start + 1.hour
|
||||
elsif interval == 'minute'
|
||||
start = start + 1.minute
|
||||
end
|
||||
}
|
||||
next if match
|
||||
data.push [counter, 0]
|
||||
if interval == 'month'
|
||||
start = start.next_month
|
||||
elsif interval == 'week'
|
||||
start = start.next_week
|
||||
elsif interval == 'day'
|
||||
start = start + 1.day
|
||||
elsif interval == 'hour'
|
||||
start = start + 1.hour
|
||||
elsif interval == 'minute'
|
||||
start = start + 1.minute
|
||||
end
|
||||
}
|
||||
data
|
||||
end
|
||||
end
|
278
app/models/report.rb
Normal file
278
app/models/report.rb
Normal file
|
@ -0,0 +1,278 @@
|
|||
class Report
|
||||
|
||||
def self.config
|
||||
config = {}
|
||||
config[:metric] = {}
|
||||
|
||||
config[:metric][:count] = {
|
||||
name: 'count',
|
||||
display: 'Ticket Count',
|
||||
default: true,
|
||||
prio: 10_000,
|
||||
}
|
||||
backend = [
|
||||
{
|
||||
name: 'created',
|
||||
display: 'Created',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'closed',
|
||||
display: 'Closed',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'backlog',
|
||||
display: 'Backlog',
|
||||
selected: true,
|
||||
dataDownload: false,
|
||||
},
|
||||
{
|
||||
name: 'first_solution',
|
||||
display: 'First Solution',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'reopen',
|
||||
display: 'Re-Open',
|
||||
selected: false,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'movedin',
|
||||
display: 'Moved in',
|
||||
selected: false,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'movedout',
|
||||
display: 'Moved out',
|
||||
selected: false,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'sla_in',
|
||||
display: 'SLA in',
|
||||
selected: false,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'sla_out',
|
||||
display: 'SLA out',
|
||||
selected: false,
|
||||
dataDownload: true,
|
||||
},
|
||||
]
|
||||
config[:metric][:count][:backend] = backend
|
||||
|
||||
config[:metric][:create_channels] = {
|
||||
name: 'create_channels',
|
||||
display: 'Create Channels',
|
||||
prio: 9000,
|
||||
}
|
||||
backend = [
|
||||
{
|
||||
name: 'phone_in',
|
||||
display: 'Phone (in)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'phone_out',
|
||||
display: 'Phone (out)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'email_in',
|
||||
display: 'Email (in)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'email_out',
|
||||
display: 'Email (out)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'web_in',
|
||||
display: 'Web (in)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'twitter_in',
|
||||
display: 'Twitter (in)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
]
|
||||
config[:metric][:create_channels][:backend] = backend
|
||||
|
||||
config[:metric][:times] = {
|
||||
name: 'times',
|
||||
display: 'Times',
|
||||
prio: 8000,
|
||||
}
|
||||
backend = [
|
||||
{
|
||||
name: 'first_response_average',
|
||||
display: 'First Response average',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'first_response_max',
|
||||
display: 'First Response max',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'first_response_min',
|
||||
display: 'First Response min',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'solution_time_average',
|
||||
display: 'Solution Time average',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'solution_time_max',
|
||||
display: 'Solution Time max',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'solution_time_min',
|
||||
display: 'Solution Time min',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
]
|
||||
config[:metric][:times][:backend] = backend
|
||||
|
||||
config[:metric][:communication] = {
|
||||
name: 'communication',
|
||||
display: 'Communication',
|
||||
prio: 7000,
|
||||
}
|
||||
backend = [
|
||||
{
|
||||
name: 'phone_in',
|
||||
display: 'Phone (in)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'phone_out',
|
||||
display: 'Phone (out)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'email_in',
|
||||
display: 'Email (in)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'email_out',
|
||||
display: 'Email (out)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'web_in',
|
||||
display: 'Web (in)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'twitter_in',
|
||||
display: 'Twitter (in)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'twitter_out',
|
||||
display: 'Twitter (out)',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
]
|
||||
config[:metric][:communication][:backend] = backend
|
||||
|
||||
config[:metric][:sla] = {
|
||||
name: 'sla',
|
||||
display: 'SLAs',
|
||||
prio: 6000,
|
||||
}
|
||||
backend = [
|
||||
{
|
||||
name: 'sla_out_1',
|
||||
display: 'SLA (out) - <1h',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'sla_out_2',
|
||||
display: 'SLA (out) - <2h',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'sla_out_4',
|
||||
display: 'SLA (out) - <4h',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'sla_out_8',
|
||||
display: 'SLA (out) - <8h',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'sla_in_1',
|
||||
display: 'SLA (in) - <1h',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'sla_in_2',
|
||||
display: 'SLA (in) - <2h',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'sla_in_4',
|
||||
display: 'SLA (in) - <4h',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
{
|
||||
name: 'sla_in_8',
|
||||
display: 'SLA (in) - <8h',
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
},
|
||||
]
|
||||
config[:metric][:sla][:backend] = backend
|
||||
|
||||
config[:metric].each {|metric_key, metric_value|
|
||||
metric_value[:backend].each {|metric_backend|
|
||||
metric_backend[:name] = "#{metric_key}::#{metric_backend[:name]}"
|
||||
}
|
||||
}
|
||||
|
||||
config
|
||||
end
|
||||
|
||||
end
|
10
app/models/report/profile.rb
Normal file
10
app/models/report/profile.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
class Report::Profile < ApplicationModel
|
||||
self.table_name = 'report_profiles'
|
||||
validates :name, presence: true
|
||||
store :condition
|
||||
|
||||
def self.list
|
||||
where(active: true)
|
||||
end
|
||||
|
||||
end
|
16
config/routes/report.rb
Normal file
16
config/routes/report.rb
Normal file
|
@ -0,0 +1,16 @@
|
|||
Zammad::Application.routes.draw do
|
||||
api_path = Rails.configuration.api_path
|
||||
|
||||
# reports
|
||||
match api_path + '/reports/config', to: 'reports#config', via: :get
|
||||
match api_path + '/reports/generate', to: 'reports#generate', via: :post
|
||||
match api_path + '/reports/sets', to: 'reports#sets', via: :post
|
||||
|
||||
# report_profiles
|
||||
match api_path + '/report_profiles', to: 'report_profiles#index', via: :get
|
||||
match api_path + '/report_profiles/:id', to: 'report_profiles#show', via: :get
|
||||
match api_path + '/report_profiles', to: 'report_profiles#create', via: :post
|
||||
match api_path + '/report_profiles/:id', to: 'report_profiles#update', via: :put
|
||||
match api_path + '/report_profiles/:id', to: 'report_profiles#destroy', via: :delete
|
||||
|
||||
end
|
63
db/migrate/20151019000001_create_report.rb
Normal file
63
db/migrate/20151019000001_create_report.rb
Normal file
|
@ -0,0 +1,63 @@
|
|||
class CreateReport < ActiveRecord::Migration
|
||||
def up
|
||||
create_table :report_profiles do |t|
|
||||
t.column :name, :string, limit: 150, null: true
|
||||
t.column :condition, :string, limit: 6000, null: true
|
||||
t.column :active, :boolean, null: false, default: true
|
||||
t.column :updated_by_id, :integer, null: false
|
||||
t.column :created_by_id, :integer, null: false
|
||||
t.timestamps null: false
|
||||
end
|
||||
add_index :report_profiles, [:name], unique: true
|
||||
|
||||
Report::Profile.create_if_not_exists(
|
||||
name: '-all-',
|
||||
condition: {},
|
||||
active: true,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
Role.create_if_not_exists( name: 'Report', created_by_id: 1, updated_by_id: 1 )
|
||||
Translation.create_if_not_exists(
|
||||
locale: 'de-de',
|
||||
source: 'Ticket Count',
|
||||
target: 'Ticket Anzahl',
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Translation.create_if_not_exists(
|
||||
locale: 'de-de',
|
||||
source: 'Ticket Count',
|
||||
target: 'Ticket Anzahl',
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Translation.create_if_not_exists(
|
||||
locale: 'de-de',
|
||||
source: 'Create Channels',
|
||||
target: 'Erstellkanäle',
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Translation.create_if_not_exists(
|
||||
locale: 'de-de',
|
||||
source: 'Times',
|
||||
target: 'Zeiten',
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
Translation.create_if_not_exists(
|
||||
locale: 'de-de',
|
||||
source: 'Communication',
|
||||
target: 'Kommunikation',
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def down
|
||||
drop_table :report_profiles
|
||||
end
|
||||
end
|
|
@ -44,7 +44,7 @@ create/update/delete index
|
|||
end
|
||||
|
||||
Rails.logger.info "# curl -X PUT \"#{url}\" \\"
|
||||
#Rails.logger.info "-d '#{data[:data].to_json}'"
|
||||
Rails.logger.debug "-d '#{data[:data].to_json}'"
|
||||
|
||||
response = UserAgent.put(
|
||||
url,
|
||||
|
@ -76,7 +76,7 @@ add new object to search index
|
|||
return if !url
|
||||
|
||||
Rails.logger.info "# curl -X POST \"#{url}\" \\"
|
||||
#Rails.logger.info "-d '#{data.to_json}'"
|
||||
Rails.logger.debug "-d '#{data.to_json}'"
|
||||
|
||||
response = UserAgent.post(
|
||||
url,
|
||||
|
@ -119,7 +119,7 @@ remove whole data from index
|
|||
password: Setting.get('es_password'),
|
||||
}
|
||||
)
|
||||
#Rails.logger.info "# #{response.code.to_s}"
|
||||
Rails.logger.info "# #{response.code}"
|
||||
return true if response.success?
|
||||
#Rails.logger.info "NOTICE: can't drop index: " + response.inspect
|
||||
false
|
||||
|
@ -194,7 +194,7 @@ return search result
|
|||
data['query']['bool']['must'].push condition
|
||||
|
||||
Rails.logger.info "# curl -X POST \"#{url}\" \\"
|
||||
#Rails.logger.info " -d'#{data.to_json}'"
|
||||
Rails.logger.debug " -d'#{data.to_json}'"
|
||||
|
||||
response = UserAgent.get(
|
||||
url,
|
||||
|
@ -232,6 +232,124 @@ return search result
|
|||
|
||||
=begin
|
||||
|
||||
return aggregation result
|
||||
|
||||
result = SearchIndexBackend.aggs(
|
||||
{
|
||||
title: 'test',
|
||||
state_id: 4,
|
||||
},
|
||||
['2014-10-19', '2015-10-19', 'created_at', 'month'],
|
||||
['Ticket'],
|
||||
)
|
||||
|
||||
# year, quarter, month, week, day, hour, minute, second
|
||||
|
||||
result = {
|
||||
hits:{
|
||||
total:4819,
|
||||
},
|
||||
aggregations:{
|
||||
time_buckets:{
|
||||
buckets:[
|
||||
{
|
||||
key_as_string:"2014-10-01T00:00:00.000Z",
|
||||
key:1412121600000,
|
||||
doc_count:420
|
||||
},
|
||||
{
|
||||
key_as_string:"2014-11-01T00:00:00.000Z",
|
||||
key:1414800000000,
|
||||
doc_count:561
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
=end
|
||||
|
||||
def self.aggs(query, range, index = nil)
|
||||
|
||||
url = build_url()
|
||||
return if !url
|
||||
if index
|
||||
if index.class == Array
|
||||
url += "/#{index.join(',')}/_search"
|
||||
else
|
||||
url += "/#{index}/_search"
|
||||
end
|
||||
else
|
||||
url += '/_search'
|
||||
end
|
||||
|
||||
and_data = []
|
||||
if query && !query.empty?
|
||||
bool = {
|
||||
bool: {
|
||||
must: {
|
||||
term: query,
|
||||
},
|
||||
},
|
||||
}
|
||||
and_data.push bool
|
||||
end
|
||||
range_data = {}
|
||||
range_data[range[2]] = {
|
||||
from: range[0],
|
||||
to: range[1],
|
||||
}
|
||||
range_data_and = {
|
||||
range: range_data,
|
||||
}
|
||||
and_data.push range_data_and
|
||||
|
||||
data = {
|
||||
query: {
|
||||
filtered: {
|
||||
filter: {
|
||||
and: and_data,
|
||||
}
|
||||
}
|
||||
},
|
||||
size: 0,
|
||||
aggs: {
|
||||
time_buckets: {
|
||||
date_histogram: {
|
||||
field: range[2],
|
||||
interval: range[3],
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rails.logger.info "# curl -X POST \"#{url}\" \\"
|
||||
Rails.logger.debug " -d'#{data.to_json}'"
|
||||
|
||||
response = UserAgent.get(
|
||||
url,
|
||||
data,
|
||||
{
|
||||
json: true,
|
||||
open_timeout: 5,
|
||||
read_timeout: 14,
|
||||
user: Setting.get('es_user'),
|
||||
password: Setting.get('es_password'),
|
||||
}
|
||||
)
|
||||
|
||||
Rails.logger.info "# #{response.code}"
|
||||
if !response.success?
|
||||
Rails.logger.error "ERROR: #{response.inspect}"
|
||||
return []
|
||||
end
|
||||
Rails.logger.debug response.data.to_json
|
||||
response.data
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
return true if backend is configured
|
||||
|
||||
result = SearchIndexBackend.enabled?
|
||||
|
|
Loading…
Reference in a new issue