##// END OF EJS Templates
templates: rename email_templates to email...
Thomas De Schampheleire -
r8418:d379e2c3 default
parent child Browse files
Show More
@@ -1,235 +1,235 b''
1 1 # -*- coding: utf-8 -*-
2 2 # This program is free software: you can redistribute it and/or modify
3 3 # it under the terms of the GNU General Public License as published by
4 4 # the Free Software Foundation, either version 3 of the License, or
5 5 # (at your option) any later version.
6 6 #
7 7 # This program is distributed in the hope that it will be useful,
8 8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 10 # GNU General Public License for more details.
11 11 #
12 12 # You should have received a copy of the GNU General Public License
13 13 # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 14 """
15 15 kallithea.model.notification
16 16 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
17 17
18 18 Model for notifications
19 19
20 20
21 21 This file was forked by the Kallithea project in July 2014.
22 22 Original author and date, and relevant copyright and licensing information is below:
23 23 :created_on: Nov 20, 2011
24 24 :author: marcink
25 25 :copyright: (c) 2013 RhodeCode GmbH, and others.
26 26 :license: GPLv3, see LICENSE.md for more details.
27 27 """
28 28
29 29 import datetime
30 30 import logging
31 31
32 32 from tg import app_globals
33 33 from tg import tmpl_context as c
34 34 from tg.i18n import ugettext as _
35 35
36 36 from kallithea.lib import helpers as h
37 37 from kallithea.model.db import User
38 38
39 39
40 40 log = logging.getLogger(__name__)
41 41
42 42
43 43 class NotificationModel(object):
44 44
45 45 TYPE_CHANGESET_COMMENT = 'cs_comment'
46 46 TYPE_MESSAGE = 'message'
47 47 TYPE_MENTION = 'mention' # not used
48 48 TYPE_REGISTRATION = 'registration'
49 49 TYPE_PULL_REQUEST = 'pull_request'
50 50 TYPE_PULL_REQUEST_COMMENT = 'pull_request_comment'
51 51
52 52 def create(self, created_by, subject, body, recipients=None,
53 53 type_=TYPE_MESSAGE, with_email=True,
54 54 email_kwargs=None, repo_name=None):
55 55 """
56 56
57 57 Creates notification of given type
58 58
59 59 :param created_by: int, str or User instance. User who created this
60 60 notification
61 61 :param subject:
62 62 :param body:
63 63 :param recipients: list of int, str or User objects, when None
64 64 is given send to all admins
65 65 :param type_: type of notification
66 66 :param with_email: send email with this notification
67 67 :param email_kwargs: additional dict to pass as args to email template
68 68 """
69 69 from kallithea.lib.celerylib import tasks
70 70 email_kwargs = email_kwargs or {}
71 71 if recipients and not getattr(recipients, '__iter__', False):
72 72 raise Exception('recipients must be a list or iterable')
73 73
74 74 created_by_obj = User.guess_instance(created_by)
75 75
76 76 recipients_objs = set()
77 77 if recipients:
78 78 for u in recipients:
79 79 obj = User.guess_instance(u)
80 80 if obj is not None:
81 81 recipients_objs.add(obj)
82 82 else:
83 83 # TODO: inform user that requested operation couldn't be completed
84 84 log.error('cannot email unknown user %r', u)
85 85 log.debug('sending notifications %s to %s',
86 86 type_, recipients_objs
87 87 )
88 88 elif recipients is None:
89 89 # empty recipients means to all admins
90 90 recipients_objs = User.query().filter(User.admin == True).all()
91 91 log.debug('sending notifications %s to admins: %s',
92 92 type_, recipients_objs
93 93 )
94 94 #else: silently skip notification mails?
95 95
96 96 if not with_email:
97 97 return
98 98
99 99 headers = {}
100 100 headers['X-Kallithea-Notification-Type'] = type_
101 101 if 'threading' in email_kwargs:
102 102 headers['References'] = ' '.join('<%s>' % x for x in email_kwargs['threading'])
103 103
104 104 # this is passed into template
105 105 created_on = h.fmt_date(datetime.datetime.now())
106 106 html_kwargs = {
107 107 'subject': subject,
108 108 'body': h.render_w_mentions(body, repo_name),
109 109 'when': created_on,
110 110 'user': created_by_obj.username,
111 111 }
112 112
113 113 txt_kwargs = {
114 114 'subject': subject,
115 115 'body': body,
116 116 'when': created_on,
117 117 'user': created_by_obj.username,
118 118 }
119 119
120 120 html_kwargs.update(email_kwargs)
121 121 txt_kwargs.update(email_kwargs)
122 122 email_subject = EmailNotificationModel() \
123 123 .get_email_description(type_, **txt_kwargs)
124 124 email_txt_body = EmailNotificationModel() \
125 125 .get_email_tmpl(type_, 'txt', **txt_kwargs)
126 126 email_html_body = EmailNotificationModel() \
127 127 .get_email_tmpl(type_, 'html', **html_kwargs)
128 128
129 129 # don't send email to the person who caused the notification, except for
130 130 # notifications about new pull requests where the author is explicitly
131 131 # added.
132 132 rec_mails = set(obj.email for obj in recipients_objs)
133 133 if type_ == NotificationModel.TYPE_PULL_REQUEST:
134 134 rec_mails.add(created_by_obj.email)
135 135 else:
136 136 rec_mails.discard(created_by_obj.email)
137 137
138 138 # send email with notification to participants
139 139 for rec_mail in sorted(rec_mails):
140 140 tasks.send_email([rec_mail], email_subject, email_txt_body,
141 141 email_html_body, headers,
142 142 from_name=created_by_obj.full_name_or_username)
143 143
144 144
145 145 class EmailNotificationModel(object):
146 146
147 147 TYPE_CHANGESET_COMMENT = NotificationModel.TYPE_CHANGESET_COMMENT
148 148 TYPE_MESSAGE = NotificationModel.TYPE_MESSAGE # only used for testing
149 149 # NotificationModel.TYPE_MENTION is not used
150 150 TYPE_PASSWORD_RESET = 'password_link'
151 151 TYPE_REGISTRATION = NotificationModel.TYPE_REGISTRATION
152 152 TYPE_PULL_REQUEST = NotificationModel.TYPE_PULL_REQUEST
153 153 TYPE_PULL_REQUEST_COMMENT = NotificationModel.TYPE_PULL_REQUEST_COMMENT
154 154 TYPE_DEFAULT = 'default'
155 155
156 156 def __init__(self):
157 157 super(EmailNotificationModel, self).__init__()
158 158 self._tmpl_lookup = app_globals.mako_lookup
159 159 self.email_types = {
160 160 self.TYPE_CHANGESET_COMMENT: 'changeset_comment',
161 161 self.TYPE_PASSWORD_RESET: 'password_reset',
162 162 self.TYPE_REGISTRATION: 'registration',
163 163 self.TYPE_DEFAULT: 'default',
164 164 self.TYPE_PULL_REQUEST: 'pull_request',
165 165 self.TYPE_PULL_REQUEST_COMMENT: 'pull_request_comment',
166 166 }
167 167 self._subj_map = {
168 168 self.TYPE_CHANGESET_COMMENT: _('[Comment] %(repo_name)s changeset %(short_id)s "%(message_short)s" on %(branch)s by %(cs_author_username)s'),
169 169 self.TYPE_MESSAGE: 'Test Message',
170 170 # self.TYPE_PASSWORD_RESET
171 171 self.TYPE_REGISTRATION: _('New user %(new_username)s registered'),
172 172 # self.TYPE_DEFAULT
173 173 self.TYPE_PULL_REQUEST: _('[Review] %(repo_name)s PR %(pr_nice_id)s "%(pr_title_short)s" from %(pr_source_branch)s by %(pr_owner_username)s'),
174 174 self.TYPE_PULL_REQUEST_COMMENT: _('[Comment] %(repo_name)s PR %(pr_nice_id)s "%(pr_title_short)s" from %(pr_source_branch)s by %(pr_owner_username)s'),
175 175 }
176 176
177 177 def get_email_description(self, type_, **kwargs):
178 178 """
179 179 return subject for email based on given type
180 180 """
181 181 tmpl = self._subj_map[type_]
182 182 try:
183 183 subj = tmpl % kwargs
184 184 except KeyError as e:
185 185 log.error('error generating email subject for %r from %s: %s', type_, ', '.join(self._subj_map), e)
186 186 raise
187 187 # gmail doesn't do proper threading but will ignore leading square
188 188 # bracket content ... so that is where we put status info
189 189 bracket_tags = []
190 190 status_change = kwargs.get('status_change')
191 191 if status_change:
192 192 bracket_tags.append(str(status_change)) # apply str to evaluate LazyString before .join
193 193 if kwargs.get('closing_pr'):
194 194 bracket_tags.append(_('Closing'))
195 195 if bracket_tags:
196 196 if subj.startswith('['):
197 197 subj = '[' + ', '.join(bracket_tags) + ': ' + subj[1:]
198 198 else:
199 199 subj = '[' + ', '.join(bracket_tags) + '] ' + subj
200 200 return subj
201 201
202 202 def get_email_tmpl(self, type_, content_type, **kwargs):
203 203 """
204 204 return generated template for email based on given type
205 205 """
206 206
207 base = 'email_templates/' + self.email_types.get(type_, self.email_types[self.TYPE_DEFAULT]) + '.' + content_type
207 base = 'email/' + self.email_types.get(type_, self.email_types[self.TYPE_DEFAULT]) + '.' + content_type
208 208 email_template = self._tmpl_lookup.get_template(base)
209 209 # translator and helpers inject
210 210 _kwargs = {'_': _,
211 211 'h': h,
212 212 'c': c}
213 213 _kwargs.update(kwargs)
214 214 if content_type == 'html':
215 215 _kwargs.update({
216 216 "color_text": "#202020",
217 217 "color_emph": "#395fa0",
218 218 "color_link": "#395fa0",
219 219 "color_border": "#ddd",
220 220 "color_background_grey": "#f9f9f9",
221 221 "color_button": "#395fa0",
222 222 "monospace_style": "font-family:Lucida Console,Consolas,Monaco,Inconsolata,Liberation Mono,monospace",
223 223 "sans_style": "font-family:Helvetica,Arial,sans-serif",
224 224 })
225 225 _kwargs.update({
226 226 "default_style": "%(sans_style)s;font-weight:200;font-size:14px;line-height:17px;color:%(color_text)s" % _kwargs,
227 227 "comment_style": "%(monospace_style)s;white-space:pre-wrap" % _kwargs,
228 228 "data_style": "border:%(color_border)s 1px solid;background:%(color_background_grey)s" % _kwargs,
229 229 "emph_style": "font-weight:600;color:%(color_emph)s" % _kwargs,
230 230 "link_style": "color:%(color_link)s;text-decoration:none" % _kwargs,
231 231 "link_text_style": "color:%(color_text)s;text-decoration:none;border:%(color_border)s 1px solid;background:%(color_background_grey)s" % _kwargs,
232 232 })
233 233
234 234 log.debug('rendering tmpl %s with kwargs %s', base, _kwargs)
235 235 return email_template.render_unicode(**_kwargs)
1 NO CONTENT: file renamed from kallithea/templates/email_templates/button.html to kallithea/templates/email/button.html
1 NO CONTENT: file renamed from kallithea/templates/email_templates/button.txt to kallithea/templates/email/button.txt
1 NO CONTENT: file renamed from kallithea/templates/email_templates/changeset_comment.html to kallithea/templates/email/changeset_comment.html
1 NO CONTENT: file renamed from kallithea/templates/email_templates/changeset_comment.txt to kallithea/templates/email/changeset_comment.txt
1 NO CONTENT: file renamed from kallithea/templates/email_templates/comment.html to kallithea/templates/email/comment.html
1 NO CONTENT: file renamed from kallithea/templates/email_templates/comment.txt to kallithea/templates/email/comment.txt
1 NO CONTENT: file renamed from kallithea/templates/email_templates/default.html to kallithea/templates/email/default.html
1 NO CONTENT: file renamed from kallithea/templates/email_templates/default.txt to kallithea/templates/email/default.txt
1 NO CONTENT: file renamed from kallithea/templates/email_templates/header.html to kallithea/templates/email/header.html
1 NO CONTENT: file renamed from kallithea/templates/email_templates/header.txt to kallithea/templates/email/header.txt
1 NO CONTENT: file renamed from kallithea/templates/email_templates/main.html to kallithea/templates/email/main.html
1 NO CONTENT: file renamed from kallithea/templates/email_templates/password_reset.html to kallithea/templates/email/password_reset.html
1 NO CONTENT: file renamed from kallithea/templates/email_templates/password_reset.txt to kallithea/templates/email/password_reset.txt
1 NO CONTENT: file renamed from kallithea/templates/email_templates/pull_request.html to kallithea/templates/email/pull_request.html
1 NO CONTENT: file renamed from kallithea/templates/email_templates/pull_request.txt to kallithea/templates/email/pull_request.txt
1 NO CONTENT: file renamed from kallithea/templates/email_templates/pull_request_comment.html to kallithea/templates/email/pull_request_comment.html
1 NO CONTENT: file renamed from kallithea/templates/email_templates/pull_request_comment.txt to kallithea/templates/email/pull_request_comment.txt
1 NO CONTENT: file renamed from kallithea/templates/email_templates/registration.html to kallithea/templates/email/registration.html
1 NO CONTENT: file renamed from kallithea/templates/email_templates/registration.txt to kallithea/templates/email/registration.txt
@@ -1,24 +1,24 b''
1 1 #!/bin/bash -xe
2 2
3 3 # Enforce some consistency in whitespace - just to avoid spurious whitespaces changes
4 4
5 files=`hg mani | egrep -v '/fontello/|/email_templates/|(^LICENSE-MERGELY.html|^docs/Makefile|^scripts/whitespacecleanup.sh|/(graph|mergely|native.history)\.js|/test_dump_html_mails.ref.html|\.png|\.gif|\.ico|\.pot|\.po|\.mo|\.tar\.gz|\.diff)$'`
5 files=`hg mani | egrep -v '/fontello/|/templates/email/|(^LICENSE-MERGELY.html|^docs/Makefile|^scripts/whitespacecleanup.sh|/(graph|mergely|native.history)\.js|/test_dump_html_mails.ref.html|\.png|\.gif|\.ico|\.pot|\.po|\.mo|\.tar\.gz|\.diff)$'`
6 6
7 7 sed -i "s/`printf '\r'`//g" $files
8 8 sed -i -e "s,`printf '\t'`, ,g" $files
9 9 sed -i -e "s, *$,,g" $files
10 10 sed -i -e 's,\([^ ]\)\\$,\1 \\,g' -e 's,\(["'"'"']["'"'"']["'"'"']\) \\$,\1\\,g' $files
11 11 # ensure one trailing newline - remove empty last line and make last line include trailing newline:
12 12 sed -i -e '$,${/^$/d}' -e '$a\' $files
13 13
14 14 sed -i -e 's,\([^ /]\){,\1 {,g' `hg loc '*.css'`
15 15 sed -i -e 's|^\([^ /].*,\)\([^ ]\)|\1 \2|g' `hg loc '*.css'`
16 16
17 17 hg mani | xargs chmod -x
18 18 hg loc 'set:!binary()&grep("^#!")&!(**_tmpl.py)&!(**/template**)' | xargs chmod +x
19 19
20 20 # isort is installed from dev_requirements.txt
21 21 hg loc 'set:!binary()&grep("^#!.*python")' '*.py' | xargs isort --line-width 160 --lines-after-imports 2
22 22
23 23 echo "diff after $0:"
24 24 hg diff
General Comments 0
You need to be logged in to leave comments. Login now