Преглед изворни кода

Add a new option `include_raw_mail` to ImapFolderAgent

Akinori MUSHA пре 7 година
родитељ
комит
4665c305c7
2 измењених фајлова са 43 додато и 8 уклоњено
  1. 20 6
      app/models/agents/imap_folder_agent.rb
  2. 23 2
      spec/models/agents/imap_folder_agent_spec.rb

+ 20 - 6
app/models/agents/imap_folder_agent.rb

@@ -54,6 +54,8 @@ module Agents
 
       Set `mark_as_read` to true to mark found mails as read.
 
+      Set `include_raw_mail` to true to add to each created event a raw unencoded mail text, in the so-called "RFC822" format defined in the [IMAP4 standard](https://tools.ietf.org/html/rfc3501).
+
       Each agent instance memorizes the highest UID of mails that are found in the last run for each watched folder, so even if you change a set of conditions so that it matches mails that are missed previously, or if you alter the flag status of already found mails, they will not show up as new events.
 
       Also, in order to avoid duplicated notification it keeps a list of Message-Id's of 100 most recent mails, so if multiple mails of the same Message-Id are found, you will only see one event out of them.
@@ -75,6 +77,8 @@ module Agents
             "matches": {
             }
           }
+
+      Additionally, "raw_mail" will be included if the `include_raw_mail` option is set.
     MD
 
     IDCACHE_SIZE = 100
@@ -113,7 +117,7 @@ module Agents
         errors.add(:base, "port must be a positive integer") unless is_positive_integer?(options['port'])
       end
 
-      %w[ssl mark_as_read].each { |key|
+      %w[ssl mark_as_read include_raw_mail].each { |key|
         if options[key].present?
           if boolify(options[key]).nil?
             errors.add(:base, '%s must be a boolean value' % key)
@@ -265,7 +269,7 @@ module Agents
 
           log 'Emitting an event for mail: %s' % message_id
 
-          create_event :payload => {
+          payload = {
             'message_id' => message_id,
             'folder' => mail.folder,
             'subject' => mail.scrubbed(:subject),
@@ -279,6 +283,12 @@ module Agents
             'has_attachment' => mail.has_attachment?,
           }
 
+          if boolify(interpolated['include_raw_mail'])
+            payload['raw_mail'] = mail.raw_mail
+          end
+
+          create_event payload: payload
+
           notified << mail.message_id if mail.message_id
         end
 
@@ -505,15 +515,19 @@ module Agents
           end
       end
 
-      def fetch
-        @parsed ||=
+      def raw_mail
+        @raw_mail ||=
           if data = @client.uid_fetch(@uid, 'BODY.PEEK[]').first
-            Mail.read_from_string(data.attr['BODY[]'])
+            data.attr['BODY[]']
           else
-            Mail.read_from_string('')
+            ''
           end
       end
 
+      def fetch
+        @parsed ||= Mail.read_from_string(raw_mail)
+      end
+
       def body_parts(mime_types = DEFAULT_BODY_MIME_TYPES)
         mail = fetch
         if mail.multipart?

+ 23 - 2
spec/models/agents/imap_folder_agent_spec.rb

@@ -47,13 +47,13 @@ describe Agents::ImapFolderAgent do
         Mail.read(Rails.root.join('spec/data_fixtures/imap1.eml')).tap { |mail|
           mail.extend(MessageMixin)
           stub(mail).uid.returns(1)
-          stub(mail).rfc822.returns(mail.encoded)
+          stub(mail).raw_mail.returns(mail.encoded)
         },
         Mail.read(Rails.root.join('spec/data_fixtures/imap2.eml')).tap { |mail|
           mail.extend(MessageMixin)
           stub(mail).uid.returns(2)
           stub(mail).has_attachment?.returns(true)
-          stub(mail).rfc822.returns(mail.encoded)
+          stub(mail).raw_mail.returns(mail.encoded)
         },
       ]
     }
@@ -294,6 +294,27 @@ describe Agents::ImapFolderAgent do
           }.not_to raise_exception
         end
       end
+
+      describe 'with include_raw_mail' do
+        before do
+          @checker.options['include_raw_mail'] = true
+          @checker.save!
+        end
+
+        it 'should check for mails and emit events with raw_mail' do
+          expect { @checker.check }.to change { Event.count }.by(2)
+          expect(@checker.notified.sort).to eq(mails.map(&:message_id).sort)
+          expect(@checker.lastseen).to eq(mails.each_with_object(@checker.make_seen) { |mail, seen|
+              seen[mail.uidvalidity] = mail.uid
+            })
+
+          expect(Event.last(2).map(&:payload)).to eq expected_payloads.map.with_index { |payload, i|
+            payload.merge('raw_mail' => mails[i].encoded)
+          }
+
+          expect { @checker.check }.not_to change { Event.count }
+        end
+      end
     end
   end