##// END OF EJS Templates
users: changed spelling of users_groups to user_groups. Because English :]
marcink -
r2067:e89cfa8f default
parent child Browse files
Show More
@@ -1,672 +1,673 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2016-2017 RhodeCode GmbH
3 # Copyright (C) 2016-2017 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 formencode
23 import formencode
24
24
25 from pyramid.httpexceptions import HTTPFound
25 from pyramid.httpexceptions import HTTPFound
26 from pyramid.view import view_config
26 from pyramid.view import view_config
27 from sqlalchemy.sql.functions import coalesce
27 from sqlalchemy.sql.functions import coalesce
28 from sqlalchemy.exc import IntegrityError
28 from sqlalchemy.exc import IntegrityError
29
29
30 from rhodecode.apps._base import BaseAppView, DataGridAppView
30 from rhodecode.apps._base import BaseAppView, DataGridAppView
31 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
31 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
32 from rhodecode.events import trigger
32 from rhodecode.events import trigger
33
33
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 (
36 from rhodecode.lib.auth import (
37 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
37 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39 from rhodecode.lib.utils2 import safe_int, safe_unicode
39 from rhodecode.lib.utils2 import safe_int, safe_unicode
40 from rhodecode.model.auth_token import AuthTokenModel
40 from rhodecode.model.auth_token import AuthTokenModel
41 from rhodecode.model.ssh_key import SshKeyModel
41 from rhodecode.model.ssh_key import SshKeyModel
42 from rhodecode.model.user import UserModel
42 from rhodecode.model.user import UserModel
43 from rhodecode.model.user_group import UserGroupModel
43 from rhodecode.model.user_group import UserGroupModel
44 from rhodecode.model.db import (
44 from rhodecode.model.db import (
45 or_, User, UserIpMap, UserEmailMap, UserApiKeys, UserSshKeys)
45 or_, User, UserIpMap, UserEmailMap, UserApiKeys, UserSshKeys)
46 from rhodecode.model.meta import Session
46 from rhodecode.model.meta import Session
47
47
48 log = logging.getLogger(__name__)
48 log = logging.getLogger(__name__)
49
49
50
50
51 class AdminUsersView(BaseAppView, DataGridAppView):
51 class AdminUsersView(BaseAppView, DataGridAppView):
52 ALLOW_SCOPED_TOKENS = False
52 ALLOW_SCOPED_TOKENS = False
53 """
53 """
54 This view has alternative version inside EE, if modified please take a look
54 This view has alternative version inside EE, if modified please take a look
55 in there as well.
55 in there as well.
56 """
56 """
57
57
58 def load_default_context(self):
58 def load_default_context(self):
59 c = self._get_local_tmpl_context()
59 c = self._get_local_tmpl_context()
60 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
60 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
61 self._register_global_c(c)
61 self._register_global_c(c)
62 return c
62 return c
63
63
64 def _redirect_for_default_user(self, username):
64 def _redirect_for_default_user(self, username):
65 _ = self.request.translate
65 _ = self.request.translate
66 if username == User.DEFAULT_USER:
66 if username == User.DEFAULT_USER:
67 h.flash(_("You can't edit this user"), category='warning')
67 h.flash(_("You can't edit this user"), category='warning')
68 # TODO(marcink): redirect to 'users' admin panel once this
68 # TODO(marcink): redirect to 'users' admin panel once this
69 # is a pyramid view
69 # is a pyramid view
70 raise HTTPFound('/')
70 raise HTTPFound('/')
71
71
72 @LoginRequired()
72 @LoginRequired()
73 @HasPermissionAllDecorator('hg.admin')
73 @HasPermissionAllDecorator('hg.admin')
74 @view_config(
74 @view_config(
75 route_name='users', request_method='GET',
75 route_name='users', request_method='GET',
76 renderer='rhodecode:templates/admin/users/users.mako')
76 renderer='rhodecode:templates/admin/users/users.mako')
77 def users_list(self):
77 def users_list(self):
78 c = self.load_default_context()
78 c = self.load_default_context()
79 return self._get_template_context(c)
79 return self._get_template_context(c)
80
80
81 @LoginRequired()
81 @LoginRequired()
82 @HasPermissionAllDecorator('hg.admin')
82 @HasPermissionAllDecorator('hg.admin')
83 @view_config(
83 @view_config(
84 # renderer defined below
84 # renderer defined below
85 route_name='users_data', request_method='GET',
85 route_name='users_data', request_method='GET',
86 renderer='json_ext', xhr=True)
86 renderer='json_ext', xhr=True)
87 def users_list_data(self):
87 def users_list_data(self):
88 column_map = {
88 column_map = {
89 'first_name': 'name',
89 'first_name': 'name',
90 'last_name': 'lastname',
90 'last_name': 'lastname',
91 }
91 }
92 draw, start, limit = self._extract_chunk(self.request)
92 draw, start, limit = self._extract_chunk(self.request)
93 search_q, order_by, order_dir = self._extract_ordering(
93 search_q, order_by, order_dir = self._extract_ordering(
94 self.request, column_map=column_map)
94 self.request, column_map=column_map)
95
95
96 _render = self.request.get_partial_renderer(
96 _render = self.request.get_partial_renderer(
97 'data_table/_dt_elements.mako')
97 'data_table/_dt_elements.mako')
98
98
99 def user_actions(user_id, username):
99 def user_actions(user_id, username):
100 return _render("user_actions", user_id, username)
100 return _render("user_actions", user_id, username)
101
101
102 users_data_total_count = User.query()\
102 users_data_total_count = User.query()\
103 .filter(User.username != User.DEFAULT_USER) \
103 .filter(User.username != User.DEFAULT_USER) \
104 .count()
104 .count()
105
105
106 # json generate
106 # json generate
107 base_q = User.query().filter(User.username != User.DEFAULT_USER)
107 base_q = User.query().filter(User.username != User.DEFAULT_USER)
108
108
109 if search_q:
109 if search_q:
110 like_expression = u'%{}%'.format(safe_unicode(search_q))
110 like_expression = u'%{}%'.format(safe_unicode(search_q))
111 base_q = base_q.filter(or_(
111 base_q = base_q.filter(or_(
112 User.username.ilike(like_expression),
112 User.username.ilike(like_expression),
113 User._email.ilike(like_expression),
113 User._email.ilike(like_expression),
114 User.name.ilike(like_expression),
114 User.name.ilike(like_expression),
115 User.lastname.ilike(like_expression),
115 User.lastname.ilike(like_expression),
116 ))
116 ))
117
117
118 users_data_total_filtered_count = base_q.count()
118 users_data_total_filtered_count = base_q.count()
119
119
120 sort_col = getattr(User, order_by, None)
120 sort_col = getattr(User, order_by, None)
121 if sort_col:
121 if sort_col:
122 if order_dir == 'asc':
122 if order_dir == 'asc':
123 # handle null values properly to order by NULL last
123 # handle null values properly to order by NULL last
124 if order_by in ['last_activity']:
124 if order_by in ['last_activity']:
125 sort_col = coalesce(sort_col, datetime.date.max)
125 sort_col = coalesce(sort_col, datetime.date.max)
126 sort_col = sort_col.asc()
126 sort_col = sort_col.asc()
127 else:
127 else:
128 # handle null values properly to order by NULL last
128 # handle null values properly to order by NULL last
129 if order_by in ['last_activity']:
129 if order_by in ['last_activity']:
130 sort_col = coalesce(sort_col, datetime.date.min)
130 sort_col = coalesce(sort_col, datetime.date.min)
131 sort_col = sort_col.desc()
131 sort_col = sort_col.desc()
132
132
133 base_q = base_q.order_by(sort_col)
133 base_q = base_q.order_by(sort_col)
134 base_q = base_q.offset(start).limit(limit)
134 base_q = base_q.offset(start).limit(limit)
135
135
136 users_list = base_q.all()
136 users_list = base_q.all()
137
137
138 users_data = []
138 users_data = []
139 for user in users_list:
139 for user in users_list:
140 users_data.append({
140 users_data.append({
141 "username": h.gravatar_with_user(self.request, user.username),
141 "username": h.gravatar_with_user(self.request, user.username),
142 "email": user.email,
142 "email": user.email,
143 "first_name": user.first_name,
143 "first_name": user.first_name,
144 "last_name": user.last_name,
144 "last_name": user.last_name,
145 "last_login": h.format_date(user.last_login),
145 "last_login": h.format_date(user.last_login),
146 "last_activity": h.format_date(user.last_activity),
146 "last_activity": h.format_date(user.last_activity),
147 "active": h.bool2icon(user.active),
147 "active": h.bool2icon(user.active),
148 "active_raw": user.active,
148 "active_raw": user.active,
149 "admin": h.bool2icon(user.admin),
149 "admin": h.bool2icon(user.admin),
150 "extern_type": user.extern_type,
150 "extern_type": user.extern_type,
151 "extern_name": user.extern_name,
151 "extern_name": user.extern_name,
152 "action": user_actions(user.user_id, user.username),
152 "action": user_actions(user.user_id, user.username),
153 })
153 })
154
154
155 data = ({
155 data = ({
156 'draw': draw,
156 'draw': draw,
157 'data': users_data,
157 'data': users_data,
158 'recordsTotal': users_data_total_count,
158 'recordsTotal': users_data_total_count,
159 'recordsFiltered': users_data_total_filtered_count,
159 'recordsFiltered': users_data_total_filtered_count,
160 })
160 })
161
161
162 return data
162 return data
163
163
164 @LoginRequired()
164 @LoginRequired()
165 @HasPermissionAllDecorator('hg.admin')
165 @HasPermissionAllDecorator('hg.admin')
166 @view_config(
166 @view_config(
167 route_name='edit_user_auth_tokens', request_method='GET',
167 route_name='edit_user_auth_tokens', request_method='GET',
168 renderer='rhodecode:templates/admin/users/user_edit.mako')
168 renderer='rhodecode:templates/admin/users/user_edit.mako')
169 def auth_tokens(self):
169 def auth_tokens(self):
170 _ = self.request.translate
170 _ = self.request.translate
171 c = self.load_default_context()
171 c = self.load_default_context()
172
172
173 user_id = self.request.matchdict.get('user_id')
173 user_id = self.request.matchdict.get('user_id')
174 c.user = User.get_or_404(user_id)
174 c.user = User.get_or_404(user_id)
175 self._redirect_for_default_user(c.user.username)
175 self._redirect_for_default_user(c.user.username)
176
176
177 c.active = 'auth_tokens'
177 c.active = 'auth_tokens'
178
178
179 c.lifetime_values = [
179 c.lifetime_values = [
180 (str(-1), _('forever')),
180 (str(-1), _('forever')),
181 (str(5), _('5 minutes')),
181 (str(5), _('5 minutes')),
182 (str(60), _('1 hour')),
182 (str(60), _('1 hour')),
183 (str(60 * 24), _('1 day')),
183 (str(60 * 24), _('1 day')),
184 (str(60 * 24 * 30), _('1 month')),
184 (str(60 * 24 * 30), _('1 month')),
185 ]
185 ]
186 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
186 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
187 c.role_values = [
187 c.role_values = [
188 (x, AuthTokenModel.cls._get_role_name(x))
188 (x, AuthTokenModel.cls._get_role_name(x))
189 for x in AuthTokenModel.cls.ROLES]
189 for x in AuthTokenModel.cls.ROLES]
190 c.role_options = [(c.role_values, _("Role"))]
190 c.role_options = [(c.role_values, _("Role"))]
191 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
191 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
192 c.user.user_id, show_expired=True)
192 c.user.user_id, show_expired=True)
193 return self._get_template_context(c)
193 return self._get_template_context(c)
194
194
195 def maybe_attach_token_scope(self, token):
195 def maybe_attach_token_scope(self, token):
196 # implemented in EE edition
196 # implemented in EE edition
197 pass
197 pass
198
198
199 @LoginRequired()
199 @LoginRequired()
200 @HasPermissionAllDecorator('hg.admin')
200 @HasPermissionAllDecorator('hg.admin')
201 @CSRFRequired()
201 @CSRFRequired()
202 @view_config(
202 @view_config(
203 route_name='edit_user_auth_tokens_add', request_method='POST')
203 route_name='edit_user_auth_tokens_add', request_method='POST')
204 def auth_tokens_add(self):
204 def auth_tokens_add(self):
205 _ = self.request.translate
205 _ = self.request.translate
206 c = self.load_default_context()
206 c = self.load_default_context()
207
207
208 user_id = self.request.matchdict.get('user_id')
208 user_id = self.request.matchdict.get('user_id')
209 c.user = User.get_or_404(user_id)
209 c.user = User.get_or_404(user_id)
210
210
211 self._redirect_for_default_user(c.user.username)
211 self._redirect_for_default_user(c.user.username)
212
212
213 user_data = c.user.get_api_data()
213 user_data = c.user.get_api_data()
214 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
214 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
215 description = self.request.POST.get('description')
215 description = self.request.POST.get('description')
216 role = self.request.POST.get('role')
216 role = self.request.POST.get('role')
217
217
218 token = AuthTokenModel().create(
218 token = AuthTokenModel().create(
219 c.user.user_id, description, lifetime, role)
219 c.user.user_id, description, lifetime, role)
220 token_data = token.get_api_data()
220 token_data = token.get_api_data()
221
221
222 self.maybe_attach_token_scope(token)
222 self.maybe_attach_token_scope(token)
223 audit_logger.store_web(
223 audit_logger.store_web(
224 'user.edit.token.add', action_data={
224 'user.edit.token.add', action_data={
225 'data': {'token': token_data, 'user': user_data}},
225 'data': {'token': token_data, 'user': user_data}},
226 user=self._rhodecode_user, )
226 user=self._rhodecode_user, )
227 Session().commit()
227 Session().commit()
228
228
229 h.flash(_("Auth token successfully created"), category='success')
229 h.flash(_("Auth token successfully created"), category='success')
230 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
230 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
231
231
232 @LoginRequired()
232 @LoginRequired()
233 @HasPermissionAllDecorator('hg.admin')
233 @HasPermissionAllDecorator('hg.admin')
234 @CSRFRequired()
234 @CSRFRequired()
235 @view_config(
235 @view_config(
236 route_name='edit_user_auth_tokens_delete', request_method='POST')
236 route_name='edit_user_auth_tokens_delete', request_method='POST')
237 def auth_tokens_delete(self):
237 def auth_tokens_delete(self):
238 _ = self.request.translate
238 _ = self.request.translate
239 c = self.load_default_context()
239 c = self.load_default_context()
240
240
241 user_id = self.request.matchdict.get('user_id')
241 user_id = self.request.matchdict.get('user_id')
242 c.user = User.get_or_404(user_id)
242 c.user = User.get_or_404(user_id)
243 self._redirect_for_default_user(c.user.username)
243 self._redirect_for_default_user(c.user.username)
244 user_data = c.user.get_api_data()
244 user_data = c.user.get_api_data()
245
245
246 del_auth_token = self.request.POST.get('del_auth_token')
246 del_auth_token = self.request.POST.get('del_auth_token')
247
247
248 if del_auth_token:
248 if del_auth_token:
249 token = UserApiKeys.get_or_404(del_auth_token)
249 token = UserApiKeys.get_or_404(del_auth_token)
250 token_data = token.get_api_data()
250 token_data = token.get_api_data()
251
251
252 AuthTokenModel().delete(del_auth_token, c.user.user_id)
252 AuthTokenModel().delete(del_auth_token, c.user.user_id)
253 audit_logger.store_web(
253 audit_logger.store_web(
254 'user.edit.token.delete', action_data={
254 'user.edit.token.delete', action_data={
255 'data': {'token': token_data, 'user': user_data}},
255 'data': {'token': token_data, 'user': user_data}},
256 user=self._rhodecode_user,)
256 user=self._rhodecode_user,)
257 Session().commit()
257 Session().commit()
258 h.flash(_("Auth token successfully deleted"), category='success')
258 h.flash(_("Auth token successfully deleted"), category='success')
259
259
260 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
260 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
261
261
262 @LoginRequired()
262 @LoginRequired()
263 @HasPermissionAllDecorator('hg.admin')
263 @HasPermissionAllDecorator('hg.admin')
264 @view_config(
264 @view_config(
265 route_name='edit_user_ssh_keys', request_method='GET',
265 route_name='edit_user_ssh_keys', request_method='GET',
266 renderer='rhodecode:templates/admin/users/user_edit.mako')
266 renderer='rhodecode:templates/admin/users/user_edit.mako')
267 def ssh_keys(self):
267 def ssh_keys(self):
268 _ = self.request.translate
268 _ = self.request.translate
269 c = self.load_default_context()
269 c = self.load_default_context()
270
270
271 user_id = self.request.matchdict.get('user_id')
271 user_id = self.request.matchdict.get('user_id')
272 c.user = User.get_or_404(user_id)
272 c.user = User.get_or_404(user_id)
273 self._redirect_for_default_user(c.user.username)
273 self._redirect_for_default_user(c.user.username)
274
274
275 c.active = 'ssh_keys'
275 c.active = 'ssh_keys'
276 c.default_key = self.request.GET.get('default_key')
276 c.default_key = self.request.GET.get('default_key')
277 c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
277 c.user_ssh_keys = SshKeyModel().get_ssh_keys(c.user.user_id)
278 return self._get_template_context(c)
278 return self._get_template_context(c)
279
279
280 @LoginRequired()
280 @LoginRequired()
281 @HasPermissionAllDecorator('hg.admin')
281 @HasPermissionAllDecorator('hg.admin')
282 @view_config(
282 @view_config(
283 route_name='edit_user_ssh_keys_generate_keypair', request_method='GET',
283 route_name='edit_user_ssh_keys_generate_keypair', request_method='GET',
284 renderer='rhodecode:templates/admin/users/user_edit.mako')
284 renderer='rhodecode:templates/admin/users/user_edit.mako')
285 def ssh_keys_generate_keypair(self):
285 def ssh_keys_generate_keypair(self):
286 _ = self.request.translate
286 _ = self.request.translate
287 c = self.load_default_context()
287 c = self.load_default_context()
288
288
289 user_id = self.request.matchdict.get('user_id')
289 user_id = self.request.matchdict.get('user_id')
290 c.user = User.get_or_404(user_id)
290 c.user = User.get_or_404(user_id)
291 self._redirect_for_default_user(c.user.username)
291 self._redirect_for_default_user(c.user.username)
292
292
293 c.active = 'ssh_keys_generate'
293 c.active = 'ssh_keys_generate'
294 comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
294 comment = 'RhodeCode-SSH {}'.format(c.user.email or '')
295 c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
295 c.private, c.public = SshKeyModel().generate_keypair(comment=comment)
296
296
297 return self._get_template_context(c)
297 return self._get_template_context(c)
298
298
299 @LoginRequired()
299 @LoginRequired()
300 @HasPermissionAllDecorator('hg.admin')
300 @HasPermissionAllDecorator('hg.admin')
301 @CSRFRequired()
301 @CSRFRequired()
302 @view_config(
302 @view_config(
303 route_name='edit_user_ssh_keys_add', request_method='POST')
303 route_name='edit_user_ssh_keys_add', request_method='POST')
304 def ssh_keys_add(self):
304 def ssh_keys_add(self):
305 _ = self.request.translate
305 _ = self.request.translate
306 c = self.load_default_context()
306 c = self.load_default_context()
307
307
308 user_id = self.request.matchdict.get('user_id')
308 user_id = self.request.matchdict.get('user_id')
309 c.user = User.get_or_404(user_id)
309 c.user = User.get_or_404(user_id)
310
310
311 self._redirect_for_default_user(c.user.username)
311 self._redirect_for_default_user(c.user.username)
312
312
313 user_data = c.user.get_api_data()
313 user_data = c.user.get_api_data()
314 key_data = self.request.POST.get('key_data')
314 key_data = self.request.POST.get('key_data')
315 description = self.request.POST.get('description')
315 description = self.request.POST.get('description')
316
316
317 try:
317 try:
318 if not key_data:
318 if not key_data:
319 raise ValueError('Please add a valid public key')
319 raise ValueError('Please add a valid public key')
320
320
321 key = SshKeyModel().parse_key(key_data.strip())
321 key = SshKeyModel().parse_key(key_data.strip())
322 fingerprint = key.hash_md5()
322 fingerprint = key.hash_md5()
323
323
324 ssh_key = SshKeyModel().create(
324 ssh_key = SshKeyModel().create(
325 c.user.user_id, fingerprint, key_data, description)
325 c.user.user_id, fingerprint, key_data, description)
326 ssh_key_data = ssh_key.get_api_data()
326 ssh_key_data = ssh_key.get_api_data()
327
327
328 audit_logger.store_web(
328 audit_logger.store_web(
329 'user.edit.ssh_key.add', action_data={
329 'user.edit.ssh_key.add', action_data={
330 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
330 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
331 user=self._rhodecode_user, )
331 user=self._rhodecode_user, )
332 Session().commit()
332 Session().commit()
333
333
334 # Trigger an event on change of keys.
334 # Trigger an event on change of keys.
335 trigger(SshKeyFileChangeEvent(), self.request.registry)
335 trigger(SshKeyFileChangeEvent(), self.request.registry)
336
336
337 h.flash(_("Ssh Key successfully created"), category='success')
337 h.flash(_("Ssh Key successfully created"), category='success')
338
338
339 except IntegrityError:
339 except IntegrityError:
340 log.exception("Exception during ssh key saving")
340 log.exception("Exception during ssh key saving")
341 h.flash(_('An error occurred during ssh key saving: {}').format(
341 h.flash(_('An error occurred during ssh key saving: {}').format(
342 'Such key already exists, please use a different one'),
342 'Such key already exists, please use a different one'),
343 category='error')
343 category='error')
344 except Exception as e:
344 except Exception as e:
345 log.exception("Exception during ssh key saving")
345 log.exception("Exception during ssh key saving")
346 h.flash(_('An error occurred during ssh key saving: {}').format(e),
346 h.flash(_('An error occurred during ssh key saving: {}').format(e),
347 category='error')
347 category='error')
348
348
349 return HTTPFound(
349 return HTTPFound(
350 h.route_path('edit_user_ssh_keys', user_id=user_id))
350 h.route_path('edit_user_ssh_keys', user_id=user_id))
351
351
352 @LoginRequired()
352 @LoginRequired()
353 @HasPermissionAllDecorator('hg.admin')
353 @HasPermissionAllDecorator('hg.admin')
354 @CSRFRequired()
354 @CSRFRequired()
355 @view_config(
355 @view_config(
356 route_name='edit_user_ssh_keys_delete', request_method='POST')
356 route_name='edit_user_ssh_keys_delete', request_method='POST')
357 def ssh_keys_delete(self):
357 def ssh_keys_delete(self):
358 _ = self.request.translate
358 _ = self.request.translate
359 c = self.load_default_context()
359 c = self.load_default_context()
360
360
361 user_id = self.request.matchdict.get('user_id')
361 user_id = self.request.matchdict.get('user_id')
362 c.user = User.get_or_404(user_id)
362 c.user = User.get_or_404(user_id)
363 self._redirect_for_default_user(c.user.username)
363 self._redirect_for_default_user(c.user.username)
364 user_data = c.user.get_api_data()
364 user_data = c.user.get_api_data()
365
365
366 del_ssh_key = self.request.POST.get('del_ssh_key')
366 del_ssh_key = self.request.POST.get('del_ssh_key')
367
367
368 if del_ssh_key:
368 if del_ssh_key:
369 ssh_key = UserSshKeys.get_or_404(del_ssh_key)
369 ssh_key = UserSshKeys.get_or_404(del_ssh_key)
370 ssh_key_data = ssh_key.get_api_data()
370 ssh_key_data = ssh_key.get_api_data()
371
371
372 SshKeyModel().delete(del_ssh_key, c.user.user_id)
372 SshKeyModel().delete(del_ssh_key, c.user.user_id)
373 audit_logger.store_web(
373 audit_logger.store_web(
374 'user.edit.ssh_key.delete', action_data={
374 'user.edit.ssh_key.delete', action_data={
375 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
375 'data': {'ssh_key': ssh_key_data, 'user': user_data}},
376 user=self._rhodecode_user,)
376 user=self._rhodecode_user,)
377 Session().commit()
377 Session().commit()
378 # Trigger an event on change of keys.
378 # Trigger an event on change of keys.
379 trigger(SshKeyFileChangeEvent(), self.request.registry)
379 trigger(SshKeyFileChangeEvent(), self.request.registry)
380 h.flash(_("Ssh key successfully deleted"), category='success')
380 h.flash(_("Ssh key successfully deleted"), category='success')
381
381
382 return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id))
382 return HTTPFound(h.route_path('edit_user_ssh_keys', user_id=user_id))
383
383
384 @LoginRequired()
384 @LoginRequired()
385 @HasPermissionAllDecorator('hg.admin')
385 @HasPermissionAllDecorator('hg.admin')
386 @view_config(
386 @view_config(
387 route_name='edit_user_emails', request_method='GET',
387 route_name='edit_user_emails', request_method='GET',
388 renderer='rhodecode:templates/admin/users/user_edit.mako')
388 renderer='rhodecode:templates/admin/users/user_edit.mako')
389 def emails(self):
389 def emails(self):
390 _ = self.request.translate
390 _ = self.request.translate
391 c = self.load_default_context()
391 c = self.load_default_context()
392
392
393 user_id = self.request.matchdict.get('user_id')
393 user_id = self.request.matchdict.get('user_id')
394 c.user = User.get_or_404(user_id)
394 c.user = User.get_or_404(user_id)
395 self._redirect_for_default_user(c.user.username)
395 self._redirect_for_default_user(c.user.username)
396
396
397 c.active = 'emails'
397 c.active = 'emails'
398 c.user_email_map = UserEmailMap.query() \
398 c.user_email_map = UserEmailMap.query() \
399 .filter(UserEmailMap.user == c.user).all()
399 .filter(UserEmailMap.user == c.user).all()
400
400
401 return self._get_template_context(c)
401 return self._get_template_context(c)
402
402
403 @LoginRequired()
403 @LoginRequired()
404 @HasPermissionAllDecorator('hg.admin')
404 @HasPermissionAllDecorator('hg.admin')
405 @CSRFRequired()
405 @CSRFRequired()
406 @view_config(
406 @view_config(
407 route_name='edit_user_emails_add', request_method='POST')
407 route_name='edit_user_emails_add', request_method='POST')
408 def emails_add(self):
408 def emails_add(self):
409 _ = self.request.translate
409 _ = self.request.translate
410 c = self.load_default_context()
410 c = self.load_default_context()
411
411
412 user_id = self.request.matchdict.get('user_id')
412 user_id = self.request.matchdict.get('user_id')
413 c.user = User.get_or_404(user_id)
413 c.user = User.get_or_404(user_id)
414 self._redirect_for_default_user(c.user.username)
414 self._redirect_for_default_user(c.user.username)
415
415
416 email = self.request.POST.get('new_email')
416 email = self.request.POST.get('new_email')
417 user_data = c.user.get_api_data()
417 user_data = c.user.get_api_data()
418 try:
418 try:
419 UserModel().add_extra_email(c.user.user_id, email)
419 UserModel().add_extra_email(c.user.user_id, email)
420 audit_logger.store_web(
420 audit_logger.store_web(
421 'user.edit.email.add', action_data={'email': email, 'user': user_data},
421 'user.edit.email.add', action_data={'email': email, 'user': user_data},
422 user=self._rhodecode_user)
422 user=self._rhodecode_user)
423 Session().commit()
423 Session().commit()
424 h.flash(_("Added new email address `%s` for user account") % email,
424 h.flash(_("Added new email address `%s` for user account") % email,
425 category='success')
425 category='success')
426 except formencode.Invalid as error:
426 except formencode.Invalid as error:
427 h.flash(h.escape(error.error_dict['email']), category='error')
427 h.flash(h.escape(error.error_dict['email']), category='error')
428 except Exception:
428 except Exception:
429 log.exception("Exception during email saving")
429 log.exception("Exception during email saving")
430 h.flash(_('An error occurred during email saving'),
430 h.flash(_('An error occurred during email saving'),
431 category='error')
431 category='error')
432 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
432 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
433
433
434 @LoginRequired()
434 @LoginRequired()
435 @HasPermissionAllDecorator('hg.admin')
435 @HasPermissionAllDecorator('hg.admin')
436 @CSRFRequired()
436 @CSRFRequired()
437 @view_config(
437 @view_config(
438 route_name='edit_user_emails_delete', request_method='POST')
438 route_name='edit_user_emails_delete', request_method='POST')
439 def emails_delete(self):
439 def emails_delete(self):
440 _ = self.request.translate
440 _ = self.request.translate
441 c = self.load_default_context()
441 c = self.load_default_context()
442
442
443 user_id = self.request.matchdict.get('user_id')
443 user_id = self.request.matchdict.get('user_id')
444 c.user = User.get_or_404(user_id)
444 c.user = User.get_or_404(user_id)
445 self._redirect_for_default_user(c.user.username)
445 self._redirect_for_default_user(c.user.username)
446
446
447 email_id = self.request.POST.get('del_email_id')
447 email_id = self.request.POST.get('del_email_id')
448 user_model = UserModel()
448 user_model = UserModel()
449
449
450 email = UserEmailMap.query().get(email_id).email
450 email = UserEmailMap.query().get(email_id).email
451 user_data = c.user.get_api_data()
451 user_data = c.user.get_api_data()
452 user_model.delete_extra_email(c.user.user_id, email_id)
452 user_model.delete_extra_email(c.user.user_id, email_id)
453 audit_logger.store_web(
453 audit_logger.store_web(
454 'user.edit.email.delete', action_data={'email': email, 'user': user_data},
454 'user.edit.email.delete', action_data={'email': email, 'user': user_data},
455 user=self._rhodecode_user)
455 user=self._rhodecode_user)
456 Session().commit()
456 Session().commit()
457 h.flash(_("Removed email address from user account"),
457 h.flash(_("Removed email address from user account"),
458 category='success')
458 category='success')
459 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
459 raise HTTPFound(h.route_path('edit_user_emails', user_id=user_id))
460
460
461 @LoginRequired()
461 @LoginRequired()
462 @HasPermissionAllDecorator('hg.admin')
462 @HasPermissionAllDecorator('hg.admin')
463 @view_config(
463 @view_config(
464 route_name='edit_user_ips', request_method='GET',
464 route_name='edit_user_ips', request_method='GET',
465 renderer='rhodecode:templates/admin/users/user_edit.mako')
465 renderer='rhodecode:templates/admin/users/user_edit.mako')
466 def ips(self):
466 def ips(self):
467 _ = self.request.translate
467 _ = self.request.translate
468 c = self.load_default_context()
468 c = self.load_default_context()
469
469
470 user_id = self.request.matchdict.get('user_id')
470 user_id = self.request.matchdict.get('user_id')
471 c.user = User.get_or_404(user_id)
471 c.user = User.get_or_404(user_id)
472 self._redirect_for_default_user(c.user.username)
472 self._redirect_for_default_user(c.user.username)
473
473
474 c.active = 'ips'
474 c.active = 'ips'
475 c.user_ip_map = UserIpMap.query() \
475 c.user_ip_map = UserIpMap.query() \
476 .filter(UserIpMap.user == c.user).all()
476 .filter(UserIpMap.user == c.user).all()
477
477
478 c.inherit_default_ips = c.user.inherit_default_permissions
478 c.inherit_default_ips = c.user.inherit_default_permissions
479 c.default_user_ip_map = UserIpMap.query() \
479 c.default_user_ip_map = UserIpMap.query() \
480 .filter(UserIpMap.user == User.get_default_user()).all()
480 .filter(UserIpMap.user == User.get_default_user()).all()
481
481
482 return self._get_template_context(c)
482 return self._get_template_context(c)
483
483
484 @LoginRequired()
484 @LoginRequired()
485 @HasPermissionAllDecorator('hg.admin')
485 @HasPermissionAllDecorator('hg.admin')
486 @CSRFRequired()
486 @CSRFRequired()
487 @view_config(
487 @view_config(
488 route_name='edit_user_ips_add', request_method='POST')
488 route_name='edit_user_ips_add', request_method='POST')
489 def ips_add(self):
489 def ips_add(self):
490 _ = self.request.translate
490 _ = self.request.translate
491 c = self.load_default_context()
491 c = self.load_default_context()
492
492
493 user_id = self.request.matchdict.get('user_id')
493 user_id = self.request.matchdict.get('user_id')
494 c.user = User.get_or_404(user_id)
494 c.user = User.get_or_404(user_id)
495 # NOTE(marcink): this view is allowed for default users, as we can
495 # NOTE(marcink): this view is allowed for default users, as we can
496 # edit their IP white list
496 # edit their IP white list
497
497
498 user_model = UserModel()
498 user_model = UserModel()
499 desc = self.request.POST.get('description')
499 desc = self.request.POST.get('description')
500 try:
500 try:
501 ip_list = user_model.parse_ip_range(
501 ip_list = user_model.parse_ip_range(
502 self.request.POST.get('new_ip'))
502 self.request.POST.get('new_ip'))
503 except Exception as e:
503 except Exception as e:
504 ip_list = []
504 ip_list = []
505 log.exception("Exception during ip saving")
505 log.exception("Exception during ip saving")
506 h.flash(_('An error occurred during ip saving:%s' % (e,)),
506 h.flash(_('An error occurred during ip saving:%s' % (e,)),
507 category='error')
507 category='error')
508 added = []
508 added = []
509 user_data = c.user.get_api_data()
509 user_data = c.user.get_api_data()
510 for ip in ip_list:
510 for ip in ip_list:
511 try:
511 try:
512 user_model.add_extra_ip(c.user.user_id, ip, desc)
512 user_model.add_extra_ip(c.user.user_id, ip, desc)
513 audit_logger.store_web(
513 audit_logger.store_web(
514 'user.edit.ip.add', action_data={'ip': ip, 'user': user_data},
514 'user.edit.ip.add', action_data={'ip': ip, 'user': user_data},
515 user=self._rhodecode_user)
515 user=self._rhodecode_user)
516 Session().commit()
516 Session().commit()
517 added.append(ip)
517 added.append(ip)
518 except formencode.Invalid as error:
518 except formencode.Invalid as error:
519 msg = error.error_dict['ip']
519 msg = error.error_dict['ip']
520 h.flash(msg, category='error')
520 h.flash(msg, category='error')
521 except Exception:
521 except Exception:
522 log.exception("Exception during ip saving")
522 log.exception("Exception during ip saving")
523 h.flash(_('An error occurred during ip saving'),
523 h.flash(_('An error occurred during ip saving'),
524 category='error')
524 category='error')
525 if added:
525 if added:
526 h.flash(
526 h.flash(
527 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
527 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
528 category='success')
528 category='success')
529 if 'default_user' in self.request.POST:
529 if 'default_user' in self.request.POST:
530 # case for editing global IP list we do it for 'DEFAULT' user
530 # case for editing global IP list we do it for 'DEFAULT' user
531 raise HTTPFound(h.route_path('admin_permissions_ips'))
531 raise HTTPFound(h.route_path('admin_permissions_ips'))
532 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
532 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
533
533
534 @LoginRequired()
534 @LoginRequired()
535 @HasPermissionAllDecorator('hg.admin')
535 @HasPermissionAllDecorator('hg.admin')
536 @CSRFRequired()
536 @CSRFRequired()
537 @view_config(
537 @view_config(
538 route_name='edit_user_ips_delete', request_method='POST')
538 route_name='edit_user_ips_delete', request_method='POST')
539 def ips_delete(self):
539 def ips_delete(self):
540 _ = self.request.translate
540 _ = self.request.translate
541 c = self.load_default_context()
541 c = self.load_default_context()
542
542
543 user_id = self.request.matchdict.get('user_id')
543 user_id = self.request.matchdict.get('user_id')
544 c.user = User.get_or_404(user_id)
544 c.user = User.get_or_404(user_id)
545 # NOTE(marcink): this view is allowed for default users, as we can
545 # NOTE(marcink): this view is allowed for default users, as we can
546 # edit their IP white list
546 # edit their IP white list
547
547
548 ip_id = self.request.POST.get('del_ip_id')
548 ip_id = self.request.POST.get('del_ip_id')
549 user_model = UserModel()
549 user_model = UserModel()
550 user_data = c.user.get_api_data()
550 user_data = c.user.get_api_data()
551 ip = UserIpMap.query().get(ip_id).ip_addr
551 ip = UserIpMap.query().get(ip_id).ip_addr
552 user_model.delete_extra_ip(c.user.user_id, ip_id)
552 user_model.delete_extra_ip(c.user.user_id, ip_id)
553 audit_logger.store_web(
553 audit_logger.store_web(
554 'user.edit.ip.delete', action_data={'ip': ip, 'user': user_data},
554 'user.edit.ip.delete', action_data={'ip': ip, 'user': user_data},
555 user=self._rhodecode_user)
555 user=self._rhodecode_user)
556 Session().commit()
556 Session().commit()
557 h.flash(_("Removed ip address from user whitelist"), category='success')
557 h.flash(_("Removed ip address from user whitelist"), category='success')
558
558
559 if 'default_user' in self.request.POST:
559 if 'default_user' in self.request.POST:
560 # case for editing global IP list we do it for 'DEFAULT' user
560 # case for editing global IP list we do it for 'DEFAULT' user
561 raise HTTPFound(h.route_path('admin_permissions_ips'))
561 raise HTTPFound(h.route_path('admin_permissions_ips'))
562 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
562 raise HTTPFound(h.route_path('edit_user_ips', user_id=user_id))
563
563
564 @LoginRequired()
564 @LoginRequired()
565 @HasPermissionAllDecorator('hg.admin')
565 @HasPermissionAllDecorator('hg.admin')
566 @view_config(
566 @view_config(
567 route_name='edit_user_groups_management', request_method='GET',
567 route_name='edit_user_groups_management', request_method='GET',
568 renderer='rhodecode:templates/admin/users/user_edit.mako')
568 renderer='rhodecode:templates/admin/users/user_edit.mako')
569 def groups_management(self):
569 def groups_management(self):
570 c = self.load_default_context()
570 c = self.load_default_context()
571
571
572 user_id = self.request.matchdict.get('user_id')
572 user_id = self.request.matchdict.get('user_id')
573 c.user = User.get_or_404(user_id)
573 c.user = User.get_or_404(user_id)
574 c.data = c.user.group_member
574 c.data = c.user.group_member
575 self._redirect_for_default_user(c.user.username)
575 self._redirect_for_default_user(c.user.username)
576 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
576 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group)
577 for group in c.user.group_member]
577 for group in c.user.group_member]
578 c.groups = json.dumps(groups)
578 c.groups = json.dumps(groups)
579 c.active = 'groups'
579 c.active = 'groups'
580
580
581 return self._get_template_context(c)
581 return self._get_template_context(c)
582
582
583 @LoginRequired()
583 @LoginRequired()
584 @HasPermissionAllDecorator('hg.admin')
584 @HasPermissionAllDecorator('hg.admin')
585 @CSRFRequired()
585 @CSRFRequired()
586 @view_config(
586 @view_config(
587 route_name='edit_user_groups_management_updates', request_method='POST')
587 route_name='edit_user_groups_management_updates', request_method='POST')
588 def groups_management_updates(self):
588 def groups_management_updates(self):
589 _ = self.request.translate
589 _ = self.request.translate
590 c = self.load_default_context()
590 c = self.load_default_context()
591
591
592 user_id = self.request.matchdict.get('user_id')
592 user_id = self.request.matchdict.get('user_id')
593 c.user = User.get_or_404(user_id)
593 c.user = User.get_or_404(user_id)
594 self._redirect_for_default_user(c.user.username)
594 self._redirect_for_default_user(c.user.username)
595
595
596 users_groups = set(self.request.POST.getall('users_group_id'))
596 user_groups = set(self.request.POST.getall('users_group_id'))
597 users_groups_model = []
597 user_groups_objects = []
598
598
599 for ugid in users_groups:
599 for ugid in user_groups:
600 users_groups_model.append(UserGroupModel().get_group(safe_int(ugid)))
600 user_groups_objects.append(
601 UserGroupModel().get_group(safe_int(ugid)))
601 user_group_model = UserGroupModel()
602 user_group_model = UserGroupModel()
602 user_group_model.change_groups(c.user, users_groups_model)
603 user_group_model.change_groups(c.user, user_groups_objects)
603
604
604 Session().commit()
605 Session().commit()
605 c.active = 'user_groups_management'
606 c.active = 'user_groups_management'
606 h.flash(_("Groups successfully changed"), category='success')
607 h.flash(_("Groups successfully changed"), category='success')
607
608
608 return HTTPFound(h.route_path(
609 return HTTPFound(h.route_path(
609 'edit_user_groups_management', user_id=user_id))
610 'edit_user_groups_management', user_id=user_id))
610
611
611 @LoginRequired()
612 @LoginRequired()
612 @HasPermissionAllDecorator('hg.admin')
613 @HasPermissionAllDecorator('hg.admin')
613 @view_config(
614 @view_config(
614 route_name='edit_user_audit_logs', request_method='GET',
615 route_name='edit_user_audit_logs', request_method='GET',
615 renderer='rhodecode:templates/admin/users/user_edit.mako')
616 renderer='rhodecode:templates/admin/users/user_edit.mako')
616 def user_audit_logs(self):
617 def user_audit_logs(self):
617 _ = self.request.translate
618 _ = self.request.translate
618 c = self.load_default_context()
619 c = self.load_default_context()
619
620
620 user_id = self.request.matchdict.get('user_id')
621 user_id = self.request.matchdict.get('user_id')
621 c.user = User.get_or_404(user_id)
622 c.user = User.get_or_404(user_id)
622 self._redirect_for_default_user(c.user.username)
623 self._redirect_for_default_user(c.user.username)
623 c.active = 'audit'
624 c.active = 'audit'
624
625
625 p = safe_int(self.request.GET.get('page', 1), 1)
626 p = safe_int(self.request.GET.get('page', 1), 1)
626
627
627 filter_term = self.request.GET.get('filter')
628 filter_term = self.request.GET.get('filter')
628 user_log = UserModel().get_user_log(c.user, filter_term)
629 user_log = UserModel().get_user_log(c.user, filter_term)
629
630
630 def url_generator(**kw):
631 def url_generator(**kw):
631 if filter_term:
632 if filter_term:
632 kw['filter'] = filter_term
633 kw['filter'] = filter_term
633 return self.request.current_route_path(_query=kw)
634 return self.request.current_route_path(_query=kw)
634
635
635 c.audit_logs = h.Page(
636 c.audit_logs = h.Page(
636 user_log, page=p, items_per_page=10, url=url_generator)
637 user_log, page=p, items_per_page=10, url=url_generator)
637 c.filter_term = filter_term
638 c.filter_term = filter_term
638 return self._get_template_context(c)
639 return self._get_template_context(c)
639
640
640 @LoginRequired()
641 @LoginRequired()
641 @HasPermissionAllDecorator('hg.admin')
642 @HasPermissionAllDecorator('hg.admin')
642 @view_config(
643 @view_config(
643 route_name='edit_user_perms_summary', request_method='GET',
644 route_name='edit_user_perms_summary', request_method='GET',
644 renderer='rhodecode:templates/admin/users/user_edit.mako')
645 renderer='rhodecode:templates/admin/users/user_edit.mako')
645 def user_perms_summary(self):
646 def user_perms_summary(self):
646 _ = self.request.translate
647 _ = self.request.translate
647 c = self.load_default_context()
648 c = self.load_default_context()
648
649
649 user_id = self.request.matchdict.get('user_id')
650 user_id = self.request.matchdict.get('user_id')
650 c.user = User.get_or_404(user_id)
651 c.user = User.get_or_404(user_id)
651 self._redirect_for_default_user(c.user.username)
652 self._redirect_for_default_user(c.user.username)
652
653
653 c.active = 'perms_summary'
654 c.active = 'perms_summary'
654 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
655 c.perm_user = c.user.AuthUser(ip_addr=self.request.remote_addr)
655
656
656 return self._get_template_context(c)
657 return self._get_template_context(c)
657
658
658 @LoginRequired()
659 @LoginRequired()
659 @HasPermissionAllDecorator('hg.admin')
660 @HasPermissionAllDecorator('hg.admin')
660 @view_config(
661 @view_config(
661 route_name='edit_user_perms_summary_json', request_method='GET',
662 route_name='edit_user_perms_summary_json', request_method='GET',
662 renderer='json_ext')
663 renderer='json_ext')
663 def user_perms_summary_json(self):
664 def user_perms_summary_json(self):
664 self.load_default_context()
665 self.load_default_context()
665
666
666 user_id = self.request.matchdict.get('user_id')
667 user_id = self.request.matchdict.get('user_id')
667 user = User.get_or_404(user_id)
668 user = User.get_or_404(user_id)
668 self._redirect_for_default_user(user.username)
669 self._redirect_for_default_user(user.username)
669
670
670 perm_user = user.AuthUser(ip_addr=self.request.remote_addr)
671 perm_user = user.AuthUser(ip_addr=self.request.remote_addr)
671
672
672 return perm_user.permissions
673 return perm_user.permissions
General Comments 0
You need to be logged in to leave comments. Login now