Changeset 359


Ignore:
Timestamp:
05/19/10 15:30:25 (14 years ago)
Author:
bas
Message:

email2trac.py.in:

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/email2trac.py.in

    r356 r359  
    113113        env = None
    114114        comment = '> '
    115    
     115
    116116        def __init__(self, env, parameters, version):
    117117                self.env = env
     
    284284
    285285                self.trac_smtp_from = self.get_config('notification', 'smtp_from')
     286
     287                self.system = None
    286288
    287289########## Email Header Functions ###########################################################
     
    611613                Transfrom a string of the form [<key>=<value>]+ to dict[<key>] = <value>
    612614                """
     615                if self.VERBOSE:
     616                        print "VB: str_to_dict"
    613617
    614618                fields = string.split(s, self.SUBJECT_FIELD_SEPARATOR)
     
    11031107                        #
    11041108                        fd = open(path, 'rb')
    1105                         att = attachment.Attachment(self.env, 'ticket', self.id)
    1106 
     1109                        if self.system == 'discussion':
     1110                                att = attachment.Attachment(self.env, 'discussion', 'topic/%s'
     1111                                  % (self.id,))
     1112                        else:
     1113                                att = attachment.Attachment(self.env, 'ticket', self.id)
     1114 
    11071115                        # This will break the ticket_update system, the body_text is vaporized
    11081116                        # ;-(
     
    11261134                return status
    11271135
    1128 ########## Fullblog functions  ###########################################################
     1136########## Fullblog functions  #################################################
    11291137
    11301138        def blog(self, id):
     
    11711179
    11721180
    1173 
    1174 ########## MAIN function  ###########################################################
     1181########## Discussion functions  ##############################################
     1182
     1183        def discussion_topic(self, content, subject):
     1184
     1185                # Import modules.
     1186                from tracdiscussion.api import DiscussionApi
     1187                from trac.util.datefmt import to_timestamp, utc
     1188
     1189                if self.DEBUG:
     1190                        print 'TD: Creating a new topic in forum:', self.id
     1191
     1192                # Get dissussion API component.
     1193                api = self.env[DiscussionApi]
     1194                context = self._create_context(content, subject)
     1195
     1196                # Get forum for new topic.
     1197                forum = api.get_forum(context, self.id)
     1198
     1199                if not forum and self.DEBUG:
     1200                        print 'ERROR: Replied forum doesn\'t exist'
     1201
     1202                # Prepare topic.
     1203                topic = {'forum' : forum['id'],
     1204                                 'subject' : context.subject,
     1205                                 'time': to_timestamp(datetime.now(utc)),
     1206                                 'author' : self.author,
     1207                                 'subscribers' : [self.email_addr],
     1208                                 'body' : self.body_text(context.content_parts)}
     1209
     1210                # Add topic to DB and commit it.
     1211                self._add_topic(api, context, topic)
     1212                self.db.commit()
     1213
     1214        def discussion_topic_reply(self, content, subject):
     1215
     1216                # Import modules.
     1217                from tracdiscussion.api import DiscussionApi
     1218                from trac.util.datefmt import to_timestamp, utc
     1219
     1220                if self.DEBUG:
     1221                        print 'TD: Replying to discussion topic', self.id
     1222
     1223                # Get dissussion API component.
     1224                api = self.env[DiscussionApi]
     1225                context = self._create_context(content, subject)
     1226
     1227                # Get replied topic.
     1228                topic = api.get_topic(context, self.id)
     1229
     1230                if not topic and self.DEBUG:
     1231                        print 'ERROR: Replied topic doesn\'t exist'
     1232
     1233                # Prepare message.
     1234                message = {'forum' : topic['forum'],
     1235                                   'topic' : topic['id'],
     1236                                   'replyto' : -1,
     1237                                   'time' : to_timestamp(datetime.now(utc)),
     1238                                   'author' : self.author,
     1239                                   'body' : self.body_text(context.content_parts)}
     1240
     1241                # Add message to DB and commit it.
     1242                self._add_message(api, context, message)
     1243                self.db.commit()
     1244
     1245        def discussion_message_reply(self, content, subject):
     1246
     1247                # Import modules.
     1248                from tracdiscussion.api import DiscussionApi
     1249                from trac.util.datefmt import to_timestamp, utc
     1250
     1251                if self.DEBUG:
     1252                        print 'TD: Replying to discussion message', self.id
     1253
     1254                # Get dissussion API component.
     1255                api = self.env[DiscussionApi]
     1256                context = self._create_context(content, subject)
     1257
     1258                # Get replied message.
     1259                message = api.get_message(context, self.id)
     1260
     1261                if not message and self.DEBUG:
     1262                        print 'ERROR: Replied message doesn\'t exist'
     1263
     1264                # Prepare message.
     1265                message = {'forum' : message['forum'],
     1266                                   'topic' : message['topic'],
     1267                                   'replyto' : message['id'],
     1268                                   'time' : to_timestamp(datetime.now(utc)),
     1269                                   'author' : self.author,
     1270                                   'body' : self.body_text(context.content_parts)}
     1271
     1272                # Add message to DB and commit it.
     1273                self._add_message(api, context, message)
     1274                self.db.commit()
     1275
     1276        def _create_context(self, content, subject):
     1277
     1278                # Import modules.
     1279                from trac.mimeview import Context
     1280                from trac.web.api import Request
     1281                from trac.perm import PermissionCache
     1282
     1283                # TODO: Read server base URL from config.
     1284                # Create request object to mockup context creation.
     1285                #
     1286                environ = {'SERVER_PORT' : 80,
     1287                                   'SERVER_NAME' : 'test',
     1288                                   'REQUEST_METHOD' : 'POST',
     1289                                   'wsgi.url_scheme' : 'http',
     1290                                   'wsgi.input' : sys.stdin}
     1291                chrome =  {'links': {},
     1292                                   'scripts': [],
     1293                                   'ctxtnav': [],
     1294                                   'warnings': [],
     1295                                   'notices': []}
     1296
     1297                if self.env.base_url_for_redirect:
     1298                        environ['trac.base_url'] = self.env.base_url
     1299
     1300                req = Request(environ, None)
     1301                req.chrome = chrome
     1302                req.tz = 'missing'
     1303                req.authname = self.author
     1304                req.perm = PermissionCache(self.env, self.author)
     1305
     1306                # Create and return context.
     1307                context = Context.from_request(req)
     1308                context.realm = 'discussion-email2trac'
     1309                context.cursor = self.db.cursor()
     1310                context.content = content
     1311                context.subject = subject
     1312
     1313                # Read content parts from content.
     1314                context.content_parts = self.get_message_parts(content)
     1315                context.content_parts = self.unique_attachment_names(
     1316                  context.content_parts)
     1317
     1318                return context
     1319
     1320        def _add_topic(self, api, context, topic):
     1321                context.req.perm.assert_permission('DISCUSSION_APPEND')
     1322
     1323                # Filter topic.
     1324                for discussion_filter in api.discussion_filters:
     1325                        accept, topic_or_error = discussion_filter.filter_topic(
     1326                          context, topic)
     1327                        if accept:
     1328                                topic = topic_or_error
     1329                        else:
     1330                                raise TracError(topic_or_error)
     1331
     1332                # Add a new topic.
     1333                api.add_topic(context, topic)
     1334
     1335                # Get inserted topic with new ID.
     1336                topic = api.get_topic_by_time(context, topic['time'])
     1337
     1338                # Attach attachments.
     1339                self.id = topic['id']
     1340                self.attach_attachments(context.content_parts, self.VERSION == 0.9)
     1341
     1342                # Notify change listeners.
     1343                for listener in api.topic_change_listeners:
     1344                        listener.topic_created(context, topic)
     1345
     1346        def _add_message(self, api, context, message):
     1347                context.req.perm.assert_permission('DISCUSSION_APPEND')
     1348
     1349                # Filter message.
     1350                for discussion_filter in api.discussion_filters:
     1351                        accept, message_or_error = discussion_filter.filter_message(
     1352                          context, message)
     1353                        if accept:
     1354                                message = message_or_error
     1355                        else:
     1356                                raise TracError(message_or_error)
     1357
     1358                # Add message.
     1359                api.add_message(context, message)
     1360
     1361                # Get inserted message with new ID.
     1362                message = api.get_message_by_time(context, message['time'])
     1363
     1364                # Attach attachments.
     1365                self.id = message['topic']
     1366                self.attach_attachments(context.content_parts, self.VERSION == 0.9)
     1367
     1368                # Notify change listeners.
     1369                for listener in api.message_change_listeners:
     1370                        listener.message_created(context, message)
     1371
     1372########## MAIN function  ######################################################
    11751373
    11761374        def parse(self, fp):
     
    12301428                        self.notification = 0
    12311429
    1232 
     1430                if not m['Subject']:
     1431                        subject  = 'No Subject'
     1432                else:
     1433                        subject  = self.email_to_unicode(m['Subject'])
     1434
     1435                if self.DEBUG:
     1436                         print "TD:", subject
     1437
     1438                #
     1439                # [hic] #1529: Re: LRZ
     1440                # [hic] #1529?owner=bas,priority=medium: Re: LRZ
     1441                #
     1442                ticket_regex = r'''
     1443                        (?P<new_fields>[#][?].*)
     1444                        |(?P<reply>(?P<id>[#][\d]+)(?P<fields>\?.*?:)*)
     1445                        '''
    12331446                # Check if  FullBlogPlugin is installed
    12341447                #
    12351448                blog_enabled = None
     1449                blog_regex = ''
    12361450                if self.get_config('components', 'tracfullblog.*') in ['enabled']:
    12371451                        blog_enabled = True
    1238 
    1239                 if not m['Subject']:
    1240                         subject  = 'No Subject'
    1241                 else:
    1242                         subject  = self.email_to_unicode(m['Subject'])         
    1243 
    1244                 #
    1245                 # [hic] #1529: Re: LRZ
    1246                 # [hic] #1529?owner=bas,priority=medium: Re: LRZ
    1247                 #
    1248                 TICKET_RE = re.compile(r"""
    1249                         (?P<blog>blog:(?P<blog_id>\w*))
    1250                         |(?P<new_fields>[#][?].*)
    1251                         |(?P<reply>[#][\d]+:)
    1252                         |(?P<reply_fields>[#][\d]+\?.*?:)
    1253                         """, re.VERBOSE)
    1254 
    1255                 # Find out if this is a ticket or a blog
    1256                 #
    1257                 result =  TICKET_RE.search(subject)
    1258 
     1452                        blog_regex = '''|(?P<blog>blog:(?P<blog_id>\w*))'''
     1453
     1454
     1455                # Check if DiscussionPlugin is installed
     1456                #
     1457                discussion_enabled = None
     1458                discussion_regex = ''
     1459                if self.get_config('components', 'tracdiscussion.api.*') in ['enabled']:
     1460                        discussion_enabled = True
     1461                        discussion_regex = r'''
     1462                        |(?P<forum>Forum[ ][#](?P<forum_id>\d+)[ ]-[ ]?)
     1463                        |(?P<topic>Topic[ ][#](?P<topic_id>\d+)[ ]-[ ]?)
     1464                        |(?P<message>Message[ ][#](?P<message_id>\d+)[ ]-[ ]?)
     1465                        '''
     1466
     1467
     1468                regex_str = ticket_regex + blog_regex + discussion_regex
     1469                SYSTEM_RE = re.compile(regex_str, re.VERBOSE)
     1470
     1471                # Find out if this is a ticket, a blog or a discussion
     1472                #
     1473                result =  SYSTEM_RE.search(subject)
    12591474                if result:
    1260                         if result.group('blog'):
    1261                                 if blog_enabled:
     1475                        # update ticket + fields
     1476                        #
     1477                        if result.group('reply') and self.TICKET_UPDATE:
     1478                                self.system = 'ticket'
     1479                                self.ticket_update(m, result.group('reply'), spam_msg)
     1480
     1481                        # New ticket + fields
     1482                        #
     1483                        elif result.group('new_fields'):
     1484                                self.system = 'ticket'
     1485                                self.new_ticket(m, subject[:result.start('new_fields')], spam_msg, result.group('new_fields'))
     1486
     1487                        if blog_enabled:
     1488                                if result.group('blog'):
     1489                                        self.system = 'blog'
    12621490                                        self.blog(result.group('blog_id'))
    1263                                 else:
    1264                                         if self.DEBUG:
    1265                                                 print "Fullblog plugin is not installed"
    1266                                                 return
    1267 
    1268                         # update ticket + fields
    1269                         #
    1270                         if result.group('reply_fields') and self.TICKET_UPDATE:
    1271                                 self.ticket_update(m, result.group('reply_fields'), spam_msg)
    1272 
    1273                         # Update ticket
    1274                         #
    1275                         elif result.group('reply') and self.TICKET_UPDATE:
    1276                                 self.ticket_update(m, result.group('reply'), spam_msg)
    1277 
    1278                         # New ticket + fields
    1279                         #
    1280                         elif result.group('new_fields'):
    1281                                 self.new_ticket(m, subject[:result.start('new_fields')], spam_msg, result.group('new_fields'))
    1282 
    1283                 else:
     1491
     1492                        if discussion_enabled:
     1493                                # New topic.
     1494                                #
     1495                                if result.group('forum'):
     1496                                        self.system = 'discussion'
     1497                                        self.id = int(result.group('forum_id'))
     1498                                        self.discussion_topic(m, subject[result.end('forum'):])
     1499
     1500                                # Reply to topic.
     1501                                #
     1502                                elif result.group('topic'):
     1503                                        self.system = 'discussion'
     1504                                        self.id = int(result.group('topic_id'))
     1505                                        self.discussion_topic_reply(m, subject[result.end('topic'):])
     1506
     1507                                # Reply to topic message.
     1508                                #
     1509                                elif result.group('message'):
     1510                                        self.system = 'discussion'
     1511                                        self.id = int(result.group('message_id'))
     1512                                        self.discussion_message_reply(m, subject[result.end('message'):])
     1513
     1514                else:
     1515                        self.system = 'ticket'
    12841516                        result = self.ticket_update_by_subject(subject)
    12851517                        if result:
     
    16011833
    16021834                if self.DEBUG:
    1603                         s = 'TD: attachment already exists: Ticket id : '
     1835                        s = 'TD: attachment already exists: Id : '
    16041836                        try:
    1605                                 print "%s%s, Filename : %s" %(s, self.id, filename)
     1837                                print "%s%s, Filename : %s" % (s, self.id, filename)
    16061838                        except UnicodeEncodeError, detail:
    16071839                                print "%s%s, Filename : Can not be printed due to non-ascii characters" %(s, self.id)
     
    16131845
    16141846                try:
    1615                         att = attachment.Attachment(self.env, 'ticket', self.id, filename)
     1847                        if self.system == 'discussion':
     1848                                att = attachment.Attachment(self.env, 'discussion', 'ticket/%s'
     1849                                  % (self.id,), filename)
     1850                        else:
     1851                                att = attachment.Attachment(self.env, 'ticket', self.id,
     1852                                  filename)
    16161853                        return True
    16171854                except attachment.ResourceNotFound:
     
    16341871                       
    16351872                        if part.get_content_maintype() == 'image' and inline:
    1636                                 body_text.append('[[Image(%s)]]' % filename)
     1873                                if self.system != 'discussion':
     1874                                        body_text.append('[[Image(%s)]]' % filename)
    16371875                                body_text.append("")
    16381876                        else:
    1639                                 body_text.append('[attachment:"%s"]' % filename)
     1877                                if self.system != 'discussion':
     1878                                        body_text.append('[attachment:"%s"]' % filename)
    16401879                                body_text.append("")
    16411880                               
     
    17491988
    17501989        ENABLE_SYSLOG = 0
    1751 
    17521990
    17531991        SHORT_OPT = 'chf:np:t:v'
     
    18232061                        from trac.ticket.notification import TicketNotifyEmail
    18242062                        from trac import config as trac_config
     2063                        from trac.core import TracError
     2064
    18252065                elif version == '0.11':
    18262066                        from trac import attachment
     
    18302070                        from trac import config as trac_config
    18312071                        from trac import util
     2072                        from trac.core import TracError
    18322073
    18332074
     
    18522093                        os.environ['PYTHON_EGG_CACHE'] = python_egg_cache
    18532094
     2095       
     2096                if int(settings['debug']) > 0:
     2097                        print 'Loading environment', settings['project']
     2098
    18542099                env = Environment(settings['project'], create=0)
    18552100
Note: See TracChangeset for help on using the changeset viewer.