Changeset in
- Timestamp:
- 05/02/09 13:38:19 (3 years ago)
- Children:
- 4bceacf6b979775083c8623c2906a66e95eefe48
- Parents:
- 935fbfb3a362aa24429eff491679842cfb8feb81
- git-committer:
- Gartersnake Server <gartersnake@gartersnake.precisionconversions.com> / 2009-05-02T13:38:19Z-0700
- Location:
- resourcetotrac
- Files:
-
- 3 added
- 3 edited
- 1 moved
-
resourcetotrac/api.py (modified) (2 diffs)
-
resourcetotrac/email/__init__.py (added)
-
resourcetotrac/email/api.py (added)
-
resourcetotrac/email/imap.py (moved) (moved from resourcetotrac/resourcetotrac/imap.py) (3 diffs)
-
resourcetotrac/email/util.py (added)
-
resourcetotrac/script.py (modified) (3 diffs)
-
setup.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
resourcetotrac/resourcetotrac/api.py
r935fbfb ref235ae 17 17 # Local imports 18 18 19 __all__ = ['IEmailStore'] 20 21 class StoreConnectError(StandardError): pass 19 __all__ = [ 20 'IDataSource', 21 'IResourceSubmitter', 22 'IResourceParser', 23 'ITypeParser', 24 'BaseParsedMessage', 25 ] 22 26 23 27 … … 62 66 """ Submits the resource to Trac """ 63 67 68 class IResourceParser(Interface): 69 """ Parse a message 70 71 This interface should be subclassed to the specific data source. 72 """ 73 74 def match_resource_type(self, resource_type): 75 """ Return whether or not to parse the given resource type """ 76 77 def parse_message(self, resource_type, message): 78 """ Parses the message and returns a child instance of 79 BaseParsedMesssage 80 """ 81 82 class ITypeParser(Interface): 83 """ Extracts the resource type from the message 84 85 This interface should be subclassed to the specific data source. 86 """ 87 88 def get_resource_type(self, msg): 89 """ Returns the resource type or None if it can't identify it """ 90 91 92 64 93 class BaseParsedMessage(object): 65 94 """ Base class for parsed messages. -
resourcetotrac/resourcetotrac/email/imap.py
r935fbfb ref235ae 20 20 21 21 # Local imports 22 from emailtoticket.api import IEmailStore, StoreConnectError 22 from resourcetotrac.api import IDataSource 23 from resourcetotrac.email.api import StoreConnectError, IEmailResourceParser 24 from resourcetotrac.email.api import IEmailTypeParser 23 25 24 __all__ = ['IMAPS tore']26 __all__ = ['IMAPSource'] 25 27 26 28 RESPONSE = 0 … … 30 32 OK = 'OK' 31 33 32 class IMAPS tore(Component):34 class IMAPSource(Component): 33 35 34 implements(I EmailStore)36 implements(IDataSource) 35 37 36 host = Option('email2ticket', 'imap.host', default='localhost', 38 resource_parsers = ExtensionPoint(IEmailResourceParser) 39 type_parsers = ExtensionPoint(IEmailTypeParser) 40 41 host = Option('resource2trac', 'imap.host', default='localhost', 37 42 doc="Hostname or IP of IMAP server. [default:localhost]") 38 port = IntOption(' email2ticket', 'imap.port', default='143',43 port = IntOption('resource2trac', 'imap.port', default='143', 39 44 doc="Port to use when connecting to IMAP server. " 40 45 "[default:143 or 993 if imap.ssl = True]") 41 ssl = BoolOption(' email2ticket', 'imap.ssl', default=False,46 ssl = BoolOption('resource2trac', 'imap.ssl', default=False, 42 47 doc="Use SSL") 43 user = Option(' email2ticket', 'imap.user',48 user = Option('resource2trac', 'imap.user', 44 49 doc="Username to use when logging into IMAP") 45 passwd = Option(' email2ticket', 'imap.passwd',50 passwd = Option('resource2trac', 'imap.passwd', 46 51 doc="IMAP password") 47 def __repr__(self):48 return 'IMAPStore'49 52 50 def __str__(self): 51 return 'IMAPStore' 53 # IDataSource Methods 54 def get_message(self): 55 """ Generator that returns a tuple of (id, email) 52 56 57 The id parameter is an identifier that can be used to locate the email 58 in the email store. 59 60 The email parameter must be an email.message.Message object 61 """ 62 if not self.connected: 63 self.log.debug('Connection timeout. Retrying connection...') 64 self._connect() 65 66 response = self.cnx.select() 67 if response[RESPONSE] != OK: 68 self.log.debug('Unable to select messages from server') 69 for x in int(response[DATA]): 70 msg = self._parse_message( msg = email.message_from_string(self.cnx.fetch(x, r'(UID RFC822)')[DATA][CONTAINER][MSG]) 71 yield (x, parsed_msg) 72 73 74 def archive_message(self, id, info={}): 75 """ Archive the email with the specified id 76 77 The id is the id retrieved from the call to get_email(). 78 """ 79 80 archive = 'INBOX._archive.%d' % ticket 81 response = self.cnx.list(archive) 82 if response[RESPONSE] == OK and response[DATA][0] == 'None': 83 response = self.cnx.create(archive) 84 if response[RESPONSE] == OK: 85 response = self.cnx.select() 86 if response[RESPONSE] == OK: 87 self.cnx.copy(id, archive) 88 pass 89 90 91 def delete_message(self, id): 92 """ Delete the email from the email store """ 93 self.cnx.store(id, '+flags', r'(\Deleted)') 94 95 96 def cleanup(self): 97 self.cnx.expunge() 98 99 # Private Methods 53 100 def _connect(self): 54 101 """ Logs into the IMAP server. """ … … 85 132 connected = property(_test_imap_cnx) 86 133 134 def _parse_email(self, msg); 135 """ Parses the message returning an instance of the appropriate 136 BaseParsedMessage subclass 137 """ 138 for p in self.type_parsers: 139 resource_type = p.get_resource_type(msg) 140 if resource_type: 141 break 142 continue 143 for p in self.resource_parsers: 144 if p.match_resource_type(resource_type): 145 return p.parse_message(resource_type, msg) 146 continue 147 return None 87 148 88 def get_email(self):89 """ Generator that returns a tuple of (id, email)149 def __repr__(self): 150 return 'IMAPSource' 90 151 91 The id parameter is an identifier that can be used to locate the email92 in the email store.152 def __str__(self): 153 return 'IMAPSource' 93 154 94 The email parameter must be an email.message.Message object95 """96 if not self.connected:97 self.log.debug('Connection timeout. Retrying connection...')98 self._connect()99 100 response = self.cnx.select()101 if response[RESPONSE] != OK:102 self.log.debug('Unable to select messages from server')103 for x in int(response[DATA]):104 yield (x, email.message_from_string(self.cnx.fetch(x, r'(UID RFC822)')[DATA][CONTAINER][MSG]))105 106 107 def archive_email(self, id, info={}):108 """ Archive the email with the specified id109 110 The id is the id retrieved from the call to get_email().111 """112 ticket = info.get('ticket', 0)113 archive = 'INBOX._archive.%d' % ticket114 response = self.cnx.list(archive)115 if response[RESPONSE] == OK and response[DATA][0] == 'None':116 response = self.cnx.create(archive)117 118 if response[RESPONSE] == OK:119 self.cnx.copy(id, archive)120 pass121 122 123 def delete_email(self, id):124 """ Delete the email from the email store """125 self.cnx.store(id, '+flags', r'(\Deleted)')126 127 128 def cleanup(self):129 self.cnx.expunge() -
resourcetotrac/resourcetotrac/script.py
r935fbfb ref235ae 19 19 import daemonize 20 20 from trac.env import Environment 21 from trac.core import Component 21 from trac.core import Component, ExtensionPoint 22 22 from trac.config import OrderedExtensionsOption 23 23 24 24 # Local imports 25 from emailtoticket.api import IEmailStore 26 from emailtoticket.util import EmailParser 25 from resourcetotrac.api import IDataSource, IResourceSubmitter 27 26 28 27 … … 30 29 31 30 32 __all__ = [' EmailToTicketConfig']31 __all__ = ['ResourceSubmission'] 33 32 34 33 35 class EmailTicketSubmission(Component):34 class ResourceSubmission(Component): 36 35 37 36 implemnts(IResourceSubmitter) 38 37 39 email_stores = OrderedExtensionsOption('email2ticket', 'stores',40 I EmailStore, include_missing=False,41 doc="List of enabled email stores")38 data_sources = OrderedExtensionsOption('resource2trac', 'sources', 39 IDataSource, include_missing=False, 40 doc="List of enabled data sources") 42 41 43 archive = BoolOption('email2ticket', 'archive', True, 44 doc="Whether or not to archive the processed emails") 42 resource_submitters = ExtensionPoint(IResourceSubmitter) 45 43 46 def submit_ticket(self, email): 47 """ Rape the email and submit/update a ticket """ 48 49 parser = EmailParser(self.env) 50 subject = parser.get_subject(email)email['Subject'].strip() 51 author_email = parseaddr(email['From'])[1] 52 update = subject[:3].lower() == 're:' 53 if update: 54 subject = subject[3:].strip() 55 44 archive = BoolOption('resource2trac', 'archive', True, 45 doc="Whether or not to archive the processed messages") 56 46 57 47 58 def process_tickets(self): 59 self.parser 60 for store in self.email_stores: 61 for id, email in store.get_email(): 48 def process_resources(self): 49 for src in self.data_sources: 50 for id, msg in src.get_message(): 62 51 try: 63 info = self.submit_ticket(email) 52 resource_type = msg.get_type() 53 for submitter in self.resource_submitters(): 54 if submitter.match_resource_type(resource_type): 55 break 56 continue 57 submitter.submit_resource(resource_type, msg) 64 58 if self.archive: 65 s tore.archive_email(id)66 s tore.delete_email(id)59 src.archive_message(id) 60 src.delete_message(id) 67 61 except: 68 self.log.debug('Unable to submit the ticket')69 s tore.cleanup()62 self.log.debug('Unable to submit the resource') 63 src.cleanup() 70 64 continue 71 72 73 65 74 66 … … 103 95 def main(argv): 104 96 opts = doArgs(argv) 105 emailticket = EmailTicketSubmission(opts.env)97 emailticket = ResourceSubmission(opts.env) 106 98 emailticket.process_tickets() 107 99 return 0 -
resourcetotrac/setup.py
r935fbfb ref235ae 27 27 resourcetotrac.api = resourcetotrac.api 28 28 resourcetotrac.config = resourcetotrac.config 29 resourcetotrac. imap = resourcetotrac.imap29 resourcetotrac.email.imap = resourcetotrac.email.imap 30 30 """ 31 31 # Currently no package data in use
Note: See TracChangeset
for help on using the changeset viewer.
