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