##// END OF EJS Templates
integrations: update emails integration with nicer emails
marcink -
r650:6e54c581 default
parent child Browse files
Show More
@@ -1,127 +1,222 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 from __future__ import unicode_literals
21 from __future__ import unicode_literals
22
23 import deform
22 import deform
24 import logging
23 import logging
25 import colander
24 import colander
26
25
27 from mako.template import Template
26 from mako.template import Template
28
27
29 from rhodecode import events
28 from rhodecode import events
30 from rhodecode.translation import _, lazy_ugettext
29 from rhodecode.translation import _, lazy_ugettext
31 from rhodecode.lib.celerylib import run_task
30 from rhodecode.lib.celerylib import run_task
32 from rhodecode.lib.celerylib import tasks
31 from rhodecode.lib.celerylib import tasks
33 from rhodecode.integrations.types.base import IntegrationTypeBase
32 from rhodecode.integrations.types.base import IntegrationTypeBase
34 from rhodecode.integrations.schema import IntegrationSettingsSchemaBase
33 from rhodecode.integrations.schema import IntegrationSettingsSchemaBase
35
34
36
35
37 log = logging.getLogger()
36 log = logging.getLogger(__name__)
37
38 repo_push_template_plaintext = Template('''
39 Commits:
40
41 % for commit in data['push']['commits']:
42 ${commit['url']} by ${commit['author']} at ${commit['date']}
43 ${commit['message']}
44 ----
45
46 % endfor
47 ''')
48
49 ## TODO (marcink): think about putting this into a file, or use base.mako email template
50
51 repo_push_template_html = Template('''
52 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
53 <html xmlns="http://www.w3.org/1999/xhtml">
54 <head>
55 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
56 <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
57 <title>${subject}</title>
58 <style type="text/css">
59 /* Based on The MailChimp Reset INLINE: Yes. */
60 #outlook a {padding:0;} /* Force Outlook to provide a "view in browser" menu link. */
61 body{width:100% !important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0;}
62 /* Prevent Webkit and Windows Mobile platforms from changing default font sizes.*/
63 .ExternalClass {width:100%;} /* Force Hotmail to display emails at full width */
64 .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {line-height: 100%;}
65 /* Forces Hotmail to display normal line spacing. More on that: http://www.emailonacid.com/forum/viewthread/43/ */
66 #backgroundTable {margin:0; padding:0; line-height: 100% !important;}
67 /* End reset */
68
69 /* defaults for images*/
70 img {outline:none; text-decoration:none; -ms-interpolation-mode: bicubic;}
71 a img {border:none;}
72 .image_fix {display:block;}
73
74 body {line-height:1.2em;}
75 p {margin: 0 0 20px;}
76 h1, h2, h3, h4, h5, h6 {color:#323232!important;}
77 a {color:#427cc9;text-decoration:none;outline:none;cursor:pointer;}
78 a:focus {outline:none;}
79 a:hover {color: #305b91;}
80 h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {color:#427cc9!important;text-decoration:none!important;}
81 h1 a:active, h2 a:active, h3 a:active, h4 a:active, h5 a:active, h6 a:active {color: #305b91!important;}
82 h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited {color: #305b91!important;}
83 table {font-size:13px;border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;}
84 table td {padding:.65em 1em .65em 0;border-collapse:collapse;vertical-align:top;text-align:left;}
85 input {display:inline;border-radius:2px;border-style:solid;border: 1px solid #dbd9da;padding:.5em;}
86 input:focus {outline: 1px solid #979797}
87 @media only screen and (-webkit-min-device-pixel-ratio: 2) {
88 /* Put your iPhone 4g styles in here */
89 }
38
90
91 /* Android targeting */
92 @media only screen and (-webkit-device-pixel-ratio:.75){
93 /* Put CSS for low density (ldpi) Android layouts in here */
94 }
95 @media only screen and (-webkit-device-pixel-ratio:1){
96 /* Put CSS for medium density (mdpi) Android layouts in here */
97 }
98 @media only screen and (-webkit-device-pixel-ratio:1.5){
99 /* Put CSS for high density (hdpi) Android layouts in here */
100 }
101 /* end Android targeting */
102
103 </style>
104
105 <!-- Targeting Windows Mobile -->
106 <!--[if IEMobile 7]>
107 <style type="text/css">
108
109 </style>
110 <![endif]-->
111
112 <!--[if gte mso 9]>
113 <style>
114 /* Target Outlook 2007 and 2010 */
115 </style>
116 <![endif]-->
117 </head>
118 <body>
119 <!-- Wrapper/Container Table: Use a wrapper table to control the width and the background color consistently of your email. Use this approach instead of setting attributes on the body tag. -->
120 <table cellpadding="0" cellspacing="0" border="0" id="backgroundTable" align="left" style="margin:1%;width:97%;padding:0;font-family:sans-serif;font-weight:100;border:1px solid #dbd9da">
121 <tr>
122 <td valign="top" style="padding:0;">
123 <table cellpadding="0" cellspacing="0" border="0" align="left" width="100%">
124 <tr><td style="width:100%;padding:7px;background-color:#202020" valign="top">
125 <a style="color:#eeeeee;text-decoration:none;" href="${instance_url}">
126 ${'RhodeCode'}
127 </a>
128 </td></tr>
129 <tr>
130 <td style="padding:15px;" valign="top">
131 % for commit in data['push']['commits']:
132 <a href="${commit['url']}">${commit['short_id']}</a> by ${commit['author']} at ${commit['date']} <br/>
133 ${commit['message_html']} <br/>
134 <br/>
135 % endfor
136 </td>
137 </tr>
138 </table>
139 </td>
140 </tr>
141 </table>
142 <!-- End of wrapper table -->
143 <p><a style="margin-top:15px;margin-left:1%;font-family:sans-serif;font-weight:100;font-size:11px;color:#666666;text-decoration:none;" href="${instance_url}">
144 ${'This is a notification from RhodeCode. %(instance_url)s' % {'instance_url': instance_url}}
145 </a></p>
146 </body>
147 </html>
148 ''')
39
149
40
150
41 class EmailSettingsSchema(IntegrationSettingsSchemaBase):
151 class EmailSettingsSchema(IntegrationSettingsSchemaBase):
42 @colander.instantiate(validator=colander.Length(min=1))
152 @colander.instantiate(validator=colander.Length(min=1))
43 class recipients(colander.SequenceSchema):
153 class recipients(colander.SequenceSchema):
44 title = lazy_ugettext('Recipients')
154 title = lazy_ugettext('Recipients')
45 description = lazy_ugettext('Email addresses to send push events to')
155 description = lazy_ugettext('Email addresses to send push events to')
46 widget = deform.widget.SequenceWidget(min_len=1)
156 widget = deform.widget.SequenceWidget(min_len=1)
47
157
48 recipient = colander.SchemaNode(
158 recipient = colander.SchemaNode(
49 colander.String(),
159 colander.String(),
50 title=lazy_ugettext('Email address'),
160 title=lazy_ugettext('Email address'),
51 description=lazy_ugettext('Email address'),
161 description=lazy_ugettext('Email address'),
52 default='',
162 default='',
53 validator=colander.Email(),
163 validator=colander.Email(),
54 widget=deform.widget.TextInputWidget(
164 widget=deform.widget.TextInputWidget(
55 placeholder='user@domain.com',
165 placeholder='user@domain.com',
56 ),
166 ),
57 )
167 )
58
168
59
169
60 class EmailIntegrationType(IntegrationTypeBase):
170 class EmailIntegrationType(IntegrationTypeBase):
61 key = 'email'
171 key = 'email'
62 display_name = lazy_ugettext('Email')
172 display_name = lazy_ugettext('Email')
63 SettingsSchema = EmailSettingsSchema
173 SettingsSchema = EmailSettingsSchema
64
174
65 def settings_schema(self):
175 def settings_schema(self):
66 schema = EmailSettingsSchema()
176 schema = EmailSettingsSchema()
67 return schema
177 return schema
68
178
69 def send_event(self, event):
179 def send_event(self, event):
70 data = event.as_dict()
180 data = event.as_dict()
71 log.debug('got event: %r', event)
181 log.debug('got event: %r', event)
72
182
73 if isinstance(event, events.RepoPushEvent):
183 if isinstance(event, events.RepoPushEvent):
74 repo_push_handler(data, self.settings)
184 repo_push_handler(data, self.settings)
75 else:
185 else:
76 log.debug('ignoring event: %r', event)
186 log.debug('ignoring event: %r', event)
77
187
78
188
79 def repo_push_handler(data, settings):
189 def repo_push_handler(data, settings):
80 for commit in data['push']['commits']:
190 commit_num = len(data['push']['commits'])
81 email_body_plaintext = repo_push_template_plaintext.render(
191 server_url = data['server_url']
82 data=data,
83 commit=commit,
84 commit_msg=commit['message'],
85 )
86 email_body_html = repo_push_template_html.render(
87 data=data,
88 commit=commit,
89 commit_msg=commit['message_html'],
90 )
91
92 subject = '[%(repo_name)s] %(commit_id)s: %(commit_msg)s' % {
93 'repo_name': data['repo']['repo_name'],
94 'commit_id': commit['short_id'],
95 'commit_msg': commit['message'].split('\n')[0][:150]
96 }
97 for email_address in settings['recipients']:
98 task = run_task(
99 tasks.send_email, email_address, subject,
100 email_body_plaintext, email_body_html)
101
102
192
103 # TODO: dan: add changed files, make html pretty
193 if commit_num == 0:
104 repo_push_template_plaintext = Template('''
194 subject = '[{repo_name}] {author} pushed {commit_num} commit on branches: {branches}'.format(
105 User: ${data['actor']['username']}
195 author=data['actor']['username'],
106 Branches: ${', '.join(branch['name'] for branch in data['push']['branches'])}
196 repo_name=data['repo']['repo_name'],
107 Repository: ${data['repo']['url']}
197 commit_num=commit_num,
108 Commit: ${commit['raw_id']}
198 branches=', '.join(
109 URL: ${commit['url']}
199 branch['name'] for branch in data['push']['branches'])
110 Author: ${commit['author']}
200 )
111 Date: ${commit['date']}
201 else:
112 Commit Message:
202 subject = '[{repo_name}] {author} pushed {commit_num} commits on branches: {branches}'.format(
203 author=data['actor']['username'],
204 repo_name=data['repo']['repo_name'],
205 commit_num=commit_num,
206 branches=', '.join(
207 branch['name'] for branch in data['push']['branches']))
113
208
114 ${commit_msg}
209 email_body_plaintext = repo_push_template_plaintext.render(
115 ''')
210 data=data,
211 subject=subject,
212 instance_url=server_url)
116
213
117 repo_push_template_html = Template('''
214 email_body_html = repo_push_template_html.render(
118 User: ${data['actor']['username']}<br>
215 data=data,
119 Branches: ${', '.join(branch['name'] for branch in data['push']['branches'])}<br>
216 subject=subject,
120 Repository: ${data['repo']['url']}<br>
217 instance_url=server_url)
121 Commit: ${commit['raw_id']}<br>
218
122 URL: ${commit['url']}<br>
219 for email_address in settings['recipients']:
123 Author: ${commit['author']}<br>
220 run_task(
124 Date: ${commit['date']}<br>
221 tasks.send_email, email_address, subject,
125 Commit Message:<br>
222 email_body_plaintext, email_body_html)
126 <p>${commit_msg}</p>
127 ''')
General Comments 0
You need to be logged in to leave comments. Login now