1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117 |
- require 'rails_helper'
- RSpec.describe 'Ticket zoom', type: :system do
- describe 'owner auto-assignment', authenticated_as: :authenticate do
- let!(:ticket) { create(:ticket, group: Group.find_by(name: 'Users'), state: Ticket::State.find_by(name: 'new')) }
- let!(:session_user) { User.find_by(login: 'master@example.com') }
- context 'for agent disabled' do
- def authenticate
- Setting.set('ticket_auto_assignment', false)
- Setting.set('ticket_auto_assignment_selector', { condition: { 'ticket.state_id' => { operator: 'is', value: Ticket::State.by_category(:work_on).pluck(:id) } } })
- Setting.set('ticket_auto_assignment_user_ids_ignore', [])
- true
- end
- it 'do not assign ticket to current session user' do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- expect(page).to have_css('select[name=owner_id]')
- expect(page).to have_select('owner_id',
- selected: '-',
- options: ['-', 'Agent 1 Test', 'Test Master Agent'])
- end
- end
- end
- context 'for agent enabled' do
- def authenticate
- Setting.set('ticket_auto_assignment', true)
- Setting.set('ticket_auto_assignment_selector', { condition: { 'ticket.state_id' => { operator: 'is', value: Ticket::State.by_category(:work_on).pluck(:id) } } })
- Setting.set('ticket_auto_assignment_user_ids_ignore', setting_user_ids_ignore) if defined?(setting_user_ids_ignore)
- true
- end
- context 'with empty "ticket_auto_assignment_user_ids_ignore"' do
- it 'assigns ticket to current session user' do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- expect(page).to have_css('.content.active select[name=owner_id]')
- expect(page).to have_select('owner_id',
- selected: session_user.fullname,
- options: ['-', 'Agent 1 Test', 'Test Master Agent'])
- end
- end
- end
- context 'with "ticket_auto_assignment_user_ids_ignore" (as integer)' do
- let(:setting_user_ids_ignore) { session_user.id }
- it 'assigns ticket not to current session user' do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- expect(page).to have_css('select[name=owner_id]')
- expect(page).to have_select('owner_id',
- selected: '-',
- options: ['-', 'Agent 1 Test', 'Test Master Agent'])
- end
- end
- end
- context 'with "ticket_auto_assignment_user_ids_ignore" (as string)' do
- let(:setting_user_ids_ignore) { session_user.id.to_s }
- it 'assigns ticket not to current session user' do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- expect(page).to have_css('select[name=owner_id]')
- expect(page).to have_select('owner_id',
- selected: '-',
- options: ['-', 'Agent 1 Test', 'Test Master Agent'])
- end
- end
- end
- context 'with "ticket_auto_assignment_user_ids_ignore" (as [integer])' do
- let(:setting_user_ids_ignore) { [session_user.id] }
- it 'assigns ticket not to current session user' do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- expect(page).to have_css('select[name=owner_id]')
- expect(page).to have_select('owner_id',
- selected: '-',
- options: ['-', 'Agent 1 Test', 'Test Master Agent'])
- end
- end
- end
- context 'with "ticket_auto_assignment_user_ids_ignore" (as [string])' do
- let(:setting_user_ids_ignore) { [session_user.id.to_s] }
- it 'assigns ticket not to current session user' do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- expect(page).to have_css('select[name=owner_id]')
- expect(page).to have_select('owner_id',
- selected: '-',
- options: ['-', 'Agent 1 Test', 'Test Master Agent'])
- end
- end
- end
- context 'with "ticket_auto_assignment_user_ids_ignore" and other user ids' do
- let(:setting_user_ids_ignore) { [99_999, 999_999] }
- it 'assigns ticket to current session user' do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- expect(page).to have_css('select[name=owner_id]')
- expect(page).to have_select('owner_id',
- selected: session_user.fullname,
- options: ['-', 'Agent 1 Test', 'Test Master Agent'])
- end
- end
- end
- end
- end
- context 'when ticket has an attachment' do
- let(:group) { Group.find_by(name: 'Users') }
- let(:ticket) { create(:ticket, group: group) }
- let(:article) { create(:ticket_article, ticket: ticket) }
- let(:attachment_name) { 'some_file.txt' }
- before do
- Store.add(
- object: 'Ticket::Article',
- o_id: article.id,
- data: 'some content',
- filename: attachment_name,
- preferences: {
- 'Content-Type' => 'text/plain',
- },
- created_by_id: 1,
- )
- end
- context 'article was already forwarded once' do
- before do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- find('a[data-type=emailForward]').click
- click('.js-reset')
- have_no_css('.js-reset')
- end
- end
- it 'adds attachments when forwarding multiple times' do
- within(:active_content) do
- find('a[data-type=emailForward]').click
- end
- within('.js-writeArea') do
- expect(page).to have_text attachment_name
- end
- end
- end
- end
- context 'replying' do
- context 'Group without signature' do
- let(:ticket) { create(:ticket) }
- let(:current_user) { create(:agent, password: 'test', groups: [ticket.group]) }
- before do
- # initial article to reply to
- create(:ticket_article, ticket: ticket)
- end
- it 'ensures that text input opens on multiple replies', authenticated_as: :current_user do
- visit "ticket/zoom/#{ticket.id}"
- 2.times do |article_offset|
- articles_existing = 1
- articles_expected = articles_existing + (article_offset + 1)
- all('a[data-type=emailReply]').last.click
- # wait till input box expands completely
- find('.attachmentPlaceholder-label').in_fixed_position
- expect(page).to have_no_css('.attachmentPlaceholder-hint')
- find('.articleNewEdit-body').send_keys('Some reply')
- click '.js-submit'
- expect(page).to have_css('.ticket-article-item', count: articles_expected)
- end
- end
- end
- context 'to inbound phone call', current_user_id: -> { agent.id }, authenticated_as: -> { agent } do
- let(:agent) { create(:agent, groups: [Group.first]) }
- let(:customer) { create(:agent) }
- let(:ticket) { create(:ticket, customer: customer, group: agent.groups.first) }
- let!(:article) { create(:ticket_article, :inbound_phone, ticket: ticket) }
- it 'goes to customer email' do
- visit "ticket/zoom/#{ticket.id}"
- within :active_ticket_article, article do
- click '.js-ArticleAction[data-type=emailReply]'
- end
- within :active_content do
- within '.article-new' do
- expect(find('[name=to]', visible: :all).value).to eq customer.email
- end
- end
- end
- end
- context 'to outbound phone call', current_user_id: -> { agent.id }, authenticated_as: -> { agent } do
- let(:agent) { create(:agent, groups: [Group.first]) }
- let(:customer) { create(:agent) }
- let(:ticket) { create(:ticket, customer: customer, group: agent.groups.first) }
- let!(:article) { create(:ticket_article, :outbound_phone, ticket: ticket) }
- it 'goes to customer email' do
- visit "ticket/zoom/#{ticket.id}"
- within :active_ticket_article, article do
- click '.js-ArticleAction[data-type=emailReply]'
- end
- within :active_content do
- within '.article-new' do
- expect(find('[name=to]', visible: :all).value).to eq customer.email
- end
- end
- end
- end
- end
- describe 'delete article', authenticated_as: :authenticate do
- let(:group) { Group.first }
- let(:admin) { create :admin, groups: [group] }
- let(:agent) { create :agent, groups: [group] }
- let(:other_agent) { create :agent, groups: [group] }
- let(:customer) { create :customer }
- let(:article) { send(item) }
- def authenticate
- Setting.set('ui_ticket_zoom_article_delete_timeframe', setting_delete_timeframe) if defined?(setting_delete_timeframe)
- article
- user
- end
- def article_communication
- create_ticket_article(sender_name: 'Agent', internal: false, type_name: 'email', updated_by: customer)
- end
- def article_note_self
- create_ticket_article(sender_name: 'Agent', internal: true, type_name: 'note', updated_by: user)
- end
- def article_note_other
- create_ticket_article(sender_name: 'Agent', internal: true, type_name: 'note', updated_by: other_agent)
- end
- def article_note_customer
- create_ticket_article(sender_name: 'Customer', internal: false, type_name: 'note', updated_by: customer)
- end
- def article_note_communication_self
- create(:ticket_article_type, name: 'note_communication', communication: true)
- create_ticket_article(sender_name: 'Agent', internal: true, type_name: 'note_communication', updated_by: user)
- end
- def article_note_communication_other
- create(:ticket_article_type, name: 'note_communication', communication: true)
- create_ticket_article(sender_name: 'Agent', internal: true, type_name: 'note_communication', updated_by: other_agent)
- end
- def create_ticket_article(sender_name:, internal:, type_name:, updated_by:)
- UserInfo.current_user_id = updated_by.id
- ticket = create :ticket, group: group, customer: customer
- create(:ticket_article,
- sender_name: sender_name, internal: internal, type_name: type_name, ticket: ticket,
- body: "to be deleted #{offset} #{item}",
- created_at: offset.ago, updated_at: offset.ago)
- end
- context 'going through full stack' do
- context 'as admin' do
- let(:user) { admin }
- let(:item) { 'article_note_self' }
- let(:offset) { 0.minutes }
- it 'succeeds' do
- ensure_websocket do
- visit "ticket/zoom/#{article.ticket.id}"
- end
- within :active_ticket_article, article do
- click '.js-ArticleAction[data-type=delete]'
- end
- in_modal do
- click '.js-submit'
- end
- wait.until_disappears { find :active_ticket_article, article, wait: false }
- end
- end
- end
- context 'verifying permissions matrix' do
- shared_examples 'according to permission matrix' do |item:, expects_visible:, offset:, description:|
- context "looking at #{description} #{item}" do
- let(:item) { item }
- let(:offset) { offset }
- let(:matcher) { expects_visible ? :have_css : :have_no_css }
- it expects_visible ? 'delete button is visible' : 'delete button is not visible' do
- visit "ticket/zoom/#{article.ticket.id}"
- within :active_ticket_article, article do
- expect(page).to send(matcher, '.js-ArticleAction[data-type=delete]', wait: 0)
- end
- end
- end
- end
- shared_examples 'deleting ticket article' do |item:, now:, later:, much_later:|
- include_examples 'according to permission matrix', item: item, expects_visible: now, offset: 0.minutes, description: 'just created'
- include_examples 'according to permission matrix', item: item, expects_visible: later, offset: 6.minutes, description: 'few minutes old'
- include_examples 'according to permission matrix', item: item, expects_visible: much_later, offset: 11.minutes, description: 'very old'
- end
- context 'as admin' do
- let(:user) { admin }
- include_examples 'deleting ticket article',
- item: 'article_communication',
- now: false, later: false, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_self',
- now: true, later: true, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_other',
- now: false, later: false, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_customer',
- now: false, later: false, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_communication_self',
- now: false, later: false, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_communication_other',
- now: false, later: false, much_later: false
- end
- context 'as agent' do
- let(:user) { agent }
- include_examples 'deleting ticket article',
- item: 'article_communication',
- now: false, later: false, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_self',
- now: true, later: true, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_other',
- now: false, later: false, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_customer',
- now: false, later: false, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_communication_self',
- now: false, later: false, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_communication_other',
- now: false, later: false, much_later: false
- end
- context 'as customer' do
- let(:user) { customer }
- include_examples 'deleting ticket article',
- item: 'article_communication',
- now: false, later: false, much_later: false
- include_examples 'deleting ticket article',
- item: 'article_note_customer',
- now: false, later: false, much_later: false
- end
- context 'with custom offset' do
- let(:setting_delete_timeframe) { 6_000 }
- context 'as admin' do
- let(:user) { admin }
- include_examples 'according to permission matrix', item: 'article_note_self', expects_visible: true, offset: 5000.seconds, description: 'outside of delete timeframe'
- include_examples 'according to permission matrix', item: 'article_note_self', expects_visible: false, offset: 8000.seconds, description: 'outside of delete timeframe'
- end
- context 'as agent' do
- let(:user) { agent }
- include_examples 'according to permission matrix', item: 'article_note_self', expects_visible: true, offset: 5000.seconds, description: 'outside of delete timeframe'
- include_examples 'according to permission matrix', item: 'article_note_self', expects_visible: false, offset: 8000.seconds, description: 'outside of delete timeframe'
- end
- end
- context 'with timeframe as 0' do
- let(:setting_delete_timeframe) { 0 }
- context 'as agent' do
- let(:user) { agent }
- include_examples 'according to permission matrix', item: 'article_note_self', expects_visible: true, offset: 99.days, description: 'long after'
- end
- end
- end
- context 'button is hidden on the go' do
- let(:setting_delete_timeframe) { 5 }
- let(:user) { agent }
- let(:item) { 'article_note_self' }
- let!(:article) { send(item) }
- let(:offset) { 0.seconds }
- it 'successfully' do
- visit "ticket/zoom/#{article.ticket.id}"
- within :active_ticket_article, article do
- find '.js-ArticleAction[data-type=delete]' # make sure delete button did show up
- expect(page).to have_no_css('.js-ArticleAction[data-type=delete]')
- end
- end
- end
- end
- context 'S/MIME active', authenticated_as: :authenticate do
- let(:system_email_address) { 'smime1@example.com' }
- let(:email_address) { create(:email_address, email: system_email_address) }
- let(:group) { create(:group, email_address: email_address) }
- let(:agent_groups) { [group] }
- let(:agent) { create(:agent, groups: agent_groups) }
- let(:sender_email_address) { 'smime2@example.com' }
- let(:customer) { create(:customer, email: sender_email_address) }
- let!(:ticket) { create(:ticket, group: group, owner: agent, customer: customer) }
- def authenticate
- Setting.set('smime_integration', true)
- agent
- end
- context 'received mail' do
- context 'article meta information' do
- context 'success' do
- it 'shows encryption/sign information' do
- create(:ticket_article, preferences: {
- security: {
- type: 'S/MIME',
- encryption: {
- success: true,
- comment: 'COMMENT_ENCRYPT_SUCCESS',
- },
- sign: {
- success: true,
- comment: 'COMMENT_SIGN_SUCCESS',
- },
- }
- }, ticket: ticket)
- visit "#ticket/zoom/#{ticket.id}"
- expect(page).to have_css('svg.icon-lock')
- expect(page).to have_css('svg.icon-signed')
- open_article_meta
- expect(page).to have_css('span', text: 'Encrypted')
- expect(page).to have_css('span', text: 'Signed')
- expect(page).to have_css('span[title=COMMENT_ENCRYPT_SUCCESS]')
- expect(page).to have_css('span[title=COMMENT_SIGN_SUCCESS]')
- end
- end
- context 'error' do
- it 'shows create information about encryption/sign failed' do
- create(:ticket_article, preferences: {
- security: {
- type: 'S/MIME',
- encryption: {
- success: false,
- comment: 'Encryption failed because XXX',
- },
- sign: {
- success: false,
- comment: 'Sign failed because XXX',
- },
- }
- }, ticket: ticket)
- visit "#ticket/zoom/#{ticket.id}"
- expect(page).to have_css('svg.icon-not-signed')
- open_article_meta
- expect(page).to have_css('div.alert.alert--warning', text: 'Encryption failed because XXX')
- expect(page).to have_css('div.alert.alert--warning', text: 'Sign failed because XXX')
- end
- end
- end
- context 'certificate not present at time of arrival' do
- it 'retry' do
- smime1 = create(:smime_certificate, :with_private, fixture: system_email_address)
- smime2 = create(:smime_certificate, :with_private, fixture: sender_email_address)
- mail = Channel::EmailBuild.build(
- from: sender_email_address,
- to: system_email_address,
- body: 'somebody with some text',
- content_type: 'text/plain',
- security: {
- type: 'S/MIME',
- sign: {
- success: true,
- },
- encryption: {
- success: true,
- },
- },
- )
- smime1.destroy
- smime2.destroy
- parsed_mail = Channel::EmailParser.new.parse(mail.to_s)
- ticket, article, _user, _mail = Channel::EmailParser.new.process({ group_id: group.id }, parsed_mail['raw'])
- expect(Ticket::Article.find(article.id).body).to eq('no visible content')
- create(:smime_certificate, fixture: sender_email_address)
- create(:smime_certificate, :with_private, fixture: system_email_address)
- visit "#ticket/zoom/#{ticket.id}"
- expect(page).to have_no_css('.article-content', text: 'somebody with some text')
- click '.js-securityRetryProcess'
- expect(page).to have_css('.article-content', text: 'somebody with some text')
- end
- end
- end
- context 'replying', authenticated_as: :setup_and_authenticate do
- def setup_and_authenticate
- create(:ticket_article, ticket: ticket, from: customer.email)
- create(:smime_certificate, :with_private, fixture: system_email_address)
- create(:smime_certificate, fixture: sender_email_address)
- authenticate
- end
- it 'plain' do
- visit "#ticket/zoom/#{ticket.id}"
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- expect(page).to have_css('.js-securityEncrypt.btn--active', wait: 5)
- expect(page).to have_css('.js-securitySign.btn--active', wait: 5)
- click '.js-securityEncrypt'
- click '.js-securitySign'
- click '.js-submit'
- expect(page).to have_css('.ticket-article-item', count: 2)
- expect(Ticket::Article.last.preferences['security']['encryption']['success']).to be nil
- expect(Ticket::Article.last.preferences['security']['sign']['success']).to be nil
- end
- it 'signed' do
- visit "#ticket/zoom/#{ticket.id}"
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- expect(page).to have_css('.js-securityEncrypt.btn--active', wait: 5)
- expect(page).to have_css('.js-securitySign.btn--active', wait: 5)
- click '.js-securityEncrypt'
- click '.js-submit'
- expect(page).to have_css('.ticket-article-item', count: 2)
- expect(Ticket::Article.last.preferences['security']['encryption']['success']).to be nil
- expect(Ticket::Article.last.preferences['security']['sign']['success']).to be true
- end
- it 'encrypted' do
- visit "#ticket/zoom/#{ticket.id}"
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- expect(page).to have_css('.js-securityEncrypt.btn--active', wait: 5)
- expect(page).to have_css('.js-securitySign.btn--active', wait: 5)
- click '.js-securitySign'
- click '.js-submit'
- expect(page).to have_css('.ticket-article-item', count: 2)
- expect(Ticket::Article.last.preferences['security']['encryption']['success']).to be true
- expect(Ticket::Article.last.preferences['security']['sign']['success']).to be nil
- end
- it 'signed and encrypted' do
- visit "#ticket/zoom/#{ticket.id}"
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- expect(page).to have_css('.js-securityEncrypt.btn--active', wait: 5)
- expect(page).to have_css('.js-securitySign.btn--active', wait: 5)
- click '.js-submit'
- expect(page).to have_css('.ticket-article-item', count: 2)
- expect(Ticket::Article.last.preferences['security']['encryption']['success']).to be true
- expect(Ticket::Article.last.preferences['security']['sign']['success']).to be true
- end
- end
- context 'Group default behavior' do
- let(:smime_config) { {} }
- def authenticate
- Setting.set('smime_integration', true)
- Setting.set('smime_config', smime_config)
- create(:ticket_article, ticket: ticket, from: customer.email)
- create(:smime_certificate, :with_private, fixture: system_email_address)
- create(:smime_certificate, fixture: sender_email_address)
- agent
- end
- shared_examples 'security defaults example' do |sign:, encrypt:|
- it "security defaults sign: #{sign}, encrypt: #{encrypt}" do
- within(:active_content) do
- encrypt_button = find('.js-securityEncrypt', wait: 5)
- sign_button = find('.js-securitySign', wait: 5)
- await_empty_ajax_queue
- active_button_class = '.btn--active'
- expect(encrypt_button.matches_css?(active_button_class, wait: 2)).to be(encrypt)
- expect(sign_button.matches_css?(active_button_class, wait: 2)).to be(sign)
- end
- end
- end
- shared_examples 'security defaults' do |sign:, encrypt:|
- before do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- await_empty_ajax_queue
- end
- end
- include_examples 'security defaults example', sign: sign, encrypt: encrypt
- end
- shared_examples 'security defaults group change' do |sign:, encrypt:|
- before do
- visit "#ticket/zoom/#{ticket.id}"
- within(:active_content) do
- all('a[data-type=emailReply]').last.click
- find('.articleNewEdit-body').send_keys('Test')
- await_empty_ajax_queue
- select new_group.name, from: 'group_id'
- end
- end
- include_examples 'security defaults example', sign: sign, encrypt: encrypt
- end
- context 'not configured' do
- it_behaves_like 'security defaults', sign: true, encrypt: true
- end
- context 'configuration present' do
- let(:smime_config) do
- {
- 'group_id' => group_defaults
- }
- end
- let(:group_defaults) do
- {
- 'default_encryption' => {
- group.id.to_s => default_encryption,
- },
- 'default_sign' => {
- group.id.to_s => default_sign,
- }
- }
- end
- let(:default_sign) { true }
- let(:default_encryption) { true }
- shared_examples 'sign and encrypt variations' do |check_examples_name|
- it_behaves_like check_examples_name, sign: true, encrypt: true
- context 'no value' do
- let(:group_defaults) { {} }
- it_behaves_like check_examples_name, sign: true, encrypt: true
- end
- context 'signing disabled' do
- let(:default_sign) { false }
- it_behaves_like check_examples_name, sign: false, encrypt: true
- end
- context 'encryption disabled' do
- let(:default_encryption) { false }
- it_behaves_like check_examples_name, sign: true, encrypt: false
- end
- end
- context 'same Group' do
- it_behaves_like 'sign and encrypt variations', 'security defaults'
- end
- context 'Group change' do
- let(:new_group) { create(:group, email_address: email_address) }
- let(:agent_groups) { [group, new_group] }
- let(:group_defaults) do
- {
- 'default_encryption' => {
- new_group.id.to_s => default_encryption,
- },
- 'default_sign' => {
- new_group.id.to_s => default_sign,
- }
- }
- end
- it_behaves_like 'sign and encrypt variations', 'security defaults group change'
- end
- end
- end
- end
- describe 'linking Knowledge Base answer' do
- include_context 'basic Knowledge Base'
- let(:ticket) { create :ticket, group: Group.find_by(name: 'Users') }
- let(:answer) { published_answer }
- let(:translation) { answer.translations.first }
- shared_examples 'verify linking' do
- it 'allows to look up an answer' do
- visit "#ticket/zoom/#{ticket.id}"
- within :active_content do
- within '.link_kb_answers' do
- find('.js-add').click
- find('.js-input').send_keys translation.title
- find(%(li[data-value="#{translation.id}"])).click
- expect(find('.link_kb_answers ol')).to have_text translation.title
- end
- end
- end
- end
- context 'with ES', searchindex: true, authenticated_as: :authenticate do
- def authenticate
- configure_elasticsearch(required: true, rebuild: true) do
- answer
- end
- true
- end
- include_examples 'verify linking'
- end
- context 'without ES', authenticated_as: :authenticate do
- def authenticate
- answer
- true
- end
- include_examples 'verify linking'
- end
- end
- describe 'forwarding article with an image' do
- let(:ticket_article_body) do
- filename = 'squares.png'
- file = File.binread(Rails.root.join("spec/fixtures/image/#{filename}"))
- ext = File.extname(filename)[1...]
- base64 = Base64.encode64(file).delete("\n")
- "<img style='width: 1004px; max-width: 100%;' src=\\\"data:image/#{ext};base64,#{base64}\\\"><br>"
- end
- def current_ticket
- Ticket.find current_url.split('/').last
- end
- def create_ticket
- visit '#ticket/create'
- within :active_content do
- find('[data-type=email-out]').click
- find('[name=title]').fill_in with: 'Title'
- find('[name=customer_id_completion]').fill_in with: 'customer@example.com'
- find('[name=group_id]').select 'Users'
- find(:richtext).execute_script "this.innerHTML = \"#{ticket_article_body}\""
- find('.js-submit').click
- end
- await_empty_ajax_queue
- end
- def forward
- within :active_content do
- click '.js-ArticleAction[data-type=emailForward]'
- fill_in 'To', with: 'customer@example.com'
- find('.js-submit').click
- end
- await_empty_ajax_queue
- end
- def images_identical?(image_a, image_b)
- return false if image_a.height != image_b.height
- return false if image_a.width != image_b.width
- image_a.height.times do |y|
- image_a.row(y).each_with_index do |pixel, x|
- return false if pixel != image_b[x, y]
- end
- end
- true
- end
- it 'keeps image intact' do
- create_ticket
- forward
- images = current_ticket.articles.map do |article|
- ChunkyPNG::Image.from_string article.attachments.first.content
- end
- expect(images_identical?(images.first, images.second)).to be(true)
- end
- end
- context 'object manager attribute permission view' do
- let!(:group_users) { Group.find_by(name: 'Users') }
- shared_examples 'shows attributes and values for agent view and editable' do
- it 'shows attributes and values for agent view and editable', authenticated_as: :current_user do
- visit "ticket/zoom/#{ticket.id}"
- refresh # refresh to have assets generated for ticket
- expect(page).to have_select('state_id', options: ['new', 'open', 'pending reminder', 'pending close', 'closed'])
- expect(page).to have_select('priority_id')
- expect(page).to have_select('owner_id')
- expect(page).to have_css('div.tabsSidebar-tab[data-tab=customer]')
- end
- end
- shared_examples 'shows attributes and values for agent view but disabled' do
- it 'shows attributes and values for agent view but disabled', authenticated_as: :current_user do
- visit "ticket/zoom/#{ticket.id}"
- refresh # refresh to have assets generated for ticket
- expect(page).to have_css('select[name=state_id][disabled]')
- expect(page).to have_css('select[name=priority_id][disabled]')
- expect(page).to have_css('select[name=owner_id][disabled]')
- expect(page).to have_css('div.tabsSidebar-tab[data-tab=customer]')
- end
- end
- shared_examples 'shows attributes and values for customer view' do
- it 'shows attributes and values for customer view', authenticated_as: :current_user do
- visit "ticket/zoom/#{ticket.id}"
- refresh # refresh to have assets generated for ticket
- expect(page).to have_select('state_id', options: %w[new open closed])
- expect(page).to have_no_select('priority_id')
- expect(page).to have_no_select('owner_id')
- expect(page).to have_no_css('div.tabsSidebar-tab[data-tab=customer]')
- end
- end
- context 'as customer' do
- let!(:current_user) { create(:customer) }
- let(:ticket) { create(:ticket, customer: current_user) }
- include_examples 'shows attributes and values for customer view'
- end
- context 'as agent with full permissions' do
- let(:current_user) { create(:agent, groups: [ group_users ] ) }
- let(:ticket) { create(:ticket, group: group_users ) }
- include_examples 'shows attributes and values for agent view and editable'
- end
- context 'as agent with change permissions' do
- let!(:current_user) { create(:agent) }
- let(:ticket) { create(:ticket, group: group_users) }
- before do
- current_user.group_names_access_map = {
- group_users.name => %w[read change],
- }
- end
- include_examples 'shows attributes and values for agent view and editable'
- end
- context 'as agent with read permissions' do
- let!(:current_user) { create(:agent) }
- let(:ticket) { create(:ticket, group: group_users) }
- before do
- current_user.group_names_access_map = {
- group_users.name => 'read',
- }
- end
- include_examples 'shows attributes and values for agent view but disabled'
- end
- context 'as agent+customer with full permissions' do
- let!(:current_user) { create(:agent_and_customer, groups: [ group_users ] ) }
- context 'normal ticket' do
- let(:ticket) { create(:ticket, group: group_users ) }
- include_examples 'shows attributes and values for agent view and editable'
- end
- context 'ticket where current_user is also customer' do
- let(:ticket) { create(:ticket, customer: current_user, group: group_users ) }
- include_examples 'shows attributes and values for agent view and editable'
- end
- end
- context 'as agent+customer with change permissions' do
- let!(:current_user) { create(:agent_and_customer) }
- before do
- current_user.group_names_access_map = {
- group_users.name => %w[read change],
- }
- end
- context 'normal ticket' do
- let(:ticket) { create(:ticket, group: group_users) }
- include_examples 'shows attributes and values for agent view and editable'
- end
- context 'ticket where current_user is also customer' do
- let(:ticket) { create(:ticket, customer: current_user, group: group_users) }
- include_examples 'shows attributes and values for agent view and editable'
- end
- end
- context 'as agent+customer with read permissions' do
- let!(:current_user) { create(:agent_and_customer) }
- before do
- current_user.group_names_access_map = {
- group_users.name => 'read',
- }
- end
- context 'normal ticket' do
- let(:ticket) { create(:ticket, group: group_users) }
- include_examples 'shows attributes and values for agent view but disabled'
- end
- context 'ticket where current_user is also customer' do
- let(:ticket) { create(:ticket, customer: current_user, group: group_users) }
- include_examples 'shows attributes and values for agent view but disabled'
- end
- end
- context 'as agent+customer but only customer for the ticket (no agent access)' do
- let!(:current_user) { create(:agent_and_customer) }
- let(:ticket) { create(:ticket, customer: current_user) }
- include_examples 'shows attributes and values for customer view'
- end
- end
- describe 'note visibility', authenticated_as: :customer do
- context 'when logged in as a customer' do
- let(:customer) { create(:customer) }
- let(:ticket) { create(:ticket, customer: customer) }
- let!(:ticket_article) { create(:ticket_article, ticket: ticket) }
- let!(:ticket_note) { create(:ticket_article, ticket: ticket, internal: true, type_name: 'note') }
- it 'previously created private note is not visible' do
- visit "ticket/zoom/#{ticket_article.ticket.id}"
- expect(page).to have_no_selector(:active_ticket_article, ticket_note)
- end
- it 'previously created private note shows up via WS push' do
- visit "ticket/zoom/#{ticket_article.ticket.id}"
- # make sure ticket is done loading and change will be pushed via WS
- find(:active_ticket_article, ticket_article)
- await_empty_ajax_queue
- ticket_note.update!(internal: false)
- expect(page).to have_selector(:active_ticket_article, ticket_note)
- end
- end
- end
- # https://github.com/zammad/zammad/issues/3260
- describe 'next in overview macro changes URL', authenticated_as: :authenticate do
- let(:ticket_a) { create(:ticket, title: 'ticket a', group: Group.first) }
- let(:macro) { create(:macro, name: 'next macro', ux_flow_next_up: 'next_from_overview') }
- def authenticate
- ticket_a && macro
- true
- end
- it 'works' do
- visit 'ticket/view/all_unassigned'
- click_on 'Welcome to Zammad!'
- click '.js-openDropdownMacro'
- expect { find(:element_containing, macro.name).click }.to change { current_url }
- end
- end
- end
|