##// END OF EJS Templates
admin-users: remove nullslast() as it's generally not mysql compatible....
marcink -
r1634:38e5e834 stable
parent child Browse files
Show More
@@ -1,317 +1,317 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2016-2017 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22
23 23 from pyramid.httpexceptions import HTTPFound
24 24 from pyramid.view import view_config
25 25
26 26 from rhodecode.lib.helpers import Page
27 27 from rhodecode_tools.lib.ext_json import json
28 28
29 29 from rhodecode.apps._base import BaseAppView
30 30 from rhodecode.lib.auth import (
31 31 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
32 32 from rhodecode.lib import helpers as h
33 33 from rhodecode.lib.utils import PartialRenderer
34 34 from rhodecode.lib.utils2 import safe_int, safe_unicode
35 35 from rhodecode.model.auth_token import AuthTokenModel
36 36 from rhodecode.model.user import UserModel
37 37 from rhodecode.model.user_group import UserGroupModel
38 38 from rhodecode.model.db import User, or_
39 39 from rhodecode.model.meta import Session
40 40
41 41 log = logging.getLogger(__name__)
42 42
43 43
44 44 class AdminUsersView(BaseAppView):
45 45 ALLOW_SCOPED_TOKENS = False
46 46 """
47 47 This view has alternative version inside EE, if modified please take a look
48 48 in there as well.
49 49 """
50 50
51 51 def load_default_context(self):
52 52 c = self._get_local_tmpl_context()
53 53 c.allow_scoped_tokens = self.ALLOW_SCOPED_TOKENS
54 54 self._register_global_c(c)
55 55 return c
56 56
57 57 def _redirect_for_default_user(self, username):
58 58 _ = self.request.translate
59 59 if username == User.DEFAULT_USER:
60 60 h.flash(_("You can't edit this user"), category='warning')
61 61 # TODO(marcink): redirect to 'users' admin panel once this
62 62 # is a pyramid view
63 63 raise HTTPFound('/')
64 64
65 65 def _extract_ordering(self, request):
66 66 column_index = safe_int(request.GET.get('order[0][column]'))
67 67 order_dir = request.GET.get(
68 68 'order[0][dir]', 'desc')
69 69 order_by = request.GET.get(
70 70 'columns[%s][data][sort]' % column_index, 'name_raw')
71 71
72 72 # translate datatable to DB columns
73 73 order_by = {
74 74 'first_name': 'name',
75 75 'last_name': 'lastname',
76 76 }.get(order_by) or order_by
77 77
78 78 search_q = request.GET.get('search[value]')
79 79 return search_q, order_by, order_dir
80 80
81 81 def _extract_chunk(self, request):
82 82 start = safe_int(request.GET.get('start'), 0)
83 83 length = safe_int(request.GET.get('length'), 25)
84 84 draw = safe_int(request.GET.get('draw'))
85 85 return draw, start, length
86 86
87 87 @HasPermissionAllDecorator('hg.admin')
88 88 @view_config(
89 89 route_name='users', request_method='GET',
90 90 renderer='rhodecode:templates/admin/users/users.mako')
91 91 def users_list(self):
92 92 c = self.load_default_context()
93 93 return self._get_template_context(c)
94 94
95 95 @HasPermissionAllDecorator('hg.admin')
96 96 @view_config(
97 97 # renderer defined below
98 98 route_name='users_data', request_method='GET', renderer='json',
99 99 xhr=True)
100 100 def users_list_data(self):
101 101 draw, start, limit = self._extract_chunk(self.request)
102 102 search_q, order_by, order_dir = self._extract_ordering(self.request)
103 103
104 104 _render = PartialRenderer('data_table/_dt_elements.mako')
105 105
106 106 def user_actions(user_id, username):
107 107 return _render("user_actions", user_id, username)
108 108
109 109 users_data_total_count = User.query()\
110 110 .filter(User.username != User.DEFAULT_USER) \
111 111 .count()
112 112
113 113 # json generate
114 114 base_q = User.query().filter(User.username != User.DEFAULT_USER)
115 115
116 116 if search_q:
117 117 like_expression = u'%{}%'.format(safe_unicode(search_q))
118 118 base_q = base_q.filter(or_(
119 119 User.username.ilike(like_expression),
120 120 User._email.ilike(like_expression),
121 121 User.name.ilike(like_expression),
122 122 User.lastname.ilike(like_expression),
123 123 ))
124 124
125 125 users_data_total_filtered_count = base_q.count()
126 126
127 127 sort_col = getattr(User, order_by, None)
128 128 if sort_col and order_dir == 'asc':
129 base_q = base_q.order_by(sort_col.asc().nullslast())
129 base_q = base_q.order_by(sort_col.asc())
130 130 elif sort_col:
131 base_q = base_q.order_by(sort_col.desc().nullslast())
131 base_q = base_q.order_by(sort_col.desc())
132 132
133 133 base_q = base_q.offset(start).limit(limit)
134 134 users_list = base_q.all()
135 135
136 136 users_data = []
137 137 for user in users_list:
138 138 users_data.append({
139 139 "username": h.gravatar_with_user(user.username),
140 140 "email": user.email,
141 141 "first_name": h.escape(user.name),
142 142 "last_name": h.escape(user.lastname),
143 143 "last_login": h.format_date(user.last_login),
144 144 "last_activity": h.format_date(user.last_activity),
145 145 "active": h.bool2icon(user.active),
146 146 "active_raw": user.active,
147 147 "admin": h.bool2icon(user.admin),
148 148 "extern_type": user.extern_type,
149 149 "extern_name": user.extern_name,
150 150 "action": user_actions(user.user_id, user.username),
151 151 })
152 152
153 153 data = ({
154 154 'draw': draw,
155 155 'data': users_data,
156 156 'recordsTotal': users_data_total_count,
157 157 'recordsFiltered': users_data_total_filtered_count,
158 158 })
159 159
160 160 return data
161 161
162 162 @LoginRequired()
163 163 @HasPermissionAllDecorator('hg.admin')
164 164 @view_config(
165 165 route_name='edit_user_auth_tokens', request_method='GET',
166 166 renderer='rhodecode:templates/admin/users/user_edit.mako')
167 167 def auth_tokens(self):
168 168 _ = self.request.translate
169 169 c = self.load_default_context()
170 170
171 171 user_id = self.request.matchdict.get('user_id')
172 172 c.user = User.get_or_404(user_id, pyramid_exc=True)
173 173 self._redirect_for_default_user(c.user.username)
174 174
175 175 c.active = 'auth_tokens'
176 176
177 177 c.lifetime_values = [
178 178 (str(-1), _('forever')),
179 179 (str(5), _('5 minutes')),
180 180 (str(60), _('1 hour')),
181 181 (str(60 * 24), _('1 day')),
182 182 (str(60 * 24 * 30), _('1 month')),
183 183 ]
184 184 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
185 185 c.role_values = [
186 186 (x, AuthTokenModel.cls._get_role_name(x))
187 187 for x in AuthTokenModel.cls.ROLES]
188 188 c.role_options = [(c.role_values, _("Role"))]
189 189 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
190 190 c.user.user_id, show_expired=True)
191 191 return self._get_template_context(c)
192 192
193 193 def maybe_attach_token_scope(self, token):
194 194 # implemented in EE edition
195 195 pass
196 196
197 197 @LoginRequired()
198 198 @HasPermissionAllDecorator('hg.admin')
199 199 @CSRFRequired()
200 200 @view_config(
201 201 route_name='edit_user_auth_tokens_add', request_method='POST')
202 202 def auth_tokens_add(self):
203 203 _ = self.request.translate
204 204 c = self.load_default_context()
205 205
206 206 user_id = self.request.matchdict.get('user_id')
207 207 c.user = User.get_or_404(user_id, pyramid_exc=True)
208 208 self._redirect_for_default_user(c.user.username)
209 209
210 210 lifetime = safe_int(self.request.POST.get('lifetime'), -1)
211 211 description = self.request.POST.get('description')
212 212 role = self.request.POST.get('role')
213 213
214 214 token = AuthTokenModel().create(
215 215 c.user.user_id, description, lifetime, role)
216 216 self.maybe_attach_token_scope(token)
217 217 Session().commit()
218 218
219 219 h.flash(_("Auth token successfully created"), category='success')
220 220 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
221 221
222 222 @LoginRequired()
223 223 @HasPermissionAllDecorator('hg.admin')
224 224 @CSRFRequired()
225 225 @view_config(
226 226 route_name='edit_user_auth_tokens_delete', request_method='POST')
227 227 def auth_tokens_delete(self):
228 228 _ = self.request.translate
229 229 c = self.load_default_context()
230 230
231 231 user_id = self.request.matchdict.get('user_id')
232 232 c.user = User.get_or_404(user_id, pyramid_exc=True)
233 233 self._redirect_for_default_user(c.user.username)
234 234
235 235 del_auth_token = self.request.POST.get('del_auth_token')
236 236
237 237 if del_auth_token:
238 238 AuthTokenModel().delete(del_auth_token, c.user.user_id)
239 239 Session().commit()
240 240 h.flash(_("Auth token successfully deleted"), category='success')
241 241
242 242 return HTTPFound(h.route_path('edit_user_auth_tokens', user_id=user_id))
243 243
244 244 @LoginRequired()
245 245 @HasPermissionAllDecorator('hg.admin')
246 246 @view_config(
247 247 route_name='edit_user_groups_management', request_method='GET',
248 248 renderer='rhodecode:templates/admin/users/user_edit.mako')
249 249 def groups_management(self):
250 250 c = self.load_default_context()
251 251
252 252 user_id = self.request.matchdict.get('user_id')
253 253 c.user = User.get_or_404(user_id, pyramid_exc=True)
254 254 c.data = c.user.group_member
255 255 self._redirect_for_default_user(c.user.username)
256 256 groups = [UserGroupModel.get_user_groups_as_dict(group.users_group) for group in c.user.group_member]
257 257 c.groups = json.dumps(groups)
258 258 c.active = 'groups'
259 259
260 260 return self._get_template_context(c)
261 261
262 262 @LoginRequired()
263 263 @HasPermissionAllDecorator('hg.admin')
264 264 @view_config(
265 265 route_name='edit_user_groups_management_updates', request_method='POST')
266 266 def groups_management_updates(self):
267 267 _ = self.request.translate
268 268 c = self.load_default_context()
269 269
270 270 user_id = self.request.matchdict.get('user_id')
271 271 c.user = User.get_or_404(user_id, pyramid_exc=True)
272 272 self._redirect_for_default_user(c.user.username)
273 273
274 274 users_groups = set(self.request.POST.getall('users_group_id'))
275 275 users_groups_model = []
276 276
277 277 for ugid in users_groups:
278 278 users_groups_model.append(UserGroupModel().get_group(safe_int(ugid)))
279 279 user_group_model = UserGroupModel()
280 280 user_group_model.change_groups(c.user, users_groups_model)
281 281
282 282 Session().commit()
283 283 c.active = 'user_groups_management'
284 284 h.flash(_("Groups successfully changed"), category='success')
285 285
286 286 return HTTPFound(h.route_path(
287 287 'edit_user_groups_management', user_id=user_id))
288 288
289 289 @LoginRequired()
290 290 @HasPermissionAllDecorator('hg.admin')
291 291 @view_config(
292 292 route_name='edit_user_audit_logs', request_method='GET',
293 293 renderer='rhodecode:templates/admin/users/user_edit.mako')
294 294 def user_audit_logs(self):
295 295 _ = self.request.translate
296 296 c = self.load_default_context()
297 297
298 298 user_id = self.request.matchdict.get('user_id')
299 299 c.user = User.get_or_404(user_id, pyramid_exc=True)
300 300 self._redirect_for_default_user(c.user.username)
301 301 c.active = 'audit'
302 302
303 303 p = safe_int(self.request.GET.get('page', 1), 1)
304 304
305 305 filter_term = self.request.GET.get('filter')
306 306 c.user_log = UserModel().get_user_log(c.user, filter_term)
307 307
308 308 def url_generator(**kw):
309 309 if filter_term:
310 310 kw['filter'] = filter_term
311 311 return self.request.current_route_path(_query=kw)
312 312
313 313 c.user_log = Page(c.user_log, page=p, items_per_page=10,
314 314 url=url_generator)
315 315 c.filter_term = filter_term
316 316 return self._get_template_context(c)
317 317
General Comments 0
You need to be logged in to leave comments. Login now