mailer.rb 8.6 KB

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