article_spec.rb 28 KB

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