Merge branch 'develop' of github.com:martini/zammad into develop
This commit is contained in:
commit
defcd7b820
17 changed files with 482 additions and 247 deletions
|
@ -365,15 +365,16 @@ class App.TicketZoom extends App.Controller
|
||||||
@autosaveLast = @taskGet()
|
@autosaveLast = @taskGet()
|
||||||
update = =>
|
update = =>
|
||||||
#console.log('AR', @formParam( @el.find('.article-add') ) )
|
#console.log('AR', @formParam( @el.find('.article-add') ) )
|
||||||
|
currentStoreTicket = @ticket.attributes()
|
||||||
|
delete currentStoreTicket.article
|
||||||
currentStore =
|
currentStore =
|
||||||
ticket: @ticket.attributes()
|
ticket: currentStoreTicket
|
||||||
article: {
|
article:
|
||||||
to: ''
|
to: ''
|
||||||
cc: ''
|
cc: ''
|
||||||
type: 'note'
|
type: 'note'
|
||||||
body: ''
|
body: ''
|
||||||
internal: ''
|
internal: ''
|
||||||
}
|
|
||||||
currentParams =
|
currentParams =
|
||||||
ticket: @formParam( @el.find('.edit') )
|
ticket: @formParam( @el.find('.edit') )
|
||||||
article: @formParam( @el.find('.article-add') )
|
article: @formParam( @el.find('.article-add') )
|
||||||
|
@ -390,13 +391,13 @@ class App.TicketZoom extends App.Controller
|
||||||
# get diff of last save
|
# get diff of last save
|
||||||
changedBetweenLastSave = _.isEqual(currentParams, @autosaveLast )
|
changedBetweenLastSave = _.isEqual(currentParams, @autosaveLast )
|
||||||
if !changedBetweenLastSave
|
if !changedBetweenLastSave
|
||||||
console.log('model DIFF ', modelDiff)
|
#console.log('model DIFF ', modelDiff)
|
||||||
|
|
||||||
@autosaveLast = clone(currentParams)
|
@autosaveLast = clone(currentParams)
|
||||||
@markFormDiff( modelDiff )
|
@markFormDiff( modelDiff )
|
||||||
|
|
||||||
@taskUpdateAll( modelDiff )
|
@taskUpdateAll( modelDiff )
|
||||||
@interval( update, 3000, 'autosave' )
|
@interval( update, 4000, 'autosave' )
|
||||||
|
|
||||||
markFormDiff: (diff = {}) =>
|
markFormDiff: (diff = {}) =>
|
||||||
ticketForm = @$('.edit')
|
ticketForm = @$('.edit')
|
||||||
|
@ -407,7 +408,7 @@ class App.TicketZoom extends App.Controller
|
||||||
params = {}
|
params = {}
|
||||||
params.ticket = @formParam( ticketForm )
|
params.ticket = @formParam( ticketForm )
|
||||||
params.article = @formParam( articleForm )
|
params.article = @formParam( articleForm )
|
||||||
console.log('markFormDiff', diff, params)
|
#console.log('markFormDiff', diff, params)
|
||||||
|
|
||||||
# clear all changes
|
# clear all changes
|
||||||
if _.isEmpty(diff.ticket) && _.isEmpty(diff.article)
|
if _.isEmpty(diff.ticket) && _.isEmpty(diff.article)
|
||||||
|
|
|
@ -77,7 +77,9 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
|
|
||||||
selectItem: (event) ->
|
selectItem: (event) ->
|
||||||
@input.val event.currentTarget.textContent.trim()
|
@input.val event.currentTarget.textContent.trim()
|
||||||
|
@input.trigger('change')
|
||||||
@shadowInput.val event.currentTarget.getAttribute('data-value')
|
@shadowInput.val event.currentTarget.getAttribute('data-value')
|
||||||
|
@shadowInput.trigger('change')
|
||||||
|
|
||||||
onTab: (event) ->
|
onTab: (event) ->
|
||||||
return if not @isOpen
|
return if not @isOpen
|
||||||
|
@ -93,7 +95,9 @@ class App.SearchableSelect extends Spine.Controller
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
|
|
||||||
@input.val @values.filter('.is-active').text().trim()
|
@input.val @values.filter('.is-active').text().trim()
|
||||||
|
@input.trigger('change')
|
||||||
@shadowInput.val @values.filter('.is-active').attr('data-value')
|
@shadowInput.val @values.filter('.is-active').attr('data-value')
|
||||||
|
@shadowInput.trigger('change')
|
||||||
@toggle()
|
@toggle()
|
||||||
|
|
||||||
filterList: (event) =>
|
filterList: (event) =>
|
||||||
|
|
|
@ -5,7 +5,6 @@ class ApplicationController < ActionController::Base
|
||||||
|
|
||||||
helper_method :current_user,
|
helper_method :current_user,
|
||||||
:authentication_check,
|
:authentication_check,
|
||||||
:authentication_check_action_token,
|
|
||||||
:config_frontend,
|
:config_frontend,
|
||||||
:role?,
|
:role?,
|
||||||
:model_create_render,
|
:model_create_render,
|
||||||
|
@ -96,89 +95,108 @@ class ApplicationController < ActionController::Base
|
||||||
session[:user_agent] = request.env['HTTP_USER_AGENT']
|
session[:user_agent] = request.env['HTTP_USER_AGENT']
|
||||||
end
|
end
|
||||||
|
|
||||||
def authentication_check_only
|
def authentication_check_only(auth_param)
|
||||||
|
|
||||||
logger.debug 'authentication_check'
|
logger.debug 'authentication_check'
|
||||||
session[:request_type] = 1
|
|
||||||
#logger.debug params.inspect
|
#logger.debug params.inspect
|
||||||
#logger.debug session.inspect
|
#logger.debug session.inspect
|
||||||
#logger.debug cookies.inspect
|
#logger.debug cookies.inspect
|
||||||
|
|
||||||
# check http basic auth
|
# already logged in, early exit
|
||||||
authenticate_with_http_basic do |username, password|
|
if session.id && session[:user_id]
|
||||||
logger.debug 'http basic auth check'
|
userdata = User.find( session[:user_id] )
|
||||||
session[:request_type] = 2
|
current_user_set(userdata)
|
||||||
|
|
||||||
userdata = User.authenticate( username, password )
|
return {
|
||||||
message = ''
|
auth: true
|
||||||
if !userdata
|
}
|
||||||
message = 'authentication failed'
|
end
|
||||||
end
|
|
||||||
|
|
||||||
# return auth ok
|
error_message = 'authentication failed'
|
||||||
if message == ''
|
|
||||||
|
|
||||||
# remember user
|
# check logon session
|
||||||
session[:user_id] = userdata.id
|
if params['logon_session']
|
||||||
|
logon_session = ActiveRecord::SessionStore::Session.where( session_id: params['logon_session'] ).first
|
||||||
|
|
||||||
# set basic auth user to current user
|
# set logon session user to current user
|
||||||
|
if logon_session
|
||||||
|
userdata = User.find( logon_session.data[:user_id] )
|
||||||
current_user_set(userdata)
|
current_user_set(userdata)
|
||||||
|
|
||||||
|
session[:persistent] = true
|
||||||
|
|
||||||
return {
|
return {
|
||||||
auth: true
|
auth: true
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# return auth not ok
|
error_message = 'no valid session, user_id'
|
||||||
|
end
|
||||||
|
|
||||||
|
# check sso
|
||||||
|
sso_userdata = User.sso(params)
|
||||||
|
if sso_userdata
|
||||||
|
|
||||||
|
current_user_set(sso_userdata)
|
||||||
|
|
||||||
|
session[:persistent] = true
|
||||||
|
|
||||||
return {
|
return {
|
||||||
auth: false,
|
auth: true
|
||||||
message: message,
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# check logon session
|
# check http basic auth
|
||||||
if params['logon_session']
|
authenticate_with_http_basic do |username, password|
|
||||||
logon_session = ActiveRecord::SessionStore::Session.where( session_id: params['logon_session'] ).first
|
logger.debug "http basic auth check '#{username}'"
|
||||||
if logon_session
|
|
||||||
userdata = User.find( logon_session.data[:user_id] )
|
|
||||||
end
|
|
||||||
|
|
||||||
session[:request_type] = 3
|
userdata = User.authenticate( username, password )
|
||||||
|
|
||||||
# set logon session user to current user
|
next if !userdata
|
||||||
|
|
||||||
|
# set basic auth user to current user
|
||||||
current_user_set(userdata)
|
current_user_set(userdata)
|
||||||
return {
|
return {
|
||||||
auth: true
|
auth: true
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
# check sso
|
# check token
|
||||||
if !session[:user_id]
|
if auth_param[:token_action]
|
||||||
|
authenticate_with_http_token do |token, _options|
|
||||||
|
logger.debug "token auth check #{token}"
|
||||||
|
|
||||||
user = User.sso(params)
|
userdata = Token.check(
|
||||||
|
action: auth_param[:token_action],
|
||||||
|
name: token,
|
||||||
|
)
|
||||||
|
|
||||||
# Log the authorizing user in.
|
next if !userdata
|
||||||
if user
|
|
||||||
session[:user_id] = user.id
|
# set token user to current user
|
||||||
|
current_user_set(userdata)
|
||||||
|
|
||||||
|
return {
|
||||||
|
auth: true
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# return auth not ok (no session exists)
|
logger.debug error_message
|
||||||
if !session[:user_id]
|
|
||||||
logger.debug 'no valid session, user_id'
|
|
||||||
message = 'no valid session, user_id'
|
|
||||||
return {
|
|
||||||
auth: false,
|
|
||||||
message: message,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auth: true
|
auth: false,
|
||||||
|
message: error_message,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def authentication_check
|
def authentication_check( auth_param = {} )
|
||||||
result = authentication_check_only
|
result = authentication_check_only(auth_param)
|
||||||
|
|
||||||
|
# check if basic_auth fallback is possible
|
||||||
|
if auth_param[:basic_auth_promt] && result[:auth] == false
|
||||||
|
|
||||||
|
return request_http_basic_authentication
|
||||||
|
end
|
||||||
|
|
||||||
# return auth not ok
|
# return auth not ok
|
||||||
if result[:auth] == false
|
if result[:auth] == false
|
||||||
|
@ -191,28 +209,13 @@ class ApplicationController < ActionController::Base
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# store current user id into the session
|
||||||
|
session[:user_id] = current_user.id
|
||||||
|
|
||||||
# return auth ok
|
# return auth ok
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def authentication_check_action_token(action)
|
|
||||||
|
|
||||||
user = Token.check(
|
|
||||||
action: action,
|
|
||||||
name: params[:action_token],
|
|
||||||
)
|
|
||||||
|
|
||||||
if !user
|
|
||||||
logger.debug params.inspect
|
|
||||||
response_access_deny
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
current_user_set( user )
|
|
||||||
|
|
||||||
true
|
|
||||||
end
|
|
||||||
|
|
||||||
def role?( role_name )
|
def role?( role_name )
|
||||||
return false if !current_user
|
return false if !current_user
|
||||||
current_user.role?( role_name )
|
current_user.role?( role_name )
|
||||||
|
|
|
@ -3,190 +3,83 @@
|
||||||
require 'icalendar'
|
require 'icalendar'
|
||||||
|
|
||||||
class IcalTicketsController < ApplicationController
|
class IcalTicketsController < ApplicationController
|
||||||
before_action { authentication_check_action_token 'iCal' }
|
before_action { authentication_check( { basic_auth_promt: true, token_action: 'iCal' } ) }
|
||||||
|
|
||||||
# @path [GET] /ical/tickets_all/:action_token
|
# @path [GET] /ical/tickets
|
||||||
#
|
#
|
||||||
# @summary Returns an iCal file with all tickets (open, new, pending, esclation) as events.
|
# @summary Returns an iCal file with all tickets (open, new, pending, esclation) as events.
|
||||||
#
|
#
|
||||||
# @parameter action_token(required) [String] The action_token identifying the requested User privileged for 'iCal' action.
|
|
||||||
#
|
|
||||||
# @response_message 200 [String] iCal file ready to import in calendar applications.
|
# @response_message 200 [String] iCal file ready to import in calendar applications.
|
||||||
# @response_message 401 Permission denied.
|
# @response_message 401 Permission denied.
|
||||||
def all
|
def all
|
||||||
|
new_open_events_data = ICal::Ticket.new_open(current_user)
|
||||||
new_open_events_data = new_open_events_data_get
|
pending_events_data = ICal::Ticket.pending(current_user)
|
||||||
pending_events_data = pending_events_data_get
|
escalation_events_data = ICal::Ticket.escalation(current_user)
|
||||||
escalation_events_data = escalation_events_data_get
|
|
||||||
|
|
||||||
events_data = new_open_events_data + pending_events_data + escalation_events_data
|
events_data = new_open_events_data + pending_events_data + escalation_events_data
|
||||||
|
|
||||||
events_data_to_ical( events_data )
|
ical = ICal.to_ical( events_data )
|
||||||
|
|
||||||
|
send_data(
|
||||||
|
ical,
|
||||||
|
filename: 'zammad_tickets.ical',
|
||||||
|
type: 'text/plain',
|
||||||
|
disposition: 'inline'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @path [GET] /ical/tickets_new_open/:action_token
|
# @path [GET] /ical/tickets_new_open
|
||||||
#
|
#
|
||||||
# @summary Returns an iCal file with all new and open tickets as events.
|
# @summary Returns an iCal file with all new and open tickets as events.
|
||||||
#
|
#
|
||||||
# @parameter action_token(required) [String] The action_token identifying the requested User privileged for 'iCal' action.
|
|
||||||
#
|
|
||||||
# @response_message 200 [String] iCal file ready to import in calendar applications.
|
# @response_message 200 [String] iCal file ready to import in calendar applications.
|
||||||
# @response_message 401 Permission denied.
|
# @response_message 401 Permission denied.
|
||||||
def new_open
|
def new_open
|
||||||
|
events_data = ICal::Ticket.new_open(current_user)
|
||||||
|
|
||||||
events_data = new_open_events_data_get
|
ical = ICal.to_ical( events_data )
|
||||||
|
|
||||||
events_data_to_ical( events_data )
|
send_data(
|
||||||
|
ical,
|
||||||
|
filename: 'zammad_tickets_new_open.ical',
|
||||||
|
type: 'text/plain',
|
||||||
|
disposition: 'inline'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @path [GET] /ical/tickets_pending/:action_token
|
# @path [GET] /ical/tickets_pending
|
||||||
#
|
#
|
||||||
# @summary Returns an iCal file with all pending tickets as events.
|
# @summary Returns an iCal file with all pending tickets as events.
|
||||||
#
|
#
|
||||||
# @parameter action_token(required) [String] The action_token identifying the requested User privileged for 'iCal' action.
|
|
||||||
#
|
|
||||||
# @response_message 200 [String] iCal file ready to import in calendar applications.
|
# @response_message 200 [String] iCal file ready to import in calendar applications.
|
||||||
# @response_message 401 Permission denied.
|
# @response_message 401 Permission denied.
|
||||||
def pending
|
def pending
|
||||||
events_data = pending_events_data_get
|
events_data = ICal::Ticket.pending(current_user)
|
||||||
|
|
||||||
events_data_to_ical( events_data )
|
ical = ICal.to_ical( events_data )
|
||||||
|
|
||||||
|
send_data(
|
||||||
|
ical,
|
||||||
|
filename: 'zammad_tickets_pending.ical',
|
||||||
|
type: 'text/plain',
|
||||||
|
disposition: 'inline'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# @path [GET] /ical/ticket_escalation/:action_token
|
# @path [GET] /ical/ticket_escalation
|
||||||
#
|
#
|
||||||
# @summary Returns an iCal file with all escalation times for tickets as events.
|
# @summary Returns an iCal file with all escalation times for tickets as events.
|
||||||
#
|
#
|
||||||
# @parameter action_token(required) [String] The action_token identifying the requested User privileged for 'iCal' action.
|
|
||||||
#
|
|
||||||
# @response_message 200 [String] iCal file ready to import in calendar applications.
|
# @response_message 200 [String] iCal file ready to import in calendar applications.
|
||||||
# @response_message 401 Permission denied.
|
# @response_message 401 Permission denied.
|
||||||
def escalation
|
def escalation
|
||||||
events_data = escalation_events_data_get
|
events_data = ICal::Ticket.escalation(current_user)
|
||||||
|
|
||||||
events_data_to_ical( events_data )
|
ical = ICal.to_ical( events_data )
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def new_open_events_data_get
|
|
||||||
|
|
||||||
condition = {
|
|
||||||
'tickets.owner_id' => current_user.id,
|
|
||||||
'tickets.state_id' => Ticket::State.where(
|
|
||||||
state_type_id: Ticket::StateType.where(
|
|
||||||
name: %w(new open),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
tickets = Ticket.search(
|
|
||||||
current_user: current_user,
|
|
||||||
condition: condition,
|
|
||||||
)
|
|
||||||
|
|
||||||
events_data = []
|
|
||||||
tickets.each do |ticket|
|
|
||||||
|
|
||||||
event_data = {}
|
|
||||||
|
|
||||||
event_data[:dtstart] = Icalendar::Values::Date.new( Time.zone.today )
|
|
||||||
event_data[:dtend] = Icalendar::Values::Date.new( Time.zone.today )
|
|
||||||
event_data[:summary] = "#{ ticket.state.name } ticket: '#{ ticket.title }'"
|
|
||||||
event_data[:description] = "T##{ ticket.number }"
|
|
||||||
|
|
||||||
events_data.push event_data
|
|
||||||
end
|
|
||||||
|
|
||||||
events_data
|
|
||||||
end
|
|
||||||
|
|
||||||
def pending_events_data_get
|
|
||||||
|
|
||||||
condition = {
|
|
||||||
'tickets.owner_id' => current_user.id,
|
|
||||||
'tickets.state_id' => Ticket::State.where(
|
|
||||||
state_type_id: Ticket::StateType.where(
|
|
||||||
name: [
|
|
||||||
'pending reminder',
|
|
||||||
'pending action',
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
tickets = Ticket.search(
|
|
||||||
current_user: current_user,
|
|
||||||
condition: condition,
|
|
||||||
)
|
|
||||||
|
|
||||||
events_data = []
|
|
||||||
tickets.each do |ticket|
|
|
||||||
|
|
||||||
event_data = {}
|
|
||||||
|
|
||||||
# rubocop:disable Rails/TimeZone
|
|
||||||
event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.pending_time )
|
|
||||||
event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.pending_time )
|
|
||||||
# rubocop:enable Rails/TimeZone
|
|
||||||
event_data[:summary] = "#{ ticket.state.name } ticket: '#{ ticket.title }'"
|
|
||||||
event_data[:description] = "T##{ ticket.number }"
|
|
||||||
|
|
||||||
events_data.push event_data
|
|
||||||
end
|
|
||||||
|
|
||||||
events_data
|
|
||||||
end
|
|
||||||
|
|
||||||
def escalation_events_data_get
|
|
||||||
|
|
||||||
condition = [
|
|
||||||
'tickets.escalation_time IS NOT NULL',
|
|
||||||
'tickets.owner_id = ?', current_user.id
|
|
||||||
]
|
|
||||||
|
|
||||||
tickets = Ticket.search(
|
|
||||||
current_user: current_user,
|
|
||||||
condition: condition,
|
|
||||||
)
|
|
||||||
|
|
||||||
events_data = []
|
|
||||||
tickets.each do |ticket|
|
|
||||||
|
|
||||||
event_data = {}
|
|
||||||
|
|
||||||
# rubocop:disable Rails/TimeZone
|
|
||||||
event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.escalation_time )
|
|
||||||
event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.escalation_time )
|
|
||||||
# rubocop:enable Rails/TimeZone
|
|
||||||
event_data[:summary] = "ticket escalation: '#{ ticket.title }'"
|
|
||||||
event_data[:description] = "T##{ ticket.number }"
|
|
||||||
|
|
||||||
events_data.push event_data
|
|
||||||
end
|
|
||||||
|
|
||||||
events_data
|
|
||||||
end
|
|
||||||
|
|
||||||
def events_data_to_ical(events_data)
|
|
||||||
|
|
||||||
cal = Icalendar::Calendar.new
|
|
||||||
|
|
||||||
events_data.each do |event_data|
|
|
||||||
|
|
||||||
cal.event do |e|
|
|
||||||
e.dtstart = event_data[:dtstart]
|
|
||||||
e.dtend = event_data[:dtend]
|
|
||||||
e.summary = event_data[:summary]
|
|
||||||
e.description = event_data[:description]
|
|
||||||
e.ip_class = 'PRIVATE'
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
send_data(
|
send_data(
|
||||||
cal.to_ical,
|
ical,
|
||||||
filename: 'zammad.ical',
|
filename: 'zammad_tickets_escalation.ical',
|
||||||
type: 'text/plain',
|
type: 'text/plain',
|
||||||
disposition: 'inline'
|
disposition: 'inline'
|
||||||
)
|
)
|
||||||
|
|
|
@ -54,6 +54,10 @@ class SessionsController < ApplicationController
|
||||||
# )
|
# )
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# sessions created via this
|
||||||
|
# controller are persistent
|
||||||
|
session[:persistent] = true
|
||||||
|
|
||||||
# return new session data
|
# return new session data
|
||||||
render status: :created,
|
render status: :created,
|
||||||
json: {
|
json: {
|
||||||
|
|
|
@ -329,7 +329,6 @@ class TicketsController < ApplicationController
|
||||||
query: params[:term],
|
query: params[:term],
|
||||||
condition: params[:condition],
|
condition: params[:condition],
|
||||||
current_user: current_user,
|
current_user: current_user,
|
||||||
detail: params[:detail]
|
|
||||||
)
|
)
|
||||||
assets = {}
|
assets = {}
|
||||||
ticket_result = []
|
ticket_result = []
|
||||||
|
@ -372,10 +371,8 @@ class TicketsController < ApplicationController
|
||||||
}
|
}
|
||||||
user_tickets_open = Ticket.search(
|
user_tickets_open = Ticket.search(
|
||||||
limit: limit,
|
limit: limit,
|
||||||
#:query => params[:term],
|
|
||||||
condition: condition,
|
condition: condition,
|
||||||
current_user: current_user,
|
current_user: current_user,
|
||||||
detail: true,
|
|
||||||
)
|
)
|
||||||
user_tickets_open_ids = assets_of_tickets(user_tickets_open, assets)
|
user_tickets_open_ids = assets_of_tickets(user_tickets_open, assets)
|
||||||
|
|
||||||
|
@ -386,10 +383,8 @@ class TicketsController < ApplicationController
|
||||||
}
|
}
|
||||||
user_tickets_closed = Ticket.search(
|
user_tickets_closed = Ticket.search(
|
||||||
limit: limit,
|
limit: limit,
|
||||||
#:query => params[:term],
|
|
||||||
condition: condition,
|
condition: condition,
|
||||||
current_user: current_user,
|
current_user: current_user,
|
||||||
detail: true,
|
|
||||||
)
|
)
|
||||||
user_tickets_closed_ids = assets_of_tickets(user_tickets_closed, assets)
|
user_tickets_closed_ids = assets_of_tickets(user_tickets_closed, assets)
|
||||||
|
|
||||||
|
@ -438,10 +433,8 @@ class TicketsController < ApplicationController
|
||||||
}
|
}
|
||||||
org_tickets_open = Ticket.search(
|
org_tickets_open = Ticket.search(
|
||||||
limit: limit,
|
limit: limit,
|
||||||
#:query => params[:term],
|
|
||||||
condition: condition,
|
condition: condition,
|
||||||
current_user: current_user,
|
current_user: current_user,
|
||||||
detail: true,
|
|
||||||
)
|
)
|
||||||
org_tickets_open_ids = assets_of_tickets(org_tickets_open, assets)
|
org_tickets_open_ids = assets_of_tickets(org_tickets_open, assets)
|
||||||
|
|
||||||
|
@ -452,10 +445,8 @@ class TicketsController < ApplicationController
|
||||||
}
|
}
|
||||||
org_tickets_closed = Ticket.search(
|
org_tickets_closed = Ticket.search(
|
||||||
limit: limit,
|
limit: limit,
|
||||||
#:query => params[:term],
|
|
||||||
condition: condition,
|
condition: condition,
|
||||||
current_user: current_user,
|
current_user: current_user,
|
||||||
detail: true,
|
|
||||||
)
|
)
|
||||||
org_tickets_closed_ids = assets_of_tickets(org_tickets_closed, assets)
|
org_tickets_closed_ids = assets_of_tickets(org_tickets_closed, assets)
|
||||||
|
|
||||||
|
|
|
@ -13,15 +13,17 @@ class Observer::Session < ActiveRecord::Observer
|
||||||
check(record)
|
check(record)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# move the persistent attribute from the sub structure
|
||||||
|
# to the first level so it gets stored in the database
|
||||||
|
# column to make the cleanup lookup more performant
|
||||||
def check(record)
|
def check(record)
|
||||||
return if !record.data
|
return if !record.data
|
||||||
return if record[:request_type]
|
return if record[:persistent]
|
||||||
|
|
||||||
# remember request type
|
return if !record.data['persistent']
|
||||||
return if !record.data['request_type']
|
|
||||||
|
|
||||||
record[:request_type] = record.data['request_type']
|
record[:persistent] = record.data['persistent']
|
||||||
record.data.delete('request_type')
|
record.data.delete('persistent')
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,7 +22,7 @@ search tickets via search index
|
||||||
:current_user => User.find(123),
|
:current_user => User.find(123),
|
||||||
:query => 'search something',
|
:query => 'search something',
|
||||||
:limit => 15,
|
:limit => 15,
|
||||||
:full => 0
|
:full => false,
|
||||||
)
|
)
|
||||||
|
|
||||||
returns
|
returns
|
||||||
|
@ -33,10 +33,19 @@ search tickets via database
|
||||||
|
|
||||||
result = Ticket.search(
|
result = Ticket.search(
|
||||||
:current_user => User.find(123),
|
:current_user => User.find(123),
|
||||||
:condition => '',
|
:condition => {
|
||||||
:detail => true,
|
'tickets.owner_id' => user.id,
|
||||||
|
'tickets.state_id' => Ticket::State.where(
|
||||||
|
state_type_id: Ticket::StateType.where(
|
||||||
|
name: [
|
||||||
|
'pending reminder',
|
||||||
|
'pending action',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
:limit => 15,
|
:limit => 15,
|
||||||
:full => 0
|
:full => false,
|
||||||
)
|
)
|
||||||
|
|
||||||
returns
|
returns
|
||||||
|
@ -57,7 +66,7 @@ returns
|
||||||
end
|
end
|
||||||
|
|
||||||
# try search index backend
|
# try search index backend
|
||||||
if !params[:detail] && SearchIndexBackend.enabled?
|
if !params[:condition] && SearchIndexBackend.enabled?
|
||||||
query_extention = {}
|
query_extention = {}
|
||||||
query_extention['bool'] = {}
|
query_extention['bool'] = {}
|
||||||
query_extention['bool']['must'] = []
|
query_extention['bool']['must'] = []
|
||||||
|
|
|
@ -21,7 +21,7 @@ class Token < ActiveRecord::Base
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
# return token if valid
|
# return token user
|
||||||
token.user
|
token.user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ Zammad::Application.routes.draw do
|
||||||
api_path = Rails.configuration.api_path
|
api_path = Rails.configuration.api_path
|
||||||
|
|
||||||
# ical ticket
|
# ical ticket
|
||||||
match api_path + '/ical/tickets/:action_token', to: 'ical_tickets#all', via: :get
|
match api_path + '/ical/tickets', to: 'ical_tickets#all', via: :get
|
||||||
match api_path + '/ical/tickets_new_open/:action_token', to: 'ical_tickets#new_open', via: :get
|
match api_path + '/ical/tickets_new_open', to: 'ical_tickets#new_open', via: :get
|
||||||
match api_path + '/ical/tickets_pending/:action_token', to: 'ical_tickets#pending', via: :get
|
match api_path + '/ical/tickets_pending', to: 'ical_tickets#pending', via: :get
|
||||||
match api_path + '/ical/tickets_escalation/:action_token', to: 'ical_tickets#escalation', via: :get
|
match api_path + '/ical/tickets_escalation', to: 'ical_tickets#escalation', via: :get
|
||||||
end
|
end
|
||||||
|
|
24
db/migrate/20150623145511_session_changes.rb
Normal file
24
db/migrate/20150623145511_session_changes.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
class SessionChanges < ActiveRecord::Migration
|
||||||
|
def up
|
||||||
|
|
||||||
|
ActiveRecord::SessionStore::Session.delete_all
|
||||||
|
|
||||||
|
remove_index :sessions, :request_type
|
||||||
|
remove_column :sessions, :request_type
|
||||||
|
|
||||||
|
add_column :sessions, :persistent, :boolean, null: true
|
||||||
|
add_index :sessions, :persistent
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
|
||||||
|
ActiveRecord::SessionStore::Session.delete_all
|
||||||
|
|
||||||
|
remove_index :sessions, :persistent
|
||||||
|
remove_column :sessions, :persistent
|
||||||
|
|
||||||
|
add_column :sessions, :request_type, :integer, null: true
|
||||||
|
add_index :sessions, :request_type
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
24
lib/i_cal.rb
Normal file
24
lib/i_cal.rb
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
module ICal
|
||||||
|
|
||||||
|
def self.to_ical(events_data)
|
||||||
|
|
||||||
|
cal = Icalendar::Calendar.new
|
||||||
|
|
||||||
|
events_data.each do |event_data|
|
||||||
|
|
||||||
|
cal.event do |e|
|
||||||
|
e.dtstart = event_data[:dtstart]
|
||||||
|
e.dtend = event_data[:dtend]
|
||||||
|
e.summary = event_data[:summary]
|
||||||
|
e.description = event_data[:description]
|
||||||
|
e.ip_class = 'PRIVATE'
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
cal.to_ical
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
108
lib/i_cal/ticket.rb
Normal file
108
lib/i_cal/ticket.rb
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
|
||||||
|
|
||||||
|
module ICal::Ticket
|
||||||
|
|
||||||
|
def self.new_open(user)
|
||||||
|
|
||||||
|
condition = {
|
||||||
|
'tickets.owner_id' => user.id,
|
||||||
|
'tickets.state_id' => Ticket::State.where(
|
||||||
|
state_type_id: Ticket::StateType.where(
|
||||||
|
name: %w(new open),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
tickets = Ticket.search(
|
||||||
|
current_user: user,
|
||||||
|
condition: condition,
|
||||||
|
)
|
||||||
|
|
||||||
|
events_data = []
|
||||||
|
tickets.each do |ticket|
|
||||||
|
|
||||||
|
event_data = {}
|
||||||
|
|
||||||
|
event_data[:dtstart] = Icalendar::Values::Date.new( Time.zone.today )
|
||||||
|
event_data[:dtend] = Icalendar::Values::Date.new( Time.zone.today )
|
||||||
|
event_data[:summary] = "#{ticket.state.name} ticket: '#{ticket.title}'"
|
||||||
|
event_data[:description] = "T##{ticket.number}"
|
||||||
|
|
||||||
|
events_data.push event_data
|
||||||
|
end
|
||||||
|
|
||||||
|
events_data
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.pending(user)
|
||||||
|
|
||||||
|
condition = {
|
||||||
|
'tickets.owner_id' => user.id,
|
||||||
|
'tickets.state_id' => Ticket::State.where(
|
||||||
|
state_type_id: Ticket::StateType.where(
|
||||||
|
name: [
|
||||||
|
'pending reminder',
|
||||||
|
'pending action',
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
tickets = Ticket.search(
|
||||||
|
current_user: user,
|
||||||
|
condition: condition,
|
||||||
|
)
|
||||||
|
|
||||||
|
events_data = []
|
||||||
|
tickets.each do |ticket|
|
||||||
|
|
||||||
|
next if !ticket.pending_time
|
||||||
|
|
||||||
|
event_data = {}
|
||||||
|
|
||||||
|
# rubocop:disable Rails/TimeZone
|
||||||
|
event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.pending_time )
|
||||||
|
event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.pending_time )
|
||||||
|
# rubocop:enable Rails/TimeZone
|
||||||
|
event_data[:summary] = "#{ticket.state.name} ticket: '#{ticket.title}'"
|
||||||
|
event_data[:description] = "T##{ticket.number}"
|
||||||
|
|
||||||
|
events_data.push event_data
|
||||||
|
end
|
||||||
|
|
||||||
|
events_data
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.escalation(user)
|
||||||
|
|
||||||
|
condition = [
|
||||||
|
'tickets.escalation_time IS NOT NULL',
|
||||||
|
'tickets.owner_id = ?', user.id
|
||||||
|
]
|
||||||
|
|
||||||
|
tickets = Ticket.search(
|
||||||
|
current_user: user,
|
||||||
|
condition: condition,
|
||||||
|
)
|
||||||
|
|
||||||
|
events_data = []
|
||||||
|
tickets.each do |ticket|
|
||||||
|
|
||||||
|
next if !ticket.escalation_time
|
||||||
|
|
||||||
|
event_data = {}
|
||||||
|
|
||||||
|
# rubocop:disable Rails/TimeZone
|
||||||
|
event_data[:dtstart] = Icalendar::Values::DateTime.new( ticket.escalation_time )
|
||||||
|
event_data[:dtend] = Icalendar::Values::DateTime.new( ticket.escalation_time )
|
||||||
|
# rubocop:enable Rails/TimeZone
|
||||||
|
event_data[:summary] = "ticket escalation: '#{ticket.title}'"
|
||||||
|
event_data[:description] = "T##{ticket.number}"
|
||||||
|
|
||||||
|
events_data.push event_data
|
||||||
|
end
|
||||||
|
|
||||||
|
events_data
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -28,11 +28,12 @@ module SessionHelper
|
||||||
|
|
||||||
def self.cleanup_expired
|
def self.cleanup_expired
|
||||||
|
|
||||||
# web sessions
|
# delete temp. sessions
|
||||||
ActiveRecord::SessionStore::Session.where('request_type = ? AND updated_at < ?', 1, Time.zone.now - 90.days ).delete_all
|
ActiveRecord::SessionStore::Session.where('persistent IS NULL AND updated_at < ?', Time.zone.now - 1.days ).delete_all
|
||||||
|
|
||||||
|
# web sessions older the x days
|
||||||
|
ActiveRecord::SessionStore::Session.where('updated_at < ?', Time.zone.now - 90.days ).delete_all
|
||||||
|
|
||||||
# http basic auth calls
|
|
||||||
ActiveRecord::SessionStore::Session.where('request_type = ? AND updated_at < ?', 2, Time.zone.now - 2.days ).delete_all
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.get(id)
|
def self.get(id)
|
||||||
|
|
|
@ -65,7 +65,7 @@ class PreferencesTest < TestCase
|
||||||
click( css: '#navigation a[href="#dashboard"]' )
|
click( css: '#navigation a[href="#dashboard"]' )
|
||||||
watch_for(
|
watch_for(
|
||||||
css: '.content.active',
|
css: '.content.active',
|
||||||
value: 'Meine zugewiesenen'
|
value: 'Meine Statistik'
|
||||||
)
|
)
|
||||||
|
|
||||||
# check language in overview
|
# check language in overview
|
||||||
|
@ -179,7 +179,7 @@ class PreferencesTest < TestCase
|
||||||
click( css: '#navigation a[href="#dashboard"]' )
|
click( css: '#navigation a[href="#dashboard"]' )
|
||||||
watch_for(
|
watch_for(
|
||||||
css: '.content.active',
|
css: '.content.active',
|
||||||
value: 'My assig'
|
value: 'My Stats'
|
||||||
)
|
)
|
||||||
|
|
||||||
# check language in overview
|
# check language in overview
|
||||||
|
@ -305,7 +305,7 @@ class PreferencesTest < TestCase
|
||||||
click( css: '#navigation a[href="#dashboard"]' )
|
click( css: '#navigation a[href="#dashboard"]' )
|
||||||
watch_for(
|
watch_for(
|
||||||
css: '.content.active',
|
css: '.content.active',
|
||||||
value: 'Meine'
|
value: 'Meine Statistik'
|
||||||
)
|
)
|
||||||
|
|
||||||
# check language in overview
|
# check language in overview
|
||||||
|
|
|
@ -1225,7 +1225,7 @@ wait untill text in selector disabppears
|
||||||
|
|
||||||
if data[:state] || data[:group] || data[:body]
|
if data[:state] || data[:group] || data[:body]
|
||||||
found = nil
|
found = nil
|
||||||
(1..5).each {
|
(1..10).each {
|
||||||
if !found
|
if !found
|
||||||
begin
|
begin
|
||||||
text = instance.find_elements( { css: '.content.active .js-reset' } )[0].text
|
text = instance.find_elements( { css: '.content.active .js-reset' } )[0].text
|
||||||
|
|
171
test/integration/i_cal_ticket_test.rb
Normal file
171
test/integration/i_cal_ticket_test.rb
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require 'integration_test_helper'
|
||||||
|
|
||||||
|
class ICalTicketTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
|
user = User.create(
|
||||||
|
firstname: 'iCal',
|
||||||
|
lastname: 'Testuser',
|
||||||
|
email: 'ical_testuser@example.com',
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
sla = Sla.create(
|
||||||
|
name: 'sla 1',
|
||||||
|
condition: {},
|
||||||
|
data: {
|
||||||
|
'Mon' => 'Mon', 'Tue' => 'Tue', 'Wed' => 'Wed', 'Thu' => 'Thu', 'Fri' => 'Fri', 'Sat' => 'Sat', 'Sun' => 'Sun',
|
||||||
|
'beginning_of_workday' => '9:00',
|
||||||
|
'end_of_workday' => '18:00',
|
||||||
|
},
|
||||||
|
timezone: 'Europe/Berlin',
|
||||||
|
first_response_time: 10,
|
||||||
|
update_time: 10,
|
||||||
|
close_time: 10,
|
||||||
|
active: true,
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
)
|
||||||
|
|
||||||
|
tickets = [
|
||||||
|
{
|
||||||
|
owner: user,
|
||||||
|
title: 'new 1',
|
||||||
|
group: Group.lookup( name: 'Users'),
|
||||||
|
customer_id: user.id,
|
||||||
|
state: Ticket::State.lookup( name: 'new' ),
|
||||||
|
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
owner: user,
|
||||||
|
title: 'open 1',
|
||||||
|
group: Group.lookup( name: 'Users'),
|
||||||
|
customer_id: user.id,
|
||||||
|
state: Ticket::State.lookup( name: 'open' ),
|
||||||
|
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
owner: user,
|
||||||
|
title: 'pending reminder 1',
|
||||||
|
group: Group.lookup( name: 'Users'),
|
||||||
|
customer_id: user.id,
|
||||||
|
state: Ticket::State.lookup( name: 'pending reminder' ),
|
||||||
|
pending_time: Time.zone.parse('1977-10-27 22:00:00 +0000'),
|
||||||
|
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
owner: user,
|
||||||
|
title: 'pending reminder 2',
|
||||||
|
group: Group.lookup( name: 'Users'),
|
||||||
|
customer_id: user.id,
|
||||||
|
state: Ticket::State.lookup( name: 'pending reminder' ),
|
||||||
|
pending_time: DateTime.tomorrow,
|
||||||
|
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
owner: user,
|
||||||
|
title: 'pending close 1',
|
||||||
|
group: Group.lookup( name: 'Users'),
|
||||||
|
customer_id: user.id,
|
||||||
|
state: Ticket::State.lookup( name: 'pending close' ),
|
||||||
|
pending_time: Time.zone.parse('1977-10-27 22:00:00 +0000'),
|
||||||
|
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
owner: user,
|
||||||
|
title: 'pending close 2',
|
||||||
|
group: Group.lookup( name: 'Users'),
|
||||||
|
customer_id: user.id,
|
||||||
|
state: Ticket::State.lookup( name: 'pending close' ),
|
||||||
|
pending_time: DateTime.tomorrow,
|
||||||
|
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
owner: user,
|
||||||
|
title: 'escalation 1',
|
||||||
|
group: Group.lookup( name: 'Users'),
|
||||||
|
customer_id: user.id,
|
||||||
|
state: Ticket::State.lookup( name: 'open' ),
|
||||||
|
priority: Ticket::Priority.lookup( name: '2 normal' ),
|
||||||
|
created_at: '2013-03-21 09:30:00 UTC',
|
||||||
|
updated_at: '2013-03-21 09:30:00 UTC',
|
||||||
|
updated_by_id: 1,
|
||||||
|
created_by_id: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
tickets.each { |ticket|
|
||||||
|
|
||||||
|
Ticket.create( ticket )
|
||||||
|
}
|
||||||
|
|
||||||
|
test 'new_open' do
|
||||||
|
|
||||||
|
event_data = ICal::Ticket.new_open( user )
|
||||||
|
|
||||||
|
assert_equal( 3, event_data.length, 'event count' )
|
||||||
|
|
||||||
|
ical = ICal.to_ical( event_data )
|
||||||
|
|
||||||
|
event_data.each{ |event|
|
||||||
|
|
||||||
|
contained = false
|
||||||
|
if ical =~ /#{event[:summary]}/
|
||||||
|
contained = true
|
||||||
|
end
|
||||||
|
|
||||||
|
assert( contained, "ical contains '#{event[:summary]}'" )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'pending' do
|
||||||
|
|
||||||
|
event_data = ICal::Ticket.pending( user )
|
||||||
|
|
||||||
|
assert_equal( 4, event_data.length, 'event count' )
|
||||||
|
|
||||||
|
ical = ICal.to_ical( event_data )
|
||||||
|
|
||||||
|
event_data.each{ |event|
|
||||||
|
|
||||||
|
contained = false
|
||||||
|
if ical =~ /#{event[:summary]}/
|
||||||
|
contained = true
|
||||||
|
end
|
||||||
|
|
||||||
|
assert( contained, "ical contains '#{event[:summary]}'" )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
test 'escalation' do
|
||||||
|
|
||||||
|
event_data = ICal::Ticket.escalation( user )
|
||||||
|
|
||||||
|
assert_equal( 7, event_data.length, 'event count' )
|
||||||
|
|
||||||
|
ical = ICal.to_ical( event_data )
|
||||||
|
|
||||||
|
event_data.each{ |event|
|
||||||
|
|
||||||
|
contained = false
|
||||||
|
if ical =~ /#{event[:summary]}/
|
||||||
|
contained = true
|
||||||
|
end
|
||||||
|
|
||||||
|
assert( contained, "ical contains '#{event[:summary]}'" )
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue