# HG changeset patch # User Marcin Lulek # Date 2019-10-03 11:32:59 # Node ID 36c4e03858e039476e70ee64f074fe484595b8e1 # Parent f86c0abcf44393b371ca2fbe0efb35eb1932c23f audit-logs: expose download user audit logs as JSON file. Primarly in larger organizations often this needs to be performed for some employees. Before we delegated users to API or DB fetch. 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')}