##// END OF EJS Templates
bookmarks: Add extra checks for bogus data in bookmarks repo/repo group ids passed.
marcink -
r3751:c36477cc new-ui
parent child Browse files
Show More
@@ -1,743 +1,743 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
361
362 repos_data = RepoModel().get_repos_as_dict(
362 repos_data = RepoModel().get_repos_as_dict(
363 repo_list=repo_list, admin=admin, short_name=False)
363 repo_list=repo_list, admin=admin, short_name=False)
364 # json used to render the grid
364 # json used to render the grid
365 return json.dumps(repos_data)
365 return json.dumps(repos_data)
366
366
367 @LoginRequired()
367 @LoginRequired()
368 @NotAnonymous()
368 @NotAnonymous()
369 @view_config(
369 @view_config(
370 route_name='my_account_repos', request_method='GET',
370 route_name='my_account_repos', request_method='GET',
371 renderer='rhodecode:templates/admin/my_account/my_account.mako')
371 renderer='rhodecode:templates/admin/my_account/my_account.mako')
372 def my_account_repos(self):
372 def my_account_repos(self):
373 c = self.load_default_context()
373 c = self.load_default_context()
374 c.active = 'repos'
374 c.active = 'repos'
375
375
376 # json used to render the grid
376 # json used to render the grid
377 c.data = self._load_my_repos_data()
377 c.data = self._load_my_repos_data()
378 return self._get_template_context(c)
378 return self._get_template_context(c)
379
379
380 @LoginRequired()
380 @LoginRequired()
381 @NotAnonymous()
381 @NotAnonymous()
382 @view_config(
382 @view_config(
383 route_name='my_account_watched', request_method='GET',
383 route_name='my_account_watched', request_method='GET',
384 renderer='rhodecode:templates/admin/my_account/my_account.mako')
384 renderer='rhodecode:templates/admin/my_account/my_account.mako')
385 def my_account_watched(self):
385 def my_account_watched(self):
386 c = self.load_default_context()
386 c = self.load_default_context()
387 c.active = 'watched'
387 c.active = 'watched'
388
388
389 # json used to render the grid
389 # json used to render the grid
390 c.data = self._load_my_repos_data(watched=True)
390 c.data = self._load_my_repos_data(watched=True)
391 return self._get_template_context(c)
391 return self._get_template_context(c)
392
392
393 @LoginRequired()
393 @LoginRequired()
394 @NotAnonymous()
394 @NotAnonymous()
395 @view_config(
395 @view_config(
396 route_name='my_account_bookmarks', request_method='GET',
396 route_name='my_account_bookmarks', request_method='GET',
397 renderer='rhodecode:templates/admin/my_account/my_account.mako')
397 renderer='rhodecode:templates/admin/my_account/my_account.mako')
398 def my_account_bookmarks(self):
398 def my_account_bookmarks(self):
399 c = self.load_default_context()
399 c = self.load_default_context()
400 c.active = 'bookmarks'
400 c.active = 'bookmarks'
401 return self._get_template_context(c)
401 return self._get_template_context(c)
402
402
403 def _process_entry(self, entry, user_id):
403 def _process_entry(self, entry, user_id):
404 position = safe_int(entry.get('position'))
404 position = safe_int(entry.get('position'))
405 if position is None:
405 if position is None:
406 return
406 return
407
407
408 # check if this is an existing entry
408 # check if this is an existing entry
409 is_new = False
409 is_new = False
410 db_entry = UserBookmark().get_by_position_for_user(position, user_id)
410 db_entry = UserBookmark().get_by_position_for_user(position, user_id)
411
411
412 if db_entry and str2bool(entry.get('remove')):
412 if db_entry and str2bool(entry.get('remove')):
413 log.debug('Marked bookmark %s for deletion', db_entry)
413 log.debug('Marked bookmark %s for deletion', db_entry)
414 Session().delete(db_entry)
414 Session().delete(db_entry)
415 return
415 return
416
416
417 if not db_entry:
417 if not db_entry:
418 # new
418 # new
419 db_entry = UserBookmark()
419 db_entry = UserBookmark()
420 is_new = True
420 is_new = True
421
421
422 should_save = False
422 should_save = False
423 default_redirect_url = ''
423 default_redirect_url = ''
424
424
425 # save repo
425 # save repo
426 if entry.get('bookmark_repo'):
426 if entry.get('bookmark_repo') and safe_int(entry.get('bookmark_repo')):
427 repo = Repository.get(entry['bookmark_repo'])
427 repo = Repository.get(entry['bookmark_repo'])
428 perm_check = HasRepoPermissionAny(
428 perm_check = HasRepoPermissionAny(
429 'repository.read', 'repository.write', 'repository.admin')
429 'repository.read', 'repository.write', 'repository.admin')
430 if repo and perm_check(repo_name=repo.repo_name):
430 if repo and perm_check(repo_name=repo.repo_name):
431 db_entry.repository = repo
431 db_entry.repository = repo
432 should_save = True
432 should_save = True
433 default_redirect_url = '${repo_url}'
433 default_redirect_url = '${repo_url}'
434 # save repo group
434 # save repo group
435 elif entry.get('bookmark_repo_group'):
435 elif entry.get('bookmark_repo_group') and safe_int(entry.get('bookmark_repo_group')):
436 repo_group = RepoGroup.get(entry['bookmark_repo_group'])
436 repo_group = RepoGroup.get(entry['bookmark_repo_group'])
437 perm_check = HasRepoGroupPermissionAny(
437 perm_check = HasRepoGroupPermissionAny(
438 'group.read', 'group.write', 'group.admin')
438 'group.read', 'group.write', 'group.admin')
439
439
440 if repo_group and perm_check(group_name=repo_group.group_name):
440 if repo_group and perm_check(group_name=repo_group.group_name):
441 db_entry.repository_group = repo_group
441 db_entry.repository_group = repo_group
442 should_save = True
442 should_save = True
443 default_redirect_url = '${repo_group_url}'
443 default_redirect_url = '${repo_group_url}'
444 # save generic info
444 # save generic info
445 elif entry.get('title') and entry.get('redirect_url'):
445 elif entry.get('title') and entry.get('redirect_url'):
446 should_save = True
446 should_save = True
447
447
448 if should_save:
448 if should_save:
449 log.debug('Saving bookmark %s, new:%s', db_entry, is_new)
449 log.debug('Saving bookmark %s, new:%s', db_entry, is_new)
450 # mark user and position
450 # mark user and position
451 db_entry.user_id = user_id
451 db_entry.user_id = user_id
452 db_entry.position = position
452 db_entry.position = position
453 db_entry.title = entry.get('title')
453 db_entry.title = entry.get('title')
454 db_entry.redirect_url = entry.get('redirect_url') or default_redirect_url
454 db_entry.redirect_url = entry.get('redirect_url') or default_redirect_url
455
455
456 Session().add(db_entry)
456 Session().add(db_entry)
457
457
458 @LoginRequired()
458 @LoginRequired()
459 @NotAnonymous()
459 @NotAnonymous()
460 @CSRFRequired()
460 @CSRFRequired()
461 @view_config(
461 @view_config(
462 route_name='my_account_bookmarks_update', request_method='POST')
462 route_name='my_account_bookmarks_update', request_method='POST')
463 def my_account_bookmarks_update(self):
463 def my_account_bookmarks_update(self):
464 _ = self.request.translate
464 _ = self.request.translate
465 c = self.load_default_context()
465 c = self.load_default_context()
466 c.active = 'bookmarks'
466 c.active = 'bookmarks'
467
467
468 controls = peppercorn.parse(self.request.POST.items())
468 controls = peppercorn.parse(self.request.POST.items())
469 user_id = c.user.user_id
469 user_id = c.user.user_id
470
470
471 try:
471 try:
472 for entry in controls.get('bookmarks', []):
472 for entry in controls.get('bookmarks', []):
473 self._process_entry(entry, user_id)
473 self._process_entry(entry, user_id)
474
474
475 Session().commit()
475 Session().commit()
476 h.flash(_("Update Bookmarks"), category='success')
476 h.flash(_("Update Bookmarks"), category='success')
477 except IntegrityError:
477 except IntegrityError:
478 h.flash(_("Failed to update bookmarks. "
478 h.flash(_("Failed to update bookmarks. "
479 "Make sure an unique position is used"), category='error')
479 "Make sure an unique position is used"), category='error')
480
480
481 return HTTPFound(h.route_path('my_account_bookmarks'))
481 return HTTPFound(h.route_path('my_account_bookmarks'))
482
482
483 @LoginRequired()
483 @LoginRequired()
484 @NotAnonymous()
484 @NotAnonymous()
485 @view_config(
485 @view_config(
486 route_name='my_account_goto_bookmark', request_method='GET',
486 route_name='my_account_goto_bookmark', request_method='GET',
487 renderer='rhodecode:templates/admin/my_account/my_account.mako')
487 renderer='rhodecode:templates/admin/my_account/my_account.mako')
488 def my_account_goto_bookmark(self):
488 def my_account_goto_bookmark(self):
489
489
490 bookmark_id = self.request.matchdict['bookmark_id']
490 bookmark_id = self.request.matchdict['bookmark_id']
491 user_bookmark = UserBookmark().query()\
491 user_bookmark = UserBookmark().query()\
492 .filter(UserBookmark.user_id == self.request.user.user_id) \
492 .filter(UserBookmark.user_id == self.request.user.user_id) \
493 .filter(UserBookmark.position == bookmark_id).scalar()
493 .filter(UserBookmark.position == bookmark_id).scalar()
494
494
495 redirect_url = h.route_path('my_account_bookmarks')
495 redirect_url = h.route_path('my_account_bookmarks')
496 if not user_bookmark:
496 if not user_bookmark:
497 raise HTTPFound(redirect_url)
497 raise HTTPFound(redirect_url)
498
498
499 # repository set
499 # repository set
500 if user_bookmark.repository:
500 if user_bookmark.repository:
501 repo_name = user_bookmark.repository.repo_name
501 repo_name = user_bookmark.repository.repo_name
502 base_redirect_url = h.route_path(
502 base_redirect_url = h.route_path(
503 'repo_summary', repo_name=repo_name)
503 'repo_summary', repo_name=repo_name)
504 if user_bookmark.redirect_url and \
504 if user_bookmark.redirect_url and \
505 '${repo_url}' in user_bookmark.redirect_url:
505 '${repo_url}' in user_bookmark.redirect_url:
506 redirect_url = string.Template(user_bookmark.redirect_url)\
506 redirect_url = string.Template(user_bookmark.redirect_url)\
507 .safe_substitute({'repo_url': base_redirect_url})
507 .safe_substitute({'repo_url': base_redirect_url})
508 else:
508 else:
509 redirect_url = base_redirect_url
509 redirect_url = base_redirect_url
510 # repository group set
510 # repository group set
511 elif user_bookmark.repository_group:
511 elif user_bookmark.repository_group:
512 repo_group_name = user_bookmark.repository_group.group_name
512 repo_group_name = user_bookmark.repository_group.group_name
513 base_redirect_url = h.route_path(
513 base_redirect_url = h.route_path(
514 'repo_group_home', repo_group_name=repo_group_name)
514 'repo_group_home', repo_group_name=repo_group_name)
515 if user_bookmark.redirect_url and \
515 if user_bookmark.redirect_url and \
516 '${repo_group_url}' in user_bookmark.redirect_url:
516 '${repo_group_url}' in user_bookmark.redirect_url:
517 redirect_url = string.Template(user_bookmark.redirect_url)\
517 redirect_url = string.Template(user_bookmark.redirect_url)\
518 .safe_substitute({'repo_group_url': base_redirect_url})
518 .safe_substitute({'repo_group_url': base_redirect_url})
519 else:
519 else:
520 redirect_url = base_redirect_url
520 redirect_url = base_redirect_url
521 # custom URL set
521 # custom URL set
522 elif user_bookmark.redirect_url:
522 elif user_bookmark.redirect_url:
523 server_url = h.route_url('home').rstrip('/')
523 server_url = h.route_url('home').rstrip('/')
524 redirect_url = string.Template(user_bookmark.redirect_url) \
524 redirect_url = string.Template(user_bookmark.redirect_url) \
525 .safe_substitute({'server_url': server_url})
525 .safe_substitute({'server_url': server_url})
526
526
527 log.debug('Redirecting bookmark %s to %s', user_bookmark, redirect_url)
527 log.debug('Redirecting bookmark %s to %s', user_bookmark, redirect_url)
528 raise HTTPFound(redirect_url)
528 raise HTTPFound(redirect_url)
529
529
530 @LoginRequired()
530 @LoginRequired()
531 @NotAnonymous()
531 @NotAnonymous()
532 @view_config(
532 @view_config(
533 route_name='my_account_perms', request_method='GET',
533 route_name='my_account_perms', request_method='GET',
534 renderer='rhodecode:templates/admin/my_account/my_account.mako')
534 renderer='rhodecode:templates/admin/my_account/my_account.mako')
535 def my_account_perms(self):
535 def my_account_perms(self):
536 c = self.load_default_context()
536 c = self.load_default_context()
537 c.active = 'perms'
537 c.active = 'perms'
538
538
539 c.perm_user = c.auth_user
539 c.perm_user = c.auth_user
540 return self._get_template_context(c)
540 return self._get_template_context(c)
541
541
542 @LoginRequired()
542 @LoginRequired()
543 @NotAnonymous()
543 @NotAnonymous()
544 @view_config(
544 @view_config(
545 route_name='my_account_notifications', request_method='GET',
545 route_name='my_account_notifications', request_method='GET',
546 renderer='rhodecode:templates/admin/my_account/my_account.mako')
546 renderer='rhodecode:templates/admin/my_account/my_account.mako')
547 def my_notifications(self):
547 def my_notifications(self):
548 c = self.load_default_context()
548 c = self.load_default_context()
549 c.active = 'notifications'
549 c.active = 'notifications'
550
550
551 return self._get_template_context(c)
551 return self._get_template_context(c)
552
552
553 @LoginRequired()
553 @LoginRequired()
554 @NotAnonymous()
554 @NotAnonymous()
555 @CSRFRequired()
555 @CSRFRequired()
556 @view_config(
556 @view_config(
557 route_name='my_account_notifications_toggle_visibility',
557 route_name='my_account_notifications_toggle_visibility',
558 request_method='POST', renderer='json_ext')
558 request_method='POST', renderer='json_ext')
559 def my_notifications_toggle_visibility(self):
559 def my_notifications_toggle_visibility(self):
560 user = self._rhodecode_db_user
560 user = self._rhodecode_db_user
561 new_status = not user.user_data.get('notification_status', True)
561 new_status = not user.user_data.get('notification_status', True)
562 user.update_userdata(notification_status=new_status)
562 user.update_userdata(notification_status=new_status)
563 Session().commit()
563 Session().commit()
564 return user.user_data['notification_status']
564 return user.user_data['notification_status']
565
565
566 @LoginRequired()
566 @LoginRequired()
567 @NotAnonymous()
567 @NotAnonymous()
568 @view_config(
568 @view_config(
569 route_name='my_account_edit',
569 route_name='my_account_edit',
570 request_method='GET',
570 request_method='GET',
571 renderer='rhodecode:templates/admin/my_account/my_account.mako')
571 renderer='rhodecode:templates/admin/my_account/my_account.mako')
572 def my_account_edit(self):
572 def my_account_edit(self):
573 c = self.load_default_context()
573 c = self.load_default_context()
574 c.active = 'profile_edit'
574 c.active = 'profile_edit'
575 c.extern_type = c.user.extern_type
575 c.extern_type = c.user.extern_type
576 c.extern_name = c.user.extern_name
576 c.extern_name = c.user.extern_name
577
577
578 schema = user_schema.UserProfileSchema().bind(
578 schema = user_schema.UserProfileSchema().bind(
579 username=c.user.username, user_emails=c.user.emails)
579 username=c.user.username, user_emails=c.user.emails)
580 appstruct = {
580 appstruct = {
581 'username': c.user.username,
581 'username': c.user.username,
582 'email': c.user.email,
582 'email': c.user.email,
583 'firstname': c.user.firstname,
583 'firstname': c.user.firstname,
584 'lastname': c.user.lastname,
584 'lastname': c.user.lastname,
585 }
585 }
586 c.form = forms.RcForm(
586 c.form = forms.RcForm(
587 schema, appstruct=appstruct,
587 schema, appstruct=appstruct,
588 action=h.route_path('my_account_update'),
588 action=h.route_path('my_account_update'),
589 buttons=(forms.buttons.save, forms.buttons.reset))
589 buttons=(forms.buttons.save, forms.buttons.reset))
590
590
591 return self._get_template_context(c)
591 return self._get_template_context(c)
592
592
593 @LoginRequired()
593 @LoginRequired()
594 @NotAnonymous()
594 @NotAnonymous()
595 @CSRFRequired()
595 @CSRFRequired()
596 @view_config(
596 @view_config(
597 route_name='my_account_update',
597 route_name='my_account_update',
598 request_method='POST',
598 request_method='POST',
599 renderer='rhodecode:templates/admin/my_account/my_account.mako')
599 renderer='rhodecode:templates/admin/my_account/my_account.mako')
600 def my_account_update(self):
600 def my_account_update(self):
601 _ = self.request.translate
601 _ = self.request.translate
602 c = self.load_default_context()
602 c = self.load_default_context()
603 c.active = 'profile_edit'
603 c.active = 'profile_edit'
604 c.perm_user = c.auth_user
604 c.perm_user = c.auth_user
605 c.extern_type = c.user.extern_type
605 c.extern_type = c.user.extern_type
606 c.extern_name = c.user.extern_name
606 c.extern_name = c.user.extern_name
607
607
608 schema = user_schema.UserProfileSchema().bind(
608 schema = user_schema.UserProfileSchema().bind(
609 username=c.user.username, user_emails=c.user.emails)
609 username=c.user.username, user_emails=c.user.emails)
610 form = forms.RcForm(
610 form = forms.RcForm(
611 schema, buttons=(forms.buttons.save, forms.buttons.reset))
611 schema, buttons=(forms.buttons.save, forms.buttons.reset))
612
612
613 controls = self.request.POST.items()
613 controls = self.request.POST.items()
614 try:
614 try:
615 valid_data = form.validate(controls)
615 valid_data = form.validate(controls)
616 skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
616 skip_attrs = ['admin', 'active', 'extern_type', 'extern_name',
617 'new_password', 'password_confirmation']
617 'new_password', 'password_confirmation']
618 if c.extern_type != "rhodecode":
618 if c.extern_type != "rhodecode":
619 # forbid updating username for external accounts
619 # forbid updating username for external accounts
620 skip_attrs.append('username')
620 skip_attrs.append('username')
621 old_email = c.user.email
621 old_email = c.user.email
622 UserModel().update_user(
622 UserModel().update_user(
623 self._rhodecode_user.user_id, skip_attrs=skip_attrs,
623 self._rhodecode_user.user_id, skip_attrs=skip_attrs,
624 **valid_data)
624 **valid_data)
625 if old_email != valid_data['email']:
625 if old_email != valid_data['email']:
626 old = UserEmailMap.query() \
626 old = UserEmailMap.query() \
627 .filter(UserEmailMap.user == c.user).filter(UserEmailMap.email == valid_data['email']).first()
627 .filter(UserEmailMap.user == c.user).filter(UserEmailMap.email == valid_data['email']).first()
628 old.email = old_email
628 old.email = old_email
629 h.flash(_('Your account was updated successfully'), category='success')
629 h.flash(_('Your account was updated successfully'), category='success')
630 Session().commit()
630 Session().commit()
631 except forms.ValidationFailure as e:
631 except forms.ValidationFailure as e:
632 c.form = e
632 c.form = e
633 return self._get_template_context(c)
633 return self._get_template_context(c)
634 except Exception:
634 except Exception:
635 log.exception("Exception updating user")
635 log.exception("Exception updating user")
636 h.flash(_('Error occurred during update of user'),
636 h.flash(_('Error occurred during update of user'),
637 category='error')
637 category='error')
638 raise HTTPFound(h.route_path('my_account_profile'))
638 raise HTTPFound(h.route_path('my_account_profile'))
639
639
640 def _get_pull_requests_list(self, statuses):
640 def _get_pull_requests_list(self, statuses):
641 draw, start, limit = self._extract_chunk(self.request)
641 draw, start, limit = self._extract_chunk(self.request)
642 search_q, order_by, order_dir = self._extract_ordering(self.request)
642 search_q, order_by, order_dir = self._extract_ordering(self.request)
643 _render = self.request.get_partial_renderer(
643 _render = self.request.get_partial_renderer(
644 'rhodecode:templates/data_table/_dt_elements.mako')
644 'rhodecode:templates/data_table/_dt_elements.mako')
645
645
646 pull_requests = PullRequestModel().get_im_participating_in(
646 pull_requests = PullRequestModel().get_im_participating_in(
647 user_id=self._rhodecode_user.user_id,
647 user_id=self._rhodecode_user.user_id,
648 statuses=statuses,
648 statuses=statuses,
649 offset=start, length=limit, order_by=order_by,
649 offset=start, length=limit, order_by=order_by,
650 order_dir=order_dir)
650 order_dir=order_dir)
651
651
652 pull_requests_total_count = PullRequestModel().count_im_participating_in(
652 pull_requests_total_count = PullRequestModel().count_im_participating_in(
653 user_id=self._rhodecode_user.user_id, statuses=statuses)
653 user_id=self._rhodecode_user.user_id, statuses=statuses)
654
654
655 data = []
655 data = []
656 comments_model = CommentsModel()
656 comments_model = CommentsModel()
657 for pr in pull_requests:
657 for pr in pull_requests:
658 repo_id = pr.target_repo_id
658 repo_id = pr.target_repo_id
659 comments = comments_model.get_all_comments(
659 comments = comments_model.get_all_comments(
660 repo_id, pull_request=pr)
660 repo_id, pull_request=pr)
661 owned = pr.user_id == self._rhodecode_user.user_id
661 owned = pr.user_id == self._rhodecode_user.user_id
662
662
663 data.append({
663 data.append({
664 'target_repo': _render('pullrequest_target_repo',
664 'target_repo': _render('pullrequest_target_repo',
665 pr.target_repo.repo_name),
665 pr.target_repo.repo_name),
666 'name': _render('pullrequest_name',
666 'name': _render('pullrequest_name',
667 pr.pull_request_id, pr.target_repo.repo_name,
667 pr.pull_request_id, pr.target_repo.repo_name,
668 short=True),
668 short=True),
669 'name_raw': pr.pull_request_id,
669 'name_raw': pr.pull_request_id,
670 'status': _render('pullrequest_status',
670 'status': _render('pullrequest_status',
671 pr.calculated_review_status()),
671 pr.calculated_review_status()),
672 'title': _render(
672 'title': _render(
673 'pullrequest_title', pr.title, pr.description),
673 'pullrequest_title', pr.title, pr.description),
674 'description': h.escape(pr.description),
674 'description': h.escape(pr.description),
675 'updated_on': _render('pullrequest_updated_on',
675 'updated_on': _render('pullrequest_updated_on',
676 h.datetime_to_time(pr.updated_on)),
676 h.datetime_to_time(pr.updated_on)),
677 'updated_on_raw': h.datetime_to_time(pr.updated_on),
677 'updated_on_raw': h.datetime_to_time(pr.updated_on),
678 'created_on': _render('pullrequest_updated_on',
678 'created_on': _render('pullrequest_updated_on',
679 h.datetime_to_time(pr.created_on)),
679 h.datetime_to_time(pr.created_on)),
680 'created_on_raw': h.datetime_to_time(pr.created_on),
680 'created_on_raw': h.datetime_to_time(pr.created_on),
681 'author': _render('pullrequest_author',
681 'author': _render('pullrequest_author',
682 pr.author.full_contact, ),
682 pr.author.full_contact, ),
683 'author_raw': pr.author.full_name,
683 'author_raw': pr.author.full_name,
684 'comments': _render('pullrequest_comments', len(comments)),
684 'comments': _render('pullrequest_comments', len(comments)),
685 'comments_raw': len(comments),
685 'comments_raw': len(comments),
686 'closed': pr.is_closed(),
686 'closed': pr.is_closed(),
687 'owned': owned
687 'owned': owned
688 })
688 })
689
689
690 # json used to render the grid
690 # json used to render the grid
691 data = ({
691 data = ({
692 'draw': draw,
692 'draw': draw,
693 'data': data,
693 'data': data,
694 'recordsTotal': pull_requests_total_count,
694 'recordsTotal': pull_requests_total_count,
695 'recordsFiltered': pull_requests_total_count,
695 'recordsFiltered': pull_requests_total_count,
696 })
696 })
697 return data
697 return data
698
698
699 @LoginRequired()
699 @LoginRequired()
700 @NotAnonymous()
700 @NotAnonymous()
701 @view_config(
701 @view_config(
702 route_name='my_account_pullrequests',
702 route_name='my_account_pullrequests',
703 request_method='GET',
703 request_method='GET',
704 renderer='rhodecode:templates/admin/my_account/my_account.mako')
704 renderer='rhodecode:templates/admin/my_account/my_account.mako')
705 def my_account_pullrequests(self):
705 def my_account_pullrequests(self):
706 c = self.load_default_context()
706 c = self.load_default_context()
707 c.active = 'pullrequests'
707 c.active = 'pullrequests'
708 req_get = self.request.GET
708 req_get = self.request.GET
709
709
710 c.closed = str2bool(req_get.get('pr_show_closed'))
710 c.closed = str2bool(req_get.get('pr_show_closed'))
711
711
712 return self._get_template_context(c)
712 return self._get_template_context(c)
713
713
714 @LoginRequired()
714 @LoginRequired()
715 @NotAnonymous()
715 @NotAnonymous()
716 @view_config(
716 @view_config(
717 route_name='my_account_pullrequests_data',
717 route_name='my_account_pullrequests_data',
718 request_method='GET', renderer='json_ext')
718 request_method='GET', renderer='json_ext')
719 def my_account_pullrequests_data(self):
719 def my_account_pullrequests_data(self):
720 self.load_default_context()
720 self.load_default_context()
721 req_get = self.request.GET
721 req_get = self.request.GET
722 closed = str2bool(req_get.get('closed'))
722 closed = str2bool(req_get.get('closed'))
723
723
724 statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN]
724 statuses = [PullRequest.STATUS_NEW, PullRequest.STATUS_OPEN]
725 if closed:
725 if closed:
726 statuses += [PullRequest.STATUS_CLOSED]
726 statuses += [PullRequest.STATUS_CLOSED]
727
727
728 data = self._get_pull_requests_list(statuses=statuses)
728 data = self._get_pull_requests_list(statuses=statuses)
729 return data
729 return data
730
730
731 @LoginRequired()
731 @LoginRequired()
732 @NotAnonymous()
732 @NotAnonymous()
733 @view_config(
733 @view_config(
734 route_name='my_account_user_group_membership',
734 route_name='my_account_user_group_membership',
735 request_method='GET',
735 request_method='GET',
736 renderer='rhodecode:templates/admin/my_account/my_account.mako')
736 renderer='rhodecode:templates/admin/my_account/my_account.mako')
737 def my_account_user_group_membership(self):
737 def my_account_user_group_membership(self):
738 c = self.load_default_context()
738 c = self.load_default_context()
739 c.active = 'user_group_membership'
739 c.active = 'user_group_membership'
740 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
740 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
741 for group in self._rhodecode_db_user.group_member]
741 for group in self._rhodecode_db_user.group_member]
742 c.user_groups = json.dumps(groups)
742 c.user_groups = json.dumps(groups)
743 return self._get_template_context(c)
743 return self._get_template_context(c)
General Comments 0
You need to be logged in to leave comments. Login now