Some new rubocop checks.

This commit is contained in:
Martin Edenhofer 2015-04-27 23:27:51 +02:00
parent 5b98be93e1
commit a2d49cefc5
26 changed files with 1178 additions and 1138 deletions

View file

@ -31,11 +31,10 @@ returns
return data if !self['created_by_id'] && !self['updated_by_id'] return data if !self['created_by_id'] && !self['updated_by_id']
['created_by_id', 'updated_by_id'].each {|item| ['created_by_id', 'updated_by_id'].each {|item|
if self[ item ] next if !self[ item ]
if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ] if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ]
user = User.lookup( id: self[ item ] ) user = User.lookup( id: self[ item ] )
data = user.assets( data ) data = user.assets( data )
end
end end
} }
data data

View file

@ -16,7 +16,6 @@ class Locale < ApplicationModel
raise "Can't load locales from #{url}: #{result.error}" if !result.success? raise "Can't load locales from #{url}: #{result.error}" if !result.success?
result.data.each {|locale| result.data.each {|locale|
puts locale.inspect
exists = Locale.where(locale: locale['locale']).first exists = Locale.where(locale: locale['locale']).first
if exists if exists
exists.update(locale.symbolize_keys!) exists.update(locale.symbolize_keys!)

View file

@ -40,11 +40,10 @@ returns
end end
end end
['created_by_id', 'updated_by_id'].each {|item| ['created_by_id', 'updated_by_id'].each {|item|
if self[ item ] next if !self[ item ]
if !data[ User.to_app_model ][ self[ item ] ] if !data[ User.to_app_model ][ self[ item ] ]
user = User.lookup( id: self[ item ] ) user = User.lookup( id: self[ item ] )
data = user.assets( data ) data = user.assets( data )
end
end end
} }
data data

View file

@ -1,6 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::ActivityStreamLog class Ticket
module ActivityStreamLog
=begin =begin
@ -15,25 +16,25 @@ returns
=end =end
def activity_stream_log (type, user_id) def activity_stream_log (type, user_id)
# return if we run import mode # return if we run import mode
return if Setting.get('import_mode') return if Setting.get('import_mode')
# return if we run on init mode # return if we run on init mode
return if !Setting.get('system_init_done') return if !Setting.get('system_init_done')
return if !self.class.activity_stream_support_config return if !self.class.activity_stream_support_config
role = self.class.activity_stream_support_config[:role] role = self.class.activity_stream_support_config[:role]
ActivityStream.add( ActivityStream.add(
o_id: self['id'], o_id: self['id'],
type: type, type: type,
object: self.class.name, object: self.class.name,
group_id: self['group_id'], group_id: self['group_id'],
role: role, role: role,
created_at: self.updated_at, created_at: self.updated_at,
created_by_id: user_id, created_by_id: user_id,
) )
end
end end
end end

View file

@ -1,50 +1,52 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Ticket::Article < ApplicationModel class Ticket
load 'ticket/article/assets.rb' class Article < ApplicationModel
include Ticket::Article::Assets load 'ticket/article/assets.rb'
load 'ticket/article/history_log.rb' include Ticket::Article::Assets
include Ticket::Article::HistoryLog load 'ticket/article/history_log.rb'
load 'ticket/article/activity_stream_log.rb' include Ticket::Article::HistoryLog
include Ticket::Article::ActivityStreamLog load 'ticket/article/activity_stream_log.rb'
include Ticket::Article::ActivityStreamLog
belongs_to :ticket belongs_to :ticket
belongs_to :type, class_name: 'Ticket::Article::Type' belongs_to :type, class_name: 'Ticket::Article::Type'
belongs_to :sender, class_name: 'Ticket::Article::Sender' belongs_to :sender, class_name: 'Ticket::Article::Sender'
belongs_to :created_by, class_name: 'User' belongs_to :created_by, class_name: 'User'
belongs_to :updated_by, class_name: 'User' belongs_to :updated_by, class_name: 'User'
before_create :check_subject before_create :check_subject
before_update :check_subject before_update :check_subject
notify_clients_support notify_clients_support
activity_stream_support ignore_attributes: { activity_stream_support ignore_attributes: {
type_id: true, type_id: true,
sender_id: true, sender_id: true,
} }
history_support ignore_attributes: { history_support ignore_attributes: {
type_id: true, type_id: true,
sender_id: true, sender_id: true,
} }
private private
def check_subject def check_subject
if self.subject if self.subject
self.subject.gsub!(/\s|\t|\r/, ' ') self.subject.gsub!(/\s|\t|\r/, ' ')
end
end
class Flag < ApplicationModel
end
class Sender < ApplicationModel
validates :name, presence: true
latest_change_support
end
class Type < ApplicationModel
validates :name, presence: true
latest_change_support
end end
end end
class Flag < ApplicationModel
end
class Sender < ApplicationModel
validates :name, presence: true
latest_change_support
end
class Type < ApplicationModel
validates :name, presence: true
latest_change_support
end
end end

View file

@ -1,6 +1,8 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Article::ActivityStreamLog class Ticket
class Article
module ActivityStreamLog
=begin =begin
@ -15,26 +17,27 @@ returns
=end =end
def activity_stream_log (type, user_id) def activity_stream_log (type, user_id)
# return if we run import mode # return if we run import mode
return if Setting.get('import_mode') return if Setting.get('import_mode')
# return if we run on init mode # return if we run on init mode
return if !Setting.get('system_init_done') return if !Setting.get('system_init_done')
return if !self.class.activity_stream_support_config return if !self.class.activity_stream_support_config
role = self.class.activity_stream_support_config[:role] role = self.class.activity_stream_support_config[:role]
ticket = Ticket.lookup( id: self.ticket_id ) ticket = Ticket.lookup( id: self.ticket_id )
ActivityStream.add( ActivityStream.add(
o_id: self['id'], o_id: self['id'],
type: type, type: type,
object: self.class.name, object: self.class.name,
group_id: ticket.group_id, group_id: ticket.group_id,
role: role, role: role,
created_at: self.updated_at, created_at: self.updated_at,
created_by_id: user_id, created_by_id: user_id,
) )
end
end
end end
end end

View file

@ -1,6 +1,8 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Article::Assets class Ticket
class Article
module Assets
=begin =begin
@ -21,35 +23,35 @@ returns
=end =end
def assets (data) def assets (data)
if !data[ Ticket.to_app_model ] if !data[ Ticket.to_app_model ]
data[ Ticket.to_app_model ] = {} data[ Ticket.to_app_model ] = {}
end end
if !data[ Ticket.to_app_model ][ self.ticket_id ] if !data[ Ticket.to_app_model ][ self.ticket_id ]
ticket = Ticket.find( self.ticket_id ) ticket = Ticket.find( self.ticket_id )
data = ticket.assets(data) data = ticket.assets(data)
end
if !data[ Ticket::Article.to_app_model ]
data[ Ticket::Article.to_app_model ] = {}
end
if !data[ Ticket::Article.to_app_model ][ self.id ]
data[ Ticket::Article.to_app_model ][ self.id ] = self.attributes
# add attachment list to article
data[ Ticket::Article.to_app_model ][ self.id ]['attachments'] = self.attachments
end
['created_by_id', 'updated_by_id'].each {|item|
if self[ item ]
if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ]
user = User.lookup( id: self[ item ] )
data = user.assets( data )
end end
end
}
data
end
if !data[ Ticket::Article.to_app_model ]
data[ Ticket::Article.to_app_model ] = {}
end
if !data[ Ticket::Article.to_app_model ][ self.id ]
data[ Ticket::Article.to_app_model ][ self.id ] = self.attributes
# add attachment list to article
data[ Ticket::Article.to_app_model ][ self.id ]['attachments'] = self.attachments
end
['created_by_id', 'updated_by_id'].each {|item|
next if !self[ item ]
if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ]
user = User.lookup( id: self[ item ] )
data = user.assets( data )
end
}
data
end
end
end
end end

View file

@ -1,6 +1,8 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Article::HistoryLog class Ticket
class Article
module HistoryLog
=begin =begin
@ -15,17 +17,18 @@ returns
=end =end
def history_log (type, user_id, data = {}) def history_log (type, user_id, data = {})
# if Ticketdata[:data[:Article has changed, remember related ticket to be able # if Ticketdata[:data[:Article has changed, remember related ticket to be able
# to show article changes in ticket history # to show article changes in ticket history
data[:o_id] = self['id'] data[:o_id] = self['id']
data[:history_type] = type data[:history_type] = type
data[:history_object] = self.class.name data[:history_object] = self.class.name
data[:related_o_id] = self['ticket_id'] data[:related_o_id] = self['ticket_id']
data[:related_history_object] = 'Ticket' data[:related_history_object] = 'Ticket'
data[:created_by_id] = user_id data[:created_by_id] = user_id
History.add(data) History.add(data)
end
end
end end
end end

View file

@ -1,6 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Assets class Ticket
module Assets
=begin =begin
@ -21,23 +22,22 @@ returns
=end =end
def assets (data) def assets (data)
if !data[ Ticket.to_app_model ] if !data[ Ticket.to_app_model ]
data[ Ticket.to_app_model ] = {} data[ Ticket.to_app_model ] = {}
end end
if !data[ Ticket.to_app_model ][ self.id ] if !data[ Ticket.to_app_model ][ self.id ]
data[ Ticket.to_app_model ][ self.id ] = self.attributes_with_associations data[ Ticket.to_app_model ][ self.id ] = self.attributes_with_associations
end end
['created_by_id', 'updated_by_id', 'owner_id', 'customer_id'].each {|item| ['created_by_id', 'updated_by_id', 'owner_id', 'customer_id'].each {|item|
if self[ item ] next if !self[ item ]
if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ] if !data[ User.to_app_model ] || !data[ User.to_app_model ][ self[ item ] ]
user = User.lookup( id: self[ item ] ) user = User.lookup( id: self[ item ] )
data = user.assets( data ) data = user.assets( data )
end end
end }
} data
data end
end end
end end

View file

@ -1,4 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Ticket::Counter < ApplicationModel class Ticket
class Counter < ApplicationModel
end
end end

View file

@ -1,6 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Escalation class Ticket
module Escalation
=begin =begin
@ -14,14 +15,14 @@ returns
=end =end
def self.rebuild_all def self.rebuild_all
state_list_open = Ticket::State.by_category( 'open' ) state_list_open = Ticket::State.by_category( 'open' )
tickets = Ticket.where( state_id: state_list_open ) tickets = Ticket.where( state_id: state_list_open )
tickets.each {|ticket| tickets.each {|ticket|
ticket.escalation_calculation ticket.escalation_calculation
} }
end end
=begin =begin
@ -36,128 +37,128 @@ returns
=end =end
def escalation_calculation def escalation_calculation
# set escalation off if ticket is already closed # set escalation off if ticket is already closed
state = Ticket::State.lookup( id: self.state_id ) state = Ticket::State.lookup( id: self.state_id )
if state.ignore_escalation? if state.ignore_escalation?
# nothing to change # nothing to change
return true if !self.escalation_time return true if !self.escalation_time
self.escalation_time = nil
# self.first_response_escal_date = nil
# self.close_time_escal_date = nil
self.callback_loop = true
self.save
return true
end
# get sla for ticket
sla_selected = escalation_calculation_get_sla
# reset escalation if no sla is set
if !sla_selected
# nothing to change
return true if !self.escalation_time
self.escalation_time = nil
# self.first_response_escal_date = nil
# self.close_time_escal_date = nil
self.callback_loop = true
self.save
return true
end
# puts sla_selected.inspect
# puts days.inspect
self.escalation_time = nil self.escalation_time = nil
# self.first_response_escal_date = nil self.first_response_escal_date = nil
# self.close_time_escal_date = nil self.update_time_escal_date = nil
self.callback_loop = true self.close_time_escal_date = nil
self.save
return true # first response
if sla_selected.first_response_time
# get escalation date without pending time
self.first_response_escal_date = TimeCalculation.dest_time( self.created_at, sla_selected.first_response_time, sla_selected.data, sla_selected.timezone )
# get pending time between created and first response escal. time
time_in_pending = escalation_suspend( self.created_at, self.first_response_escal_date, 'relative', sla_selected, sla_selected.first_response_time )
# get new escalation time (original escal_date + time_in_pending)
self.first_response_escal_date = TimeCalculation.dest_time( self.first_response_escal_date, time_in_pending.to_i, sla_selected.data, sla_selected.timezone )
# set ticket escalation
self.escalation_time = calculation_higher_time( self.escalation_time, self.first_response_escal_date, self.first_response )
end
if self.first_response# && !self.first_response_in_min
# get response time in min between created and first response
self.first_response_in_min = escalation_suspend( self.created_at, self.first_response, 'real', sla_selected )
end
# set time to show if sla is raised ot in
if sla_selected.first_response_time && self.first_response_in_min
self.first_response_diff_in_min = sla_selected.first_response_time - self.first_response_in_min
end
# update time
last_update = self.last_contact_agent
if !last_update
last_update = self.created_at
end
if sla_selected.update_time
self.update_time_escal_date = TimeCalculation.dest_time( last_update, sla_selected.update_time, sla_selected.data, sla_selected.timezone )
# get pending time between created and update escal. time
time_in_pending = escalation_suspend( last_update, self.update_time_escal_date, 'relative', sla_selected, sla_selected.update_time )
# get new escalation time (original escal_date + time_in_pending)
self.update_time_escal_date = TimeCalculation.dest_time( self.update_time_escal_date, time_in_pending.to_i, sla_selected.data, sla_selected.timezone )
# set ticket escalation
self.escalation_time = calculation_higher_time( self.escalation_time, self.update_time_escal_date, false )
end
if self.last_contact_agent
self.update_time_in_min = TimeCalculation.business_time_diff( self.created_at, self.last_contact_agent, sla_selected.data, sla_selected.timezone )
end
# set sla time
if sla_selected.update_time && self.update_time_in_min
self.update_time_diff_in_min = sla_selected.update_time - self.update_time_in_min
end
# close time
if sla_selected.close_time
# get escalation date without pending time
self.close_time_escal_date = TimeCalculation.dest_time( self.created_at, sla_selected.close_time, sla_selected.data, sla_selected.timezone )
# get pending time between created and close escal. time
extended_escalation = escalation_suspend( self.created_at, self.close_time_escal_date, 'relative', sla_selected, sla_selected.close_time )
# get new escalation time (original escal_date + time_in_pending)
self.close_time_escal_date = TimeCalculation.dest_time( self.close_time_escal_date, extended_escalation.to_i, sla_selected.data, sla_selected.timezone )
# set ticket escalation
self.escalation_time = calculation_higher_time( self.escalation_time, self.close_time_escal_date, self.close_time )
end
if self.close_time # && !self.close_time_in_min
self.close_time_in_min = escalation_suspend( self.created_at, self.close_time, 'real', sla_selected )
end
# set sla time
if sla_selected.close_time && self.close_time_in_min
self.close_time_diff_in_min = sla_selected.close_time - self.close_time_in_min
end
if self.changed?
self.callback_loop = true
self.save
end
end end
# get sla for ticket
sla_selected = escalation_calculation_get_sla
# reset escalation if no sla is set
if !sla_selected
# nothing to change
return true if !self.escalation_time
self.escalation_time = nil
# self.first_response_escal_date = nil
# self.close_time_escal_date = nil
self.callback_loop = true
self.save
return true
end
# puts sla_selected.inspect
# puts days.inspect
self.escalation_time = nil
self.first_response_escal_date = nil
self.update_time_escal_date = nil
self.close_time_escal_date = nil
# first response
if sla_selected.first_response_time
# get escalation date without pending time
self.first_response_escal_date = TimeCalculation.dest_time( self.created_at, sla_selected.first_response_time, sla_selected.data, sla_selected.timezone )
# get pending time between created and first response escal. time
time_in_pending = escalation_suspend( self.created_at, self.first_response_escal_date, 'relative', sla_selected, sla_selected.first_response_time )
# get new escalation time (original escal_date + time_in_pending)
self.first_response_escal_date = TimeCalculation.dest_time( self.first_response_escal_date, time_in_pending.to_i, sla_selected.data, sla_selected.timezone )
# set ticket escalation
self.escalation_time = calculation_higher_time( self.escalation_time, self.first_response_escal_date, self.first_response )
end
if self.first_response# && !self.first_response_in_min
# get response time in min between created and first response
self.first_response_in_min = escalation_suspend( self.created_at, self.first_response, 'real', sla_selected )
end
# set time to show if sla is raised ot in
if sla_selected.first_response_time && self.first_response_in_min
self.first_response_diff_in_min = sla_selected.first_response_time - self.first_response_in_min
end
# update time
last_update = self.last_contact_agent
if !last_update
last_update = self.created_at
end
if sla_selected.update_time
self.update_time_escal_date = TimeCalculation.dest_time( last_update, sla_selected.update_time, sla_selected.data, sla_selected.timezone )
# get pending time between created and update escal. time
time_in_pending = escalation_suspend( last_update, self.update_time_escal_date, 'relative', sla_selected, sla_selected.update_time )
# get new escalation time (original escal_date + time_in_pending)
self.update_time_escal_date = TimeCalculation.dest_time( self.update_time_escal_date, time_in_pending.to_i, sla_selected.data, sla_selected.timezone )
# set ticket escalation
self.escalation_time = calculation_higher_time( self.escalation_time, self.update_time_escal_date, false )
end
if self.last_contact_agent
self.update_time_in_min = TimeCalculation.business_time_diff( self.created_at, self.last_contact_agent, sla_selected.data, sla_selected.timezone )
end
# set sla time
if sla_selected.update_time && self.update_time_in_min
self.update_time_diff_in_min = sla_selected.update_time - self.update_time_in_min
end
# close time
if sla_selected.close_time
# get escalation date without pending time
self.close_time_escal_date = TimeCalculation.dest_time( self.created_at, sla_selected.close_time, sla_selected.data, sla_selected.timezone )
# get pending time between created and close escal. time
extended_escalation = escalation_suspend( self.created_at, self.close_time_escal_date, 'relative', sla_selected, sla_selected.close_time )
# get new escalation time (original escal_date + time_in_pending)
self.close_time_escal_date = TimeCalculation.dest_time( self.close_time_escal_date, extended_escalation.to_i, sla_selected.data, sla_selected.timezone )
# set ticket escalation
self.escalation_time = calculation_higher_time( self.escalation_time, self.close_time_escal_date, self.close_time )
end
if self.close_time # && !self.close_time_in_min
self.close_time_in_min = escalation_suspend( self.created_at, self.close_time, 'real', sla_selected )
end
# set sla time
if sla_selected.close_time && self.close_time_in_min
self.close_time_diff_in_min = sla_selected.close_time - self.close_time_in_min
end
if self.changed?
self.callback_loop = true
self.save
end
end
=begin =begin
return sla for ticket return sla for ticket
@ -171,153 +172,154 @@ returns
=end =end
def escalation_calculation_get_sla def escalation_calculation_get_sla
sla_selected = nil sla_selected = nil
sla_list = Cache.get( 'SLA::List::Active' ) sla_list = Cache.get( 'SLA::List::Active' )
if sla_list == nil if sla_list == nil
sla_list = Sla.where( active: true ) sla_list = Sla.where( active: true )
Cache.write( 'SLA::List::Active', sla_list, { expires_in: 1.hour } ) Cache.write( 'SLA::List::Active', sla_list, { expires_in: 1.hour } )
end end
sla_list.each {|sla| sla_list.each {|sla|
if !sla.condition || sla.condition.empty? if !sla.condition || sla.condition.empty?
sla_selected = sla
elsif sla.condition
hit = false
map = [
[ 'tickets.priority_id', 'priority_id' ],
[ 'tickets.group_id', 'group_id' ]
]
map.each {|item|
if sla.condition[ item[0] ]
if sla.condition[ item[0] ].class == String
sla.condition[ item[0] ] = [ sla.condition[ item[0] ] ]
end
if sla.condition[ item[0] ].include?( self[ item[1] ].to_s )
hit = true
else
hit = false
end
end
}
if hit
sla_selected = sla sla_selected = sla
elsif sla.condition
hit = false
map = [
[ 'tickets.priority_id', 'priority_id' ],
[ 'tickets.group_id', 'group_id' ]
]
map.each {|item|
if sla.condition[ item[0] ]
if sla.condition[ item[0] ].class == String
sla.condition[ item[0] ] = [ sla.condition[ item[0] ] ]
end
if sla.condition[ item[0] ].include?( self[ item[1] ].to_s )
hit = true
else
hit = false
end
end
}
if hit
sla_selected = sla
end
end end
end }
} sla_selected
sla_selected
end
private
#type could be:
# real - time without supsend state
# relative - only suspend time
def escalation_suspend (start_time, end_time, type, sla_selected, sla_time = 0)
if type == 'relative'
end_time += sla_time * 60
end end
total_time_without_pending = 0
total_time = 0
#get history for ticket
history_list = self.history_get
#loop through hist. changes and get time private
last_state = nil
last_state_change = nil
last_state_is_pending = false
history_list.each { |history_item|
# ignore if it isn't a state change #type could be:
next if !history_item['attribute'] # real - time without supsend state
next if history_item['attribute'] != 'state' # relative - only suspend time
# ignore all newer state before start_time def escalation_suspend (start_time, end_time, type, sla_selected, sla_time = 0)
next if history_item['created_at'] < start_time if type == 'relative'
end_time += sla_time * 60
# ignore all older state changes after end_time
next if last_state_change && last_state_change > end_time
# if created_at is later then end_time, use end_time as last time
if history_item['created_at'] > end_time
history_item['created_at'] = end_time
end end
total_time_without_pending = 0
total_time = 0
#get history for ticket
history_list = self.history_get
# get initial state and time #loop through hist. changes and get time
if !last_state last_state = nil
last_state = history_item['value_from'] last_state_change = nil
last_state_change = start_time last_state_is_pending = false
end history_list.each { |history_item|
# check if time need to be counted # ignore if it isn't a state change
counted = true next if !history_item['attribute']
if history_item['value_from'] == 'pending reminder' next if history_item['attribute'] != 'state'
counted = false
elsif history_item['value_from'] == 'close'
counted = false
end
diff = escalation_time_diff( last_state_change, history_item['created_at'], sla_selected ) # ignore all newer state before start_time
if counted next if history_item['created_at'] < start_time
# puts "Diff count #{history_item['value_from']} -> #{history_item['value_to']} / #{last_state_change} -> #{history_item['created_at']}"
# ignore all older state changes after end_time
next if last_state_change && last_state_change > end_time
# if created_at is later then end_time, use end_time as last time
if history_item['created_at'] > end_time
history_item['created_at'] = end_time
end
# get initial state and time
if !last_state
last_state = history_item['value_from']
last_state_change = start_time
end
# check if time need to be counted
counted = true
if history_item['value_from'] == 'pending reminder'
counted = false
elsif history_item['value_from'] == 'close'
counted = false
end
diff = escalation_time_diff( last_state_change, history_item['created_at'], sla_selected )
if counted
# puts "Diff count #{history_item['value_from']} -> #{history_item['value_to']} / #{last_state_change} -> #{history_item['created_at']}"
total_time_without_pending = total_time_without_pending + diff
else
# puts "Diff not count #{history_item['value_from']} -> #{history_item['value_to']} / #{last_state_change} -> #{history_item['created_at']}"
end
total_time = total_time + diff
if history_item['value_to'] == 'pending reminder'
last_state_is_pending = true
else
last_state_is_pending = false
end
# remember for next loop last state
last_state = history_item['value_to']
last_state_change = history_item['created_at']
}
# if last state isnt pending, count rest
if !last_state_is_pending && last_state_change && last_state_change < end_time
diff = escalation_time_diff( last_state_change, end_time, sla_selected )
# puts "Diff count last state was not pending #{diff.to_s} - #{last_state_change} - #{end_time}"
total_time_without_pending = total_time_without_pending + diff total_time_without_pending = total_time_without_pending + diff
else total_time = total_time + diff
# puts "Diff not count #{history_item['value_from']} -> #{history_item['value_to']} / #{last_state_change} -> #{history_item['created_at']}"
end
total_time = total_time + diff
if history_item['value_to'] == 'pending reminder'
last_state_is_pending = true
else
last_state_is_pending = false
end end
# remember for next loop last state # if we have not had any state change
last_state = history_item['value_to'] if !last_state_change
last_state_change = history_item['created_at'] diff = escalation_time_diff( start_time, end_time, sla_selected )
} # puts 'Diff state has not changed ' + diff.to_s
total_time_without_pending = total_time_without_pending + diff
total_time = total_time + diff
end
# if last state isnt pending, count rest #return sum
if !last_state_is_pending && last_state_change && last_state_change < end_time if type == 'real'
diff = escalation_time_diff( last_state_change, end_time, sla_selected ) return total_time_without_pending
# puts "Diff count last state was not pending #{diff.to_s} - #{last_state_change} - #{end_time}" elsif type == 'relative'
total_time_without_pending = total_time_without_pending + diff relative = total_time - total_time_without_pending
total_time = total_time + diff return relative
else
raise "ERROR: Unknown type #{type}"
end
end end
# if we have not had any state change def escalation_time_diff( start_time, end_time, sla_selected )
if !last_state_change if sla_selected
diff = escalation_time_diff( start_time, end_time, sla_selected ) diff = TimeCalculation.business_time_diff( start_time, end_time, sla_selected.data, sla_selected.timezone)
# puts 'Diff state has not changed ' + diff.to_s else
total_time_without_pending = total_time_without_pending + diff diff = TimeCalculation.business_time_diff( start_time, end_time )
total_time = total_time + diff end
diff
end end
#return sum def calculation_higher_time(escalation_time, check_time, done_time)
if type == 'real' return escalation_time if done_time
return total_time_without_pending return check_time if !escalation_time
elsif type == 'relative' return escalation_time if !check_time
relative = total_time - total_time_without_pending return check_time if escalation_time > check_time
return relative return escalation_time
else
raise "ERROR: Unknown type #{type}"
end end
end end
def escalation_time_diff( start_time, end_time, sla_selected )
if sla_selected
diff = TimeCalculation.business_time_diff( start_time, end_time, sla_selected.data, sla_selected.timezone)
else
diff = TimeCalculation.business_time_diff( start_time, end_time )
end
diff
end
def calculation_higher_time(escalation_time, check_time, done_time)
return escalation_time if done_time
return check_time if !escalation_time
return escalation_time if !check_time
return check_time if escalation_time > check_time
return escalation_time
end
end end

View file

@ -1,4 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Ticket::Flag < ApplicationModel class Ticket
class Flag < ApplicationModel
end
end end

View file

@ -1,6 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::HistoryLog class Ticket
module HistoryLog
=begin =begin
@ -15,15 +16,15 @@ returns
=end =end
def history_log (type, user_id, data = {}) def history_log (type, user_id, data = {})
data[:o_id] = self['id'] data[:o_id] = self['id']
data[:history_type] = type data[:history_type] = type
data[:history_object] = self.class.name data[:history_object] = self.class.name
data[:related_o_id] = nil data[:related_o_id] = nil
data[:related_history_object] = nil data[:related_history_object] = nil
data[:created_by_id] = user_id data[:created_by_id] = user_id
History.add(data) History.add(data)
end end
=begin =begin
@ -57,25 +58,25 @@ returns
=end =end
def history_get(fulldata = false) def history_get(fulldata = false)
list = History.list( self.class.name, self['id'], 'Ticket::Article' ) list = History.list( self.class.name, self['id'], 'Ticket::Article' )
return list if !fulldata return list if !fulldata
# get related objects # get related objects
assets = {} assets = {}
list.each {|item| list.each {|item|
record = Kernel.const_get( item['object'] ).find( item['o_id'] ) record = Kernel.const_get( item['object'] ).find( item['o_id'] )
assets = record.assets(assets)
if item['related_object']
record = Kernel.const_get( item['related_object'] ).find( item['related_o_id'] )
assets = record.assets(assets) assets = record.assets(assets)
end
}
return {
history: list,
assets: assets,
}
end
if item['related_object']
record = Kernel.const_get( item['related_object'] ).find( item['related_o_id'] )
assets = record.assets(assets)
end
}
return {
history: list,
assets: assets,
}
end
end
end end

View file

@ -1,7 +1,8 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Ticket::Number class Ticket
include ApplicationLib class Number
include ApplicationLib
=begin =begin
@ -15,16 +16,16 @@ returns
=end =end
def self.generate def self.generate
# generate number # generate number
(1..50_000).each { |i| (1..50_000).each { |i|
number = adapter.generate number = adapter.generate
ticket = Ticket.where( number: number ).first ticket = Ticket.where( number: number ).first
return number if !ticket return number if !ticket
} }
raise "Can't generate new ticket number!" raise "Can't generate new ticket number!"
end end
=begin =begin
@ -38,21 +39,22 @@ returns
=end =end
def self.check(string) def self.check(string)
adapter.check(string) adapter.check(string)
end
def self.adapter
# load backend based on config
adapter_name = Setting.get('ticket_number')
if !adapter_name
raise 'Missing ticket_number setting option'
end end
adapter = load_adapter(adapter_name)
if !adapter def self.adapter
raise "Can't load ticket_number adapter '#{adapter_name}'"
# load backend based on config
adapter_name = Setting.get('ticket_number')
if !adapter_name
raise 'Missing ticket_number setting option'
end
adapter = load_adapter(adapter_name)
if !adapter
raise "Can't load ticket_number adapter '#{adapter_name}'"
end
adapter
end end
adapter
end end
end end

View file

@ -1,83 +1,88 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Number::Date class Ticket
extend self class Number
module Date
extend self
def generate def generate
# get config # get config
config = Setting.get('ticket_number_date') config = Setting.get('ticket_number_date')
t = Time.now t = Time.zone.now
date = t.strftime('%Y-%m-%d') date = t.strftime('%Y-%m-%d')
# read counter # read counter
counter_increment = nil counter_increment = nil
Ticket::Counter.transaction do Ticket::Counter.transaction do
counter = Ticket::Counter.where( generator: 'Date' ).lock(true).first counter = Ticket::Counter.where( generator: 'Date' ).lock(true).first
if !counter if !counter
counter = Ticket::Counter.new( generator: 'Date', content: '0' ) counter = Ticket::Counter.new( generator: 'Date', content: '0' )
end end
# increase counter # increase counter
counter_increment, date_file = counter.content.to_s.split(';') counter_increment, date_file = counter.content.to_s.split(';')
if date_file == date if date_file == date
counter_increment = counter_increment.to_i + 1 counter_increment = counter_increment.to_i + 1
else else
counter_increment = 1 counter_increment = 1
end end
# store new counter value # store new counter value
counter.content = counter_increment.to_s + ';' + date counter.content = counter_increment.to_s + ';' + date
counter.save counter.save
end
system_id = Setting.get('system_id') || ''
number = t.strftime('%Y%m%d') + system_id.to_s + sprintf( '%04d', counter_increment)
# calculate a checksum
# The algorithm to calculate the checksum is derived from the one
# Deutsche Bundesbahn (german railway company) uses for calculation
# of the check digit of their vehikel numbering.
# The checksum is calculated by alternately multiplying the digits
# with 1 and 2 and adding the resulsts from left to right of the
# vehikel number. The modulus to 10 of this sum is substracted from
# 10. See: http://www.pruefziffernberechnung.de/F/Fahrzeugnummer.shtml
# (german)
if config[:checksum]
chksum = 0
mult = 1
(1..number.length).each do |i|
digit = number.to_s[i, 1]
chksum = chksum + ( mult * digit.to_i )
mult += 1
if mult == 3
mult = 1
end end
end
chksum %= 10
chksum = 10 - chksum
if chksum == 10
chksum = 1
end
number += chksum.to_s
end
number
end
def check(string)
# get config system_id = Setting.get('system_id') || ''
system_id = Setting.get('system_id') || '' number = t.strftime('%Y%m%d') + system_id.to_s + sprintf( '%04d', counter_increment)
ticket_hook = Setting.get('ticket_hook')
ticket_hook_divider = Setting.get('ticket_hook_divider') || ''
ticket = nil
# probe format # calculate a checksum
if string =~ /#{ticket_hook}#{ticket_hook_divider}(#{system_id}\d{2,50})/i then # The algorithm to calculate the checksum is derived from the one
ticket = Ticket.where( number: $1 ).first # Deutsche Bundesbahn (german railway company) uses for calculation
elsif string =~ /#{ticket_hook}\s{0,2}(#{system_id}\d{2,50})/i then # of the check digit of their vehikel numbering.
ticket = Ticket.where( number: $1 ).first # The checksum is calculated by alternately multiplying the digits
# with 1 and 2 and adding the resulsts from left to right of the
# vehikel number. The modulus to 10 of this sum is substracted from
# 10. See: http://www.pruefziffernberechnung.de/F/Fahrzeugnummer.shtml
# (german)
if config[:checksum]
chksum = 0
mult = 1
(1..number.length).each do |i|
digit = number.to_s[i, 1]
chksum = chksum + ( mult * digit.to_i )
mult += 1
if mult == 3
mult = 1
end
end
chksum %= 10
chksum = 10 - chksum
if chksum == 10
chksum = 1
end
number += chksum.to_s
end
number
end
def check(string)
# get config
system_id = Setting.get('system_id') || ''
ticket_hook = Setting.get('ticket_hook')
ticket_hook_divider = Setting.get('ticket_hook_divider') || ''
ticket = nil
# probe format
if string =~ /#{ticket_hook}#{ticket_hook_divider}(#{system_id}\d{2,50})/i
ticket = Ticket.where( number: $1 ).first
elsif string =~ /#{ticket_hook}\s{0,2}(#{system_id}\d{2,50})/i
ticket = Ticket.where( number: $1 ).first
end
ticket
end
end end
ticket
end end
end end

View file

@ -1,87 +1,91 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Number::Increment class Ticket
extend self class Number
module Increment
extend self
def generate def generate
# get config # get config
config = Setting.get('ticket_number_increment') config = Setting.get('ticket_number_increment')
# read counter # read counter
min_digs = config[:min_size] || 4 min_digs = config[:min_size] || 4
counter_increment = nil counter_increment = nil
Ticket::Counter.transaction do Ticket::Counter.transaction do
counter = Ticket::Counter.where( generator: 'Increment' ).lock(true).first counter = Ticket::Counter.where( generator: 'Increment' ).lock(true).first
if !counter if !counter
counter = Ticket::Counter.new( generator: 'Increment', content: '0' ) counter = Ticket::Counter.new( generator: 'Increment', content: '0' )
end end
counter_increment = counter.content.to_i counter_increment = counter.content.to_i
# increase counter # increase counter
counter_increment += 1 counter_increment += 1
# store new counter value # store new counter value
counter.content = counter_increment.to_s counter.content = counter_increment.to_s
counter.save counter.save
end
# fill up number counter
if config[:checksum]
min_digs = min_digs.to_i - 1
end
fillup = Setting.get('system_id') || '1'
( 1..100 ).each do |i|
if ( fillup.length.to_i + counter_increment.to_s.length.to_i ) < min_digs.to_i
fillup = fillup + '0'
end
end
number = fillup.to_s + counter_increment.to_s
# calculate a checksum
# The algorithm to calculate the checksum is derived from the one
# Deutsche Bundesbahn (german railway company) uses for calculation
# of the check digit of their vehikel numbering.
# The checksum is calculated by alternately multiplying the digits
# with 1 and 2 and adding the resulsts from left to right of the
# vehikel number. The modulus to 10 of this sum is substracted from
# 10. See: http://www.pruefziffernberechnung.de/F/Fahrzeugnummer.shtml
# (german)
if config[:checksum]
chksum = 0
mult = 1
(1..number.length).each do |i|
digit = number.to_s[i, 1]
chksum = chksum + ( mult * digit.to_i )
mult += 1
if mult == 3
mult = 1
end end
# fill up number counter
if config[:checksum]
min_digs = min_digs.to_i - 1
end
fillup = Setting.get('system_id') || '1'
( 1..100 ).each do |i|
if ( fillup.length.to_i + counter_increment.to_s.length.to_i ) < min_digs.to_i
fillup = fillup + '0'
end
end
number = fillup.to_s + counter_increment.to_s
# calculate a checksum
# The algorithm to calculate the checksum is derived from the one
# Deutsche Bundesbahn (german railway company) uses for calculation
# of the check digit of their vehikel numbering.
# The checksum is calculated by alternately multiplying the digits
# with 1 and 2 and adding the resulsts from left to right of the
# vehikel number. The modulus to 10 of this sum is substracted from
# 10. See: http://www.pruefziffernberechnung.de/F/Fahrzeugnummer.shtml
# (german)
if config[:checksum]
chksum = 0
mult = 1
(1..number.length).each do |i|
digit = number.to_s[i, 1]
chksum = chksum + ( mult * digit.to_i )
mult += 1
if mult == 3
mult = 1
end
end
chksum %= 10
chksum = 10 - chksum
if chksum == 10
chksum = 1
end
number += chksum.to_s
end
number
end end
chksum %= 10
chksum = 10 - chksum def check(string)
if chksum == 10
chksum = 1 # get config
system_id = Setting.get('system_id') || ''
ticket_hook = Setting.get('ticket_hook')
ticket_hook_divider = Setting.get('ticket_hook_divider') || ''
ticket = nil
# probe format
if string =~ /#{ticket_hook}#{ticket_hook_divider}(#{system_id}\d{2,48})/i
ticket = Ticket.where( number: $1 ).first
elsif string =~ /#{ticket_hook}\s{0,2}(#{system_id}\d{2,48})/i
ticket = Ticket.where( number: $1 ).first
end
ticket
end end
number += chksum.to_s
end end
number
end
def check(string)
# get config
system_id = Setting.get('system_id') || ''
ticket_hook = Setting.get('ticket_hook')
ticket_hook_divider = Setting.get('ticket_hook_divider') || ''
ticket = nil
# probe format
if string =~ /#{ticket_hook}#{ticket_hook_divider}(#{system_id}\d{2,48})/i then
ticket = Ticket.where( number: $1 ).first
elsif string =~ /#{ticket_hook}\s{0,2}(#{system_id}\d{2,48})/i then
ticket = Ticket.where( number: $1 ).first
end
ticket
end end
end end

View file

@ -1,6 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Overviews class Ticket
module Overviews
=begin =begin
@ -16,24 +17,24 @@ returns
=end =end
def self.all (data) def self.all (data)
# get customer overviews # get customer overviews
if data[:current_user].is_role('Customer') if data[:current_user].is_role('Customer')
role = data[:current_user].is_role( 'Customer' ) role = data[:current_user].is_role( 'Customer' )
if data[:current_user].organization_id && data[:current_user].organization.shared if data[:current_user].organization_id && data[:current_user].organization.shared
overviews = Overview.where( role_id: role.id, active: true ) overviews = Overview.where( role_id: role.id, active: true )
else else
overviews = Overview.where( role_id: role.id, organization_shared: false, active: true ) overviews = Overview.where( role_id: role.id, organization_shared: false, active: true )
end
return overviews
end end
return overviews
end
# get agent overviews # get agent overviews
role = data[:current_user].is_role( 'Agent' ) role = data[:current_user].is_role( 'Agent' )
return if !role return if !role
Overview.where( role_id: role.id, active: true ) Overview.where( role_id: role.id, active: true )
end end
=begin =begin
@ -54,197 +55,199 @@ returns
=end =end
def self.list (data) def self.list (data)
overviews = self.all(data) overviews = self.all(data)
return if !overviews return if !overviews
# build up attributes hash # build up attributes hash
overview_selected = nil overview_selected = nil
overview_selected_raw = nil overview_selected_raw = nil
overviews.each { |overview|
# remember selected view
if data[:view] && data[:view] == overview.link
overview_selected = overview
overview_selected_raw = Marshal.load( Marshal.dump(overview.attributes) )
end
# replace e.g. 'current_user.id' with current_user.id
overview.condition.each { |item, value |
if value && value.class.to_s == 'String'
parts = value.split( '.', 2 )
if parts[0] && parts[1] && parts[0] == 'current_user'
overview.condition[item] = data[:current_user][parts[1].to_sym]
end
end
}
}
if data[:view] && !overview_selected
raise "No such view '#{ data[:view] }'"
end
# sortby
# prio
# state
# group
# customer
# order
# asc
# desc
# groupby
# prio
# state
# group
# customer
# all = attributes[:myopenassigned]
# all.merge( { :group_id => groups } )
# @tickets = Ticket.where(:group_id => groups, attributes[:myopenassigned] ).limit(params[:limit])
# get only tickets with permissions
if data[:current_user].is_role('Customer')
group_ids = Group.select( 'groups.id' ).
where( 'groups.active = ?', true ).
map( &:id )
else
group_ids = Group.select( 'groups.id' ).joins(:users).
where( 'groups_users.user_id = ?', [ data[:current_user].id ] ).
where( 'groups.active = ?', true ).
map( &:id )
end
# overview meta for navbar
if !overview_selected
# loop each overview
result = []
overviews.each { |overview| overviews.each { |overview|
# get count # remember selected view
count = Ticket.where( group_id: group_ids ).where( _condition( overview.condition ) ).count() if data[:view] && data[:view] == overview.link
overview_selected = overview
overview_selected_raw = Marshal.load( Marshal.dump(overview.attributes) )
end
# get meta info # replace e.g. 'current_user.id' with current_user.id
all = { overview.condition.each { |item, value |
name: overview.name, if value && value.class.to_s == 'String'
prio: overview.prio, parts = value.split( '.', 2 )
link: overview.link, if parts[0] && parts[1] && parts[0] == 'current_user'
overview.condition[item] = data[:current_user][parts[1].to_sym]
end
end
}
}
if data[:view] && !overview_selected
raise "No such view '#{ data[:view] }'"
end
# sortby
# prio
# state
# group
# customer
# order
# asc
# desc
# groupby
# prio
# state
# group
# customer
# all = attributes[:myopenassigned]
# all.merge( { :group_id => groups } )
# @tickets = Ticket.where(:group_id => groups, attributes[:myopenassigned] ).limit(params[:limit])
# get only tickets with permissions
if data[:current_user].is_role('Customer')
group_ids = Group.select( 'groups.id' ).
where( 'groups.active = ?', true ).
map( &:id )
else
group_ids = Group.select( 'groups.id' ).joins(:users).
where( 'groups_users.user_id = ?', [ data[:current_user].id ] ).
where( 'groups.active = ?', true ).
map( &:id )
end
# overview meta for navbar
if !overview_selected
# loop each overview
result = []
overviews.each { |overview|
# get count
count = Ticket.where( group_id: group_ids ).where( _condition( overview.condition ) ).count()
# get meta info
all = {
name: overview.name,
prio: overview.prio,
link: overview.link,
}
# push to result data
result.push all.merge( { count: count } )
}
return result
end
# get result list
if data[:array]
order_by = overview_selected[:order][:by].to_s + ' ' + overview_selected[:order][:direction].to_s
if overview_selected.group_by && !overview_selected.group_by.empty?
order_by = overview_selected.group_by + '_id, ' + order_by
end
tickets = Ticket.select( 'id' ).
where( group_id: group_ids ).
where( _condition( overview_selected.condition ) ).
order( order_by ).
limit( 500 )
ticket_ids = []
tickets.each { |ticket|
ticket_ids.push ticket.id
} }
# push to result data tickets_count = Ticket.where( group_id: group_ids ).
result.push all.merge( { count: count } ) where( _condition( overview_selected.condition ) ).
} count()
return result
end
# get result list return {
if data[:array] ticket_ids: ticket_ids,
order_by = overview_selected[:order][:by].to_s + ' ' + overview_selected[:order][:direction].to_s tickets_count: tickets_count,
if overview_selected.group_by && !overview_selected.group_by.empty? overview: overview_selected_raw,
order_by = overview_selected.group_by + '_id, ' + order_by }
end end
tickets = Ticket.select( 'id' ).
where( group_id: group_ids ).
where( _condition( overview_selected.condition ) ).
order( order_by ).
limit( 500 )
ticket_ids = [] # get tickets for overview
tickets.each { |ticket| data[:start_page] ||= 1
ticket_ids.push ticket.id tickets = Ticket.where( group_id: group_ids ).
} where( _condition( overview_selected.condition ) ).
order( overview_selected[:order][:by].to_s + ' ' + overview_selected[:order][:direction].to_s )#.
# limit( overview_selected.view[ data[:view_mode].to_sym ][:per_page] ).
# offset( overview_selected.view[ data[:view_mode].to_sym ][:per_page].to_i * ( data[:start_page].to_i - 1 ) )
tickets_count = Ticket.where( group_id: group_ids ). tickets_count = Ticket.where( group_id: group_ids ).
where( _condition( overview_selected.condition ) ). where( _condition( overview_selected.condition ) ).
count() count()
return { {
ticket_ids: ticket_ids, tickets: tickets,
tickets_count: tickets_count, tickets_count: tickets_count,
overview: overview_selected_raw, overview: overview_selected_raw,
} }
end end
# get tickets for overview private
data[:start_page] ||= 1
tickets = Ticket.where( group_id: group_ids ).
where( _condition( overview_selected.condition ) ).
order( overview_selected[:order][:by].to_s + ' ' + overview_selected[:order][:direction].to_s )#.
# limit( overview_selected.view[ data[:view_mode].to_sym ][:per_page] ).
# offset( overview_selected.view[ data[:view_mode].to_sym ][:per_page].to_i * ( data[:start_page].to_i - 1 ) )
tickets_count = Ticket.where( group_id: group_ids ). def self._condition(condition)
where( _condition( overview_selected.condition ) ). sql = ''
count() bind = [nil]
condition.each {|key, value|
{ if sql != ''
tickets: tickets, sql += ' AND '
tickets_count: tickets_count,
overview: overview_selected_raw,
}
end
private
def self._condition(condition)
sql = ''
bind = [nil]
condition.each {|key, value|
if sql != ''
sql += ' AND '
end
if value.class == Array
sql += " #{key} IN (?)"
bind.push value
elsif value.class == Hash || value.class == ActiveSupport::HashWithIndifferentAccess
time = Time.now
if value['area'] == 'minute'
if value['direction'] == 'last'
time -= value['count'].to_i * 60
else
time += value['count'].to_i * 60
end
elsif value['area'] == 'hour'
if value['direction'] == 'last'
time -= value['count'].to_i * 60 * 60
else
time += value['count'].to_i * 60 * 60
end
elsif value['area'] == 'day'
if value['direction'] == 'last'
time -= value['count'].to_i * 60 * 60 * 24
else
time += value['count'].to_i * 60 * 60 * 24
end
elsif value['area'] == 'month'
if value['direction'] == 'last'
time -= value['count'].to_i * 60 * 60 * 24 * 31
else
time += value['count'].to_i * 60 * 60 * 24 * 31
end
elsif value['area'] == 'year'
if value['direction'] == 'last'
time -= value['count'].to_i * 60 * 60 * 24 * 365
else
time += value['count'].to_i * 60 * 60 * 24 * 365
end
end end
if value['direction'] == 'last' if value.class == Array
sql += " #{key} > ?" sql += " #{key} IN (?)"
bind.push time bind.push value
elsif value.class == Hash || value.class == ActiveSupport::HashWithIndifferentAccess
time = Time.now
if value['area'] == 'minute'
if value['direction'] == 'last'
time -= value['count'].to_i * 60
else
time += value['count'].to_i * 60
end
elsif value['area'] == 'hour'
if value['direction'] == 'last'
time -= value['count'].to_i * 60 * 60
else
time += value['count'].to_i * 60 * 60
end
elsif value['area'] == 'day'
if value['direction'] == 'last'
time -= value['count'].to_i * 60 * 60 * 24
else
time += value['count'].to_i * 60 * 60 * 24
end
elsif value['area'] == 'month'
if value['direction'] == 'last'
time -= value['count'].to_i * 60 * 60 * 24 * 31
else
time += value['count'].to_i * 60 * 60 * 24 * 31
end
elsif value['area'] == 'year'
if value['direction'] == 'last'
time -= value['count'].to_i * 60 * 60 * 24 * 365
else
time += value['count'].to_i * 60 * 60 * 24 * 365
end
end
if value['direction'] == 'last'
sql += " #{key} > ?"
bind.push time
else
sql += " #{key} < ?"
bind.push time
end
else else
sql += " #{key} < ?" sql += " #{key} = ?"
bind.push time bind.push value
end end
else }
sql += " #{key} = ?" bind[0] = sql
bind.push value bind
end end
}
bind[0] = sql
bind
end end
end end

View file

@ -1,6 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Permission class Ticket
module Permission
=begin =begin
@ -15,33 +16,33 @@ returns
=end =end
def permission (data) def permission (data)
# check customer # check customer
if data[:current_user].is_role('Customer') if data[:current_user].is_role('Customer')
# access ok if its own ticket # access ok if its own ticket
return true if self.customer_id == data[:current_user].id return true if self.customer_id == data[:current_user].id
# access ok if its organization ticket # access ok if its organization ticket
if data[:current_user].organization_id && self.organization_id if data[:current_user].organization_id && self.organization_id
return true if self.organization_id == data[:current_user].organization_id return true if self.organization_id == data[:current_user].organization_id
end
# no access
return false
end end
# no access # check agent
return false
# access if requestor is owner
return true if self.owner_id == data[:current_user].id
# access if requestor is in group
data[:current_user].groups.each {|group|
return true if self.group.id == group.id
}
false
end end
# check agent
# access if requestor is owner
return true if self.owner_id == data[:current_user].id
# access if requestor is in group
data[:current_user].groups.each {|group|
return true if self.group.id == group.id
}
false
end end
end end

View file

@ -1,6 +1,8 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Ticket::Priority < ApplicationModel class Ticket
self.table_name = 'ticket_priorities' class Priority < ApplicationModel
validates :name, presence: true self.table_name = 'ticket_priorities'
validates :name, presence: true
end
end end

View file

@ -1,6 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::ScreenOptions class Ticket
module ScreenOptions
=begin =begin
@ -14,9 +15,9 @@ returns
=end =end
def self.agents def self.agents
User.where( active: true ).joins(:roles).where( 'roles.name' => 'Agent', 'roles.active' => true ).uniq() User.where( active: true ).joins(:roles).where( 'roles.name' => 'Agent', 'roles.active' => true ).uniq()
end end
=begin =begin
@ -42,83 +43,83 @@ returns
=end =end
def self.attributes_to_change(params) def self.attributes_to_change(params)
if params[:ticket_id] if params[:ticket_id]
params[:ticket] = Ticket.find( params[:ticket_id] ) params[:ticket] = Ticket.find( params[:ticket_id] )
end
if params[:article_id]
params[:article] = Ticket::Article.find( params[:article_id] )
end
filter = {}
assets = {}
# get ticket states
state_ids = []
if params[:ticket]
state_type = params[:ticket].state.state_type
end
state_types = ['open', 'closed', 'pending action', 'pending reminder']
if state_type && !state_types.include?(state_type.name)
state_ids.push params[:ticket].state.id
end
state_types.each {|type|
state_type = Ticket::StateType.where( name: type ).first
if state_type
state_type.states.each {|state|
assets = state.assets(assets)
state_ids.push state.id
}
end end
} if params[:article_id]
filter[:state_id] = state_ids params[:article] = Ticket::Article.find( params[:article_id] )
# get priorities
priority_ids = []
Ticket::Priority.where( active: true ).each { |priority|
assets = priority.assets(assets)
priority_ids.push priority.id
}
filter[:priority_id] = priority_ids
type_ids = []
if params[:ticket]
types = ['note', 'phone']
if params[:ticket].group.email_address_id
types.push 'email'
end end
types.each {|type_name|
type = Ticket::Article::Type.lookup( name: type_name ) filter = {}
if type assets = {}
type_ids.push type.id
# get ticket states
state_ids = []
if params[:ticket]
state_type = params[:ticket].state.state_type
end
state_types = ['open', 'closed', 'pending action', 'pending reminder']
if state_type && !state_types.include?(state_type.name)
state_ids.push params[:ticket].state.id
end
state_types.each {|type|
state_type = Ticket::StateType.where( name: type ).first
if state_type
state_type.states.each {|state|
assets = state.assets(assets)
state_ids.push state.id
}
end end
} }
end filter[:state_id] = state_ids
filter[:type_id] = type_ids
# get group / user relations # get priorities
agents = {} priority_ids = []
Ticket::ScreenOptions.agents.each { |user| Ticket::Priority.where( active: true ).each { |priority|
agents[ user.id ] = 1 assets = priority.assets(assets)
} priority_ids.push priority.id
dependencies = { group_id: { '' => { owner_id: [] } } }
Group.where( active: true ).each { |group|
assets = group.assets(assets)
dependencies[:group_id][group.id] = { owner_id: [] }
group.users.each {|user|
next if !agents[ user.id ]
assets = user.assets(assets)
dependencies[:group_id][ group.id ][ :owner_id ].push user.id
} }
} filter[:priority_id] = priority_ids
{ type_ids = []
assets: assets, if params[:ticket]
filter: filter, types = ['note', 'phone']
dependencies: dependencies, if params[:ticket].group.email_address_id
} types.push 'email'
end end
types.each {|type_name|
type = Ticket::Article::Type.lookup( name: type_name )
if type
type_ids.push type.id
end
}
end
filter[:type_id] = type_ids
# get group / user relations
agents = {}
Ticket::ScreenOptions.agents.each { |user|
agents[ user.id ] = 1
}
dependencies = { group_id: { '' => { owner_id: [] } } }
Group.where( active: true ).each { |group|
assets = group.assets(assets)
dependencies[:group_id][group.id] = { owner_id: [] }
group.users.each {|user|
next if !agents[ user.id ]
assets = user.assets(assets)
dependencies[:group_id][ group.id ][ :owner_id ].push user.id
}
}
{
assets: assets,
filter: filter,
dependencies: dependencies,
}
end
=begin =begin
@ -139,39 +140,39 @@ returns
=end =end
def self.list_by_customer(data) def self.list_by_customer(data)
# get closed/open states # get closed/open states
state_list_open = Ticket::State.by_category( 'open' ) state_list_open = Ticket::State.by_category( 'open' )
state_list_closed = Ticket::State.by_category( 'closed' ) state_list_closed = Ticket::State.by_category( 'closed' )
# get tickets # get tickets
tickets_open = Ticket.where( tickets_open = Ticket.where(
customer_id: data[:customer_id], customer_id: data[:customer_id],
state_id: state_list_open state_id: state_list_open
).limit( data[:limit] || 15 ).order('created_at DESC') ).limit( data[:limit] || 15 ).order('created_at DESC')
assets = {} assets = {}
ticket_ids_open = [] ticket_ids_open = []
tickets_open.each {|ticket| tickets_open.each {|ticket|
ticket_ids_open.push ticket.id ticket_ids_open.push ticket.id
assets = ticket.assets(assets) assets = ticket.assets(assets)
} }
tickets_closed = Ticket.where( tickets_closed = Ticket.where(
customer_id: data[:customer_id], customer_id: data[:customer_id],
state_id: state_list_closed state_id: state_list_closed
).limit( data[:limit] || 15 ).order('created_at DESC') ).limit( data[:limit] || 15 ).order('created_at DESC')
ticket_ids_closed = [] ticket_ids_closed = []
tickets_closed.each {|ticket| tickets_closed.each {|ticket|
ticket_ids_closed.push ticket.id ticket_ids_closed.push ticket.id
assets = ticket.assets(assets) assets = ticket.assets(assets)
} }
{ {
ticket_ids_open: ticket_ids_open, ticket_ids_open: ticket_ids_open,
ticket_ids_closed: ticket_ids_closed, ticket_ids_closed: ticket_ids_closed,
assets: assets, assets: assets,
} }
end
end end
end end

View file

@ -1,6 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Search class Ticket
module Search
=begin =begin
@ -45,102 +46,102 @@ returns
=end =end
def search (params) def search (params)
# get params # get params
query = params[:query] query = params[:query]
limit = params[:limit] || 12 limit = params[:limit] || 12
current_user = params[:current_user] current_user = params[:current_user]
full = false full = false
if params[:full] || !params.key?(:full) if params[:full] || !params.key?(:full)
full = true full = true
end
# try search index backend
if !params[:detail] && SearchIndexBackend.enabled?
query_extention = {}
query_extention['bool'] = {}
query_extention['bool']['must'] = []
if current_user.is_role('Agent')
groups = Group.joins(:users).
where( 'groups_users.user_id = ?', current_user.id ).
where( 'groups.active = ?', true )
group_condition = []
groups.each {|group|
group_condition.push group.name
}
access_condition = {
'query_string' => { 'default_field' => 'Ticket.group.name', 'query' => "\"#{group_condition.join('" OR "')}\"" }
}
query_extention['bool']['must'].push access_condition
else
if !current_user.organization || ( !current_user.organization.shared || current_user.organization.shared == false )
access_condition = {
'query_string' => { 'default_field' => 'Ticket.customer_id', 'query' => current_user.id }
}
# customer_id: XXX
# conditions = [ 'customer_id = ?', current_user.id ]
else
access_condition = {
'query_string' => { 'query' => "Ticket.customer_id:#{current_user.id} OR Ticket.organization_id:#{current_user.organization.id}" }
}
# customer_id: XXX OR organization_id: XXX
# conditions = [ '( customer_id = ? OR organization_id = ? )', current_user.id, current_user.organization.id ]
end
query_extention['bool']['must'].push access_condition
end end
items = SearchIndexBackend.search( query, limit, 'Ticket', query_extention ) # try search index backend
if !params[:detail] && SearchIndexBackend.enabled?
query_extention = {}
query_extention['bool'] = {}
query_extention['bool']['must'] = []
if current_user.is_role('Agent')
groups = Group.joins(:users)
.where( 'groups_users.user_id = ?', current_user.id )
.where( 'groups.active = ?', true )
group_condition = []
groups.each {|group|
group_condition.push group.name
}
access_condition = {
'query_string' => { 'default_field' => 'Ticket.group.name', 'query' => "\"#{group_condition.join('" OR "')}\"" }
}
query_extention['bool']['must'].push access_condition
else
if !current_user.organization || ( !current_user.organization.shared || current_user.organization.shared == false )
access_condition = {
'query_string' => { 'default_field' => 'Ticket.customer_id', 'query' => current_user.id }
}
# customer_id: XXX
# conditions = [ 'customer_id = ?', current_user.id ]
else
access_condition = {
'query_string' => { 'query' => "Ticket.customer_id:#{current_user.id} OR Ticket.organization_id:#{current_user.organization.id}" }
}
# customer_id: XXX OR organization_id: XXX
# conditions = [ '( customer_id = ? OR organization_id = ? )', current_user.id, current_user.organization.id ]
end
query_extention['bool']['must'].push access_condition
end
items = SearchIndexBackend.search( query, limit, 'Ticket', query_extention )
if !full
ids = []
items.each {|item|
ids.push item[:id]
}
return ids
end
tickets = []
items.each { |item|
tickets.push Ticket.lookup( id: item[:id] )
}
return tickets
end
# fallback do sql query
access_condition = Ticket.access_condition( current_user )
# do query
# - stip out * we already search for *query* -
if query
query.gsub! '*', ''
tickets_all = Ticket.select('DISTINCT(tickets.id)')
.where(access_condition)
.where( '( `tickets`.`title` LIKE ? OR `tickets`.`number` LIKE ? OR `ticket_articles`.`body` LIKE ? OR `ticket_articles`.`from` LIKE ? OR `ticket_articles`.`to` LIKE ? OR `ticket_articles`.`subject` LIKE ?)', "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%" )
.joins(:articles)
.order('`tickets`.`created_at` DESC')
.limit(limit)
else
tickets_all = Ticket.select('DISTINCT(tickets.id)')
.where(access_condition)
.where(params[:condition])
.order('`tickets`.`created_at` DESC')
.limit(limit)
end
# build result list
if !full if !full
ids = [] ids = []
items.each {|item| tickets_all.each { |ticket|
ids.push item[:id] ids.push ticket.id
} }
return ids return ids
end end
tickets = [] tickets = []
items.each { |item|
tickets.push Ticket.lookup( id: item[:id] )
}
return tickets
end
# fallback do sql query
access_condition = Ticket.access_condition( current_user )
# do query
# - stip out * we already search for *query* -
if query
query.gsub! '*', ''
tickets_all = Ticket.select('DISTINCT(tickets.id)').
where(access_condition).
where( '( `tickets`.`title` LIKE ? OR `tickets`.`number` LIKE ? OR `ticket_articles`.`body` LIKE ? OR `ticket_articles`.`from` LIKE ? OR `ticket_articles`.`to` LIKE ? OR `ticket_articles`.`subject` LIKE ?)', "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%", "%#{query}%" ).
joins(:articles).
order('`tickets`.`created_at` DESC').
limit(limit)
else
tickets_all = Ticket.select('DISTINCT(tickets.id)').
where(access_condition).
where(params[:condition]).
order('`tickets`.`created_at` DESC').
limit(limit)
end
# build result list
if !full
ids = []
tickets_all.each { |ticket| tickets_all.each { |ticket|
ids.push ticket.id tickets.push Ticket.lookup( id: ticket.id )
} }
return ids tickets
end end
tickets = []
tickets_all.each { |ticket|
tickets.push Ticket.lookup( id: ticket.id )
}
tickets
end end
end end

View file

@ -1,6 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::SearchIndex class Ticket
module SearchIndex
=begin =begin
@ -15,95 +16,95 @@ returns
=end =end
def search_index_update_backend def search_index_update_backend
return if !self.class.search_index_support_config return if !self.class.search_index_support_config
# default ignored attributes # default ignored attributes
ignore_attributes = { ignore_attributes = {
created_by_id: true, created_by_id: true,
updated_by_id: true, updated_by_id: true,
active: true, active: true,
}
if self.class.search_index_support_config[:ignore_attributes]
self.class.search_index_support_config[:ignore_attributes].each {|key, value|
ignore_attributes[key] = value
} }
end if self.class.search_index_support_config[:ignore_attributes]
self.class.search_index_support_config[:ignore_attributes].each {|key, value|
# for performance reasons, Model.search_index_reload will only collect if of object ignore_attributes[key] = value
# get whole data here }
ticket = self.class.find(self.id)
# remove ignored attributes
attributes = ticket.attributes
ignore_attributes.each {|key, value|
next if value != true
attributes.delete( key.to_s )
}
# add tags
tags = Tag.tag_list( object: 'Ticket', o_id: self.id )
if tags && !tags.empty?
attributes[:tag] = tags
end
# lookup attributes of ref. objects (normally name and note)
attributes = search_index_attribute_lookup( attributes, ticket )
# list ignored file extentions
attachments_ignore = Setting.get('es_attachment_ignore') || [ '.png', '.jpg', '.jpeg', '.mpeg', '.mpg', '.mov', '.bin', '.exe' ]
# max attachment size
attachment_max_size_in_mb = Setting.get('es_attachment_max_size_in_mb') || 40
# collect article data
articles = Ticket::Article.where( ticket_id: self.id )
attributes['articles'] = []
articles.each {|article|
article_attributes = article.attributes
# remove note needed attributes
ignore = ['created_by_id', 'updated_by_id', 'updated_at', 'references', 'message_id_md5', 'message_id', 'in_reply_to', 'ticket_id']
ignore.each {|attribute|
article_attributes.delete( attribute )
}
# lookup attributes of ref. objects (normally name and note)
article_attributes = search_index_attribute_lookup( article_attributes, article )
# index raw text body
if article_attributes['content_type'] && article_attributes['content_type'] == 'text/html' && article_attributes['body']
article_attributes['body'] = article_attributes['body'].html2text
end end
# lookup attachments # for performance reasons, Model.search_index_reload will only collect if of object
article.attachments.each {|attachment| # get whole data here
if !article_attributes['attachments'] ticket = self.class.find(self.id)
article_attributes['attachments'] = []
# remove ignored attributes
attributes = ticket.attributes
ignore_attributes.each {|key, value|
next if value != true
attributes.delete( key.to_s )
}
# add tags
tags = Tag.tag_list( object: 'Ticket', o_id: self.id )
if tags && !tags.empty?
attributes[:tag] = tags
end
# lookup attributes of ref. objects (normally name and note)
attributes = search_index_attribute_lookup( attributes, ticket )
# list ignored file extentions
attachments_ignore = Setting.get('es_attachment_ignore') || [ '.png', '.jpg', '.jpeg', '.mpeg', '.mpg', '.mov', '.bin', '.exe' ]
# max attachment size
attachment_max_size_in_mb = Setting.get('es_attachment_max_size_in_mb') || 40
# collect article data
articles = Ticket::Article.where( ticket_id: self.id )
attributes['articles'] = []
articles.each {|article|
article_attributes = article.attributes
# remove note needed attributes
ignore = ['created_by_id', 'updated_by_id', 'updated_at', 'references', 'message_id_md5', 'message_id', 'in_reply_to', 'ticket_id']
ignore.each {|attribute|
article_attributes.delete( attribute )
}
# lookup attributes of ref. objects (normally name and note)
article_attributes = search_index_attribute_lookup( article_attributes, article )
# index raw text body
if article_attributes['content_type'] && article_attributes['content_type'] == 'text/html' && article_attributes['body']
article_attributes['body'] = article_attributes['body'].html2text
end end
# check file size # lookup attachments
if attachment.content && attachment.content.size / 1024 <= attachment_max_size_in_mb * 1024 article.attachments.each {|attachment|
if !article_attributes['attachments']
article_attributes['attachments'] = []
end
# check ignored files # check file size
if attachment.filename if attachment.content && attachment.content.size / 1024 <= attachment_max_size_in_mb * 1024
filename_extention = attachment.filename.downcase
filename_extention.gsub!(/^.*(\..+?)$/, '\\1') # check ignored files
if !attachments_ignore.include?( filename_extention.downcase ) if attachment.filename
data = { filename_extention = attachment.filename.downcase
'_name' => attachment.filename, filename_extention.gsub!(/^.*(\..+?)$/, '\\1')
'_content' => Base64.encode64( attachment.content ) if !attachments_ignore.include?( filename_extention.downcase )
} data = {
article_attributes['attachments'].push data '_name' => attachment.filename,
'_content' => Base64.encode64( attachment.content )
}
article_attributes['attachments'].push data
end
end end
end end
end }
attributes['articles'].push article_attributes
} }
attributes['articles'].push article_attributes
}
return if !attributes return if !attributes
SearchIndexBackend.add(self.class.to_s, attributes) SearchIndexBackend.add(self.class.to_s, attributes)
end
end end
end end

View file

@ -1,10 +1,11 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Ticket::State < ApplicationModel class Ticket
belongs_to :state_type, class_name: 'Ticket::StateType' class State < ApplicationModel
validates :name, presence: true belongs_to :state_type, class_name: 'Ticket::StateType'
validates :name, presence: true
latest_change_support latest_change_support
=begin =begin
@ -18,18 +19,18 @@ returns:
=end =end
def self.by_category(category) def self.by_category(category)
if category == 'open' if category == 'open'
return Ticket::State.where( return Ticket::State.where(
state_type_id: Ticket::StateType.where( name: ['new', 'open', 'pending reminder', 'pending action'] ) state_type_id: Ticket::StateType.where( name: ['new', 'open', 'pending reminder', 'pending action'] )
) )
elsif category == 'closed' elsif category == 'closed'
return Ticket::State.where( return Ticket::State.where(
state_type_id: Ticket::StateType.where( name: ['closed'] ) state_type_id: Ticket::StateType.where( name: ['closed'] )
) )
end
raise "Unknown category '#{category}'"
end end
raise "Unknown category '#{category}'"
end
=begin =begin
@ -45,9 +46,10 @@ returns:
=end =end
def ignore_escalation? def ignore_escalation?
ignore_escalation = ['removed', 'closed', 'merged'] ignore_escalation = ['removed', 'closed', 'merged']
return true if ignore_escalation.include?( self.name ) return true if ignore_escalation.include?( self.name )
false false
end
end end
end end

View file

@ -1,7 +1,9 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Ticket::StateType < ApplicationModel class Ticket
has_many :states, class_name: 'Ticket::State' class StateType < ApplicationModel
validates :name, presence: true has_many :states, class_name: 'Ticket::State'
latest_change_support validates :name, presence: true
latest_change_support
end
end end

View file

@ -1,6 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
module Ticket::Subject class Ticket
module Subject
=begin =begin
@ -15,28 +16,28 @@ returns
=end =end
def subject_build (subject) def subject_build (subject)
# clena subject # clena subject
subject = self.subject_clean(subject) subject = self.subject_clean(subject)
ticket_hook = Setting.get('ticket_hook') ticket_hook = Setting.get('ticket_hook')
ticket_hook_divider = Setting.get('ticket_hook_divider') ticket_hook_divider = Setting.get('ticket_hook_divider')
# none position # none position
if Setting.get('ticket_hook_position') == 'none' if Setting.get('ticket_hook_position') == 'none'
return subject return subject
end
# right position
if Setting.get('ticket_hook_position') == 'right'
return subject + " [#{ticket_hook}#{ticket_hook_divider}#{self.number}] "
end
# left position
return "[#{ticket_hook}#{ticket_hook_divider}#{self.number}] " + subject
end end
# right position
if Setting.get('ticket_hook_position') == 'right'
return subject + " [#{ticket_hook}#{ticket_hook_divider}#{self.number}] "
end
# left position
return "[#{ticket_hook}#{ticket_hook_divider}#{self.number}] " + subject
end
=begin =begin
clean subject remove ticket number and other not needed chars clean subject remove ticket number and other not needed chars
@ -50,29 +51,30 @@ returns
=end =end
def subject_clean (subject) def subject_clean (subject)
ticket_hook = Setting.get('ticket_hook') ticket_hook = Setting.get('ticket_hook')
ticket_hook_divider = Setting.get('ticket_hook_divider') ticket_hook_divider = Setting.get('ticket_hook_divider')
ticket_subject_size = Setting.get('ticket_subject_size') ticket_subject_size = Setting.get('ticket_subject_size')
# remove all possible ticket hook formats with [] # remove all possible ticket hook formats with []
subject = subject.gsub /\[#{ticket_hook}: #{self.number}\](\s+?|)/, '' subject = subject.gsub /\[#{ticket_hook}: #{self.number}\](\s+?|)/, ''
subject = subject.gsub /\[#{ticket_hook}:#{self.number}\](\s+?|)/, '' subject = subject.gsub /\[#{ticket_hook}:#{self.number}\](\s+?|)/, ''
subject = subject.gsub /\[#{ticket_hook}#{ticket_hook_divider}#{self.number}\](\s+?|)/, '' subject = subject.gsub /\[#{ticket_hook}#{ticket_hook_divider}#{self.number}\](\s+?|)/, ''
# remove all possible ticket hook formats without [] # remove all possible ticket hook formats without []
subject = subject.gsub /#{ticket_hook}: #{self.number}(\s+?|)/, '' subject = subject.gsub /#{ticket_hook}: #{self.number}(\s+?|)/, ''
subject = subject.gsub /#{ticket_hook}:#{self.number}(\s+?|)/, '' subject = subject.gsub /#{ticket_hook}:#{self.number}(\s+?|)/, ''
subject = subject.gsub /#{ticket_hook}#{ticket_hook_divider}#{self.number}(\s+?|)/, '' subject = subject.gsub /#{ticket_hook}#{ticket_hook_divider}#{self.number}(\s+?|)/, ''
# remove leading "..:\s" and "..[\d+]:\s" e. g. "Re: " or "Re[5]: " # remove leading "..:\s" and "..[\d+]:\s" e. g. "Re: " or "Re[5]: "
subject = subject.gsub /^(..(\[\d+\])?:\s)+/, '' subject = subject.gsub /^(..(\[\d+\])?:\s)+/, ''
# resize subject based on config # resize subject based on config
if subject.length > ticket_subject_size.to_i if subject.length > ticket_subject_size.to_i
subject = subject[ 0, ticket_subject_size.to_i ] + '[...]' subject = subject[ 0, ticket_subject_size.to_i ] + '[...]'
end
subject
end end
subject
end end
end end

View file

@ -75,11 +75,10 @@ returns
end end
end end
['created_by_id', 'updated_by_id'].each {|item| ['created_by_id', 'updated_by_id'].each {|item|
if self[ item ] next if !self[ item ]
if !data[ User.to_app_model ][ self[ item ] ] if !data[ User.to_app_model ][ self[ item ] ]
user = User.lookup( id: self[ item ] ) user = User.lookup( id: self[ item ] )
data = user.assets( data ) data = user.assets( data )
end
end end
} }
data data