13668.1.21
by Curtis Hovey
Updated copyrights. |
1 |
# Copyright 2010-2011 Canonical Ltd. This software is licensed under the
|
12043.4.2
by Gavin Panella
Move AnswerTrackerHandler to lp.answers.mail.handler. |
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
3 |
||
4 |
"""Handle incoming Answers email."""
|
|
5 |
||
6 |
__metaclass__ = type |
|
12043.4.3
by Gavin Panella
Reenable emailinterface.txt test for Answers. |
7 |
__all__ = [ |
8 |
"AnswerTrackerHandler", |
|
9 |
]
|
|
12043.4.2
by Gavin Panella
Move AnswerTrackerHandler to lp.answers.mail.handler. |
10 |
|
11 |
import re |
|
12 |
||
13 |
from zope.component import getUtility |
|
14 |
from zope.interface import implements |
|
15 |
||
13668.1.22
by Curtis Hovey
Sorted imports. |
16 |
from lp.answers.enums import QuestionStatus |
17 |
from lp.answers.interfaces.questioncollection import IQuestionSet |
|
13668.1.4
by Curtis Hovey
Moved c.l.interfaces.mail to lp.services.mail.interfaces. |
18 |
from lp.services.mail.interfaces import IMailHandler |
12929.9.2
by j.c.sackett
Moved messages from canonical to lp.services |
19 |
from lp.services.messages.interfaces.message import IMessageSet |
14612.2.1
by William Grant
format-imports on lib/. So many imports. |
20 |
from lp.services.webapp.interfaces import ILaunchBag |
12043.4.2
by Gavin Panella
Move AnswerTrackerHandler to lp.answers.mail.handler. |
21 |
|
22 |
||
23 |
class AnswerTrackerHandler: |
|
24 |
"""Handles emails sent to the Answer Tracker."""
|
|
25 |
||
26 |
implements(IMailHandler) |
|
27 |
||
28 |
allow_unknown_users = False |
|
29 |
||
30 |
# XXX flacoste 2007-04-23: The 'ticket' part is there for backward
|
|
31 |
# compatibility with the old notification address. We probably want to
|
|
32 |
# remove it in the future.
|
|
33 |
_question_address = re.compile(r'^(ticket|question)(?P<id>\d+)@.*') |
|
34 |
||
35 |
def process(self, signed_msg, to_addr, filealias=None, log=None): |
|
36 |
"""See IMailHandler."""
|
|
37 |
match = self._question_address.match(to_addr) |
|
38 |
if not match: |
|
39 |
return False |
|
40 |
||
41 |
question_id = int(match.group('id')) |
|
42 |
question = getUtility(IQuestionSet).get(question_id) |
|
43 |
if question is None: |
|
44 |
# No such question, don't process the email.
|
|
45 |
return False |
|
46 |
||
47 |
messageset = getUtility(IMessageSet) |
|
48 |
message = messageset.fromEmail( |
|
49 |
signed_msg.parsed_string, |
|
50 |
owner=getUtility(ILaunchBag).user, |
|
51 |
filealias=filealias, |
|
52 |
parsed_message=signed_msg) |
|
53 |
||
54 |
if message.owner == question.owner: |
|
55 |
self.processOwnerMessage(question, message) |
|
56 |
else: |
|
57 |
self.processUserMessage(question, message) |
|
58 |
return True |
|
59 |
||
60 |
def processOwnerMessage(self, question, message): |
|
61 |
"""Choose the right workflow action for a message coming from
|
|
62 |
the question owner.
|
|
63 |
||
64 |
When the question status is OPEN or NEEDINFO,
|
|
65 |
the message is a GIVEINFO action; when the status is ANSWERED
|
|
66 |
or EXPIRED, we interpret the message as a reopenening request;
|
|
67 |
otherwise it's a comment.
|
|
68 |
"""
|
|
69 |
if question.status in [ |
|
70 |
QuestionStatus.OPEN, QuestionStatus.NEEDSINFO]: |
|
71 |
question.giveInfo(message) |
|
72 |
elif question.status in [ |
|
73 |
QuestionStatus.ANSWERED, QuestionStatus.EXPIRED]: |
|
74 |
question.reopen(message) |
|
75 |
else: |
|
76 |
question.addComment(message.owner, message) |
|
77 |
||
78 |
def processUserMessage(self, question, message): |
|
79 |
"""Choose the right workflow action for a message coming from a user
|
|
80 |
that is not the question owner.
|
|
81 |
||
82 |
When the question status is OPEN, NEEDSINFO, or ANSWERED, we interpret
|
|
83 |
the message as containing an answer. (If it was really a request for
|
|
84 |
more information, the owner will still be able to answer it while
|
|
85 |
reopening the request.)
|
|
86 |
||
87 |
In the other status, the message is a comment without status change.
|
|
88 |
"""
|
|
89 |
if question.status in [ |
|
90 |
QuestionStatus.OPEN, QuestionStatus.NEEDSINFO, |
|
91 |
QuestionStatus.ANSWERED]: |
|
92 |
question.giveAnswer(message.owner, message) |
|
93 |
else: |
|
94 |
# In the other states, only a comment can be added.
|
|
95 |
question.addComment(message.owner, message) |