##// END OF EJS Templates
emails: improved styling, and fixed problems with some email clients...
ergo -
r4377:a2405083 stable
parent child Browse files
Show More
@@ -1,402 +1,419 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2020 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import os
22 22 import logging
23 23 import datetime
24 24
25 25 from pyramid.view import view_config
26 26 from pyramid.renderers import render_to_response
27 27 from rhodecode.apps._base import BaseAppView
28 28 from rhodecode.lib.celerylib import run_task, tasks
29 29 from rhodecode.lib.utils2 import AttributeDict
30 30 from rhodecode.model.db import User
31 31 from rhodecode.model.notification import EmailNotificationModel
32 32
33 33 log = logging.getLogger(__name__)
34 34
35 35
36 36 class DebugStyleView(BaseAppView):
37 37 def load_default_context(self):
38 38 c = self._get_local_tmpl_context()
39 39
40 40 return c
41 41
42 42 @view_config(
43 43 route_name='debug_style_home', request_method='GET',
44 44 renderer=None)
45 45 def index(self):
46 46 c = self.load_default_context()
47 47 c.active = 'index'
48 48
49 49 return render_to_response(
50 50 'debug_style/index.html', self._get_template_context(c),
51 51 request=self.request)
52 52
53 53 @view_config(
54 54 route_name='debug_style_email', request_method='GET',
55 55 renderer=None)
56 56 @view_config(
57 57 route_name='debug_style_email_plain_rendered', request_method='GET',
58 58 renderer=None)
59 59 def render_email(self):
60 60 c = self.load_default_context()
61 61 email_id = self.request.matchdict['email_id']
62 62 c.active = 'emails'
63 63
64 64 pr = AttributeDict(
65 65 pull_request_id=123,
66 66 title='digital_ocean: fix redis, elastic search start on boot, '
67 67 'fix fd limits on supervisor, set postgres 11 version',
68 68 description='''
69 69 Check if we should use full-topic or mini-topic.
70 70
71 71 - full topic produces some problems with merge states etc
72 72 - server-mini-topic needs probably tweeks.
73 73 ''',
74 74 repo_name='foobar',
75 75 source_ref_parts=AttributeDict(type='branch', name='fix-ticket-2000'),
76 76 target_ref_parts=AttributeDict(type='branch', name='master'),
77 77 )
78 78 target_repo = AttributeDict(repo_name='repo_group/target_repo')
79 79 source_repo = AttributeDict(repo_name='repo_group/source_repo')
80 80 user = User.get_by_username(self.request.GET.get('user')) or self._rhodecode_db_user
81 81 # file/commit changes for PR update
82 82 commit_changes = AttributeDict({
83 83 'added': ['aaaaaaabbbbb', 'cccccccddddddd'],
84 84 'removed': ['eeeeeeeeeee'],
85 85 })
86 86 file_changes = AttributeDict({
87 87 'added': ['a/file1.md', 'file2.py'],
88 88 'modified': ['b/modified_file.rst'],
89 89 'removed': ['.idea'],
90 90 })
91 91
92 92 exc_traceback = {
93 93 'exc_utc_date': '2020-03-26T12:54:50.683281',
94 94 'exc_id': 139638856342656,
95 95 'exc_timestamp': '1585227290.683288',
96 96 'version': 'v1',
97 97 'exc_message': 'Traceback (most recent call last):\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/tweens.py", line 41, in excview_tween\n response = handler(request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/router.py", line 148, in handle_request\n registry, request, context, context_iface, view_name\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/view.py", line 667, in _call_view\n response = view_callable(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/config/views.py", line 188, in attr_view\n return view(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/config/views.py", line 214, in predicate_wrapper\n return view(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/viewderivers.py", line 401, in viewresult_to_response\n result = view(context, request)\n File "/nix/store/s43k2r9rysfbzmsjdqnxgzvvb7zjhkxb-python2.7-pyramid-1.10.4/lib/python2.7/site-packages/pyramid/viewderivers.py", line 132, in _class_view\n response = getattr(inst, attr)()\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/apps/debug_style/views.py", line 355, in render_email\n template_type, **email_kwargs.get(email_id, {}))\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/model/notification.py", line 402, in render_email\n body = email_template.render(None, **_kwargs)\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/lib/partial_renderer.py", line 95, in render\n return self._render_with_exc(tmpl, args, kwargs)\n File "/mnt/hgfs/marcink/workspace/rhodecode-enterprise-ce/rhodecode/lib/partial_renderer.py", line 79, in _render_with_exc\n return render_func.render(*args, **kwargs)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/template.py", line 476, in render\n return runtime._render(self, self.callable_, args, data)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/runtime.py", line 883, in _render\n **_kwargs_for_callable(callable_, data)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/runtime.py", line 920, in _render_context\n _exec_template(inherit, lclcontext, args=args, kwargs=kwargs)\n File "/nix/store/dakh34sxz4yfr435c0cwjz0sd6hnd5g3-python2.7-mako-1.1.0/lib/python2.7/site-packages/mako/runtime.py", line 947, in _exec_template\n callable_(context, *args, **kwargs)\n File "rhodecode_templates_email_templates_base_mako", line 63, in render_body\n File "rhodecode_templates_email_templates_exception_tracker_mako", line 43, in render_body\nAttributeError: \'str\' object has no attribute \'get\'\n',
98 98 'exc_type': 'AttributeError'
99 99 }
100 100 email_kwargs = {
101 101 'test': {},
102 102 'message': {
103 103 'body': 'message body !'
104 104 },
105 105 'email_test': {
106 106 'user': user,
107 107 'date': datetime.datetime.now(),
108 108 },
109 109 'exception': {
110 110 'email_prefix': '[RHODECODE ERROR]',
111 111 'exc_id': exc_traceback['exc_id'],
112 112 'exc_url': 'http://server-url/{}'.format(exc_traceback['exc_id']),
113 113 'exc_type_name': 'NameError',
114 114 'exc_traceback': exc_traceback,
115 115 },
116 116 'password_reset': {
117 117 'password_reset_url': 'http://example.com/reset-rhodecode-password/token',
118 118
119 119 'user': user,
120 120 'date': datetime.datetime.now(),
121 121 'email': 'test@rhodecode.com',
122 122 'first_admin_email': User.get_first_super_admin().email
123 123 },
124 124 'password_reset_confirmation': {
125 125 'new_password': 'new-password-example',
126 126 'user': user,
127 127 'date': datetime.datetime.now(),
128 128 'email': 'test@rhodecode.com',
129 129 'first_admin_email': User.get_first_super_admin().email
130 130 },
131 131 'registration': {
132 132 'user': user,
133 133 'date': datetime.datetime.now(),
134 134 },
135 135
136 136 'pull_request_comment': {
137 137 'user': user,
138 138
139 139 'status_change': None,
140 140 'status_change_type': None,
141 141
142 142 'pull_request': pr,
143 143 'pull_request_commits': [],
144 144
145 145 'pull_request_target_repo': target_repo,
146 146 'pull_request_target_repo_url': 'http://target-repo/url',
147 147
148 148 'pull_request_source_repo': source_repo,
149 149 'pull_request_source_repo_url': 'http://source-repo/url',
150 150
151 151 'pull_request_url': 'http://localhost/pr1',
152 152 'pr_comment_url': 'http://comment-url',
153 153 'pr_comment_reply_url': 'http://comment-url#reply',
154 154
155 155 'comment_file': None,
156 156 'comment_line': None,
157 157 'comment_type': 'note',
158 158 'comment_body': 'This is my comment body. *I like !*',
159 159 'comment_id': 2048,
160 160 'renderer_type': 'markdown',
161 161 'mention': True,
162 162
163 163 },
164 164 'pull_request_comment+status': {
165 165 'user': user,
166 166
167 167 'status_change': 'approved',
168 168 'status_change_type': 'approved',
169 169
170 170 'pull_request': pr,
171 171 'pull_request_commits': [],
172 172
173 173 'pull_request_target_repo': target_repo,
174 174 'pull_request_target_repo_url': 'http://target-repo/url',
175 175
176 176 'pull_request_source_repo': source_repo,
177 177 'pull_request_source_repo_url': 'http://source-repo/url',
178 178
179 179 'pull_request_url': 'http://localhost/pr1',
180 180 'pr_comment_url': 'http://comment-url',
181 181 'pr_comment_reply_url': 'http://comment-url#reply',
182 182
183 183 'comment_type': 'todo',
184 184 'comment_file': None,
185 185 'comment_line': None,
186 186 'comment_body': '''
187 187 I think something like this would be better
188 188
189 189 ```py
190 // markdown renderer
190 191
191 192 def db():
192 193 global connection
193 194 return connection
194 195
195 196 ```
196 197
197 198 ''',
198 199 'comment_id': 2048,
199 200 'renderer_type': 'markdown',
200 201 'mention': True,
201 202
202 203 },
203 204 'pull_request_comment+file': {
204 205 'user': user,
205 206
206 207 'status_change': None,
207 208 'status_change_type': None,
208 209
209 210 'pull_request': pr,
210 211 'pull_request_commits': [],
211 212
212 213 'pull_request_target_repo': target_repo,
213 214 'pull_request_target_repo_url': 'http://target-repo/url',
214 215
215 216 'pull_request_source_repo': source_repo,
216 217 'pull_request_source_repo_url': 'http://source-repo/url',
217 218
218 219 'pull_request_url': 'http://localhost/pr1',
219 220
220 221 'pr_comment_url': 'http://comment-url',
221 222 'pr_comment_reply_url': 'http://comment-url#reply',
222 223
223 224 'comment_file': 'rhodecode/model/get_flow_commits',
224 225 'comment_line': 'o1210',
225 226 'comment_type': 'todo',
226 227 'comment_body': '''
227 228 I like this !
228 229
229 But please check this code::
230
231 def main():
232 print 'ok'
230 But please check this code
231
232 .. code-block:: javascript
233
234 // THIS IS RST CODE
235
236 this.createResolutionComment = function(commentId) {
237 // hide the trigger text
238 $('#resolve-comment-{0}'.format(commentId)).hide();
239
240 var comment = $('#comment-'+commentId);
241 var commentData = comment.data();
242 if (commentData.commentInline) {
243 this.createComment(comment, commentId)
244 } else {
245 Rhodecode.comments.createGeneralComment('general', "$placeholder", commentId)
246 }
247
248 return false;
249 };
233 250
234 251 This should work better !
235 252 ''',
236 253 'comment_id': 2048,
237 254 'renderer_type': 'rst',
238 255 'mention': True,
239 256
240 257 },
241 258
242 259 'pull_request_update': {
243 260 'updating_user': user,
244 261
245 262 'status_change': None,
246 263 'status_change_type': None,
247 264
248 265 'pull_request': pr,
249 266 'pull_request_commits': [],
250 267
251 268 'pull_request_target_repo': target_repo,
252 269 'pull_request_target_repo_url': 'http://target-repo/url',
253 270
254 271 'pull_request_source_repo': source_repo,
255 272 'pull_request_source_repo_url': 'http://source-repo/url',
256 273
257 274 'pull_request_url': 'http://localhost/pr1',
258 275
259 276 # update comment links
260 277 'pr_comment_url': 'http://comment-url',
261 278 'pr_comment_reply_url': 'http://comment-url#reply',
262 279 'ancestor_commit_id': 'f39bd443',
263 280 'added_commits': commit_changes.added,
264 281 'removed_commits': commit_changes.removed,
265 282 'changed_files': (file_changes.added + file_changes.modified + file_changes.removed),
266 283 'added_files': file_changes.added,
267 284 'modified_files': file_changes.modified,
268 285 'removed_files': file_changes.removed,
269 286 },
270 287
271 288 'cs_comment': {
272 289 'user': user,
273 290 'commit': AttributeDict(idx=123, raw_id='a'*40, message='Commit message'),
274 291 'status_change': None,
275 292 'status_change_type': None,
276 293
277 294 'commit_target_repo_url': 'http://foo.example.com/#comment1',
278 295 'repo_name': 'test-repo',
279 296 'comment_type': 'note',
280 297 'comment_file': None,
281 298 'comment_line': None,
282 299 'commit_comment_url': 'http://comment-url',
283 300 'commit_comment_reply_url': 'http://comment-url#reply',
284 301 'comment_body': 'This is my comment body. *I like !*',
285 302 'comment_id': 2048,
286 303 'renderer_type': 'markdown',
287 304 'mention': True,
288 305 },
289 306 'cs_comment+status': {
290 307 'user': user,
291 308 'commit': AttributeDict(idx=123, raw_id='a' * 40, message='Commit message'),
292 309 'status_change': 'approved',
293 310 'status_change_type': 'approved',
294 311
295 312 'commit_target_repo_url': 'http://foo.example.com/#comment1',
296 313 'repo_name': 'test-repo',
297 314 'comment_type': 'note',
298 315 'comment_file': None,
299 316 'comment_line': None,
300 317 'commit_comment_url': 'http://comment-url',
301 318 'commit_comment_reply_url': 'http://comment-url#reply',
302 319 'comment_body': '''
303 320 Hello **world**
304 321
305 322 This is a multiline comment :)
306 323
307 324 - list
308 325 - list2
309 326 ''',
310 327 'comment_id': 2048,
311 328 'renderer_type': 'markdown',
312 329 'mention': True,
313 330 },
314 331 'cs_comment+file': {
315 332 'user': user,
316 333 'commit': AttributeDict(idx=123, raw_id='a' * 40, message='Commit message'),
317 334 'status_change': None,
318 335 'status_change_type': None,
319 336
320 337 'commit_target_repo_url': 'http://foo.example.com/#comment1',
321 338 'repo_name': 'test-repo',
322 339
323 340 'comment_type': 'note',
324 341 'comment_file': 'test-file.py',
325 342 'comment_line': 'n100',
326 343
327 344 'commit_comment_url': 'http://comment-url',
328 345 'commit_comment_reply_url': 'http://comment-url#reply',
329 346 'comment_body': 'This is my comment body. *I like !*',
330 347 'comment_id': 2048,
331 348 'renderer_type': 'markdown',
332 349 'mention': True,
333 350 },
334 351
335 352 'pull_request': {
336 353 'user': user,
337 354 'pull_request': pr,
338 355 'pull_request_commits': [
339 356 ('472d1df03bf7206e278fcedc6ac92b46b01c4e21', '''\
340 357 my-account: moved email closer to profile as it's similar data just moved outside.
341 358 '''),
342 359 ('cbfa3061b6de2696c7161ed15ba5c6a0045f90a7', '''\
343 360 users: description edit fixes
344 361
345 362 - tests
346 363 - added metatags info
347 364 '''),
348 365 ],
349 366
350 367 'pull_request_target_repo': target_repo,
351 368 'pull_request_target_repo_url': 'http://target-repo/url',
352 369
353 370 'pull_request_source_repo': source_repo,
354 371 'pull_request_source_repo_url': 'http://source-repo/url',
355 372
356 373 'pull_request_url': 'http://code.rhodecode.com/_pull-request/123',
357 374 }
358 375
359 376 }
360 377
361 378 template_type = email_id.split('+')[0]
362 379 (c.subject, c.headers, c.email_body,
363 380 c.email_body_plaintext) = EmailNotificationModel().render_email(
364 381 template_type, **email_kwargs.get(email_id, {}))
365 382
366 383 test_email = self.request.GET.get('email')
367 384 if test_email:
368 385 recipients = [test_email]
369 386 run_task(tasks.send_email, recipients, c.subject,
370 387 c.email_body_plaintext, c.email_body)
371 388
372 389 if self.request.matched_route.name == 'debug_style_email_plain_rendered':
373 390 template = 'debug_style/email_plain_rendered.mako'
374 391 else:
375 392 template = 'debug_style/email.mako'
376 393 return render_to_response(
377 394 template, self._get_template_context(c),
378 395 request=self.request)
379 396
380 397 @view_config(
381 398 route_name='debug_style_template', request_method='GET',
382 399 renderer=None)
383 400 def template(self):
384 401 t_path = self.request.matchdict['t_path']
385 402 c = self.load_default_context()
386 403 c.active = os.path.splitext(t_path)[0]
387 404 c.came_from = ''
388 405 c.email_types = {
389 406 'cs_comment+file': {},
390 407 'cs_comment+status': {},
391 408
392 409 'pull_request_comment+file': {},
393 410 'pull_request_comment+status': {},
394 411
395 412 'pull_request_update': {},
396 413 }
397 414 c.email_types.update(EmailNotificationModel.email_types)
398 415
399 416 return render_to_response(
400 417 'debug_style/' + t_path, self._get_template_context(c),
401 418 request=self.request)
402 419
@@ -1,603 +1,642 b''
1 1 ## -*- coding: utf-8 -*-
2 2
3 3 ## helpers
4 4 <%def name="tag_button(text, tag_type=None)">
5 5 <%
6 6 color_scheme = {
7 7 'default': 'border:1px solid #979797;color:#666666;background-color:#f9f9f9',
8 8 'approved': 'border:1px solid #0ac878;color:#0ac878;background-color:#f9f9f9',
9 9 'rejected': 'border:1px solid #e85e4d;color:#e85e4d;background-color:#f9f9f9',
10 10 'under_review': 'border:1px solid #ffc854;color:#ffc854;background-color:#f9f9f9',
11 11 }
12 12
13 13 css_style = ';'.join([
14 14 'display:inline',
15 15 'border-radius:2px',
16 16 'font-size:12px',
17 17 'padding:.2em',
18 18 ])
19 19
20 20 %>
21 21 <pre style="${css_style}; ${color_scheme.get(tag_type, color_scheme['default'])}">${text}</pre>
22 22 </%def>
23 23
24 24 <%def name="status_text(text, tag_type=None)">
25 25 <%
26 26 color_scheme = {
27 27 'default': 'color:#666666',
28 28 'approved': 'color:#0ac878',
29 29 'rejected': 'color:#e85e4d',
30 30 'under_review': 'color:#ffc854',
31 31 }
32 32 %>
33 33 <span style="font-weight:bold;font-size:12px;padding:.2em;${color_scheme.get(tag_type, color_scheme['default'])}">${text}</span>
34 34 </%def>
35 35
36 36 <%def name="gravatar_img(email, size=16)">
37 37 <%
38 38 css_style = ';'.join([
39 39 'padding: 0',
40 40 'margin: -4px 0',
41 41 'border-radius: 50%',
42 42 'box-sizing: content-box',
43 43 'display: inline',
44 44 'line-height: 1em',
45 45 'min-width: 16px',
46 46 'min-height: 16px',
47 47 ])
48 48 %>
49 49
50 50 <img alt="gravatar" style="${css_style}" src="${h.gravatar_url(email, size)}" height="${size}" width="${size}">
51 51 </%def>
52 52
53 53 <%def name="link_css()">\
54 54 <%
55 55 css_style = ';'.join([
56 56 'color:#427cc9',
57 57 'text-decoration:none',
58 58 'cursor:pointer'
59 59 ])
60 60 %>\
61 61 ${css_style}\
62 62 </%def>
63 63
64 64 ## Constants
65 65 <%
66 66 text_regular = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', Helvetica, sans-serif"
67 67 text_monospace = "'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace"
68 68
69 69 %>
70 70
71 71 ## headers we additionally can set for email
72 72 <%def name="headers()" filter="n,trim"></%def>
73 73
74 74 <%def name="plaintext_footer()" filter="trim">
75 75 ${_('This is a notification from RhodeCode.')} ${instance_url}
76 76 </%def>
77 77
78 78 <%def name="body_plaintext()" filter="n,trim">
79 79 ## this example is not called itself but overridden in each template
80 80 ## the plaintext_footer should be at the bottom of both html and text emails
81 81 ${self.plaintext_footer()}
82 82 </%def>
83 83
84 84 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
85 85 <html xmlns="http://www.w3.org/1999/xhtml">
86 86 <head>
87 87 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
88 88 <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
89 89 <title>${self.subject()}</title>
90 90 <style type="text/css">
91 91 /* Based on The MailChimp Reset INLINE: Yes. */
92 92 #outlook a {
93 93 padding: 0;
94 94 }
95 95
96 96 /* Force Outlook to provide a "view in browser" menu link. */
97 97 body {
98 98 width: 100% !important;
99 99 -webkit-text-size-adjust: 100%;
100 100 -ms-text-size-adjust: 100%;
101 101 margin: 0;
102 102 padding: 0;
103 103 font-family: ${text_regular|n};
104 color: #000000;
104 105 }
105 106
106 107 /* Prevent Webkit and Windows Mobile platforms from changing default font sizes.*/
107 108 .ExternalClass {
108 109 width: 100%;
109 110 }
110 111
111 112 /* Force Hotmail to display emails at full width */
112 113 .ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {
113 114 line-height: 100%;
114 115 }
115 116
116 117 /* Forces Hotmail to display normal line spacing. More on that: http://www.emailonacid.com/forum/viewthread/43/ */
117 118 #backgroundTable {
118 119 margin: 0;
119 120 padding: 0;
120 121 line-height: 100% !important;
121 122 }
122 123
123 124 /* End reset */
124 125
125 126 /* defaults for images*/
126 127 img {
127 128 outline: none;
128 129 text-decoration: none;
129 130 -ms-interpolation-mode: bicubic;
130 131 }
131 132
132 133 a img {
133 134 border: none;
134 135 }
135 136
136 137 .image_fix {
137 138 display: block;
138 139 }
139 140
140 141 body {
141 142 line-height: 1.2em;
142 143 }
143 144
144 145 p {
145 146 margin: 0 0 20px;
146 147 }
147 148
148 149 h1, h2, h3, h4, h5, h6 {
149 150 color: #323232 !important;
150 151 }
151 152
152 153 a {
153 154 color: #427cc9;
154 155 text-decoration: none;
155 156 outline: none;
156 157 cursor: pointer;
157 158 }
158 159
159 160 a:focus {
160 161 outline: none;
161 162 }
162 163
163 164 a:hover {
164 165 color: #305b91;
165 166 }
166 167
167 168 h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
168 169 color: #427cc9 !important;
169 170 text-decoration: none !important;
170 171 }
171 172
172 173 h1 a:active, h2 a:active, h3 a:active, h4 a:active, h5 a:active, h6 a:active {
173 174 color: #305b91 !important;
174 175 }
175 176
176 177 h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited {
177 178 color: #305b91 !important;
178 179 }
179 180
180 181 table {
181 182 font-size: 13px;
182 183 border-collapse: collapse;
183 184 mso-table-lspace: 0pt;
184 185 mso-table-rspace: 0pt;
185 186 }
186 187
187 188 table tr {
188 189 display: table-row;
189 190 vertical-align: inherit;
190 191 border-color: inherit;
191 192 border-spacing: 0 3px;
192 193 }
193 194
194 195 table td {
195 196 padding: .65em 1em .65em 0;
196 197 border-collapse: collapse;
197 198 vertical-align: top;
198 199 text-align: left;
199 200 }
200 201
201 202 input {
202 203 display: inline;
203 204 border-radius: 2px;
204 205 border: 1px solid #dbd9da;
205 206 padding: .5em;
206 207 }
207 208
208 209 input:focus {
209 210 outline: 1px solid #979797
210 211 }
211 212
212 213 code {
213 214 font-family: ${text_monospace|n};
215 white-space: pre-line !important;
216 color: #000000;
217 }
218
219 ul.changes-ul {
220 list-style: none;
221 list-style-type: none;
222 padding: 0;
223 margin: 10px 0;
224 }
225 ul.changes-ul li {
226 list-style: none;
227 list-style-type: none;
228 margin: 2px 0;
214 229 }
215 230
216 231 @media only screen and (-webkit-min-device-pixel-ratio: 2) {
217 232 /* Put your iPhone 4g styles in here */
218 233 }
219 234
220 235 /* Android targeting */
221 236 @media only screen and (-webkit-device-pixel-ratio:.75){
222 237 /* Put CSS for low density (ldpi) Android layouts in here */
223 238 }
224 239 @media only screen and (-webkit-device-pixel-ratio:1){
225 240 /* Put CSS for medium density (mdpi) Android layouts in here */
226 241 }
227 242 @media only screen and (-webkit-device-pixel-ratio:1.5){
228 243 /* Put CSS for high density (hdpi) Android layouts in here */
229 244 }
230 245 /* end Android targeting */
231 246
232 247 /** MARKDOWN styling **/
233 248 div.markdown-block {
234 249 clear: both;
235 250 overflow: hidden;
236 251 margin: 0;
237 252 padding: 3px 5px 3px
238 253 }
239 254
240 div.markdown-block h1, div.markdown-block h2, div.markdown-block h3, div.markdown-block h4, div.markdown-block h5, div.markdown-block h6 {
255 div.markdown-block h1,
256 div.markdown-block h2,
257 div.markdown-block h3,
258 div.markdown-block h4,
259 div.markdown-block h5,
260 div.markdown-block h6 {
241 261 border-bottom: none !important;
242 262 padding: 0 !important;
243 263 overflow: visible !important
244 264 }
245 265
246 div.markdown-block h1, div.markdown-block h2 {
266 div.markdown-block h1,
267 div.markdown-block h2 {
247 268 border-bottom: 1px #e6e5e5 solid !important
248 269 }
249 270
250 271 div.markdown-block h1 {
251 272 font-size: 32px;
252 273 margin: 15px 0 15px 0 !important;
253 274 padding-bottom: 5px !important
254 275 }
255 276
256 277 div.markdown-block h2 {
257 278 font-size: 24px !important;
258 279 margin: 34px 0 10px 0 !important;
259 280 padding-top: 15px !important;
260 281 padding-bottom: 8px !important
261 282 }
262 283
263 284 div.markdown-block h3 {
264 285 font-size: 18px !important;
265 286 margin: 30px 0 8px 0 !important;
266 287 padding-bottom: 2px !important
267 288 }
268 289
269 290 div.markdown-block h4 {
270 291 font-size: 13px !important;
271 292 margin: 18px 0 3px 0 !important
272 293 }
273 294
274 295 div.markdown-block h5 {
275 296 font-size: 12px !important;
276 297 margin: 15px 0 3px 0 !important
277 298 }
278 299
279 300 div.markdown-block h6 {
280 301 font-size: 12px;
281 302 color: #777777;
282 303 margin: 15px 0 3px 0 !important
283 304 }
284 305
285 306 div.markdown-block hr {
286 307 border: 0;
287 308 color: #e6e5e5;
288 309 background-color: #e6e5e5;
289 310 height: 3px;
290 311 margin-bottom: 13px
291 312 }
292 313
293 div.markdown-block ol, div.markdown-block ul, div.markdown-block p, div.markdown-block blockquote, div.markdown-block dl, div.markdown-block li, div.markdown-block table {
314 div.markdown-block ol,
315 div.markdown-block ul,
316 div.markdown-block p,
317 div.markdown-block blockquote,
318 div.markdown-block dl,
319 div.markdown-block li,
320 div.markdown-block table {
294 321 margin: 3px 0 13px 0 !important;
295 322 color: #424242 !important;
296 323 font-size: 13px !important;
297 324 font-family: ${text_regular|n};
298 325 font-weight: normal !important;
299 326 overflow: visible !important;
300 327 line-height: 140% !important
301 328 }
302 329
303 330 div.markdown-block pre {
304 331 margin: 3px 0 13px 0 !important;
305 332 padding: .5em;
306 333 color: #424242 !important;
307 334 font-size: 13px !important;
308 335 overflow: visible !important;
309 336 line-height: 140% !important;
310 337 background-color: #F5F5F5
311 338 }
312 339
313 340 div.markdown-block img {
314 341 border-style: none;
315 342 background-color: #fff;
316 343 padding-right: 20px;
317 344 max-width: 100%
318 345 }
319 346
320 347 div.markdown-block strong {
321 348 font-weight: 600;
322 349 margin: 0
323 350 }
324 351
325 352 div.markdown-block ul.checkbox, div.markdown-block ol.checkbox {
326 353 padding-left: 20px !important;
327 354 margin-top: 0 !important;
328 355 margin-bottom: 18px !important
329 356 }
330 357
331 358 div.markdown-block ul, div.markdown-block ol {
332 359 padding-left: 30px !important;
333 360 margin-top: 0 !important;
334 361 margin-bottom: 18px !important
335 362 }
336 363
337 364 div.markdown-block ul.checkbox li, div.markdown-block ol.checkbox li {
338 365 list-style: none !important;
339 366 margin: 6px !important;
340 367 padding: 0 !important
341 368 }
342 369
343 370 div.markdown-block ul li, div.markdown-block ol li {
344 371 list-style: disc !important;
345 372 margin: 6px !important;
346 373 padding: 0 !important
347 374 }
348 375
349 376 div.markdown-block ol li {
350 377 list-style: decimal !important
351 378 }
352 379
353 380 div.markdown-block #message {
354 381 -webkit-border-radius: 2px;
355 382 -moz-border-radius: 2px;
356 383 border-radius: 2px;
357 384 border: 1px solid #dbd9da;
358 385 display: block;
359 386 width: 100%;
360 387 height: 60px;
361 388 margin: 6px 0
362 389 }
363 390
364 391 div.markdown-block button, div.markdown-block #ws {
365 392 font-size: 13px;
366 393 padding: 4px 6px;
367 394 -webkit-border-radius: 2px;
368 395 -moz-border-radius: 2px;
369 396 border-radius: 2px;
370 397 border: 1px solid #dbd9da;
371 398 background-color: #eeeeee
372 399 }
373 400
374 div.markdown-block code, div.markdown-block pre, div.markdown-block #ws, div.markdown-block #message {
401 div.markdown-block code,
402 div.markdown-block pre,
403 div.markdown-block #ws,
404 div.markdown-block #message {
375 405 font-family: ${text_monospace|n};
376 406 font-size: 11px;
377 407 -webkit-border-radius: 2px;
378 408 -moz-border-radius: 2px;
379 409 border-radius: 2px;
380 background-color: white;
410 background-color: #FFFFFF;
381 411 color: #7E7F7F
382 412 }
383 413
384 414 div.markdown-block code {
385 border: 1px solid #eeeeee;
415 border: 1px solid #7E7F7F;
386 416 margin: 0 2px;
387 417 padding: 0 5px
388 418 }
389 419
390 420 div.markdown-block pre {
391 border: 1px solid #dbd9da;
421 border: 1px solid #7E7F7F;
392 422 overflow: auto;
393 423 padding: .5em;
394 background-color: #F5F5F5
424 background-color: #FFFFFF;
395 425 }
396 426
397 427 div.markdown-block pre > code {
398 428 border: 0;
399 429 margin: 0;
400 430 padding: 0
401 431 }
402 432
403 433 div.rst-block {
404 434 clear: both;
405 435 overflow: hidden;
406 436 margin: 0;
407 437 padding: 3px 5px 3px
408 438 }
409 439
410 440 div.rst-block h2 {
411 441 font-weight: normal
412 442 }
413 443
414 div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
444 div.rst-block h1,
445 div.rst-block h2,
446 div.rst-block h3,
447 div.rst-block h4,
448 div.rst-block h5,
449 div.rst-block h6 {
415 450 border-bottom: 0 !important;
416 451 margin: 0 !important;
417 452 padding: 0 !important;
418 453 line-height: 1.5em !important
419 454 }
420 455
421 456 div.rst-block h1:first-child {
422 457 padding-top: .25em !important
423 458 }
424 459
425 460 div.rst-block h2, div.rst-block h3 {
426 461 margin: 1em 0 !important
427 462 }
428 463
429 464 div.rst-block h1, div.rst-block h2 {
430 465 border-bottom: 1px #e6e5e5 solid !important
431 466 }
432 467
433 468 div.rst-block h2 {
434 469 margin-top: 1.5em !important;
435 470 padding-top: .5em !important
436 471 }
437 472
438 473 div.rst-block p {
439 474 color: black !important;
440 475 margin: 1em 0 !important;
441 476 line-height: 1.5em !important
442 477 }
443 478
444 479 div.rst-block ul {
445 480 list-style: disc !important;
446 481 margin: 1em 0 1em 2em !important;
447 482 clear: both
448 483 }
449 484
450 485 div.rst-block ol {
451 486 list-style: decimal;
452 487 margin: 1em 0 1em 2em !important
453 488 }
454 489
455 490 div.rst-block pre, div.rst-block code {
456 491 font: 12px "Bitstream Vera Sans Mono", "Courier", monospace
457 492 }
458 493
459 494 div.rst-block code {
460 495 font-size: 12px !important;
461 496 background-color: ghostWhite !important;
462 497 color: #444 !important;
463 498 padding: 0 .2em !important;
464 border: 1px solid #dedede !important
499 border: 1px solid #7E7F7F !important
465 500 }
466 501
467 502 div.rst-block pre code {
468 503 padding: 0 !important;
469 504 font-size: 12px !important;
470 505 background-color: #eee !important;
471 506 border: none !important
472 507 }
473 508
474 509 div.rst-block pre {
475 510 margin: 1em 0;
476 511 padding: 15px;
477 border: 1px solid #eeeeee;
512 border: 1px solid #7E7F7F;
478 513 -webkit-border-radius: 2px;
479 514 -moz-border-radius: 2px;
480 515 border-radius: 2px;
481 516 overflow: auto;
482 517 font-size: 12px;
483 518 color: #444;
484 background-color: #F5F5F5
519 background-color: #FFFFFF;
520 }
521
522 .clear-both {
523 clear:both;
485 524 }
486 525
487 526 /*elasticmatch is custom rhodecode tag*/
488 527 .codehilite .c-ElasticMatch {
489 background-color: #faffa6;
490 padding: 0.2em;
528 background-color: #faffa6;
529 padding: 0.2em;
491 530 }
492 531
493 532 .codehilite .c-ElasticMatch { background-color: #faffa6; padding: 0.2em;}
494 533 .codehilite .hll { background-color: #ffffcc }
495 534 .codehilite .c { color: #408080; font-style: italic } /* Comment */
496 535 .codehilite .err { border: none } /* Error */
497 536 .codehilite .k { color: #008000; font-weight: bold } /* Keyword */
498 537 .codehilite .o { color: #666666 } /* Operator */
499 538 .codehilite .ch { color: #408080; font-style: italic } /* Comment.Hashbang */
500 539 .codehilite .cm { color: #408080; font-style: italic } /* Comment.Multiline */
501 540 .codehilite .cp { color: #BC7A00 } /* Comment.Preproc */
502 541 .codehilite .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */
503 542 .codehilite .c1 { color: #408080; font-style: italic } /* Comment.Single */
504 543 .codehilite .cs { color: #408080; font-style: italic } /* Comment.Special */
505 544 .codehilite .gd { color: #A00000 } /* Generic.Deleted */
506 545 .codehilite .ge { font-style: italic } /* Generic.Emph */
507 546 .codehilite .gr { color: #FF0000 } /* Generic.Error */
508 547 .codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */
509 548 .codehilite .gi { color: #00A000 } /* Generic.Inserted */
510 549 .codehilite .go { color: #888888 } /* Generic.Output */
511 550 .codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
512 551 .codehilite .gs { font-weight: bold } /* Generic.Strong */
513 552 .codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
514 553 .codehilite .gt { color: #0044DD } /* Generic.Traceback */
515 554 .codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
516 555 .codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
517 556 .codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
518 557 .codehilite .kp { color: #008000 } /* Keyword.Pseudo */
519 558 .codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
520 559 .codehilite .kt { color: #B00040 } /* Keyword.Type */
521 560 .codehilite .m { color: #666666 } /* Literal.Number */
522 561 .codehilite .s { color: #BA2121 } /* Literal.String */
523 562 .codehilite .na { color: #7D9029 } /* Name.Attribute */
524 563 .codehilite .nb { color: #008000 } /* Name.Builtin */
525 564 .codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */
526 565 .codehilite .no { color: #880000 } /* Name.Constant */
527 566 .codehilite .nd { color: #AA22FF } /* Name.Decorator */
528 567 .codehilite .ni { color: #999999; font-weight: bold } /* Name.Entity */
529 568 .codehilite .ne { color: #D2413A; font-weight: bold } /* Name.Exception */
530 569 .codehilite .nf { color: #0000FF } /* Name.Function */
531 570 .codehilite .nl { color: #A0A000 } /* Name.Label */
532 571 .codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
533 572 .codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */
534 573 .codehilite .nv { color: #19177C } /* Name.Variable */
535 574 .codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
536 575 .codehilite .w { color: #bbbbbb } /* Text.Whitespace */
537 576 .codehilite .mb { color: #666666 } /* Literal.Number.Bin */
538 577 .codehilite .mf { color: #666666 } /* Literal.Number.Float */
539 578 .codehilite .mh { color: #666666 } /* Literal.Number.Hex */
540 579 .codehilite .mi { color: #666666 } /* Literal.Number.Integer */
541 580 .codehilite .mo { color: #666666 } /* Literal.Number.Oct */
542 581 .codehilite .sa { color: #BA2121 } /* Literal.String.Affix */
543 582 .codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */
544 583 .codehilite .sc { color: #BA2121 } /* Literal.String.Char */
545 584 .codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */
546 585 .codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
547 586 .codehilite .s2 { color: #BA2121 } /* Literal.String.Double */
548 587 .codehilite .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */
549 588 .codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */
550 589 .codehilite .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */
551 590 .codehilite .sx { color: #008000 } /* Literal.String.Other */
552 591 .codehilite .sr { color: #BB6688 } /* Literal.String.Regex */
553 592 .codehilite .s1 { color: #BA2121 } /* Literal.String.Single */
554 593 .codehilite .ss { color: #19177C } /* Literal.String.Symbol */
555 594 .codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */
556 595 .codehilite .fm { color: #0000FF } /* Name.Function.Magic */
557 596 .codehilite .vc { color: #19177C } /* Name.Variable.Class */
558 597 .codehilite .vg { color: #19177C } /* Name.Variable.Global */
559 598 .codehilite .vi { color: #19177C } /* Name.Variable.Instance */
560 599 .codehilite .vm { color: #19177C } /* Name.Variable.Magic */
561 600 .codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */
562 601
563 602 </style>
564 603
565 604 </head>
566 605 <body>
567 606
568 607 <div>
569 608 <!-- 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. -->
570 609 <table cellpadding="0" cellspacing="0" border="0" id="backgroundTable" align="left" style="margin:1%;width:97%;padding:0;font-family:${text_regular|n};font-weight:100;border:1px solid #dbd9da">
571 610 <tr>
572 611 <td valign="top" style="padding:0;">
573 612 <table cellpadding="0" cellspacing="0" border="0" align="left" width="100%">
574 613 <tr>
575 614 <td style="width:100%;padding:10px 15px;background-color:#202020" valign="top">
576 615 <a style="color:#eeeeee;text-decoration:none;" href="${instance_url}">
577 616 ${_('RhodeCode')}
578 617 % if rhodecode_instance_name:
579 618 - ${rhodecode_instance_name}
580 619 % endif
581 620 </a>
582 621 </td>
583 622 </tr>
584 <tr>
623 <tr style="background-color: #fff">
585 624 <td style="padding:15px;" valign="top">${self.body()}</td>
586 625 </tr>
587 626 </table>
588 627 </td>
589 628 </tr>
590 629 </table>
591 630 <!-- End of wrapper table -->
592 631 </div>
593 632
594 633 <div style="width:100%; clear: both; height: 1px">&nbsp;</div>
595 634
596 635 <div style="margin-left:1%;font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace};">
597 636 ${_('This is a notification from RhodeCode.')}
598 637 <a style="font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace};" href="${instance_url}">
599 638 ${instance_url}
600 639 </a>
601 640 </div>
602 641 </body>
603 642 </html>
@@ -1,170 +1,172 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="base.mako"/>
3 3 <%namespace name="base" file="base.mako"/>
4 4
5 5 ## EMAIL SUBJECT
6 6 <%def name="subject()" filter="n,trim,whitespace_filter">
7 7 <%
8 8 data = {
9 9 'user': '@'+h.person(user),
10 10 'repo_name': repo_name,
11 11 'status': status_change,
12 12 'comment_file': comment_file,
13 13 'comment_line': comment_line,
14 14 'comment_type': comment_type,
15 15 'comment_id': comment_id,
16 16
17 17 'commit_id': h.show_id(commit),
18 18 }
19 19 %>
20 20
21 21
22 22 % if comment_file:
23 23 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on file `{comment_file}` in commit `{commit_id}`').format(**data)} ${_('in the `{repo_name}` repository').format(**data) |n}
24 24 % else:
25 25 % if status_change:
26 26 ${(_('[mention]') if mention else '')} ${_('[status: {status}] {user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the `{repo_name}` repository').format(**data) |n}
27 27 % else:
28 28 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the `{repo_name}` repository').format(**data) |n}
29 29 % endif
30 30 % endif
31 31
32 32 </%def>
33 33
34 34 ## PLAINTEXT VERSION OF BODY
35 35 <%def name="body_plaintext()" filter="n,trim">
36 36 <%
37 37 data = {
38 38 'user': h.person(user),
39 39 'repo_name': repo_name,
40 40 'status': status_change,
41 41 'comment_file': comment_file,
42 42 'comment_line': comment_line,
43 43 'comment_type': comment_type,
44 44 'comment_id': comment_id,
45 45
46 46 'commit_id': h.show_id(commit),
47 47 }
48 48 %>
49 49
50 50 * ${_('Comment link')}: ${commit_comment_url}
51 51
52 52 %if status_change:
53 53 * ${_('Commit status')}: ${_('Status was changed to')}: *${status_change}*
54 54
55 55 %endif
56 56 * ${_('Commit')}: ${h.show_id(commit)}
57 57
58 58 * ${_('Commit message')}: ${commit.message}
59 59
60 60 %if comment_file:
61 61 * ${_('File: {comment_file} on line {comment_line}').format(**data)}
62 62
63 63 %endif
64 64 % if comment_type == 'todo':
65 65 ${('Inline' if comment_file else 'General')} ${_('`TODO` number')} ${comment_id}:
66 66 % else:
67 67 ${('Inline' if comment_file else 'General')} ${_('`Note` number')} ${comment_id}:
68 68 % endif
69 69
70 70 ${comment_body |n, trim}
71 71
72 72 ---
73 73 ${self.plaintext_footer()}
74 74 </%def>
75 75
76 76
77 77 <%
78 78 data = {
79 79 'user': h.person(user),
80 80 'comment_file': comment_file,
81 81 'comment_line': comment_line,
82 82 'comment_type': comment_type,
83 83 'comment_id': comment_id,
84 84 'renderer_type': renderer_type or 'plain',
85 85
86 86 'repo': commit_target_repo_url,
87 87 'repo_name': repo_name,
88 88 'commit_id': h.show_id(commit),
89 89 }
90 90 %>
91 91
92 ## header
92 93 <table style="text-align:left;vertical-align:middle;width: 100%">
93 94 <tr>
94 95 <td style="width:100%;border-bottom:1px solid #dbd9da;">
95 96
96 <h4 style="margin: 0">
97 <div style="margin-bottom: 4px">
97 <div style="margin: 0; font-weight: bold">
98 <div class="clear-both" style="margin-bottom: 4px">
98 99 <span style="color:#7E7F7F">@${h.person(user.username)}</span>
99 100 ${_('left a')}
100 101 <a href="${commit_comment_url}" style="${base.link_css()}">
101 102 % if comment_file:
102 103 ${_('{comment_type} on file `{comment_file}` in commit.').format(**data)}
103 104 % else:
104 105 ${_('{comment_type} on commit.').format(**data) |n}
105 106 % endif
106 107 </a>
107 108 </div>
108 109 <div style="margin-top: 10px"></div>
109 110 ${_('Commit')} <code>${data['commit_id']}</code> ${_('of repository')}: ${data['repo_name']}
110 </h4>
111 </div>
111 112
112 113 </td>
113 114 </tr>
114 115
115 116 </table>
116
117 <div class="clear-both"></div>
118 ## main body
117 119 <table style="text-align:left;vertical-align:middle;width: 100%">
118 120
119 121 ## spacing def
120 122 <tr>
121 123 <td style="width: 130px"></td>
122 124 <td></td>
123 125 </tr>
124 126
125 127 % if status_change:
126 128 <tr>
127 129 <td style="padding-right:20px;">${_('Commit Status')}:</td>
128 130 <td>
129 131 ${_('Status was changed to')}: ${base.status_text(status_change, tag_type=status_change_type)}
130 132 </td>
131 133 </tr>
132 134 % endif
133 135
134 136 <tr>
135 137 <td style="padding-right:20px;">${_('Commit')}:</td>
136 138 <td>
137 139 <a href="${commit_comment_url}" style="${base.link_css()}">${h.show_id(commit)}</a>
138 140 </td>
139 141 </tr>
140 142 <tr>
141 143 <td style="padding-right:20px;">${_('Commit message')}:</td>
142 144 <td style="white-space:pre-wrap">${h.urlify_commit_message(commit.message, repo_name)}</td>
143 145 </tr>
144 146
145 147 % if comment_file:
146 148 <tr>
147 149 <td style="padding-right:20px;">${_('File')}:</td>
148 150 <td><a href="${commit_comment_url}" style="${base.link_css()}">${_('`{comment_file}` on line {comment_line}').format(**data)}</a></td>
149 151 </tr>
150 152 % endif
151 153
152 154 <tr style="border-bottom:1px solid #dbd9da;">
153 155 <td colspan="2" style="padding-right:20px;">
154 156 % if comment_type == 'todo':
155 157 ${('Inline' if comment_file else 'General')} ${_('`TODO` number')} ${comment_id}:
156 158 % else:
157 159 ${('Inline' if comment_file else 'General')} ${_('`Note` number')} ${comment_id}:
158 160 % endif
159 161 </td>
160 162 </tr>
161 163
162 164 <tr>
163 165 <td colspan="2" style="background: #F7F7F7">${h.render(comment_body, renderer=data['renderer_type'], mentions=True)}</td>
164 166 </tr>
165 167
166 168 <tr>
167 169 <td><a href="${commit_comment_reply_url}">${_('Reply')}</a></td>
168 170 <td></td>
169 171 </tr>
170 172 </table>
@@ -1,201 +1,203 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="base.mako"/>
3 3 <%namespace name="base" file="base.mako"/>
4 4
5 5 ## EMAIL SUBJECT
6 6 <%def name="subject()" filter="n,trim,whitespace_filter">
7 7 <%
8 8 data = {
9 9 'user': '@'+h.person(user),
10 10 'repo_name': repo_name,
11 11 'status': status_change,
12 12 'comment_file': comment_file,
13 13 'comment_line': comment_line,
14 14 'comment_type': comment_type,
15 15 'comment_id': comment_id,
16 16
17 17 'pr_title': pull_request.title,
18 18 'pr_id': pull_request.pull_request_id,
19 19 }
20 20 %>
21 21
22 22
23 23 % if comment_file:
24 24 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on file `{comment_file}` in pull request !{pr_id}: "{pr_title}"').format(**data) |n}
25 25 % else:
26 26 % if status_change:
27 27 ${(_('[mention]') if mention else '')} ${_('[status: {status}] {user} left a {comment_type} on pull request !{pr_id}: "{pr_title}"').format(**data) |n}
28 28 % else:
29 29 ${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on pull request !{pr_id}: "{pr_title}"').format(**data) |n}
30 30 % endif
31 31 % endif
32 32
33 33 </%def>
34 34
35 35 ## PLAINTEXT VERSION OF BODY
36 36 <%def name="body_plaintext()" filter="n,trim">
37 37 <%
38 38 data = {
39 39 'user': h.person(user),
40 40 'repo_name': repo_name,
41 41 'status': status_change,
42 42 'comment_file': comment_file,
43 43 'comment_line': comment_line,
44 44 'comment_type': comment_type,
45 45 'comment_id': comment_id,
46 46
47 47 'pr_title': pull_request.title,
48 48 'pr_id': pull_request.pull_request_id,
49 49 'source_ref_type': pull_request.source_ref_parts.type,
50 50 'source_ref_name': pull_request.source_ref_parts.name,
51 51 'target_ref_type': pull_request.target_ref_parts.type,
52 52 'target_ref_name': pull_request.target_ref_parts.name,
53 53 'source_repo': pull_request_source_repo.repo_name,
54 54 'target_repo': pull_request_target_repo.repo_name,
55 55 'source_repo_url': pull_request_source_repo_url,
56 56 'target_repo_url': pull_request_target_repo_url,
57 57 }
58 58 %>
59 59
60 60 * ${_('Comment link')}: ${pr_comment_url}
61 61
62 62 * ${_('Pull Request')}: !${pull_request.pull_request_id}
63 63
64 64 * ${h.literal(_('Commit flow: {source_ref_type}:{source_ref_name} of {source_repo_url} into {target_ref_type}:{target_ref_name} of {target_repo_url}').format(**data))}
65 65
66 66 %if status_change and not closing_pr:
67 67 * ${_('{user} submitted pull request !{pr_id} status: *{status}*').format(**data)}
68 68
69 69 %elif status_change and closing_pr:
70 70 * ${_('{user} submitted pull request !{pr_id} status: *{status} and closed*').format(**data)}
71 71
72 72 %endif
73 73 %if comment_file:
74 74 * ${_('File: {comment_file} on line {comment_line}').format(**data)}
75 75
76 76 %endif
77 77 % if comment_type == 'todo':
78 78 ${('Inline' if comment_file else 'General')} ${_('`TODO` number')} ${comment_id}:
79 79 % else:
80 80 ${('Inline' if comment_file else 'General')} ${_('`Note` number')} ${comment_id}:
81 81 % endif
82 82
83 83 ${comment_body |n, trim}
84 84
85 85 ---
86 86 ${self.plaintext_footer()}
87 87 </%def>
88 88
89 89
90 90 <%
91 91 data = {
92 92 'user': h.person(user),
93 93 'comment_file': comment_file,
94 94 'comment_line': comment_line,
95 95 'comment_type': comment_type,
96 96 'comment_id': comment_id,
97 97 'renderer_type': renderer_type or 'plain',
98 98
99 99 'pr_title': pull_request.title,
100 100 'pr_id': pull_request.pull_request_id,
101 101 'status': status_change,
102 102 'source_ref_type': pull_request.source_ref_parts.type,
103 103 'source_ref_name': pull_request.source_ref_parts.name,
104 104 'target_ref_type': pull_request.target_ref_parts.type,
105 105 'target_ref_name': pull_request.target_ref_parts.name,
106 106 'source_repo': pull_request_source_repo.repo_name,
107 107 'target_repo': pull_request_target_repo.repo_name,
108 108 'source_repo_url': h.link_to(pull_request_source_repo.repo_name, pull_request_source_repo_url),
109 109 'target_repo_url': h.link_to(pull_request_target_repo.repo_name, pull_request_target_repo_url),
110 110 }
111 111 %>
112 112
113 ## header
113 114 <table style="text-align:left;vertical-align:middle;width: 100%">
114 115 <tr>
115 116 <td style="width:100%;border-bottom:1px solid #dbd9da;">
116 117
117 <h4 style="margin: 0">
118 <div style="margin-bottom: 4px">
118 <div style="margin: 0; font-weight: bold">
119 <div class="clear-both" style="margin-bottom: 4px">
119 120 <span style="color:#7E7F7F">@${h.person(user.username)}</span>
120 121 ${_('left a')}
121 122 <a href="${pr_comment_url}" style="${base.link_css()}">
122 123 % if comment_file:
123 124 ${_('{comment_type} on file `{comment_file}` in pull request.').format(**data)}
124 125 % else:
125 126 ${_('{comment_type} on pull request.').format(**data) |n}
126 127 % endif
127 128 </a>
128 129 </div>
129 130 <div style="margin-top: 10px"></div>
130 131 ${_('Pull request')} <code>!${data['pr_id']}: ${data['pr_title']}</code>
131 </h4>
132 </div>
132 133
133 134 </td>
134 135 </tr>
135 136
136 137 </table>
137
138 <div class="clear-both"></div>
139 ## main body
138 140 <table style="text-align:left;vertical-align:middle;width: 100%">
139 141
140 142 ## spacing def
141 143 <tr>
142 144 <td style="width: 130px"></td>
143 145 <td></td>
144 146 </tr>
145 147
146 148 % if status_change:
147 149 <tr>
148 150 <td style="padding-right:20px;">${_('Review Status')}:</td>
149 151 <td>
150 152 % if closing_pr:
151 153 ${_('Closed pull request with status')}: ${base.status_text(status_change, tag_type=status_change_type)}
152 154 % else:
153 155 ${_('Submitted review status')}: ${base.status_text(status_change, tag_type=status_change_type)}
154 156 % endif
155 157 </td>
156 158 </tr>
157 159 % endif
158 160 <tr>
159 161 <td style="padding-right:20px;">${_('Pull request')}:</td>
160 162 <td>
161 163 <a href="${pull_request_url}" style="${base.link_css()}">
162 164 !${pull_request.pull_request_id}
163 165 </a>
164 166 </td>
165 167 </tr>
166 168
167 169 <tr>
168 170 <td style="padding-right:20px;line-height:20px;">${_('Commit Flow')}:</td>
169 171 <td style="line-height:20px;">
170 172 <code>${'{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name)}</code> ${_('of')} ${data['source_repo_url']}
171 173 &rarr;
172 174 <code>${'{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name)}</code> ${_('of')} ${data['target_repo_url']}
173 175 </td>
174 176 </tr>
175 177
176 178 % if comment_file:
177 179 <tr>
178 180 <td style="padding-right:20px;">${_('File')}:</td>
179 181 <td><a href="${pr_comment_url}" style="${base.link_css()}">${_('`{comment_file}` on line {comment_line}').format(**data)}</a></td>
180 182 </tr>
181 183 % endif
182 184
183 185 <tr style="border-bottom:1px solid #dbd9da;">
184 186 <td colspan="2" style="padding-right:20px;">
185 187 % if comment_type == 'todo':
186 188 ${('Inline' if comment_file else 'General')} ${_('`TODO` number')} ${comment_id}:
187 189 % else:
188 190 ${('Inline' if comment_file else 'General')} ${_('`Note` number')} ${comment_id}:
189 191 % endif
190 192 </td>
191 193 </tr>
192 194
193 195 <tr>
194 196 <td colspan="2" style="background: #F7F7F7">${h.render(comment_body, renderer=data['renderer_type'], mentions=True)}</td>
195 197 </tr>
196 198
197 199 <tr>
198 200 <td><a href="${pr_comment_reply_url}">${_('Reply')}</a></td>
199 201 <td></td>
200 202 </tr>
201 203 </table>
@@ -1,143 +1,144 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="base.mako"/>
3 3 <%namespace name="base" file="base.mako"/>
4 4
5 5 ## EMAIL SUBJECT
6 6 <%def name="subject()" filter="n,trim,whitespace_filter">
7 7 <%
8 8 data = {
9 9 'user': '@'+h.person(user),
10 10 'pr_id': pull_request.pull_request_id,
11 11 'pr_title': pull_request.title,
12 12 }
13 13 %>
14 14
15 15 ${_('{user} requested a pull request review. !{pr_id}: "{pr_title}"').format(**data) |n}
16 16 </%def>
17 17
18 18 ## PLAINTEXT VERSION OF BODY
19 19 <%def name="body_plaintext()" filter="n,trim">
20 20 <%
21 21 data = {
22 22 'user': h.person(user),
23 23 'pr_id': pull_request.pull_request_id,
24 24 'pr_title': pull_request.title,
25 25 'source_ref_type': pull_request.source_ref_parts.type,
26 26 'source_ref_name': pull_request.source_ref_parts.name,
27 27 'target_ref_type': pull_request.target_ref_parts.type,
28 28 'target_ref_name': pull_request.target_ref_parts.name,
29 29 'repo_url': pull_request_source_repo_url,
30 30 'source_repo': pull_request_source_repo.repo_name,
31 31 'target_repo': pull_request_target_repo.repo_name,
32 32 'source_repo_url': pull_request_source_repo_url,
33 33 'target_repo_url': pull_request_target_repo_url,
34 34 }
35 35 %>
36 36
37 37 * ${_('Pull Request link')}: ${pull_request_url}
38 38
39 39 * ${h.literal(_('Commit flow: {source_ref_type}:{source_ref_name} of {source_repo_url} into {target_ref_type}:{target_ref_name} of {target_repo_url}').format(**data))}
40 40
41 41 * ${_('Title')}: ${pull_request.title}
42 42
43 43 * ${_('Description')}:
44 44
45 45 ${pull_request.description | trim}
46 46
47 47
48 48 * ${_ungettext('Commit (%(num)s)', 'Commits (%(num)s)', len(pull_request_commits) ) % {'num': len(pull_request_commits)}}:
49 49
50 50 % for commit_id, message in pull_request_commits:
51 51 - ${h.short_id(commit_id)}
52 52 ${h.chop_at_smart(message, '\n', suffix_if_chopped='...')}
53 53
54 54 % endfor
55 55
56 56 ---
57 57 ${self.plaintext_footer()}
58 58 </%def>
59 59 <%
60 60 data = {
61 61 'user': h.person(user),
62 62 'pr_id': pull_request.pull_request_id,
63 63 'pr_title': pull_request.title,
64 64 'source_ref_type': pull_request.source_ref_parts.type,
65 65 'source_ref_name': pull_request.source_ref_parts.name,
66 66 'target_ref_type': pull_request.target_ref_parts.type,
67 67 'target_ref_name': pull_request.target_ref_parts.name,
68 68 'repo_url': pull_request_source_repo_url,
69 69 'source_repo': pull_request_source_repo.repo_name,
70 70 'target_repo': pull_request_target_repo.repo_name,
71 71 'source_repo_url': h.link_to(pull_request_source_repo.repo_name, pull_request_source_repo_url),
72 72 'target_repo_url': h.link_to(pull_request_target_repo.repo_name, pull_request_target_repo_url),
73 73 }
74 74 %>
75
75 ## header
76 76 <table style="text-align:left;vertical-align:middle;width: 100%">
77 77 <tr>
78 78 <td style="width:100%;border-bottom:1px solid #dbd9da;">
79 79
80 <h4 style="margin: 0">
81 <div style="margin-bottom: 4px">
80 <div style="margin: 0; font-weight: bold">
81 <div class="clear-both" class="clear-both" style="margin-bottom: 4px">
82 82 <span style="color:#7E7F7F">@${h.person(user.username)}</span>
83 83 ${_('requested a')}
84 84 <a href="${pull_request_url}" style="${base.link_css()}">
85 85 ${_('pull request review.').format(**data) }
86 86 </a>
87 87 </div>
88 88 <div style="margin-top: 10px"></div>
89 89 ${_('Pull request')} <code>!${data['pr_id']}: ${data['pr_title']}</code>
90 </h4>
90 </div>
91 91
92 92 </td>
93 93 </tr>
94 94
95 95 </table>
96
96 <div class="clear-both"></div>
97 ## main body
97 98 <table style="text-align:left;vertical-align:middle;width: 100%">
98 99 ## spacing def
99 100 <tr>
100 101 <td style="width: 130px"></td>
101 102 <td></td>
102 103 </tr>
103 104
104 105 <tr>
105 106 <td style="padding-right:20px;">${_('Pull request')}:</td>
106 107 <td>
107 108 <a href="${pull_request_url}" style="${base.link_css()}">
108 109 !${pull_request.pull_request_id}
109 110 </a>
110 111 </td>
111 112 </tr>
112 113
113 114 <tr>
114 115 <td style="padding-right:20px;line-height:20px;">${_('Commit Flow')}:</td>
115 116 <td style="line-height:20px;">
116 117 <code>${'{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name)}</code> ${_('of')} ${data['source_repo_url']}
117 118 &rarr;
118 119 <code>${'{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name)}</code> ${_('of')} ${data['target_repo_url']}
119 120 </td>
120 121 </tr>
121 122
122 123 <tr>
123 124 <td style="padding-right:20px;">${_('Description')}:</td>
124 125 <td style="white-space:pre-wrap"><code>${pull_request.description | trim}</code></td>
125 126 </tr>
126 127 <tr>
127 128 <td style="padding-right:20px;">${_ungettext('Commit (%(num)s)', 'Commits (%(num)s)', len(pull_request_commits)) % {'num': len(pull_request_commits)}}:</td>
128 129 <td></td>
129 130 </tr>
130 131
131 132 <tr>
132 133 <td colspan="2">
133 134 <ol style="margin:0 0 0 1em;padding:0;text-align:left;">
134 135 % for commit_id, message in pull_request_commits:
135 136 <li style="margin:0 0 1em;">
136 137 <pre style="margin:0 0 .5em"><a href="${h.route_path('repo_commit', repo_name=pull_request_source_repo.repo_name, commit_id=commit_id)}" style="${base.link_css()}">${h.short_id(commit_id)}</a></pre>
137 138 ${h.chop_at_smart(message, '\n', suffix_if_chopped='...')}
138 139 </li>
139 140 % endfor
140 141 </ol>
141 142 </td>
142 143 </tr>
143 144 </table>
@@ -1,164 +1,170 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="base.mako"/>
3 3 <%namespace name="base" file="base.mako"/>
4 4
5 5 ## EMAIL SUBJECT
6 6 <%def name="subject()" filter="n,trim,whitespace_filter">
7 7 <%
8 8 data = {
9 9 'updating_user': '@'+h.person(updating_user),
10 10 'pr_id': pull_request.pull_request_id,
11 11 'pr_title': pull_request.title,
12 12 }
13 13 %>
14 14
15 15 ${_('{updating_user} updated pull request. !{pr_id}: "{pr_title}"').format(**data) |n}
16 16 </%def>
17 17
18 18 ## PLAINTEXT VERSION OF BODY
19 19 <%def name="body_plaintext()" filter="n,trim">
20 20 <%
21 21 data = {
22 22 'updating_user': h.person(updating_user),
23 23 'pr_id': pull_request.pull_request_id,
24 24 'pr_title': pull_request.title,
25 25 'source_ref_type': pull_request.source_ref_parts.type,
26 26 'source_ref_name': pull_request.source_ref_parts.name,
27 27 'target_ref_type': pull_request.target_ref_parts.type,
28 28 'target_ref_name': pull_request.target_ref_parts.name,
29 29 'repo_url': pull_request_source_repo_url,
30 30 'source_repo': pull_request_source_repo.repo_name,
31 31 'target_repo': pull_request_target_repo.repo_name,
32 32 'source_repo_url': pull_request_source_repo_url,
33 33 'target_repo_url': pull_request_target_repo_url,
34 34 }
35 35 %>
36 36
37 37 * ${_('Pull Request link')}: ${pull_request_url}
38 38
39 39 * ${h.literal(_('Commit flow: {source_ref_type}:{source_ref_name} of {source_repo_url} into {target_ref_type}:{target_ref_name} of {target_repo_url}').format(**data))}
40 40
41 41 * ${_('Title')}: ${pull_request.title}
42 42
43 43 * ${_('Description')}:
44 44
45 45 ${pull_request.description | trim}
46 46
47 47 * Changed commits:
48 48
49 49 - Added: ${len(added_commits)}
50 50 - Removed: ${len(removed_commits)}
51 51
52 52 * Changed files:
53 53
54 54 %if not changed_files:
55 55 No file changes found
56 56 %else:
57 57 %for file_name in added_files:
58 58 - A `${file_name}`
59 59 %endfor
60 60 %for file_name in modified_files:
61 61 - M `${file_name}`
62 62 %endfor
63 63 %for file_name in removed_files:
64 64 - R `${file_name}`
65 65 %endfor
66 66 %endif
67 67
68 68 ---
69 69 ${self.plaintext_footer()}
70 70 </%def>
71 71 <%
72 72 data = {
73 73 'updating_user': h.person(updating_user),
74 74 'pr_id': pull_request.pull_request_id,
75 75 'pr_title': pull_request.title,
76 76 'source_ref_type': pull_request.source_ref_parts.type,
77 77 'source_ref_name': pull_request.source_ref_parts.name,
78 78 'target_ref_type': pull_request.target_ref_parts.type,
79 79 'target_ref_name': pull_request.target_ref_parts.name,
80 80 'repo_url': pull_request_source_repo_url,
81 81 'source_repo': pull_request_source_repo.repo_name,
82 82 'target_repo': pull_request_target_repo.repo_name,
83 83 'source_repo_url': h.link_to(pull_request_source_repo.repo_name, pull_request_source_repo_url),
84 84 'target_repo_url': h.link_to(pull_request_target_repo.repo_name, pull_request_target_repo_url),
85 85 }
86 86 %>
87 87
88 ## header
88 89 <table style="text-align:left;vertical-align:middle;width: 100%">
89 90 <tr>
90 91 <td style="width:100%;border-bottom:1px solid #dbd9da;">
91 92
92 <h4 style="margin: 0">
93 <div style="margin-bottom: 4px">
93 <div style="margin: 0; font-weight: bold">
94 <div class="clear-both" style="margin-bottom: 4px">
94 95 <span style="color:#7E7F7F">@${h.person(updating_user.username)}</span>
95 96 ${_('updated')}
96 97 <a href="${pull_request_url}" style="${base.link_css()}">
97 98 ${_('pull request.').format(**data) }
98 99 </a>
99 100 </div>
100 101 <div style="margin-top: 10px"></div>
101 102 ${_('Pull request')} <code>!${data['pr_id']}: ${data['pr_title']}</code>
102 </h4>
103 </div>
103 104
104 105 </td>
105 106 </tr>
106 107
107 108 </table>
108
109 <div class="clear-both"></div>
110 ## main body
109 111 <table style="text-align:left;vertical-align:middle;width: 100%">
110 112 ## spacing def
111 113 <tr>
112 114 <td style="width: 130px"></td>
113 115 <td></td>
114 116 </tr>
115 117
116 118 <tr>
117 119 <td style="padding-right:20px;">${_('Pull request')}:</td>
118 120 <td>
119 121 <a href="${pull_request_url}" style="${base.link_css()}">
120 122 !${pull_request.pull_request_id}
121 123 </a>
122 124 </td>
123 125 </tr>
124 126
125 127 <tr>
126 128 <td style="padding-right:20px;line-height:20px;">${_('Commit Flow')}:</td>
127 129 <td style="line-height:20px;">
128 130 <code>${'{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name)}</code> ${_('of')} ${data['source_repo_url']}
129 131 &rarr;
130 132 <code>${'{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name)}</code> ${_('of')} ${data['target_repo_url']}
131 133 </td>
132 134 </tr>
133 135
134 136 <tr>
135 137 <td style="padding-right:20px;">${_('Description')}:</td>
136 138 <td style="white-space:pre-wrap"><code>${pull_request.description | trim}</code></td>
137 139 </tr>
138 140 <tr>
139 141 <td style="padding-right:20px;">${_('Changes')}:</td>
140 <td style="white-space:pre-line">\
142 <td>
141 143 <strong>Changed commits:</strong>
142
143 - Added: ${len(added_commits)}
144 - Removed: ${len(removed_commits)}
144 <ul class="changes-ul">
145 <li>- Added: ${len(added_commits)}</li>
146 <li>- Removed: ${len(removed_commits)}</li>
147 </ul>
145 148
146 149 <strong>Changed files:</strong>
150 <ul class="changes-ul">
147 151
148 152 %if not changed_files:
149 No file changes found
153 <li>No file changes found</li>
150 154 %else:
151 %for file_name in added_files:
152 - A <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a>
153 %endfor
154 %for file_name in modified_files:
155 - M <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a>
156 %endfor
157 %for file_name in removed_files:
158 - R <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a>
159 %endfor
155 %for file_name in added_files:
156 <li>- A <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a></li>
157 %endfor
158 %for file_name in modified_files:
159 <li>- M <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a></li>
160 %endfor
161 %for file_name in removed_files:
162 <li>- R <a href="${pull_request_url + '#a_' + h.FID(ancestor_commit_id, file_name)}">${file_name}</a></li>
163 %endfor
160 164 %endif
165
166 </ul>
161 167 </td>
162 168 </tr>
163 169
164 170 </table>
@@ -1,59 +1,60 b''
1 1 ## -*- coding: utf-8 -*-
2 2 <%inherit file="base.mako"/>
3 3 <%namespace name="base" file="base.mako"/>
4 4
5 5 <%def name="subject()" filter="n,trim,whitespace_filter">
6 6 RhodeCode new user registration: ${user.username}
7 7 </%def>
8 8
9 9 <%def name="body_plaintext()" filter="n,trim">
10 10
11 11 A new user `${user.username}` has registered on ${h.format_date(date)}
12 12
13 13 - Username: ${user.username}
14 14 - Full Name: ${user.first_name} ${user.last_name}
15 15 - Email: ${user.email}
16 16 - Profile link: ${h.route_url('user_profile', username=user.username)}
17 17
18 18 ---
19 19 ${self.plaintext_footer()}
20 20 </%def>
21 21
22
22 ## header
23 23 <table style="text-align:left;vertical-align:middle;width: 100%">
24 24 <tr>
25 25 <td style="width:100%;border-bottom:1px solid #dbd9da;">
26 26 <h4 style="margin: 0">
27 27 <a href="${h.route_url('user_profile', username=user.username)}" style="${base.link_css()}">
28 28 ${_('New user {user} has registered on {date}').format(user=user.username, date=h.format_date(date))}
29 29 </a>
30 30 </h4>
31 31 </td>
32 32 </tr>
33 33 </table>
34
34 <div class="clear-both"></div>
35 ## main body
35 36 <table style="text-align:left;vertical-align:middle;width: 100%">
36 37 ## spacing def
37 38 <tr>
38 39 <td style="width: 130px"></td>
39 40 <td></td>
40 41 </tr>
41 42 <tr>
42 43 <td style="padding-right:20px;padding-top:20px;">${_('Username')}:</td>
43 44 <td style="line-height:1;padding-top:20px;">${user.username}</td>
44 45 </tr>
45 46 <tr>
46 47 <td style="padding-right:20px;">${_('Full Name')}:</td>
47 48 <td>${user.first_name} ${user.last_name}</td>
48 49 </tr>
49 50 <tr>
50 51 <td style="padding-right:20px;">${_('Email')}:</td>
51 52 <td>${user.email}</td>
52 53 </tr>
53 54 <tr>
54 55 <td style="padding-right:20px;">${_('Profile')}:</td>
55 56 <td>
56 57 <a href="${h.route_url('user_profile', username=user.username)}">${h.route_url('user_profile', username=user.username)}</a>
57 58 </td>
58 59 </tr>
59 60 </table>
General Comments 0
You need to be logged in to leave comments. Login now