##// END OF EJS Templates
emailing: log failing emailing as an error...
Mads Kiilerich -
r3781:40d50bb7 beta
parent child Browse files
Show More
@@ -1,281 +1,285 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.notification
3 rhodecode.model.notification
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Model for notifications
6 Model for notifications
7
7
8
8
9 :created_on: Nov 20, 2011
9 :created_on: Nov 20, 2011
10 :author: marcink
10 :author: marcink
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
12 :license: GPLv3, see COPYING for more details.
12 :license: GPLv3, see COPYING for more details.
13 """
13 """
14 # This program is free software: you can redistribute it and/or modify
14 # This program is free software: you can redistribute it and/or modify
15 # it under the terms of the GNU General Public License as published by
15 # it under the terms of the GNU General Public License as published by
16 # the Free Software Foundation, either version 3 of the License, or
16 # the Free Software Foundation, either version 3 of the License, or
17 # (at your option) any later version.
17 # (at your option) any later version.
18 #
18 #
19 # This program is distributed in the hope that it will be useful,
19 # This program is distributed in the hope that it will be useful,
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # but WITHOUT ANY WARRANTY; without even the implied warranty of
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 # GNU General Public License for more details.
22 # GNU General Public License for more details.
23 #
23 #
24 # You should have received a copy of the GNU General Public License
24 # You should have received a copy of the GNU General Public License
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 # along with this program. If not, see <http://www.gnu.org/licenses/>.
26
26
27 import os
27 import os
28 import logging
28 import logging
29 import traceback
29 import traceback
30
30
31 from pylons import tmpl_context as c
31 from pylons import tmpl_context as c
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33
33
34 import rhodecode
34 import rhodecode
35 from rhodecode.lib import helpers as h
35 from rhodecode.lib import helpers as h
36 from rhodecode.model import BaseModel
36 from rhodecode.model import BaseModel
37 from rhodecode.model.db import Notification, User, UserNotification
37 from rhodecode.model.db import Notification, User, UserNotification
38 from rhodecode.model.meta import Session
38 from rhodecode.model.meta import Session
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(self, created_by, subject, body, recipients=None,
57 def create(self, created_by, subject, body, recipients=None,
58 type_=Notification.TYPE_MESSAGE, with_email=True,
58 type_=Notification.TYPE_MESSAGE, with_email=True,
59 email_kwargs={}, email_subject=None):
59 email_kwargs={}, email_subject=None):
60 """
60 """
61
61
62 Creates notification of given type
62 Creates notification of given type
63
63
64 :param created_by: int, str or User instance. User who created this
64 :param created_by: int, str or User instance. User who created this
65 notification
65 notification
66 :param subject:
66 :param subject:
67 :param body:
67 :param body:
68 :param recipients: list of int, str or User objects, when None
68 :param recipients: list of int, str or User objects, when None
69 is given send to all admins
69 is given send to all admins
70 :param type_: type of notification
70 :param type_: type of notification
71 :param with_email: send email with this notification
71 :param with_email: send email with this notification
72 :param email_kwargs: additional dict to pass as args to email template
72 :param email_kwargs: additional dict to pass as args to email template
73 :param email_subject: use given subject as email subject
73 :param email_subject: use given subject as email subject
74 """
74 """
75 from rhodecode.lib.celerylib import tasks, run_task
75 from rhodecode.lib.celerylib import tasks, run_task
76
76
77 if recipients and not getattr(recipients, '__iter__', False):
77 if recipients and not getattr(recipients, '__iter__', False):
78 raise Exception('recipients must be a list or iterable')
78 raise Exception('recipients must be a list or iterable')
79
79
80 created_by_obj = self._get_user(created_by)
80 created_by_obj = self._get_user(created_by)
81
81
82 if recipients:
82 if recipients:
83 recipients_objs = []
83 recipients_objs = []
84 for u in recipients:
84 for u in recipients:
85 obj = self._get_user(u)
85 obj = self._get_user(u)
86 if obj:
86 if obj:
87 recipients_objs.append(obj)
87 recipients_objs.append(obj)
88 else:
89 # TODO: inform user that requested operation couldn't be completed
90 log.error('cannot email unknown user %r', u)
88 recipients_objs = set(recipients_objs)
91 recipients_objs = set(recipients_objs)
89 log.debug('sending notifications %s to %s' % (
92 log.debug('sending notifications %s to %s' % (
90 type_, recipients_objs)
93 type_, recipients_objs)
91 )
94 )
92 else:
95 else:
93 # empty recipients means to all admins
96 # empty recipients means to all admins
94 recipients_objs = User.query().filter(User.admin == True).all()
97 recipients_objs = User.query().filter(User.admin == True).all()
95 log.debug('sending notifications %s to admins: %s' % (
98 log.debug('sending notifications %s to admins: %s' % (
96 type_, recipients_objs)
99 type_, recipients_objs)
97 )
100 )
101 # TODO: inform user who are notified
98 notif = Notification.create(
102 notif = Notification.create(
99 created_by=created_by_obj, subject=subject,
103 created_by=created_by_obj, subject=subject,
100 body=body, recipients=recipients_objs, type_=type_
104 body=body, recipients=recipients_objs, type_=type_
101 )
105 )
102
106
103 if not with_email:
107 if not with_email:
104 return notif
108 return notif
105
109
106 #don't send email to person who created this comment
110 #don't send email to person who created this comment
107 rec_objs = set(recipients_objs).difference(set([created_by_obj]))
111 rec_objs = set(recipients_objs).difference(set([created_by_obj]))
108
112
109 # send email with notification to all other participants
113 # send email with notification to all other participants
110 for rec in rec_objs:
114 for rec in rec_objs:
111 if not email_subject:
115 if not email_subject:
112 email_subject = NotificationModel()\
116 email_subject = NotificationModel()\
113 .make_description(notif, show_age=False)
117 .make_description(notif, show_age=False)
114 type_ = type_
118 type_ = type_
115 email_body = None # we set body to none, we just send HTML emails
119 email_body = None # we set body to none, we just send HTML emails
116 ## this is passed into template
120 ## this is passed into template
117 kwargs = {'subject': subject, 'body': h.rst_w_mentions(body)}
121 kwargs = {'subject': subject, 'body': h.rst_w_mentions(body)}
118 kwargs.update(email_kwargs)
122 kwargs.update(email_kwargs)
119 email_body_html = EmailNotificationModel()\
123 email_body_html = EmailNotificationModel()\
120 .get_email_tmpl(type_, **kwargs)
124 .get_email_tmpl(type_, **kwargs)
121
125
122 run_task(tasks.send_email, rec.email, email_subject, email_body,
126 run_task(tasks.send_email, rec.email, email_subject, email_body,
123 email_body_html)
127 email_body_html)
124
128
125 return notif
129 return notif
126
130
127 def delete(self, user, notification):
131 def delete(self, user, notification):
128 # we don't want to remove actual notification just the assignment
132 # we don't want to remove actual notification just the assignment
129 try:
133 try:
130 notification = self.__get_notification(notification)
134 notification = self.__get_notification(notification)
131 user = self._get_user(user)
135 user = self._get_user(user)
132 if notification and user:
136 if notification and user:
133 obj = UserNotification.query()\
137 obj = UserNotification.query()\
134 .filter(UserNotification.user == user)\
138 .filter(UserNotification.user == user)\
135 .filter(UserNotification.notification
139 .filter(UserNotification.notification
136 == notification)\
140 == notification)\
137 .one()
141 .one()
138 Session().delete(obj)
142 Session().delete(obj)
139 return True
143 return True
140 except Exception:
144 except Exception:
141 log.error(traceback.format_exc())
145 log.error(traceback.format_exc())
142 raise
146 raise
143
147
144 def get_for_user(self, user, filter_=None):
148 def get_for_user(self, user, filter_=None):
145 """
149 """
146 Get mentions for given user, filter them if filter dict is given
150 Get mentions for given user, filter them if filter dict is given
147
151
148 :param user:
152 :param user:
149 :param filter:
153 :param filter:
150 """
154 """
151 user = self._get_user(user)
155 user = self._get_user(user)
152
156
153 q = UserNotification.query()\
157 q = UserNotification.query()\
154 .filter(UserNotification.user == user)\
158 .filter(UserNotification.user == user)\
155 .join((Notification, UserNotification.notification_id ==
159 .join((Notification, UserNotification.notification_id ==
156 Notification.notification_id))
160 Notification.notification_id))
157
161
158 if filter_:
162 if filter_:
159 q = q.filter(Notification.type_.in_(filter_))
163 q = q.filter(Notification.type_.in_(filter_))
160
164
161 return q.all()
165 return q.all()
162
166
163 def mark_read(self, user, notification):
167 def mark_read(self, user, notification):
164 try:
168 try:
165 notification = self.__get_notification(notification)
169 notification = self.__get_notification(notification)
166 user = self._get_user(user)
170 user = self._get_user(user)
167 if notification and user:
171 if notification and user:
168 obj = UserNotification.query()\
172 obj = UserNotification.query()\
169 .filter(UserNotification.user == user)\
173 .filter(UserNotification.user == user)\
170 .filter(UserNotification.notification
174 .filter(UserNotification.notification
171 == notification)\
175 == notification)\
172 .one()
176 .one()
173 obj.read = True
177 obj.read = True
174 Session().add(obj)
178 Session().add(obj)
175 return True
179 return True
176 except Exception:
180 except Exception:
177 log.error(traceback.format_exc())
181 log.error(traceback.format_exc())
178 raise
182 raise
179
183
180 def mark_all_read_for_user(self, user, filter_=None):
184 def mark_all_read_for_user(self, user, filter_=None):
181 user = self._get_user(user)
185 user = self._get_user(user)
182 q = UserNotification.query()\
186 q = UserNotification.query()\
183 .filter(UserNotification.user == user)\
187 .filter(UserNotification.user == user)\
184 .filter(UserNotification.read == False)\
188 .filter(UserNotification.read == False)\
185 .join((Notification, UserNotification.notification_id ==
189 .join((Notification, UserNotification.notification_id ==
186 Notification.notification_id))
190 Notification.notification_id))
187 if filter_:
191 if filter_:
188 q = q.filter(Notification.type_.in_(filter_))
192 q = q.filter(Notification.type_.in_(filter_))
189
193
190 # this is a little inefficient but sqlalchemy doesn't support
194 # this is a little inefficient but sqlalchemy doesn't support
191 # update on joined tables :(
195 # update on joined tables :(
192 for obj in q.all():
196 for obj in q.all():
193 obj.read = True
197 obj.read = True
194 Session().add(obj)
198 Session().add(obj)
195
199
196 def get_unread_cnt_for_user(self, user):
200 def get_unread_cnt_for_user(self, user):
197 user = self._get_user(user)
201 user = self._get_user(user)
198 return UserNotification.query()\
202 return UserNotification.query()\
199 .filter(UserNotification.read == False)\
203 .filter(UserNotification.read == False)\
200 .filter(UserNotification.user == user).count()
204 .filter(UserNotification.user == user).count()
201
205
202 def get_unread_for_user(self, user):
206 def get_unread_for_user(self, user):
203 user = self._get_user(user)
207 user = self._get_user(user)
204 return [x.notification for x in UserNotification.query()\
208 return [x.notification for x in UserNotification.query()\
205 .filter(UserNotification.read == False)\
209 .filter(UserNotification.read == False)\
206 .filter(UserNotification.user == user).all()]
210 .filter(UserNotification.user == user).all()]
207
211
208 def get_user_notification(self, user, notification):
212 def get_user_notification(self, user, notification):
209 user = self._get_user(user)
213 user = self._get_user(user)
210 notification = self.__get_notification(notification)
214 notification = self.__get_notification(notification)
211
215
212 return UserNotification.query()\
216 return UserNotification.query()\
213 .filter(UserNotification.notification == notification)\
217 .filter(UserNotification.notification == notification)\
214 .filter(UserNotification.user == user).scalar()
218 .filter(UserNotification.user == user).scalar()
215
219
216 def make_description(self, notification, show_age=True):
220 def make_description(self, notification, show_age=True):
217 """
221 """
218 Creates a human readable description based on properties
222 Creates a human readable description based on properties
219 of notification object
223 of notification object
220 """
224 """
221 #alias
225 #alias
222 _n = notification
226 _n = notification
223 _map = {
227 _map = {
224 _n.TYPE_CHANGESET_COMMENT: _('%(user)s commented on changeset at %(when)s'),
228 _n.TYPE_CHANGESET_COMMENT: _('%(user)s commented on changeset at %(when)s'),
225 _n.TYPE_MESSAGE: _('%(user)s sent message at %(when)s'),
229 _n.TYPE_MESSAGE: _('%(user)s sent message at %(when)s'),
226 _n.TYPE_MENTION: _('%(user)s mentioned you at %(when)s'),
230 _n.TYPE_MENTION: _('%(user)s mentioned you at %(when)s'),
227 _n.TYPE_REGISTRATION: _('%(user)s registered in RhodeCode at %(when)s'),
231 _n.TYPE_REGISTRATION: _('%(user)s registered in RhodeCode at %(when)s'),
228 _n.TYPE_PULL_REQUEST: _('%(user)s opened new pull request at %(when)s'),
232 _n.TYPE_PULL_REQUEST: _('%(user)s opened new pull request at %(when)s'),
229 _n.TYPE_PULL_REQUEST_COMMENT: _('%(user)s commented on pull request at %(when)s')
233 _n.TYPE_PULL_REQUEST_COMMENT: _('%(user)s commented on pull request at %(when)s')
230 }
234 }
231 tmpl = _map[notification.type_]
235 tmpl = _map[notification.type_]
232
236
233 if show_age:
237 if show_age:
234 when = h.age(notification.created_on)
238 when = h.age(notification.created_on)
235 else:
239 else:
236 when = h.fmt_date(notification.created_on)
240 when = h.fmt_date(notification.created_on)
237
241
238 return tmpl % dict(
242 return tmpl % dict(
239 user=notification.created_by_user.username,
243 user=notification.created_by_user.username,
240 when=when,
244 when=when,
241 )
245 )
242
246
243
247
244 class EmailNotificationModel(BaseModel):
248 class EmailNotificationModel(BaseModel):
245
249
246 TYPE_CHANGESET_COMMENT = Notification.TYPE_CHANGESET_COMMENT
250 TYPE_CHANGESET_COMMENT = Notification.TYPE_CHANGESET_COMMENT
247 TYPE_PASSWORD_RESET = 'password_link'
251 TYPE_PASSWORD_RESET = 'password_link'
248 TYPE_REGISTRATION = Notification.TYPE_REGISTRATION
252 TYPE_REGISTRATION = Notification.TYPE_REGISTRATION
249 TYPE_PULL_REQUEST = Notification.TYPE_PULL_REQUEST
253 TYPE_PULL_REQUEST = Notification.TYPE_PULL_REQUEST
250 TYPE_PULL_REQUEST_COMMENT = Notification.TYPE_PULL_REQUEST_COMMENT
254 TYPE_PULL_REQUEST_COMMENT = Notification.TYPE_PULL_REQUEST_COMMENT
251 TYPE_DEFAULT = 'default'
255 TYPE_DEFAULT = 'default'
252
256
253 def __init__(self):
257 def __init__(self):
254 self._template_root = rhodecode.CONFIG['pylons.paths']['templates'][0]
258 self._template_root = rhodecode.CONFIG['pylons.paths']['templates'][0]
255 self._tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
259 self._tmpl_lookup = rhodecode.CONFIG['pylons.app_globals'].mako_lookup
256
260
257 self.email_types = {
261 self.email_types = {
258 self.TYPE_CHANGESET_COMMENT: 'email_templates/changeset_comment.html',
262 self.TYPE_CHANGESET_COMMENT: 'email_templates/changeset_comment.html',
259 self.TYPE_PASSWORD_RESET: 'email_templates/password_reset.html',
263 self.TYPE_PASSWORD_RESET: 'email_templates/password_reset.html',
260 self.TYPE_REGISTRATION: 'email_templates/registration.html',
264 self.TYPE_REGISTRATION: 'email_templates/registration.html',
261 self.TYPE_DEFAULT: 'email_templates/default.html',
265 self.TYPE_DEFAULT: 'email_templates/default.html',
262 self.TYPE_PULL_REQUEST: 'email_templates/pull_request.html',
266 self.TYPE_PULL_REQUEST: 'email_templates/pull_request.html',
263 self.TYPE_PULL_REQUEST_COMMENT: 'email_templates/pull_request_comment.html',
267 self.TYPE_PULL_REQUEST_COMMENT: 'email_templates/pull_request_comment.html',
264 }
268 }
265
269
266 def get_email_tmpl(self, type_, **kwargs):
270 def get_email_tmpl(self, type_, **kwargs):
267 """
271 """
268 return generated template for email based on given type
272 return generated template for email based on given type
269
273
270 :param type_:
274 :param type_:
271 """
275 """
272
276
273 base = self.email_types.get(type_, self.email_types[self.TYPE_DEFAULT])
277 base = self.email_types.get(type_, self.email_types[self.TYPE_DEFAULT])
274 email_template = self._tmpl_lookup.get_template(base)
278 email_template = self._tmpl_lookup.get_template(base)
275 # translator and helpers inject
279 # translator and helpers inject
276 _kwargs = {'_': _,
280 _kwargs = {'_': _,
277 'h': h,
281 'h': h,
278 'c': c}
282 'c': c}
279 _kwargs.update(kwargs)
283 _kwargs.update(kwargs)
280 log.debug('rendering tmpl %s with kwargs %s' % (base, _kwargs))
284 log.debug('rendering tmpl %s with kwargs %s' % (base, _kwargs))
281 return email_template.render(**_kwargs)
285 return email_template.render(**_kwargs)
@@ -1,158 +1,156 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.pull_request
3 rhodecode.model.pull_request
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 pull request model for RhodeCode
6 pull request model for RhodeCode
7
7
8 :created_on: Jun 6, 2012
8 :created_on: Jun 6, 2012
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2012-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2012-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25
26 import logging
26 import logging
27 import datetime
27 import datetime
28
28
29 from pylons.i18n.translation import _
29 from pylons.i18n.translation import _
30
30
31 from rhodecode.model.meta import Session
31 from rhodecode.model.meta import Session
32 from rhodecode.lib import helpers as h
32 from rhodecode.lib import helpers as h
33 from rhodecode.model import BaseModel
33 from rhodecode.model import BaseModel
34 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
34 from rhodecode.model.db import PullRequest, PullRequestReviewers, Notification,\
35 ChangesetStatus
35 ChangesetStatus
36 from rhodecode.model.notification import NotificationModel
36 from rhodecode.model.notification import NotificationModel
37 from rhodecode.lib.utils2 import safe_unicode
37 from rhodecode.lib.utils2 import safe_unicode
38
38
39
39
40 log = logging.getLogger(__name__)
40 log = logging.getLogger(__name__)
41
41
42
42
43 class PullRequestModel(BaseModel):
43 class PullRequestModel(BaseModel):
44
44
45 cls = PullRequest
45 cls = PullRequest
46
46
47 def __get_pull_request(self, pull_request):
47 def __get_pull_request(self, pull_request):
48 return self._get_instance(PullRequest, pull_request)
48 return self._get_instance(PullRequest, pull_request)
49
49
50 def get_all(self, repo):
50 def get_all(self, repo):
51 repo = self._get_repo(repo)
51 repo = self._get_repo(repo)
52 return PullRequest.query()\
52 return PullRequest.query()\
53 .filter(PullRequest.other_repo == repo)\
53 .filter(PullRequest.other_repo == repo)\
54 .order_by(PullRequest.created_on.desc())\
54 .order_by(PullRequest.created_on.desc())\
55 .all()
55 .all()
56
56
57 def create(self, created_by, org_repo, org_ref, other_repo, other_ref,
57 def create(self, created_by, org_repo, org_ref, other_repo, other_ref,
58 revisions, reviewers, title, description=None):
58 revisions, reviewers, title, description=None):
59 from rhodecode.model.changeset_status import ChangesetStatusModel
59 from rhodecode.model.changeset_status import ChangesetStatusModel
60
60
61 created_by_user = self._get_user(created_by)
61 created_by_user = self._get_user(created_by)
62 org_repo = self._get_repo(org_repo)
62 org_repo = self._get_repo(org_repo)
63 other_repo = self._get_repo(other_repo)
63 other_repo = self._get_repo(other_repo)
64
64
65 new = PullRequest()
65 new = PullRequest()
66 new.org_repo = org_repo
66 new.org_repo = org_repo
67 new.org_ref = org_ref
67 new.org_ref = org_ref
68 new.other_repo = other_repo
68 new.other_repo = other_repo
69 new.other_ref = other_ref
69 new.other_ref = other_ref
70 new.revisions = revisions
70 new.revisions = revisions
71 new.title = title
71 new.title = title
72 new.description = description
72 new.description = description
73 new.author = created_by_user
73 new.author = created_by_user
74 Session().add(new)
74 Session().add(new)
75 Session().flush()
75 Session().flush()
76 #members
76 #members
77 for member in set(reviewers):
77 for member in set(reviewers):
78 _usr = self._get_user(member)
78 _usr = self._get_user(member)
79 reviewer = PullRequestReviewers(_usr, new)
79 reviewer = PullRequestReviewers(_usr, new)
80 Session().add(reviewer)
80 Session().add(reviewer)
81
81
82 #reset state to under-review
82 #reset state to under-review
83 ChangesetStatusModel().set_status(
83 ChangesetStatusModel().set_status(
84 repo=org_repo,
84 repo=org_repo,
85 status=ChangesetStatus.STATUS_UNDER_REVIEW,
85 status=ChangesetStatus.STATUS_UNDER_REVIEW,
86 user=created_by_user,
86 user=created_by_user,
87 pull_request=new
87 pull_request=new
88 )
88 )
89 revision_data = [(x.raw_id, x.message)
89 revision_data = [(x.raw_id, x.message)
90 for x in map(org_repo.get_changeset, revisions)]
90 for x in map(org_repo.get_changeset, revisions)]
91 #notification to reviewers
91 #notification to reviewers
92 notif = NotificationModel()
93
94 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
92 pr_url = h.url('pullrequest_show', repo_name=other_repo.repo_name,
95 pull_request_id=new.pull_request_id,
93 pull_request_id=new.pull_request_id,
96 qualified=True,
94 qualified=True,
97 )
95 )
98 subject = safe_unicode(
96 subject = safe_unicode(
99 h.link_to(
97 h.link_to(
100 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
98 _('%(user)s wants you to review pull request #%(pr_id)s: %(pr_title)s') % \
101 {'user': created_by_user.username,
99 {'user': created_by_user.username,
102 'pr_title': new.title,
100 'pr_title': new.title,
103 'pr_id': new.pull_request_id},
101 'pr_id': new.pull_request_id},
104 pr_url
102 pr_url
105 )
103 )
106 )
104 )
107 body = description
105 body = description
108 kwargs = {
106 kwargs = {
109 'pr_title': title,
107 'pr_title': title,
110 'pr_user_created': h.person(created_by_user.email),
108 'pr_user_created': h.person(created_by_user.email),
111 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
109 'pr_repo_url': h.url('summary_home', repo_name=other_repo.repo_name,
112 qualified=True,),
110 qualified=True,),
113 'pr_url': pr_url,
111 'pr_url': pr_url,
114 'pr_revisions': revision_data
112 'pr_revisions': revision_data
115 }
113 }
116
114
117 notif.create(created_by=created_by_user, subject=subject, body=body,
115 NotificationModel().create(created_by=created_by_user, subject=subject, body=body,
118 recipients=reviewers,
116 recipients=reviewers,
119 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
117 type_=Notification.TYPE_PULL_REQUEST, email_kwargs=kwargs)
120 return new
118 return new
121
119
122 def update_reviewers(self, pull_request, reviewers_ids):
120 def update_reviewers(self, pull_request, reviewers_ids):
123 reviewers_ids = set(reviewers_ids)
121 reviewers_ids = set(reviewers_ids)
124 pull_request = self.__get_pull_request(pull_request)
122 pull_request = self.__get_pull_request(pull_request)
125 current_reviewers = PullRequestReviewers.query()\
123 current_reviewers = PullRequestReviewers.query()\
126 .filter(PullRequestReviewers.pull_request==
124 .filter(PullRequestReviewers.pull_request==
127 pull_request)\
125 pull_request)\
128 .all()
126 .all()
129 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
127 current_reviewers_ids = set([x.user.user_id for x in current_reviewers])
130
128
131 to_add = reviewers_ids.difference(current_reviewers_ids)
129 to_add = reviewers_ids.difference(current_reviewers_ids)
132 to_remove = current_reviewers_ids.difference(reviewers_ids)
130 to_remove = current_reviewers_ids.difference(reviewers_ids)
133
131
134 log.debug("Adding %s reviewers" % to_add)
132 log.debug("Adding %s reviewers" % to_add)
135 log.debug("Removing %s reviewers" % to_remove)
133 log.debug("Removing %s reviewers" % to_remove)
136
134
137 for uid in to_add:
135 for uid in to_add:
138 _usr = self._get_user(uid)
136 _usr = self._get_user(uid)
139 reviewer = PullRequestReviewers(_usr, pull_request)
137 reviewer = PullRequestReviewers(_usr, pull_request)
140 Session().add(reviewer)
138 Session().add(reviewer)
141
139
142 for uid in to_remove:
140 for uid in to_remove:
143 reviewer = PullRequestReviewers.query()\
141 reviewer = PullRequestReviewers.query()\
144 .filter(PullRequestReviewers.user_id==uid,
142 .filter(PullRequestReviewers.user_id==uid,
145 PullRequestReviewers.pull_request==pull_request)\
143 PullRequestReviewers.pull_request==pull_request)\
146 .scalar()
144 .scalar()
147 if reviewer:
145 if reviewer:
148 Session().delete(reviewer)
146 Session().delete(reviewer)
149
147
150 def delete(self, pull_request):
148 def delete(self, pull_request):
151 pull_request = self.__get_pull_request(pull_request)
149 pull_request = self.__get_pull_request(pull_request)
152 Session().delete(pull_request)
150 Session().delete(pull_request)
153
151
154 def close_pull_request(self, pull_request):
152 def close_pull_request(self, pull_request):
155 pull_request = self.__get_pull_request(pull_request)
153 pull_request = self.__get_pull_request(pull_request)
156 pull_request.status = PullRequest.STATUS_CLOSED
154 pull_request.status = PullRequest.STATUS_CLOSED
157 pull_request.updated_on = datetime.datetime.now()
155 pull_request.updated_on = datetime.datetime.now()
158 Session().add(pull_request)
156 Session().add(pull_request)
General Comments 0
You need to be logged in to leave comments. Login now