article_spec.rb 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe 'Ticket Article API endpoints', type: :request do
  4. let(:admin) do
  5. create(:admin, groups: Group.all)
  6. end
  7. let!(:group) { create(:group) }
  8. let(:agent) do
  9. create(:agent, groups: Group.all)
  10. end
  11. let(:customer) do
  12. create(:customer)
  13. end
  14. describe 'request handling' do
  15. it 'does ticket create with agent and articles' do
  16. params = {
  17. title: 'a new ticket #1',
  18. group: 'Users',
  19. customer_id: customer.id,
  20. article: {
  21. body: 'some body',
  22. }
  23. }
  24. authenticated_as(agent)
  25. post '/api/v1/tickets', params: params, as: :json
  26. expect(response).to have_http_status(:created)
  27. params = {
  28. ticket_id: json_response['id'],
  29. content_type: 'text/plain', # or text/html
  30. body: 'some body',
  31. type: 'note',
  32. }
  33. post '/api/v1/ticket_articles', params: params, as: :json
  34. expect(response).to have_http_status(:created)
  35. expect(json_response).to be_a(Hash)
  36. expect(json_response['subject']).to be_nil
  37. expect(json_response['body']).to eq('some body')
  38. expect(json_response['content_type']).to eq('text/plain')
  39. expect(json_response['updated_by_id']).to eq(agent.id)
  40. expect(json_response['created_by_id']).to eq(agent.id)
  41. ticket = Ticket.find(json_response['ticket_id'])
  42. expect(ticket.articles.count).to eq(2)
  43. expect(ticket.articles[0].attachments.count).to eq(0)
  44. expect(ticket.articles[1].attachments.count).to eq(0)
  45. params = {
  46. ticket_id: json_response['ticket_id'],
  47. content_type: 'text/html', # or text/html
  48. body: 'some body <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
  49. AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
  50. 9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />',
  51. type: 'note',
  52. }
  53. post '/api/v1/ticket_articles', params: params, as: :json
  54. expect(response).to have_http_status(:created)
  55. expect(json_response).to be_a(Hash)
  56. expect(json_response['subject']).to be_nil
  57. expect(json_response['body']).not_to match(%r{some body <img src="cid:.+?})
  58. expect(json_response['body']).to match(%r{some body <img src="/api/v1/ticket_attachment/.+?" alt="Red dot"})
  59. expect(json_response['content_type']).to eq('text/html')
  60. expect(json_response['updated_by_id']).to eq(agent.id)
  61. expect(json_response['created_by_id']).to eq(agent.id)
  62. ticket.articles.reload
  63. expect(ticket.articles.count).to eq(3)
  64. expect(ticket.articles[0].attachments.count).to eq(0)
  65. expect(ticket.articles[1].attachments.count).to eq(0)
  66. expect(ticket.articles[2].attachments.count).to eq(1)
  67. expect(ticket.articles[2].attachments[0]['id']).to be_truthy
  68. expect(ticket.articles[2].attachments[0]['filename']).to eq('image1.png')
  69. expect(ticket.articles[2].attachments[0]['size']).to eq('21')
  70. expect(ticket.articles[2].attachments[0]['preferences']['Mime-Type']).to eq('image/png')
  71. expect(ticket.articles[2].attachments[0]['preferences']['Content-Disposition']).to eq('inline')
  72. expect(ticket.articles[2].attachments[0]['preferences']['Content-ID']).to match(%r{@zammad.example.com})
  73. params = {
  74. ticket_id: json_response['ticket_id'],
  75. content_type: 'text/html', # or text/html
  76. body: 'some body',
  77. type: 'note',
  78. attachments: [
  79. { 'filename' => 'some_file.txt',
  80. 'data' => 'dGVzdCAxMjM=',
  81. 'mime-type' => 'text/plain' },
  82. ],
  83. }
  84. post '/api/v1/ticket_articles', params: params, as: :json
  85. expect(response).to have_http_status(:created)
  86. expect(json_response).to be_a(Hash)
  87. expect(json_response['subject']).to be_nil
  88. expect(json_response['body']).to eq('some body')
  89. expect(json_response['content_type']).to eq('text/html')
  90. expect(json_response['updated_by_id']).to eq(agent.id)
  91. expect(json_response['created_by_id']).to eq(agent.id)
  92. ticket.articles.reload
  93. expect(ticket.articles.count).to eq(4)
  94. expect(ticket.articles[0].attachments.count).to eq(0)
  95. expect(ticket.articles[1].attachments.count).to eq(0)
  96. expect(ticket.articles[2].attachments.count).to eq(1)
  97. expect(ticket.articles[3].attachments.count).to eq(1)
  98. get "/api/v1/ticket_articles/#{json_response['id']}?expand=true", params: {}, as: :json
  99. expect(response).to have_http_status(:ok)
  100. expect(json_response).to be_a(Hash)
  101. expect(json_response['attachments'].count).to eq(1)
  102. expect(json_response['attachments'][0]['id']).to be_truthy
  103. expect(json_response['attachments'][0]['filename']).to eq('some_file.txt')
  104. expect(json_response['attachments'][0]['size']).to eq('8')
  105. expect(json_response['attachments'][0]['preferences']['Mime-Type']).to eq('text/plain')
  106. params = {
  107. ticket_id: json_response['ticket_id'],
  108. content_type: 'text/plain',
  109. body: 'some body',
  110. type: 'note',
  111. internal: false,
  112. preferences: {
  113. some_key1: 123,
  114. highlight: '123',
  115. },
  116. }
  117. post '/api/v1/ticket_articles', params: params, as: :json
  118. expect(response).to have_http_status(:created)
  119. expect(json_response).to be_a(Hash)
  120. expect(json_response['subject']).to be_nil
  121. expect(json_response['body']).to eq('some body')
  122. expect(json_response['internal']).to be(false)
  123. expect(json_response['content_type']).to eq('text/plain')
  124. expect(json_response['updated_by_id']).to eq(agent.id)
  125. expect(json_response['created_by_id']).to eq(agent.id)
  126. expect(json_response['preferences']['some_key1']).to eq(123)
  127. expect(json_response['preferences']['highlight']).to eq('123')
  128. expect(ticket.articles.count).to eq(5)
  129. params = {
  130. body: 'some body 2',
  131. internal: true,
  132. preferences: {
  133. some_key2: 'abc',
  134. highlight: '234',
  135. },
  136. }
  137. put "/api/v1/ticket_articles/#{json_response['id']}", params: params, as: :json
  138. expect(response).to have_http_status(:ok)
  139. expect(json_response).to be_a(Hash)
  140. expect(json_response['subject']).to be_nil
  141. expect(json_response['body']).not_to eq('some body 2')
  142. expect(json_response['internal']).to be(true)
  143. expect(json_response['content_type']).to eq('text/plain')
  144. expect(json_response['updated_by_id']).to eq(agent.id)
  145. expect(json_response['created_by_id']).to eq(agent.id)
  146. expect(json_response['preferences']['some_key1']).to eq(123)
  147. expect(json_response['preferences']['some_key2']).not_to eq('abc')
  148. expect(json_response['preferences']['highlight']).to eq('234')
  149. end
  150. it 'does ticket create with customer and articles' do
  151. params = {
  152. title: 'a new ticket #2',
  153. group: 'Users',
  154. article: {
  155. body: 'some body',
  156. }
  157. }
  158. authenticated_as(customer)
  159. post '/api/v1/tickets', params: params, as: :json
  160. expect(response).to have_http_status(:created)
  161. params = {
  162. ticket_id: json_response['id'],
  163. content_type: 'text/plain', # or text/html
  164. body: 'some body',
  165. type: 'note',
  166. }
  167. post '/api/v1/ticket_articles', params: params, as: :json
  168. expect(response).to have_http_status(:created)
  169. expect(json_response).to be_a(Hash)
  170. expect(json_response['subject']).to be_nil
  171. expect(json_response['body']).to eq('some body')
  172. expect(json_response['content_type']).to eq('text/plain')
  173. expect(json_response['updated_by_id']).to eq(customer.id)
  174. expect(json_response['created_by_id']).to eq(customer.id)
  175. ticket = Ticket.find(json_response['ticket_id'])
  176. expect(ticket.articles.count).to eq(2)
  177. expect(ticket.articles[1].sender.name).to eq('Customer')
  178. expect(ticket.articles[0].attachments.count).to eq(0)
  179. expect(ticket.articles[1].attachments.count).to eq(0)
  180. params = {
  181. ticket_id: json_response['ticket_id'],
  182. content_type: 'text/plain', # or text/html
  183. body: 'some body',
  184. sender: 'Agent',
  185. type: 'note',
  186. }
  187. post '/api/v1/ticket_articles', params: params, as: :json
  188. expect(response).to have_http_status(:created)
  189. expect(json_response).to be_a(Hash)
  190. expect(json_response['subject']).to be_nil
  191. expect(json_response['body']).to eq('some body')
  192. expect(json_response['content_type']).to eq('text/plain')
  193. expect(json_response['updated_by_id']).to eq(customer.id)
  194. expect(json_response['created_by_id']).to eq(customer.id)
  195. ticket.articles.reload
  196. ticket = Ticket.find(json_response['ticket_id'])
  197. expect(ticket.articles.count).to eq(3)
  198. expect(ticket.articles[2].sender.name).to eq('Customer')
  199. expect(ticket.articles[2].internal).to be(false)
  200. expect(ticket.articles[0].attachments.count).to eq(0)
  201. expect(ticket.articles[1].attachments.count).to eq(0)
  202. expect(ticket.articles[2].attachments.count).to eq(0)
  203. params = {
  204. ticket_id: json_response['ticket_id'],
  205. content_type: 'text/plain', # or text/html
  206. body: 'some body 2',
  207. sender: 'Agent',
  208. type: 'note',
  209. internal: true,
  210. }
  211. post '/api/v1/ticket_articles', params: params, as: :json
  212. expect(response).to have_http_status(:created)
  213. expect(json_response).to be_a(Hash)
  214. expect(json_response['subject']).to be_nil
  215. expect(json_response['body']).to eq('some body 2')
  216. expect(json_response['content_type']).to eq('text/plain')
  217. expect(json_response['updated_by_id']).to eq(customer.id)
  218. expect(json_response['created_by_id']).to eq(customer.id)
  219. ticket.articles.reload
  220. ticket = Ticket.find(json_response['ticket_id'])
  221. expect(ticket.articles.count).to eq(4)
  222. expect(ticket.articles[3].sender.name).to eq('Customer')
  223. expect(ticket.articles[3].internal).to be(false)
  224. expect(ticket.articles[0].attachments.count).to eq(0)
  225. expect(ticket.articles[1].attachments.count).to eq(0)
  226. expect(ticket.articles[2].attachments.count).to eq(0)
  227. expect(ticket.articles[3].attachments.count).to eq(0)
  228. # add internal article
  229. article = create(
  230. :ticket_article,
  231. ticket_id: ticket.id,
  232. internal: true,
  233. sender: Ticket::Article::Sender.find_by(name: 'Agent'),
  234. type: Ticket::Article::Type.find_by(name: 'note'),
  235. )
  236. ticket.articles.reload
  237. expect(ticket.articles.count).to eq(5)
  238. expect(ticket.articles[4].sender.name).to eq('Agent')
  239. expect(ticket.articles[4].updated_by_id).to eq(1)
  240. expect(ticket.articles[4].created_by_id).to eq(1)
  241. expect(ticket.articles[0].attachments.count).to eq(0)
  242. expect(ticket.articles[1].attachments.count).to eq(0)
  243. expect(ticket.articles[2].attachments.count).to eq(0)
  244. expect(ticket.articles[3].attachments.count).to eq(0)
  245. expect(ticket.articles[4].attachments.count).to eq(0)
  246. get "/api/v1/ticket_articles/#{article.id}", params: {}, as: :json
  247. expect(response).to have_http_status(:forbidden)
  248. expect(json_response).to be_a(Hash)
  249. expect(json_response['error']).to eq('Not authorized')
  250. put "/api/v1/ticket_articles/#{article.id}", params: { internal: false }, as: :json
  251. expect(response).to have_http_status(:forbidden)
  252. expect(json_response).to be_a(Hash)
  253. expect(json_response['error']).to eq('Not authorized')
  254. end
  255. it 'does create phone ticket for customer and expected origin_by_id' do
  256. params = {
  257. title: 'a new ticket #1',
  258. group: 'Users',
  259. customer_id: customer.id,
  260. article: {
  261. body: 'some body',
  262. sender: 'Customer',
  263. type: 'phone',
  264. }
  265. }
  266. authenticated_as(agent)
  267. post '/api/v1/tickets', params: params, as: :json
  268. expect(response).to have_http_status(:created)
  269. expect(json_response).to be_a(Hash)
  270. expect(json_response['title']).to eq('a new ticket #1')
  271. expect(Ticket::Article.where(ticket_id: json_response['id']).count).to eq(2) # original + auto responder
  272. article = Ticket::Article.where(ticket_id: json_response['id']).first
  273. expect(article.origin_by_id).to eq(customer.id)
  274. expect(article.from).to be_in(
  275. [
  276. "#{customer.firstname} #{customer.lastname} <#{customer.email}>",
  277. "\"#{customer.firstname} #{customer.lastname}\" <#{customer.email}>"
  278. ]
  279. )
  280. end
  281. it 'does create phone ticket by customer and manipulate origin_by_id' do
  282. params = {
  283. title: 'a new ticket #1',
  284. group: 'Users',
  285. customer_id: customer.id,
  286. article: {
  287. body: 'some body',
  288. sender: 'Customer',
  289. type: 'phone',
  290. origin_by_id: 1,
  291. }
  292. }
  293. authenticated_as(customer)
  294. post '/api/v1/tickets', params: params, as: :json
  295. expect(response).to have_http_status(:created)
  296. expect(json_response).to be_a(Hash)
  297. expect(Ticket::Article.where(ticket_id: json_response['id']).count).to eq(1) # ony original
  298. article = Ticket::Article.where(ticket_id: json_response['id']).first
  299. expect(article.origin_by_id).to eq(customer.id)
  300. end
  301. it 'does ticket split with html - check attachments' do
  302. ticket = create(:ticket, group: group)
  303. article = create(
  304. :ticket_article,
  305. ticket_id: ticket.id,
  306. type: Ticket::Article::Type.lookup(name: 'note'),
  307. sender: Ticket::Article::Sender.lookup(name: 'Customer'),
  308. body: '<b>test</b> <img src="cid:15.274327094.140938@ZAMMAD.example.com"/> test <img src="cid:15.274327094.140938.3@ZAMMAD.example.com"/>',
  309. content_type: 'text/html',
  310. )
  311. create(:store,
  312. object: 'Ticket::Article',
  313. o_id: article.id,
  314. data: 'content_file1_normally_should_be_an_image',
  315. filename: 'some_file1.jpg',
  316. preferences: {
  317. 'Content-Type' => 'image/jpeg',
  318. 'Mime-Type' => 'image/jpeg',
  319. 'Content-ID' => '15.274327094.140938@zammad.example.com',
  320. 'Content-Disposition' => 'inline',
  321. })
  322. create(:store,
  323. object: 'Ticket::Article',
  324. o_id: article.id,
  325. data: 'content_file2_normally_should_be_an_image',
  326. filename: 'some_file2.jpg',
  327. preferences: {
  328. 'Content-Type' => 'image/jpeg',
  329. 'Mime-Type' => 'image/jpeg',
  330. 'Content-ID' => '15.274327094.140938.2@zammad.example.com',
  331. 'Content-Disposition' => 'inline',
  332. })
  333. create(:store,
  334. object: 'Ticket::Article',
  335. o_id: article.id,
  336. data: 'content_file3_normally_should_be_an_image',
  337. filename: 'some_file3.jpg',
  338. preferences: {
  339. 'Content-Type' => 'image/jpeg',
  340. 'Mime-Type' => 'image/jpeg',
  341. 'Content-ID' => '15.274327094.140938.3@zammad.example.com',
  342. })
  343. create(:store,
  344. object: 'Ticket::Article',
  345. o_id: article.id,
  346. data: 'content_file4_normally_should_be_an_image',
  347. filename: 'some_file4.jpg',
  348. preferences: {
  349. 'Content-Type' => 'image/jpeg',
  350. 'Mime-Type' => 'image/jpeg',
  351. 'Content-ID' => '15.274327094.140938.4@zammad.example.com',
  352. })
  353. create(:store,
  354. object: 'Ticket::Article',
  355. o_id: article.id,
  356. data: 'content_file1_normally_should_be_an_pdf',
  357. filename: 'Rechnung_RE-2018-200.pdf',
  358. preferences: {
  359. 'Content-Type' => 'application/octet-stream; name="Rechnung_RE-2018-200.pdf"',
  360. 'Mime-Type' => 'application/octet-stream',
  361. 'Content-ID' => '8AB0BEC88984EE4EBEF643C79C8E0346@zammad.example.com',
  362. 'Content-Description' => 'Rechnung_RE-2018-200.pdf',
  363. 'Content-Disposition' => 'attachment',
  364. })
  365. params = {
  366. form_id: 'b47ea422-1b96-49db-8399-aeffaa0e3fc9',
  367. }
  368. authenticated_as(agent)
  369. post "/api/v1/ticket_attachment_upload_clone_by_article/#{article.id}", params: params, as: :json
  370. expect(response).to have_http_status(:ok)
  371. expect(json_response).to be_a(Hash)
  372. expect(json_response['attachments']).to be_truthy
  373. expect(json_response['attachments'].count).to eq(3)
  374. post "/api/v1/ticket_attachment_upload_clone_by_article/#{article.id}", params: params, as: :json
  375. expect(response).to have_http_status(:ok)
  376. expect(json_response).to be_a(Hash)
  377. expect(json_response['attachments']).to be_truthy
  378. expect(json_response['attachments'].count).to eq(0)
  379. end
  380. it 'does ticket split with plain - check attachments' do
  381. ticket = create(
  382. :ticket,
  383. group: group,
  384. updated_by_id: agent.id,
  385. created_by_id: agent.id,
  386. )
  387. article = create(
  388. :ticket_article,
  389. ticket_id: ticket.id,
  390. type: Ticket::Article::Type.lookup(name: 'note'),
  391. sender: Ticket::Article::Sender.lookup(name: 'Customer'),
  392. body: '<b>test</b> <img src="cid:15.274327094.140938@zammad.example.com"/>',
  393. content_type: 'text/plain',
  394. updated_by_id: 1,
  395. created_by_id: 1,
  396. )
  397. create(:store,
  398. object: 'Ticket::Article',
  399. o_id: article.id,
  400. data: 'content_file1_normally_should_be_an_image',
  401. filename: 'some_file1.jpg',
  402. preferences: {
  403. 'Content-Type' => 'image/jpeg',
  404. 'Mime-Type' => 'image/jpeg',
  405. 'Content-ID' => '15.274327094.140938@zammad.example.com',
  406. 'Content-Disposition' => 'inline',
  407. })
  408. create(:store,
  409. object: 'Ticket::Article',
  410. o_id: article.id,
  411. data: 'content_file1_normally_should_be_an_image',
  412. filename: 'some_file2.jpg',
  413. preferences: {
  414. 'Content-Type' => 'image/jpeg',
  415. 'Mime-Type' => 'image/jpeg',
  416. 'Content-ID' => '15.274327094.140938.2@zammad.example.com',
  417. 'Content-Disposition' => 'inline',
  418. })
  419. create(:store,
  420. object: 'Ticket::Article',
  421. o_id: article.id,
  422. data: 'content_file1_normally_should_be_an_pdf',
  423. filename: 'Rechnung_RE-2018-200.pdf',
  424. preferences: {
  425. 'Content-Type' => 'application/octet-stream; name="Rechnung_RE-2018-200.pdf"',
  426. 'Mime-Type' => 'application/octet-stream',
  427. 'Content-ID' => '8AB0BEC88984EE4EBEF643C79C8E0346@zammad.example.com',
  428. 'Content-Description' => 'Rechnung_RE-2018-200.pdf',
  429. 'Content-Disposition' => 'attachment',
  430. })
  431. params = {
  432. form_id: 'b47ea422-1b96-49db-8399-aeffaa0e3fc9',
  433. }
  434. authenticated_as(agent)
  435. post "/api/v1/ticket_attachment_upload_clone_by_article/#{article.id}", params: params, as: :json
  436. expect(response).to have_http_status(:ok)
  437. expect(json_response).to be_a(Hash)
  438. expect(json_response['attachments']).to be_truthy
  439. expect(json_response['attachments'].count).to eq(3)
  440. post "/api/v1/ticket_attachment_upload_clone_by_article/#{article.id}", params: params, as: :json
  441. expect(response).to have_http_status(:ok)
  442. expect(json_response).to be_a(Hash)
  443. expect(json_response['attachments']).to be_truthy
  444. expect(json_response['attachments'].count).to eq(0)
  445. end
  446. it 'does ticket create with mentions' do
  447. params = {
  448. title: 'a new ticket #1',
  449. group: 'Users',
  450. customer_id: customer.id,
  451. article: {
  452. body: "some body <a data-mention-user-id=\"#{agent.id}\">agent</a>",
  453. }
  454. }
  455. authenticated_as(agent)
  456. post '/api/v1/tickets', params: params, as: :json
  457. expect(response).to have_http_status(:created)
  458. expect(Mention.where(mentionable: Ticket.last).count).to eq(1)
  459. end
  460. it 'does not ticket create with invalid mentions' do
  461. params = {
  462. title: 'a new ticket #1',
  463. group: 'Users',
  464. customer_id: customer.id,
  465. article: {
  466. body: "some body <a data-mention-user-id=\"#{create(:customer).id}\">customer</a>",
  467. }
  468. }
  469. authenticated_as(agent)
  470. post '/api/v1/tickets', params: params, as: :json
  471. expect(response).to have_http_status(:unprocessable_entity)
  472. expect(Mention.count).to eq(0)
  473. end
  474. it 'does not ticket create with mentions when customer' do
  475. params = {
  476. title: 'a new ticket #1',
  477. group: 'Users',
  478. customer_id: customer.id,
  479. article: {
  480. body: "some body <a data-mention-user-id=\"#{agent.id}\">agent</a>",
  481. }
  482. }
  483. authenticated_as(customer)
  484. post '/api/v1/tickets', params: params, as: :json
  485. expect(response).to have_http_status(:forbidden)
  486. expect(Mention.count).to eq(0)
  487. end
  488. end
  489. describe 'DELETE /api/v1/ticket_articles/:id', authenticated_as: -> { user } do
  490. let(:other_agent) { create(:agent, groups: [Group.first]) }
  491. let(:ticket) do
  492. create(:ticket, group: Group.first)
  493. end
  494. let(:article_communication) do
  495. create(:ticket_article,
  496. sender_name: 'Agent', type_name: 'email', ticket: ticket,
  497. updated_by_id: agent.id, created_by_id: agent.id)
  498. end
  499. let(:article_note_self) do
  500. create(:ticket_article,
  501. sender_name: 'Agent', internal: true, type_name: 'note', ticket: ticket,
  502. updated_by_id: user.id, created_by_id: user.id)
  503. end
  504. let(:article_note_other) do
  505. create(:ticket_article,
  506. sender_name: 'Agent', internal: true, type_name: 'note', ticket: ticket,
  507. updated_by_id: other_agent.id, created_by_id: other_agent.id)
  508. end
  509. let(:article_note_customer) do
  510. create(:ticket_article,
  511. sender_name: 'Customer', internal: false, type_name: 'note', ticket: ticket,
  512. updated_by_id: customer.id, created_by_id: customer.id)
  513. end
  514. let(:article_note_communication_self) do
  515. create(:ticket_article_type, name: 'note_communication', communication: true)
  516. create(:ticket_article,
  517. sender_name: 'Agent', internal: true, type_name: 'note_communication', ticket: ticket,
  518. updated_by_id: user.id, created_by_id: user.id)
  519. end
  520. let(:article_note_communication_other) do
  521. create(:ticket_article_type, name: 'note_communication', communication: true)
  522. create(:ticket_article,
  523. sender_name: 'Agent', internal: true, type_name: 'note_communication', ticket: ticket,
  524. updated_by_id: other_agent.id, created_by_id: other_agent.id)
  525. end
  526. def delete_article_via_rest(article)
  527. delete "/api/v1/ticket_articles/#{article.id}", params: {}, as: :json
  528. end
  529. shared_examples 'succeeds' do
  530. it 'succeeds' do
  531. expect { delete_article_via_rest(article) }.to change { Ticket::Article.exists?(id: article.id) }
  532. end
  533. end
  534. shared_examples 'fails' do
  535. it 'fails' do
  536. expect { delete_article_via_rest(article) }.not_to change { Ticket::Article.exists?(id: article.id) }
  537. end
  538. end
  539. shared_examples 'deleting' do |item:, now:, later:, much_later:|
  540. context "deleting #{item}" do
  541. let(:article) { send(item) }
  542. include_examples now ? 'succeeds' : 'fails'
  543. context '8 minutes later' do
  544. before { article && travel(8.minutes) }
  545. include_examples later ? 'succeeds' : 'fails'
  546. end
  547. context '11 minutes later' do
  548. before { article && travel(11.minutes) }
  549. include_examples much_later ? 'succeeds' : 'fails'
  550. end
  551. end
  552. end
  553. context 'as admin' do
  554. let(:user) { admin }
  555. include_examples 'deleting',
  556. item: 'article_communication',
  557. now: false, later: false, much_later: false
  558. include_examples 'deleting',
  559. item: 'article_note_self',
  560. now: true, later: true, much_later: false
  561. include_examples 'deleting',
  562. item: 'article_note_other',
  563. now: false, later: false, much_later: false
  564. include_examples 'deleting',
  565. item: 'article_note_customer',
  566. now: false, later: false, much_later: false
  567. include_examples 'deleting',
  568. item: 'article_note_communication_self',
  569. now: true, later: true, much_later: false
  570. include_examples 'deleting',
  571. item: 'article_note_communication_other',
  572. now: false, later: false, much_later: false
  573. end
  574. context 'as agent' do
  575. let(:user) { agent }
  576. include_examples 'deleting',
  577. item: 'article_communication',
  578. now: false, later: false, much_later: false
  579. include_examples 'deleting',
  580. item: 'article_note_self',
  581. now: true, later: true, much_later: false
  582. include_examples 'deleting',
  583. item: 'article_note_other',
  584. now: false, later: false, much_later: false
  585. include_examples 'deleting',
  586. item: 'article_note_customer',
  587. now: false, later: false, much_later: false
  588. include_examples 'deleting',
  589. item: 'article_note_communication_self',
  590. now: true, later: true, much_later: false
  591. include_examples 'deleting',
  592. item: 'article_note_communication_other',
  593. now: false, later: false, much_later: false
  594. end
  595. context 'as customer' do
  596. let(:user) { customer }
  597. include_examples 'deleting',
  598. item: 'article_communication',
  599. now: false, later: false, much_later: false
  600. include_examples 'deleting',
  601. item: 'article_note_other',
  602. now: false, later: false, much_later: false
  603. include_examples 'deleting',
  604. item: 'article_note_customer',
  605. now: false, later: false, much_later: false
  606. include_examples 'deleting',
  607. item: 'article_note_communication_self',
  608. now: false, later: false, much_later: false
  609. include_examples 'deleting',
  610. item: 'article_note_communication_other',
  611. now: false, later: false, much_later: false
  612. end
  613. context 'with custom timeframe' do
  614. before { Setting.set 'ui_ticket_zoom_article_delete_timeframe', 6000 }
  615. let(:article) { article_note_self }
  616. context 'as admin' do
  617. let(:user) { admin }
  618. context 'deleting before timeframe' do
  619. before { article && travel(5000.seconds) }
  620. include_examples 'succeeds'
  621. end
  622. context 'deleting after timeframe' do
  623. before { article && travel(8000.seconds) }
  624. include_examples 'fails'
  625. end
  626. end
  627. context 'as agent' do
  628. let(:user) { agent }
  629. context 'deleting before timeframe' do
  630. before { article && travel(5000.seconds) }
  631. include_examples 'succeeds'
  632. end
  633. context 'deleting after timeframe' do
  634. before { article && travel(8000.seconds) }
  635. include_examples 'fails'
  636. end
  637. end
  638. end
  639. context 'with timeframe as 0' do
  640. before { Setting.set 'ui_ticket_zoom_article_delete_timeframe', 0 }
  641. let(:article) { article_note_self }
  642. context 'as agent' do
  643. let(:user) { agent }
  644. context 'deleting long after' do
  645. before { article && travel(99.days) }
  646. include_examples 'succeeds'
  647. end
  648. end
  649. end
  650. end
  651. end