##// END OF EJS Templates
ssh-keys: expose last access time on admin summary page for SSH keys.
marcink -
r2134:5a024fcf default
parent child Browse files
Show More
@@ -1,481 +1,482 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 re
21 import re
22 import logging
22 import logging
23 import formencode
23 import formencode
24 import formencode.htmlfill
24 import formencode.htmlfill
25 import datetime
25 import datetime
26 from pyramid.interfaces import IRoutesMapper
26 from pyramid.interfaces import IRoutesMapper
27
27
28 from pyramid.view import view_config
28 from pyramid.view import view_config
29 from pyramid.httpexceptions import HTTPFound
29 from pyramid.httpexceptions import HTTPFound
30 from pyramid.renderers import render
30 from pyramid.renderers import render
31 from pyramid.response import Response
31 from pyramid.response import Response
32
32
33 from rhodecode.apps._base import BaseAppView, DataGridAppView
33 from rhodecode.apps._base import BaseAppView, DataGridAppView
34 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
34 from rhodecode.apps.ssh_support import SshKeyFileChangeEvent
35 from rhodecode.events import trigger
35 from rhodecode.events import trigger
36
36
37 from rhodecode.lib import helpers as h
37 from rhodecode.lib import helpers as h
38 from rhodecode.lib.auth import (
38 from rhodecode.lib.auth import (
39 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
39 LoginRequired, HasPermissionAllDecorator, CSRFRequired)
40 from rhodecode.lib.utils2 import aslist, safe_unicode
40 from rhodecode.lib.utils2 import aslist, safe_unicode
41 from rhodecode.model.db import (
41 from rhodecode.model.db import (
42 or_, coalesce, User, UserIpMap, UserSshKeys)
42 or_, coalesce, User, UserIpMap, UserSshKeys)
43 from rhodecode.model.forms import (
43 from rhodecode.model.forms import (
44 ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm)
44 ApplicationPermissionsForm, ObjectPermissionsForm, UserPermissionsForm)
45 from rhodecode.model.meta import Session
45 from rhodecode.model.meta import Session
46 from rhodecode.model.permission import PermissionModel
46 from rhodecode.model.permission import PermissionModel
47 from rhodecode.model.settings import SettingsModel
47 from rhodecode.model.settings import SettingsModel
48
48
49
49
50 log = logging.getLogger(__name__)
50 log = logging.getLogger(__name__)
51
51
52
52
53 class AdminPermissionsView(BaseAppView, DataGridAppView):
53 class AdminPermissionsView(BaseAppView, DataGridAppView):
54 def load_default_context(self):
54 def load_default_context(self):
55 c = self._get_local_tmpl_context()
55 c = self._get_local_tmpl_context()
56
56
57 self._register_global_c(c)
57 self._register_global_c(c)
58 PermissionModel().set_global_permission_choices(
58 PermissionModel().set_global_permission_choices(
59 c, gettext_translator=self.request.translate)
59 c, gettext_translator=self.request.translate)
60 return c
60 return c
61
61
62 @LoginRequired()
62 @LoginRequired()
63 @HasPermissionAllDecorator('hg.admin')
63 @HasPermissionAllDecorator('hg.admin')
64 @view_config(
64 @view_config(
65 route_name='admin_permissions_application', request_method='GET',
65 route_name='admin_permissions_application', request_method='GET',
66 renderer='rhodecode:templates/admin/permissions/permissions.mako')
66 renderer='rhodecode:templates/admin/permissions/permissions.mako')
67 def permissions_application(self):
67 def permissions_application(self):
68 c = self.load_default_context()
68 c = self.load_default_context()
69 c.active = 'application'
69 c.active = 'application'
70
70
71 c.user = User.get_default_user(refresh=True)
71 c.user = User.get_default_user(refresh=True)
72
72
73 app_settings = SettingsModel().get_all_settings()
73 app_settings = SettingsModel().get_all_settings()
74 defaults = {
74 defaults = {
75 'anonymous': c.user.active,
75 'anonymous': c.user.active,
76 'default_register_message': app_settings.get(
76 'default_register_message': app_settings.get(
77 'rhodecode_register_message')
77 'rhodecode_register_message')
78 }
78 }
79 defaults.update(c.user.get_default_perms())
79 defaults.update(c.user.get_default_perms())
80
80
81 data = render('rhodecode:templates/admin/permissions/permissions.mako',
81 data = render('rhodecode:templates/admin/permissions/permissions.mako',
82 self._get_template_context(c), self.request)
82 self._get_template_context(c), self.request)
83 html = formencode.htmlfill.render(
83 html = formencode.htmlfill.render(
84 data,
84 data,
85 defaults=defaults,
85 defaults=defaults,
86 encoding="UTF-8",
86 encoding="UTF-8",
87 force_defaults=False
87 force_defaults=False
88 )
88 )
89 return Response(html)
89 return Response(html)
90
90
91 @LoginRequired()
91 @LoginRequired()
92 @HasPermissionAllDecorator('hg.admin')
92 @HasPermissionAllDecorator('hg.admin')
93 @CSRFRequired()
93 @CSRFRequired()
94 @view_config(
94 @view_config(
95 route_name='admin_permissions_application_update', request_method='POST',
95 route_name='admin_permissions_application_update', request_method='POST',
96 renderer='rhodecode:templates/admin/permissions/permissions.mako')
96 renderer='rhodecode:templates/admin/permissions/permissions.mako')
97 def permissions_application_update(self):
97 def permissions_application_update(self):
98 _ = self.request.translate
98 _ = self.request.translate
99 c = self.load_default_context()
99 c = self.load_default_context()
100 c.active = 'application'
100 c.active = 'application'
101
101
102 _form = ApplicationPermissionsForm(
102 _form = ApplicationPermissionsForm(
103 [x[0] for x in c.register_choices],
103 [x[0] for x in c.register_choices],
104 [x[0] for x in c.password_reset_choices],
104 [x[0] for x in c.password_reset_choices],
105 [x[0] for x in c.extern_activate_choices])()
105 [x[0] for x in c.extern_activate_choices])()
106
106
107 try:
107 try:
108 form_result = _form.to_python(dict(self.request.POST))
108 form_result = _form.to_python(dict(self.request.POST))
109 form_result.update({'perm_user_name': User.DEFAULT_USER})
109 form_result.update({'perm_user_name': User.DEFAULT_USER})
110 PermissionModel().update_application_permissions(form_result)
110 PermissionModel().update_application_permissions(form_result)
111
111
112 settings = [
112 settings = [
113 ('register_message', 'default_register_message'),
113 ('register_message', 'default_register_message'),
114 ]
114 ]
115 for setting, form_key in settings:
115 for setting, form_key in settings:
116 sett = SettingsModel().create_or_update_setting(
116 sett = SettingsModel().create_or_update_setting(
117 setting, form_result[form_key])
117 setting, form_result[form_key])
118 Session().add(sett)
118 Session().add(sett)
119
119
120 Session().commit()
120 Session().commit()
121 h.flash(_('Application permissions updated successfully'),
121 h.flash(_('Application permissions updated successfully'),
122 category='success')
122 category='success')
123
123
124 except formencode.Invalid as errors:
124 except formencode.Invalid as errors:
125 defaults = errors.value
125 defaults = errors.value
126
126
127 data = render(
127 data = render(
128 'rhodecode:templates/admin/permissions/permissions.mako',
128 'rhodecode:templates/admin/permissions/permissions.mako',
129 self._get_template_context(c), self.request)
129 self._get_template_context(c), self.request)
130 html = formencode.htmlfill.render(
130 html = formencode.htmlfill.render(
131 data,
131 data,
132 defaults=defaults,
132 defaults=defaults,
133 errors=errors.error_dict or {},
133 errors=errors.error_dict or {},
134 prefix_error=False,
134 prefix_error=False,
135 encoding="UTF-8",
135 encoding="UTF-8",
136 force_defaults=False
136 force_defaults=False
137 )
137 )
138 return Response(html)
138 return Response(html)
139
139
140 except Exception:
140 except Exception:
141 log.exception("Exception during update of permissions")
141 log.exception("Exception during update of permissions")
142 h.flash(_('Error occurred during update of permissions'),
142 h.flash(_('Error occurred during update of permissions'),
143 category='error')
143 category='error')
144
144
145 raise HTTPFound(h.route_path('admin_permissions_application'))
145 raise HTTPFound(h.route_path('admin_permissions_application'))
146
146
147 @LoginRequired()
147 @LoginRequired()
148 @HasPermissionAllDecorator('hg.admin')
148 @HasPermissionAllDecorator('hg.admin')
149 @view_config(
149 @view_config(
150 route_name='admin_permissions_object', request_method='GET',
150 route_name='admin_permissions_object', request_method='GET',
151 renderer='rhodecode:templates/admin/permissions/permissions.mako')
151 renderer='rhodecode:templates/admin/permissions/permissions.mako')
152 def permissions_objects(self):
152 def permissions_objects(self):
153 c = self.load_default_context()
153 c = self.load_default_context()
154 c.active = 'objects'
154 c.active = 'objects'
155
155
156 c.user = User.get_default_user(refresh=True)
156 c.user = User.get_default_user(refresh=True)
157 defaults = {}
157 defaults = {}
158 defaults.update(c.user.get_default_perms())
158 defaults.update(c.user.get_default_perms())
159
159
160 data = render(
160 data = render(
161 'rhodecode:templates/admin/permissions/permissions.mako',
161 'rhodecode:templates/admin/permissions/permissions.mako',
162 self._get_template_context(c), self.request)
162 self._get_template_context(c), self.request)
163 html = formencode.htmlfill.render(
163 html = formencode.htmlfill.render(
164 data,
164 data,
165 defaults=defaults,
165 defaults=defaults,
166 encoding="UTF-8",
166 encoding="UTF-8",
167 force_defaults=False
167 force_defaults=False
168 )
168 )
169 return Response(html)
169 return Response(html)
170
170
171 @LoginRequired()
171 @LoginRequired()
172 @HasPermissionAllDecorator('hg.admin')
172 @HasPermissionAllDecorator('hg.admin')
173 @CSRFRequired()
173 @CSRFRequired()
174 @view_config(
174 @view_config(
175 route_name='admin_permissions_object_update', request_method='POST',
175 route_name='admin_permissions_object_update', request_method='POST',
176 renderer='rhodecode:templates/admin/permissions/permissions.mako')
176 renderer='rhodecode:templates/admin/permissions/permissions.mako')
177 def permissions_objects_update(self):
177 def permissions_objects_update(self):
178 _ = self.request.translate
178 _ = self.request.translate
179 c = self.load_default_context()
179 c = self.load_default_context()
180 c.active = 'objects'
180 c.active = 'objects'
181
181
182 _form = ObjectPermissionsForm(
182 _form = ObjectPermissionsForm(
183 [x[0] for x in c.repo_perms_choices],
183 [x[0] for x in c.repo_perms_choices],
184 [x[0] for x in c.group_perms_choices],
184 [x[0] for x in c.group_perms_choices],
185 [x[0] for x in c.user_group_perms_choices])()
185 [x[0] for x in c.user_group_perms_choices])()
186
186
187 try:
187 try:
188 form_result = _form.to_python(dict(self.request.POST))
188 form_result = _form.to_python(dict(self.request.POST))
189 form_result.update({'perm_user_name': User.DEFAULT_USER})
189 form_result.update({'perm_user_name': User.DEFAULT_USER})
190 PermissionModel().update_object_permissions(form_result)
190 PermissionModel().update_object_permissions(form_result)
191
191
192 Session().commit()
192 Session().commit()
193 h.flash(_('Object permissions updated successfully'),
193 h.flash(_('Object permissions updated successfully'),
194 category='success')
194 category='success')
195
195
196 except formencode.Invalid as errors:
196 except formencode.Invalid as errors:
197 defaults = errors.value
197 defaults = errors.value
198
198
199 data = render(
199 data = render(
200 'rhodecode:templates/admin/permissions/permissions.mako',
200 'rhodecode:templates/admin/permissions/permissions.mako',
201 self._get_template_context(c), self.request)
201 self._get_template_context(c), self.request)
202 html = formencode.htmlfill.render(
202 html = formencode.htmlfill.render(
203 data,
203 data,
204 defaults=defaults,
204 defaults=defaults,
205 errors=errors.error_dict or {},
205 errors=errors.error_dict or {},
206 prefix_error=False,
206 prefix_error=False,
207 encoding="UTF-8",
207 encoding="UTF-8",
208 force_defaults=False
208 force_defaults=False
209 )
209 )
210 return Response(html)
210 return Response(html)
211 except Exception:
211 except Exception:
212 log.exception("Exception during update of permissions")
212 log.exception("Exception during update of permissions")
213 h.flash(_('Error occurred during update of permissions'),
213 h.flash(_('Error occurred during update of permissions'),
214 category='error')
214 category='error')
215
215
216 raise HTTPFound(h.route_path('admin_permissions_object'))
216 raise HTTPFound(h.route_path('admin_permissions_object'))
217
217
218 @LoginRequired()
218 @LoginRequired()
219 @HasPermissionAllDecorator('hg.admin')
219 @HasPermissionAllDecorator('hg.admin')
220 @view_config(
220 @view_config(
221 route_name='admin_permissions_global', request_method='GET',
221 route_name='admin_permissions_global', request_method='GET',
222 renderer='rhodecode:templates/admin/permissions/permissions.mako')
222 renderer='rhodecode:templates/admin/permissions/permissions.mako')
223 def permissions_global(self):
223 def permissions_global(self):
224 c = self.load_default_context()
224 c = self.load_default_context()
225 c.active = 'global'
225 c.active = 'global'
226
226
227 c.user = User.get_default_user(refresh=True)
227 c.user = User.get_default_user(refresh=True)
228 defaults = {}
228 defaults = {}
229 defaults.update(c.user.get_default_perms())
229 defaults.update(c.user.get_default_perms())
230
230
231 data = render(
231 data = render(
232 'rhodecode:templates/admin/permissions/permissions.mako',
232 'rhodecode:templates/admin/permissions/permissions.mako',
233 self._get_template_context(c), self.request)
233 self._get_template_context(c), self.request)
234 html = formencode.htmlfill.render(
234 html = formencode.htmlfill.render(
235 data,
235 data,
236 defaults=defaults,
236 defaults=defaults,
237 encoding="UTF-8",
237 encoding="UTF-8",
238 force_defaults=False
238 force_defaults=False
239 )
239 )
240 return Response(html)
240 return Response(html)
241
241
242 @LoginRequired()
242 @LoginRequired()
243 @HasPermissionAllDecorator('hg.admin')
243 @HasPermissionAllDecorator('hg.admin')
244 @CSRFRequired()
244 @CSRFRequired()
245 @view_config(
245 @view_config(
246 route_name='admin_permissions_global_update', request_method='POST',
246 route_name='admin_permissions_global_update', request_method='POST',
247 renderer='rhodecode:templates/admin/permissions/permissions.mako')
247 renderer='rhodecode:templates/admin/permissions/permissions.mako')
248 def permissions_global_update(self):
248 def permissions_global_update(self):
249 _ = self.request.translate
249 _ = self.request.translate
250 c = self.load_default_context()
250 c = self.load_default_context()
251 c.active = 'global'
251 c.active = 'global'
252
252
253 _form = UserPermissionsForm(
253 _form = UserPermissionsForm(
254 [x[0] for x in c.repo_create_choices],
254 [x[0] for x in c.repo_create_choices],
255 [x[0] for x in c.repo_create_on_write_choices],
255 [x[0] for x in c.repo_create_on_write_choices],
256 [x[0] for x in c.repo_group_create_choices],
256 [x[0] for x in c.repo_group_create_choices],
257 [x[0] for x in c.user_group_create_choices],
257 [x[0] for x in c.user_group_create_choices],
258 [x[0] for x in c.fork_choices],
258 [x[0] for x in c.fork_choices],
259 [x[0] for x in c.inherit_default_permission_choices])()
259 [x[0] for x in c.inherit_default_permission_choices])()
260
260
261 try:
261 try:
262 form_result = _form.to_python(dict(self.request.POST))
262 form_result = _form.to_python(dict(self.request.POST))
263 form_result.update({'perm_user_name': User.DEFAULT_USER})
263 form_result.update({'perm_user_name': User.DEFAULT_USER})
264 PermissionModel().update_user_permissions(form_result)
264 PermissionModel().update_user_permissions(form_result)
265
265
266 Session().commit()
266 Session().commit()
267 h.flash(_('Global permissions updated successfully'),
267 h.flash(_('Global permissions updated successfully'),
268 category='success')
268 category='success')
269
269
270 except formencode.Invalid as errors:
270 except formencode.Invalid as errors:
271 defaults = errors.value
271 defaults = errors.value
272
272
273 data = render(
273 data = render(
274 'rhodecode:templates/admin/permissions/permissions.mako',
274 'rhodecode:templates/admin/permissions/permissions.mako',
275 self._get_template_context(c), self.request)
275 self._get_template_context(c), self.request)
276 html = formencode.htmlfill.render(
276 html = formencode.htmlfill.render(
277 data,
277 data,
278 defaults=defaults,
278 defaults=defaults,
279 errors=errors.error_dict or {},
279 errors=errors.error_dict or {},
280 prefix_error=False,
280 prefix_error=False,
281 encoding="UTF-8",
281 encoding="UTF-8",
282 force_defaults=False
282 force_defaults=False
283 )
283 )
284 return Response(html)
284 return Response(html)
285 except Exception:
285 except Exception:
286 log.exception("Exception during update of permissions")
286 log.exception("Exception during update of permissions")
287 h.flash(_('Error occurred during update of permissions'),
287 h.flash(_('Error occurred during update of permissions'),
288 category='error')
288 category='error')
289
289
290 raise HTTPFound(h.route_path('admin_permissions_global'))
290 raise HTTPFound(h.route_path('admin_permissions_global'))
291
291
292 @LoginRequired()
292 @LoginRequired()
293 @HasPermissionAllDecorator('hg.admin')
293 @HasPermissionAllDecorator('hg.admin')
294 @view_config(
294 @view_config(
295 route_name='admin_permissions_ips', request_method='GET',
295 route_name='admin_permissions_ips', request_method='GET',
296 renderer='rhodecode:templates/admin/permissions/permissions.mako')
296 renderer='rhodecode:templates/admin/permissions/permissions.mako')
297 def permissions_ips(self):
297 def permissions_ips(self):
298 c = self.load_default_context()
298 c = self.load_default_context()
299 c.active = 'ips'
299 c.active = 'ips'
300
300
301 c.user = User.get_default_user(refresh=True)
301 c.user = User.get_default_user(refresh=True)
302 c.user_ip_map = (
302 c.user_ip_map = (
303 UserIpMap.query().filter(UserIpMap.user == c.user).all())
303 UserIpMap.query().filter(UserIpMap.user == c.user).all())
304
304
305 return self._get_template_context(c)
305 return self._get_template_context(c)
306
306
307 @LoginRequired()
307 @LoginRequired()
308 @HasPermissionAllDecorator('hg.admin')
308 @HasPermissionAllDecorator('hg.admin')
309 @view_config(
309 @view_config(
310 route_name='admin_permissions_overview', request_method='GET',
310 route_name='admin_permissions_overview', request_method='GET',
311 renderer='rhodecode:templates/admin/permissions/permissions.mako')
311 renderer='rhodecode:templates/admin/permissions/permissions.mako')
312 def permissions_overview(self):
312 def permissions_overview(self):
313 c = self.load_default_context()
313 c = self.load_default_context()
314 c.active = 'perms'
314 c.active = 'perms'
315
315
316 c.user = User.get_default_user(refresh=True)
316 c.user = User.get_default_user(refresh=True)
317 c.perm_user = c.user.AuthUser()
317 c.perm_user = c.user.AuthUser()
318 return self._get_template_context(c)
318 return self._get_template_context(c)
319
319
320 @LoginRequired()
320 @LoginRequired()
321 @HasPermissionAllDecorator('hg.admin')
321 @HasPermissionAllDecorator('hg.admin')
322 @view_config(
322 @view_config(
323 route_name='admin_permissions_auth_token_access', request_method='GET',
323 route_name='admin_permissions_auth_token_access', request_method='GET',
324 renderer='rhodecode:templates/admin/permissions/permissions.mako')
324 renderer='rhodecode:templates/admin/permissions/permissions.mako')
325 def auth_token_access(self):
325 def auth_token_access(self):
326 from rhodecode import CONFIG
326 from rhodecode import CONFIG
327
327
328 c = self.load_default_context()
328 c = self.load_default_context()
329 c.active = 'auth_token_access'
329 c.active = 'auth_token_access'
330
330
331 c.user = User.get_default_user(refresh=True)
331 c.user = User.get_default_user(refresh=True)
332 c.perm_user = c.user.AuthUser()
332 c.perm_user = c.user.AuthUser()
333
333
334 mapper = self.request.registry.queryUtility(IRoutesMapper)
334 mapper = self.request.registry.queryUtility(IRoutesMapper)
335 c.view_data = []
335 c.view_data = []
336
336
337 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
337 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
338 introspector = self.request.registry.introspector
338 introspector = self.request.registry.introspector
339
339
340 view_intr = {}
340 view_intr = {}
341 for view_data in introspector.get_category('views'):
341 for view_data in introspector.get_category('views'):
342 intr = view_data['introspectable']
342 intr = view_data['introspectable']
343
343
344 if 'route_name' in intr and intr['attr']:
344 if 'route_name' in intr and intr['attr']:
345 view_intr[intr['route_name']] = '{}:{}'.format(
345 view_intr[intr['route_name']] = '{}:{}'.format(
346 str(intr['derived_callable'].func_name), intr['attr']
346 str(intr['derived_callable'].func_name), intr['attr']
347 )
347 )
348
348
349 c.whitelist_key = 'api_access_controllers_whitelist'
349 c.whitelist_key = 'api_access_controllers_whitelist'
350 c.whitelist_file = CONFIG.get('__file__')
350 c.whitelist_file = CONFIG.get('__file__')
351 whitelist_views = aslist(
351 whitelist_views = aslist(
352 CONFIG.get(c.whitelist_key), sep=',')
352 CONFIG.get(c.whitelist_key), sep=',')
353
353
354 for route_info in mapper.get_routes():
354 for route_info in mapper.get_routes():
355 if not route_info.name.startswith('__'):
355 if not route_info.name.startswith('__'):
356 routepath = route_info.pattern
356 routepath = route_info.pattern
357
357
358 def replace(matchobj):
358 def replace(matchobj):
359 if matchobj.group(1):
359 if matchobj.group(1):
360 return "{%s}" % matchobj.group(1).split(':')[0]
360 return "{%s}" % matchobj.group(1).split(':')[0]
361 else:
361 else:
362 return "{%s}" % matchobj.group(2)
362 return "{%s}" % matchobj.group(2)
363
363
364 routepath = _argument_prog.sub(replace, routepath)
364 routepath = _argument_prog.sub(replace, routepath)
365
365
366 if not routepath.startswith('/'):
366 if not routepath.startswith('/'):
367 routepath = '/' + routepath
367 routepath = '/' + routepath
368
368
369 view_fqn = view_intr.get(route_info.name, 'NOT AVAILABLE')
369 view_fqn = view_intr.get(route_info.name, 'NOT AVAILABLE')
370 active = view_fqn in whitelist_views
370 active = view_fqn in whitelist_views
371 c.view_data.append((route_info.name, view_fqn, routepath, active))
371 c.view_data.append((route_info.name, view_fqn, routepath, active))
372
372
373 c.whitelist_views = whitelist_views
373 c.whitelist_views = whitelist_views
374 return self._get_template_context(c)
374 return self._get_template_context(c)
375
375
376 def ssh_enabled(self):
376 def ssh_enabled(self):
377 return self.request.registry.settings.get(
377 return self.request.registry.settings.get(
378 'ssh.generate_authorized_keyfile')
378 'ssh.generate_authorized_keyfile')
379
379
380 @LoginRequired()
380 @LoginRequired()
381 @HasPermissionAllDecorator('hg.admin')
381 @HasPermissionAllDecorator('hg.admin')
382 @view_config(
382 @view_config(
383 route_name='admin_permissions_ssh_keys', request_method='GET',
383 route_name='admin_permissions_ssh_keys', request_method='GET',
384 renderer='rhodecode:templates/admin/permissions/permissions.mako')
384 renderer='rhodecode:templates/admin/permissions/permissions.mako')
385 def ssh_keys(self):
385 def ssh_keys(self):
386 c = self.load_default_context()
386 c = self.load_default_context()
387 c.active = 'ssh_keys'
387 c.active = 'ssh_keys'
388 c.ssh_enabled = self.ssh_enabled()
388 c.ssh_enabled = self.ssh_enabled()
389 return self._get_template_context(c)
389 return self._get_template_context(c)
390
390
391 @LoginRequired()
391 @LoginRequired()
392 @HasPermissionAllDecorator('hg.admin')
392 @HasPermissionAllDecorator('hg.admin')
393 @view_config(
393 @view_config(
394 route_name='admin_permissions_ssh_keys_data', request_method='GET',
394 route_name='admin_permissions_ssh_keys_data', request_method='GET',
395 renderer='json_ext', xhr=True)
395 renderer='json_ext', xhr=True)
396 def ssh_keys_data(self):
396 def ssh_keys_data(self):
397 _ = self.request.translate
397 _ = self.request.translate
398 column_map = {
398 column_map = {
399 'fingerprint': 'ssh_key_fingerprint',
399 'fingerprint': 'ssh_key_fingerprint',
400 'username': User.username
400 'username': User.username
401 }
401 }
402 draw, start, limit = self._extract_chunk(self.request)
402 draw, start, limit = self._extract_chunk(self.request)
403 search_q, order_by, order_dir = self._extract_ordering(
403 search_q, order_by, order_dir = self._extract_ordering(
404 self.request, column_map=column_map)
404 self.request, column_map=column_map)
405
405
406 ssh_keys_data_total_count = UserSshKeys.query()\
406 ssh_keys_data_total_count = UserSshKeys.query()\
407 .count()
407 .count()
408
408
409 # json generate
409 # json generate
410 base_q = UserSshKeys.query().join(UserSshKeys.user)
410 base_q = UserSshKeys.query().join(UserSshKeys.user)
411
411
412 if search_q:
412 if search_q:
413 like_expression = u'%{}%'.format(safe_unicode(search_q))
413 like_expression = u'%{}%'.format(safe_unicode(search_q))
414 base_q = base_q.filter(or_(
414 base_q = base_q.filter(or_(
415 User.username.ilike(like_expression),
415 User.username.ilike(like_expression),
416 UserSshKeys.ssh_key_fingerprint.ilike(like_expression),
416 UserSshKeys.ssh_key_fingerprint.ilike(like_expression),
417 ))
417 ))
418
418
419 users_data_total_filtered_count = base_q.count()
419 users_data_total_filtered_count = base_q.count()
420
420
421 sort_col = self._get_order_col(order_by, UserSshKeys)
421 sort_col = self._get_order_col(order_by, UserSshKeys)
422 if sort_col:
422 if sort_col:
423 if order_dir == 'asc':
423 if order_dir == 'asc':
424 # handle null values properly to order by NULL last
424 # handle null values properly to order by NULL last
425 if order_by in ['created_on']:
425 if order_by in ['created_on']:
426 sort_col = coalesce(sort_col, datetime.date.max)
426 sort_col = coalesce(sort_col, datetime.date.max)
427 sort_col = sort_col.asc()
427 sort_col = sort_col.asc()
428 else:
428 else:
429 # handle null values properly to order by NULL last
429 # handle null values properly to order by NULL last
430 if order_by in ['created_on']:
430 if order_by in ['created_on']:
431 sort_col = coalesce(sort_col, datetime.date.min)
431 sort_col = coalesce(sort_col, datetime.date.min)
432 sort_col = sort_col.desc()
432 sort_col = sort_col.desc()
433
433
434 base_q = base_q.order_by(sort_col)
434 base_q = base_q.order_by(sort_col)
435 base_q = base_q.offset(start).limit(limit)
435 base_q = base_q.offset(start).limit(limit)
436
436
437 ssh_keys = base_q.all()
437 ssh_keys = base_q.all()
438
438
439 ssh_keys_data = []
439 ssh_keys_data = []
440 for ssh_key in ssh_keys:
440 for ssh_key in ssh_keys:
441 ssh_keys_data.append({
441 ssh_keys_data.append({
442 "username": h.gravatar_with_user(self.request, ssh_key.user.username),
442 "username": h.gravatar_with_user(self.request, ssh_key.user.username),
443 "fingerprint": ssh_key.ssh_key_fingerprint,
443 "fingerprint": ssh_key.ssh_key_fingerprint,
444 "description": ssh_key.description,
444 "description": ssh_key.description,
445 "created_on": h.format_date(ssh_key.created_on),
445 "created_on": h.format_date(ssh_key.created_on),
446 "accessed_on": h.format_date(ssh_key.accessed_on),
446 "action": h.link_to(
447 "action": h.link_to(
447 _('Edit'), h.route_path('edit_user_ssh_keys',
448 _('Edit'), h.route_path('edit_user_ssh_keys',
448 user_id=ssh_key.user.user_id))
449 user_id=ssh_key.user.user_id))
449 })
450 })
450
451
451 data = ({
452 data = ({
452 'draw': draw,
453 'draw': draw,
453 'data': ssh_keys_data,
454 'data': ssh_keys_data,
454 'recordsTotal': ssh_keys_data_total_count,
455 'recordsTotal': ssh_keys_data_total_count,
455 'recordsFiltered': users_data_total_filtered_count,
456 'recordsFiltered': users_data_total_filtered_count,
456 })
457 })
457
458
458 return data
459 return data
459
460
460 @LoginRequired()
461 @LoginRequired()
461 @HasPermissionAllDecorator('hg.admin')
462 @HasPermissionAllDecorator('hg.admin')
462 @CSRFRequired()
463 @CSRFRequired()
463 @view_config(
464 @view_config(
464 route_name='admin_permissions_ssh_keys_update', request_method='POST',
465 route_name='admin_permissions_ssh_keys_update', request_method='POST',
465 renderer='rhodecode:templates/admin/permissions/permissions.mako')
466 renderer='rhodecode:templates/admin/permissions/permissions.mako')
466 def ssh_keys_update(self):
467 def ssh_keys_update(self):
467 _ = self.request.translate
468 _ = self.request.translate
468 self.load_default_context()
469 self.load_default_context()
469
470
470 ssh_enabled = self.ssh_enabled()
471 ssh_enabled = self.ssh_enabled()
471 key_file = self.request.registry.settings.get(
472 key_file = self.request.registry.settings.get(
472 'ssh.authorized_keys_file_path')
473 'ssh.authorized_keys_file_path')
473 if ssh_enabled:
474 if ssh_enabled:
474 trigger(SshKeyFileChangeEvent(), self.request.registry)
475 trigger(SshKeyFileChangeEvent(), self.request.registry)
475 h.flash(_('Updated SSH keys file: {}').format(key_file),
476 h.flash(_('Updated SSH keys file: {}').format(key_file),
476 category='success')
477 category='success')
477 else:
478 else:
478 h.flash(_('SSH key support is disabled in .ini file'),
479 h.flash(_('SSH key support is disabled in .ini file'),
479 category='warning')
480 category='warning')
480
481
481 raise HTTPFound(h.route_path('admin_permissions_ssh_keys'))
482 raise HTTPFound(h.route_path('admin_permissions_ssh_keys'))
@@ -1,91 +1,93 b''
1
1
2 <div class="panel panel-default">
2 <div class="panel panel-default">
3 <div class="panel-heading">
3 <div class="panel-heading">
4 <h3 class="panel-title">${_('SSH Keys')} - <span id="ssh_keys_count"></span></h3>
4 <h3 class="panel-title">${_('SSH Keys')} - <span id="ssh_keys_count"></span></h3>
5
5
6 ${h.secure_form(h.route_path('admin_permissions_ssh_keys_update'), request=request)}
6 ${h.secure_form(h.route_path('admin_permissions_ssh_keys_update'), request=request)}
7 <button class="btn btn-link pull-right" type="submit">${_('Update SSH keys file')}</button>
7 <button class="btn btn-link pull-right" type="submit">${_('Update SSH keys file')}</button>
8 ${h.end_form()}
8 ${h.end_form()}
9 </div>
9 </div>
10 <div class="panel-body">
10 <div class="panel-body">
11 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
11 <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" placeholder="${_('quick filter...')}" value=""/>
12
12
13 <div id="repos_list_wrap">
13 <div id="repos_list_wrap">
14 <table id="ssh_keys_table" class="display"></table>
14 <table id="ssh_keys_table" class="display"></table>
15 </div>
15 </div>
16 </div>
16 </div>
17 </div>
17 </div>
18
18
19
19
20 <script type="text/javascript">
20 <script type="text/javascript">
21
21
22 $(document).ready(function() {
22 $(document).ready(function() {
23 var $sshKeyListTable = $('#ssh_keys_table');
23 var $sshKeyListTable = $('#ssh_keys_table');
24
24
25 var getDatatableCount = function(){
25 var getDatatableCount = function(){
26 var table = $sshKeyListTable.dataTable();
26 var table = $sshKeyListTable.dataTable();
27 var page = table.api().page.info();
27 var page = table.api().page.info();
28 var active = page.recordsDisplay;
28 var active = page.recordsDisplay;
29 var total = page.recordsTotal;
29 var total = page.recordsTotal;
30
30
31 var _text = _gettext("{0} out of {1} ssh keys").format(active, total);
31 var _text = _gettext("{0} out of {1} ssh keys").format(active, total);
32 $('#ssh_keys_count').text(_text);
32 $('#ssh_keys_count').text(_text);
33 };
33 };
34
34
35 // user list
35 // user list
36 $sshKeyListTable.DataTable({
36 $sshKeyListTable.DataTable({
37 processing: true,
37 processing: true,
38 serverSide: true,
38 serverSide: true,
39 ajax: "${h.route_path('admin_permissions_ssh_keys_data')}",
39 ajax: "${h.route_path('admin_permissions_ssh_keys_data')}",
40 dom: 'rtp',
40 dom: 'rtp',
41 pageLength: ${c.visual.admin_grid_items},
41 pageLength: ${c.visual.admin_grid_items},
42 order: [[ 0, "asc" ]],
42 order: [[ 0, "asc" ]],
43 columns: [
43 columns: [
44 { data: {"_": "username",
44 { data: {"_": "username",
45 "sort": "username"}, title: "${_('Username')}", className: "td-user" },
45 "sort": "username"}, title: "${_('Username')}", className: "td-user" },
46 { data: {"_": "fingerprint",
46 { data: {"_": "fingerprint",
47 "sort": "fingerprint"}, title: "${_('Fingerprint')}", className: "td-type" },
47 "sort": "fingerprint"}, title: "${_('Fingerprint')}", className: "td-type" },
48 { data: {"_": "description",
48 { data: {"_": "description",
49 "sort": "description"}, title: "${_('Description')}", className: "td-type" },
49 "sort": "description"}, title: "${_('Description')}", className: "td-type" },
50 { data: {"_": "created_on",
50 { data: {"_": "created_on",
51 "sort": "created_on"}, title: "${_('Created on')}", className: "td-time" },
51 "sort": "created_on"}, title: "${_('Created on')}", className: "td-time" },
52 { data: {"_": "accessed_on",
53 "sort": "accessed_on"}, title: "${_('Accessed on')}", className: "td-time" },
52 { data: {"_": "action",
54 { data: {"_": "action",
53 "sort": "action"}, title: "${_('Action')}", className: "td-action", orderable: false }
55 "sort": "action"}, title: "${_('Action')}", className: "td-action", orderable: false }
54 ],
56 ],
55 language: {
57 language: {
56 paginate: DEFAULT_GRID_PAGINATION,
58 paginate: DEFAULT_GRID_PAGINATION,
57 sProcessing: _gettext('loading...'),
59 sProcessing: _gettext('loading...'),
58 emptyTable: _gettext("No ssh keys available yet.")
60 emptyTable: _gettext("No ssh keys available yet.")
59 },
61 },
60
62
61 "createdRow": function ( row, data, index ) {
63 "createdRow": function ( row, data, index ) {
62 if (!data['active_raw']){
64 if (!data['active_raw']){
63 $(row).addClass('closed')
65 $(row).addClass('closed')
64 }
66 }
65 }
67 }
66 });
68 });
67
69
68 $sshKeyListTable.on('xhr.dt', function(e, settings, json, xhr){
70 $sshKeyListTable.on('xhr.dt', function(e, settings, json, xhr){
69 $sshKeyListTable.css('opacity', 1);
71 $sshKeyListTable.css('opacity', 1);
70 });
72 });
71
73
72 $sshKeyListTable.on('preXhr.dt', function(e, settings, data){
74 $sshKeyListTable.on('preXhr.dt', function(e, settings, data){
73 $sshKeyListTable.css('opacity', 0.3);
75 $sshKeyListTable.css('opacity', 0.3);
74 });
76 });
75
77
76 // refresh counters on draw
78 // refresh counters on draw
77 $sshKeyListTable.on('draw.dt', function(){
79 $sshKeyListTable.on('draw.dt', function(){
78 getDatatableCount();
80 getDatatableCount();
79 });
81 });
80
82
81 // filter
83 // filter
82 $('#q_filter').on('keyup',
84 $('#q_filter').on('keyup',
83 $.debounce(250, function() {
85 $.debounce(250, function() {
84 $sshKeyListTable.DataTable().search(
86 $sshKeyListTable.DataTable().search(
85 $('#q_filter').val()
87 $('#q_filter').val()
86 ).draw();
88 ).draw();
87 })
89 })
88 );
90 );
89
91
90 });
92 });
91 </script>
93 </script>
General Comments 0
You need to be logged in to leave comments. Login now