~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/services/features/scopes.py

  • Committer: Launchpad Patch Queue Manager
  • Date: 2011-08-01 13:37:39 UTC
  • mfrom: (12913.2.23 mail-scope)
  • Revision ID: launchpad@pqm.canonical.com-20110801133739-r61kp1hfiqe0x83z
[r=adeuring,gmb][bug=810290] add 'mail_header:' feature scope

Show diffs side-by-side

added added

removed removed

Lines of Context:
169
169
        return scope_name == self.script_scope
170
170
 
171
171
 
 
172
class MailHeaderScope(BaseScope):
 
173
    """Matches a regex against the un-wrapped form of arbitrary mail headers.
 
174
 
 
175
    For example mail_header:received:bad-example\\.com will match any mail
 
176
    that passed through that host.
 
177
 
 
178
    The header name is matched case-insensitively, and if the header is
 
179
    repeated this scope looks for a match in any occurrence.
 
180
 
 
181
    The value is matched as a Python regex, without
 
182
    anchoring to the start of the string, and with Python's default regexp
 
183
    options.  For a case-insensitive match, you should include (?i) at the
 
184
    start.
 
185
 
 
186
    Headers are not unfolded before matching, so wrapped lines may appear as
 
187
    "\n\t".
 
188
    """
 
189
 
 
190
    pattern = r'mail_header:(?P<header_name>[^:]*):(?P<value_regex>.*)'
 
191
 
 
192
    def __init__(self, email_message):
 
193
        self.email_message = email_message
 
194
 
 
195
    def lookup(self, scope_name):
 
196
        match = self.compiled_pattern.match(scope_name)
 
197
        if match is None:
 
198
            return False  # Shouldn't happen?
 
199
        header_name = match.group('header_name')
 
200
        regex_str = match.group('value_regex')
 
201
        regex = re.compile(regex_str)
 
202
        for header_value in self.email_message.get_all(header_name, []):
 
203
            if regex.search(header_value):
 
204
                return True
 
205
        else:
 
206
            return False
 
207
 
 
208
 
172
209
# These are the handlers for all of the allowable scopes, listed here so that
173
210
# we can for example show all of them in an admin page.  Any new scope will
174
211
# need a scope handler and that scope handler has to be added to this list.
175
212
# See BaseScope for hints as to what a scope handler should look like.
176
 
HANDLERS = set([DefaultScope, PageScope, TeamScope, ServerScope, ScriptScope])
 
213
HANDLERS = set([
 
214
    DefaultScope,
 
215
    MailHeaderScope,
 
216
    PageScope,
 
217
    ScriptScope,
 
218
    ServerScope,
 
219
    TeamScope,
 
220
    ])
177
221
 
178
222
 
179
223
class MultiScopeHandler():
186
230
    def __init__(self, scopes):
187
231
        self.handlers = scopes
188
232
 
 
233
    def __repr__(self):
 
234
        return "%s(%r)" % (
 
235
            self.__class__.__name__,
 
236
            self.handlers)
 
237
 
189
238
    def _findMatchingHandlers(self, scope_name):
190
239
        """Find any handlers that match `scope_name`."""
191
240
        return [
231
280
        super(ScopesForScript, self).__init__([
232
281
            DefaultScope(),
233
282
            ScriptScope(script_name)])
 
283
 
 
284
 
 
285
class ScopesForMail(MultiScopeHandler):
 
286
    """Identify feature scopes for handling user email."""
 
287
 
 
288
    def __init__(self, mail_object):
 
289
        """Construct set of scopes for incoming mail.
 
290
 
 
291
        :param mail_object: An ISignedMessage giving the parsed
 
292
            form of the incoming message.  (Note that it's *not*
 
293
            necessarily signed, just potentially signed.)
 
294
        """
 
295
        super(ScopesForMail, self).__init__([
 
296
            DefaultScope(),
 
297
            MailHeaderScope(mail_object),
 
298
            ServerScope(),
 
299
            TeamScope(),
 
300
            ])