Return-Path: X-Original-To: apmail-incubator-allura-commits-archive@minotaur.apache.org Delivered-To: apmail-incubator-allura-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 9DF71108C9 for ; Wed, 30 Oct 2013 17:03:02 +0000 (UTC) Received: (qmail 99922 invoked by uid 500); 30 Oct 2013 17:01:13 -0000 Delivered-To: apmail-incubator-allura-commits-archive@incubator.apache.org Received: (qmail 99466 invoked by uid 500); 30 Oct 2013 17:00:50 -0000 Mailing-List: contact allura-commits-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: allura-dev@incubator.apache.org Delivered-To: mailing list allura-commits@incubator.apache.org Received: (qmail 98471 invoked by uid 99); 30 Oct 2013 17:00:21 -0000 Received: from tyr.zones.apache.org (HELO tyr.zones.apache.org) (140.211.11.114) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 30 Oct 2013 17:00:21 +0000 Received: by tyr.zones.apache.org (Postfix, from userid 65534) id 4D1F0890DC2; Wed, 30 Oct 2013 17:00:20 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: johnsca@apache.org To: allura-commits@incubator.apache.org Date: Wed, 30 Oct 2013 17:00:29 -0000 Message-Id: <40f4d015894f4cc19023e5db3400e78f@git.apache.org> In-Reply-To: <1feed2ec8aa5453688a5765e6d220fe6@git.apache.org> References: <1feed2ec8aa5453688a5765e6d220fe6@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [11/40] git commit: [#6328] ticket:448 Set Message-ID for first ticket notification [#6328] ticket:448 Set Message-ID for first ticket notification When ticket is created set Message-ID: in corresponding notification to ticket.message_id(). Thus later we can use this value in top-level comments notifications as In-Reply-To: and References: to group emails in one thread. Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/0b5ceda0 Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/0b5ceda0 Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/0b5ceda0 Branch: refs/heads/cj/6777 Commit: 0b5ceda03e77c34b9c860d66fb95a46f7a402fce Parents: 734bf8a Author: Igor Bondarenko Authored: Wed Oct 23 08:36:22 2013 +0000 Committer: Cory Johns Committed: Thu Oct 24 18:59:28 2013 +0000 ---------------------------------------------------------------------- Allura/allura/lib/mail_util.py | 1 + Allura/allura/model/notification.py | 3 +- ForgeTracker/forgetracker/model/ticket.py | 9 ++- .../forgetracker/tests/functional/test_root.py | 62 +++++++++++++++++++- 4 files changed, 70 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/0b5ceda0/Allura/allura/lib/mail_util.py ---------------------------------------------------------------------- diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py index db7ddb3..3a67e10 100644 --- a/Allura/allura/lib/mail_util.py +++ b/Allura/allura/lib/mail_util.py @@ -195,6 +195,7 @@ class SMTPClient(object): if not isinstance(in_reply_to, basestring): raise TypeError('Only strings are supported now, not lists') message['In-Reply-To'] = Header(u'<%s>' % in_reply_to) + message['References'] = message['In-Reply-To'] content = message.as_string() smtp_addrs = map(_parse_smtp_addr, addrs) smtp_addrs = [ a for a in smtp_addrs if isvalid(a) ] http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/0b5ceda0/Allura/allura/model/notification.py ---------------------------------------------------------------------- diff --git a/Allura/allura/model/notification.py b/Allura/allura/model/notification.py index 95b51ba..718a60f 100644 --- a/Allura/allura/model/notification.py +++ b/Allura/allura/model/notification.py @@ -184,13 +184,14 @@ class Notification(MappedClass): h.get_first(idx, 'title'), getattr(artifact, 'email_address', u'noreply@in.sf.net')) d = dict( - message_id=artifact.message_id(), from_address=reply_to, reply_to_address=reply_to, subject=subject_prefix + subject, text=kwargs.pop('text', subject), author_id=c.user._id, pubdate=datetime.utcnow()) + if kwargs.get('message_id'): + d['_id'] = kwargs['message_id'] if c.user.get_pref('email_address'): d['from_address'] = '"%s" <%s>' % ( c.user.get_pref('display_name'), http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/0b5ceda0/ForgeTracker/forgetracker/model/ticket.py ---------------------------------------------------------------------- diff --git a/ForgeTracker/forgetracker/model/ticket.py b/ForgeTracker/forgetracker/model/ticket.py index d580c43..5bd7788 100644 --- a/ForgeTracker/forgetracker/model/ticket.py +++ b/ForgeTracker/forgetracker/model/ticket.py @@ -799,7 +799,14 @@ class Ticket(VersionedArtifact, ActivityObject, VotableArtifact): subject = self.email_subject Thread.new(discussion_id=self.app_config.discussion_id, ref_id=self.index_id()) - n = Notification.post(artifact=self, topic='metadata', text=description, subject=subject) + # First ticket notification. Use persistend Message-ID (self.message_id()). + # Thus we can group notification emails in one thread later. + n = Notification.post( + message_id=self.message_id(), + artifact=self, + topic='metadata', + text=description, + subject=subject) if monitoring_email and n and (not self.private or self.app.config.options.get('TicketMonitoringType') in ( 'NewTicketsOnly', 'AllTicketChanges')): http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/0b5ceda0/ForgeTracker/forgetracker/tests/functional/test_root.py ---------------------------------------------------------------------- diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py index cfd2a61..d524563 100644 --- a/ForgeTracker/forgetracker/tests/functional/test_root.py +++ b/ForgeTracker/forgetracker/tests/functional/test_root.py @@ -2684,10 +2684,10 @@ class TestStats(TrackerTestController): assert_in('# tickets: 0', r.body) -class TestNotifications(TrackerTestController): +class TestNotificationEmailGrouping(TrackerTestController): - def test_notification_email_grouping(self): - ticket_view = self.new_ticket(summary='Test Ticket') + def test_new_ticket_message_id(self): + self.new_ticket(summary='Test Ticket') ThreadLocalORMSession.flush_all() M.MonQTask.run_ready() ThreadLocalORMSession.flush_all() @@ -2695,3 +2695,59 @@ class TestNotifications(TrackerTestController): ticket = tm.Ticket.query.get(ticket_num=1) assert_equal(email.kwargs.message_id, ticket.message_id()) assert_equal(email.kwargs.in_reply_to, None) + + def test_comments(self): + ticket_view = self.new_ticket(summary='Test Ticket').follow() + ThreadLocalORMSession.flush_all() + M.MonQTask.query.remove() + ThreadLocalORMSession.flush_all() + # Messy code to add a comment + for f in ticket_view.html.findAll('form'): + if f.get('action', '').endswith('/post'): + break + post_content = 'top-level comment' + params = dict() + inputs = f.findAll('input') + for field in inputs: + if field.has_key('name'): + params[field['name']] = field.has_key('value') and field['value'] or '' + params[f.find('textarea')['name']] = post_content + r = self.app.post(f['action'].encode('utf-8'), params=params, + headers={'Referer': '/bugs/1/'.encode("utf-8")}) + ThreadLocalORMSession.flush_all() + M.MonQTask.run_ready() + ThreadLocalORMSession.flush_all() + # Check that comment notification refers ticket's message id + email = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendmail')).first() + ticket = tm.Ticket.query.get(ticket_num=1) + top_level_comment = ticket.discussion_thread.posts[0] + top_level_comment_msg_id = ticket.url() + top_level_comment._id + assert_equal(email.kwargs.message_id, top_level_comment_msg_id) + assert_equal(email.kwargs.in_reply_to, ticket.message_id()) + + ThreadLocalORMSession.flush_all() + M.MonQTask.query.remove() + ThreadLocalORMSession.flush_all() + # Messy code to add reply + r = self.app.get('/bugs/1/') + post_link = str(r.html.find('div', {'class': 'edit_post_form reply'}).find('form')['action']) + post_form = r.html.find('form', {'action': post_link + 'reply'}) + params = dict() + inputs = post_form.findAll('input') + for field in inputs: + if field.has_key('name'): + params[field['name']] = field.has_key('value') and field['value'] or '' + reply_text = 'Reply to top-level-comment' + params[post_form.find('textarea')['name']] = reply_text + r = self.app.post(post_link + 'reply', + params=params, + headers={'Referer':post_link.encode("utf-8")}) + ThreadLocalORMSession.flush_all() + M.MonQTask.run_ready() + ThreadLocalORMSession.flush_all() + # Check that reply notification refers top-level comment's message id + email = M.MonQTask.query.find(dict(task_name='allura.tasks.mail_tasks.sendmail')).first() + ticket = tm.Ticket.query.get(ticket_num=1) + reply = [post for post in ticket.discussion_thread.posts if post.text == reply_text][0] + assert_equal(email.kwargs.message_id, ticket.url() + reply._id) + assert_equal(email.kwargs.in_reply_to, top_level_comment_msg_id)