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 | pattern='/audit_logs') |
|
34 | pattern='/audit_logs') | |
35 |
|
35 | |||
36 | config.add_route( |
|
36 | config.add_route( | |
|
37 | name='admin_audit_log_entry', | |||
|
38 | pattern='/audit_logs/{audit_log_id}') | |||
|
39 | ||||
|
40 | config.add_route( | |||
37 | name='pull_requests_global_0', # backward compat |
|
41 | name='pull_requests_global_0', # backward compat | |
38 | pattern='/pull_requests/{pull_request_id:\d+}') |
|
42 | pattern='/pull_requests/{pull_request_id:\d+}') | |
39 | config.add_route( |
|
43 | config.add_route( |
@@ -20,6 +20,7 b'' | |||||
20 |
|
20 | |||
21 | import logging |
|
21 | import logging | |
22 |
|
22 | |||
|
23 | from pyramid.httpexceptions import HTTPNotFound | |||
23 | from pyramid.view import view_config |
|
24 | from pyramid.view import view_config | |
24 |
|
25 | |||
25 | from rhodecode.apps._base import BaseAppView |
|
26 | from rhodecode.apps._base import BaseAppView | |
@@ -70,3 +71,21 b' class AdminAuditLogsView(BaseAppView):' | |||||
70 | c.audit_logs = Page(users_log, page=p, items_per_page=10, |
|
71 | c.audit_logs = Page(users_log, page=p, items_per_page=10, | |
71 | url=url_generator) |
|
72 | url=url_generator) | |
72 | return self._get_template_context(c) |
|
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 | user_log.action_date = datetime.datetime.now() |
|
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 | return user_log |
|
136 | return user_log | |
140 |
|
137 | |||
141 |
|
138 | |||
@@ -239,19 +236,27 b' def store(action, user, action_data=None' | |||||
239 | repository_id = getattr( |
|
236 | repository_id = getattr( | |
240 | Repository.get_by_repo_name(repository_name), 'repo_id', None) |
|
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 | user_log = _store_log( |
|
242 | user_log = _store_log( | |
243 |
action_name= |
|
243 | action_name=action_name, | |
244 | action_data=action_data or {}, |
|
244 | action_data=action_data or {}, | |
245 | user_id=user_id, |
|
245 | user_id=user_id, | |
246 | username=username, |
|
246 | username=username, | |
247 | user_data=user_data or {}, |
|
247 | user_data=user_data or {}, | |
248 |
ip_address= |
|
248 | ip_address=ip_address, | |
249 | repository_id=repository_id, |
|
249 | repository_id=repository_id, | |
250 | repository_name=repository_name |
|
250 | repository_name=repository_name | |
251 | ) |
|
251 | ) | |
|
252 | ||||
252 | sa_session.add(user_log) |
|
253 | sa_session.add(user_log) | |
253 | if commit: |
|
254 | if commit: | |
254 | sa_session.commit() |
|
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 | except Exception: |
|
261 | except Exception: | |
257 | log.exception('AUDIT: failed to store audit log') |
|
262 | log.exception('AUDIT: failed to store audit log') |
@@ -1252,6 +1252,10 b' class UserLog(Base, BaseModel):' | |||||
1252 | 'action': self.action, |
|
1252 | 'action': self.action, | |
1253 | } |
|
1253 | } | |
1254 |
|
1254 | |||
|
1255 | @hybrid_property | |||
|
1256 | def entry_id(self): | |||
|
1257 | return self.user_log_id | |||
|
1258 | ||||
1255 | @property |
|
1259 | @property | |
1256 | def action_as_day(self): |
|
1260 | def action_as_day(self): | |
1257 | return datetime.date(*self.action_date.timetuple()[:3]) |
|
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 | // TRUNCATING |
|
259 | // TRUNCATING | |
255 | // TODO: lisaq: should this possibly be moved out of tables.less? |
|
260 | // TODO: lisaq: should this possibly be moved out of tables.less? |
@@ -38,6 +38,7 b' function registerRCRoutes() {' | |||||
38 | pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []); |
|
38 | pyroutes.register('ops_error_test_legacy', '/_admin/error_test', []); | |
39 | pyroutes.register('admin_home', '/_admin', []); |
|
39 | pyroutes.register('admin_home', '/_admin', []); | |
40 | pyroutes.register('admin_audit_logs', '/_admin/audit_logs', []); |
|
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 | pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']); |
|
42 | pyroutes.register('pull_requests_global_0', '/_admin/pull_requests/%(pull_request_id)s', ['pull_request_id']); | |
42 | pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']); |
|
43 | pyroutes.register('pull_requests_global_1', '/_admin/pull-requests/%(pull_request_id)s', ['pull_request_id']); | |
43 | pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']); |
|
44 | pyroutes.register('pull_requests_global', '/_admin/pull-request/%(pull_request_id)s', ['pull_request_id']); |
@@ -3,6 +3,7 b'' | |||||
3 | %if c.audit_logs: |
|
3 | %if c.audit_logs: | |
4 | <table class="rctable admin_log"> |
|
4 | <table class="rctable admin_log"> | |
5 | <tr> |
|
5 | <tr> | |
|
6 | <th>${_('Uid')}</th> | |||
6 | <th>${_('Username')}</th> |
|
7 | <th>${_('Username')}</th> | |
7 | <th>${_('Action')}</th> |
|
8 | <th>${_('Action')}</th> | |
8 | <th>${_('Action Data')}</th> |
|
9 | <th>${_('Action Data')}</th> | |
@@ -13,6 +14,9 b'' | |||||
13 |
|
14 | |||
14 | %for cnt,l in enumerate(c.audit_logs): |
|
15 | %for cnt,l in enumerate(c.audit_logs): | |
15 | <tr class="parity${cnt%2}"> |
|
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 | <td class="td-user"> |
|
20 | <td class="td-user"> | |
17 | %if l.user is not None: |
|
21 | %if l.user is not None: | |
18 | ${base.gravatar_with_user(l.user.email)} |
|
22 | ${base.gravatar_with_user(l.user.email)} |
General Comments 0
You need to be logged in to leave comments.
Login now