2022-01-01 13:38:12 +00:00
# Copyright (C) 2012-2022 Zammad Foundation, https://zammad-foundation.org/
2021-06-01 12:20:20 +00:00
2016-04-13 23:40:37 +00:00
class NotificationFactory :: Mailer
= begin
get notification settings for user and notification type
result = NotificationFactory :: Mailer . notification_settings ( user , ticket , type )
2016-11-13 18:33:12 +00:00
type : create | update | reminder_reached | escalation ( escalation_warning )
2016-04-13 23:40:37 +00:00
returns
{
user : user ,
channels : {
online : true ,
email : true ,
} ,
}
= end
def self . notification_settings ( user , ticket , type )
2016-11-13 18:33:12 +00:00
# map types if needed
map = {
'escalation_warning' = > 'escalation'
}
2021-08-19 17:31:15 +00:00
type = type . split ( '.' ) . first # pick parent type of a subtype. Eg. update vs update.merged_into
2016-11-13 18:33:12 +00:00
if map [ type ]
type = map [ type ]
end
2020-01-17 16:13:30 +00:00
# this cache will optimize the preference catch performance
# because of the yaml deserialization its pretty slow
# on many tickets you we cache it.
2021-05-31 13:05:54 +00:00
user_preferences = Cache . read ( " NotificationFactory::Mailer.notification_settings:: #{ user . id } " )
2020-01-17 16:13:30 +00:00
if user_preferences . blank?
user_preferences = user . preferences
Cache . write ( " NotificationFactory::Mailer.notification_settings:: #{ user . id } " , user_preferences , expires_in : 20 . seconds )
end
return if ! user_preferences
return if ! user_preferences [ 'notification_config' ]
2018-10-09 06:17:41 +00:00
2020-01-17 16:13:30 +00:00
matrix = user_preferences [ 'notification_config' ] [ 'matrix' ]
2016-04-13 23:40:37 +00:00
return if ! matrix
2017-09-05 09:49:32 +00:00
owned_by_nobody = false
owned_by_me = false
2021-03-22 13:25:43 +00:00
subscribed = false
2020-07-13 12:46:08 +00:00
case ticket . owner_id
when 1
2017-09-05 09:49:32 +00:00
owned_by_nobody = true
2020-07-13 12:46:08 +00:00
when user . id
2017-09-05 09:49:32 +00:00
owned_by_me = true
else
# check the replacement chain of max 10
# if the current user is in it
check_for = ticket . owner
10 . times do
replacement = check_for . out_of_office_agent
break if ! replacement
check_for = replacement
next if replacement . id != user . id
owned_by_me = true
break
end
end
2021-03-22 13:25:43 +00:00
# always trigger notifications for user if he is subscribed
2021-03-16 08:59:32 +00:00
if owned_by_me == false && ticket . mentions . exists? ( user : user )
2021-03-22 13:25:43 +00:00
subscribed = true
2021-03-16 08:59:32 +00:00
end
2017-09-05 09:49:32 +00:00
# check if group is in selected groups
2021-03-27 04:43:33 +00:00
if ! owned_by_me && ! subscribed
2020-01-17 16:13:30 +00:00
selected_group_ids = user_preferences [ 'notification_config' ] [ 'group_ids' ]
2017-09-05 09:49:32 +00:00
if selected_group_ids . is_a? ( Array )
hit = nil
2020-11-12 11:42:44 +00:00
if selected_group_ids . blank? || ( selected_group_ids [ 0 ] == '-' && selected_group_ids . count == 1 )
2017-09-05 09:49:32 +00:00
hit = true
else
hit = false
2017-10-01 12:25:52 +00:00
selected_group_ids . each do | selected_group_id |
2017-09-05 09:49:32 +00:00
if selected_group_id . to_s == ticket . group_id . to_s
hit = true
break
end
2017-10-01 12:25:52 +00:00
end
2016-04-13 23:40:37 +00:00
end
2017-09-05 09:49:32 +00:00
return if ! hit # no group access
2016-04-13 23:40:37 +00:00
end
end
return if ! matrix [ type ]
2018-10-09 06:17:41 +00:00
2016-04-13 23:40:37 +00:00
data = matrix [ type ]
return if ! data
return if ! data [ 'criteria' ]
2018-10-09 06:17:41 +00:00
2016-04-13 23:40:37 +00:00
channels = data [ 'channel' ]
return if ! channels
2018-10-09 06:17:41 +00:00
2017-09-05 09:49:32 +00:00
if data [ 'criteria' ] [ 'owned_by_me' ] && owned_by_me
2016-04-13 23:40:37 +00:00
return {
2018-12-19 17:31:51 +00:00
user : user ,
2016-04-13 23:40:37 +00:00
channels : channels
}
end
2017-09-05 09:49:32 +00:00
if data [ 'criteria' ] [ 'owned_by_nobody' ] && owned_by_nobody
2016-04-13 23:40:37 +00:00
return {
2018-12-19 17:31:51 +00:00
user : user ,
2016-04-13 23:40:37 +00:00
channels : channels
}
end
2021-03-22 13:25:43 +00:00
if data [ 'criteria' ] [ 'subscribed' ] && subscribed
2021-03-16 08:59:32 +00:00
return {
user : user ,
channels : channels
}
end
2016-04-13 23:40:37 +00:00
return if ! data [ 'criteria' ] [ 'no' ]
2018-10-09 06:17:41 +00:00
2016-04-13 23:40:37 +00:00
{
2018-12-19 17:31:51 +00:00
user : user ,
2016-04-13 23:40:37 +00:00
channels : channels
}
end
= begin
success = NotificationFactory :: Mailer . send (
recipient : User . find ( 123 ) ,
2018-08-07 12:49:32 +00:00
subject : 'some subject' ,
2016-04-13 23:40:37 +00:00
body : 'some body' ,
content_type : '' , # optional, e. g. 'text/html'
2018-08-07 12:49:32 +00:00
message_id : '<some_message_id@fqdn>' , # optional
2017-02-03 15:44:55 +00:00
references : [ 'message-id123' , 'message-id456' ] , # optional
2016-07-11 23:32:20 +00:00
attachments : [ attachments ... ] , # optional
2016-04-13 23:40:37 +00:00
)
= end
def self . send ( data )
2020-02-19 14:57:32 +00:00
raise Exceptions :: UnprocessableEntity , " Unable to send mail to user with id #{ data [ :recipient ] [ :id ] } because there is no email available. " if data [ :recipient ] [ :email ] . blank?
2016-04-13 23:40:37 +00:00
sender = Setting . get ( 'notification_sender' )
2021-05-10 14:18:43 +00:00
Rails . logger . debug { " Send notification to: #{ data [ :recipient ] [ :email ] } (from: #{ sender } /subject: #{ data [ :subject ] } ) " }
2016-04-13 23:40:37 +00:00
content_type = 'text/plain'
if data [ :content_type ]
content_type = data [ :content_type ]
end
# get active Email::Outbound Channel and send
channel = Channel . find_by ( area : 'Email::Notification' , active : true )
2019-08-21 12:55:26 +00:00
if channel . blank?
Rails . logger . info " Can't find an active 'Email::Notification' channel. Canceling notification sending. "
2020-02-19 14:57:32 +00:00
return false
2019-08-21 12:55:26 +00:00
end
2016-04-13 23:40:37 +00:00
channel . deliver (
{
# in_reply_to: in_reply_to,
2018-12-19 17:31:51 +00:00
from : sender ,
to : data [ :recipient ] [ :email ] ,
subject : data [ :subject ] ,
message_id : data [ :message_id ] ,
references : data [ :references ] ,
body : data [ :body ] ,
2016-04-13 23:40:37 +00:00
content_type : content_type ,
2018-12-19 17:31:51 +00:00
attachments : data [ :attachments ] ,
2016-04-13 23:40:37 +00:00
} ,
true
)
end
= begin
NotificationFactory :: Mailer . notification (
template : 'password_reset' ,
user : User . find ( 2 ) ,
objects : {
recipient : User . find ( 2 ) ,
} ,
main_object : ticket . find ( 123 ) , # optional
2017-02-03 15:44:55 +00:00
message_id : '<some_message_id@fqdn>' , # optional
references : [ 'message-id123' , 'message-id456' ] , # optional
2016-04-13 23:40:37 +00:00
standalone : true , # default: false - will send header & footer
2016-07-11 23:32:20 +00:00
attachments : [ attachments ... ] , # optional
2016-04-13 23:40:37 +00:00
)
= end
def self . notification ( data )
# get subject
result = NotificationFactory :: Mailer . template (
2018-12-19 17:31:51 +00:00
template : data [ :template ] ,
locale : data [ :user ] [ :preferences ] [ :locale ] ,
objects : data [ :objects ] ,
2016-04-13 23:40:37 +00:00
standalone : data [ :standalone ] ,
)
# rebuild subject
2018-04-12 14:57:37 +00:00
if data [ :main_object ] . respond_to? ( :subject_build )
2016-04-13 23:40:37 +00:00
result [ :subject ] = data [ :main_object ] . subject_build ( result [ :subject ] )
end
2017-03-17 05:27:50 +00:00
# prepare scaling of images
if result [ :body ]
result [ :body ] = HtmlSanitizer . dynamic_image_size ( result [ :body ] )
end
2016-04-13 23:40:37 +00:00
NotificationFactory :: Mailer . send (
2018-12-19 17:31:51 +00:00
recipient : data [ :user ] ,
subject : result [ :subject ] ,
body : result [ :body ] ,
2016-04-13 23:40:37 +00:00
content_type : 'text/html' ,
2018-12-19 17:31:51 +00:00
message_id : data [ :message_id ] ,
references : data [ :references ] ,
attachments : data [ :attachments ] ,
2016-04-13 23:40:37 +00:00
)
end
= begin
get count of already sent notifications
count = NotificationFactory :: Mailer . already_sent? ( ticket , recipient_user , type )
retunes
8
= end
def self . already_sent? ( ticket , recipient , type )
2018-12-31 19:15:17 +00:00
result = ticket . history_get
2016-04-13 23:40:37 +00:00
count = 0
2017-10-01 12:25:52 +00:00
result . each do | item |
2016-04-13 23:40:37 +00:00
next if item [ 'type' ] != 'notification'
next if item [ 'object' ] != 'Ticket'
2021-05-12 11:37:44 +00:00
next if ! item [ 'value_to' ] . match? ( %r{ #{ recipient . email } }i )
next if ! item [ 'value_to' ] . match? ( %r{ #{ type } }i )
2018-10-09 06:17:41 +00:00
2016-04-13 23:40:37 +00:00
count += 1
2017-10-01 12:25:52 +00:00
end
2016-04-13 23:40:37 +00:00
count
end
= begin
result = NotificationFactory :: Mailer . template (
template : 'password_reset' ,
locale : 'en-us' ,
2019-02-10 11:01:38 +00:00
timezone : 'America/Santiago' ,
2016-04-13 23:40:37 +00:00
objects : {
recipient : User . find ( 2 ) ,
} ,
)
result = NotificationFactory :: Mailer . template (
2016-11-13 18:33:12 +00:00
templateInline : " Invitation to \# {config.product_name} at \# {config.fqdn} " ,
2016-04-13 23:40:37 +00:00
locale : 'en-us' ,
2019-02-10 11:01:38 +00:00
timezone : 'America/Santiago' ,
2016-04-13 23:40:37 +00:00
objects : {
recipient : User . find ( 2 ) ,
} ,
2016-11-13 18:33:12 +00:00
quote : true , # html quoting
2016-04-13 23:40:37 +00:00
)
only raw subject / body
result = NotificationFactory :: Mailer . template (
template : 'password_reset' ,
locale : 'en-us' ,
2019-02-10 11:01:38 +00:00
timezone : 'America/Santiago' ,
2016-04-13 23:40:37 +00:00
objects : {
recipient : User . find ( 2 ) ,
} ,
raw : true , # will not add application template
standalone : true , # default: false - will send header & footer
)
returns
{
subject : 'some subject' ,
body : 'some body' ,
}
= end
def self . template ( data )
if data [ :templateInline ]
2019-02-10 11:01:38 +00:00
return NotificationFactory :: Renderer . new (
objects : data [ :objects ] ,
locale : data [ :locale ] ,
timezone : data [ :timezone ] ,
template : data [ :templateInline ] ,
escape : data [ :quote ]
) . render
2016-04-13 23:40:37 +00:00
end
template = NotificationFactory . template_read (
2020-01-27 09:28:17 +00:00
locale : data [ :locale ] || Locale . default ,
2016-04-13 23:40:37 +00:00
template : data [ :template ] ,
2019-08-06 15:26:29 +00:00
format : data [ :format ] || 'html' ,
2018-12-19 17:31:51 +00:00
type : 'mailer' ,
2016-04-13 23:40:37 +00:00
)
2019-02-10 11:01:38 +00:00
message_subject = NotificationFactory :: Renderer . new (
objects : data [ :objects ] ,
locale : data [ :locale ] ,
timezone : data [ :timezone ] ,
template : template [ :subject ] ,
2021-09-23 10:04:18 +00:00
escape : false ,
trusted : true ,
2019-02-10 11:01:38 +00:00
) . render
2019-08-06 15:26:29 +00:00
2019-09-16 12:20:59 +00:00
# strip off the extra newline at the end of the subject to avoid =0A suffixes (see #2726)
message_subject . chomp!
2019-08-06 15:26:29 +00:00
2019-02-10 11:01:38 +00:00
message_body = NotificationFactory :: Renderer . new (
objects : data [ :objects ] ,
locale : data [ :locale ] ,
timezone : data [ :timezone ] ,
2021-09-23 10:04:18 +00:00
template : template [ :body ] ,
trusted : true ,
2019-02-10 11:01:38 +00:00
) . render
2016-04-13 23:40:37 +00:00
if ! data [ :raw ]
application_template = NotificationFactory . application_template_read (
format : 'html' ,
2018-12-19 17:31:51 +00:00
type : 'mailer' ,
2016-04-13 23:40:37 +00:00
)
data [ :objects ] [ :message ] = message_body
data [ :objects ] [ :standalone ] = data [ :standalone ]
2019-02-10 11:01:38 +00:00
message_body = NotificationFactory :: Renderer . new (
objects : data [ :objects ] ,
locale : data [ :locale ] ,
timezone : data [ :timezone ] ,
2021-09-23 10:04:18 +00:00
template : application_template ,
trusted : true ,
2019-02-10 11:01:38 +00:00
) . render
2016-04-13 23:40:37 +00:00
end
{
subject : message_subject ,
2018-12-19 17:31:51 +00:00
body : message_body ,
2016-04-13 23:40:37 +00:00
}
end
end