ticket_spec.rb 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. require 'rails_helper'
  2. require 'models/concerns/can_lookup_examples'
  3. RSpec.describe Ticket do
  4. include_examples 'CanLookup'
  5. describe '#merge_to' do
  6. it 'reassigns all links to the target ticket after merge' do
  7. source_ticket = create(:ticket)
  8. target_ticket = create(:ticket)
  9. important_ticket1 = create(:ticket)
  10. important_ticket2 = create(:ticket)
  11. important_ticket3 = create(:ticket)
  12. create(:link, link_object_source_value: source_ticket.id, link_object_target_value: important_ticket1.id)
  13. create(:link, link_object_source_value: source_ticket.id, link_object_target_value: important_ticket2.id)
  14. create(:link, link_object_source_value: source_ticket.id, link_object_target_value: important_ticket3.id)
  15. source_ticket.merge_to(
  16. ticket_id: target_ticket.id,
  17. user_id: 1,
  18. )
  19. links = Link.list(
  20. link_object: 'Ticket',
  21. link_object_value: target_ticket.id,
  22. )
  23. expected_ticket_ids = [source_ticket.id, important_ticket1.id, important_ticket2.id, important_ticket3.id ]
  24. check_ticket_ids = links.collect { |link| link['link_object_value'] }
  25. expect(check_ticket_ids).to match_array(expected_ticket_ids)
  26. end
  27. it 'prevents cross merging tickets' do
  28. source_ticket = create(:ticket)
  29. target_ticket = create(:ticket)
  30. result = source_ticket.merge_to(
  31. ticket_id: target_ticket.id,
  32. user_id: 1,
  33. )
  34. expect(result).to be(true)
  35. expect do
  36. result = target_ticket.merge_to(
  37. ticket_id: source_ticket.id,
  38. user_id: 1,
  39. )
  40. end.to raise_error('ticket already merged, no merge into merged ticket possible')
  41. end
  42. it 'prevents merging ticket in it self' do
  43. source_ticket = create(:ticket)
  44. expect do
  45. result = source_ticket.merge_to(
  46. ticket_id: source_ticket.id,
  47. user_id: 1,
  48. )
  49. end.to raise_error('Can\'t merge ticket with it self!')
  50. end
  51. end
  52. describe '#destroy' do
  53. it 'deletes all related objects before destroy' do
  54. ApplicationHandleInfo.current = 'application_server'
  55. source_ticket = create(:ticket)
  56. # create some links
  57. important_ticket1 = create(:ticket)
  58. important_ticket2 = create(:ticket)
  59. important_ticket3 = create(:ticket)
  60. # create some articles
  61. create(:ticket_article, ticket_id: source_ticket.id)
  62. create(:ticket_article, ticket_id: source_ticket.id)
  63. create(:ticket_article, ticket_id: source_ticket.id)
  64. create(:link, link_object_source_value: source_ticket.id, link_object_target_value: important_ticket1.id)
  65. create(:link, link_object_source_value: important_ticket2.id, link_object_target_value: source_ticket.id)
  66. create(:link, link_object_source_value: source_ticket.id, link_object_target_value: important_ticket3.id)
  67. create(:online_notification, o_id: source_ticket.id)
  68. create(:tag, o_id: source_ticket.id)
  69. Observer::Transaction.commit
  70. Scheduler.worker(true)
  71. # get before destroy
  72. activities = ActivityStream.where(
  73. activity_stream_object_id: ObjectLookup.by_name('Ticket'),
  74. o_id: source_ticket.id,
  75. )
  76. links = Link.list(
  77. link_object: 'Ticket',
  78. link_object_value: source_ticket.id
  79. )
  80. articles = Ticket::Article.where(ticket_id: source_ticket.id)
  81. history = History.list('Ticket', source_ticket.id, nil, true)
  82. karma_log = Karma::ActivityLog.where(
  83. object_lookup_id: ObjectLookup.by_name('Ticket'),
  84. o_id: source_ticket.id,
  85. )
  86. online_notifications = OnlineNotification.where(
  87. object_lookup_id: ObjectLookup.by_name('Ticket'),
  88. o_id: source_ticket.id,
  89. )
  90. recent_views = OnlineNotification.where(
  91. object_lookup_id: ObjectLookup.by_name('Ticket'),
  92. o_id: source_ticket.id,
  93. )
  94. tags = Tag.tag_list(
  95. object: 'Ticket',
  96. o_id: source_ticket.id,
  97. )
  98. # check before destroy
  99. expect(activities.count).to be >= 0
  100. expect(links.count).to be >= 0
  101. expect(articles.count).to be >= 0
  102. expect(history[:list].count).to be >= 0
  103. expect(karma_log.count).to be >= 0
  104. expect(online_notifications.count).to be >= 0
  105. expect(recent_views.count).to be >= 0
  106. expect(tags.count).to be >= 0
  107. # destroy ticket
  108. source_ticket.destroy
  109. # get after destroy
  110. activities = ActivityStream.where(
  111. activity_stream_object_id: ObjectLookup.by_name('Ticket'),
  112. o_id: source_ticket.id,
  113. )
  114. links = Link.list(
  115. link_object: 'Ticket',
  116. link_object_value: source_ticket.id
  117. )
  118. articles = Ticket::Article.where(ticket_id: source_ticket.id)
  119. history = History.list('Ticket', source_ticket.id, nil, true)
  120. karma_log = Karma::ActivityLog.where(
  121. object_lookup_id: ObjectLookup.by_name('Ticket'),
  122. o_id: source_ticket.id,
  123. )
  124. online_notifications = OnlineNotification.where(
  125. object_lookup_id: ObjectLookup.by_name('Ticket'),
  126. o_id: source_ticket.id,
  127. )
  128. recent_views = OnlineNotification.where(
  129. object_lookup_id: ObjectLookup.by_name('Ticket'),
  130. o_id: source_ticket.id,
  131. )
  132. tags = Tag.tag_list(
  133. object: 'Ticket',
  134. o_id: source_ticket.id,
  135. )
  136. # check after destroy
  137. expect(activities.count).to be == 0
  138. expect(links.count).to be == 0
  139. expect(articles.count).to be == 0
  140. expect(history[:list].count).to be == 0
  141. expect(karma_log.count).to be == 0
  142. expect(online_notifications.count).to be == 0
  143. expect(recent_views.count).to be == 0
  144. expect(tags.count).to be == 0
  145. end
  146. end
  147. describe '#perform_changes' do
  148. it 'performs a ticket state change on a ticket' do
  149. source_ticket = create(:ticket)
  150. changes = {
  151. 'ticket.state_id' => { 'value' => Ticket::State.lookup(name: 'closed').id.to_s },
  152. }
  153. source_ticket.perform_changes(changes, 'trigger', source_ticket, User.find(1))
  154. source_ticket.reload
  155. expect(source_ticket.state.name).to eq('closed')
  156. end
  157. it 'performs a ticket deletion on a ticket' do
  158. source_ticket = create(:ticket)
  159. changes = {
  160. 'ticket.state_id' => { 'value' => Ticket::State.lookup(name: 'closed').id.to_s },
  161. 'ticket.action' => { 'value' => 'delete' },
  162. }
  163. source_ticket.perform_changes(changes, 'trigger', source_ticket, User.find(1))
  164. ticket_with_source_ids = Ticket.where(id: source_ticket.id)
  165. expect(ticket_with_source_ids).to match_array([])
  166. end
  167. # Regression test for https://github.com/zammad/zammad/issues/2001
  168. it 'does not modify its arguments' do
  169. trigger = Trigger.new(
  170. perform: {
  171. 'notification.email' => {
  172. body: "Hello \#{ticket.customer.firstname} \#{ticket.customer.lastname},",
  173. recipient: %w[article_last_sender ticket_owner ticket_customer ticket_agents],
  174. subject: "Autoclose (\#{ticket.title})"
  175. }
  176. }
  177. )
  178. expect { Ticket.first.perform_changes(trigger.perform, 'trigger', {}, 1) }
  179. .to not_change { trigger.perform['notification.email'][:body] }
  180. .and not_change { trigger.perform['notification.email'][:subject] }
  181. end
  182. # Regression test for https://github.com/zammad/zammad/issues/1543
  183. #
  184. # If a new article fires an email notification trigger,
  185. # and then another article is added to the same ticket
  186. # before that trigger is performed,
  187. # the email template's 'article' var should refer to the originating article,
  188. # not the newest one.
  189. #
  190. # (This occurs whenever one action fires multiple email notification triggers.)
  191. it 'passes the correct article to NotificationFactory::Mailer' do
  192. # required by Ticket#perform_changes for email notifications
  193. Group.first.update(email_address: create(:email_address))
  194. ticket = Ticket.first
  195. orig_article = Ticket::Article.where(ticket_id: ticket.id).first
  196. newer_article = create(:ticket_article, ticket_id: ticket.id)
  197. trigger = Trigger.new(
  198. perform: {
  199. 'notification.email' => {
  200. body: '',
  201. recipient: 'ticket_customer',
  202. subject: ''
  203. }
  204. }
  205. )
  206. allow(NotificationFactory::Mailer).to receive(:template).and_return('')
  207. ticket.perform_changes(trigger.perform, 'trigger', { article_id: orig_article.id }, 1)
  208. expect(NotificationFactory::Mailer)
  209. .to have_received(:template)
  210. .with(hash_including(objects: { ticket: ticket, article: orig_article }))
  211. .at_least(:once)
  212. expect(NotificationFactory::Mailer)
  213. .not_to have_received(:template)
  214. .with(hash_including(objects: { ticket: ticket, article: newer_article }))
  215. end
  216. end
  217. describe '#selectors' do
  218. # https://github.com/zammad/zammad/issues/1769
  219. it 'does not return multiple results for a single ticket' do
  220. source_ticket = create(:ticket)
  221. source_ticket2 = create(:ticket)
  222. # create some articles
  223. create(:ticket_article, ticket_id: source_ticket.id, from: 'asdf1@blubselector.de')
  224. create(:ticket_article, ticket_id: source_ticket.id, from: 'asdf2@blubselector.de')
  225. create(:ticket_article, ticket_id: source_ticket.id, from: 'asdf3@blubselector.de')
  226. create(:ticket_article, ticket_id: source_ticket2.id, from: 'asdf4@blubselector.de')
  227. create(:ticket_article, ticket_id: source_ticket2.id, from: 'asdf5@blubselector.de')
  228. create(:ticket_article, ticket_id: source_ticket2.id, from: 'asdf6@blubselector.de')
  229. condition = {
  230. 'article.from' => {
  231. operator: 'contains',
  232. value: 'blubselector.de',
  233. },
  234. }
  235. ticket_count, tickets = Ticket.selectors(condition, 100, nil, 'full')
  236. expect(ticket_count).to be == 2
  237. expect(tickets.count).to be == 2
  238. end
  239. end
  240. context 'callbacks' do
  241. describe '#reset_pending_time' do
  242. it 'resets the pending time on state change' do
  243. ticket = create(:ticket,
  244. state: Ticket::State.lookup(name: 'pending reminder'),
  245. pending_time: Time.zone.now + 2.days)
  246. expect(ticket.pending_time).not_to be nil
  247. ticket.update!(state: Ticket::State.lookup(name: 'open'))
  248. expect(ticket.pending_time).to be nil
  249. end
  250. it 'lets handle ActiveRecord nil as new value' do
  251. ticket = create(:ticket)
  252. expect do
  253. ticket.update!(state: nil)
  254. end.to raise_error(ActiveRecord::StatementInvalid)
  255. end
  256. end
  257. end
  258. describe '#access?' do
  259. context 'agent' do
  260. it 'allows owner access' do
  261. owner = create(:agent_user)
  262. ticket = create(:ticket, owner: owner)
  263. expect( ticket.access?(owner, 'full') ).to be(true)
  264. end
  265. it 'allows group access' do
  266. agent = create(:agent_user)
  267. group = create(:group)
  268. ticket = create(:ticket, group: group)
  269. agent.group_names_access_map = {
  270. group.name => 'full',
  271. }
  272. expect( ticket.access?(agent, 'full') ).to be(true)
  273. end
  274. it 'prevents unauthorized access' do
  275. agent = create(:agent_user)
  276. ticket = create(:ticket)
  277. expect( ticket.access?(agent, 'read') ).to be(false)
  278. end
  279. end
  280. context 'customer' do
  281. it 'allows assigned access' do
  282. customer = create(:customer_user)
  283. ticket = create(:ticket, customer: customer)
  284. expect( ticket.access?(customer, 'full') ).to be(true)
  285. end
  286. context 'organization' do
  287. it 'allows access for shared' do
  288. organization = create(:organization)
  289. assigned = create(:customer_user, organization: organization)
  290. collegue = create(:customer_user, organization: organization)
  291. ticket = create(:ticket, customer: assigned)
  292. expect( ticket.access?(collegue, 'full') ).to be(true)
  293. end
  294. it 'prevents unshared access' do
  295. organization = create(:organization, shared: false)
  296. assigned = create(:customer_user, organization: organization)
  297. collegue = create(:customer_user, organization: organization)
  298. ticket = create(:ticket, customer: assigned)
  299. expect( ticket.access?(collegue, 'full') ).to be(false)
  300. end
  301. end
  302. it 'prevents unauthorized access' do
  303. customer = create(:customer_user)
  304. ticket = create(:ticket)
  305. expect( ticket.access?(customer, 'read') ).to be(false)
  306. end
  307. end
  308. end
  309. end