##// END OF EJS Templates
ux: put gravatar and username together in user list #3203
lisaq -
r495:6dfe88f2 default
parent child Browse files
Show More
@@ -1,719 +1,717 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 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 """
21 """
22 Users crud controller for pylons
22 Users crud controller for pylons
23 """
23 """
24
24
25 import logging
25 import logging
26 import formencode
26 import formencode
27
27
28 from formencode import htmlfill
28 from formencode import htmlfill
29 from pylons import request, tmpl_context as c, url, config
29 from pylons import request, tmpl_context as c, url, config
30 from pylons.controllers.util import redirect
30 from pylons.controllers.util import redirect
31 from pylons.i18n.translation import _
31 from pylons.i18n.translation import _
32
32
33 from rhodecode.authentication.plugins import auth_rhodecode
33 from rhodecode.authentication.plugins import auth_rhodecode
34 from rhodecode.lib.exceptions import (
34 from rhodecode.lib.exceptions import (
35 DefaultUserException, UserOwnsReposException, UserOwnsRepoGroupsException,
35 DefaultUserException, UserOwnsReposException, UserOwnsRepoGroupsException,
36 UserOwnsUserGroupsException, UserCreationError)
36 UserOwnsUserGroupsException, UserCreationError)
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38 from rhodecode.lib import auth
38 from rhodecode.lib import auth
39 from rhodecode.lib.auth import (
39 from rhodecode.lib.auth import (
40 LoginRequired, HasPermissionAllDecorator, AuthUser, generate_auth_token)
40 LoginRequired, HasPermissionAllDecorator, AuthUser, generate_auth_token)
41 from rhodecode.lib.base import BaseController, render
41 from rhodecode.lib.base import BaseController, render
42 from rhodecode.model.auth_token import AuthTokenModel
42 from rhodecode.model.auth_token import AuthTokenModel
43
43
44 from rhodecode.model.db import (
44 from rhodecode.model.db import (
45 PullRequestReviewers, User, UserEmailMap, UserIpMap, RepoGroup)
45 PullRequestReviewers, User, UserEmailMap, UserIpMap, RepoGroup)
46 from rhodecode.model.forms import (
46 from rhodecode.model.forms import (
47 UserForm, UserPermissionsForm, UserIndividualPermissionsForm)
47 UserForm, UserPermissionsForm, UserIndividualPermissionsForm)
48 from rhodecode.model.user import UserModel
48 from rhodecode.model.user import UserModel
49 from rhodecode.model.meta import Session
49 from rhodecode.model.meta import Session
50 from rhodecode.model.permission import PermissionModel
50 from rhodecode.model.permission import PermissionModel
51 from rhodecode.lib.utils import action_logger
51 from rhodecode.lib.utils import action_logger
52 from rhodecode.lib.ext_json import json
52 from rhodecode.lib.ext_json import json
53 from rhodecode.lib.utils2 import datetime_to_time, safe_int
53 from rhodecode.lib.utils2 import datetime_to_time, safe_int
54
54
55 log = logging.getLogger(__name__)
55 log = logging.getLogger(__name__)
56
56
57
57
58 class UsersController(BaseController):
58 class UsersController(BaseController):
59 """REST Controller styled on the Atom Publishing Protocol"""
59 """REST Controller styled on the Atom Publishing Protocol"""
60
60
61 @LoginRequired()
61 @LoginRequired()
62 def __before__(self):
62 def __before__(self):
63 super(UsersController, self).__before__()
63 super(UsersController, self).__before__()
64 c.available_permissions = config['available_permissions']
64 c.available_permissions = config['available_permissions']
65 c.allowed_languages = [
65 c.allowed_languages = [
66 ('en', 'English (en)'),
66 ('en', 'English (en)'),
67 ('de', 'German (de)'),
67 ('de', 'German (de)'),
68 ('fr', 'French (fr)'),
68 ('fr', 'French (fr)'),
69 ('it', 'Italian (it)'),
69 ('it', 'Italian (it)'),
70 ('ja', 'Japanese (ja)'),
70 ('ja', 'Japanese (ja)'),
71 ('pl', 'Polish (pl)'),
71 ('pl', 'Polish (pl)'),
72 ('pt', 'Portuguese (pt)'),
72 ('pt', 'Portuguese (pt)'),
73 ('ru', 'Russian (ru)'),
73 ('ru', 'Russian (ru)'),
74 ('zh', 'Chinese (zh)'),
74 ('zh', 'Chinese (zh)'),
75 ]
75 ]
76 PermissionModel().set_global_permission_choices(c, translator=_)
76 PermissionModel().set_global_permission_choices(c, translator=_)
77
77
78 @HasPermissionAllDecorator('hg.admin')
78 @HasPermissionAllDecorator('hg.admin')
79 def index(self):
79 def index(self):
80 """GET /users: All items in the collection"""
80 """GET /users: All items in the collection"""
81 # url('users')
81 # url('users')
82
82
83 from rhodecode.lib.utils import PartialRenderer
83 from rhodecode.lib.utils import PartialRenderer
84 _render = PartialRenderer('data_table/_dt_elements.html')
84 _render = PartialRenderer('data_table/_dt_elements.html')
85
85
86 def grav_tmpl(user_email, size):
86 def grav_tmpl(user_email, size):
87 return _render("user_gravatar", user_email, size)
87 return _render("user_gravatar", user_email, size)
88
88
89 def username(user_id, username):
89 def username(user_id, username):
90 return _render("user_name", user_id, username)
90 return _render("user_name", user_id, username)
91
91
92 def user_actions(user_id, username):
92 def user_actions(user_id, username):
93 return _render("user_actions", user_id, username)
93 return _render("user_actions", user_id, username)
94
94
95 # json generate
95 # json generate
96 c.users_list = User.query()\
96 c.users_list = User.query()\
97 .filter(User.username != User.DEFAULT_USER) \
97 .filter(User.username != User.DEFAULT_USER) \
98 .all()
98 .all()
99
99
100 users_data = []
100 users_data = []
101 for user in c.users_list:
101 for user in c.users_list:
102 users_data.append({
102 users_data.append({
103 "gravatar": grav_tmpl(user.email, 20),
103 "username": h.gravatar_with_user(user.username),
104 "username": h.link_to(
105 user.username, h.url('user_profile', username=user.username)),
106 "username_raw": user.username,
104 "username_raw": user.username,
107 "email": user.email,
105 "email": user.email,
108 "first_name": h.escape(user.name),
106 "first_name": h.escape(user.name),
109 "last_name": h.escape(user.lastname),
107 "last_name": h.escape(user.lastname),
110 "last_login": h.format_date(user.last_login),
108 "last_login": h.format_date(user.last_login),
111 "last_login_raw": datetime_to_time(user.last_login),
109 "last_login_raw": datetime_to_time(user.last_login),
112 "last_activity": h.format_date(
110 "last_activity": h.format_date(
113 h.time_to_datetime(user.user_data.get('last_activity', 0))),
111 h.time_to_datetime(user.user_data.get('last_activity', 0))),
114 "last_activity_raw": user.user_data.get('last_activity', 0),
112 "last_activity_raw": user.user_data.get('last_activity', 0),
115 "active": h.bool2icon(user.active),
113 "active": h.bool2icon(user.active),
116 "active_raw": user.active,
114 "active_raw": user.active,
117 "admin": h.bool2icon(user.admin),
115 "admin": h.bool2icon(user.admin),
118 "admin_raw": user.admin,
116 "admin_raw": user.admin,
119 "extern_type": user.extern_type,
117 "extern_type": user.extern_type,
120 "extern_name": user.extern_name,
118 "extern_name": user.extern_name,
121 "action": user_actions(user.user_id, user.username),
119 "action": user_actions(user.user_id, user.username),
122 })
120 })
123
121
124
122
125 c.data = json.dumps(users_data)
123 c.data = json.dumps(users_data)
126 return render('admin/users/users.html')
124 return render('admin/users/users.html')
127
125
128 @HasPermissionAllDecorator('hg.admin')
126 @HasPermissionAllDecorator('hg.admin')
129 @auth.CSRFRequired()
127 @auth.CSRFRequired()
130 def create(self):
128 def create(self):
131 """POST /users: Create a new item"""
129 """POST /users: Create a new item"""
132 # url('users')
130 # url('users')
133 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
131 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
134 user_model = UserModel()
132 user_model = UserModel()
135 user_form = UserForm()()
133 user_form = UserForm()()
136 try:
134 try:
137 form_result = user_form.to_python(dict(request.POST))
135 form_result = user_form.to_python(dict(request.POST))
138 user = user_model.create(form_result)
136 user = user_model.create(form_result)
139 Session().flush()
137 Session().flush()
140 username = form_result['username']
138 username = form_result['username']
141 action_logger(c.rhodecode_user, 'admin_created_user:%s' % username,
139 action_logger(c.rhodecode_user, 'admin_created_user:%s' % username,
142 None, self.ip_addr, self.sa)
140 None, self.ip_addr, self.sa)
143
141
144 user_link = h.link_to(h.escape(username),
142 user_link = h.link_to(h.escape(username),
145 url('edit_user',
143 url('edit_user',
146 user_id=user.user_id))
144 user_id=user.user_id))
147 h.flash(h.literal(_('Created user %(user_link)s')
145 h.flash(h.literal(_('Created user %(user_link)s')
148 % {'user_link': user_link}), category='success')
146 % {'user_link': user_link}), category='success')
149 Session().commit()
147 Session().commit()
150 except formencode.Invalid as errors:
148 except formencode.Invalid as errors:
151 return htmlfill.render(
149 return htmlfill.render(
152 render('admin/users/user_add.html'),
150 render('admin/users/user_add.html'),
153 defaults=errors.value,
151 defaults=errors.value,
154 errors=errors.error_dict or {},
152 errors=errors.error_dict or {},
155 prefix_error=False,
153 prefix_error=False,
156 encoding="UTF-8",
154 encoding="UTF-8",
157 force_defaults=False)
155 force_defaults=False)
158 except UserCreationError as e:
156 except UserCreationError as e:
159 h.flash(e, 'error')
157 h.flash(e, 'error')
160 except Exception:
158 except Exception:
161 log.exception("Exception creation of user")
159 log.exception("Exception creation of user")
162 h.flash(_('Error occurred during creation of user %s')
160 h.flash(_('Error occurred during creation of user %s')
163 % request.POST.get('username'), category='error')
161 % request.POST.get('username'), category='error')
164 return redirect(url('users'))
162 return redirect(url('users'))
165
163
166 @HasPermissionAllDecorator('hg.admin')
164 @HasPermissionAllDecorator('hg.admin')
167 def new(self):
165 def new(self):
168 """GET /users/new: Form to create a new item"""
166 """GET /users/new: Form to create a new item"""
169 # url('new_user')
167 # url('new_user')
170 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
168 c.default_extern_type = auth_rhodecode.RhodeCodeAuthPlugin.name
171 return render('admin/users/user_add.html')
169 return render('admin/users/user_add.html')
172
170
173 @HasPermissionAllDecorator('hg.admin')
171 @HasPermissionAllDecorator('hg.admin')
174 @auth.CSRFRequired()
172 @auth.CSRFRequired()
175 def update(self, user_id):
173 def update(self, user_id):
176 """PUT /users/user_id: Update an existing item"""
174 """PUT /users/user_id: Update an existing item"""
177 # Forms posted to this method should contain a hidden field:
175 # Forms posted to this method should contain a hidden field:
178 # <input type="hidden" name="_method" value="PUT" />
176 # <input type="hidden" name="_method" value="PUT" />
179 # Or using helpers:
177 # Or using helpers:
180 # h.form(url('update_user', user_id=ID),
178 # h.form(url('update_user', user_id=ID),
181 # method='put')
179 # method='put')
182 # url('user', user_id=ID)
180 # url('user', user_id=ID)
183 user_id = safe_int(user_id)
181 user_id = safe_int(user_id)
184 c.user = User.get_or_404(user_id)
182 c.user = User.get_or_404(user_id)
185 c.active = 'profile'
183 c.active = 'profile'
186 c.extern_type = c.user.extern_type
184 c.extern_type = c.user.extern_type
187 c.extern_name = c.user.extern_name
185 c.extern_name = c.user.extern_name
188 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
186 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
189 available_languages = [x[0] for x in c.allowed_languages]
187 available_languages = [x[0] for x in c.allowed_languages]
190 _form = UserForm(edit=True, available_languages=available_languages,
188 _form = UserForm(edit=True, available_languages=available_languages,
191 old_data={'user_id': user_id,
189 old_data={'user_id': user_id,
192 'email': c.user.email})()
190 'email': c.user.email})()
193 form_result = {}
191 form_result = {}
194 try:
192 try:
195 form_result = _form.to_python(dict(request.POST))
193 form_result = _form.to_python(dict(request.POST))
196 skip_attrs = ['extern_type', 'extern_name']
194 skip_attrs = ['extern_type', 'extern_name']
197 # TODO: plugin should define if username can be updated
195 # TODO: plugin should define if username can be updated
198 if c.extern_type != "rhodecode":
196 if c.extern_type != "rhodecode":
199 # forbid updating username for external accounts
197 # forbid updating username for external accounts
200 skip_attrs.append('username')
198 skip_attrs.append('username')
201
199
202 UserModel().update_user(user_id, skip_attrs=skip_attrs, **form_result)
200 UserModel().update_user(user_id, skip_attrs=skip_attrs, **form_result)
203 usr = form_result['username']
201 usr = form_result['username']
204 action_logger(c.rhodecode_user, 'admin_updated_user:%s' % usr,
202 action_logger(c.rhodecode_user, 'admin_updated_user:%s' % usr,
205 None, self.ip_addr, self.sa)
203 None, self.ip_addr, self.sa)
206 h.flash(_('User updated successfully'), category='success')
204 h.flash(_('User updated successfully'), category='success')
207 Session().commit()
205 Session().commit()
208 except formencode.Invalid as errors:
206 except formencode.Invalid as errors:
209 defaults = errors.value
207 defaults = errors.value
210 e = errors.error_dict or {}
208 e = errors.error_dict or {}
211
209
212 return htmlfill.render(
210 return htmlfill.render(
213 render('admin/users/user_edit.html'),
211 render('admin/users/user_edit.html'),
214 defaults=defaults,
212 defaults=defaults,
215 errors=e,
213 errors=e,
216 prefix_error=False,
214 prefix_error=False,
217 encoding="UTF-8",
215 encoding="UTF-8",
218 force_defaults=False)
216 force_defaults=False)
219 except UserCreationError as e:
217 except UserCreationError as e:
220 h.flash(e, 'error')
218 h.flash(e, 'error')
221 except Exception:
219 except Exception:
222 log.exception("Exception updating user")
220 log.exception("Exception updating user")
223 h.flash(_('Error occurred during update of user %s')
221 h.flash(_('Error occurred during update of user %s')
224 % form_result.get('username'), category='error')
222 % form_result.get('username'), category='error')
225 return redirect(url('edit_user', user_id=user_id))
223 return redirect(url('edit_user', user_id=user_id))
226
224
227 @HasPermissionAllDecorator('hg.admin')
225 @HasPermissionAllDecorator('hg.admin')
228 @auth.CSRFRequired()
226 @auth.CSRFRequired()
229 def delete(self, user_id):
227 def delete(self, user_id):
230 """DELETE /users/user_id: Delete an existing item"""
228 """DELETE /users/user_id: Delete an existing item"""
231 # Forms posted to this method should contain a hidden field:
229 # Forms posted to this method should contain a hidden field:
232 # <input type="hidden" name="_method" value="DELETE" />
230 # <input type="hidden" name="_method" value="DELETE" />
233 # Or using helpers:
231 # Or using helpers:
234 # h.form(url('delete_user', user_id=ID),
232 # h.form(url('delete_user', user_id=ID),
235 # method='delete')
233 # method='delete')
236 # url('user', user_id=ID)
234 # url('user', user_id=ID)
237 user_id = safe_int(user_id)
235 user_id = safe_int(user_id)
238 c.user = User.get_or_404(user_id)
236 c.user = User.get_or_404(user_id)
239
237
240 _repos = c.user.repositories
238 _repos = c.user.repositories
241 _repo_groups = c.user.repository_groups
239 _repo_groups = c.user.repository_groups
242 _user_groups = c.user.user_groups
240 _user_groups = c.user.user_groups
243
241
244 handle_repos = None
242 handle_repos = None
245 handle_repo_groups = None
243 handle_repo_groups = None
246 handle_user_groups = None
244 handle_user_groups = None
247 # dummy call for flash of handle
245 # dummy call for flash of handle
248 set_handle_flash_repos = lambda: None
246 set_handle_flash_repos = lambda: None
249 set_handle_flash_repo_groups = lambda: None
247 set_handle_flash_repo_groups = lambda: None
250 set_handle_flash_user_groups = lambda: None
248 set_handle_flash_user_groups = lambda: None
251
249
252 if _repos and request.POST.get('user_repos'):
250 if _repos and request.POST.get('user_repos'):
253 do = request.POST['user_repos']
251 do = request.POST['user_repos']
254 if do == 'detach':
252 if do == 'detach':
255 handle_repos = 'detach'
253 handle_repos = 'detach'
256 set_handle_flash_repos = lambda: h.flash(
254 set_handle_flash_repos = lambda: h.flash(
257 _('Detached %s repositories') % len(_repos),
255 _('Detached %s repositories') % len(_repos),
258 category='success')
256 category='success')
259 elif do == 'delete':
257 elif do == 'delete':
260 handle_repos = 'delete'
258 handle_repos = 'delete'
261 set_handle_flash_repos = lambda: h.flash(
259 set_handle_flash_repos = lambda: h.flash(
262 _('Deleted %s repositories') % len(_repos),
260 _('Deleted %s repositories') % len(_repos),
263 category='success')
261 category='success')
264
262
265 if _repo_groups and request.POST.get('user_repo_groups'):
263 if _repo_groups and request.POST.get('user_repo_groups'):
266 do = request.POST['user_repo_groups']
264 do = request.POST['user_repo_groups']
267 if do == 'detach':
265 if do == 'detach':
268 handle_repo_groups = 'detach'
266 handle_repo_groups = 'detach'
269 set_handle_flash_repo_groups = lambda: h.flash(
267 set_handle_flash_repo_groups = lambda: h.flash(
270 _('Detached %s repository groups') % len(_repo_groups),
268 _('Detached %s repository groups') % len(_repo_groups),
271 category='success')
269 category='success')
272 elif do == 'delete':
270 elif do == 'delete':
273 handle_repo_groups = 'delete'
271 handle_repo_groups = 'delete'
274 set_handle_flash_repo_groups = lambda: h.flash(
272 set_handle_flash_repo_groups = lambda: h.flash(
275 _('Deleted %s repository groups') % len(_repo_groups),
273 _('Deleted %s repository groups') % len(_repo_groups),
276 category='success')
274 category='success')
277
275
278 if _user_groups and request.POST.get('user_user_groups'):
276 if _user_groups and request.POST.get('user_user_groups'):
279 do = request.POST['user_user_groups']
277 do = request.POST['user_user_groups']
280 if do == 'detach':
278 if do == 'detach':
281 handle_user_groups = 'detach'
279 handle_user_groups = 'detach'
282 set_handle_flash_user_groups = lambda: h.flash(
280 set_handle_flash_user_groups = lambda: h.flash(
283 _('Detached %s user groups') % len(_user_groups),
281 _('Detached %s user groups') % len(_user_groups),
284 category='success')
282 category='success')
285 elif do == 'delete':
283 elif do == 'delete':
286 handle_user_groups = 'delete'
284 handle_user_groups = 'delete'
287 set_handle_flash_user_groups = lambda: h.flash(
285 set_handle_flash_user_groups = lambda: h.flash(
288 _('Deleted %s user groups') % len(_user_groups),
286 _('Deleted %s user groups') % len(_user_groups),
289 category='success')
287 category='success')
290
288
291 try:
289 try:
292 UserModel().delete(c.user, handle_repos=handle_repos,
290 UserModel().delete(c.user, handle_repos=handle_repos,
293 handle_repo_groups=handle_repo_groups,
291 handle_repo_groups=handle_repo_groups,
294 handle_user_groups=handle_user_groups)
292 handle_user_groups=handle_user_groups)
295 Session().commit()
293 Session().commit()
296 set_handle_flash_repos()
294 set_handle_flash_repos()
297 set_handle_flash_repo_groups()
295 set_handle_flash_repo_groups()
298 set_handle_flash_user_groups()
296 set_handle_flash_user_groups()
299 h.flash(_('Successfully deleted user'), category='success')
297 h.flash(_('Successfully deleted user'), category='success')
300 except (UserOwnsReposException, UserOwnsRepoGroupsException,
298 except (UserOwnsReposException, UserOwnsRepoGroupsException,
301 UserOwnsUserGroupsException, DefaultUserException) as e:
299 UserOwnsUserGroupsException, DefaultUserException) as e:
302 h.flash(e, category='warning')
300 h.flash(e, category='warning')
303 except Exception:
301 except Exception:
304 log.exception("Exception during deletion of user")
302 log.exception("Exception during deletion of user")
305 h.flash(_('An error occurred during deletion of user'),
303 h.flash(_('An error occurred during deletion of user'),
306 category='error')
304 category='error')
307 return redirect(url('users'))
305 return redirect(url('users'))
308
306
309 @HasPermissionAllDecorator('hg.admin')
307 @HasPermissionAllDecorator('hg.admin')
310 @auth.CSRFRequired()
308 @auth.CSRFRequired()
311 def reset_password(self, user_id):
309 def reset_password(self, user_id):
312 """
310 """
313 toggle reset password flag for this user
311 toggle reset password flag for this user
314
312
315 :param user_id:
313 :param user_id:
316 """
314 """
317 user_id = safe_int(user_id)
315 user_id = safe_int(user_id)
318 c.user = User.get_or_404(user_id)
316 c.user = User.get_or_404(user_id)
319 try:
317 try:
320 old_value = c.user.user_data.get('force_password_change')
318 old_value = c.user.user_data.get('force_password_change')
321 c.user.update_userdata(force_password_change=not old_value)
319 c.user.update_userdata(force_password_change=not old_value)
322 Session().commit()
320 Session().commit()
323 if old_value:
321 if old_value:
324 msg = _('Force password change disabled for user')
322 msg = _('Force password change disabled for user')
325 else:
323 else:
326 msg = _('Force password change enabled for user')
324 msg = _('Force password change enabled for user')
327 h.flash(msg, category='success')
325 h.flash(msg, category='success')
328 except Exception:
326 except Exception:
329 log.exception("Exception during password reset for user")
327 log.exception("Exception during password reset for user")
330 h.flash(_('An error occurred during password reset for user'),
328 h.flash(_('An error occurred during password reset for user'),
331 category='error')
329 category='error')
332
330
333 return redirect(url('edit_user_advanced', user_id=user_id))
331 return redirect(url('edit_user_advanced', user_id=user_id))
334
332
335 @HasPermissionAllDecorator('hg.admin')
333 @HasPermissionAllDecorator('hg.admin')
336 @auth.CSRFRequired()
334 @auth.CSRFRequired()
337 def create_personal_repo_group(self, user_id):
335 def create_personal_repo_group(self, user_id):
338 """
336 """
339 Create personal repository group for this user
337 Create personal repository group for this user
340
338
341 :param user_id:
339 :param user_id:
342 """
340 """
343 from rhodecode.model.repo_group import RepoGroupModel
341 from rhodecode.model.repo_group import RepoGroupModel
344
342
345 user_id = safe_int(user_id)
343 user_id = safe_int(user_id)
346 c.user = User.get_or_404(user_id)
344 c.user = User.get_or_404(user_id)
347
345
348 try:
346 try:
349 desc = RepoGroupModel.PERSONAL_GROUP_DESC % {
347 desc = RepoGroupModel.PERSONAL_GROUP_DESC % {
350 'username': c.user.username}
348 'username': c.user.username}
351 if not RepoGroup.get_by_group_name(c.user.username):
349 if not RepoGroup.get_by_group_name(c.user.username):
352 RepoGroupModel().create(group_name=c.user.username,
350 RepoGroupModel().create(group_name=c.user.username,
353 group_description=desc,
351 group_description=desc,
354 owner=c.user.username)
352 owner=c.user.username)
355
353
356 msg = _('Created repository group `%s`' % (c.user.username,))
354 msg = _('Created repository group `%s`' % (c.user.username,))
357 h.flash(msg, category='success')
355 h.flash(msg, category='success')
358 except Exception:
356 except Exception:
359 log.exception("Exception during repository group creation")
357 log.exception("Exception during repository group creation")
360 msg = _(
358 msg = _(
361 'An error occurred during repository group creation for user')
359 'An error occurred during repository group creation for user')
362 h.flash(msg, category='error')
360 h.flash(msg, category='error')
363
361
364 return redirect(url('edit_user_advanced', user_id=user_id))
362 return redirect(url('edit_user_advanced', user_id=user_id))
365
363
366 @HasPermissionAllDecorator('hg.admin')
364 @HasPermissionAllDecorator('hg.admin')
367 def show(self, user_id):
365 def show(self, user_id):
368 """GET /users/user_id: Show a specific item"""
366 """GET /users/user_id: Show a specific item"""
369 # url('user', user_id=ID)
367 # url('user', user_id=ID)
370 User.get_or_404(-1)
368 User.get_or_404(-1)
371
369
372 @HasPermissionAllDecorator('hg.admin')
370 @HasPermissionAllDecorator('hg.admin')
373 def edit(self, user_id):
371 def edit(self, user_id):
374 """GET /users/user_id/edit: Form to edit an existing item"""
372 """GET /users/user_id/edit: Form to edit an existing item"""
375 # url('edit_user', user_id=ID)
373 # url('edit_user', user_id=ID)
376 user_id = safe_int(user_id)
374 user_id = safe_int(user_id)
377 c.user = User.get_or_404(user_id)
375 c.user = User.get_or_404(user_id)
378 if c.user.username == User.DEFAULT_USER:
376 if c.user.username == User.DEFAULT_USER:
379 h.flash(_("You can't edit this user"), category='warning')
377 h.flash(_("You can't edit this user"), category='warning')
380 return redirect(url('users'))
378 return redirect(url('users'))
381
379
382 c.active = 'profile'
380 c.active = 'profile'
383 c.extern_type = c.user.extern_type
381 c.extern_type = c.user.extern_type
384 c.extern_name = c.user.extern_name
382 c.extern_name = c.user.extern_name
385 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
383 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
386
384
387 defaults = c.user.get_dict()
385 defaults = c.user.get_dict()
388 defaults.update({'language': c.user.user_data.get('language')})
386 defaults.update({'language': c.user.user_data.get('language')})
389 return htmlfill.render(
387 return htmlfill.render(
390 render('admin/users/user_edit.html'),
388 render('admin/users/user_edit.html'),
391 defaults=defaults,
389 defaults=defaults,
392 encoding="UTF-8",
390 encoding="UTF-8",
393 force_defaults=False)
391 force_defaults=False)
394
392
395 @HasPermissionAllDecorator('hg.admin')
393 @HasPermissionAllDecorator('hg.admin')
396 def edit_advanced(self, user_id):
394 def edit_advanced(self, user_id):
397 user_id = safe_int(user_id)
395 user_id = safe_int(user_id)
398 user = c.user = User.get_or_404(user_id)
396 user = c.user = User.get_or_404(user_id)
399 if user.username == User.DEFAULT_USER:
397 if user.username == User.DEFAULT_USER:
400 h.flash(_("You can't edit this user"), category='warning')
398 h.flash(_("You can't edit this user"), category='warning')
401 return redirect(url('users'))
399 return redirect(url('users'))
402
400
403 c.active = 'advanced'
401 c.active = 'advanced'
404 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
402 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
405 c.personal_repo_group = RepoGroup.get_by_group_name(user.username)
403 c.personal_repo_group = RepoGroup.get_by_group_name(user.username)
406 c.first_admin = User.get_first_super_admin()
404 c.first_admin = User.get_first_super_admin()
407 defaults = user.get_dict()
405 defaults = user.get_dict()
408
406
409 # Interim workaround if the user participated on any pull requests as a
407 # Interim workaround if the user participated on any pull requests as a
410 # reviewer.
408 # reviewer.
411 has_review = bool(PullRequestReviewers.query().filter(
409 has_review = bool(PullRequestReviewers.query().filter(
412 PullRequestReviewers.user_id == user_id).first())
410 PullRequestReviewers.user_id == user_id).first())
413 c.can_delete_user = not has_review
411 c.can_delete_user = not has_review
414 c.can_delete_user_message = _(
412 c.can_delete_user_message = _(
415 'The user participates as reviewer in pull requests and '
413 'The user participates as reviewer in pull requests and '
416 'cannot be deleted. You can set the user to '
414 'cannot be deleted. You can set the user to '
417 '"inactive" instead of deleting it.') if has_review else ''
415 '"inactive" instead of deleting it.') if has_review else ''
418
416
419 return htmlfill.render(
417 return htmlfill.render(
420 render('admin/users/user_edit.html'),
418 render('admin/users/user_edit.html'),
421 defaults=defaults,
419 defaults=defaults,
422 encoding="UTF-8",
420 encoding="UTF-8",
423 force_defaults=False)
421 force_defaults=False)
424
422
425 @HasPermissionAllDecorator('hg.admin')
423 @HasPermissionAllDecorator('hg.admin')
426 def edit_auth_tokens(self, user_id):
424 def edit_auth_tokens(self, user_id):
427 user_id = safe_int(user_id)
425 user_id = safe_int(user_id)
428 c.user = User.get_or_404(user_id)
426 c.user = User.get_or_404(user_id)
429 if c.user.username == User.DEFAULT_USER:
427 if c.user.username == User.DEFAULT_USER:
430 h.flash(_("You can't edit this user"), category='warning')
428 h.flash(_("You can't edit this user"), category='warning')
431 return redirect(url('users'))
429 return redirect(url('users'))
432
430
433 c.active = 'auth_tokens'
431 c.active = 'auth_tokens'
434 show_expired = True
432 show_expired = True
435 c.lifetime_values = [
433 c.lifetime_values = [
436 (str(-1), _('forever')),
434 (str(-1), _('forever')),
437 (str(5), _('5 minutes')),
435 (str(5), _('5 minutes')),
438 (str(60), _('1 hour')),
436 (str(60), _('1 hour')),
439 (str(60 * 24), _('1 day')),
437 (str(60 * 24), _('1 day')),
440 (str(60 * 24 * 30), _('1 month')),
438 (str(60 * 24 * 30), _('1 month')),
441 ]
439 ]
442 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
440 c.lifetime_options = [(c.lifetime_values, _("Lifetime"))]
443 c.role_values = [(x, AuthTokenModel.cls._get_role_name(x))
441 c.role_values = [(x, AuthTokenModel.cls._get_role_name(x))
444 for x in AuthTokenModel.cls.ROLES]
442 for x in AuthTokenModel.cls.ROLES]
445 c.role_options = [(c.role_values, _("Role"))]
443 c.role_options = [(c.role_values, _("Role"))]
446 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
444 c.user_auth_tokens = AuthTokenModel().get_auth_tokens(
447 c.user.user_id, show_expired=show_expired)
445 c.user.user_id, show_expired=show_expired)
448 defaults = c.user.get_dict()
446 defaults = c.user.get_dict()
449 return htmlfill.render(
447 return htmlfill.render(
450 render('admin/users/user_edit.html'),
448 render('admin/users/user_edit.html'),
451 defaults=defaults,
449 defaults=defaults,
452 encoding="UTF-8",
450 encoding="UTF-8",
453 force_defaults=False)
451 force_defaults=False)
454
452
455 @HasPermissionAllDecorator('hg.admin')
453 @HasPermissionAllDecorator('hg.admin')
456 @auth.CSRFRequired()
454 @auth.CSRFRequired()
457 def add_auth_token(self, user_id):
455 def add_auth_token(self, user_id):
458 user_id = safe_int(user_id)
456 user_id = safe_int(user_id)
459 c.user = User.get_or_404(user_id)
457 c.user = User.get_or_404(user_id)
460 if c.user.username == User.DEFAULT_USER:
458 if c.user.username == User.DEFAULT_USER:
461 h.flash(_("You can't edit this user"), category='warning')
459 h.flash(_("You can't edit this user"), category='warning')
462 return redirect(url('users'))
460 return redirect(url('users'))
463
461
464 lifetime = safe_int(request.POST.get('lifetime'), -1)
462 lifetime = safe_int(request.POST.get('lifetime'), -1)
465 description = request.POST.get('description')
463 description = request.POST.get('description')
466 role = request.POST.get('role')
464 role = request.POST.get('role')
467 AuthTokenModel().create(c.user.user_id, description, lifetime, role)
465 AuthTokenModel().create(c.user.user_id, description, lifetime, role)
468 Session().commit()
466 Session().commit()
469 h.flash(_("Auth token successfully created"), category='success')
467 h.flash(_("Auth token successfully created"), category='success')
470 return redirect(url('edit_user_auth_tokens', user_id=c.user.user_id))
468 return redirect(url('edit_user_auth_tokens', user_id=c.user.user_id))
471
469
472 @HasPermissionAllDecorator('hg.admin')
470 @HasPermissionAllDecorator('hg.admin')
473 @auth.CSRFRequired()
471 @auth.CSRFRequired()
474 def delete_auth_token(self, user_id):
472 def delete_auth_token(self, user_id):
475 user_id = safe_int(user_id)
473 user_id = safe_int(user_id)
476 c.user = User.get_or_404(user_id)
474 c.user = User.get_or_404(user_id)
477 if c.user.username == User.DEFAULT_USER:
475 if c.user.username == User.DEFAULT_USER:
478 h.flash(_("You can't edit this user"), category='warning')
476 h.flash(_("You can't edit this user"), category='warning')
479 return redirect(url('users'))
477 return redirect(url('users'))
480
478
481 auth_token = request.POST.get('del_auth_token')
479 auth_token = request.POST.get('del_auth_token')
482 if request.POST.get('del_auth_token_builtin'):
480 if request.POST.get('del_auth_token_builtin'):
483 user = User.get(c.user.user_id)
481 user = User.get(c.user.user_id)
484 if user:
482 if user:
485 user.api_key = generate_auth_token(user.username)
483 user.api_key = generate_auth_token(user.username)
486 Session().add(user)
484 Session().add(user)
487 Session().commit()
485 Session().commit()
488 h.flash(_("Auth token successfully reset"), category='success')
486 h.flash(_("Auth token successfully reset"), category='success')
489 elif auth_token:
487 elif auth_token:
490 AuthTokenModel().delete(auth_token, c.user.user_id)
488 AuthTokenModel().delete(auth_token, c.user.user_id)
491 Session().commit()
489 Session().commit()
492 h.flash(_("Auth token successfully deleted"), category='success')
490 h.flash(_("Auth token successfully deleted"), category='success')
493
491
494 return redirect(url('edit_user_auth_tokens', user_id=c.user.user_id))
492 return redirect(url('edit_user_auth_tokens', user_id=c.user.user_id))
495
493
496 @HasPermissionAllDecorator('hg.admin')
494 @HasPermissionAllDecorator('hg.admin')
497 def edit_global_perms(self, user_id):
495 def edit_global_perms(self, user_id):
498 user_id = safe_int(user_id)
496 user_id = safe_int(user_id)
499 c.user = User.get_or_404(user_id)
497 c.user = User.get_or_404(user_id)
500 if c.user.username == User.DEFAULT_USER:
498 if c.user.username == User.DEFAULT_USER:
501 h.flash(_("You can't edit this user"), category='warning')
499 h.flash(_("You can't edit this user"), category='warning')
502 return redirect(url('users'))
500 return redirect(url('users'))
503
501
504 c.active = 'global_perms'
502 c.active = 'global_perms'
505
503
506 c.default_user = User.get_default_user()
504 c.default_user = User.get_default_user()
507 defaults = c.user.get_dict()
505 defaults = c.user.get_dict()
508 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
506 defaults.update(c.default_user.get_default_perms(suffix='_inherited'))
509 defaults.update(c.default_user.get_default_perms())
507 defaults.update(c.default_user.get_default_perms())
510 defaults.update(c.user.get_default_perms())
508 defaults.update(c.user.get_default_perms())
511
509
512 return htmlfill.render(
510 return htmlfill.render(
513 render('admin/users/user_edit.html'),
511 render('admin/users/user_edit.html'),
514 defaults=defaults,
512 defaults=defaults,
515 encoding="UTF-8",
513 encoding="UTF-8",
516 force_defaults=False)
514 force_defaults=False)
517
515
518 @HasPermissionAllDecorator('hg.admin')
516 @HasPermissionAllDecorator('hg.admin')
519 @auth.CSRFRequired()
517 @auth.CSRFRequired()
520 def update_global_perms(self, user_id):
518 def update_global_perms(self, user_id):
521 """PUT /users_perm/user_id: Update an existing item"""
519 """PUT /users_perm/user_id: Update an existing item"""
522 # url('user_perm', user_id=ID, method='put')
520 # url('user_perm', user_id=ID, method='put')
523 user_id = safe_int(user_id)
521 user_id = safe_int(user_id)
524 user = User.get_or_404(user_id)
522 user = User.get_or_404(user_id)
525 c.active = 'global_perms'
523 c.active = 'global_perms'
526 try:
524 try:
527 # first stage that verifies the checkbox
525 # first stage that verifies the checkbox
528 _form = UserIndividualPermissionsForm()
526 _form = UserIndividualPermissionsForm()
529 form_result = _form.to_python(dict(request.POST))
527 form_result = _form.to_python(dict(request.POST))
530 inherit_perms = form_result['inherit_default_permissions']
528 inherit_perms = form_result['inherit_default_permissions']
531 user.inherit_default_permissions = inherit_perms
529 user.inherit_default_permissions = inherit_perms
532 Session().add(user)
530 Session().add(user)
533
531
534 if not inherit_perms:
532 if not inherit_perms:
535 # only update the individual ones if we un check the flag
533 # only update the individual ones if we un check the flag
536 _form = UserPermissionsForm(
534 _form = UserPermissionsForm(
537 [x[0] for x in c.repo_create_choices],
535 [x[0] for x in c.repo_create_choices],
538 [x[0] for x in c.repo_create_on_write_choices],
536 [x[0] for x in c.repo_create_on_write_choices],
539 [x[0] for x in c.repo_group_create_choices],
537 [x[0] for x in c.repo_group_create_choices],
540 [x[0] for x in c.user_group_create_choices],
538 [x[0] for x in c.user_group_create_choices],
541 [x[0] for x in c.fork_choices],
539 [x[0] for x in c.fork_choices],
542 [x[0] for x in c.inherit_default_permission_choices])()
540 [x[0] for x in c.inherit_default_permission_choices])()
543
541
544 form_result = _form.to_python(dict(request.POST))
542 form_result = _form.to_python(dict(request.POST))
545 form_result.update({'perm_user_id': user.user_id})
543 form_result.update({'perm_user_id': user.user_id})
546
544
547 PermissionModel().update_user_permissions(form_result)
545 PermissionModel().update_user_permissions(form_result)
548
546
549 Session().commit()
547 Session().commit()
550 h.flash(_('User global permissions updated successfully'),
548 h.flash(_('User global permissions updated successfully'),
551 category='success')
549 category='success')
552
550
553 Session().commit()
551 Session().commit()
554 except formencode.Invalid as errors:
552 except formencode.Invalid as errors:
555 defaults = errors.value
553 defaults = errors.value
556 c.user = user
554 c.user = user
557 return htmlfill.render(
555 return htmlfill.render(
558 render('admin/users/user_edit.html'),
556 render('admin/users/user_edit.html'),
559 defaults=defaults,
557 defaults=defaults,
560 errors=errors.error_dict or {},
558 errors=errors.error_dict or {},
561 prefix_error=False,
559 prefix_error=False,
562 encoding="UTF-8",
560 encoding="UTF-8",
563 force_defaults=False)
561 force_defaults=False)
564 except Exception:
562 except Exception:
565 log.exception("Exception during permissions saving")
563 log.exception("Exception during permissions saving")
566 h.flash(_('An error occurred during permissions saving'),
564 h.flash(_('An error occurred during permissions saving'),
567 category='error')
565 category='error')
568 return redirect(url('edit_user_global_perms', user_id=user_id))
566 return redirect(url('edit_user_global_perms', user_id=user_id))
569
567
570 @HasPermissionAllDecorator('hg.admin')
568 @HasPermissionAllDecorator('hg.admin')
571 def edit_perms_summary(self, user_id):
569 def edit_perms_summary(self, user_id):
572 user_id = safe_int(user_id)
570 user_id = safe_int(user_id)
573 c.user = User.get_or_404(user_id)
571 c.user = User.get_or_404(user_id)
574 if c.user.username == User.DEFAULT_USER:
572 if c.user.username == User.DEFAULT_USER:
575 h.flash(_("You can't edit this user"), category='warning')
573 h.flash(_("You can't edit this user"), category='warning')
576 return redirect(url('users'))
574 return redirect(url('users'))
577
575
578 c.active = 'perms_summary'
576 c.active = 'perms_summary'
579 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
577 c.perm_user = AuthUser(user_id=user_id, ip_addr=self.ip_addr)
580
578
581 return render('admin/users/user_edit.html')
579 return render('admin/users/user_edit.html')
582
580
583 @HasPermissionAllDecorator('hg.admin')
581 @HasPermissionAllDecorator('hg.admin')
584 def edit_emails(self, user_id):
582 def edit_emails(self, user_id):
585 user_id = safe_int(user_id)
583 user_id = safe_int(user_id)
586 c.user = User.get_or_404(user_id)
584 c.user = User.get_or_404(user_id)
587 if c.user.username == User.DEFAULT_USER:
585 if c.user.username == User.DEFAULT_USER:
588 h.flash(_("You can't edit this user"), category='warning')
586 h.flash(_("You can't edit this user"), category='warning')
589 return redirect(url('users'))
587 return redirect(url('users'))
590
588
591 c.active = 'emails'
589 c.active = 'emails'
592 c.user_email_map = UserEmailMap.query() \
590 c.user_email_map = UserEmailMap.query() \
593 .filter(UserEmailMap.user == c.user).all()
591 .filter(UserEmailMap.user == c.user).all()
594
592
595 defaults = c.user.get_dict()
593 defaults = c.user.get_dict()
596 return htmlfill.render(
594 return htmlfill.render(
597 render('admin/users/user_edit.html'),
595 render('admin/users/user_edit.html'),
598 defaults=defaults,
596 defaults=defaults,
599 encoding="UTF-8",
597 encoding="UTF-8",
600 force_defaults=False)
598 force_defaults=False)
601
599
602 @HasPermissionAllDecorator('hg.admin')
600 @HasPermissionAllDecorator('hg.admin')
603 @auth.CSRFRequired()
601 @auth.CSRFRequired()
604 def add_email(self, user_id):
602 def add_email(self, user_id):
605 """POST /user_emails:Add an existing item"""
603 """POST /user_emails:Add an existing item"""
606 # url('user_emails', user_id=ID, method='put')
604 # url('user_emails', user_id=ID, method='put')
607 user_id = safe_int(user_id)
605 user_id = safe_int(user_id)
608 c.user = User.get_or_404(user_id)
606 c.user = User.get_or_404(user_id)
609
607
610 email = request.POST.get('new_email')
608 email = request.POST.get('new_email')
611 user_model = UserModel()
609 user_model = UserModel()
612
610
613 try:
611 try:
614 user_model.add_extra_email(user_id, email)
612 user_model.add_extra_email(user_id, email)
615 Session().commit()
613 Session().commit()
616 h.flash(_("Added new email address `%s` for user account") % email,
614 h.flash(_("Added new email address `%s` for user account") % email,
617 category='success')
615 category='success')
618 except formencode.Invalid as error:
616 except formencode.Invalid as error:
619 msg = error.error_dict['email']
617 msg = error.error_dict['email']
620 h.flash(msg, category='error')
618 h.flash(msg, category='error')
621 except Exception:
619 except Exception:
622 log.exception("Exception during email saving")
620 log.exception("Exception during email saving")
623 h.flash(_('An error occurred during email saving'),
621 h.flash(_('An error occurred during email saving'),
624 category='error')
622 category='error')
625 return redirect(url('edit_user_emails', user_id=user_id))
623 return redirect(url('edit_user_emails', user_id=user_id))
626
624
627 @HasPermissionAllDecorator('hg.admin')
625 @HasPermissionAllDecorator('hg.admin')
628 @auth.CSRFRequired()
626 @auth.CSRFRequired()
629 def delete_email(self, user_id):
627 def delete_email(self, user_id):
630 """DELETE /user_emails_delete/user_id: Delete an existing item"""
628 """DELETE /user_emails_delete/user_id: Delete an existing item"""
631 # url('user_emails_delete', user_id=ID, method='delete')
629 # url('user_emails_delete', user_id=ID, method='delete')
632 user_id = safe_int(user_id)
630 user_id = safe_int(user_id)
633 c.user = User.get_or_404(user_id)
631 c.user = User.get_or_404(user_id)
634 email_id = request.POST.get('del_email_id')
632 email_id = request.POST.get('del_email_id')
635 user_model = UserModel()
633 user_model = UserModel()
636 user_model.delete_extra_email(user_id, email_id)
634 user_model.delete_extra_email(user_id, email_id)
637 Session().commit()
635 Session().commit()
638 h.flash(_("Removed email address from user account"), category='success')
636 h.flash(_("Removed email address from user account"), category='success')
639 return redirect(url('edit_user_emails', user_id=user_id))
637 return redirect(url('edit_user_emails', user_id=user_id))
640
638
641 @HasPermissionAllDecorator('hg.admin')
639 @HasPermissionAllDecorator('hg.admin')
642 def edit_ips(self, user_id):
640 def edit_ips(self, user_id):
643 user_id = safe_int(user_id)
641 user_id = safe_int(user_id)
644 c.user = User.get_or_404(user_id)
642 c.user = User.get_or_404(user_id)
645 if c.user.username == User.DEFAULT_USER:
643 if c.user.username == User.DEFAULT_USER:
646 h.flash(_("You can't edit this user"), category='warning')
644 h.flash(_("You can't edit this user"), category='warning')
647 return redirect(url('users'))
645 return redirect(url('users'))
648
646
649 c.active = 'ips'
647 c.active = 'ips'
650 c.user_ip_map = UserIpMap.query() \
648 c.user_ip_map = UserIpMap.query() \
651 .filter(UserIpMap.user == c.user).all()
649 .filter(UserIpMap.user == c.user).all()
652
650
653 c.inherit_default_ips = c.user.inherit_default_permissions
651 c.inherit_default_ips = c.user.inherit_default_permissions
654 c.default_user_ip_map = UserIpMap.query() \
652 c.default_user_ip_map = UserIpMap.query() \
655 .filter(UserIpMap.user == User.get_default_user()).all()
653 .filter(UserIpMap.user == User.get_default_user()).all()
656
654
657 defaults = c.user.get_dict()
655 defaults = c.user.get_dict()
658 return htmlfill.render(
656 return htmlfill.render(
659 render('admin/users/user_edit.html'),
657 render('admin/users/user_edit.html'),
660 defaults=defaults,
658 defaults=defaults,
661 encoding="UTF-8",
659 encoding="UTF-8",
662 force_defaults=False)
660 force_defaults=False)
663
661
664 @HasPermissionAllDecorator('hg.admin')
662 @HasPermissionAllDecorator('hg.admin')
665 @auth.CSRFRequired()
663 @auth.CSRFRequired()
666 def add_ip(self, user_id):
664 def add_ip(self, user_id):
667 """POST /user_ips:Add an existing item"""
665 """POST /user_ips:Add an existing item"""
668 # url('user_ips', user_id=ID, method='put')
666 # url('user_ips', user_id=ID, method='put')
669
667
670 user_id = safe_int(user_id)
668 user_id = safe_int(user_id)
671 c.user = User.get_or_404(user_id)
669 c.user = User.get_or_404(user_id)
672 user_model = UserModel()
670 user_model = UserModel()
673 try:
671 try:
674 ip_list = user_model.parse_ip_range(request.POST.get('new_ip'))
672 ip_list = user_model.parse_ip_range(request.POST.get('new_ip'))
675 except Exception as e:
673 except Exception as e:
676 ip_list = []
674 ip_list = []
677 log.exception("Exception during ip saving")
675 log.exception("Exception during ip saving")
678 h.flash(_('An error occurred during ip saving:%s' % (e,)),
676 h.flash(_('An error occurred during ip saving:%s' % (e,)),
679 category='error')
677 category='error')
680
678
681 desc = request.POST.get('description')
679 desc = request.POST.get('description')
682 added = []
680 added = []
683 for ip in ip_list:
681 for ip in ip_list:
684 try:
682 try:
685 user_model.add_extra_ip(user_id, ip, desc)
683 user_model.add_extra_ip(user_id, ip, desc)
686 Session().commit()
684 Session().commit()
687 added.append(ip)
685 added.append(ip)
688 except formencode.Invalid as error:
686 except formencode.Invalid as error:
689 msg = error.error_dict['ip']
687 msg = error.error_dict['ip']
690 h.flash(msg, category='error')
688 h.flash(msg, category='error')
691 except Exception:
689 except Exception:
692 log.exception("Exception during ip saving")
690 log.exception("Exception during ip saving")
693 h.flash(_('An error occurred during ip saving'),
691 h.flash(_('An error occurred during ip saving'),
694 category='error')
692 category='error')
695 if added:
693 if added:
696 h.flash(
694 h.flash(
697 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
695 _("Added ips %s to user whitelist") % (', '.join(ip_list), ),
698 category='success')
696 category='success')
699 if 'default_user' in request.POST:
697 if 'default_user' in request.POST:
700 return redirect(url('admin_permissions_ips'))
698 return redirect(url('admin_permissions_ips'))
701 return redirect(url('edit_user_ips', user_id=user_id))
699 return redirect(url('edit_user_ips', user_id=user_id))
702
700
703 @HasPermissionAllDecorator('hg.admin')
701 @HasPermissionAllDecorator('hg.admin')
704 @auth.CSRFRequired()
702 @auth.CSRFRequired()
705 def delete_ip(self, user_id):
703 def delete_ip(self, user_id):
706 """DELETE /user_ips_delete/user_id: Delete an existing item"""
704 """DELETE /user_ips_delete/user_id: Delete an existing item"""
707 # url('user_ips_delete', user_id=ID, method='delete')
705 # url('user_ips_delete', user_id=ID, method='delete')
708 user_id = safe_int(user_id)
706 user_id = safe_int(user_id)
709 c.user = User.get_or_404(user_id)
707 c.user = User.get_or_404(user_id)
710
708
711 ip_id = request.POST.get('del_ip_id')
709 ip_id = request.POST.get('del_ip_id')
712 user_model = UserModel()
710 user_model = UserModel()
713 user_model.delete_extra_ip(user_id, ip_id)
711 user_model.delete_extra_ip(user_id, ip_id)
714 Session().commit()
712 Session().commit()
715 h.flash(_("Removed ip address from user whitelist"), category='success')
713 h.flash(_("Removed ip address from user whitelist"), category='success')
716
714
717 if 'default_user' in request.POST:
715 if 'default_user' in request.POST:
718 return redirect(url('admin_permissions_ips'))
716 return redirect(url('admin_permissions_ips'))
719 return redirect(url('edit_user_ips', user_id=user_id))
717 return redirect(url('edit_user_ips', user_id=user_id))
@@ -1,141 +1,140 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('Users administration')}
5 ${_('Users administration')}
6 %if c.rhodecode_name:
6 %if c.rhodecode_name:
7 &middot; ${h.branding(c.rhodecode_name)}
7 &middot; ${h.branding(c.rhodecode_name)}
8 %endif
8 %endif
9 </%def>
9 </%def>
10
10
11 <%def name="breadcrumbs_links()">
11 <%def name="breadcrumbs_links()">
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
12 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
13 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="user_count">0</span>
13 ${h.link_to(_('Admin'),h.url('admin_home'))} &raquo; <span id="user_count">0</span>
14 </%def>
14 </%def>
15
15
16 <%def name="menu_bar_nav()">
16 <%def name="menu_bar_nav()">
17 ${self.menu_items(active='admin')}
17 ${self.menu_items(active='admin')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box">
21 <div class="box">
22
22
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 <ul class="links">
25 <ul class="links">
26 <li>
26 <li>
27 <a href="${h.url('new_user')}" class="btn btn-small btn-success">${_(u'Add User')}</a>
27 <a href="${h.url('new_user')}" class="btn btn-small btn-success">${_(u'Add User')}</a>
28 </li>
28 </li>
29 </ul>
29 </ul>
30 </div>
30 </div>
31
31
32 <div id="repos_list_wrap">
32 <div id="repos_list_wrap">
33 <table id="user_list_table" class="display"></table>
33 <table id="user_list_table" class="display"></table>
34 </div>
34 </div>
35 </div>
35 </div>
36
36
37 <script>
37 <script>
38 $(document).ready(function() {
38 $(document).ready(function() {
39
39
40 var get_datatable_count = function(){
40 var get_datatable_count = function(){
41 var datatable = $('#user_list_table').dataTable();
41 var datatable = $('#user_list_table').dataTable();
42 var api = datatable.api();
42 var api = datatable.api();
43 var total = api.page.info().recordsDisplay;
43 var total = api.page.info().recordsDisplay;
44 var active = datatable.fnGetFilteredData();
44 var active = datatable.fnGetFilteredData();
45 var _text = _gettext("{0} active out of {1} users").format(active, total);
45 var _text = _gettext("{0} active out of {1} users").format(active, total);
46 $('#user_count').text(_text);
46 $('#user_count').text(_text);
47 };
47 };
48
48
49 // custom filter that filters by username OR email
49 // custom filter that filters by username OR email
50 $.fn.dataTable.ext.search.push(
50 $.fn.dataTable.ext.search.push(
51 function( settings, data, dataIndex ) {
51 function( settings, data, dataIndex ) {
52 var query = $('#q_filter').val();
52 var query = $('#q_filter').val();
53 var username = data[1];
53 var username = data[1];
54 var email = data[2];
54 var email = data[2];
55 var first_name = data[3];
55 var first_name = data[3];
56 var last_name = data[4];
56 var last_name = data[4];
57
57
58 var query_str = username + " " +
58 var query_str = username + " " +
59 email + " " +
59 email + " " +
60 first_name + " " +
60 first_name + " " +
61 last_name;
61 last_name;
62 if((query_str).indexOf(query) !== -1){
62 if((query_str).indexOf(query) !== -1){
63 return true;
63 return true;
64 }
64 }
65 return false;
65 return false;
66 }
66 }
67 );
67 );
68 // filtered data plugin
68 // filtered data plugin
69 $.fn.dataTableExt.oApi.fnGetFilteredData = function ( oSettings ) {
69 $.fn.dataTableExt.oApi.fnGetFilteredData = function ( oSettings ) {
70 var res = [];
70 var res = [];
71 for ( var i=0, iLen=oSettings.fnRecordsDisplay() ; i<iLen ; i++ ) {
71 for ( var i=0, iLen=oSettings.fnRecordsDisplay() ; i<iLen ; i++ ) {
72 var record = oSettings.aoData[i]._aData;
72 var record = oSettings.aoData[i]._aData;
73 if(record['active_raw']){
73 if(record['active_raw']){
74 res.push(record);
74 res.push(record);
75 }
75 }
76 }
76 }
77 return res.length;
77 return res.length;
78 };
78 };
79
79
80 // user list
80 // user list
81 $('#user_list_table').DataTable({
81 $('#user_list_table').DataTable({
82 data: ${c.data|n},
82 data: ${c.data|n},
83 dom: 'rtp',
83 dom: 'rtp',
84 pageLength: ${c.visual.admin_grid_items},
84 pageLength: ${c.visual.admin_grid_items},
85 order: [[ 1, "asc" ]],
85 order: [[ 1, "asc" ]],
86 columns: [
86 columns: [
87 { data: {"_": "gravatar"}, className: "td-gravatar" },
88 { data: {"_": "username",
87 { data: {"_": "username",
89 "sort": "username_raw"}, title: "${_('Username')}", className: "td-user" },
88 "sort": "username_raw"}, title: "${_('Username')}", className: "td-user" },
90 { data: {"_": "email",
89 { data: {"_": "email",
91 "sort": "email"}, title: "${_('Email')}", className: "td-email" },
90 "sort": "email"}, title: "${_('Email')}", className: "td-email" },
92 { data: {"_": "first_name",
91 { data: {"_": "first_name",
93 "sort": "first_name"}, title: "${_('First Name')}", className: "td-user" },
92 "sort": "first_name"}, title: "${_('First Name')}", className: "td-user" },
94 { data: {"_": "last_name",
93 { data: {"_": "last_name",
95 "sort": "last_name"}, title: "${_('Last Name')}", className: "td-user" },
94 "sort": "last_name"}, title: "${_('Last Name')}", className: "td-user" },
96 { data: {"_": "last_login",
95 { data: {"_": "last_login",
97 "sort": "last_login_raw",
96 "sort": "last_login_raw",
98 "type": Number}, title: "${_('Last login')}", className: "td-time" },
97 "type": Number}, title: "${_('Last login')}", className: "td-time" },
99 { data: {"_": "active",
98 { data: {"_": "active",
100 "sort": "active_raw"}, title: "${_('Active')}", className: "td-active" },
99 "sort": "active_raw"}, title: "${_('Active')}", className: "td-active" },
101 { data: {"_": "admin",
100 { data: {"_": "admin",
102 "sort": "admin_raw"}, title: "${_('Admin')}", className: "td-admin" },
101 "sort": "admin_raw"}, title: "${_('Admin')}", className: "td-admin" },
103 { data: {"_": "extern_type",
102 { data: {"_": "extern_type",
104 "sort": "extern_type"}, title: "${_('Authentication type')}", className: "td-type" },
103 "sort": "extern_type"}, title: "${_('Authentication type')}", className: "td-type" },
105 { data: {"_": "action",
104 { data: {"_": "action",
106 "sort": "action"}, title: "${_('Action')}", className: "td-action" }
105 "sort": "action"}, title: "${_('Action')}", className: "td-action" }
107 ],
106 ],
108 language: {
107 language: {
109 paginate: DEFAULT_GRID_PAGINATION,
108 paginate: DEFAULT_GRID_PAGINATION,
110 emptyTable: _gettext("No user_gettext(s available yet.")
109 emptyTable: _gettext("No user_gettext(s available yet.")
111 },
110 },
112 "initComplete": function( settings, json ) {
111 "initComplete": function( settings, json ) {
113 get_datatable_count();
112 get_datatable_count();
114 },
113 },
115 "createdRow": function ( row, data, index ) {
114 "createdRow": function ( row, data, index ) {
116 if (!data['active_raw']){
115 if (!data['active_raw']){
117 $(row).addClass('closed')
116 $(row).addClass('closed')
118 }
117 }
119 }
118 }
120 });
119 });
121
120
122 // update the counter when doing search
121 // update the counter when doing search
123 $('#user_list_table').on( 'search.dt', function (e,settings) {
122 $('#user_list_table').on( 'search.dt', function (e,settings) {
124 get_datatable_count();
123 get_datatable_count();
125 });
124 });
126
125
127 // filter, filter both grids
126 // filter, filter both grids
128 $('#q_filter').on( 'keyup', function () {
127 $('#q_filter').on( 'keyup', function () {
129 var user_api = $('#user_list_table').dataTable().api();
128 var user_api = $('#user_list_table').dataTable().api();
130 user_api
129 user_api
131 .draw();
130 .draw();
132 });
131 });
133
132
134 // refilter table if page load via back button
133 // refilter table if page load via back button
135 $("#q_filter").trigger('keyup');
134 $("#q_filter").trigger('keyup');
136
135
137 });
136 });
138
137
139 </script>
138 </script>
140
139
141 </%def>
140 </%def>
General Comments 0
You need to be logged in to leave comments. Login now