diff --git a/rhodecode/apps/admin/__init__.py b/rhodecode/apps/admin/__init__.py --- a/rhodecode/apps/admin/__init__.py +++ b/rhodecode/apps/admin/__init__.py @@ -378,6 +378,10 @@ def admin_routes(config): name='edit_user_audit_logs', pattern='/users/{user_id:\d+}/edit/audit', user_route=True) + config.add_route( + name='edit_user_audit_logs_download', + pattern='/users/{user_id:\d+}/edit/audit/download', user_route=True) + # user caches config.add_route( name='edit_user_caches', diff --git a/rhodecode/apps/admin/tests/test_admin_users.py b/rhodecode/apps/admin/tests/test_admin_users.py --- a/rhodecode/apps/admin/tests/test_admin_users.py +++ b/rhodecode/apps/admin/tests/test_admin_users.py @@ -91,6 +91,9 @@ def route_path(name, params=None, **kwar 'edit_user_audit_logs': ADMIN_PREFIX + '/users/{user_id}/edit/audit', + 'edit_user_audit_logs_download': + ADMIN_PREFIX + '/users/{user_id}/edit/audit/download', + }[name].format(**kwargs) if params: @@ -318,7 +321,6 @@ class TestAdminUsersView(TestController) route_path('edit_user_emails', user_id=user_id)) response.mustcontain(no=['example@rhodecode.com']) - def test_create(self, request, xhr_header): self.log_user() username = 'newtestuser' @@ -531,8 +533,7 @@ class TestAdminUsersView(TestController) params={'csrf_token': self.csrf_token}) msg = 'user "%s" still owns 1 repositories and cannot be removed. ' \ - 'Switch owners or remove those repositories:%s' % (username, - obj_name) + 'Switch owners or remove those repositories:%s' % (username, obj_name) assert_session_flash(response, msg) fixture.destroy_repo(obj_name) @@ -583,8 +584,7 @@ class TestAdminUsersView(TestController) params={'csrf_token': self.csrf_token}) msg = 'user "%s" still owns 1 repository groups and cannot be removed. ' \ - 'Switch owners or remove those repository groups:%s' % (username, - obj_name) + 'Switch owners or remove those repository groups:%s' % (username, obj_name) assert_session_flash(response, msg) fixture.destroy_repo_group(obj_name) @@ -635,8 +635,7 @@ class TestAdminUsersView(TestController) params={'csrf_token': self.csrf_token}) msg = 'user "%s" still owns 1 user groups and cannot be removed. ' \ - 'Switch owners or remove those user groups:%s' % (username, - obj_name) + 'Switch owners or remove those user groups:%s' % (username, obj_name) assert_session_flash(response, msg) fixture.destroy_user_group(obj_name) @@ -779,3 +778,13 @@ class TestAdminUsersView(TestController) user = self.log_user() self.app.get( route_path('edit_user_audit_logs', user_id=user['user_id'])) + + def test_audit_log_page_download(self): + user = self.log_user() + user_id = user['user_id'] + response = self.app.get( + route_path('edit_user_audit_logs_download', user_id=user_id)) + + assert response.content_disposition == \ + 'attachment; filename=user_{}_audit_logs.json'.format(user_id) + assert response.content_type == "application/json" diff --git a/rhodecode/apps/admin/views/users.py b/rhodecode/apps/admin/views/users.py --- a/rhodecode/apps/admin/views/users.py +++ b/rhodecode/apps/admin/views/users.py @@ -1200,6 +1200,29 @@ class UsersView(UserAppView): @LoginRequired() @HasPermissionAllDecorator('hg.admin') @view_config( + route_name='edit_user_audit_logs_download', request_method='GET', + renderer='string') + def user_audit_logs_download(self): + _ = self.request.translate + c = self.load_default_context() + c.user = self.db_user + + user_log = UserModel().get_user_log(c.user, filter_term=None) + + audit_log_data = {} + for entry in user_log: + audit_log_data[entry.user_log_id] = entry.get_dict() + + response = Response(json.dumps(audit_log_data, indent=4)) + response.content_disposition = str( + 'attachment; filename=%s' % 'user_{}_audit_logs.json'.format(c.user.user_id)) + response.content_type = 'application/json' + + return response + + @LoginRequired() + @HasPermissionAllDecorator('hg.admin') + @view_config( route_name='edit_user_perms_summary', request_method='GET', renderer='rhodecode:templates/admin/users/user_edit.mako') def user_perms_summary(self): diff --git a/rhodecode/public/js/rhodecode/routes.js b/rhodecode/public/js/rhodecode/routes.js --- a/rhodecode/public/js/rhodecode/routes.js +++ b/rhodecode/public/js/rhodecode/routes.js @@ -121,6 +121,7 @@ function registerRCRoutes() { pyroutes.register('edit_user_groups_management', '/_admin/users/%(user_id)s/edit/groups_management', ['user_id']); pyroutes.register('edit_user_groups_management_updates', '/_admin/users/%(user_id)s/edit/edit_user_groups_management/updates', ['user_id']); pyroutes.register('edit_user_audit_logs', '/_admin/users/%(user_id)s/edit/audit', ['user_id']); + pyroutes.register('edit_user_audit_logs_download', '/_admin/users/%(user_id)s/edit/audit/download', ['user_id']); pyroutes.register('edit_user_caches', '/_admin/users/%(user_id)s/edit/caches', ['user_id']); pyroutes.register('edit_user_caches_update', '/_admin/users/%(user_id)s/edit/caches/update', ['user_id']); pyroutes.register('user_groups', '/_admin/user_groups', []); diff --git a/rhodecode/templates/admin/users/user_edit_audit.mako b/rhodecode/templates/admin/users/user_edit_audit.mako --- a/rhodecode/templates/admin/users/user_edit_audit.mako +++ b/rhodecode/templates/admin/users/user_edit_audit.mako @@ -7,6 +7,7 @@

${_('User Audit Logs')} - ${_ungettext('%s entry', '%s entries', c.audit_logs.item_count) % (c.audit_logs.item_count)}

+ ${_('Download as JSON')}