ticket_spec.rb 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe Gql::Queries::Ticket, type: :graphql do
  4. context 'when fetching tickets' do
  5. let(:agent) { create(:agent) }
  6. let(:query) do
  7. <<~QUERY
  8. query ticket($ticketId: ID, $ticketInternalId: Int, $ticketNumber: String) {
  9. ticket(
  10. ticket: {
  11. ticketId: $ticketId
  12. ticketInternalId: $ticketInternalId
  13. ticketNumber: $ticketNumber
  14. }
  15. ) {
  16. id
  17. internalId
  18. number
  19. title
  20. owner {
  21. id
  22. firstname
  23. email
  24. createdBy {
  25. internalId
  26. }
  27. updatedBy {
  28. internalId
  29. }
  30. }
  31. customer {
  32. id
  33. firstname
  34. email
  35. }
  36. organization {
  37. name
  38. }
  39. tags
  40. subscribed
  41. mentions {
  42. edges {
  43. node {
  44. user {
  45. id
  46. }
  47. }
  48. cursor
  49. }
  50. }
  51. policy {
  52. update
  53. destroy
  54. followUp
  55. agentReadAccess
  56. agentUpdateAccess
  57. createMentions
  58. }
  59. timeUnitsPerType {
  60. name
  61. timeUnit
  62. }
  63. stateColorCode
  64. }
  65. }
  66. QUERY
  67. end
  68. let(:variables) { { ticketId: gql.id(ticket) } }
  69. let(:ticket) do
  70. create(:ticket).tap do |t|
  71. t.tag_add('tag1', 1)
  72. t.tag_add('tag2', 1)
  73. end
  74. end
  75. before do
  76. setup if defined?(setup)
  77. gql.execute(query, variables: variables)
  78. end
  79. context 'with an agent', authenticated_as: :agent do
  80. context 'with permission' do
  81. let(:agent) { create(:agent, groups: [ticket.group]) }
  82. shared_examples 'finds the ticket' do
  83. let(:expected_result) do
  84. {
  85. 'id' => gql.id(ticket),
  86. 'internalId' => ticket.id,
  87. 'number' => ticket.number,
  88. # Agent is allowed to see user data
  89. 'owner' => include(
  90. 'firstname' => ticket.owner.firstname,
  91. 'email' => ticket.owner.email,
  92. 'createdBy' => { 'internalId' => 1 },
  93. 'updatedBy' => { 'internalId' => 1 },
  94. ),
  95. 'tags' => %w[tag1 tag2],
  96. 'policy' => {
  97. 'agentReadAccess' => true,
  98. 'agentUpdateAccess' => true,
  99. 'createMentions' => true,
  100. 'destroy' => false,
  101. 'followUp' => true,
  102. 'update' => true
  103. },
  104. 'stateColorCode' => 'open',
  105. }
  106. end
  107. it 'finds the ticket' do
  108. expect(gql.result.data).to include(expected_result)
  109. end
  110. end
  111. context 'when fetching a ticket by ticketId' do
  112. include_examples 'finds the ticket'
  113. end
  114. context 'when fetching a ticket by ticketInternalId' do
  115. let(:variables) { { ticketInternalId: ticket.id } }
  116. include_examples 'finds the ticket'
  117. end
  118. context 'when fetching a ticket by ticketNumber' do
  119. let(:variables) { { ticketNumber: ticket.number } }
  120. include_examples 'finds the ticket'
  121. end
  122. context 'when locator is missing' do
  123. let(:variables) { {} }
  124. it 'raises an exception' do
  125. expect(gql.result.error_type).to eq(GraphQL::Schema::Validator::ValidationFailedError)
  126. end
  127. end
  128. context 'with having time accounting enabled' do
  129. let(:ticket_time_accounting_types) { create_list(:ticket_time_accounting_type, 2) }
  130. let(:ticket_time_accounting) { create(:ticket_time_accounting, ticket: ticket, time_unit: 50) }
  131. let(:ticket_time_accounting_with_type) { create(:ticket_time_accounting, ticket: ticket, time_unit: 25, type: ticket_time_accounting_types[0]) }
  132. let(:ticket_time_accounting_with_type2) { create(:ticket_time_accounting, ticket: ticket, time_unit: 250, type: ticket_time_accounting_types[1]) }
  133. let(:setup) do
  134. Setting.set('time_accounting', true)
  135. Setting.set('time_accounting_types', true)
  136. ticket_time_accounting_with_type2 && ticket_time_accounting_with_type && ticket_time_accounting
  137. end
  138. it 'contains time unit entries grouped by type with a sum' do
  139. expect(gql.result.data['timeUnitsPerType']).to eq([
  140. {
  141. 'name' => ticket_time_accounting_types[1].name,
  142. 'timeUnit' => 250.0,
  143. },
  144. {
  145. 'name' => 'None',
  146. 'timeUnit' => 50.0,
  147. },
  148. {
  149. 'name' => ticket_time_accounting_types[0].name,
  150. 'timeUnit' => 25.0,
  151. },
  152. ])
  153. end
  154. end
  155. context 'when subscribed' do
  156. before do
  157. Mention.subscribe! ticket, agent
  158. gql.execute(query, variables: variables)
  159. end
  160. it 'returns subscribed' do
  161. expect(gql.result.data).to include('subscribed' => true)
  162. end
  163. it 'returns user in subscribers list' do
  164. expect(gql.result.data.dig('mentions', 'edges'))
  165. .to include(include('node' => include('user' => include('id' => gql.id(agent)))))
  166. end
  167. end
  168. end
  169. context 'without permission' do
  170. it 'raises authorization error' do
  171. expect(gql.result.error_type).to eq(Exceptions::Forbidden)
  172. end
  173. end
  174. context 'without ticket' do
  175. let(:ticket) { create(:ticket).tap(&:destroy) }
  176. it 'fetches no ticket' do
  177. expect(gql.result.error_type).to eq(ActiveRecord::RecordNotFound)
  178. end
  179. end
  180. end
  181. context 'with a customer', authenticated_as: :customer do
  182. let(:customer) { create(:customer) }
  183. let(:ticket) { create(:ticket, customer: customer) }
  184. let(:expected_result) do
  185. {
  186. 'id' => gql.id(ticket),
  187. 'internalId' => ticket.id,
  188. 'number' => ticket.number,
  189. # Customer is not allowed to see data of other users
  190. 'owner' => include(
  191. 'firstname' => ticket.owner.firstname,
  192. 'email' => nil,
  193. 'createdBy' => nil,
  194. 'updatedBy' => nil,
  195. ),
  196. # Customer may see their own data
  197. 'customer' => include(
  198. 'firstname' => customer.firstname,
  199. 'email' => customer.email,
  200. ),
  201. 'policy' => {
  202. 'agentReadAccess' => false,
  203. 'agentUpdateAccess' => false,
  204. 'createMentions' => false,
  205. 'destroy' => false,
  206. 'followUp' => true,
  207. 'update' => true
  208. },
  209. }
  210. end
  211. it 'finds the ticket, but without data of other users' do
  212. expect(gql.result.data).to include(expected_result)
  213. end
  214. end
  215. it_behaves_like 'graphql responds with error if unauthenticated'
  216. end
  217. end