Show More
@@ -0,0 +1,112 b'' | |||
|
1 | ## -*- coding: utf-8 -*- | |
|
2 | <%inherit file="/base/base.mako"/> | |
|
3 | <%namespace name="base" file="/base/base.mako"/> | |
|
4 | ||
|
5 | <%def name="title()"> | |
|
6 | ${_('Admin audit log entry')} | |
|
7 | %if c.rhodecode_name: | |
|
8 | · ${h.branding(c.rhodecode_name)} | |
|
9 | %endif | |
|
10 | </%def> | |
|
11 | ||
|
12 | <%def name="breadcrumbs_links()"> | |
|
13 | ${_('Audit long entry')} ${c.audit_log_entry.entry_id} | |
|
14 | </%def> | |
|
15 | ||
|
16 | <%def name="menu_bar_nav()"> | |
|
17 | ${self.menu_items(active='admin')} | |
|
18 | </%def> | |
|
19 | <%def name="main()"> | |
|
20 | <div class="box"> | |
|
21 | <!-- box / title --> | |
|
22 | <div class="title"> | |
|
23 | ${self.breadcrumbs()} | |
|
24 | </div> | |
|
25 | <!-- end box / title --> | |
|
26 | <div class="table"> | |
|
27 | <div id="user_log"> | |
|
28 | <table class="rctable audit-log"> | |
|
29 | <tr> | |
|
30 | <td> | |
|
31 | ${_('User')}: | |
|
32 | </td> | |
|
33 | <td> | |
|
34 | %if c.audit_log_entry.user is not None: | |
|
35 | ${base.gravatar_with_user(c.audit_log_entry.user.email)} | |
|
36 | %else: | |
|
37 | ${c.audit_log_entry.username} | |
|
38 | %endif | |
|
39 | </td> | |
|
40 | </tr> | |
|
41 | <tr> | |
|
42 | <td> | |
|
43 | ${_('Date')}: | |
|
44 | </td> | |
|
45 | <td> | |
|
46 | ${h.format_date(c.audit_log_entry.action_date)} | |
|
47 | </td> | |
|
48 | </tr> | |
|
49 | <tr> | |
|
50 | <td> | |
|
51 | ${_('IP')}: | |
|
52 | </td> | |
|
53 | <td> | |
|
54 | ${c.audit_log_entry.user_ip} | |
|
55 | </td> | |
|
56 | </tr> | |
|
57 | ||
|
58 | <tr> | |
|
59 | <td> | |
|
60 | ${_('Action')}: | |
|
61 | </td> | |
|
62 | <td> | |
|
63 | % if c.audit_log_entry.version == c.audit_log_entry.VERSION_1: | |
|
64 | ${h.action_parser(l)[0]()} | |
|
65 | % else: | |
|
66 | ${h.literal(c.audit_log_entry.action)} | |
|
67 | % endif | |
|
68 | ||
|
69 | <div class="journal_action_params"> | |
|
70 | % if c.audit_log_entry.version == c.audit_log_entry.VERSION_1: | |
|
71 | ${h.literal(h.action_parser(l)[1]())} | |
|
72 | % endif | |
|
73 | </div> | |
|
74 | </td> | |
|
75 | </tr> | |
|
76 | <tr> | |
|
77 | <td> | |
|
78 | ${_('Action Data')}: | |
|
79 | </td> | |
|
80 | <td class="td-journalaction"> | |
|
81 | % if c.audit_log_entry.version == c.audit_log_entry.VERSION_2: | |
|
82 | <div> | |
|
83 | <pre>${h.json.dumps(c.audit_log_entry.action_data, indent=4, sort_keys=True)}</pre> | |
|
84 | </div> | |
|
85 | % else: | |
|
86 | <pre title="${_('data not available for v1 entries type')}">-</pre> | |
|
87 | % endif | |
|
88 | </td> | |
|
89 | </tr> | |
|
90 | <tr> | |
|
91 | <td> | |
|
92 | ${_('Repository')}: | |
|
93 | </td> | |
|
94 | <td class="td-journalaction"> | |
|
95 | %if c.audit_log_entry.repository is not None: | |
|
96 | ${h.link_to(c.audit_log_entry.repository.repo_name, h.route_path('repo_summary',repo_name=c.audit_log_entry.repository.repo_name))} | |
|
97 | %else: | |
|
98 | ${c.audit_log_entry.repository_name or '-'} | |
|
99 | %endif | |
|
100 | </td> | |
|
101 | </tr> | |
|
102 | ||
|
103 | </table> | |
|
104 | ||
|
105 | </div> | |
|
106 | </div> | |
|
107 | </div> | |
|
108 | ||
|
109 | <script> | |
|
110 | $('#j_filter').autoGrowInput(); | |
|
111 | </script> | |
|
112 | </%def> |
@@ -34,6 +34,10 b' def admin_routes(config):' | |||
|
34 | 34 | pattern='/audit_logs') |
|
35 | 35 | |
|
36 | 36 | config.add_route( |
|
37 | name='admin_audit_log_entry', | |
|
38 | pattern='/audit_logs/{audit_log_id}') | |
|
39 | ||
|
40 | config.add_route( | |
|
37 | 41 | name='pull_requests_global_0', # backward compat |
|
38 | 42 | pattern='/pull_requests/{pull_request_id:\d+}') |
|
39 | 43 | config.add_route( |
@@ -20,6 +20,7 b'' | |||
|
20 | 20 | |
|
21 | 21 | import logging |
|
22 | 22 | |
|
23 | from pyramid.httpexceptions import HTTPNotFound | |
|
23 | 24 | from pyramid.view import view_config |
|
24 | 25 | |
|
25 | 26 | from rhodecode.apps._base import BaseAppView |
@@ -70,3 +71,21 b' class AdminAuditLogsView(BaseAppView):' | |||
|
70 | 71 | c.audit_logs = Page(users_log, page=p, items_per_page=10, |
|
71 | 72 | url=url_generator) |
|
72 | 73 | return self._get_template_context(c) |
|
74 | ||
|
75 | @LoginRequired() | |
|
76 | @HasPermissionAllDecorator('hg.admin') | |
|
77 | @view_config( | |
|
78 | route_name='admin_audit_log_entry', request_method='GET', | |
|
79 | renderer='rhodecode:templates/admin/admin_audit_log_entry.mako') | |
|
80 | def admin_audit_log_entry(self): | |
|
81 | c = self.load_default_context() | |
|
82 | audit_log_id = self.request.matchdict['audit_log_id'] | |
|
83 | ||
|
84 | c.audit_log_entry = UserLog.query()\ | |
|
85 | .options(joinedload(UserLog.user))\ | |
|
86 | .options(joinedload(UserLog.repository))\ | |
|
87 | .filter(UserLog.user_log_id == audit_log_id).scalar() | |
|
88 | if not c.audit_log_entry: | |
|
89 | raise HTTPNotFound() | |
|
90 | ||
|
91 | return self._get_template_context(c) |
@@ -133,9 +133,6 b' def _store_log(action_name, action_data,' | |||
|
133 | 133 | |
|
134 | 134 | user_log.action_date = datetime.datetime.now() |
|
135 | 135 | |
|
136 | log.info('AUDIT: Logging action: `%s` by user:id:%s[%s] ip:%s', | |
|
137 | action_name, user_id, username, ip_address) | |
|
138 | ||
|
139 | 136 | return user_log |
|
140 | 137 | |
|
141 | 138 | |
@@ -239,19 +236,27 b' def store(action, user, action_data=None' | |||
|
239 | 236 | repository_id = getattr( |
|
240 | 237 | Repository.get_by_repo_name(repository_name), 'repo_id', None) |
|
241 | 238 | |
|
239 | action_name = safe_unicode(action) | |
|
240 | ip_address = safe_unicode(ip_addr) | |
|
241 | ||
|
242 | 242 | user_log = _store_log( |
|
243 |
action_name= |
|
|
243 | action_name=action_name, | |
|
244 | 244 | action_data=action_data or {}, |
|
245 | 245 | user_id=user_id, |
|
246 | 246 | username=username, |
|
247 | 247 | user_data=user_data or {}, |
|
248 |
ip_address= |
|
|
248 | ip_address=ip_address, | |
|
249 | 249 | repository_id=repository_id, |
|
250 | 250 | repository_name=repository_name |
|
251 | 251 | ) |
|
252 | ||
|
252 | 253 | sa_session.add(user_log) |
|
253 | 254 | if commit: |
|
254 | 255 | sa_session.commit() |
|
255 | 256 | |
|
257 | entry_id = user_log.entry_id or '' | |
|
258 | log.info('AUDIT[%s]: Logging action: `%s` by user:id:%s[%s] ip:%s', | |
|
259 | entry_id, action_name, user_id, username, ip_address) | |
|
260 | ||
|
256 | 261 | except Exception: |
|
257 | 262 | log.exception('AUDIT: failed to store audit log') |
@@ -1252,6 +1252,10 b' class UserLog(Base, BaseModel):' | |||
|
1252 | 1252 | 'action': self.action, |
|
1253 | 1253 | } |
|
1254 | 1254 | |
|
1255 | @hybrid_property | |
|
1256 | def entry_id(self): | |
|
1257 | return self.user_log_id | |
|
1258 | ||
|
1255 | 1259 | @property |
|
1256 | 1260 | def action_as_day(self): |
|
1257 | 1261 | return datetime.date(*self.action_date.timetuple()[:3]) |
@@ -250,6 +250,11 b' table.dataTable {' | |||
|
250 | 250 | } |
|
251 | 251 | } |
|
252 | 252 | } |
|
253 | .rctable.audit-log { | |
|
254 | td { | |
|
255 | vertical-align: top; | |
|
256 | } | |
|
257 | } | |
|
253 | 258 | |
|
254 | 259 | // TRUNCATING |
|
255 | 260 | // TODO: lisaq: should this possibly be moved out of tables.less? |
@@ -38,6 +38,7 b' function registerRCRoutes() {' | |||
|
38 | 38 | pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []); |
|
39 | 39 | pyroutes.register('admin_home', '/_admin', []); |
|
40 | 40 | pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []); |
|
41 | pyroutes.register('admin_audit_log_entry', '/_admin/audit_logs/%(audit_log_id)s', ['audit_log_id']); | |
|
41 | 42 | pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']); |
|
42 | 43 | pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']); |
|
43 | 44 | pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']); |
@@ -3,6 +3,7 b'' | |||
|
3 | 3 | %if c.audit_logs: |
|
4 | 4 | <table class="rctable admin_log"> |
|
5 | 5 | <tr> |
|
6 | <th>${_('Uid')}</th> | |
|
6 | 7 | <th>${_('Username')}</th> |
|
7 | 8 | <th>${_('Action')}</th> |
|
8 | 9 | <th>${_('Action Data')}</th> |
@@ -13,6 +14,9 b'' | |||
|
13 | 14 | |
|
14 | 15 | %for cnt,l in enumerate(c.audit_logs): |
|
15 | 16 | <tr class="parity${cnt%2}"> |
|
17 | <td class="td-col"> | |
|
18 | <a href="${h.route_path('admin_audit_log_entry', audit_log_id=l.entry_id)}">${l.entry_id}</a> | |
|
19 | </td> | |
|
16 | 20 | <td class="td-user"> |
|
17 | 21 | %if l.user is not None: |
|
18 | 22 | ${base.gravatar_with_user(l.user.email)} |
General Comments 0
You need to be logged in to leave comments.
Login now