Moved back to compact module/class definition to prevent "superclass mismatch for class Ticket (TypeError)".

This commit is contained in:
Martin Edenhofer 2015-04-28 01:19:26 +02:00
parent 95e27b0994
commit ba1d7abf91
22 changed files with 1119 additions and 1173 deletions

View file

@ -1,7 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::ActivityStreamLog
module ActivityStreamLog
=begin =begin
@ -16,25 +15,24 @@ 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,52 +1,50 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket::Article < ApplicationModel
load 'ticket/article/assets.rb'
include Ticket::Article::Assets
load 'ticket/article/history_log.rb'
include Ticket::Article::HistoryLog
load 'ticket/article/activity_stream_log.rb'
include Ticket::Article::ActivityStreamLog
class Ticket belongs_to :ticket
class Article < ApplicationModel belongs_to :type, class_name: 'Ticket::Article::Type'
load 'ticket/article/assets.rb' belongs_to :sender, class_name: 'Ticket::Article::Sender'
include Ticket::Article::Assets belongs_to :created_by, class_name: 'User'
load 'ticket/article/history_log.rb' belongs_to :updated_by, class_name: 'User'
include Ticket::Article::HistoryLog before_create :check_subject
load 'ticket/article/activity_stream_log.rb' before_update :check_subject
include Ticket::Article::ActivityStreamLog notify_clients_support
belongs_to :ticket activity_stream_support ignore_attributes: {
belongs_to :type, class_name: 'Ticket::Article::Type' type_id: true,
belongs_to :sender, class_name: 'Ticket::Article::Sender' sender_id: true,
belongs_to :created_by, class_name: 'User' }
belongs_to :updated_by, class_name: 'User'
before_create :check_subject
before_update :check_subject
notify_clients_support
activity_stream_support ignore_attributes: { history_support ignore_attributes: {
type_id: true, type_id: true,
sender_id: true, sender_id: true,
} }
history_support ignore_attributes: { private
type_id: true,
sender_id: true,
}
private def check_subject
if self.subject
def check_subject self.subject.gsub!(/\s|\t|\r/, ' ')
if self.subject
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,8 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::Article::ActivityStreamLog
class Article
module ActivityStreamLog
=begin =begin
@ -17,27 +15,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]
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,8 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Ticket module Ticket::Article::Assets
class Article
module Assets
=begin =begin
@ -23,35 +21,33 @@ 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
if !data[ Ticket.to_app_model ][ self.ticket_id ]
ticket = Ticket.find( self.ticket_id )
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|
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
if !data[ Ticket.to_app_model ][ self.ticket_id ]
ticket = Ticket.find( self.ticket_id )
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|
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

View file

@ -1,8 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Ticket module Ticket::Article::HistoryLog
class Article
module HistoryLog
=begin =begin
@ -17,18 +15,16 @@ 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,7 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::Assets
module Assets
=begin =begin
@ -22,22 +21,21 @@ 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
if !data[ Ticket.to_app_model ][ self.id ]
data[ Ticket.to_app_model ][ self.id ] = self.attributes_with_associations
end
['created_by_id', 'updated_by_id', 'owner_id', 'customer_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
if !data[ Ticket.to_app_model ][ self.id ]
data[ Ticket.to_app_model ][ self.id ] = self.attributes_with_associations
end
['created_by_id', 'updated_by_id', 'owner_id', 'customer_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

View file

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

View file

@ -1,7 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::Escalation
module Escalation
=begin =begin
@ -15,14 +14,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
@ -37,128 +36,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.update_time_escal_date = nil # self.close_time_escal_date = nil
self.close_time_escal_date = nil self.callback_loop = true
self.save
# first response return true
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
@ -172,154 +171,153 @@ 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 sla_selected = sla
elsif sla.condition elsif sla.condition
hit = false hit = false
map = [ map = [
[ 'tickets.priority_id', 'priority_id' ], [ 'tickets.priority_id', 'priority_id' ],
[ 'tickets.group_id', 'group_id' ] [ 'tickets.group_id', 'group_id' ]
] ]
map.each {|item| map.each {|item|
if sla.condition[ item[0] ] if sla.condition[ item[0] ]
if sla.condition[ item[0] ].class == String if sla.condition[ item[0] ].class == String
sla.condition[ item[0] ] = [ sla.condition[ item[0] ] ] sla.condition[ item[0] ] = [ sla.condition[ item[0] ] ]
end end
if sla.condition[ item[0] ].include?( self[ item[1] ].to_s ) if sla.condition[ item[0] ].include?( self[ item[1] ].to_s )
hit = true hit = true
else else
hit = false hit = false
end
end end
}
if hit
sla_selected = sla
end end
}
if hit
sla_selected = sla
end end
}
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 sla_selected
#get history for ticket end
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
end
total_time_without_pending = 0
total_time = 0
#get history for ticket
history_list = self.history_get
# ignore all older state changes after end_time #loop through hist. changes and get time
next if last_state_change && last_state_change > end_time last_state = nil
last_state_change = nil
last_state_is_pending = false
history_list.each { |history_item|
# if created_at is later then end_time, use end_time as last time # ignore if it isn't a state change
if history_item['created_at'] > end_time next if !history_item['attribute']
history_item['created_at'] = end_time next if history_item['attribute'] != 'state'
end
# get initial state and time # ignore all newer state before start_time
if !last_state next if history_item['created_at'] < start_time
last_state = history_item['value_from']
last_state_change = start_time
end
# check if time need to be counted # ignore all older state changes after end_time
counted = true next if last_state_change && last_state_change > end_time
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 created_at is later then end_time, use end_time as last time
if counted if history_item['created_at'] > end_time
# puts "Diff count #{history_item['value_from']} -> #{history_item['value_to']} / #{last_state_change} -> #{history_item['created_at']}" history_item['created_at'] = end_time
total_time_without_pending = total_time_without_pending + diff end
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' # get initial state and time
last_state_is_pending = true if !last_state
else last_state = history_item['value_from']
last_state_is_pending = false last_state_change = start_time
end end
# remember for next loop last state # check if time need to be counted
last_state = history_item['value_to'] counted = true
last_state_change = history_item['created_at'] if history_item['value_from'] == 'pending reminder'
} counted = false
elsif history_item['value_from'] == 'close'
counted = false
end
# if last state isnt pending, count rest diff = escalation_time_diff( last_state_change, history_item['created_at'], sla_selected )
if !last_state_is_pending && last_state_change && last_state_change < end_time if counted
diff = escalation_time_diff( last_state_change, end_time, sla_selected ) # puts "Diff count #{history_item['value_from']} -> #{history_item['value_to']} / #{last_state_change} -> #{history_item['created_at']}"
# 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
total_time = total_time + diff
end
# if we have not had any state change
if !last_state_change
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
#return sum
if type == 'real'
return total_time_without_pending
elsif type == 'relative'
relative = total_time - total_time_without_pending
return relative
else else
raise "ERROR: Unknown type #{type}" # puts "Diff not count #{history_item['value_from']} -> #{history_item['value_to']} / #{last_state_change} -> #{history_item['created_at']}"
end 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 = total_time + diff
end end
def escalation_time_diff( start_time, end_time, sla_selected ) # if we have not had any state change
if sla_selected if !last_state_change
diff = TimeCalculation.business_time_diff( start_time, end_time, sla_selected.data, sla_selected.timezone) diff = escalation_time_diff( start_time, end_time, sla_selected )
else # puts 'Diff state has not changed ' + diff.to_s
diff = TimeCalculation.business_time_diff( start_time, end_time ) total_time_without_pending = total_time_without_pending + diff
end total_time = total_time + diff
diff
end end
def calculation_higher_time(escalation_time, check_time, done_time) #return sum
return escalation_time if done_time if type == 'real'
return check_time if !escalation_time return total_time_without_pending
return escalation_time if !check_time elsif type == 'relative'
return check_time if escalation_time > check_time relative = total_time - total_time_without_pending
escalation_time return relative
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
escalation_time
end
end end

View file

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

View file

@ -1,7 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::HistoryLog
module HistoryLog
=begin =begin
@ -16,15 +15,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
@ -58,25 +57,24 @@ 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
if item['related_object'] }
record = Kernel.const_get( item['related_object'] ).find( item['related_o_id'] ) {
assets = record.assets(assets) history: list,
end assets: assets,
} }
{
history: list,
assets: assets,
}
end
end end
end end

View file

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

View file

@ -1,88 +1,84 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
module Ticket::Number::Date
extend self
class Ticket def generate
class Number
module Date
extend self
def generate # get config
config = Setting.get('ticket_number_date')
# get config t = Time.zone.now
config = Setting.get('ticket_number_date') date = t.strftime('%Y-%m-%d')
t = Time.zone.now # read counter
date = t.strftime('%Y-%m-%d') counter_increment = nil
Ticket::Counter.transaction do
# read counter counter = Ticket::Counter.where( generator: 'Date' ).lock(true).first
counter_increment = nil if !counter
Ticket::Counter.transaction do counter = Ticket::Counter.new( generator: 'Date', content: '0' )
counter = Ticket::Counter.where( generator: 'Date' ).lock(true).first
if !counter
counter = Ticket::Counter.new( generator: 'Date', content: '0' )
end
# increase counter
counter_increment, date_file = counter.content.to_s.split(';')
if date_file == date
counter_increment = counter_increment.to_i + 1
else
counter_increment = 1
end
# store new counter value
counter.content = counter_increment.to_s + ';' + date
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
chksum %= 10
chksum = 10 - chksum
if chksum == 10
chksum = 1
end
number += chksum.to_s
end
number
end end
def check(string) # increase counter
counter_increment, date_file = counter.content.to_s.split(';')
# get config if date_file == date
system_id = Setting.get('system_id') || '' counter_increment = counter_increment.to_i + 1
ticket_hook = Setting.get('ticket_hook') else
ticket_hook_divider = Setting.get('ticket_hook_divider') || '' counter_increment = 1
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
# store new counter value
counter.content = counter_increment.to_s + ';' + date
counter.save
end 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
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 end

View file

@ -1,91 +1,87 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
class Ticket module Ticket::Number::Increment
class Number extend self
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
counter_increment = counter.content.to_i
# increase counter
counter_increment += 1
# store new counter value
counter.content = counter_increment.to_s
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
chksum %= 10
chksum = 10 - chksum
if chksum == 10
chksum = 1
end
number += chksum.to_s
end
number
end end
counter_increment = counter.content.to_i
def check(string) # increase counter
counter_increment += 1
# get config # store new counter value
system_id = Setting.get('system_id') || '' counter.content = counter_increment.to_s
ticket_hook = Setting.get('ticket_hook') counter.save
ticket_hook_divider = Setting.get('ticket_hook_divider') || '' end
ticket = nil
# probe format # fill up number counter
if string =~ /#{ticket_hook}#{ticket_hook_divider}(#{system_id}\d{2,48})/i if config[:checksum]
ticket = Ticket.where( number: $1 ).first min_digs = min_digs.to_i - 1
elsif string =~ /#{ticket_hook}\s{0,2}(#{system_id}\d{2,48})/i end
ticket = Ticket.where( number: $1 ).first fillup = Setting.get('system_id') || '1'
end ( 1..100 ).each do |i|
ticket if ( fillup.length.to_i + counter_increment.to_s.length.to_i ) < min_digs.to_i
fillup = fillup + '0'
end end
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
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
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
end end

View file

@ -1,7 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::Overviews
module Overviews
=begin =begin
@ -17,25 +16,25 @@ 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
# get agent overviews
role = data[:current_user].is_role( 'Agent' )
return if !role
Overview.where( role_id: role.id, active: true )
end end
# get agent overviews
role = data[:current_user].is_role( 'Agent' )
return if !role
Overview.where( role_id: role.id, active: true )
end
=begin =begin
selected overview by user selected overview by user
@ -55,199 +54,198 @@ 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|
# remember selected view # get count
if data[:view] && data[:view] == overview.link count = Ticket.where( group_id: group_ids ).where( _condition( overview.condition ) ).count()
overview_selected = overview
overview_selected_raw = Marshal.load( Marshal.dump(overview.attributes) )
end
# replace e.g. 'current_user.id' with current_user.id # get meta info
overview.condition.each { |item, value | all = {
if value && value.class.to_s == 'String' name: overview.name,
parts = value.split( '.', 2 ) prio: overview.prio,
if parts[0] && parts[1] && parts[0] == 'current_user' link: overview.link,
overview.condition[item] = data[:current_user][parts[1].to_sym]
end
end
} }
# push to result data
result.push all.merge( { count: count } )
} }
return result
end
if data[:view] && !overview_selected # get result list
raise "No such view '#{ data[:view] }'" 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 end
tickets = Ticket.select( 'id' ).
# sortby where( group_id: group_ids ).
# 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
}
tickets_count = Ticket.where( group_id: group_ids ).
where( _condition( overview_selected.condition ) ).
count()
return {
ticket_ids: ticket_ids,
tickets_count: tickets_count,
overview: overview_selected_raw,
}
end
# get tickets for overview
data[:start_page] ||= 1
tickets = Ticket.where( group_id: group_ids ).
where( _condition( overview_selected.condition ) ). where( _condition( overview_selected.condition ) ).
order( overview_selected[:order][:by].to_s + ' ' + overview_selected[:order][:direction].to_s )#. order( order_by ).
# limit( overview_selected.view[ data[:view_mode].to_sym ][:per_page] ). limit( 500 )
# offset( overview_selected.view[ data[:view_mode].to_sym ][:per_page].to_i * ( data[:start_page].to_i - 1 ) )
ticket_ids = []
tickets.each { |ticket|
ticket_ids.push ticket.id
}
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 {
tickets: tickets, ticket_ids: ticket_ids,
tickets_count: tickets_count, tickets_count: tickets_count,
overview: overview_selected_raw, overview: overview_selected_raw,
} }
end end
private # get tickets for overview
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 ) )
def self._condition(condition) tickets_count = Ticket.where( group_id: group_ids ).
sql = '' where( _condition( overview_selected.condition ) ).
bind = [nil] count()
condition.each {|key, value|
if sql != '' {
sql += ' AND ' tickets: tickets,
end tickets_count: tickets_count,
if value.class == Array overview: overview_selected_raw,
sql += " #{key} IN (?)" }
bind.push value end
elsif value.class == Hash || value.class == ActiveSupport::HashWithIndifferentAccess
time = Time.now private
if value['area'] == 'minute'
if value['direction'] == 'last' def self._condition(condition)
time -= value['count'].to_i * 60 sql = ''
else bind = [nil]
time += value['count'].to_i * 60 condition.each {|key, value|
end if sql != ''
elsif value['area'] == 'hour' sql += ' AND '
if value['direction'] == 'last' end
time -= value['count'].to_i * 60 * 60 if value.class == Array
else sql += " #{key} IN (?)"
time += value['count'].to_i * 60 * 60 bind.push value
end elsif value.class == Hash || value.class == ActiveSupport::HashWithIndifferentAccess
elsif value['area'] == 'day' time = Time.now
if value['direction'] == 'last' if value['area'] == 'minute'
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' if value['direction'] == 'last'
sql += " #{key} > ?" time -= value['count'].to_i * 60
bind.push time
else else
sql += " #{key} < ?" time += value['count'].to_i * 60
bind.push time 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
else
sql += " #{key} = ?"
bind.push value
end end
} if value['direction'] == 'last'
bind[0] = sql sql += " #{key} > ?"
bind bind.push time
end else
sql += " #{key} < ?"
bind.push time
end
else
sql += " #{key} = ?"
bind.push value
end
}
bind[0] = sql
bind
end end
end end

View file

@ -1,7 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::Permission
module Permission
=begin =begin
@ -16,33 +15,32 @@ 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
# check agent # no access
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,8 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket class Ticket::Priority < ApplicationModel
class Priority < ApplicationModel self.table_name = 'ticket_priorities'
self.table_name = 'ticket_priorities' validates :name, presence: true
validates :name, presence: true
end
end end

View file

@ -1,7 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::ScreenOptions
module ScreenOptions
=begin =begin
@ -15,9 +14,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
@ -43,83 +42,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 end
if params[:article_id] if params[:article_id]
params[:article] = Ticket::Article.find( params[:article_id] ) params[:article] = Ticket::Article.find( params[:article_id] )
end end
filter = {} filter = {}
assets = {} assets = {}
# get ticket states # get ticket states
state_ids = [] state_ids = []
if params[:ticket] if params[:ticket]
state_type = params[:ticket].state.state_type state_type = params[:ticket].state.state_type
end end
state_types = ['open', 'closed', 'pending action', 'pending reminder'] state_types = ['open', 'closed', 'pending action', 'pending reminder']
if state_type && !state_types.include?(state_type.name) if state_type && !state_types.include?(state_type.name)
state_ids.push params[:ticket].state.id state_ids.push params[:ticket].state.id
end end
state_types.each {|type| state_types.each {|type|
state_type = Ticket::StateType.where( name: type ).first state_type = Ticket::StateType.where( name: type ).first
if state_type if state_type
state_type.states.each {|state| state_type.states.each {|state|
assets = state.assets(assets) assets = state.assets(assets)
state_ids.push state.id state_ids.push state.id
}
end
}
filter[:state_id] = state_ids
# 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
types.each {|type_name|
type = Ticket::Article::Type.lookup( name: type_name )
if type
type_ids.push type.id
end
} }
end end
filter[:type_id] = type_ids }
filter[:state_id] = state_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
}
filter[:priority_id] = priority_ids
dependencies = { group_id: { '' => { owner_id: [] } } } type_ids = []
Group.where( active: true ).each { |group| if params[:ticket]
assets = group.assets(assets) types = ['note', 'phone']
dependencies[:group_id][group.id] = { owner_id: [] } if params[:ticket].group.email_address_id
group.users.each {|user| types.push 'email'
next if !agents[ user.id ] end
assets = user.assets(assets) types.each {|type_name|
dependencies[:group_id][ group.id ][ :owner_id ].push user.id type = Ticket::Article::Type.lookup( name: type_name )
} if type
} type_ids.push type.id
end
{
assets: assets,
filter: filter,
dependencies: dependencies,
} }
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
@ -140,39 +139,38 @@ 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,7 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::Search
module Search
=begin =begin
@ -46,102 +45,101 @@ 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 end
# try search index backend # try search index backend
if !params[:detail] && SearchIndexBackend.enabled? if !params[:detail] && SearchIndexBackend.enabled?
query_extention = {} query_extention = {}
query_extention['bool'] = {} query_extention['bool'] = {}
query_extention['bool']['must'] = [] query_extention['bool']['must'] = []
if current_user.is_role('Agent') if current_user.is_role('Agent')
groups = Group.joins(:users) groups = Group.joins(:users)
.where( 'groups_users.user_id = ?', current_user.id ) .where( 'groups_users.user_id = ?', current_user.id )
.where( 'groups.active = ?', true ) .where( 'groups.active = ?', true )
group_condition = [] group_condition = []
groups.each {|group| groups.each {|group|
group_condition.push group.name 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 access_condition = {
end 'query_string' => { 'default_field' => 'Ticket.group.name', 'query' => "\"#{group_condition.join('" OR "')}\"" }
}
# fallback do sql query query_extention['bool']['must'].push access_condition
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 else
tickets_all = Ticket.select('DISTINCT(tickets.id)') if !current_user.organization || ( !current_user.organization.shared || current_user.organization.shared == false )
.where(access_condition) access_condition = {
.where(params[:condition]) 'query_string' => { 'default_field' => 'Ticket.customer_id', 'query' => current_user.id }
.order('`tickets`.`created_at` DESC') }
.limit(limit) # 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
# build result list items = SearchIndexBackend.search( query, limit, 'Ticket', query_extention )
if !full if !full
ids = [] ids = []
tickets_all.each { |ticket| items.each {|item|
ids.push ticket.id ids.push item[:id]
} }
return ids return ids
end end
tickets = [] tickets = []
tickets_all.each { |ticket| items.each { |item|
tickets.push Ticket.lookup( id: ticket.id ) tickets.push Ticket.lookup( id: item[:id] )
} }
tickets return tickets
end 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|
ids.push ticket.id
}
return ids
end
tickets = []
tickets_all.each { |ticket|
tickets.push Ticket.lookup( id: ticket.id )
}
tickets
end end
end end

View file

@ -1,7 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::SearchIndex
module SearchIndex
=begin =begin
@ -16,95 +15,94 @@ 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
} }
if self.class.search_index_support_config[:ignore_attributes] end
self.class.search_index_support_config[:ignore_attributes].each {|key, value|
ignore_attributes[key] = value
}
end
# for performance reasons, Model.search_index_reload will only collect if of object # for performance reasons, Model.search_index_reload will only collect if of object
# get whole data here # get whole data here
ticket = self.class.find(self.id) ticket = self.class.find(self.id)
# remove ignored attributes # remove ignored attributes
attributes = ticket.attributes attributes = ticket.attributes
ignore_attributes.each {|key, value| ignore_attributes.each {|key, value|
next if value != true next if value != true
attributes.delete( key.to_s ) 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 )
} }
# 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) # lookup attributes of ref. objects (normally name and note)
attributes = search_index_attribute_lookup( attributes, ticket ) article_attributes = search_index_attribute_lookup( article_attributes, article )
# list ignored file extentions # index raw text body
attachments_ignore = Setting.get('es_attachment_ignore') || [ '.png', '.jpg', '.jpeg', '.mpeg', '.mpg', '.mov', '.bin', '.exe' ] if article_attributes['content_type'] && article_attributes['content_type'] == 'text/html' && article_attributes['body']
article_attributes['body'] = article_attributes['body'].html2text
end
# max attachment size # lookup attachments
attachment_max_size_in_mb = Setting.get('es_attachment_max_size_in_mb') || 40 article.attachments.each {|attachment|
if !article_attributes['attachments']
# collect article data article_attributes['attachments'] = []
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 # check file size
article.attachments.each {|attachment| if attachment.content && attachment.content.size / 1024 <= attachment_max_size_in_mb * 1024
if !article_attributes['attachments']
article_attributes['attachments'] = []
end
# check file size # check ignored files
if attachment.content && attachment.content.size / 1024 <= attachment_max_size_in_mb * 1024 if attachment.filename
filename_extention = attachment.filename.downcase
# check ignored files filename_extention.gsub!(/^.*(\..+?)$/, '\\1')
if attachment.filename if !attachments_ignore.include?( filename_extention.downcase )
filename_extention = attachment.filename.downcase data = {
filename_extention.gsub!(/^.*(\..+?)$/, '\\1') '_name' => attachment.filename,
if !attachments_ignore.include?( filename_extention.downcase ) '_content' => Base64.encode64( attachment.content )
data = { }
'_name' => attachment.filename, article_attributes['attachments'].push data
'_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,11 +1,10 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket::State < ApplicationModel
belongs_to :state_type, class_name: 'Ticket::StateType'
validates :name, presence: true
class Ticket latest_change_support
class State < ApplicationModel
belongs_to :state_type, class_name: 'Ticket::StateType'
validates :name, presence: true
latest_change_support
=begin =begin
@ -19,18 +18,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
@ -46,10 +45,9 @@ 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,9 +1,7 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket class Ticket::StateType < ApplicationModel
class StateType < ApplicationModel has_many :states, class_name: 'Ticket::State'
has_many :states, class_name: 'Ticket::State' validates :name, presence: true
validates :name, presence: true latest_change_support
latest_change_support
end
end end

View file

@ -1,7 +1,6 @@
# Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2014 Zammad Foundation, http://zammad-foundation.org/
# rubocop:disable ClassAndModuleChildren
class Ticket module Ticket::Subject
module Subject
=begin =begin
@ -16,28 +15,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
@ -51,30 +50,29 @@ 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