##// END OF EJS Templates
notifications: reduce logging for email notifications.
dan -
r4292:6a785798 default
parent child Browse files
Show More
@@ -1,411 +1,411 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 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
21
22 """
22 """
23 Model for notifications
23 Model for notifications
24 """
24 """
25
25
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 import premailer
29 import premailer
30 from pyramid.threadlocal import get_current_request
30 from pyramid.threadlocal import get_current_request
31 from sqlalchemy.sql.expression import false, true
31 from sqlalchemy.sql.expression import false, true
32
32
33 import rhodecode
33 import rhodecode
34 from rhodecode.lib import helpers as h
34 from rhodecode.lib import helpers as h
35 from rhodecode.model import BaseModel
35 from rhodecode.model import BaseModel
36 from rhodecode.model.db import Notification, User, UserNotification
36 from rhodecode.model.db import Notification, User, UserNotification
37 from rhodecode.model.meta import Session
37 from rhodecode.model.meta import Session
38 from rhodecode.translation import TranslationString
38 from rhodecode.translation import TranslationString
39
39
40 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
41
41
42
42
43 class NotificationModel(BaseModel):
43 class NotificationModel(BaseModel):
44
44
45 cls = Notification
45 cls = Notification
46
46
47 def __get_notification(self, notification):
47 def __get_notification(self, notification):
48 if isinstance(notification, Notification):
48 if isinstance(notification, Notification):
49 return notification
49 return notification
50 elif isinstance(notification, (int, long)):
50 elif isinstance(notification, (int, long)):
51 return Notification.get(notification)
51 return Notification.get(notification)
52 else:
52 else:
53 if notification:
53 if notification:
54 raise Exception('notification must be int, long or Instance'
54 raise Exception('notification must be int, long or Instance'
55 ' of Notification got %s' % type(notification))
55 ' of Notification got %s' % type(notification))
56
56
57 def create(
57 def create(
58 self, created_by, notification_subject, notification_body,
58 self, created_by, notification_subject, notification_body,
59 notification_type=Notification.TYPE_MESSAGE, recipients=None,
59 notification_type=Notification.TYPE_MESSAGE, recipients=None,
60 mention_recipients=None, with_email=True, email_kwargs=None):
60 mention_recipients=None, with_email=True, email_kwargs=None):
61 """
61 """
62
62
63 Creates notification of given type
63 Creates notification of given type
64
64
65 :param created_by: int, str or User instance. User who created this
65 :param created_by: int, str or User instance. User who created this
66 notification
66 notification
67 :param notification_subject: subject of notification itself
67 :param notification_subject: subject of notification itself
68 :param notification_body: body of notification text
68 :param notification_body: body of notification text
69 :param notification_type: type of notification, based on that we
69 :param notification_type: type of notification, based on that we
70 pick templates
70 pick templates
71
71
72 :param recipients: list of int, str or User objects, when None
72 :param recipients: list of int, str or User objects, when None
73 is given send to all admins
73 is given send to all admins
74 :param mention_recipients: list of int, str or User objects,
74 :param mention_recipients: list of int, str or User objects,
75 that were mentioned
75 that were mentioned
76 :param with_email: send email with this notification
76 :param with_email: send email with this notification
77 :param email_kwargs: dict with arguments to generate email
77 :param email_kwargs: dict with arguments to generate email
78 """
78 """
79
79
80 from rhodecode.lib.celerylib import tasks, run_task
80 from rhodecode.lib.celerylib import tasks, run_task
81
81
82 if recipients and not getattr(recipients, '__iter__', False):
82 if recipients and not getattr(recipients, '__iter__', False):
83 raise Exception('recipients must be an iterable object')
83 raise Exception('recipients must be an iterable object')
84
84
85 created_by_obj = self._get_user(created_by)
85 created_by_obj = self._get_user(created_by)
86 # default MAIN body if not given
86 # default MAIN body if not given
87 email_kwargs = email_kwargs or {'body': notification_body}
87 email_kwargs = email_kwargs or {'body': notification_body}
88 mention_recipients = mention_recipients or set()
88 mention_recipients = mention_recipients or set()
89
89
90 if not created_by_obj:
90 if not created_by_obj:
91 raise Exception('unknown user %s' % created_by)
91 raise Exception('unknown user %s' % created_by)
92
92
93 if recipients is None:
93 if recipients is None:
94 # recipients is None means to all admins
94 # recipients is None means to all admins
95 recipients_objs = User.query().filter(User.admin == true()).all()
95 recipients_objs = User.query().filter(User.admin == true()).all()
96 log.debug('sending notifications %s to admins: %s',
96 log.debug('sending notifications %s to admins: %s',
97 notification_type, recipients_objs)
97 notification_type, recipients_objs)
98 else:
98 else:
99 recipients_objs = set()
99 recipients_objs = set()
100 for u in recipients:
100 for u in recipients:
101 obj = self._get_user(u)
101 obj = self._get_user(u)
102 if obj:
102 if obj:
103 recipients_objs.add(obj)
103 recipients_objs.add(obj)
104 else: # we didn't find this user, log the error and carry on
104 else: # we didn't find this user, log the error and carry on
105 log.error('cannot notify unknown user %r', u)
105 log.error('cannot notify unknown user %r', u)
106
106
107 if not recipients_objs:
107 if not recipients_objs:
108 raise Exception('no valid recipients specified')
108 raise Exception('no valid recipients specified')
109
109
110 log.debug('sending notifications %s to %s',
110 log.debug('sending notifications %s to %s',
111 notification_type, recipients_objs)
111 notification_type, recipients_objs)
112
112
113 # add mentioned users into recipients
113 # add mentioned users into recipients
114 final_recipients = set(recipients_objs).union(mention_recipients)
114 final_recipients = set(recipients_objs).union(mention_recipients)
115
115
116 notification = Notification.create(
116 notification = Notification.create(
117 created_by=created_by_obj, subject=notification_subject,
117 created_by=created_by_obj, subject=notification_subject,
118 body=notification_body, recipients=final_recipients,
118 body=notification_body, recipients=final_recipients,
119 type_=notification_type
119 type_=notification_type
120 )
120 )
121
121
122 if not with_email: # skip sending email, and just create notification
122 if not with_email: # skip sending email, and just create notification
123 return notification
123 return notification
124
124
125 # don't send email to person who created this comment
125 # don't send email to person who created this comment
126 rec_objs = set(recipients_objs).difference({created_by_obj})
126 rec_objs = set(recipients_objs).difference({created_by_obj})
127
127
128 # now notify all recipients in question
128 # now notify all recipients in question
129
129
130 for recipient in rec_objs.union(mention_recipients):
130 for recipient in rec_objs.union(mention_recipients):
131 # inject current recipient
131 # inject current recipient
132 email_kwargs['recipient'] = recipient
132 email_kwargs['recipient'] = recipient
133 email_kwargs['mention'] = recipient in mention_recipients
133 email_kwargs['mention'] = recipient in mention_recipients
134 (subject, headers, email_body,
134 (subject, headers, email_body,
135 email_body_plaintext) = EmailNotificationModel().render_email(
135 email_body_plaintext) = EmailNotificationModel().render_email(
136 notification_type, **email_kwargs)
136 notification_type, **email_kwargs)
137
137
138 log.debug(
138 log.debug(
139 'Creating notification email task for user:`%s`', recipient)
139 'Creating notification email task for user:`%s`', recipient)
140 task = run_task(
140 task = run_task(
141 tasks.send_email, recipient.email, subject,
141 tasks.send_email, recipient.email, subject,
142 email_body_plaintext, email_body)
142 email_body_plaintext, email_body)
143 log.debug('Created email task: %s', task)
143 log.debug('Created email task: %s', task)
144
144
145 return notification
145 return notification
146
146
147 def delete(self, user, notification):
147 def delete(self, user, notification):
148 # we don't want to remove actual notification just the assignment
148 # we don't want to remove actual notification just the assignment
149 try:
149 try:
150 notification = self.__get_notification(notification)
150 notification = self.__get_notification(notification)
151 user = self._get_user(user)
151 user = self._get_user(user)
152 if notification and user:
152 if notification and user:
153 obj = UserNotification.query()\
153 obj = UserNotification.query()\
154 .filter(UserNotification.user == user)\
154 .filter(UserNotification.user == user)\
155 .filter(UserNotification.notification == notification)\
155 .filter(UserNotification.notification == notification)\
156 .one()
156 .one()
157 Session().delete(obj)
157 Session().delete(obj)
158 return True
158 return True
159 except Exception:
159 except Exception:
160 log.error(traceback.format_exc())
160 log.error(traceback.format_exc())
161 raise
161 raise
162
162
163 def get_for_user(self, user, filter_=None):
163 def get_for_user(self, user, filter_=None):
164 """
164 """
165 Get mentions for given user, filter them if filter dict is given
165 Get mentions for given user, filter them if filter dict is given
166 """
166 """
167 user = self._get_user(user)
167 user = self._get_user(user)
168
168
169 q = UserNotification.query()\
169 q = UserNotification.query()\
170 .filter(UserNotification.user == user)\
170 .filter(UserNotification.user == user)\
171 .join((
171 .join((
172 Notification, UserNotification.notification_id ==
172 Notification, UserNotification.notification_id ==
173 Notification.notification_id))
173 Notification.notification_id))
174 if filter_ == ['all']:
174 if filter_ == ['all']:
175 q = q # no filter
175 q = q # no filter
176 elif filter_ == ['unread']:
176 elif filter_ == ['unread']:
177 q = q.filter(UserNotification.read == false())
177 q = q.filter(UserNotification.read == false())
178 elif filter_:
178 elif filter_:
179 q = q.filter(Notification.type_.in_(filter_))
179 q = q.filter(Notification.type_.in_(filter_))
180
180
181 return q
181 return q
182
182
183 def mark_read(self, user, notification):
183 def mark_read(self, user, notification):
184 try:
184 try:
185 notification = self.__get_notification(notification)
185 notification = self.__get_notification(notification)
186 user = self._get_user(user)
186 user = self._get_user(user)
187 if notification and user:
187 if notification and user:
188 obj = UserNotification.query()\
188 obj = UserNotification.query()\
189 .filter(UserNotification.user == user)\
189 .filter(UserNotification.user == user)\
190 .filter(UserNotification.notification == notification)\
190 .filter(UserNotification.notification == notification)\
191 .one()
191 .one()
192 obj.read = True
192 obj.read = True
193 Session().add(obj)
193 Session().add(obj)
194 return True
194 return True
195 except Exception:
195 except Exception:
196 log.error(traceback.format_exc())
196 log.error(traceback.format_exc())
197 raise
197 raise
198
198
199 def mark_all_read_for_user(self, user, filter_=None):
199 def mark_all_read_for_user(self, user, filter_=None):
200 user = self._get_user(user)
200 user = self._get_user(user)
201 q = UserNotification.query()\
201 q = UserNotification.query()\
202 .filter(UserNotification.user == user)\
202 .filter(UserNotification.user == user)\
203 .filter(UserNotification.read == false())\
203 .filter(UserNotification.read == false())\
204 .join((
204 .join((
205 Notification, UserNotification.notification_id ==
205 Notification, UserNotification.notification_id ==
206 Notification.notification_id))
206 Notification.notification_id))
207 if filter_ == ['unread']:
207 if filter_ == ['unread']:
208 q = q.filter(UserNotification.read == false())
208 q = q.filter(UserNotification.read == false())
209 elif filter_:
209 elif filter_:
210 q = q.filter(Notification.type_.in_(filter_))
210 q = q.filter(Notification.type_.in_(filter_))
211
211
212 # this is a little inefficient but sqlalchemy doesn't support
212 # this is a little inefficient but sqlalchemy doesn't support
213 # update on joined tables :(
213 # update on joined tables :(
214 for obj in q.all():
214 for obj in q.all():
215 obj.read = True
215 obj.read = True
216 Session().add(obj)
216 Session().add(obj)
217
217
218 def get_unread_cnt_for_user(self, user):
218 def get_unread_cnt_for_user(self, user):
219 user = self._get_user(user)
219 user = self._get_user(user)
220 return UserNotification.query()\
220 return UserNotification.query()\
221 .filter(UserNotification.read == false())\
221 .filter(UserNotification.read == false())\
222 .filter(UserNotification.user == user).count()
222 .filter(UserNotification.user == user).count()
223
223
224 def get_unread_for_user(self, user):
224 def get_unread_for_user(self, user):
225 user = self._get_user(user)
225 user = self._get_user(user)
226 return [x.notification for x in UserNotification.query()
226 return [x.notification for x in UserNotification.query()
227 .filter(UserNotification.read == false())
227 .filter(UserNotification.read == false())
228 .filter(UserNotification.user == user).all()]
228 .filter(UserNotification.user == user).all()]
229
229
230 def get_user_notification(self, user, notification):
230 def get_user_notification(self, user, notification):
231 user = self._get_user(user)
231 user = self._get_user(user)
232 notification = self.__get_notification(notification)
232 notification = self.__get_notification(notification)
233
233
234 return UserNotification.query()\
234 return UserNotification.query()\
235 .filter(UserNotification.notification == notification)\
235 .filter(UserNotification.notification == notification)\
236 .filter(UserNotification.user == user).scalar()
236 .filter(UserNotification.user == user).scalar()
237
237
238 def make_description(self, notification, translate, show_age=True):
238 def make_description(self, notification, translate, show_age=True):
239 """
239 """
240 Creates a human readable description based on properties
240 Creates a human readable description based on properties
241 of notification object
241 of notification object
242 """
242 """
243 _ = translate
243 _ = translate
244 _map = {
244 _map = {
245 notification.TYPE_CHANGESET_COMMENT: [
245 notification.TYPE_CHANGESET_COMMENT: [
246 _('%(user)s commented on commit %(date_or_age)s'),
246 _('%(user)s commented on commit %(date_or_age)s'),
247 _('%(user)s commented on commit at %(date_or_age)s'),
247 _('%(user)s commented on commit at %(date_or_age)s'),
248 ],
248 ],
249 notification.TYPE_MESSAGE: [
249 notification.TYPE_MESSAGE: [
250 _('%(user)s sent message %(date_or_age)s'),
250 _('%(user)s sent message %(date_or_age)s'),
251 _('%(user)s sent message at %(date_or_age)s'),
251 _('%(user)s sent message at %(date_or_age)s'),
252 ],
252 ],
253 notification.TYPE_MENTION: [
253 notification.TYPE_MENTION: [
254 _('%(user)s mentioned you %(date_or_age)s'),
254 _('%(user)s mentioned you %(date_or_age)s'),
255 _('%(user)s mentioned you at %(date_or_age)s'),
255 _('%(user)s mentioned you at %(date_or_age)s'),
256 ],
256 ],
257 notification.TYPE_REGISTRATION: [
257 notification.TYPE_REGISTRATION: [
258 _('%(user)s registered in RhodeCode %(date_or_age)s'),
258 _('%(user)s registered in RhodeCode %(date_or_age)s'),
259 _('%(user)s registered in RhodeCode at %(date_or_age)s'),
259 _('%(user)s registered in RhodeCode at %(date_or_age)s'),
260 ],
260 ],
261 notification.TYPE_PULL_REQUEST: [
261 notification.TYPE_PULL_REQUEST: [
262 _('%(user)s opened new pull request %(date_or_age)s'),
262 _('%(user)s opened new pull request %(date_or_age)s'),
263 _('%(user)s opened new pull request at %(date_or_age)s'),
263 _('%(user)s opened new pull request at %(date_or_age)s'),
264 ],
264 ],
265 notification.TYPE_PULL_REQUEST_UPDATE: [
265 notification.TYPE_PULL_REQUEST_UPDATE: [
266 _('%(user)s updated pull request %(date_or_age)s'),
266 _('%(user)s updated pull request %(date_or_age)s'),
267 _('%(user)s updated pull request at %(date_or_age)s'),
267 _('%(user)s updated pull request at %(date_or_age)s'),
268 ],
268 ],
269 notification.TYPE_PULL_REQUEST_COMMENT: [
269 notification.TYPE_PULL_REQUEST_COMMENT: [
270 _('%(user)s commented on pull request %(date_or_age)s'),
270 _('%(user)s commented on pull request %(date_or_age)s'),
271 _('%(user)s commented on pull request at %(date_or_age)s'),
271 _('%(user)s commented on pull request at %(date_or_age)s'),
272 ],
272 ],
273 }
273 }
274
274
275 templates = _map[notification.type_]
275 templates = _map[notification.type_]
276
276
277 if show_age:
277 if show_age:
278 template = templates[0]
278 template = templates[0]
279 date_or_age = h.age(notification.created_on)
279 date_or_age = h.age(notification.created_on)
280 if translate:
280 if translate:
281 date_or_age = translate(date_or_age)
281 date_or_age = translate(date_or_age)
282
282
283 if isinstance(date_or_age, TranslationString):
283 if isinstance(date_or_age, TranslationString):
284 date_or_age = date_or_age.interpolate()
284 date_or_age = date_or_age.interpolate()
285
285
286 else:
286 else:
287 template = templates[1]
287 template = templates[1]
288 date_or_age = h.format_date(notification.created_on)
288 date_or_age = h.format_date(notification.created_on)
289
289
290 return template % {
290 return template % {
291 'user': notification.created_by_user.username,
291 'user': notification.created_by_user.username,
292 'date_or_age': date_or_age,
292 'date_or_age': date_or_age,
293 }
293 }
294
294
295
295
296 class EmailNotificationModel(BaseModel):
296 class EmailNotificationModel(BaseModel):
297 TYPE_COMMIT_COMMENT = Notification.TYPE_CHANGESET_COMMENT
297 TYPE_COMMIT_COMMENT = Notification.TYPE_CHANGESET_COMMENT
298 TYPE_REGISTRATION = Notification.TYPE_REGISTRATION
298 TYPE_REGISTRATION = Notification.TYPE_REGISTRATION
299 TYPE_PULL_REQUEST = Notification.TYPE_PULL_REQUEST
299 TYPE_PULL_REQUEST = Notification.TYPE_PULL_REQUEST
300 TYPE_PULL_REQUEST_COMMENT = Notification.TYPE_PULL_REQUEST_COMMENT
300 TYPE_PULL_REQUEST_COMMENT = Notification.TYPE_PULL_REQUEST_COMMENT
301 TYPE_PULL_REQUEST_UPDATE = Notification.TYPE_PULL_REQUEST_UPDATE
301 TYPE_PULL_REQUEST_UPDATE = Notification.TYPE_PULL_REQUEST_UPDATE
302 TYPE_MAIN = Notification.TYPE_MESSAGE
302 TYPE_MAIN = Notification.TYPE_MESSAGE
303
303
304 TYPE_PASSWORD_RESET = 'password_reset'
304 TYPE_PASSWORD_RESET = 'password_reset'
305 TYPE_PASSWORD_RESET_CONFIRMATION = 'password_reset_confirmation'
305 TYPE_PASSWORD_RESET_CONFIRMATION = 'password_reset_confirmation'
306 TYPE_EMAIL_TEST = 'email_test'
306 TYPE_EMAIL_TEST = 'email_test'
307 TYPE_EMAIL_EXCEPTION = 'exception'
307 TYPE_EMAIL_EXCEPTION = 'exception'
308 TYPE_TEST = 'test'
308 TYPE_TEST = 'test'
309
309
310 email_types = {
310 email_types = {
311 TYPE_MAIN:
311 TYPE_MAIN:
312 'rhodecode:templates/email_templates/main.mako',
312 'rhodecode:templates/email_templates/main.mako',
313 TYPE_TEST:
313 TYPE_TEST:
314 'rhodecode:templates/email_templates/test.mako',
314 'rhodecode:templates/email_templates/test.mako',
315 TYPE_EMAIL_EXCEPTION:
315 TYPE_EMAIL_EXCEPTION:
316 'rhodecode:templates/email_templates/exception_tracker.mako',
316 'rhodecode:templates/email_templates/exception_tracker.mako',
317 TYPE_EMAIL_TEST:
317 TYPE_EMAIL_TEST:
318 'rhodecode:templates/email_templates/email_test.mako',
318 'rhodecode:templates/email_templates/email_test.mako',
319 TYPE_REGISTRATION:
319 TYPE_REGISTRATION:
320 'rhodecode:templates/email_templates/user_registration.mako',
320 'rhodecode:templates/email_templates/user_registration.mako',
321 TYPE_PASSWORD_RESET:
321 TYPE_PASSWORD_RESET:
322 'rhodecode:templates/email_templates/password_reset.mako',
322 'rhodecode:templates/email_templates/password_reset.mako',
323 TYPE_PASSWORD_RESET_CONFIRMATION:
323 TYPE_PASSWORD_RESET_CONFIRMATION:
324 'rhodecode:templates/email_templates/password_reset_confirmation.mako',
324 'rhodecode:templates/email_templates/password_reset_confirmation.mako',
325 TYPE_COMMIT_COMMENT:
325 TYPE_COMMIT_COMMENT:
326 'rhodecode:templates/email_templates/commit_comment.mako',
326 'rhodecode:templates/email_templates/commit_comment.mako',
327 TYPE_PULL_REQUEST:
327 TYPE_PULL_REQUEST:
328 'rhodecode:templates/email_templates/pull_request_review.mako',
328 'rhodecode:templates/email_templates/pull_request_review.mako',
329 TYPE_PULL_REQUEST_COMMENT:
329 TYPE_PULL_REQUEST_COMMENT:
330 'rhodecode:templates/email_templates/pull_request_comment.mako',
330 'rhodecode:templates/email_templates/pull_request_comment.mako',
331 TYPE_PULL_REQUEST_UPDATE:
331 TYPE_PULL_REQUEST_UPDATE:
332 'rhodecode:templates/email_templates/pull_request_update.mako',
332 'rhodecode:templates/email_templates/pull_request_update.mako',
333 }
333 }
334
334
335 premailer_instance = premailer.Premailer(
335 premailer_instance = premailer.Premailer(
336 cssutils_logging_level=logging.DEBUG,
336 cssutils_logging_level=logging.WARNING,
337 cssutils_logging_handler=logging.getLogger().handlers[0]
337 cssutils_logging_handler=logging.getLogger().handlers[0]
338 if logging.getLogger().handlers else None,
338 if logging.getLogger().handlers else None,
339 )
339 )
340
340
341 def __init__(self):
341 def __init__(self):
342 """
342 """
343 Example usage::
343 Example usage::
344
344
345 (subject, headers, email_body,
345 (subject, headers, email_body,
346 email_body_plaintext) = EmailNotificationModel().render_email(
346 email_body_plaintext) = EmailNotificationModel().render_email(
347 EmailNotificationModel.TYPE_TEST, **email_kwargs)
347 EmailNotificationModel.TYPE_TEST, **email_kwargs)
348
348
349 """
349 """
350 super(EmailNotificationModel, self).__init__()
350 super(EmailNotificationModel, self).__init__()
351 self.rhodecode_instance_name = rhodecode.CONFIG.get('rhodecode_title')
351 self.rhodecode_instance_name = rhodecode.CONFIG.get('rhodecode_title')
352
352
353 def _update_kwargs_for_render(self, kwargs):
353 def _update_kwargs_for_render(self, kwargs):
354 """
354 """
355 Inject params required for Mako rendering
355 Inject params required for Mako rendering
356
356
357 :param kwargs:
357 :param kwargs:
358 """
358 """
359
359
360 kwargs['rhodecode_instance_name'] = self.rhodecode_instance_name
360 kwargs['rhodecode_instance_name'] = self.rhodecode_instance_name
361 kwargs['rhodecode_version'] = rhodecode.__version__
361 kwargs['rhodecode_version'] = rhodecode.__version__
362 instance_url = h.route_url('home')
362 instance_url = h.route_url('home')
363 _kwargs = {
363 _kwargs = {
364 'instance_url': instance_url,
364 'instance_url': instance_url,
365 'whitespace_filter': self.whitespace_filter
365 'whitespace_filter': self.whitespace_filter
366 }
366 }
367 _kwargs.update(kwargs)
367 _kwargs.update(kwargs)
368 return _kwargs
368 return _kwargs
369
369
370 def whitespace_filter(self, text):
370 def whitespace_filter(self, text):
371 return text.replace('\n', '').replace('\t', '')
371 return text.replace('\n', '').replace('\t', '')
372
372
373 def get_renderer(self, type_, request):
373 def get_renderer(self, type_, request):
374 template_name = self.email_types[type_]
374 template_name = self.email_types[type_]
375 return request.get_partial_renderer(template_name)
375 return request.get_partial_renderer(template_name)
376
376
377 def render_email(self, type_, **kwargs):
377 def render_email(self, type_, **kwargs):
378 """
378 """
379 renders template for email, and returns a tuple of
379 renders template for email, and returns a tuple of
380 (subject, email_headers, email_html_body, email_plaintext_body)
380 (subject, email_headers, email_html_body, email_plaintext_body)
381 """
381 """
382 # translator and helpers inject
382 # translator and helpers inject
383 _kwargs = self._update_kwargs_for_render(kwargs)
383 _kwargs = self._update_kwargs_for_render(kwargs)
384 request = get_current_request()
384 request = get_current_request()
385 email_template = self.get_renderer(type_, request=request)
385 email_template = self.get_renderer(type_, request=request)
386
386
387 subject = email_template.render('subject', **_kwargs)
387 subject = email_template.render('subject', **_kwargs)
388
388
389 try:
389 try:
390 headers = email_template.render('headers', **_kwargs)
390 headers = email_template.render('headers', **_kwargs)
391 except AttributeError:
391 except AttributeError:
392 # it's not defined in template, ok we can skip it
392 # it's not defined in template, ok we can skip it
393 headers = ''
393 headers = ''
394
394
395 try:
395 try:
396 body_plaintext = email_template.render('body_plaintext', **_kwargs)
396 body_plaintext = email_template.render('body_plaintext', **_kwargs)
397 except AttributeError:
397 except AttributeError:
398 # it's not defined in template, ok we can skip it
398 # it's not defined in template, ok we can skip it
399 body_plaintext = ''
399 body_plaintext = ''
400
400
401 # render WHOLE template
401 # render WHOLE template
402 body = email_template.render(None, **_kwargs)
402 body = email_template.render(None, **_kwargs)
403
403
404 try:
404 try:
405 # Inline CSS styles and conversion
405 # Inline CSS styles and conversion
406 body = self.premailer_instance.transform(body)
406 body = self.premailer_instance.transform(body)
407 except Exception:
407 except Exception:
408 log.exception('Failed to parse body with premailer')
408 log.exception('Failed to parse body with premailer')
409 pass
409 pass
410
410
411 return subject, headers, body, body_plaintext
411 return subject, headers, body, body_plaintext
General Comments 0
You need to be logged in to leave comments. Login now