##// END OF EJS Templates
my-account: speed up fetching permissions in my account repos grid.
marcink -
r4144:6a12088f default
parent child Browse files
Show More
@@ -1,764 +1,765 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2019 RhodeCode GmbH
3 # Copyright (C) 2016-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 import logging
21 import logging
22 import datetime
22 import datetime
23 import string
23 import string
24
24
25 import formencode
25 import formencode
26 import formencode.htmlfill
26 import formencode.htmlfill
27 import peppercorn
27 import peppercorn
28 from pyramid.httpexceptions import HTTPFound
28 from pyramid.httpexceptions import HTTPFound
29 from pyramid.view import view_config
29 from pyramid.view import view_config
30
30
31 from rhodecode.apps._base import BaseAppView, DataGridAppView
31 from rhodecode.apps._base import BaseAppView, DataGridAppView
32 from rhodecode import forms
32 from rhodecode import forms
33 from rhodecode.lib import helpers as h
33 from rhodecode.lib import helpers as h
34 from rhodecode.lib import audit_logger
34 from rhodecode.lib import audit_logger
35 from rhodecode.lib.ext_json import json
35 from rhodecode.lib.ext_json import json
36 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired, \
36 from rhodecode.lib.auth import LoginRequired, NotAnonymous, CSRFRequired, \
37 HasRepoPermissionAny, HasRepoGroupPermissionAny
37 HasRepoPermissionAny, HasRepoGroupPermissionAny
38 from rhodecode.lib.channelstream import (
38 from rhodecode.lib.channelstream import (
39 channelstream_request, ChannelstreamException)
39 channelstream_request, ChannelstreamException)
40 from rhodecode.lib.utils2 import safe_int, md5, str2bool
40 from rhodecode.lib.utils2 import safe_int, md5, str2bool
41 from rhodecode.model.auth_token import AuthTokenModel
41 from rhodecode.model.auth_token import AuthTokenModel
42 from rhodecode.model.comment import CommentsModel
42 from rhodecode.model.comment import CommentsModel
43 from rhodecode.model.db import (
43 from rhodecode.model.db import (
44 IntegrityError, joinedload,
44 IntegrityError, joinedload,
45 Repository, UserEmailMap, UserApiKeys, UserFollowing,
45 Repository, UserEmailMap, UserApiKeys, UserFollowing,
46 PullRequest, UserBookmark, RepoGroup)
46 PullRequest, UserBookmark, RepoGroup)
47 from rhodecode.model.meta import Session
47 from rhodecode.model.meta import Session
48 from rhodecode.model.pull_request import PullRequestModel
48 from rhodecode.model.pull_request import PullRequestModel
49 from rhodecode.model.scm import RepoList
49 from rhodecode.model.scm import RepoList
50 from rhodecode.model.user import UserModel
50 from rhodecode.model.user import UserModel
51 from rhodecode.model.repo import RepoModel
51 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.user_group import UserGroupModel
52 from rhodecode.model.user_group import UserGroupModel
53 from rhodecode.model.validation_schema.schemas import user_schema
53 from rhodecode.model.validation_schema.schemas import user_schema
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57
57
58 class MyAccountView(BaseAppView, DataGridAppView):
58 class MyAccountView(BaseAppView, DataGridAppView):
59 ALLOW_SCOPED_TOKENS = False
59 ALLOW_SCOPED_TOKENS = False
60 """
60 """
61 This view has alternative version inside EE, if modified please take a look
61 This view has alternative version inside EE, if modified please take a look
62 in there as well.
62 in there as well.
63 """
63 """
64
64
65 def load_default_context(self):
65 def load_default_context(self):
66 c = self._get_local_tmpl_context()
66 c = self._get_local_tmpl_context()
67 c.user = c.auth_user.get_instance()
67 c.user = c.auth_user.get_instance()
68 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
68 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
69
69
70 return c
70 return c
71
71
72 @LoginRequired()
72 @LoginRequired()
73 @NotAnonymous()
73 @NotAnonymous()
74 @view_config(
74 @view_config(
75 route_name='my_account_profile', request_method='GET',
75 route_name='my_account_profile', request_method='GET',
76 renderer='rhodecode:templates/admin/my_account/my_account.mako')
76 renderer='rhodecode:templates/admin/my_account/my_account.mako')
77 def my_account_profile(self):
77 def my_account_profile(self):
78 c = self.load_default_context()
78 c = self.load_default_context()
79 c.active = 'profile'
79 c.active = 'profile'
80 return self._get_template_context(c)
80 return self._get_template_context(c)
81
81
82 @LoginRequired()
82 @LoginRequired()
83 @NotAnonymous()
83 @NotAnonymous()
84 @view_config(
84 @view_config(
85 route_name='my_account_password', request_method='GET',
85 route_name='my_account_password', request_method='GET',
86 renderer='rhodecode:templates/admin/my_account/my_account.mako')
86 renderer='rhodecode:templates/admin/my_account/my_account.mako')
87 def my_account_password(self):
87 def my_account_password(self):
88 c = self.load_default_context()
88 c = self.load_default_context()
89 c.active = 'password'
89 c.active = 'password'
90 c.extern_type = c.user.extern_type
90 c.extern_type = c.user.extern_type
91
91
92 schema = user_schema.ChangePasswordSchema().bind(
92 schema = user_schema.ChangePasswordSchema().bind(
93 username=c.user.username)
93 username=c.user.username)
94
94
95 form = forms.Form(
95 form = forms.Form(
96 schema,
96 schema,
97 action=h.route_path('my_account_password_update'),
97 action=h.route_path('my_account_password_update'),
98 buttons=(forms.buttons.save, forms.buttons.reset))
98 buttons=(forms.buttons.save, forms.buttons.reset))
99
99
100 c.form = form
100 c.form = form
101 return self._get_template_context(c)
101 return self._get_template_context(c)
102
102
103 @LoginRequired()
103 @LoginRequired()
104 @NotAnonymous()
104 @NotAnonymous()
105 @CSRFRequired()
105 @CSRFRequired()
106 @view_config(
106 @view_config(
107 route_name='my_account_password_update', request_method='POST',
107 route_name='my_account_password_update', request_method='POST',
108 renderer='rhodecode:templates/admin/my_account/my_account.mako')
108 renderer='rhodecode:templates/admin/my_account/my_account.mako')
109 def my_account_password_update(self):
109 def my_account_password_update(self):
110 _ = self.request.translate
110 _ = self.request.translate
111 c = self.load_default_context()
111 c = self.load_default_context()
112 c.active = 'password'
112 c.active = 'password'
113 c.extern_type = c.user.extern_type
113 c.extern_type = c.user.extern_type
114
114
115 schema = user_schema.ChangePasswordSchema().bind(
115 schema = user_schema.ChangePasswordSchema().bind(
116 username=c.user.username)
116 username=c.user.username)
117
117
118 form = forms.Form(
118 form = forms.Form(
119 schema, buttons=(forms.buttons.save, forms.buttons.reset))
119 schema, buttons=(forms.buttons.save, forms.buttons.reset))
120
120
121 if c.extern_type != 'rhodecode':
121 if c.extern_type != 'rhodecode':
122 raise HTTPFound(self.request.route_path('my_account_password'))
122 raise HTTPFound(self.request.route_path('my_account_password'))
123
123
124 controls = self.request.POST.items()
124 controls = self.request.POST.items()
125 try:
125 try:
126 valid_data = form.validate(controls)
126 valid_data = form.validate(controls)
127 UserModel().update_user(c.user.user_id, **valid_data)
127 UserModel().update_user(c.user.user_id, **valid_data)
128 c.user.update_userdata(force_password_change=False)
128 c.user.update_userdata(force_password_change=False)
129 Session().commit()
129 Session().commit()
130 except forms.ValidationFailure as e:
130 except forms.ValidationFailure as e:
131 c.form = e
131 c.form = e
132 return self._get_template_context(c)
132 return self._get_template_context(c)
133
133
134 except Exception:
134 except Exception:
135 log.exception("Exception updating password")
135 log.exception("Exception updating password")
136 h.flash(_('Error occurred during update of user password'),
136 h.flash(_('Error occurred during update of user password'),
137 category='error')
137 category='error')
138 else:
138 else:
139 instance = c.auth_user.get_instance()
139 instance = c.auth_user.get_instance()
140 self.session.setdefault('rhodecode_user', {}).update(
140 self.session.setdefault('rhodecode_user', {}).update(
141 {'password': md5(instance.password)})
141 {'password': md5(instance.password)})
142 self.session.save()
142 self.session.save()
143 h.flash(_("Successfully updated password"), category='success')
143 h.flash(_("Successfully updated password"), category='success')
144
144
145 raise HTTPFound(self.request.route_path('my_account_password'))
145 raise HTTPFound(self.request.route_path('my_account_password'))
146
146
147 @LoginRequired()
147 @LoginRequired()
148 @NotAnonymous()
148 @NotAnonymous()
149 @view_config(
149 @view_config(
150 route_name='my_account_auth_tokens', request_method='GET',
150 route_name='my_account_auth_tokens', request_method='GET',
151 renderer='rhodecode:templates/admin/my_account/my_account.mako')
151 renderer='rhodecode:templates/admin/my_account/my_account.mako')
152 def my_account_auth_tokens(self):
152 def my_account_auth_tokens(self):
153 _ = self.request.translate
153 _ = self.request.translate
154
154
155 c = self.load_default_context()
155 c = self.load_default_context()
156 c.active = 'auth_tokens'
156 c.active = 'auth_tokens'
157 c.lifetime_values = AuthTokenModel.get_lifetime_values(translator=_)
157 c.lifetime_values = AuthTokenModel.get_lifetime_values(translator=_)
158 c.role_values = [
158 c.role_values = [
159 (x, AuthTokenModel.cls._get_role_name(x))
159 (x, AuthTokenModel.cls._get_role_name(x))
160 for x in AuthTokenModel.cls.ROLES]
160 for x in AuthTokenModel.cls.ROLES]
161 c.role_options = [(c.role_values, _("Role"))]
161 c.role_options = [(c.role_values, _("Role"))]
162 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
162 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
163 c.user.user_id, show_expired=True)
163 c.user.user_id, show_expired=True)
164 c.role_vcs = AuthTokenModel.cls.ROLE_VCS
164 c.role_vcs = AuthTokenModel.cls.ROLE_VCS
165 return self._get_template_context(c)
165 return self._get_template_context(c)
166
166
167 def maybe_attach_token_scope(self, token):
167 def maybe_attach_token_scope(self, token):
168 # implemented in EE edition
168 # implemented in EE edition
169 pass
169 pass
170
170
171 @LoginRequired()
171 @LoginRequired()
172 @NotAnonymous()
172 @NotAnonymous()
173 @CSRFRequired()
173 @CSRFRequired()
174 @view_config(
174 @view_config(
175 route_name='my_account_auth_tokens_add', request_method='POST',)
175 route_name='my_account_auth_tokens_add', request_method='POST',)
176 def my_account_auth_tokens_add(self):
176 def my_account_auth_tokens_add(self):
177 _ = self.request.translate
177 _ = self.request.translate
178 c = self.load_default_context()
178 c = self.load_default_context()
179
179
180 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
180 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
181 description = self.request.POST.get('description')
181 description = self.request.POST.get('description')
182 role = self.request.POST.get('role')
182 role = self.request.POST.get('role')
183
183
184 token = UserModel().add_auth_token(
184 token = UserModel().add_auth_token(
185 user=c.user.user_id,
185 user=c.user.user_id,
186 lifetime_minutes=lifetime, role=role, description=description,
186 lifetime_minutes=lifetime, role=role, description=description,
187 scope_callback=self.maybe_attach_token_scope)
187 scope_callback=self.maybe_attach_token_scope)
188 token_data = token.get_api_data()
188 token_data = token.get_api_data()
189
189
190 audit_logger.store_web(
190 audit_logger.store_web(
191 'user.edit.token.add', action_data={
191 'user.edit.token.add', action_data={
192 'data': {'token': token_data, 'user': 'self'}},
192 'data': {'token': token_data, 'user': 'self'}},
193 user=self._rhodecode_user, )
193 user=self._rhodecode_user, )
194 Session().commit()
194 Session().commit()
195
195
196 h.flash(_("Auth token successfully created"), category='success')
196 h.flash(_("Auth token successfully created"), category='success')
197 return HTTPFound(h.route_path('my_account_auth_tokens'))
197 return HTTPFound(h.route_path('my_account_auth_tokens'))
198
198
199 @LoginRequired()
199 @LoginRequired()
200 @NotAnonymous()
200 @NotAnonymous()
201 @CSRFRequired()
201 @CSRFRequired()
202 @view_config(
202 @view_config(
203 route_name='my_account_auth_tokens_delete', request_method='POST')
203 route_name='my_account_auth_tokens_delete', request_method='POST')
204 def my_account_auth_tokens_delete(self):
204 def my_account_auth_tokens_delete(self):
205 _ = self.request.translate
205 _ = self.request.translate
206 c = self.load_default_context()
206 c = self.load_default_context()
207
207
208 del_auth_token = self.request.POST.get('del_auth_token')
208 del_auth_token = self.request.POST.get('del_auth_token')
209
209
210 if del_auth_token:
210 if del_auth_token:
211 token = UserApiKeys.get_or_404(del_auth_token)
211 token = UserApiKeys.get_or_404(del_auth_token)
212 token_data = token.get_api_data()
212 token_data = token.get_api_data()
213
213
214 AuthTokenModel().delete(del_auth_token, c.user.user_id)
214 AuthTokenModel().delete(del_auth_token, c.user.user_id)
215 audit_logger.store_web(
215 audit_logger.store_web(
216 'user.edit.token.delete', action_data={
216 'user.edit.token.delete', action_data={
217 'data': {'token': token_data, 'user': 'self'}},
217 'data': {'token': token_data, 'user': 'self'}},
218 user=self._rhodecode_user,)
218 user=self._rhodecode_user,)
219 Session().commit()
219 Session().commit()
220 h.flash(_("Auth token successfully deleted"), category='success')
220 h.flash(_("Auth token successfully deleted"), category='success')
221
221
222 return HTTPFound(h.route_path('my_account_auth_tokens'))
222 return HTTPFound(h.route_path('my_account_auth_tokens'))
223
223
224 @LoginRequired()
224 @LoginRequired()
225 @NotAnonymous()
225 @NotAnonymous()
226 @view_config(
226 @view_config(
227 route_name='my_account_emails', request_method='GET',
227 route_name='my_account_emails', request_method='GET',
228 renderer='rhodecode:templates/admin/my_account/my_account.mako')
228 renderer='rhodecode:templates/admin/my_account/my_account.mako')
229 def my_account_emails(self):
229 def my_account_emails(self):
230 _ = self.request.translate
230 _ = self.request.translate
231
231
232 c = self.load_default_context()
232 c = self.load_default_context()
233 c.active = 'emails'
233 c.active = 'emails'
234
234
235 c.user_email_map = UserEmailMap.query()\
235 c.user_email_map = UserEmailMap.query()\
236 .filter(UserEmailMap.user == c.user).all()
236 .filter(UserEmailMap.user == c.user).all()
237
237
238 schema = user_schema.AddEmailSchema().bind(
238 schema = user_schema.AddEmailSchema().bind(
239 username=c.user.username, user_emails=c.user.emails)
239 username=c.user.username, user_emails=c.user.emails)
240
240
241 form = forms.RcForm(schema,
241 form = forms.RcForm(schema,
242 action=h.route_path('my_account_emails_add'),
242 action=h.route_path('my_account_emails_add'),
243 buttons=(forms.buttons.save, forms.buttons.reset))
243 buttons=(forms.buttons.save, forms.buttons.reset))
244
244
245 c.form = form
245 c.form = form
246 return self._get_template_context(c)
246 return self._get_template_context(c)
247
247
248 @LoginRequired()
248 @LoginRequired()
249 @NotAnonymous()
249 @NotAnonymous()
250 @CSRFRequired()
250 @CSRFRequired()
251 @view_config(
251 @view_config(
252 route_name='my_account_emails_add', request_method='POST',
252 route_name='my_account_emails_add', request_method='POST',
253 renderer='rhodecode:templates/admin/my_account/my_account.mako')
253 renderer='rhodecode:templates/admin/my_account/my_account.mako')
254 def my_account_emails_add(self):
254 def my_account_emails_add(self):
255 _ = self.request.translate
255 _ = self.request.translate
256 c = self.load_default_context()
256 c = self.load_default_context()
257 c.active = 'emails'
257 c.active = 'emails'
258
258
259 schema = user_schema.AddEmailSchema().bind(
259 schema = user_schema.AddEmailSchema().bind(
260 username=c.user.username, user_emails=c.user.emails)
260 username=c.user.username, user_emails=c.user.emails)
261
261
262 form = forms.RcForm(
262 form = forms.RcForm(
263 schema, action=h.route_path('my_account_emails_add'),
263 schema, action=h.route_path('my_account_emails_add'),
264 buttons=(forms.buttons.save, forms.buttons.reset))
264 buttons=(forms.buttons.save, forms.buttons.reset))
265
265
266 controls = self.request.POST.items()
266 controls = self.request.POST.items()
267 try:
267 try:
268 valid_data = form.validate(controls)
268 valid_data = form.validate(controls)
269 UserModel().add_extra_email(c.user.user_id, valid_data['email'])
269 UserModel().add_extra_email(c.user.user_id, valid_data['email'])
270 audit_logger.store_web(
270 audit_logger.store_web(
271 'user.edit.email.add', action_data={
271 'user.edit.email.add', action_data={
272 'data': {'email': valid_data['email'], 'user': 'self'}},
272 'data': {'email': valid_data['email'], 'user': 'self'}},
273 user=self._rhodecode_user,)
273 user=self._rhodecode_user,)
274 Session().commit()
274 Session().commit()
275 except formencode.Invalid as error:
275 except formencode.Invalid as error:
276 h.flash(h.escape(error.error_dict['email']), category='error')
276 h.flash(h.escape(error.error_dict['email']), category='error')
277 except forms.ValidationFailure as e:
277 except forms.ValidationFailure as e:
278 c.user_email_map = UserEmailMap.query() \
278 c.user_email_map = UserEmailMap.query() \
279 .filter(UserEmailMap.user == c.user).all()
279 .filter(UserEmailMap.user == c.user).all()
280 c.form = e
280 c.form = e
281 return self._get_template_context(c)
281 return self._get_template_context(c)
282 except Exception:
282 except Exception:
283 log.exception("Exception adding email")
283 log.exception("Exception adding email")
284 h.flash(_('Error occurred during adding email'),
284 h.flash(_('Error occurred during adding email'),
285 category='error')
285 category='error')
286 else:
286 else:
287 h.flash(_("Successfully added email"), category='success')
287 h.flash(_("Successfully added email"), category='success')
288
288
289 raise HTTPFound(self.request.route_path('my_account_emails'))
289 raise HTTPFound(self.request.route_path('my_account_emails'))
290
290
291 @LoginRequired()
291 @LoginRequired()
292 @NotAnonymous()
292 @NotAnonymous()
293 @CSRFRequired()
293 @CSRFRequired()
294 @view_config(
294 @view_config(
295 route_name='my_account_emails_delete', request_method='POST')
295 route_name='my_account_emails_delete', request_method='POST')
296 def my_account_emails_delete(self):
296 def my_account_emails_delete(self):
297 _ = self.request.translate
297 _ = self.request.translate
298 c = self.load_default_context()
298 c = self.load_default_context()
299
299
300 del_email_id = self.request.POST.get('del_email_id')
300 del_email_id = self.request.POST.get('del_email_id')
301 if del_email_id:
301 if del_email_id:
302 email = UserEmailMap.get_or_404(del_email_id).email
302 email = UserEmailMap.get_or_404(del_email_id).email
303 UserModel().delete_extra_email(c.user.user_id, del_email_id)
303 UserModel().delete_extra_email(c.user.user_id, del_email_id)
304 audit_logger.store_web(
304 audit_logger.store_web(
305 'user.edit.email.delete', action_data={
305 'user.edit.email.delete', action_data={
306 'data': {'email': email, 'user': 'self'}},
306 'data': {'email': email, 'user': 'self'}},
307 user=self._rhodecode_user,)
307 user=self._rhodecode_user,)
308 Session().commit()
308 Session().commit()
309 h.flash(_("Email successfully deleted"),
309 h.flash(_("Email successfully deleted"),
310 category='success')
310 category='success')
311 return HTTPFound(h.route_path('my_account_emails'))
311 return HTTPFound(h.route_path('my_account_emails'))
312
312
313 @LoginRequired()
313 @LoginRequired()
314 @NotAnonymous()
314 @NotAnonymous()
315 @CSRFRequired()
315 @CSRFRequired()
316 @view_config(
316 @view_config(
317 route_name='my_account_notifications_test_channelstream',
317 route_name='my_account_notifications_test_channelstream',
318 request_method='POST', renderer='json_ext')
318 request_method='POST', renderer='json_ext')
319 def my_account_notifications_test_channelstream(self):
319 def my_account_notifications_test_channelstream(self):
320 message = 'Test message sent via Channelstream by user: {}, on {}'.format(
320 message = 'Test message sent via Channelstream by user: {}, on {}'.format(
321 self._rhodecode_user.username, datetime.datetime.now())
321 self._rhodecode_user.username, datetime.datetime.now())
322 payload = {
322 payload = {
323 # 'channel': 'broadcast',
323 # 'channel': 'broadcast',
324 'type': 'message',
324 'type': 'message',
325 'timestamp': datetime.datetime.utcnow(),
325 'timestamp': datetime.datetime.utcnow(),
326 'user': 'system',
326 'user': 'system',
327 'pm_users': [self._rhodecode_user.username],
327 'pm_users': [self._rhodecode_user.username],
328 'message': {
328 'message': {
329 'message': message,
329 'message': message,
330 'level': 'info',
330 'level': 'info',
331 'topic': '/notifications'
331 'topic': '/notifications'
332 }
332 }
333 }
333 }
334
334
335 registry = self.request.registry
335 registry = self.request.registry
336 rhodecode_plugins = getattr(registry, 'rhodecode_plugins', {})
336 rhodecode_plugins = getattr(registry, 'rhodecode_plugins', {})
337 channelstream_config = rhodecode_plugins.get('channelstream', {})
337 channelstream_config = rhodecode_plugins.get('channelstream', {})
338
338
339 try:
339 try:
340 channelstream_request(channelstream_config, [payload], '/message')
340 channelstream_request(channelstream_config, [payload], '/message')
341 except ChannelstreamException as e:
341 except ChannelstreamException as e:
342 log.exception('Failed to send channelstream data')
342 log.exception('Failed to send channelstream data')
343 return {"response": 'ERROR: {}'.format(e.__class__.__name__)}
343 return {"response": 'ERROR: {}'.format(e.__class__.__name__)}
344 return {"response": 'Channelstream data sent. '
344 return {"response": 'Channelstream data sent. '
345 'You should see a new live message now.'}
345 'You should see a new live message now.'}
346
346
347 def _load_my_repos_data(self, watched=False):
347 def _load_my_repos_data(self, watched=False):
348 if watched:
348 if watched:
349 admin = False
349 admin = False
350 follows_repos = Session().query(UserFollowing)\
350 follows_repos = Session().query(UserFollowing)\
351 .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
351 .filter(UserFollowing.user_id == self._rhodecode_user.user_id)\
352 .options(joinedload(UserFollowing.follows_repository))\
352 .options(joinedload(UserFollowing.follows_repository))\
353 .all()
353 .all()
354 repo_list = [x.follows_repository for x in follows_repos]
354 repo_list = [x.follows_repository for x in follows_repos]
355 else:
355 else:
356 admin = True
356 admin = True
357 repo_list = Repository.get_all_repos(
357 repo_list = Repository.get_all_repos(
358 user_id=self._rhodecode_user.user_id)
358 user_id=self._rhodecode_user.user_id)
359 repo_list = RepoList(repo_list, perm_set=[
359 repo_list = RepoList(repo_list, perm_set=[
360 'repository.read', 'repository.write', 'repository.admin'])
360 'repository.read', 'repository.write', 'repository.admin'],
361 extra_kwargs=dict(user=self._rhodecode_user))
361
362
362 repos_data = RepoModel().get_repos_as_dict(
363 repos_data = RepoModel().get_repos_as_dict(
363 repo_list=repo_list, admin=admin, short_name=False)
364 repo_list=repo_list, admin=admin, short_name=False)
364 # json used to render the grid
365 # json used to render the grid
365 return json.dumps(repos_data)
366 return json.dumps(repos_data)
366
367
367 @LoginRequired()
368 @LoginRequired()
368 @NotAnonymous()
369 @NotAnonymous()
369 @view_config(
370 @view_config(
370 route_name='my_account_repos', request_method='GET',
371 route_name='my_account_repos', request_method='GET',
371 renderer='rhodecode:templates/admin/my_account/my_account.mako')
372 renderer='rhodecode:templates/admin/my_account/my_account.mako')
372 def my_account_repos(self):
373 def my_account_repos(self):
373 c = self.load_default_context()
374 c = self.load_default_context()
374 c.active = 'repos'
375 c.active = 'repos'
375
376
376 # json used to render the grid
377 # json used to render the grid
377 c.data = self._load_my_repos_data()
378 c.data = self._load_my_repos_data()
378 return self._get_template_context(c)
379 return self._get_template_context(c)
379
380
380 @LoginRequired()
381 @LoginRequired()
381 @NotAnonymous()
382 @NotAnonymous()
382 @view_config(
383 @view_config(
383 route_name='my_account_watched', request_method='GET',
384 route_name='my_account_watched', request_method='GET',
384 renderer='rhodecode:templates/admin/my_account/my_account.mako')
385 renderer='rhodecode:templates/admin/my_account/my_account.mako')
385 def my_account_watched(self):
386 def my_account_watched(self):
386 c = self.load_default_context()
387 c = self.load_default_context()
387 c.active = 'watched'
388 c.active = 'watched'
388
389
389 # json used to render the grid
390 # json used to render the grid
390 c.data = self._load_my_repos_data(watched=True)
391 c.data = self._load_my_repos_data(watched=True)
391 return self._get_template_context(c)
392 return self._get_template_context(c)
392
393
393 @LoginRequired()
394 @LoginRequired()
394 @NotAnonymous()
395 @NotAnonymous()
395 @view_config(
396 @view_config(
396 route_name='my_account_bookmarks', request_method='GET',
397 route_name='my_account_bookmarks', request_method='GET',
397 renderer='rhodecode:templates/admin/my_account/my_account.mako')
398 renderer='rhodecode:templates/admin/my_account/my_account.mako')
398 def my_account_bookmarks(self):
399 def my_account_bookmarks(self):
399 c = self.load_default_context()
400 c = self.load_default_context()
400 c.active = 'bookmarks'
401 c.active = 'bookmarks'
401 c.bookmark_items = UserBookmark.get_bookmarks_for_user(
402 c.bookmark_items = UserBookmark.get_bookmarks_for_user(
402 self._rhodecode_db_user.user_id, cache=False)
403 self._rhodecode_db_user.user_id, cache=False)
403 return self._get_template_context(c)
404 return self._get_template_context(c)
404
405
405 def _process_bookmark_entry(self, entry, user_id):
406 def _process_bookmark_entry(self, entry, user_id):
406 position = safe_int(entry.get('position'))
407 position = safe_int(entry.get('position'))
407 cur_position = safe_int(entry.get('cur_position'))
408 cur_position = safe_int(entry.get('cur_position'))
408 if position is None:
409 if position is None:
409 return
410 return
410
411
411 # check if this is an existing entry
412 # check if this is an existing entry
412 is_new = False
413 is_new = False
413 db_entry = UserBookmark().get_by_position_for_user(cur_position, user_id)
414 db_entry = UserBookmark().get_by_position_for_user(cur_position, user_id)
414
415
415 if db_entry and str2bool(entry.get('remove')):
416 if db_entry and str2bool(entry.get('remove')):
416 log.debug('Marked bookmark %s for deletion', db_entry)
417 log.debug('Marked bookmark %s for deletion', db_entry)
417 Session().delete(db_entry)
418 Session().delete(db_entry)
418 return
419 return
419
420
420 if not db_entry:
421 if not db_entry:
421 # new
422 # new
422 db_entry = UserBookmark()
423 db_entry = UserBookmark()
423 is_new = True
424 is_new = True
424
425
425 should_save = False
426 should_save = False
426 default_redirect_url = ''
427 default_redirect_url = ''
427
428
428 # save repo
429 # save repo
429 if entry.get('bookmark_repo') and safe_int(entry.get('bookmark_repo')):
430 if entry.get('bookmark_repo') and safe_int(entry.get('bookmark_repo')):
430 repo = Repository.get(entry['bookmark_repo'])
431 repo = Repository.get(entry['bookmark_repo'])
431 perm_check = HasRepoPermissionAny(
432 perm_check = HasRepoPermissionAny(
432 'repository.read', 'repository.write', 'repository.admin')
433 'repository.read', 'repository.write', 'repository.admin')
433 if repo and perm_check(repo_name=repo.repo_name):
434 if repo and perm_check(repo_name=repo.repo_name):
434 db_entry.repository = repo
435 db_entry.repository = repo
435 should_save = True
436 should_save = True
436 default_redirect_url = '${repo_url}'
437 default_redirect_url = '${repo_url}'
437 # save repo group
438 # save repo group
438 elif entry.get('bookmark_repo_group') and safe_int(entry.get('bookmark_repo_group')):
439 elif entry.get('bookmark_repo_group') and safe_int(entry.get('bookmark_repo_group')):
439 repo_group = RepoGroup.get(entry['bookmark_repo_group'])
440 repo_group = RepoGroup.get(entry['bookmark_repo_group'])
440 perm_check = HasRepoGroupPermissionAny(
441 perm_check = HasRepoGroupPermissionAny(
441 'group.read', 'group.write', 'group.admin')
442 'group.read', 'group.write', 'group.admin')
442
443
443 if repo_group and perm_check(group_name=repo_group.group_name):
444 if repo_group and perm_check(group_name=repo_group.group_name):
444 db_entry.repository_group = repo_group
445 db_entry.repository_group = repo_group
445 should_save = True
446 should_save = True
446 default_redirect_url = '${repo_group_url}'
447 default_redirect_url = '${repo_group_url}'
447 # save generic info
448 # save generic info
448 elif entry.get('title') and entry.get('redirect_url'):
449 elif entry.get('title') and entry.get('redirect_url'):
449 should_save = True
450 should_save = True
450
451
451 if should_save:
452 if should_save:
452 # mark user and position
453 # mark user and position
453 db_entry.user_id = user_id
454 db_entry.user_id = user_id
454 db_entry.position = position
455 db_entry.position = position
455 db_entry.title = entry.get('title')
456 db_entry.title = entry.get('title')
456 db_entry.redirect_url = entry.get('redirect_url') or default_redirect_url
457 db_entry.redirect_url = entry.get('redirect_url') or default_redirect_url
457 log.debug('Saving bookmark %s, new:%s', db_entry, is_new)
458 log.debug('Saving bookmark %s, new:%s', db_entry, is_new)
458
459
459 Session().add(db_entry)
460 Session().add(db_entry)
460
461
461 @LoginRequired()
462 @LoginRequired()
462 @NotAnonymous()
463 @NotAnonymous()
463 @CSRFRequired()
464 @CSRFRequired()
464 @view_config(
465 @view_config(
465 route_name='my_account_bookmarks_update', request_method='POST')
466 route_name='my_account_bookmarks_update', request_method='POST')
466 def my_account_bookmarks_update(self):
467 def my_account_bookmarks_update(self):
467 _ = self.request.translate
468 _ = self.request.translate
468 c = self.load_default_context()
469 c = self.load_default_context()
469 c.active = 'bookmarks'
470 c.active = 'bookmarks'
470
471
471 controls = peppercorn.parse(self.request.POST.items())
472 controls = peppercorn.parse(self.request.POST.items())
472 user_id = c.user.user_id
473 user_id = c.user.user_id
473
474
474 # validate positions
475 # validate positions
475 positions = {}
476 positions = {}
476 for entry in controls.get('bookmarks', []):
477 for entry in controls.get('bookmarks', []):
477 position = safe_int(entry['position'])
478 position = safe_int(entry['position'])
478 if position is None:
479 if position is None:
479 continue
480 continue
480
481
481 if position in positions:
482 if position in positions:
482 h.flash(_("Position {} is defined twice. "
483 h.flash(_("Position {} is defined twice. "
483 "Please correct this error.").format(position), category='error')
484 "Please correct this error.").format(position), category='error')
484 return HTTPFound(h.route_path('my_account_bookmarks'))
485 return HTTPFound(h.route_path('my_account_bookmarks'))
485
486
486 entry['position'] = position
487 entry['position'] = position
487 entry['cur_position'] = safe_int(entry.get('cur_position'))
488 entry['cur_position'] = safe_int(entry.get('cur_position'))
488 positions[position] = entry
489 positions[position] = entry
489
490
490 try:
491 try:
491 for entry in positions.values():
492 for entry in positions.values():
492 self._process_bookmark_entry(entry, user_id)
493 self._process_bookmark_entry(entry, user_id)
493
494
494 Session().commit()
495 Session().commit()
495 h.flash(_("Update Bookmarks"), category='success')
496 h.flash(_("Update Bookmarks"), category='success')
496 except IntegrityError:
497 except IntegrityError:
497 h.flash(_("Failed to update bookmarks. "
498 h.flash(_("Failed to update bookmarks. "
498 "Make sure an unique position is used."), category='error')
499 "Make sure an unique position is used."), category='error')
499
500
500 return HTTPFound(h.route_path('my_account_bookmarks'))
501 return HTTPFound(h.route_path('my_account_bookmarks'))
501
502
502 @LoginRequired()
503 @LoginRequired()
503 @NotAnonymous()
504 @NotAnonymous()
504 @view_config(
505 @view_config(
505 route_name='my_account_goto_bookmark', request_method='GET',
506 route_name='my_account_goto_bookmark', request_method='GET',
506 renderer='rhodecode:templates/admin/my_account/my_account.mako')
507 renderer='rhodecode:templates/admin/my_account/my_account.mako')
507 def my_account_goto_bookmark(self):
508 def my_account_goto_bookmark(self):
508
509
509 bookmark_id = self.request.matchdict['bookmark_id']
510 bookmark_id = self.request.matchdict['bookmark_id']
510 user_bookmark = UserBookmark().query()\
511 user_bookmark = UserBookmark().query()\
511 .filter(UserBookmark.user_id == self.request.user.user_id) \
512 .filter(UserBookmark.user_id == self.request.user.user_id) \
512 .filter(UserBookmark.position == bookmark_id).scalar()
513 .filter(UserBookmark.position == bookmark_id).scalar()
513
514
514 redirect_url = h.route_path('my_account_bookmarks')
515 redirect_url = h.route_path('my_account_bookmarks')
515 if not user_bookmark:
516 if not user_bookmark:
516 raise HTTPFound(redirect_url)
517 raise HTTPFound(redirect_url)
517
518
518 # repository set
519 # repository set
519 if user_bookmark.repository:
520 if user_bookmark.repository:
520 repo_name = user_bookmark.repository.repo_name
521 repo_name = user_bookmark.repository.repo_name
521 base_redirect_url = h.route_path(
522 base_redirect_url = h.route_path(
522 'repo_summary', repo_name=repo_name)
523 'repo_summary', repo_name=repo_name)
523 if user_bookmark.redirect_url and \
524 if user_bookmark.redirect_url and \
524 '${repo_url}' in user_bookmark.redirect_url:
525 '${repo_url}' in user_bookmark.redirect_url:
525 redirect_url = string.Template(user_bookmark.redirect_url)\
526 redirect_url = string.Template(user_bookmark.redirect_url)\
526 .safe_substitute({'repo_url': base_redirect_url})
527 .safe_substitute({'repo_url': base_redirect_url})
527 else:
528 else:
528 redirect_url = base_redirect_url
529 redirect_url = base_redirect_url
529 # repository group set
530 # repository group set
530 elif user_bookmark.repository_group:
531 elif user_bookmark.repository_group:
531 repo_group_name = user_bookmark.repository_group.group_name
532 repo_group_name = user_bookmark.repository_group.group_name
532 base_redirect_url = h.route_path(
533 base_redirect_url = h.route_path(
533 'repo_group_home', repo_group_name=repo_group_name)
534 'repo_group_home', repo_group_name=repo_group_name)
534 if user_bookmark.redirect_url and \
535 if user_bookmark.redirect_url and \
535 '${repo_group_url}' in user_bookmark.redirect_url:
536 '${repo_group_url}' in user_bookmark.redirect_url:
536 redirect_url = string.Template(user_bookmark.redirect_url)\
537 redirect_url = string.Template(user_bookmark.redirect_url)\
537 .safe_substitute({'repo_group_url': base_redirect_url})
538 .safe_substitute({'repo_group_url': base_redirect_url})
538 else:
539 else:
539 redirect_url = base_redirect_url
540 redirect_url = base_redirect_url
540 # custom URL set
541 # custom URL set
541 elif user_bookmark.redirect_url:
542 elif user_bookmark.redirect_url:
542 server_url = h.route_url('home').rstrip('/')
543 server_url = h.route_url('home').rstrip('/')
543 redirect_url = string.Template(user_bookmark.redirect_url) \
544 redirect_url = string.Template(user_bookmark.redirect_url) \
544 .safe_substitute({'server_url': server_url})
545 .safe_substitute({'server_url': server_url})
545
546
546 log.debug('Redirecting bookmark %s to %s', user_bookmark, redirect_url)
547 log.debug('Redirecting bookmark %s to %s', user_bookmark, redirect_url)
547 raise HTTPFound(redirect_url)
548 raise HTTPFound(redirect_url)
548
549
549 @LoginRequired()
550 @LoginRequired()
550 @NotAnonymous()
551 @NotAnonymous()
551 @view_config(
552 @view_config(
552 route_name='my_account_perms', request_method='GET',
553 route_name='my_account_perms', request_method='GET',
553 renderer='rhodecode:templates/admin/my_account/my_account.mako')
554 renderer='rhodecode:templates/admin/my_account/my_account.mako')
554 def my_account_perms(self):
555 def my_account_perms(self):
555 c = self.load_default_context()
556 c = self.load_default_context()
556 c.active = 'perms'
557 c.active = 'perms'
557
558
558 c.perm_user = c.auth_user
559 c.perm_user = c.auth_user
559 return self._get_template_context(c)
560 return self._get_template_context(c)
560
561
561 @LoginRequired()
562 @LoginRequired()
562 @NotAnonymous()
563 @NotAnonymous()
563 @view_config(
564 @view_config(
564 route_name='my_account_notifications', request_method='GET',
565 route_name='my_account_notifications', request_method='GET',
565 renderer='rhodecode:templates/admin/my_account/my_account.mako')
566 renderer='rhodecode:templates/admin/my_account/my_account.mako')
566 def my_notifications(self):
567 def my_notifications(self):
567 c = self.load_default_context()
568 c = self.load_default_context()
568 c.active = 'notifications'
569 c.active = 'notifications'
569
570
570 return self._get_template_context(c)
571 return self._get_template_context(c)
571
572
572 @LoginRequired()
573 @LoginRequired()
573 @NotAnonymous()
574 @NotAnonymous()
574 @CSRFRequired()
575 @CSRFRequired()
575 @view_config(
576 @view_config(
576 route_name='my_account_notifications_toggle_visibility',
577 route_name='my_account_notifications_toggle_visibility',
577 request_method='POST', renderer='json_ext')
578 request_method='POST', renderer='json_ext')
578 def my_notifications_toggle_visibility(self):
579 def my_notifications_toggle_visibility(self):
579 user = self._rhodecode_db_user
580 user = self._rhodecode_db_user
580 new_status = not user.user_data.get('notification_status', True)
581 new_status = not user.user_data.get('notification_status', True)
581 user.update_userdata(notification_status=new_status)
582 user.update_userdata(notification_status=new_status)
582 Session().commit()
583 Session().commit()
583 return user.user_data['notification_status']
584 return user.user_data['notification_status']
584
585
585 @LoginRequired()
586 @LoginRequired()
586 @NotAnonymous()
587 @NotAnonymous()
587 @view_config(
588 @view_config(
588 route_name='my_account_edit',
589 route_name='my_account_edit',
589 request_method='GET',
590 request_method='GET',
590 renderer='rhodecode:templates/admin/my_account/my_account.mako')
591 renderer='rhodecode:templates/admin/my_account/my_account.mako')
591 def my_account_edit(self):
592 def my_account_edit(self):
592 c = self.load_default_context()
593 c = self.load_default_context()
593 c.active = 'profile_edit'
594 c.active = 'profile_edit'
594 c.extern_type = c.user.extern_type
595 c.extern_type = c.user.extern_type
595 c.extern_name = c.user.extern_name
596 c.extern_name = c.user.extern_name
596
597
597 schema = user_schema.UserProfileSchema().bind(
598 schema = user_schema.UserProfileSchema().bind(
598 username=c.user.username, user_emails=c.user.emails)
599 username=c.user.username, user_emails=c.user.emails)
599 appstruct = {
600 appstruct = {
600 'username': c.user.username,
601 'username': c.user.username,
601 'email': c.user.email,
602 'email': c.user.email,
602 'firstname': c.user.firstname,
603 'firstname': c.user.firstname,
603 'lastname': c.user.lastname,
604 'lastname': c.user.lastname,
604 'description': c.user.description,
605 'description': c.user.description,
605 }
606 }
606 c.form = forms.RcForm(
607 c.form = forms.RcForm(
607 schema, appstruct=appstruct,
608 schema, appstruct=appstruct,
608 action=h.route_path('my_account_update'),
609 action=h.route_path('my_account_update'),
609 buttons=(forms.buttons.save, forms.buttons.reset))
610 buttons=(forms.buttons.save, forms.buttons.reset))
610
611
611 return self._get_template_context(c)
612 return self._get_template_context(c)
612
613
613 @LoginRequired()
614 @LoginRequired()
614 @NotAnonymous()
615 @NotAnonymous()
615 @CSRFRequired()
616 @CSRFRequired()
616 @view_config(
617 @view_config(
617 route_name='my_account_update',
618 route_name='my_account_update',
618 request_method='POST',
619 request_method='POST',
619 renderer='rhodecode:templates/admin/my_account/my_account.mako')
620 renderer='rhodecode:templates/admin/my_account/my_account.mako')
620 def my_account_update(self):
621 def my_account_update(self):
621 _ = self.request.translate
622 _ = self.request.translate
622 c = self.load_default_context()
623 c = self.load_default_context()
623 c.active = 'profile_edit'
624 c.active = 'profile_edit'
624 c.perm_user = c.auth_user
625 c.perm_user = c.auth_user
625 c.extern_type = c.user.extern_type
626 c.extern_type = c.user.extern_type
626 c.extern_name = c.user.extern_name
627 c.extern_name = c.user.extern_name
627
628
628 schema = user_schema.UserProfileSchema().bind(
629 schema = user_schema.UserProfileSchema().bind(
629 username=c.user.username, user_emails=c.user.emails)
630 username=c.user.username, user_emails=c.user.emails)
630 form = forms.RcForm(
631 form = forms.RcForm(
631 schema, buttons=(forms.buttons.save, forms.buttons.reset))
632 schema, buttons=(forms.buttons.save, forms.buttons.reset))
632
633
633 controls = self.request.POST.items()
634 controls = self.request.POST.items()
634 try:
635 try:
635 valid_data = form.validate(controls)
636 valid_data = form.validate(controls)
636 skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
637 skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
637 'new_password', 'password_confirmation']
638 'new_password', 'password_confirmation']
638 if c.extern_type != "rhodecode":
639 if c.extern_type != "rhodecode":
639 # forbid updating username for external accounts
640 # forbid updating username for external accounts
640 skip_attrs.append('username')
641 skip_attrs.append('username')
641 old_email = c.user.email
642 old_email = c.user.email
642 UserModel().update_user(
643 UserModel().update_user(
643 self._rhodecode_user.user_id, skip_attrs=skip_attrs,
644 self._rhodecode_user.user_id, skip_attrs=skip_attrs,
644 **valid_data)
645 **valid_data)
645 if old_email != valid_data['email']:
646 if old_email != valid_data['email']:
646 old = UserEmailMap.query() \
647 old = UserEmailMap.query() \
647 .filter(UserEmailMap.user == c.user).filter(UserEmailMap.email == valid_data['email']).first()
648 .filter(UserEmailMap.user == c.user).filter(UserEmailMap.email == valid_data['email']).first()
648 old.email = old_email
649 old.email = old_email
649 h.flash(_('Your account was updated successfully'), category='success')
650 h.flash(_('Your account was updated successfully'), category='success')
650 Session().commit()
651 Session().commit()
651 except forms.ValidationFailure as e:
652 except forms.ValidationFailure as e:
652 c.form = e
653 c.form = e
653 return self._get_template_context(c)
654 return self._get_template_context(c)
654 except Exception:
655 except Exception:
655 log.exception("Exception updating user")
656 log.exception("Exception updating user")
656 h.flash(_('Error occurred during update of user'),
657 h.flash(_('Error occurred during update of user'),
657 category='error')
658 category='error')
658 raise HTTPFound(h.route_path('my_account_profile'))
659 raise HTTPFound(h.route_path('my_account_profile'))
659
660
660 def _get_pull_requests_list(self, statuses):
661 def _get_pull_requests_list(self, statuses):
661 draw, start, limit = self._extract_chunk(self.request)
662 draw, start, limit = self._extract_chunk(self.request)
662 search_q, order_by, order_dir = self._extract_ordering(self.request)
663 search_q, order_by, order_dir = self._extract_ordering(self.request)
663 _render = self.request.get_partial_renderer(
664 _render = self.request.get_partial_renderer(
664 'rhodecode:templates/data_table/_dt_elements.mako')
665 'rhodecode:templates/data_table/_dt_elements.mako')
665
666
666 pull_requests = PullRequestModel().get_im_participating_in(
667 pull_requests = PullRequestModel().get_im_participating_in(
667 user_id=self._rhodecode_user.user_id,
668 user_id=self._rhodecode_user.user_id,
668 statuses=statuses,
669 statuses=statuses,
669 offset=start, length=limit, order_by=order_by,
670 offset=start, length=limit, order_by=order_by,
670 order_dir=order_dir)
671 order_dir=order_dir)
671
672
672 pull_requests_total_count = PullRequestModel().count_im_participating_in(
673 pull_requests_total_count = PullRequestModel().count_im_participating_in(
673 user_id=self._rhodecode_user.user_id, statuses=statuses)
674 user_id=self._rhodecode_user.user_id, statuses=statuses)
674
675
675 data = []
676 data = []
676 comments_model = CommentsModel()
677 comments_model = CommentsModel()
677 for pr in pull_requests:
678 for pr in pull_requests:
678 repo_id = pr.target_repo_id
679 repo_id = pr.target_repo_id
679 comments = comments_model.get_all_comments(
680 comments = comments_model.get_all_comments(
680 repo_id, pull_request=pr)
681 repo_id, pull_request=pr)
681 owned = pr.user_id == self._rhodecode_user.user_id
682 owned = pr.user_id == self._rhodecode_user.user_id
682
683
683 data.append({
684 data.append({
684 'target_repo': _render('pullrequest_target_repo',
685 'target_repo': _render('pullrequest_target_repo',
685 pr.target_repo.repo_name),
686 pr.target_repo.repo_name),
686 'name': _render('pullrequest_name',
687 'name': _render('pullrequest_name',
687 pr.pull_request_id, pr.pull_request_state,
688 pr.pull_request_id, pr.pull_request_state,
688 pr.work_in_progress, pr.target_repo.repo_name,
689 pr.work_in_progress, pr.target_repo.repo_name,
689 short=True),
690 short=True),
690 'name_raw': pr.pull_request_id,
691 'name_raw': pr.pull_request_id,
691 'status': _render('pullrequest_status',
692 'status': _render('pullrequest_status',
692 pr.calculated_review_status()),
693 pr.calculated_review_status()),
693 'title': _render('pullrequest_title', pr.title, pr.description),
694 'title': _render('pullrequest_title', pr.title, pr.description),
694 'description': h.escape(pr.description),
695 'description': h.escape(pr.description),
695 'updated_on': _render('pullrequest_updated_on',
696 'updated_on': _render('pullrequest_updated_on',
696 h.datetime_to_time(pr.updated_on)),
697 h.datetime_to_time(pr.updated_on)),
697 'updated_on_raw': h.datetime_to_time(pr.updated_on),
698 'updated_on_raw': h.datetime_to_time(pr.updated_on),
698 'created_on': _render('pullrequest_updated_on',
699 'created_on': _render('pullrequest_updated_on',
699 h.datetime_to_time(pr.created_on)),
700 h.datetime_to_time(pr.created_on)),
700 'created_on_raw': h.datetime_to_time(pr.created_on),
701 'created_on_raw': h.datetime_to_time(pr.created_on),
701 'state': pr.pull_request_state,
702 'state': pr.pull_request_state,
702 'author': _render('pullrequest_author',
703 'author': _render('pullrequest_author',
703 pr.author.full_contact, ),
704 pr.author.full_contact, ),
704 'author_raw': pr.author.full_name,
705 'author_raw': pr.author.full_name,
705 'comments': _render('pullrequest_comments', len(comments)),
706 'comments': _render('pullrequest_comments', len(comments)),
706 'comments_raw': len(comments),
707 'comments_raw': len(comments),
707 'closed': pr.is_closed(),
708 'closed': pr.is_closed(),
708 'owned': owned
709 'owned': owned
709 })
710 })
710
711
711 # json used to render the grid
712 # json used to render the grid
712 data = ({
713 data = ({
713 'draw': draw,
714 'draw': draw,
714 'data': data,
715 'data': data,
715 'recordsTotal': pull_requests_total_count,
716 'recordsTotal': pull_requests_total_count,
716 'recordsFiltered': pull_requests_total_count,
717 'recordsFiltered': pull_requests_total_count,
717 })
718 })
718 return data
719 return data
719
720
720 @LoginRequired()
721 @LoginRequired()
721 @NotAnonymous()
722 @NotAnonymous()
722 @view_config(
723 @view_config(
723 route_name='my_account_pullrequests',
724 route_name='my_account_pullrequests',
724 request_method='GET',
725 request_method='GET',
725 renderer='rhodecode:templates/admin/my_account/my_account.mako')
726 renderer='rhodecode:templates/admin/my_account/my_account.mako')
726 def my_account_pullrequests(self):
727 def my_account_pullrequests(self):
727 c = self.load_default_context()
728 c = self.load_default_context()
728 c.active = 'pullrequests'
729 c.active = 'pullrequests'
729 req_get = self.request.GET
730 req_get = self.request.GET
730
731
731 c.closed = str2bool(req_get.get('pr_show_closed'))
732 c.closed = str2bool(req_get.get('pr_show_closed'))
732
733
733 return self._get_template_context(c)
734 return self._get_template_context(c)
734
735
735 @LoginRequired()
736 @LoginRequired()
736 @NotAnonymous()
737 @NotAnonymous()
737 @view_config(
738 @view_config(
738 route_name='my_account_pullrequests_data',
739 route_name='my_account_pullrequests_data',
739 request_method='GET', renderer='json_ext')
740 request_method='GET', renderer='json_ext')
740 def my_account_pullrequests_data(self):
741 def my_account_pullrequests_data(self):
741 self.load_default_context()
742 self.load_default_context()
742 req_get = self.request.GET
743 req_get = self.request.GET
743 closed = str2bool(req_get.get('closed'))
744 closed = str2bool(req_get.get('closed'))
744
745
745 statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN]
746 statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN]
746 if closed:
747 if closed:
747 statuses += [PullRequest.STATUS_CLOSED]
748 statuses += [PullRequest.STATUS_CLOSED]
748
749
749 data = self._get_pull_requests_list(statuses=statuses)
750 data = self._get_pull_requests_list(statuses=statuses)
750 return data
751 return data
751
752
752 @LoginRequired()
753 @LoginRequired()
753 @NotAnonymous()
754 @NotAnonymous()
754 @view_config(
755 @view_config(
755 route_name='my_account_user_group_membership',
756 route_name='my_account_user_group_membership',
756 request_method='GET',
757 request_method='GET',
757 renderer='rhodecode:templates/admin/my_account/my_account.mako')
758 renderer='rhodecode:templates/admin/my_account/my_account.mako')
758 def my_account_user_group_membership(self):
759 def my_account_user_group_membership(self):
759 c = self.load_default_context()
760 c = self.load_default_context()
760 c.active = 'user_group_membership'
761 c.active = 'user_group_membership'
761 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
762 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
762 for group in self._rhodecode_db_user.group_member]
763 for group in self._rhodecode_db_user.group_member]
763 c.user_groups = json.dumps(groups)
764 c.user_groups = json.dumps(groups)
764 return self._get_template_context(c)
765 return self._get_template_context(c)
General Comments 0
You need to be logged in to leave comments. Login now