Repository: allura
Updated Branches:
  refs/heads/master 502b5e442 -> 590a5ca74


[#8132] thread messages by References: if missing In-Reply-To:


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/590a5ca7
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/590a5ca7
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/590a5ca7

Branch: refs/heads/master
Commit: 590a5ca7454e9d455fb734e93b155a012c302cf5
Parents: 502b5e4
Author: Dave Brondsema <d...@brondsema.net>
Authored: Wed Oct 5 13:59:16 2016 -0500
Committer: Dave Brondsema <d...@brondsema.net>
Committed: Thu Oct 13 13:22:55 2016 -0400

----------------------------------------------------------------------
 Allura/allura/app.py                            |  2 +-
 ForgeDiscussion/forgediscussion/model/forum.py  | 18 ++++-----
 .../tests/functional/test_forum.py              | 42 +++++++++++++++++---
 3 files changed, 45 insertions(+), 17 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/590a5ca7/Allura/allura/app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/app.py b/Allura/allura/app.py
index f155514..22190e6 100644
--- a/Allura/allura/app.py
+++ b/Allura/allura/app.py
@@ -703,7 +703,7 @@ class Application(object):
                 post_id=message_id,
                 artifact_id=message_id)
             return
-        # Handle duplicates
+        # Handle duplicates (from multipart mail messages)
         post = self.PostClass.query.get(_id=message_id)
         if post:
             log.info(

http://git-wip-us.apache.org/repos/asf/allura/blob/590a5ca7/ForgeDiscussion/forgediscussion/model/forum.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/model/forum.py 
b/ForgeDiscussion/forgediscussion/model/forum.py
index 675efa2..bab3edf 100644
--- a/ForgeDiscussion/forgediscussion/model/forum.py
+++ b/ForgeDiscussion/forgediscussion/model/forum.py
@@ -111,19 +111,17 @@ class Forum(M.Discussion):
     def get_discussion_thread(self, data=None):
         # If the data is a reply, use the parent's thread
         subject = '[no subject]'
-        parent_id = None
         if data is not None:
-            in_reply_to = data.get('in_reply_to')
-            if in_reply_to:
-                parent_id = in_reply_to[0].split('/')[-1]
-            else:
-                parent_id = None
             message_id = data.get('message_id') or ''
             subject = data['headers'].get('Subject', subject)
-        if parent_id is not None:
-            parent = self.post_class().query.get(_id=parent_id)
-            if parent:
-                return parent.thread, parent_id
+            in_reply_to = data.get('in_reply_to') or []
+            references = data.get('references') or []
+            # find first valid In-Reply-To: header or References: header 
(starting from end)
+            for msg_id in in_reply_to + list(reversed(references)):
+                parent_id = msg_id.split('/')[-1]
+                parent = self.post_class().query.get(_id=parent_id)
+                if parent:
+                    return parent.thread, parent_id
         if message_id:
             post = self.post_class().query.get(_id=message_id)
             if post:

http://git-wip-us.apache.org/repos/asf/allura/blob/590a5ca7/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py 
b/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
index 99df83b..a8c3283 100644
--- a/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
+++ b/ForgeDiscussion/forgediscussion/tests/functional/test_forum.py
@@ -25,6 +25,8 @@ from email.mime.image import MIMEImage
 from email.mime.multipart import MIMEMultipart
 
 import pkg_resources
+import pymongo
+
 from ming.odm import ThreadLocalORMSession
 from pylons import tmpl_context as c
 
@@ -129,7 +131,11 @@ class TestForumEmail(TestController):
         M.artifact_orm_session.flush()
 
 
-class TestForumAsync(TestController):
+class TestForumMessageHandling(TestController):
+    '''
+    Tests all the "handle_message" related logic, which is what inbound emails 
run through
+    '''
+
     def setUp(self):
         TestController.setUp(self)
         self.app.get('/discussion/')
@@ -166,17 +172,38 @@ class TestForumAsync(TestController):
         posts = FM.ForumPost.query.find()
         assert_equal(posts.count(), 1)
         assert_equal(FM.ForumThread.query.get().num_replies, 1)
-        assert_equal(FM.ForumThread.query.get()
-                     .first_post_id, 'test_re...@domain.net')
+        assert_equal(FM.ForumThread.query.get().first_post_id, 
'test_re...@domain.net')
 
         post = posts.first()
         self._post('testforum', 'Test Reply', 'Nothing here, either',
-                   message_id=post.thread.url() + post._id,
+                   message_id='test_reply-m...@domain.net',
                    in_reply_to=['test_re...@domain.net'])
         assert_equal(FM.ForumThread.query.find().count(), 1)
         assert_equal(FM.ForumPost.query.find().count(), 2)
-        assert_equal(FM.ForumThread.query.get()
-                     .first_post_id, 'test_re...@domain.net')
+        assert_equal(FM.ForumThread.query.get().first_post_id, 
'test_re...@domain.net')
+
+    def test_reply_using_references_headers(self):
+        self._post('testforum', 'Test Thread', 'Nothing here',
+                   message_id='first-message-id')
+        prev_post = FM.ForumPost.query.find().first()
+        thread = FM.ForumThread.query.find().first()
+
+        refs = M.Notification._references(thread, prev_post) + 
['first-message-id']
+        self._post('testforum', 'Test Thread', 'Nothing here, yet',
+                   message_id='second-message-id',
+                   in_reply_to=['some-other...@not.helpful.com'],
+                   references=refs)
+        assert_equal(FM.ForumThread.query.find().count(), 1)
+        assert_equal(FM.ForumPost.query.find().count(), 2)
+
+        prev_post = FM.ForumPost.query.find().sort('timestamp', 
pymongo.DESCENDING).first()
+        refs = M.Notification._references(thread, prev_post) + 
['second-message-id']
+        self._post('testforum', 'Test Reply', 'Nothing here, either',
+                   message_id='third-message-id',
+                   # missing in_reply_to altogether
+                   references=refs)
+        assert_equal(FM.ForumThread.query.find().count(), 1)
+        assert_equal(FM.ForumPost.query.find().count(), 3)
 
     def test_attach(self):
         self._post('testforum', 'Attachment Thread', 'This is a text file',
@@ -255,6 +282,9 @@ class TestForumAsync(TestController):
                           params=dict(subject='', delete='on'))
 
     def _post(self, topic, subject, body, **kw):
+        '''
+        Submit a message very similar to how incoming email works
+        '''
         message_id = kw.pop('message_id', '%s...@test.com' % random.random())
         with h.push_config(c, user=self.user):
             c.app.handle_message(

Reply via email to