Browse Source

Fixes #3022 - Detect ServiceNow follow-ups

Rolf Schmidt 4 years ago
parent
commit
afa6b9984a

+ 60 - 0
app/models/channel/filter/service_now_check.rb

@@ -0,0 +1,60 @@
+# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
+
+module Channel::Filter::ServiceNowCheck
+
+  # This filter will run pre and post
+  def self.run(_channel, mail, ticket = nil, _article = nil, _session_user = nil)
+    source_id = self.source_id(from: mail[:from], subject: mail[:subject])
+    return if source_id.blank?
+
+    # check if we can followup by existing service now relation
+    if ticket.blank?
+      sync_entry = ExternalSync.find_by(
+        source:    'ServiceNow',
+        source_id: source_id,
+        object:    'Ticket',
+      )
+      return if sync_entry.blank?
+
+      mail[ 'x-zammad-ticket-id'.to_sym ] = sync_entry.o_id
+      return
+    end
+
+    ExternalSync.create_with(source_id: source_id).find_or_create_by(source: 'ServiceNow', object: 'Ticket', o_id: ticket.id)
+  end
+
+=begin
+
+This function returns the source id of the service now email if given.
+
+  source_id = Channel::Filter::ServiceNowCheck.source_id(
+    from:    'test@servicnow.com',
+    subject: 'Incident INC12345 --- test',
+  )
+
+returns:
+
+  source_id = 'INC12345'
+
+=end
+
+  def self.source_id(from: '', subject: '')
+
+    # check if data is sent by service now
+    begin
+      return if Mail::AddressList.new(from).addresses.none? do |line|
+        line.address.end_with?('@service-now.com')
+      end
+    rescue
+      Rails.logger.info "Unable to parse email address in '#{from}'"
+    end
+
+    # check if we can find the service now relation
+    source_id = nil
+    if subject =~ /\s(INC\d+)\s/
+      source_id = $1
+    end
+
+    source_id
+  end
+end

+ 28 - 0
db/migrate/20200401000001_service_now_config.rb

@@ -0,0 +1,28 @@
+class ServiceNowConfig < ActiveRecord::Migration[4.2]
+  def up
+
+    # return if it's a new setup
+    return if !Setting.find_by(name: 'system_init_done')
+
+    Setting.create_if_not_exists(
+      title:       'Defines postmaster filter.',
+      name:        '5400_postmaster_filter_service_now_check',
+      area:        'Postmaster::PreFilter',
+      description: 'Defines postmaster filter to identify service now mails for correct follow-ups.',
+      options:     {},
+      state:       'Channel::Filter::ServiceNowCheck',
+      frontend:    false
+    )
+
+    Setting.create_if_not_exists(
+      title:       'Defines postmaster filter.',
+      name:        '5401_postmaster_filter_service_now_check',
+      area:        'Postmaster::PostFilter',
+      description: 'Defines postmaster filter to identify service now mails for correct follow-ups.',
+      options:     {},
+      state:       'Channel::Filter::ServiceNowCheck',
+      frontend:    false
+    )
+  end
+
+end

+ 18 - 0
db/seeds/settings.rb

@@ -3449,6 +3449,24 @@ Setting.create_if_not_exists(
   state:       'Channel::Filter::Monit',
   frontend:    false
 )
+Setting.create_if_not_exists(
+  title:       'Defines postmaster filter.',
+  name:        '5400_postmaster_filter_service_now_check',
+  area:        'Postmaster::PreFilter',
+  description: 'Defines postmaster filter to identify service now mails for correct follow-ups.',
+  options:     {},
+  state:       'Channel::Filter::ServiceNowCheck',
+  frontend:    false
+)
+Setting.create_if_not_exists(
+  title:       'Defines postmaster filter.',
+  name:        '5401_postmaster_filter_service_now_check',
+  area:        'Postmaster::PostFilter',
+  description: 'Defines postmaster filter to identify service now mails for correct follow-ups.',
+  options:     {},
+  state:       'Channel::Filter::ServiceNowCheck',
+  frontend:    false
+)
 Setting.create_if_not_exists(
   title:       'Icinga integration',
   name:        'icinga_integration',

+ 28 - 0
spec/models/channel/email_parser_spec.rb

@@ -983,6 +983,34 @@ RSpec.describe Channel::EmailParser, type: :model do
       end
     end
 
+    describe 'ServiceNow handling' do
+      context 'when emails with service now reference are sent' do
+        let(:mail_file) { Rails.root.join('test/data/mail/mail089.box') }
+        let(:mail_file_answer) { Rails.root.join('test/data/mail/mail090.box') }
+        let(:raw_mail_answer)  { File.read(mail_file_answer) }
+
+        it 'does create a ticket with external sync reference' do
+          expect { described_class.new.process({}, raw_mail) }
+            .to change(Ticket, :count).by(1)
+            .and change(Ticket::Article, :count).by(1)
+            .and change(ExternalSync, :count).by(1)
+
+          expect(ExternalSync.last.source).to eq('ServiceNow')
+          expect(ExternalSync.last.source_id).to eq('INC678439')
+          expect(ExternalSync.last.object).to eq('Ticket')
+          expect(ExternalSync.last.o_id).to eq(Ticket.last.id)
+          expect(Ticket.last.articles.last.subject).to eq('Incident INC678439 -- zugewiesen an EXT-XXXINIS')
+
+          expect { described_class.new.process({}, raw_mail_answer) }
+            .to change(Ticket, :count).by(0)
+            .and change(Ticket::Article, :count).by(1)
+            .and change(ExternalSync, :count).by(0)
+
+          expect(Ticket.last.articles.last.subject).to eq('Incident INC678439 -- Arbeitsnotizen beigefügt')
+        end
+      end
+    end
+
     describe 'XSS protection' do
       let(:article) { described_class.new.process({}, raw_mail).second }
 

+ 22 - 0
test/data/mail/mail089.box

@@ -0,0 +1,22 @@
+From: IT example <example@service-now.com>
+To: support@example.com
+Message-ID: <18659453.58107.1576665116411@app129169.gva3.service-now.com>
+Subject: Incident INC678439 -- zugewiesen an EXT-XXXINIS
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+    boundary="----=_Part_58105_29005161.1576665006397"
+X-ServiceNow-Source: Notification-5555502c4ff4aa0096d7e6101310c734
+X-ServiceNow-SysEmail-Version: 2
+Precedence: bulk
+Auto-Submitted: auto-generated
+X-ServiceNow-Generated: true
+
+------=_Part_58105_29005161.1576665006397
+Content-Type: multipart/alternative;
+    boundary="----=_Part_58106_4969544.1576665006398"
+
+------=_Part_58106_4969544.1576665006398
+Content-Transfer-Encoding: quoted-printable
+Content-Type: text/plain; charset=UTF-8
+
+Incident content

+ 22 - 0
test/data/mail/mail090.box

@@ -0,0 +1,22 @@
+From: IT example <example@service-now.com>
+To: support@example.com
+Message-ID: <18659453.58107.1576665116411@app129169.gva3.service-now.com>
+Subject: =?UTF-8?Q?Incident_INC678439_--_Arbeitsnotizen_beigef=C3=BCgt?=
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+    boundary="----=_Part_58105_29005161.1576665006397"
+X-ServiceNow-Source: Notification-5555502c4ff4aa0096d7e6101310c734
+X-ServiceNow-SysEmail-Version: 2
+Precedence: bulk
+Auto-Submitted: auto-generated
+X-ServiceNow-Generated: true
+
+------=_Part_58105_29005161.1576665006397
+Content-Type: multipart/alternative;
+    boundary="----=_Part_58106_4969544.1576665006398"
+
+------=_Part_58106_4969544.1576665006398
+Content-Transfer-Encoding: quoted-printable
+Content-Type: text/plain; charset=UTF-8
+
+Incident content