123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- require 'rails_helper'
- RSpec.describe Gql::Mutations::Ticket::Update, :aggregate_failures, type: :graphql do
- let(:query) do
- <<~QUERY
- mutation ticketUpdate($ticketId: ID!, $input: TicketUpdateInput!, $meta: TicketUpdateMetaInput) {
- ticketUpdate(ticketId: $ticketId, input: $input, meta: $meta) {
- ticket {
- id
- title
- group {
- name
- }
- priority {
- name
- }
- customer {
- fullname
- }
- owner {
- fullname
- }
- objectAttributeValues {
- attribute {
- name
- }
- value
- }
- }
- errors {
- message
- field
- exception
- }
- }
- }
- QUERY
- end
- let(:agent) { create(:agent, groups: [ Group.find_by(name: 'Users')]) }
- let(:customer) { create(:customer) }
- let(:user) { agent }
- let(:group) { agent.groups.first }
- let(:priority) { Ticket::Priority.last }
- let(:ticket) { create(:ticket, group: agent.groups.first, customer: customer) }
- let(:article_payload) { nil }
- let(:input_base_payload) do
- {
- title: 'Ticket Create Mutation Test',
- groupId: gql.id(group),
- priorityId: gql.id(priority),
- customer: { id: gql.id(customer) },
- ownerId: gql.id(agent),
- article: article_payload
- # pending_time: 10.minutes.from_now,
- # type: ...
- }
- end
- let(:input_payload) { input_base_payload }
- let(:variables) { { ticketId: gql.id(ticket), input: input_payload } }
- let(:expected_base_response) do
- {
- 'id' => gql.id(Ticket.last),
- 'title' => 'Ticket Create Mutation Test',
- 'owner' => { 'fullname' => agent.fullname },
- 'group' => { 'name' => agent.groups.first.name },
- 'customer' => { 'fullname' => customer.fullname },
- 'priority' => { 'name' => Ticket::Priority.last.name },
- 'objectAttributeValues' => [],
- }
- end
- let(:expected_response) do
- expected_base_response
- end
- context 'when updating a ticket' do
- context 'with an agent', authenticated_as: :agent do
- it 'updates the attributes' do
- gql.execute(query, variables: variables)
- expect(gql.result.data[:ticket]).to eq(expected_response)
- end
- context 'without title' do
- let(:input_payload) { input_base_payload.tap { |h| h[:title] = ' ' } }
- it 'fails validation' do
- gql.execute(query, variables: variables)
- expect(gql.result.error_message).to include('Variable $input of type TicketUpdateInput! was provided invalid value for title')
- end
- end
- context 'with an article payload' do
- let(:article_payload) do
- {
- body: 'dummy',
- type: 'note',
- }
- end
- it 'adds a new article with a specific type' do
- expect { gql.execute(query, variables: variables) }
- .to change(Ticket::Article, :count).by(1)
- expect(Ticket.last.articles.last.type.name).to eq('note')
- end
- it 'adds a new article with a specific sender' do
- expect { gql.execute(query, variables: variables) }
- .to change(Ticket::Article, :count).by(1)
- expect(Ticket.last.articles.last.sender.name).to eq('Agent')
- end
- context 'with macro' do
- let(:new_title) { Faker::Lorem.word }
- let(:macro) { create(:macro, perform: { 'ticket.title' => { 'value' => new_title } }) }
- let(:variables) do
- {
- ticketId: gql.id(ticket),
- input: input_payload,
- meta: {
- macroId: gql.id(macro)
- }
- }
- end
- it 'adds a new article with time unit' do
- gql.execute(query, variables:)
- expect(ticket.reload).to have_attributes(title: new_title)
- end
- end
- context 'with time unit' do
- let(:time_accounting_enabled) { true }
- let(:exception) { Gql::Types::Enum::BaseEnum.graphql_compatible_name('Service::Ticket::Update::Validator::TimeAccounting::Error') }
- let(:accounted_time_type) { create(:ticket_time_accounting_type) }
- let(:variables) do
- {
- ticketId: gql.id(ticket),
- input: input_payload,
- meta: {
- skipValidators: [exception],
- },
- }
- end
- let(:article_payload) do
- {
- body: 'dummy',
- type: 'web',
- timeUnit: 123,
- accountedTimeTypeId: gql.id(accounted_time_type),
- }
- end
- before do
- Setting.set('time_accounting', time_accounting_enabled)
- end
- it 'adds a new article with time unit' do
- expect { gql.execute(query, variables: variables) }
- .to change(Ticket::Article, :count).by(1)
- expect(Ticket.last.articles.last.ticket_time_accounting.time_unit).to eq(123)
- expect(Ticket.last.articles.last.ticket_time_accounting.type).to eq(accounted_time_type)
- end
- context 'when time accounting disabled' do
- let(:time_accounting_enabled) { false }
- it 'does not create ticket article' do
- expect { gql.execute(query, variables: variables) }
- .not_to change(Ticket::Article, :count)
- expect(gql.result.error_message)
- .to match('Time Accounting is not enabled')
- end
- end
- end
- context 'with active secure mailing (S/MIME)' do
- before do
- Setting.set('smime_integration', true)
- end
- it 'adds a new article' do
- expect { gql.execute(query, variables: variables) }
- .to change(Ticket::Article, :count).by(1)
- expect(Ticket.last.articles.last.type.name).to eq('note')
- end
- end
- end
- context 'with custom object_attribute', db_strategy: :reset do
- let(:object_attribute) do
- screens = { create: { 'admin.organization': { shown: true, required: false } } }
- create(:object_manager_attribute_text, object_name: 'Ticket', screens: screens).tap do |_oa|
- ObjectManager::Attribute.migration_execute
- end
- end
- let(:input_payload) do
- input_base_payload.merge(
- {
- objectAttributeValues: [ { name: object_attribute.name, value: 'object_attribute_value' } ]
- }
- )
- end
- let(:expected_response) do
- expected_base_response.merge(
- {
- 'objectAttributeValues' => [{ 'attribute' => { 'name'=>object_attribute.name }, 'value' => 'object_attribute_value' }]
- }
- )
- end
- it 'updates the attributes' do
- gql.execute(query, variables: variables)
- expect(gql.result.data[:ticket]).to eq(expected_response)
- end
- end
- context 'when moving the ticket into a group with only :change permission' do
- let(:group) { create(:group) }
- before do
- user.groups << group
- user.group_names_access_map = { user.groups.first.name => %w[read change], group.name => ['change'] }
- end
- it 'updates the ticket, but returns an error trying to access the new ticket' do
- gql.execute(query, variables: variables)
- expect(ticket.reload.group_id).to eq(group.id)
- expect(gql.result.payload['data']['ticketUpdate']).to eq({ 'ticket' => nil, 'errors' => nil }) # Mutation did run, but data retrieval was not authorized.
- expect(gql.result.payload['errors'].first['message']).to eq('Access forbidden by Gql::Types::TicketType')
- expect(gql.result.payload['errors'].first['extensions']['type']).to eq('Exceptions::Forbidden')
- end
- end
- context 'with no permission to the group' do
- let(:group) { create(:group) }
- it 'raises an error', :aggregate_failures do
- gql.execute(query, variables: variables)
- expect(gql.result.error_type).to eq(Exceptions::Forbidden)
- expect(gql.result.error_message).to eq('Access forbidden by Gql::Types::GroupType')
- end
- end
- context 'when ticket has a checklist and is being closed', current_user_id: 1 do
- let(:checklist) { create(:checklist, ticket: ticket) }
- let(:exception) { Gql::Types::Enum::BaseEnum.graphql_compatible_name('Service::Ticket::Update::Validator::ChecklistCompleted::Error') }
- let(:input_base_payload) do
- {
- title: 'Ticket Create Mutation Test',
- groupId: gql.id(group),
- priorityId: gql.id(priority),
- customer: { id: gql.id(customer) },
- ownerId: gql.id(agent),
- article: article_payload,
- stateId: gql.id(Ticket::State.find_by(name: 'closed')),
- }
- end
- before do
- checklist
- gql.execute(query, variables: variables)
- end
- it 'returns a user error' do
- expect(gql.result.data).to eq({
- 'ticket' => nil,
- 'errors' => [
- 'message' => 'The ticket checklist is incomplete.',
- 'field' => nil,
- 'exception' => exception,
- ],
- })
- end
- context 'when validator is being skipped' do
- let(:variables) do
- {
- ticketId: gql.id(ticket),
- input: input_payload,
- meta: {
- skipValidators: [exception],
- },
- }
- end
- it 'updates the ticket' do
- expect(gql.result.data[:ticket]).to eq(expected_response)
- end
- end
- end
- end
- context 'with a customer', authenticated_as: :customer do
- let(:input_payload) { input_base_payload.tap { |h| h.delete(:customer) } }
- let(:expected_response) do
- expected_base_response.merge(
- {
- 'owner' => { 'fullname' => nil },
- 'priority' => { 'name' => Ticket::Priority.where(default_create: true).first.name },
- }
- )
- end
- it 'updates the ticket with filtered values' do
- gql.execute(query, variables: variables)
- expect(gql.result.data[:ticket]).to eq(expected_response)
- end
- context 'when sending a different customerId' do
- let(:input_payload) { input_base_payload.tap { |h| h[:customer][:id] = gql.id(create(:customer)) } }
- it 'fails creating a ticket with permission exception' do
- gql.execute(query, variables: variables)
- expect(gql.result.error_type).to eq(Exceptions::Forbidden)
- expect(gql.result.error_message).to eq('Access forbidden by Gql::Types::UserType')
- end
- end
- context 'with an article payload' do
- let(:article_payload) do
- {
- body: 'dummy',
- type: 'web',
- }
- end
- it 'adds a new article with a specific type' do
- expect { gql.execute(query, variables: variables) }
- .to change(Ticket::Article, :count).by(1)
- expect(Ticket.last.articles.last.type.name).to eq('web')
- end
- it 'adds a new article with a specific sender' do
- expect { gql.execute(query, variables: variables) }
- .to change(Ticket::Article, :count).by(1)
- expect(Ticket.last.articles.last.sender.name).to eq('Customer')
- end
- end
- end
- end
- end
|