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.
This commit is contained in:
Marcin Lulek 2019-10-03 13:32:59 +02:00
parent 340b56f1fa
commit f70f60713e
5 changed files with 45 additions and 7 deletions

View file

@ -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',

View file

@ -91,6 +91,9 @@ def route_path(name, params=None, **kwargs):
'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"

View file

@ -1197,6 +1197,29 @@ class UsersView(UserAppView):
c.filter_term = filter_term
return self._get_template_context(c)
@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(

View file

@ -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', []);

View file

@ -7,6 +7,7 @@
<h3 class="panel-title">${_('User Audit Logs')} -
${_ungettext('%s entry', '%s entries', c.audit_logs.item_count) % (c.audit_logs.item_count)}
</h3>
<a href="${h.route_path('edit_user_audit_logs_download', user_id=c.user.user_id)}" class="panel-edit">${_('Download as JSON')}</a>
</div>
<div class="panel-body">