2016-10-19 03:11:36 +00:00
|
|
|
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
2015-01-03 22:53:07 +00:00
|
|
|
|
2016-04-15 21:56:10 +00:00
|
|
|
class Transaction::Notification
|
2016-02-22 07:58:33 +00:00
|
|
|
|
|
|
|
=begin
|
2016-04-15 21:56:10 +00:00
|
|
|
{
|
|
|
|
object: 'Ticket',
|
2016-02-27 11:48:44 +00:00
|
|
|
type: 'update',
|
2016-04-22 06:55:10 +00:00
|
|
|
object_id: 123,
|
2016-08-20 19:29:22 +00:00
|
|
|
interface_handle: 'application_server', # application_server|websocket|scheduler
|
2016-02-27 11:48:44 +00:00
|
|
|
changes: {
|
2016-04-15 21:56:10 +00:00
|
|
|
'attribute1' => [before, now],
|
|
|
|
'attribute2' => [before, now],
|
2016-07-16 21:43:08 +00:00
|
|
|
},
|
|
|
|
created_at: Time.zone.now,
|
2016-04-27 07:31:11 +00:00
|
|
|
user_id: 123,
|
2016-04-15 21:56:10 +00:00
|
|
|
},
|
2016-02-22 07:58:33 +00:00
|
|
|
=end
|
2016-04-15 21:56:10 +00:00
|
|
|
|
|
|
|
def initialize(item, params = {})
|
|
|
|
@item = item
|
|
|
|
@params = params
|
2014-08-25 23:58:04 +00:00
|
|
|
end
|
2015-05-07 10:27:12 +00:00
|
|
|
|
2014-08-25 23:58:04 +00:00
|
|
|
def perform
|
2016-04-22 06:55:10 +00:00
|
|
|
|
|
|
|
# return if we run import mode
|
|
|
|
return if Setting.get('import_mode')
|
|
|
|
return if @item[:object] != 'Ticket'
|
2016-04-16 09:13:12 +00:00
|
|
|
return if @params[:disable_notification]
|
|
|
|
|
2017-09-05 09:49:32 +00:00
|
|
|
ticket = Ticket.find_by(id: @item[:object_id])
|
|
|
|
return if !ticket
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-04-15 21:56:10 +00:00
|
|
|
if @item[:article_id]
|
|
|
|
article = Ticket::Article.find(@item[:article_id])
|
2016-05-04 09:45:05 +00:00
|
|
|
|
|
|
|
# ignore notifications
|
|
|
|
sender = Ticket::Article::Sender.lookup(id: article.sender_id)
|
2017-11-23 08:09:44 +00:00
|
|
|
if sender&.name == 'System'
|
2017-07-26 18:46:31 +00:00
|
|
|
return if @item[:changes].blank? && article.preferences[:notification] != true
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-07-26 18:46:31 +00:00
|
|
|
if article.preferences[:notification] != true
|
|
|
|
article = nil
|
|
|
|
end
|
2016-05-04 09:45:05 +00:00
|
|
|
end
|
2015-01-03 22:53:07 +00:00
|
|
|
end
|
2014-08-25 23:58:04 +00:00
|
|
|
|
|
|
|
# find recipients
|
2016-02-07 13:00:29 +00:00
|
|
|
recipients_and_channels = []
|
2017-09-05 09:49:32 +00:00
|
|
|
recipients_reason = {}
|
2014-08-25 23:58:04 +00:00
|
|
|
|
2016-02-07 13:00:29 +00:00
|
|
|
# loop through all users
|
2019-10-04 09:42:44 +00:00
|
|
|
possible_recipients = possible_recipients_of_group(ticket.group_id)
|
2017-09-05 09:49:32 +00:00
|
|
|
|
|
|
|
# apply owner
|
|
|
|
if ticket.owner_id != 1
|
2016-02-07 13:00:29 +00:00
|
|
|
possible_recipients.push ticket.owner
|
2017-09-05 09:49:32 +00:00
|
|
|
recipients_reason[ticket.owner_id] = 'are assigned'
|
|
|
|
end
|
|
|
|
|
|
|
|
# apply out of office agents
|
|
|
|
possible_recipients_additions = Set.new
|
2017-10-01 12:25:52 +00:00
|
|
|
possible_recipients.each do |user|
|
2017-09-05 09:49:32 +00:00
|
|
|
recursive_ooo_replacements(
|
|
|
|
user: user,
|
|
|
|
replacements: possible_recipients_additions,
|
|
|
|
reasons: recipients_reason,
|
|
|
|
)
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2017-09-05 09:49:32 +00:00
|
|
|
|
|
|
|
if possible_recipients_additions.present?
|
|
|
|
# join unique entries
|
|
|
|
possible_recipients = possible_recipients | possible_recipients_additions.to_a
|
2015-01-03 22:53:07 +00:00
|
|
|
end
|
2017-06-20 15:13:42 +00:00
|
|
|
|
2016-02-07 13:00:29 +00:00
|
|
|
already_checked_recipient_ids = {}
|
2017-10-01 12:25:52 +00:00
|
|
|
possible_recipients.each do |user|
|
2016-04-15 21:56:10 +00:00
|
|
|
result = NotificationFactory::Mailer.notification_settings(user, ticket, @item[:type])
|
2016-02-27 11:48:44 +00:00
|
|
|
next if !result
|
2017-09-05 09:49:32 +00:00
|
|
|
next if already_checked_recipient_ids[user.id]
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-09-05 09:49:32 +00:00
|
|
|
already_checked_recipient_ids[user.id] = true
|
2016-02-27 11:48:44 +00:00
|
|
|
recipients_and_channels.push result
|
2017-09-05 09:49:32 +00:00
|
|
|
next if recipients_reason[user.id]
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-09-05 09:49:32 +00:00
|
|
|
recipients_reason[user.id] = 'are in group'
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2014-08-25 23:58:04 +00:00
|
|
|
|
|
|
|
# send notifications
|
2016-02-07 13:00:29 +00:00
|
|
|
recipients_and_channels.each do |item|
|
|
|
|
user = item[:user]
|
|
|
|
channels = item[:channels]
|
2015-01-02 15:50:31 +00:00
|
|
|
|
2016-02-03 07:58:51 +00:00
|
|
|
# ignore user who changed it by him self via web
|
2016-08-20 19:29:22 +00:00
|
|
|
if @params[:interface_handle] == 'application_server'
|
2017-11-23 08:09:44 +00:00
|
|
|
next if article&.updated_by_id == user.id
|
2016-04-27 07:31:11 +00:00
|
|
|
next if !article && @item[:user_id] == user.id
|
2016-02-03 07:58:51 +00:00
|
|
|
end
|
2015-01-09 19:44:04 +00:00
|
|
|
|
|
|
|
# ignore inactive users
|
2017-09-05 09:49:32 +00:00
|
|
|
next if !user.active?
|
2015-01-02 15:50:31 +00:00
|
|
|
|
2016-02-07 13:00:29 +00:00
|
|
|
# ignore if no changes has been done
|
|
|
|
changes = human_changes(user, ticket)
|
2017-07-26 18:46:31 +00:00
|
|
|
next if @item[:type] == 'update' && !article && changes.blank?
|
2014-08-25 23:58:04 +00:00
|
|
|
|
2016-02-22 10:05:33 +00:00
|
|
|
# check if today already notified
|
2016-04-15 21:56:10 +00:00
|
|
|
if @item[:type] == 'reminder_reached' || @item[:type] == 'escalation' || @item[:type] == 'escalation_warning'
|
2016-02-20 10:12:15 +00:00
|
|
|
identifier = user.email
|
|
|
|
if !identifier || identifier == ''
|
|
|
|
identifier = user.login
|
|
|
|
end
|
2020-01-17 16:08:43 +00:00
|
|
|
|
|
|
|
already_notified = History.where(
|
|
|
|
history_type_id: History.type_lookup('notification').id,
|
|
|
|
history_object_id: History.object_lookup('Ticket').id,
|
|
|
|
o_id: ticket.id
|
2020-09-30 09:07:01 +00:00
|
|
|
).where('created_at > ?', Time.zone.now.beginning_of_day).exists?(['value_to LIKE ?', "%#{identifier}(#{@item[:type]}:%"])
|
2020-01-17 16:08:43 +00:00
|
|
|
|
2016-02-20 10:12:15 +00:00
|
|
|
next if already_notified
|
|
|
|
end
|
|
|
|
|
2016-02-07 13:00:29 +00:00
|
|
|
# create online notification
|
|
|
|
used_channels = []
|
|
|
|
if channels['online']
|
|
|
|
used_channels.push 'online'
|
2016-02-20 10:12:15 +00:00
|
|
|
|
2016-04-27 07:31:11 +00:00
|
|
|
created_by_id = @item[:user_id] || 1
|
2016-02-22 19:58:23 +00:00
|
|
|
|
2016-02-20 10:12:15 +00:00
|
|
|
# delete old notifications
|
2016-04-15 21:56:10 +00:00
|
|
|
if @item[:type] == 'reminder_reached'
|
2016-02-20 13:09:56 +00:00
|
|
|
seen = false
|
2016-02-22 19:58:23 +00:00
|
|
|
created_by_id = 1
|
2016-04-15 21:56:10 +00:00
|
|
|
OnlineNotification.remove_by_type('Ticket', ticket.id, @item[:type], user)
|
2016-02-22 07:58:33 +00:00
|
|
|
|
2016-04-15 21:56:10 +00:00
|
|
|
elsif @item[:type] == 'escalation' || @item[:type] == 'escalation_warning'
|
2016-02-22 23:28:13 +00:00
|
|
|
seen = false
|
|
|
|
created_by_id = 1
|
|
|
|
OnlineNotification.remove_by_type('Ticket', ticket.id, 'escalation', user)
|
|
|
|
OnlineNotification.remove_by_type('Ticket', ticket.id, 'escalation_warning', user)
|
|
|
|
|
2016-02-22 07:58:33 +00:00
|
|
|
# on updates without state changes create unseen messages
|
2017-07-26 18:46:31 +00:00
|
|
|
elsif @item[:type] != 'create' && (@item[:changes].blank? || @item[:changes]['state_id'].blank?)
|
2016-02-22 07:58:33 +00:00
|
|
|
seen = false
|
|
|
|
else
|
|
|
|
seen = ticket.online_notification_seen_state(user.id)
|
2016-02-20 10:12:15 +00:00
|
|
|
end
|
2016-02-22 07:58:33 +00:00
|
|
|
|
2016-02-07 13:00:29 +00:00
|
|
|
OnlineNotification.add(
|
2018-12-19 17:31:51 +00:00
|
|
|
type: @item[:type],
|
|
|
|
object: 'Ticket',
|
|
|
|
o_id: ticket.id,
|
|
|
|
seen: seen,
|
2016-02-22 19:58:23 +00:00
|
|
|
created_by_id: created_by_id,
|
2018-12-19 17:31:51 +00:00
|
|
|
user_id: user.id,
|
2016-02-07 13:00:29 +00:00
|
|
|
)
|
2018-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { "sent ticket online notifiaction to agent (#{@item[:type]}/#{ticket.id}/#{user.email})" }
|
2014-08-25 23:58:04 +00:00
|
|
|
end
|
|
|
|
|
2019-07-31 08:23:48 +00:00
|
|
|
# ignore email channel notification and empty emails
|
2020-02-19 14:57:32 +00:00
|
|
|
if !channels['email'] || user.email.blank?
|
2016-04-15 21:56:10 +00:00
|
|
|
add_recipient_list(ticket, user, used_channels, @item[:type])
|
2015-01-09 19:44:04 +00:00
|
|
|
next
|
|
|
|
end
|
2015-01-04 12:52:14 +00:00
|
|
|
|
2016-02-07 13:00:29 +00:00
|
|
|
used_channels.push 'email'
|
2016-04-15 21:56:10 +00:00
|
|
|
add_recipient_list(ticket, user, used_channels, @item[:type])
|
2016-02-07 13:00:29 +00:00
|
|
|
|
2015-01-03 22:53:07 +00:00
|
|
|
# get user based notification template
|
|
|
|
# if create, send create message / block update messages
|
2016-02-19 21:05:36 +00:00
|
|
|
template = nil
|
2020-07-13 12:46:08 +00:00
|
|
|
case @item[:type]
|
|
|
|
when 'create'
|
2016-02-19 21:05:36 +00:00
|
|
|
template = 'ticket_create'
|
2020-07-13 12:46:08 +00:00
|
|
|
when 'update'
|
2016-02-19 21:05:36 +00:00
|
|
|
template = 'ticket_update'
|
2020-07-13 12:46:08 +00:00
|
|
|
when 'reminder_reached'
|
2016-02-20 10:12:15 +00:00
|
|
|
template = 'ticket_reminder_reached'
|
2020-07-13 12:46:08 +00:00
|
|
|
when 'escalation'
|
2016-02-20 10:12:15 +00:00
|
|
|
template = 'ticket_escalation'
|
2020-07-13 12:46:08 +00:00
|
|
|
when 'escalation_warning'
|
2016-02-22 23:28:13 +00:00
|
|
|
template = 'ticket_escalation_warning'
|
2015-01-03 22:53:07 +00:00
|
|
|
else
|
2016-04-15 21:56:10 +00:00
|
|
|
raise "unknown type for notification #{@item[:type]}"
|
2015-01-03 22:53:07 +00:00
|
|
|
end
|
|
|
|
|
2016-04-27 09:21:07 +00:00
|
|
|
current_user = User.lookup(id: @item[:user_id])
|
2016-04-27 07:31:11 +00:00
|
|
|
if !current_user
|
|
|
|
current_user = User.lookup(id: 1)
|
|
|
|
end
|
|
|
|
|
2016-07-11 23:35:30 +00:00
|
|
|
attachments = []
|
|
|
|
if article
|
|
|
|
attachments = article.attachments_inline
|
|
|
|
end
|
2016-04-13 23:40:37 +00:00
|
|
|
NotificationFactory::Mailer.notification(
|
2018-12-19 17:31:51 +00:00
|
|
|
template: template,
|
|
|
|
user: user,
|
|
|
|
objects: {
|
|
|
|
ticket: ticket,
|
|
|
|
article: article,
|
|
|
|
recipient: user,
|
2016-04-27 07:31:11 +00:00
|
|
|
current_user: current_user,
|
2018-12-19 17:31:51 +00:00
|
|
|
changes: changes,
|
|
|
|
reason: recipients_reason[user.id],
|
2016-02-20 07:14:51 +00:00
|
|
|
},
|
2018-12-19 17:31:51 +00:00
|
|
|
message_id: "<notification.#{DateTime.current.to_s(:number)}.#{ticket.id}.#{user.id}.#{rand(999_999)}@#{Setting.get('fqdn')}>",
|
|
|
|
references: ticket.get_references,
|
2016-02-20 07:14:51 +00:00
|
|
|
main_object: ticket,
|
2016-07-11 23:35:30 +00:00
|
|
|
attachments: attachments,
|
2014-08-25 23:58:04 +00:00
|
|
|
)
|
2018-03-20 17:47:49 +00:00
|
|
|
Rails.logger.debug { "sent ticket email notifiaction to agent (#{@item[:type]}/#{ticket.id}/#{user.email})" }
|
2014-08-25 23:58:04 +00:00
|
|
|
end
|
|
|
|
|
2016-02-07 15:53:21 +00:00
|
|
|
end
|
2015-04-30 15:25:04 +00:00
|
|
|
|
2016-02-20 10:12:15 +00:00
|
|
|
def add_recipient_list(ticket, user, channels, type)
|
2017-11-23 08:09:44 +00:00
|
|
|
return if channels.blank?
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2016-02-07 16:17:27 +00:00
|
|
|
identifier = user.email
|
2016-02-08 05:58:28 +00:00
|
|
|
if !identifier || identifier == ''
|
2016-02-07 16:17:27 +00:00
|
|
|
identifier = user.login
|
|
|
|
end
|
2016-02-20 10:12:15 +00:00
|
|
|
recipient_list = "#{identifier}(#{type}:#{channels.join(',')})"
|
2015-04-30 15:25:04 +00:00
|
|
|
History.add(
|
2018-12-19 17:31:51 +00:00
|
|
|
o_id: ticket.id,
|
|
|
|
history_type: 'notification',
|
2015-04-30 15:25:04 +00:00
|
|
|
history_object: 'Ticket',
|
2018-12-19 17:31:51 +00:00
|
|
|
value_to: recipient_list,
|
|
|
|
created_by_id: @item[:user_id] || 1
|
2015-04-30 15:25:04 +00:00
|
|
|
)
|
2014-08-25 23:58:04 +00:00
|
|
|
end
|
2015-01-03 22:53:07 +00:00
|
|
|
|
2015-01-04 12:52:14 +00:00
|
|
|
def human_changes(user, record)
|
|
|
|
|
2016-04-15 21:56:10 +00:00
|
|
|
return {} if !@item[:changes]
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2020-01-27 09:28:17 +00:00
|
|
|
locale = user.locale
|
2015-01-04 12:52:14 +00:00
|
|
|
|
|
|
|
# only show allowed attributes
|
2020-08-20 07:10:08 +00:00
|
|
|
attribute_list = ObjectManager::Object.new('Ticket').attributes(user).index_by { |item| item[:name] }
|
2019-02-10 11:01:38 +00:00
|
|
|
|
2015-01-04 12:52:14 +00:00
|
|
|
user_related_changes = {}
|
2017-10-01 12:25:52 +00:00
|
|
|
@item[:changes].each do |key, value|
|
2015-01-04 15:39:57 +00:00
|
|
|
|
|
|
|
# if no config exists, use all attributes
|
2020-11-12 11:42:44 +00:00
|
|
|
# or if config exists, just use existing attributes for user
|
|
|
|
if attribute_list.blank? || attribute_list[key.to_s]
|
2015-01-04 12:52:14 +00:00
|
|
|
user_related_changes[key] = value
|
|
|
|
end
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2015-01-04 12:52:14 +00:00
|
|
|
|
|
|
|
changes = {}
|
2017-10-01 12:25:52 +00:00
|
|
|
user_related_changes.each do |key, value|
|
2015-01-04 12:52:14 +00:00
|
|
|
|
|
|
|
# get attribute name
|
|
|
|
attribute_name = key.to_s
|
|
|
|
object_manager_attribute = attribute_list[attribute_name]
|
2015-04-27 14:53:29 +00:00
|
|
|
if attribute_name[-3, 3] == '_id'
|
2015-04-27 14:41:03 +00:00
|
|
|
attribute_name = attribute_name[ 0, attribute_name.length - 3 ].to_s
|
2015-01-04 12:52:14 +00:00
|
|
|
end
|
2015-02-10 22:48:14 +00:00
|
|
|
|
|
|
|
# add item to changes hash
|
|
|
|
if key.to_s == attribute_name
|
|
|
|
changes[attribute_name] = value
|
2015-01-04 12:52:14 +00:00
|
|
|
end
|
|
|
|
|
2019-07-31 08:23:48 +00:00
|
|
|
# if changed item is an _id field/reference, look up the real values
|
2015-02-10 22:48:14 +00:00
|
|
|
value_id = []
|
2015-01-04 12:52:14 +00:00
|
|
|
value_str = [ value[0], value[1] ]
|
2015-04-27 14:53:29 +00:00
|
|
|
if key.to_s[-3, 3] == '_id'
|
2015-01-04 12:52:14 +00:00
|
|
|
value_id[0] = value[0]
|
|
|
|
value_id[1] = value[1]
|
|
|
|
|
2016-03-08 06:32:58 +00:00
|
|
|
if record.respond_to?(attribute_name) && record.send(attribute_name)
|
2015-01-04 12:52:14 +00:00
|
|
|
relation_class = record.send(attribute_name).class
|
|
|
|
if relation_class && value_id[0]
|
2016-03-08 06:32:58 +00:00
|
|
|
relation_model = relation_class.lookup(id: value_id[0])
|
2015-01-04 12:52:14 +00:00
|
|
|
if relation_model
|
|
|
|
if relation_model['name']
|
|
|
|
value_str[0] = relation_model['name']
|
|
|
|
elsif relation_model.respond_to?('fullname')
|
|
|
|
value_str[0] = relation_model.send('fullname')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if relation_class && value_id[1]
|
2016-03-08 06:32:58 +00:00
|
|
|
relation_model = relation_class.lookup(id: value_id[1])
|
2015-01-04 12:52:14 +00:00
|
|
|
if relation_model
|
|
|
|
if relation_model['name']
|
|
|
|
value_str[1] = relation_model['name']
|
|
|
|
elsif relation_model.respond_to?('fullname')
|
|
|
|
value_str[1] = relation_model.send('fullname')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2015-02-10 22:48:14 +00:00
|
|
|
|
2019-07-31 08:23:48 +00:00
|
|
|
# check if we have a dedicated display name for it
|
2015-01-04 12:52:14 +00:00
|
|
|
display = attribute_name
|
|
|
|
if object_manager_attribute && object_manager_attribute[:display]
|
2015-02-10 22:48:14 +00:00
|
|
|
|
|
|
|
# delete old key
|
2016-03-08 06:32:58 +00:00
|
|
|
changes.delete(display)
|
2015-02-10 22:48:14 +00:00
|
|
|
|
|
|
|
# set new key
|
|
|
|
display = object_manager_attribute[:display].to_s
|
2015-01-04 12:52:14 +00:00
|
|
|
end
|
2016-01-15 17:22:57 +00:00
|
|
|
changes[display] = if object_manager_attribute && object_manager_attribute[:translate]
|
2016-02-19 21:05:36 +00:00
|
|
|
from = Translation.translate(locale, value_str[0])
|
|
|
|
to = Translation.translate(locale, value_str[1])
|
|
|
|
[from, to]
|
2016-01-15 17:22:57 +00:00
|
|
|
else
|
|
|
|
[value_str[0].to_s, value_str[1].to_s]
|
|
|
|
end
|
2017-10-01 12:25:52 +00:00
|
|
|
end
|
2015-01-04 12:52:14 +00:00
|
|
|
changes
|
|
|
|
end
|
|
|
|
|
2017-09-05 09:49:32 +00:00
|
|
|
private
|
|
|
|
|
|
|
|
def recursive_ooo_replacements(user:, replacements:, reasons:, level: 0)
|
|
|
|
if level == 10
|
|
|
|
Rails.logger.warn("Found more than 10 replacement levels for agent #{user}.")
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
|
|
|
replacement = user.out_of_office_agent
|
|
|
|
return if !replacement
|
|
|
|
# return for already found, added and checked users
|
|
|
|
# to prevent re-doing complete lookup paths
|
|
|
|
return if !replacements.add?(replacement)
|
2018-10-09 06:17:41 +00:00
|
|
|
|
2017-09-05 09:49:32 +00:00
|
|
|
reasons[replacement.id] = 'are the out-of-office replacement of the owner'
|
|
|
|
|
|
|
|
recursive_ooo_replacements(
|
|
|
|
user: replacement,
|
|
|
|
replacements: replacements,
|
|
|
|
reasons: reasons,
|
|
|
|
level: level + 1
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
2019-10-04 09:42:44 +00:00
|
|
|
def possible_recipients_of_group(group_id)
|
|
|
|
cache = Cache.get("Transaction::Notification.group_access.full::#{group_id}")
|
|
|
|
return cache if cache
|
|
|
|
|
|
|
|
possible_recipients = User.group_access(group_id, 'full').sort_by(&:login)
|
|
|
|
Cache.write("Transaction::Notification.group_access.full::#{group_id}", possible_recipients, expires_in: 20.seconds)
|
|
|
|
possible_recipients
|
|
|
|
end
|
2015-04-27 14:15:29 +00:00
|
|
|
end
|