notification_factory_renderer_test.rb 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. # Copyright (C) 2012-2023 Zammad Foundation, https://zammad-foundation.org/
  2. require 'test_helper'
  3. class NotificationFactoryRendererTest < ActiveSupport::TestCase
  4. # RSpec incoming!
  5. def described_class
  6. NotificationFactory::Renderer
  7. end
  8. group = Group.new(name: 'Users')
  9. owner = User.new(firstname: 'Owner<b>xxx</b>', lastname: 'Agent1<b>yyy</b>')
  10. current_user = User.new(firstname: 'CurrentUser<b>xxx</b>', lastname: 'Agent2<b>yyy</b>')
  11. state = Ticket::State.new(name: 'new')
  12. ticket = Ticket.new(
  13. id: 1,
  14. title: '<b>Welcome to Zammad!</b>',
  15. group: group,
  16. owner: owner,
  17. state: state,
  18. created_by: current_user,
  19. updated_by: current_user,
  20. created_at: Time.zone.parse('2016-11-12 12:00:00 UTC'),
  21. updated_at: Time.zone.parse('2016-11-12 14:00:00 UTC'),
  22. )
  23. article_html1 = Ticket::Article.new(
  24. body: 'test <b>hello</b><br>some new line',
  25. content_type: 'text/html',
  26. )
  27. article_plain1 = Ticket::Article.new(
  28. body: "test <b>hello</b>\nsome new line",
  29. content_type: 'text/plain',
  30. )
  31. article_plain2 = Ticket::Article.new(
  32. body: "test <b>hello</b>\nsome new line",
  33. )
  34. test 'replace object attribute' do
  35. template = "\#{ticket.title}"
  36. result = described_class.new(
  37. objects: {
  38. ticket: ticket,
  39. },
  40. locale: 'en-us',
  41. timezone: 'Europe/Berlin',
  42. template: template,
  43. ).render
  44. assert_equal(CGI.escapeHTML(ticket.title), result)
  45. template = "\#{ticket.created_at}"
  46. result = described_class.new(
  47. objects: {
  48. ticket: ticket,
  49. },
  50. locale: 'en-us',
  51. timezone: 'Europe/Berlin',
  52. template: template,
  53. ).render
  54. assert_equal('11/12/2016 1:00 pm (Europe/Berlin)', result)
  55. template = "\#{ticket.created_by.firstname}"
  56. result = described_class.new(
  57. objects: {
  58. ticket: ticket,
  59. },
  60. locale: 'en-us',
  61. timezone: 'Europe/Berlin',
  62. template: template,
  63. ).render
  64. assert_equal('CurrentUser&lt;b&gt;xxx&lt;/b&gt;', result)
  65. template = "\#{ticket.updated_at}"
  66. result = described_class.new(
  67. objects: {
  68. ticket: ticket,
  69. },
  70. locale: 'en-us',
  71. timezone: 'Europe/Berlin',
  72. template: template,
  73. ).render
  74. assert_equal('11/12/2016 3:00 pm (Europe/Berlin)', result)
  75. template = "\#{ticket.updated_by.firstname}"
  76. result = described_class.new(
  77. objects: {
  78. ticket: ticket,
  79. },
  80. locale: 'en-us',
  81. timezone: 'Europe/Berlin',
  82. template: template,
  83. ).render
  84. assert_equal('CurrentUser&lt;b&gt;xxx&lt;/b&gt;', result)
  85. template = "\#{ticket.owner.firstname}"
  86. result = described_class.new(
  87. objects: {
  88. ticket: ticket,
  89. },
  90. locale: 'en-us',
  91. timezone: 'Europe/Berlin',
  92. template: template,
  93. ).render
  94. assert_equal('Owner&lt;b&gt;xxx&lt;/b&gt;', result)
  95. template = "\#{ticket. title}"
  96. result = described_class.new(
  97. objects: {
  98. ticket: ticket,
  99. },
  100. locale: 'en-us',
  101. timezone: 'Europe/Berlin',
  102. template: template,
  103. ).render
  104. assert_equal(CGI.escapeHTML(ticket.title), result)
  105. template = "\#{ticket.\n title}"
  106. result = described_class.new(
  107. objects: {
  108. ticket: ticket,
  109. },
  110. locale: 'en-us',
  111. timezone: 'Europe/Berlin',
  112. template: template,
  113. ).render
  114. assert_equal(CGI.escapeHTML(ticket.title), result)
  115. template = "\#{ticket.\t title}"
  116. result = described_class.new(
  117. objects: {
  118. ticket: ticket,
  119. },
  120. locale: 'en-us',
  121. timezone: 'Europe/Berlin',
  122. template: template,
  123. ).render
  124. assert_equal(CGI.escapeHTML(ticket.title), result)
  125. template = "\#{ticket.\t\n title\t}"
  126. result = described_class.new(
  127. objects: {
  128. ticket: ticket,
  129. },
  130. locale: 'en-us',
  131. timezone: 'Europe/Berlin',
  132. template: template,
  133. ).render
  134. assert_equal(CGI.escapeHTML(ticket.title), result)
  135. template = "\#{ticket.\" title\t}"
  136. result = described_class.new(
  137. objects: {
  138. ticket: ticket,
  139. },
  140. locale: 'en-us',
  141. timezone: 'Europe/Berlin',
  142. template: template,
  143. ).render
  144. assert_equal(CGI.escapeHTML(ticket.title), result)
  145. template = "\#{<a href=\"/test123\">ticket.\" title</a>}"
  146. result = described_class.new(
  147. objects: {
  148. ticket: ticket,
  149. },
  150. locale: 'en-us',
  151. timezone: 'Europe/Berlin',
  152. template: template,
  153. ).render
  154. assert_equal(CGI.escapeHTML(ticket.title), result)
  155. template = "some test<br>\#{article.body}"
  156. result = described_class.new(
  157. objects: {
  158. article: article_html1,
  159. },
  160. locale: 'en-us',
  161. timezone: 'Europe/Berlin',
  162. template: template,
  163. ).render
  164. assert_equal('some test<br>&gt; test hello<br>&gt; some new line<br>', result)
  165. result = described_class.new(
  166. objects: {
  167. article: article_plain1,
  168. },
  169. locale: 'en-us',
  170. timezone: 'Europe/Berlin',
  171. template: template,
  172. ).render
  173. assert_equal('some test<br>&gt; test &lt;b&gt;hello&lt;/b&gt;<br>&gt; some new line<br>', result)
  174. result = described_class.new(
  175. objects: {
  176. article: article_plain2,
  177. },
  178. locale: 'en-us',
  179. timezone: 'Europe/Berlin',
  180. template: template,
  181. ).render
  182. assert_equal('some test<br>&gt; test &lt;b&gt;hello&lt;/b&gt;<br>&gt; some new line<br>', result)
  183. end
  184. test 'config' do
  185. setting = 'fqdn'
  186. template = "\#{config.#{setting}}"
  187. result = described_class.new(
  188. objects: {
  189. ticket: ticket,
  190. },
  191. locale: 'en-us',
  192. timezone: 'Europe/Berlin',
  193. template: template,
  194. ).render
  195. assert_equal(Setting.get(setting), result)
  196. setting1 = 'fqdn'
  197. setting2 = 'product_name'
  198. template = "some \#{config.#{setting1}} and \#{config.#{setting2}}"
  199. result = described_class.new(
  200. objects: {
  201. ticket: ticket,
  202. },
  203. locale: 'en-us',
  204. timezone: 'Europe/Berlin',
  205. template: template,
  206. ).render
  207. assert_equal("some #{Setting.get(setting1)} and #{Setting.get(setting2)}", result)
  208. setting1 = 'fqdn'
  209. setting2 = 'product_name'
  210. template = "some \#{ config.#{setting1}} and \#{\tconfig.#{setting2}}"
  211. result = described_class.new(
  212. objects: {
  213. ticket: ticket,
  214. },
  215. locale: 'en-us',
  216. timezone: 'Europe/Berlin',
  217. template: template,
  218. ).render
  219. assert_equal("some #{Setting.get(setting1)} and #{Setting.get(setting2)}", result)
  220. end
  221. test 'translation' do
  222. # template = "<%= t 'new' %>"
  223. template = "\#{t('new')}"
  224. result = described_class.new(
  225. objects: {
  226. ticket: ticket,
  227. },
  228. locale: 'de-de',
  229. timezone: 'Europe/Berlin',
  230. template: template,
  231. ).render
  232. assert_equal('neu', result)
  233. template = "some text \#{t('new')} and \#{t('open')}"
  234. result = described_class.new(
  235. objects: {
  236. ticket: ticket,
  237. },
  238. locale: 'de-de',
  239. timezone: 'Europe/Berlin',
  240. template: template,
  241. ).render
  242. assert_equal('some text neu and offen', result)
  243. template = "some text \#{t('new') } and \#{ t('open')}"
  244. result = described_class.new(
  245. objects: {
  246. ticket: ticket,
  247. },
  248. locale: 'de-de',
  249. timezone: 'Europe/Berlin',
  250. template: template,
  251. ).render
  252. assert_equal('some text neu and offen', result)
  253. template = "some text \#{\nt('new') } and \#{ t('open')\t}"
  254. result = described_class.new(
  255. objects: {
  256. ticket: ticket,
  257. },
  258. locale: 'de-de',
  259. timezone: 'Europe/Berlin',
  260. template: template,
  261. ).render
  262. assert_equal('some text neu and offen', result)
  263. end
  264. test 'chained function calls' do
  265. template = "\#{t(ticket.state.name)}"
  266. result = described_class.new(
  267. objects: {
  268. ticket: ticket,
  269. },
  270. locale: 'de-de',
  271. timezone: 'Europe/Berlin',
  272. template: template,
  273. ).render
  274. assert_equal('neu', result)
  275. end
  276. test 'not existing object and attribute' do
  277. template = "\#{}"
  278. result = described_class.new(
  279. objects: {
  280. ticket: ticket,
  281. },
  282. locale: 'en-us',
  283. timezone: 'Europe/Berlin',
  284. template: template,
  285. ).render
  286. assert_equal(CGI.escapeHTML('#{no such object}'), result)
  287. template = "\#{notexsiting.notexsiting}"
  288. result = described_class.new(
  289. objects: {
  290. ticket: ticket,
  291. },
  292. locale: 'en-us',
  293. timezone: 'Europe/Berlin',
  294. template: template,
  295. ).render
  296. assert_equal(CGI.escapeHTML('#{notexsiting / no such object}'), result)
  297. template = "\#{ticket.notexsiting}"
  298. result = described_class.new(
  299. objects: {
  300. ticket: ticket,
  301. },
  302. locale: 'en-us',
  303. timezone: 'Europe/Berlin',
  304. template: template,
  305. ).render
  306. assert_equal(CGI.escapeHTML('#{ticket.notexsiting / no such method}'), result)
  307. template = "\#{ticket.}"
  308. result = described_class.new(
  309. objects: {
  310. ticket: ticket,
  311. },
  312. locale: 'en-us',
  313. timezone: 'Europe/Berlin',
  314. template: template,
  315. ).render
  316. assert_equal(CGI.escapeHTML('#{ticket. / no such method}'), result)
  317. template = "\#{ticket.title.notexsiting}"
  318. result = described_class.new(
  319. objects: {
  320. ticket: ticket,
  321. },
  322. locale: 'en-us',
  323. timezone: 'Europe/Berlin',
  324. template: template,
  325. ).render
  326. assert_equal(CGI.escapeHTML('#{ticket.title.notexsiting / no such method}'), result)
  327. template = "\#{ticket.notexsiting.notexsiting}"
  328. result = described_class.new(
  329. objects: {
  330. ticket: ticket,
  331. },
  332. locale: 'en-us',
  333. timezone: 'Europe/Berlin',
  334. template: template,
  335. ).render
  336. assert_equal(CGI.escapeHTML('#{ticket.notexsiting / no such method}'), result)
  337. template = "\#{notexsiting}"
  338. result = described_class.new(
  339. objects: {
  340. ticket: ticket,
  341. },
  342. locale: 'en-us',
  343. timezone: 'Europe/Berlin',
  344. template: template,
  345. ).render
  346. assert_equal(CGI.escapeHTML('#{notexsiting / no such object}'), result)
  347. template = "\#{notexsiting.}"
  348. result = described_class.new(
  349. objects: {
  350. ticket: ticket,
  351. },
  352. locale: 'en-us',
  353. timezone: 'Europe/Berlin',
  354. template: template,
  355. ).render
  356. assert_equal(CGI.escapeHTML('#{notexsiting / no such object}'), result)
  357. template = "\#{string}"
  358. result = described_class.new(
  359. objects: {
  360. string: 'some string',
  361. },
  362. locale: 'en-us',
  363. timezone: 'Europe/Berlin',
  364. template: template,
  365. ).render
  366. assert_equal(CGI.escapeHTML('some string'), result)
  367. template = "\#{fixum}"
  368. result = described_class.new(
  369. objects: {
  370. fixum: 123,
  371. },
  372. locale: 'en-us',
  373. timezone: 'Europe/Berlin',
  374. template: template,
  375. ).render
  376. assert_equal(CGI.escapeHTML('123'), result)
  377. template = "\#{float}"
  378. result = described_class.new(
  379. objects: {
  380. float: 123.99,
  381. },
  382. locale: 'en-us',
  383. timezone: 'Europe/Berlin',
  384. template: template,
  385. ).render
  386. assert_equal(CGI.escapeHTML('123.99'), result)
  387. end
  388. test 'data key validation' do
  389. template = "\#{ticket.title `echo 1`}"
  390. result = described_class.new(
  391. objects: {
  392. ticket: ticket,
  393. },
  394. locale: 'en-us',
  395. timezone: 'Europe/Berlin',
  396. template: template,
  397. ).render
  398. assert_equal(CGI.escapeHTML('#{ticket.title`echo1` / not allowed}'), result)
  399. template = "\#{ticket.destroy}"
  400. result = described_class.new(
  401. objects: {
  402. ticket: ticket,
  403. },
  404. locale: 'en-us',
  405. timezone: 'Europe/Berlin',
  406. template: template,
  407. ).render
  408. assert_equal(CGI.escapeHTML('#{ticket.destroy / not allowed}'), result)
  409. template = "\#{ticket.save}"
  410. result = described_class.new(
  411. objects: {
  412. ticket: ticket,
  413. },
  414. locale: 'en-us',
  415. timezone: 'Europe/Berlin',
  416. template: template,
  417. ).render
  418. assert_equal(CGI.escapeHTML('#{ticket.save / not allowed}'), result)
  419. template = "\#{ticket.update}"
  420. result = described_class.new(
  421. objects: {
  422. ticket: ticket,
  423. },
  424. locale: 'en-us',
  425. timezone: 'Europe/Berlin',
  426. template: template,
  427. ).render
  428. assert_equal(CGI.escapeHTML('#{ticket.update / not allowed}'), result)
  429. template = "\#{ticket.create}"
  430. result = described_class.new(
  431. objects: {
  432. ticket: ticket,
  433. },
  434. locale: 'en-us',
  435. timezone: 'Europe/Berlin',
  436. template: template,
  437. ).render
  438. assert_equal(CGI.escapeHTML('#{ticket.create / not allowed}'), result)
  439. template = "\#{ticket.delete}"
  440. result = described_class.new(
  441. objects: {
  442. ticket: ticket,
  443. },
  444. locale: 'en-us',
  445. timezone: 'Europe/Berlin',
  446. template: template,
  447. ).render
  448. assert_equal(CGI.escapeHTML('#{ticket.delete / not allowed}'), result)
  449. template = "\#{ticket.remove}"
  450. result = described_class.new(
  451. objects: {
  452. ticket: ticket,
  453. },
  454. locale: 'en-us',
  455. timezone: 'Europe/Berlin',
  456. template: template,
  457. ).render
  458. assert_equal(CGI.escapeHTML('#{ticket.remove / not allowed}'), result)
  459. template = "\#{ticket.drop}"
  460. result = described_class.new(
  461. objects: {
  462. ticket: ticket,
  463. },
  464. locale: 'en-us',
  465. timezone: 'Europe/Berlin',
  466. template: template,
  467. ).render
  468. assert_equal(CGI.escapeHTML('#{ticket.drop / not allowed}'), result)
  469. template = "\#{ticket.create}"
  470. result = described_class.new(
  471. objects: {
  472. ticket: ticket,
  473. },
  474. locale: 'en-us',
  475. timezone: 'Europe/Berlin',
  476. template: template,
  477. ).render
  478. assert_equal(CGI.escapeHTML('#{ticket.create / not allowed}'), result)
  479. template = "\#{ticket.new}"
  480. result = described_class.new(
  481. objects: {
  482. ticket: ticket,
  483. },
  484. locale: 'en-us',
  485. timezone: 'Europe/Berlin',
  486. template: template,
  487. ).render
  488. assert_equal(CGI.escapeHTML('#{ticket.new / not allowed}'), result)
  489. template = "\#{ticket.update_att}"
  490. result = described_class.new(
  491. objects: {
  492. ticket: ticket,
  493. },
  494. locale: 'en-us',
  495. timezone: 'Europe/Berlin',
  496. template: template,
  497. ).render
  498. assert_equal(CGI.escapeHTML('#{ticket.update_att / not allowed}'), result)
  499. template = "\#{ticket.all}"
  500. result = described_class.new(
  501. objects: {
  502. ticket: ticket,
  503. },
  504. locale: 'en-us',
  505. timezone: 'Europe/Berlin',
  506. template: template,
  507. ).render
  508. assert_equal(CGI.escapeHTML('#{ticket.all / not allowed}'), result)
  509. template = "\#{ticket.find}"
  510. result = described_class.new(
  511. objects: {
  512. ticket: ticket,
  513. },
  514. locale: 'en-us',
  515. timezone: 'Europe/Berlin',
  516. template: template,
  517. ).render
  518. assert_equal(CGI.escapeHTML('#{ticket.find / not allowed}'), result)
  519. template = "\#{ticket.where}"
  520. result = described_class.new(
  521. objects: {
  522. ticket: ticket,
  523. },
  524. locale: 'en-us',
  525. timezone: 'Europe/Berlin',
  526. template: template,
  527. ).render
  528. assert_equal(CGI.escapeHTML('#{ticket.where / not allowed}'), result)
  529. template = "\#{ticket. destroy}"
  530. result = described_class.new(
  531. objects: {
  532. ticket: ticket,
  533. },
  534. locale: 'en-us',
  535. timezone: 'Europe/Berlin',
  536. template: template,
  537. ).render
  538. assert_equal(CGI.escapeHTML('#{ticket.destroy / not allowed}'), result)
  539. template = "\#{ticket.\n destroy}"
  540. result = described_class.new(
  541. objects: {
  542. ticket: ticket,
  543. },
  544. locale: 'en-us',
  545. timezone: 'Europe/Berlin',
  546. template: template,
  547. ).render
  548. assert_equal(CGI.escapeHTML("\#{ticket.destroy / not allowed}"), result)
  549. template = "\#{ticket.\t destroy}"
  550. result = described_class.new(
  551. objects: {
  552. ticket: ticket,
  553. },
  554. locale: 'en-us',
  555. timezone: 'Europe/Berlin',
  556. template: template,
  557. ).render
  558. assert_equal(CGI.escapeHTML("\#{ticket.destroy / not allowed}"), result)
  559. template = "\#{ticket.\r destroy}"
  560. result = described_class.new(
  561. objects: {
  562. ticket: ticket,
  563. },
  564. locale: 'en-us',
  565. timezone: 'Europe/Berlin',
  566. template: template,
  567. ).render
  568. assert_equal(CGI.escapeHTML("\#{ticket.destroy / not allowed}"), result)
  569. end
  570. test 'methods with single Integer parameter' do
  571. template = "\#{ticket.title.first(3)}"
  572. result = described_class.new(
  573. objects: {
  574. ticket: ticket,
  575. },
  576. locale: 'en-us',
  577. timezone: 'Europe/Berlin',
  578. template: template,
  579. ).render
  580. assert_equal(CGI.escapeHTML('<b>'), result)
  581. template = "\#{ticket.title.last(4)}"
  582. result = described_class.new(
  583. objects: {
  584. ticket: ticket,
  585. },
  586. locale: 'en-us',
  587. timezone: 'Europe/Berlin',
  588. template: template,
  589. ).render
  590. assert_equal(CGI.escapeHTML('</b>'), result)
  591. template = "\#{ticket.title.slice(3, 4)}"
  592. result = described_class.new(
  593. objects: {
  594. ticket: ticket,
  595. },
  596. locale: 'en-us',
  597. timezone: 'Europe/Berlin',
  598. template: template,
  599. ).render
  600. assert_equal(CGI.escapeHTML("\#{ticket.title.slice(3,4) / invalid parameter: 3,4}"), result)
  601. template = "\#{ticket.title.first('some invalid parameter')}"
  602. result = described_class.new(
  603. objects: {
  604. ticket: ticket,
  605. },
  606. locale: 'en-us',
  607. timezone: 'Europe/Berlin',
  608. template: template,
  609. ).render
  610. assert_equal("\#{ticket.title.first(someinvalidparameter) / invalid parameter: someinvalidparameter}", result)
  611. template = "\#{ticket.title.chomp(`cat /etc/passwd`)}"
  612. result = described_class.new(
  613. objects: {
  614. ticket: ticket,
  615. },
  616. locale: 'en-us',
  617. timezone: 'Europe/Berlin',
  618. template: template,
  619. ).render
  620. assert_equal("\#{ticket.title.chomp(`cat/etc/passwd`) / not allowed}", result)
  621. end
  622. end