source: trunk/trac-hacks/announcerplugin/announcerplugin/formatters/ticket_email.py @ 745

Revision 745, 7.1 KB checked in by rcorsaro, 4 years ago (diff)

merged latest announcer trac-hacks commits

Line 
1from trac.core import Component, implements
2from announcerplugin.api import IAnnouncementFormatter
3from trac.config import Option, IntOption, ListOption
4from genshi.template import NewTextTemplate, MarkupTemplate
5from genshi import HTML
6from trac.web.href import Href
7from trac.web.chrome import Chrome
8from genshi.template import TemplateLoader
9from trac.util.text import wrap
10from trac.versioncontrol.diff import diff_blocks
11import difflib
12
13def diff_cleanup(gen):
14    for value in gen:
15        if value.startswith('---'):
16            continue
17       
18        if value.startswith('+++'):
19            continue
20           
21        if value.startswith('@@'):
22            yield '\n'
23        else:
24            yield value
25
26def lineup(gen):
27    for value in gen:
28        yield ' ' + value
29
30class TicketEmailFormatter(Component):
31    implements(IAnnouncementFormatter)
32       
33    ticket_email_subject = Option('announcer', 'ticket_email_subject', 
34        "Ticket #${ticket.id}: ${ticket['summary']} {% if action %}[${action}]{% end %}")
35   
36    ticket_email_header_fields = ListOption('announcer', 'ticket_email_header_fields', 'owner, reporter, milestone, priority, severity')
37   
38    def get_format_transport(self):
39        return "email"
40       
41    def get_format_realms(self, transport):
42        if transport == "email":
43            yield "ticket"
44        return
45       
46    def get_format_styles(self, transport, realm):
47        if transport == "email":
48            if realm == "ticket":
49                yield "text/plain"
50                yield "text/html"
51               
52        return
53       
54    def get_format_alternative(self, transport, realm, style):
55        if transport == "email":
56            if realm == "ticket":
57                if style == "text/html":
58                    return "text/plain"
59
60        return None
61       
62    def format_headers(self, transport, realm, style, event):
63        ticket = event.target
64        return dict(
65            realm=realm,
66            ticket=ticket.id,
67            priority=ticket['priority'],
68            severity=ticket['severity']           
69        )
70       
71    def format_subject(self, transport, realm, style, event):
72        action = None
73        if transport == "email":
74            if realm == "ticket":
75                if event.changes:
76                    if 'status' in event.changes:
77                        action = 'Status -> %s' % (event.target['status'])
78                       
79                template = NewTextTemplate(self.ticket_email_subject)
80                return template.generate(ticket=event.target, event=event, action=action).render()
81               
82    def format(self, transport, realm, style, event):
83        if transport == "email":
84            if realm == "ticket":
85                if style == "text/plain":
86                    return self._format_plaintext(event)
87                elif style == "text/html":
88                    return self._format_html(event)
89
90    def _format_plaintext(self, event):
91        ticket = event.target
92        short_changes = {}
93        long_changes = {}
94       
95        changed_items = [(field, unicode(old_value)) for field, old_value in 
96            event.changes.items()]
97        for field, old_value in changed_items:
98            new_value = unicode(ticket[field])
99            if ('\n' in new_value) or ('\n' in old_value):
100                # long_changes[field.capitalize()] = \
101                # '\n'.join(
102                #     diff_cleanup(
103                #         difflib.context_diff(
104                #             old_value.split('\r\n'), new_value.split('\r\n'),
105                #             lineterm='', n=2
106                #         )
107                #     )
108                # )
109                long_changes[field.capitalize()] = '\n'.join(
110                    lineup(
111                        wrap(new_value, cols=67).split('\n')
112                    )
113                )
114            else:
115                short_changes[field.capitalize()] = (old_value, new_value)
116       
117        data = dict(
118            ticket = ticket,
119            author = event.author,
120            comment = event.comment,
121            header = self.ticket_email_header_fields,
122            category = event.category,
123            ticket_link = self.env.abs_href('ticket', ticket.id),
124            project_name = self.env.project_name,
125            project_desc = self.env.project_description,
126            project_link = self.env.project_url or self.env.abs_href(),
127            has_changes = short_changes or long_changes,
128            long_changes = long_changes,
129            short_changes = short_changes,
130            attachment= event.attachment
131        )
132       
133        chrome = Chrome(self.env)       
134        dirs = []
135        for provider in chrome.template_providers:
136            dirs += provider.get_templates_dirs()
137
138        templates = TemplateLoader(dirs, variable_lookup='lenient')
139
140        template = templates.load('ticket_email_plaintext.txt', cls=NewTextTemplate)
141
142        if template:
143            stream = template.generate(**data)
144            output = stream.render('text')
145
146        return output
147       
148    def _format_html(self, event):
149        ticket = event.target
150        short_changes = {}
151        long_changes = {}
152        chrome = Chrome(self.env)       
153       
154        for field, old_value in event.changes.items():
155            new_value = ticket[field]
156            if ('\n' in new_value) or ('\n' in old_value):
157                long_changes[field.capitalize()] = HTML(
158                    "<pre>\n%s\n</pre>" % (
159                        '\n'.join(
160                            diff_cleanup(
161                                difflib.unified_diff(
162                                    wrap(old_value, cols=60).split('\n'), 
163                                    wrap(new_value, cols=60).split('\n'),
164                                    lineterm='', n=3
165                                )
166                            )
167                        )
168                    )
169                )
170
171            else:
172                short_changes[field.capitalize()] = (old_value, new_value)
173
174        data = dict(
175            ticket = ticket,
176            author = event.author,
177            header = self.ticket_email_header_fields,
178            comment = event.comment,
179            category = event.category,
180            ticket_link = self.env.abs_href('ticket', ticket.id),
181            project_name = self.env.project_name,
182            project_desc = self.env.project_description,
183            project_link = self.env.project_url or self.env.abs_href(),
184            has_changes = short_changes or long_changes,
185            long_changes = long_changes,
186            short_changes = short_changes,
187            attachment= event.attachment
188        )
189       
190        chrome = Chrome(self.env)
191        dirs = []
192        for provider in chrome.template_providers:
193            dirs += provider.get_templates_dirs()
194       
195        templates = TemplateLoader(dirs, variable_lookup='lenient')
196       
197        template = templates.load('ticket_email_mimic.html', cls=MarkupTemplate)
198       
199        if template:
200            stream = template.generate(**data)
201            output = stream.render()
202       
203        return output
Note: See TracBrowser for help on using the repository browser.