mailer.rb 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. class NotificationFactory::Mailer
  2. =begin
  3. get notification settings for user and notification type
  4. result = NotificationFactory::Mailer.notification_settings(user, ticket, type)
  5. type: create | update | reminder_reached | escalation (escalation_warning)
  6. returns
  7. {
  8. user: user,
  9. channels: {
  10. online: true,
  11. email: true,
  12. },
  13. }
  14. =end
  15. def self.notification_settings(user, ticket, type)
  16. # map types if needed
  17. map = {
  18. 'escalation_warning' => 'escalation'
  19. }
  20. if map[type]
  21. type = map[type]
  22. end
  23. # this cache will optimize the preference catch performance
  24. # because of the yaml deserialization its pretty slow
  25. # on many tickets you we cache it.
  26. user_preferences = Cache.get("NotificationFactory::Mailer.notification_settings::#{user.id}")
  27. if user_preferences.blank?
  28. user_preferences = user.preferences
  29. Cache.write("NotificationFactory::Mailer.notification_settings::#{user.id}", user_preferences, expires_in: 20.seconds)
  30. end
  31. return if !user_preferences
  32. return if !user_preferences['notification_config']
  33. matrix = user_preferences['notification_config']['matrix']
  34. return if !matrix
  35. owned_by_nobody = false
  36. owned_by_me = false
  37. subscribed = false
  38. case ticket.owner_id
  39. when 1
  40. owned_by_nobody = true
  41. when user.id
  42. owned_by_me = true
  43. else
  44. # check the replacement chain of max 10
  45. # if the current user is in it
  46. check_for = ticket.owner
  47. 10.times do
  48. replacement = check_for.out_of_office_agent
  49. break if !replacement
  50. check_for = replacement
  51. next if replacement.id != user.id
  52. owned_by_me = true
  53. break
  54. end
  55. end
  56. # always trigger notifications for user if he is subscribed
  57. if owned_by_me == false && ticket.mentions.exists?(user: user)
  58. subscribed = true
  59. end
  60. # check if group is in selected groups
  61. if !owned_by_me && !subscribed
  62. selected_group_ids = user_preferences['notification_config']['group_ids']
  63. if selected_group_ids.is_a?(Array)
  64. hit = nil
  65. if selected_group_ids.blank? || (selected_group_ids[0] == '-' && selected_group_ids.count == 1)
  66. hit = true
  67. else
  68. hit = false
  69. selected_group_ids.each do |selected_group_id|
  70. if selected_group_id.to_s == ticket.group_id.to_s
  71. hit = true
  72. break
  73. end
  74. end
  75. end
  76. return if !hit # no group access
  77. end
  78. end
  79. return if !matrix[type]
  80. data = matrix[type]
  81. return if !data
  82. return if !data['criteria']
  83. channels = data['channel']
  84. return if !channels
  85. if data['criteria']['owned_by_me'] && owned_by_me
  86. return {
  87. user: user,
  88. channels: channels
  89. }
  90. end
  91. if data['criteria']['owned_by_nobody'] && owned_by_nobody
  92. return {
  93. user: user,
  94. channels: channels
  95. }
  96. end
  97. if data['criteria']['subscribed'] && subscribed
  98. return {
  99. user: user,
  100. channels: channels
  101. }
  102. end
  103. return if !data['criteria']['no']
  104. {
  105. user: user,
  106. channels: channels
  107. }
  108. end
  109. =begin
  110. success = NotificationFactory::Mailer.send(
  111. recipient: User.find(123),
  112. subject: 'some subject',
  113. body: 'some body',
  114. content_type: '', # optional, e. g. 'text/html'
  115. message_id: '<some_message_id@fqdn>', # optional
  116. references: ['message-id123', 'message-id456'], # optional
  117. attachments: [attachments...], # optional
  118. )
  119. =end
  120. def self.send(data)
  121. 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?
  122. sender = Setting.get('notification_sender')
  123. Rails.logger.debug { "Send notification to: #{data[:recipient][:email]} (from:#{sender}/subject:#{data[:subject]})" }
  124. content_type = 'text/plain'
  125. if data[:content_type]
  126. content_type = data[:content_type]
  127. end
  128. # get active Email::Outbound Channel and send
  129. channel = Channel.find_by(area: 'Email::Notification', active: true)
  130. if channel.blank?
  131. Rails.logger.info "Can't find an active 'Email::Notification' channel. Canceling notification sending."
  132. return false
  133. end
  134. channel.deliver(
  135. {
  136. # in_reply_to: in_reply_to,
  137. from: sender,
  138. to: data[:recipient][:email],
  139. subject: data[:subject],
  140. message_id: data[:message_id],
  141. references: data[:references],
  142. body: data[:body],
  143. content_type: content_type,
  144. attachments: data[:attachments],
  145. },
  146. true
  147. )
  148. end
  149. =begin
  150. NotificationFactory::Mailer.notification(
  151. template: 'password_reset',
  152. user: User.find(2),
  153. objects: {
  154. recipient: User.find(2),
  155. },
  156. main_object: ticket.find(123), # optional
  157. message_id: '<some_message_id@fqdn>', # optional
  158. references: ['message-id123', 'message-id456'], # optional
  159. standalone: true, # default: false - will send header & footer
  160. attachments: [attachments...], # optional
  161. )
  162. =end
  163. def self.notification(data)
  164. # get subject
  165. result = NotificationFactory::Mailer.template(
  166. template: data[:template],
  167. locale: data[:user][:preferences][:locale],
  168. objects: data[:objects],
  169. standalone: data[:standalone],
  170. )
  171. # rebuild subject
  172. if data[:main_object].respond_to?(:subject_build)
  173. result[:subject] = data[:main_object].subject_build(result[:subject])
  174. end
  175. # prepare scaling of images
  176. if result[:body]
  177. result[:body] = HtmlSanitizer.dynamic_image_size(result[:body])
  178. end
  179. NotificationFactory::Mailer.send(
  180. recipient: data[:user],
  181. subject: result[:subject],
  182. body: result[:body],
  183. content_type: 'text/html',
  184. message_id: data[:message_id],
  185. references: data[:references],
  186. attachments: data[:attachments],
  187. )
  188. end
  189. =begin
  190. get count of already sent notifications
  191. count = NotificationFactory::Mailer.already_sent?(ticket, recipient_user, type)
  192. retunes
  193. 8
  194. =end
  195. def self.already_sent?(ticket, recipient, type)
  196. result = ticket.history_get
  197. count = 0
  198. result.each do |item|
  199. next if item['type'] != 'notification'
  200. next if item['object'] != 'Ticket'
  201. next if !item['value_to'].match?(%r{#{recipient.email}}i)
  202. next if !item['value_to'].match?(%r{#{type}}i)
  203. count += 1
  204. end
  205. count
  206. end
  207. =begin
  208. result = NotificationFactory::Mailer.template(
  209. template: 'password_reset',
  210. locale: 'en-us',
  211. timezone: 'America/Santiago',
  212. objects: {
  213. recipient: User.find(2),
  214. },
  215. )
  216. result = NotificationFactory::Mailer.template(
  217. templateInline: "Invitation to \#{config.product_name} at \#{config.fqdn}",
  218. locale: 'en-us',
  219. timezone: 'America/Santiago',
  220. objects: {
  221. recipient: User.find(2),
  222. },
  223. quote: true, # html quoting
  224. )
  225. only raw subject/body
  226. result = NotificationFactory::Mailer.template(
  227. template: 'password_reset',
  228. locale: 'en-us',
  229. timezone: 'America/Santiago',
  230. objects: {
  231. recipient: User.find(2),
  232. },
  233. raw: true, # will not add application template
  234. standalone: true, # default: false - will send header & footer
  235. )
  236. returns
  237. {
  238. subject: 'some subject',
  239. body: 'some body',
  240. }
  241. =end
  242. def self.template(data)
  243. if data[:templateInline]
  244. return NotificationFactory::Renderer.new(
  245. objects: data[:objects],
  246. locale: data[:locale],
  247. timezone: data[:timezone],
  248. template: data[:templateInline],
  249. escape: data[:quote]
  250. ).render
  251. end
  252. template = NotificationFactory.template_read(
  253. locale: data[:locale] || Locale.default,
  254. template: data[:template],
  255. format: data[:format] || 'html',
  256. type: 'mailer',
  257. )
  258. message_subject = NotificationFactory::Renderer.new(
  259. objects: data[:objects],
  260. locale: data[:locale],
  261. timezone: data[:timezone],
  262. template: template[:subject],
  263. escape: false
  264. ).render
  265. # strip off the extra newline at the end of the subject to avoid =0A suffixes (see #2726)
  266. message_subject.chomp!
  267. message_body = NotificationFactory::Renderer.new(
  268. objects: data[:objects],
  269. locale: data[:locale],
  270. timezone: data[:timezone],
  271. template: template[:body]
  272. ).render
  273. if !data[:raw]
  274. application_template = NotificationFactory.application_template_read(
  275. format: 'html',
  276. type: 'mailer',
  277. )
  278. data[:objects][:message] = message_body
  279. data[:objects][:standalone] = data[:standalone]
  280. message_body = NotificationFactory::Renderer.new(
  281. objects: data[:objects],
  282. locale: data[:locale],
  283. timezone: data[:timezone],
  284. template: application_template
  285. ).render
  286. end
  287. {
  288. subject: message_subject,
  289. body: message_body,
  290. }
  291. end
  292. end