create_spec.rb 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. RSpec.describe Service::Ticket::Article::Create, current_user_id: -> { user.id } do
  4. subject(:service) { described_class.new(current_user: user) }
  5. let(:ticket) { create(:ticket, customer: create(:agent)) }
  6. let(:user) { create(:agent, groups: [ticket.group]) }
  7. let(:payload) { { body: 'test' } }
  8. let(:article) { service.execute(article_data: payload, ticket: ticket) }
  9. describe '#execute' do
  10. it 'creates an article' do
  11. expect(article).to be_persisted
  12. end
  13. it 'creates an article even if contains wrong ticket id' do
  14. payload[:ticket_id] = 123_456
  15. expect(article).to be_persisted.and(have_attributes(ticket_id: ticket.id))
  16. end
  17. describe 'time accounting', :aggregate_failures do
  18. let(:time_accounting_enabled) { true }
  19. before do
  20. Setting.set('time_accounting', time_accounting_enabled)
  21. payload[:time_unit] = 60
  22. end
  23. it 'adds time accounting without type' do
  24. expect(article.ticket_time_accounting.time_unit).to be_present
  25. expect(article.ticket_time_accounting.type).to be_nil
  26. end
  27. context 'with accounting type' do
  28. let(:accounted_time_type) { create(:ticket_time_accounting_type) }
  29. before do
  30. payload[:accounted_time_type] = accounted_time_type
  31. end
  32. it 'adds time accounting with type' do
  33. expect(article.ticket_time_accounting.time_unit).to be_present
  34. expect(article.ticket_time_accounting.type).to eq(accounted_time_type)
  35. end
  36. end
  37. context 'when time accounting is not enabled' do
  38. let(:time_accounting_enabled) { false }
  39. it 'does not save article and raises error' do
  40. expect { article }
  41. .to raise_error(%r{Time Accounting is not enabled})
  42. end
  43. end
  44. end
  45. describe 'to and cc fields processing' do
  46. it 'translates to and cc fields from arrays to strings' do
  47. payload.merge!({ to: %w[a b], cc: %w[b c] })
  48. expect(article).to have_attributes(to: 'a, b', cc: 'b, c')
  49. end
  50. it 'handles string and nil values' do
  51. payload.merge!({ to: 'a,b', cc: nil })
  52. expect(article).to have_attributes(to: 'a,b', cc: '')
  53. end
  54. end
  55. describe 'sender processing' do
  56. context 'when user is agent' do
  57. it 'agent is set to agent' do
  58. expect(article.sender.name).to eq 'Agent'
  59. end
  60. it 'preserves original value if given' do
  61. payload[:sender] = 'Customer'
  62. expect(article.sender.name).to eq 'Customer'
  63. end
  64. end
  65. context 'when user is customer' do
  66. let(:user) { ticket.customer }
  67. let(:ticket) { create(:ticket, customer: create(:customer)) }
  68. it 'ensures sender is set to customer' do
  69. expect(article.sender.name).to eq 'Customer'
  70. end
  71. end
  72. # Agent-Customer is incorrectly detected as Agent in a group he has no access to
  73. # https://github.com/zammad/zammad/issues/4649
  74. context 'when user is agent-customer' do
  75. let(:user) { ticket.customer }
  76. it 'ensures sender is set to customer' do
  77. expect(article.sender.name).to eq 'Agent'
  78. end
  79. end
  80. end
  81. describe 'processing for customer' do
  82. context 'when user is customer' do
  83. let(:user) { ticket.customer }
  84. let(:ticket) { create(:ticket, customer: create(:customer)) }
  85. it 'ensures internal is false' do
  86. payload[:internal] = true
  87. expect(article.internal).to be_falsey
  88. end
  89. it 'changes type from web to note' do
  90. payload[:type] = 'phone'
  91. expect(article.type.name).to eq('note')
  92. end
  93. end
  94. # Agent-Customer is incorrectly detected as Agent in a group he has no access to
  95. # https://github.com/zammad/zammad/issues/4649
  96. context 'when user is agent-customer' do
  97. let(:user) { ticket.customer }
  98. it 'ensures internal is false' do
  99. payload[:internal] = false
  100. expect(article.internal).to be_falsey
  101. end
  102. it 'changes type from web to note' do
  103. payload[:type] = 'phone'
  104. expect(article.type.name).to eq('phone')
  105. end
  106. end
  107. context 'when user is agent' do
  108. it 'allows internal to be true' do
  109. payload[:internal] = true
  110. expect(article.internal).to be_truthy
  111. end
  112. it 'applies no changes to type' do
  113. payload[:type] = 'phone'
  114. expect(article.type.name).to eq('phone')
  115. end
  116. end
  117. end
  118. describe 'transforming attachments' do
  119. it 'adds attachments with inlines' do
  120. payload[:content_type] = 'text/html'
  121. payload[:body] = 'some body <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
  122. AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
  123. 9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" />'
  124. expect(article.attachments).to be_one
  125. end
  126. context 'when attachment is uploaded' do
  127. let(:form_id) { SecureRandom.uuid }
  128. let(:taskbar) { create(:taskbar, user_id: user.id, state: { form_id: }) }
  129. before do
  130. taskbar
  131. file_name = 'file1.png'
  132. file_type = 'image/png'
  133. file_content = Base64.strict_encode64('file1')
  134. UploadCache.new(form_id).tap do |cache|
  135. cache.add(
  136. data: file_content,
  137. filename: file_name,
  138. preferences: { 'Content-Type' => file_type },
  139. created_by_id: 1,
  140. )
  141. end
  142. end
  143. it 'adds attachments with inlines and updates taskbar state', aggregate_failures: true do
  144. payload[:content_type] = 'text/html'
  145. payload[:attachments] = {
  146. files: [],
  147. form_id:,
  148. }
  149. payload[:body] = "some body <img src='/api/v1/attachments/#{Store.last.id}'> alt='Red dot' />"
  150. expect(article.attachments).to be_one
  151. expect(taskbar.reload.state).to eq({})
  152. end
  153. end
  154. end
  155. describe 'mentions', aggregate_failures: true do
  156. def text_blob_with(user)
  157. "Lorem ipsum dolor <a data-mention-user-id='#{user.id}'>#{user.fullname}</a>"
  158. end
  159. let(:payload) { { body: body } }
  160. context 'when author can mention other users' do
  161. context 'when valid user is mentioned' do
  162. let(:body) { text_blob_with(user) }
  163. it 'create ticket with mentions' do
  164. expect { article }.to change(Mention, :count).by(1)
  165. end
  166. end
  167. context 'when user without access to the ticket is mentioned' do
  168. let(:body) { text_blob_with(create(:agent)) }
  169. it 'raises an error with one of mentions being invalid' do
  170. expect { article }
  171. .to raise_error(ActiveRecord::RecordInvalid)
  172. expect(Mention.count).to eq(0)
  173. end
  174. end
  175. end
  176. context 'when author does not have permissions to create mentions' do
  177. let(:user) { create(:customer) }
  178. let(:body) { text_blob_with(create(:agent, groups: [ticket.group])) }
  179. it 'raise an error if author does not have permissions to create mentions' do
  180. expect { article }
  181. .to raise_error(Pundit::NotAuthorizedError)
  182. expect(Mention.count).to eq(0)
  183. end
  184. end
  185. end
  186. end
  187. end