notification_factory.rb 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. module NotificationFactory
  2. =begin
  3. get notification settings for user and notification type
  4. result = NotificationFactory.notification_settings(user, ticket, type)
  5. type: create | update | reminder_reached | pending
  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. return if !user.preferences
  17. return if !user.preferences['notification_config']
  18. matrix = user.preferences['notification_config']['matrix']
  19. return if !matrix
  20. # check if group is in selecd groups
  21. if ticket.owner_id != user.id
  22. selected_group_ids = user.preferences['notification_config']['group_ids']
  23. if selected_group_ids
  24. if selected_group_ids.class == Array
  25. hit = nil
  26. if selected_group_ids.empty?
  27. hit = true
  28. elsif selected_group_ids[0] == '-' && selected_group_ids.count == 1
  29. hit = true
  30. else
  31. hit = false
  32. selected_group_ids.each {|selected_group_id|
  33. if selected_group_id.to_s == ticket.group_id.to_s
  34. hit = true
  35. break
  36. end
  37. }
  38. end
  39. return if !hit
  40. end
  41. end
  42. end
  43. return if !matrix[type]
  44. data = matrix[type]
  45. return if !data
  46. return if !data['criteria']
  47. channels = data['channel']
  48. return if !channels
  49. if data['criteria']['owned_by_me'] && ticket.owner_id == user.id
  50. return {
  51. user: user,
  52. channels: channels
  53. }
  54. end
  55. if data['criteria']['owned_by_nobody'] && ticket.owner_id == 1
  56. return {
  57. user: user,
  58. channels: channels
  59. }
  60. end
  61. return if !data['criteria']['no']
  62. {
  63. user: user,
  64. channels: channels
  65. }
  66. end
  67. =begin
  68. # deprecated, will be removed with 2.0
  69. result_string = NotificationFactory.build(
  70. string: 'Hi #{recipient.firstname},',
  71. objects: {
  72. ticket : ticket,
  73. recipient: User.find(2),
  74. },
  75. locale: 'en',
  76. )
  77. =end
  78. def self.build(data)
  79. data[:string].gsub!( / \#\{ \s* ( .+? ) \s* \} /xm ) { |placeholder|
  80. # store possible callback to work with
  81. # and check if it's valid for execution
  82. original_string = $&
  83. callback = $1
  84. object_name = nil
  85. object_method = nil
  86. if callback =~ /\A ( [\w]+ )\.( [\w\.]+ ) \z/x
  87. object_name = $1
  88. object_method = $2
  89. end
  90. # do validaton, ignore some methodes
  91. if callback =~ /(`|\.(|\s*)(save|destroy|delete|remove|drop|update\(|update_att|create\(|new|all|where|find))/i
  92. placeholder = "#{original_string} (not allowed)"
  93. # get value based on object_name and object_method
  94. elsif object_name && object_method
  95. # use config params
  96. if object_name == 'config'
  97. placeholder = Setting.get(object_method)
  98. # if object_name dosn't exist
  99. elsif !data[:objects][object_name.to_sym]
  100. placeholder = "\#{#{object_name} / no such object}"
  101. else
  102. value = nil
  103. object_refs = data[:objects][object_name.to_sym]
  104. object_methods = object_method.split('.')
  105. object_methods_s = ''
  106. object_methods.each {|method|
  107. if object_methods_s != ''
  108. object_methods_s += '.'
  109. end
  110. object_methods_s += method
  111. # if method exists
  112. if !object_refs.respond_to?( method.to_sym )
  113. value = "\#{#{object_name}.#{object_methods_s} / no such method}"
  114. break
  115. end
  116. object_refs = object_refs.send( method.to_sym )
  117. # add body quote
  118. next if object_name != 'article'
  119. next if method != 'body'
  120. next if data[:objects][:article].content_type != 'text/html'
  121. object_refs = object_refs.html2text.chomp
  122. }
  123. placeholder = if !value
  124. object_refs
  125. else
  126. value
  127. end
  128. end
  129. end
  130. placeholder
  131. }
  132. # translate
  133. data[:string].gsub!( /i18n\((|.+?)\)/ ) {
  134. string = $1
  135. locale = data[:locale] || 'en'
  136. Translation.translate( locale, string )
  137. }
  138. data[:string]
  139. end
  140. =begin
  141. success = NotificationFactory.send(
  142. recipient: User.find(123),
  143. subject: 'sime subject',
  144. body: 'some body',
  145. content_type: '', # optional, e. g. 'text/html'
  146. references: ['message-id123', 'message-id456'],
  147. )
  148. =end
  149. def self.send(data)
  150. sender = Setting.get('notification_sender')
  151. Rails.logger.info "Send notification to: #{data[:recipient][:email]} (from #{sender})"
  152. content_type = 'text/plain'
  153. if data[:content_type]
  154. content_type = data[:content_type]
  155. end
  156. # get active Email::Outbound Channel and send
  157. channel = Channel.find_by(area: 'Email::Notification', active: true)
  158. channel.deliver(
  159. {
  160. # in_reply_to: in_reply_to,
  161. from: sender,
  162. to: data[:recipient][:email],
  163. subject: data[:subject],
  164. references: data[:references],
  165. body: data[:body],
  166. content_type: content_type,
  167. },
  168. true
  169. )
  170. end
  171. =begin
  172. NotificationFactory.notification(
  173. template: 'password_reset',
  174. user: User.find(2),
  175. objects: {
  176. recipient: User.find(2),
  177. },
  178. main_object: ticket.find(123), # optional
  179. references: ['message-id123', 'message-id456'],
  180. )
  181. =end
  182. def self.notification(data)
  183. # get subject
  184. result = NotificationFactory.template(
  185. template: data[:template],
  186. locale: data[:user].preferences[:locale],
  187. objects: data[:objects],
  188. )
  189. # rebuild subject
  190. if data[:main_object] && data[:main_object].respond_to?(:subject_build)
  191. result[:subject] = data[:main_object].subject_build(result[:subject])
  192. end
  193. NotificationFactory.send(
  194. recipient: data[:user],
  195. subject: result[:subject],
  196. body: result[:body],
  197. content_type: 'text/html',
  198. references: data[:references],
  199. )
  200. end
  201. =begin
  202. get count of already sent notifications
  203. count = NotificationFactory.already_sent?(ticket, recipient_user, type)
  204. retunes
  205. 8
  206. =end
  207. def self.already_sent?(ticket, recipient, type)
  208. result = ticket.history_get()
  209. count = 0
  210. result.each {|item|
  211. next if item['type'] != 'notification'
  212. next if item['object'] != 'Ticket'
  213. next if item['value_to'] !~ /#{recipient.email}/i
  214. next if item['value_to'] !~ /#{type}/i
  215. count += 1
  216. }
  217. count
  218. end
  219. =begin
  220. result = NotificationFactory.template(
  221. template: 'password_reset',
  222. locale: 'en-us',
  223. objects: {
  224. recipient: User.find(2),
  225. },
  226. )
  227. result = NotificationFactory.template(
  228. templateInline: "Invitation to <%= c 'product_name' %> at <%= c 'fqdn' %>",
  229. locale: 'en-us',
  230. objects: {
  231. recipient: User.find(2),
  232. },
  233. )
  234. only raw subject/body
  235. result = NotificationFactory.template(
  236. template: 'password_reset',
  237. locale: 'en-us',
  238. objects: {
  239. recipient: User.find(2),
  240. },
  241. raw: true,
  242. )
  243. returns
  244. {
  245. subject: 'some sobject',
  246. body: 'some body',
  247. }
  248. =end
  249. def self.template(data)
  250. if data[:templateInline]
  251. return NotificationFactory::Template.new(data[:objects], data[:locale], data[:templateInline], false).render
  252. end
  253. template_subject = nil
  254. template_body = ''
  255. locale = data[:locale] || 'en'
  256. template = data[:template]
  257. root = Rails.root
  258. location = "#{root}/app/views/mailer/#{template}/#{locale}.html.erb"
  259. # as fallback, use 2 char locale
  260. if !File.exist?(location)
  261. locale = locale[0, 2]
  262. location = "#{root}/app/views/mailer/#{template}/#{locale}.html.erb"
  263. end
  264. # as fallback, use en
  265. if !File.exist?(location)
  266. location = "#{root}/app/views/mailer/#{template}/en.html.erb"
  267. end
  268. File.open(location, 'r:UTF-8').each do |line|
  269. if !template_subject
  270. template_subject = line
  271. next
  272. end
  273. template_body += line
  274. end
  275. message_subject = NotificationFactory::Template.new(data[:objects], data[:locale], template_subject, false).render
  276. message_body = NotificationFactory::Template.new(data[:objects], data[:locale], template_body).render
  277. if !data[:raw]
  278. application_template = nil
  279. File.open("#{root}/app/views/mailer/application.html.erb", 'r:UTF-8') do |file|
  280. application_template = file.read
  281. end
  282. data[:objects][:message] = message_body
  283. message_body = NotificationFactory::Template.new(data[:objects], data[:locale], application_template).render
  284. end
  285. {
  286. subject: message_subject,
  287. body: message_body,
  288. }
  289. end
  290. class Template
  291. def initialize(objects, locale, template, escape = true)
  292. @objects = objects
  293. @locale = locale || 'en-us'
  294. @template = template
  295. @escape = escape
  296. end
  297. def render
  298. ERB.new(@template).result(binding)
  299. end
  300. def d(key, escape = nil)
  301. # do validaton, ignore some methodes
  302. if key =~ /(`|\.(|\s*)(save|destroy|delete|remove|drop|update\(|update_att|create\(|new|all|where|find))/i
  303. return "#{key} (not allowed)"
  304. end
  305. value = nil
  306. object_methods = key.split('.')
  307. object_name = object_methods.shift.to_sym
  308. object_refs = @objects[object_name]
  309. object_methods_s = ''
  310. object_methods.each {|method|
  311. if object_methods_s != ''
  312. object_methods_s += '.'
  313. end
  314. object_methods_s += method
  315. # if method exists
  316. if !object_refs.respond_to?( method.to_sym )
  317. value = "\#{#{object_name}.#{object_methods_s} / no such method}"
  318. break
  319. end
  320. object_refs = object_refs.send( method.to_sym )
  321. }
  322. placeholder = if !value
  323. object_refs
  324. else
  325. value
  326. end
  327. return placeholder if escape == false || (escape.nil? && !@escape)
  328. h placeholder
  329. end
  330. def c(key, escape = nil)
  331. config = Setting.get(key)
  332. return config if escape == false || (escape.nil? && !@escape)
  333. h config
  334. end
  335. def t(key, escape = nil)
  336. translation = Translation.translate(@locale, key)
  337. return translation if escape == false || (escape.nil? && !@escape)
  338. h translation
  339. end
  340. def a(article)
  341. content_type = d "#{article}.content_type", false
  342. if content_type =~ /html/
  343. return d "#{article}.body", false
  344. end
  345. d("#{article}.body", false).text2html
  346. end
  347. def h(key)
  348. return key if !key
  349. CGI.escapeHTML(key.to_s)
  350. end
  351. end
  352. end