##// END OF EJS Templates
audit-logs: don't use old style parser for new audit logs.
marcink -
r1834:b6177862 default
parent child Browse files
Show More
@@ -1,316 +1,349 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 import logging
21 import logging
22
22
23 from pylons import url
23 from pylons import url
24 from pylons.i18n.translation import _
24 from pylons.i18n.translation import _
25 from webhelpers.html.builder import literal
25 from webhelpers.html.builder import literal
26 from webhelpers.html.tags import link_to
26 from webhelpers.html.tags import link_to
27
27
28 from rhodecode.lib.utils2 import AttributeDict
28 from rhodecode.lib.utils2 import AttributeDict
29 from rhodecode.lib.vcs.backends.base import BaseCommit
29 from rhodecode.lib.vcs.backends.base import BaseCommit
30 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
30 from rhodecode.lib.vcs.exceptions import CommitDoesNotExistError
31
31
32
32
33 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
34
34
35
35
36 def action_parser(user_log, feed=False, parse_cs=False):
36 def action_parser(user_log, feed=False, parse_cs=False):
37 """
37 """
38 This helper will action_map the specified string action into translated
38 This helper will action_map the specified string action into translated
39 fancy names with icons and links
39 fancy names with icons and links
40
40
41 :param user_log: user log instance
41 :param user_log: user log instance
42 :param feed: use output for feeds (no html and fancy icons)
42 :param feed: use output for feeds (no html and fancy icons)
43 :param parse_cs: parse Changesets into VCS instances
43 :param parse_cs: parse Changesets into VCS instances
44 """
44 """
45 ap = ActionParser(user_log, feed=False, parse_commits=False)
45 if user_log.version == 'v2':
46 return ap.callbacks()
46 ap = AuditLogParser(user_log)
47 return ap.callbacks()
48 else:
49 # old style
50 ap = ActionParser(user_log, feed=False, parse_commits=False)
51 return ap.callbacks()
47
52
48
53
49 class ActionParser(object):
54 class ActionParser(object):
50
55
51 commits_limit = 3 # display this amount always
56 commits_limit = 3 # display this amount always
52 commits_top_limit = 50 # show up to this amount of commits hidden
57 commits_top_limit = 50 # show up to this amount of commits hidden
53
58
54 def __init__(self, user_log, feed=False, parse_commits=False):
59 def __init__(self, user_log, feed=False, parse_commits=False):
55 self.user_log = user_log
60 self.user_log = user_log
56 self.feed = feed
61 self.feed = feed
57 self.parse_commits = parse_commits
62 self.parse_commits = parse_commits
58
63
59 self.action = user_log.action
64 self.action = user_log.action
60 self.action_params = ' '
65 self.action_params = ' '
61 x = self.action.split(':', 1)
66 x = self.action.split(':', 1)
62 if len(x) > 1:
67 if len(x) > 1:
63 self.action, self.action_params = x
68 self.action, self.action_params = x
64
69
65 def callbacks(self):
70 def callbacks(self):
66 action_str = self.action_map.get(self.action, self.action)
71 action_str = self.action_map.get(self.action, self.action)
67 if self.feed:
72 if self.feed:
68 action = action_str[0].replace('[', '').replace(']', '')
73 action = action_str[0].replace('[', '').replace(']', '')
69 else:
74 else:
70 action = action_str[0]\
75 action = action_str[0]\
71 .replace('[', '<span class="journal_highlight">')\
76 .replace('[', '<span class="journal_highlight">')\
72 .replace(']', '</span>')
77 .replace(']', '</span>')
73
78
74 action_params_func = _no_params_func
79 action_params_func = _no_params_func
75 if callable(action_str[1]):
80 if callable(action_str[1]):
76 action_params_func = action_str[1]
81 action_params_func = action_str[1]
77
82
78 # returned callbacks we need to call to get
83 # returned callbacks we need to call to get
79 return [
84 return [
80 lambda: literal(action), action_params_func,
85 lambda: literal(action), action_params_func,
81 self.action_parser_icon]
86 self.action_parser_icon]
82
87
83 @property
88 @property
84 def action_map(self):
89 def action_map(self):
85
90
86 # action : translated str, callback(extractor), icon
91 # action : translated str, callback(extractor), icon
87 action_map = {
92 action_map = {
88 'user_deleted_repo': (
93 'user_deleted_repo': (
89 _('[deleted] repository'),
94 _('[deleted] repository'),
90 None, 'icon-trash'),
95 None, 'icon-trash'),
91 'user_created_repo': (
96 'user_created_repo': (
92 _('[created] repository'),
97 _('[created] repository'),
93 None, 'icon-plus icon-plus-colored'),
98 None, 'icon-plus icon-plus-colored'),
94 'user_created_fork': (
99 'user_created_fork': (
95 _('[created] repository as fork'),
100 _('[created] repository as fork'),
96 None, 'icon-code-fork'),
101 None, 'icon-code-fork'),
97 'user_forked_repo': (
102 'user_forked_repo': (
98 _('[forked] repository'),
103 _('[forked] repository'),
99 self.get_fork_name, 'icon-code-fork'),
104 self.get_fork_name, 'icon-code-fork'),
100 'user_updated_repo': (
105 'user_updated_repo': (
101 _('[updated] repository'),
106 _('[updated] repository'),
102 None, 'icon-pencil icon-pencil-colored'),
107 None, 'icon-pencil icon-pencil-colored'),
103 'user_downloaded_archive': (
108 'user_downloaded_archive': (
104 _('[downloaded] archive from repository'),
109 _('[downloaded] archive from repository'),
105 self.get_archive_name, 'icon-download-alt'),
110 self.get_archive_name, 'icon-download-alt'),
106 'admin_deleted_repo': (
111 'admin_deleted_repo': (
107 _('[delete] repository'),
112 _('[delete] repository'),
108 None, 'icon-trash'),
113 None, 'icon-trash'),
109 'admin_created_repo': (
114 'admin_created_repo': (
110 _('[created] repository'),
115 _('[created] repository'),
111 None, 'icon-plus icon-plus-colored'),
116 None, 'icon-plus icon-plus-colored'),
112 'admin_forked_repo': (
117 'admin_forked_repo': (
113 _('[forked] repository'),
118 _('[forked] repository'),
114 None, 'icon-code-fork icon-fork-colored'),
119 None, 'icon-code-fork icon-fork-colored'),
115 'admin_updated_repo': (
120 'admin_updated_repo': (
116 _('[updated] repository'),
121 _('[updated] repository'),
117 None, 'icon-pencil icon-pencil-colored'),
122 None, 'icon-pencil icon-pencil-colored'),
118 'admin_created_user': (
123 'admin_created_user': (
119 _('[created] user'),
124 _('[created] user'),
120 self.get_user_name, 'icon-user icon-user-colored'),
125 self.get_user_name, 'icon-user icon-user-colored'),
121 'admin_updated_user': (
126 'admin_updated_user': (
122 _('[updated] user'),
127 _('[updated] user'),
123 self.get_user_name, 'icon-user icon-user-colored'),
128 self.get_user_name, 'icon-user icon-user-colored'),
124 'admin_created_users_group': (
129 'admin_created_users_group': (
125 _('[created] user group'),
130 _('[created] user group'),
126 self.get_users_group, 'icon-pencil icon-pencil-colored'),
131 self.get_users_group, 'icon-pencil icon-pencil-colored'),
127 'admin_updated_users_group': (
132 'admin_updated_users_group': (
128 _('[updated] user group'),
133 _('[updated] user group'),
129 self.get_users_group, 'icon-pencil icon-pencil-colored'),
134 self.get_users_group, 'icon-pencil icon-pencil-colored'),
130 'user_commented_revision': (
135 'user_commented_revision': (
131 _('[commented] on commit in repository'),
136 _('[commented] on commit in repository'),
132 self.get_cs_links, 'icon-comment icon-comment-colored'),
137 self.get_cs_links, 'icon-comment icon-comment-colored'),
133 'user_commented_pull_request': (
138 'user_commented_pull_request': (
134 _('[commented] on pull request for'),
139 _('[commented] on pull request for'),
135 self.get_pull_request, 'icon-comment icon-comment-colored'),
140 self.get_pull_request, 'icon-comment icon-comment-colored'),
136 'user_closed_pull_request': (
141 'user_closed_pull_request': (
137 _('[closed] pull request for'),
142 _('[closed] pull request for'),
138 self.get_pull_request, 'icon-check'),
143 self.get_pull_request, 'icon-check'),
139 'user_merged_pull_request': (
144 'user_merged_pull_request': (
140 _('[merged] pull request for'),
145 _('[merged] pull request for'),
141 self.get_pull_request, 'icon-check'),
146 self.get_pull_request, 'icon-check'),
142 'push': (
147 'push': (
143 _('[pushed] into'),
148 _('[pushed] into'),
144 self.get_cs_links, 'icon-arrow-up'),
149 self.get_cs_links, 'icon-arrow-up'),
145 'push_local': (
150 'push_local': (
146 _('[committed via RhodeCode] into repository'),
151 _('[committed via RhodeCode] into repository'),
147 self.get_cs_links, 'icon-pencil icon-pencil-colored'),
152 self.get_cs_links, 'icon-pencil icon-pencil-colored'),
148 'push_remote': (
153 'push_remote': (
149 _('[pulled from remote] into repository'),
154 _('[pulled from remote] into repository'),
150 self.get_cs_links, 'icon-arrow-up'),
155 self.get_cs_links, 'icon-arrow-up'),
151 'pull': (
156 'pull': (
152 _('[pulled] from'),
157 _('[pulled] from'),
153 None, 'icon-arrow-down'),
158 None, 'icon-arrow-down'),
154 'started_following_repo': (
159 'started_following_repo': (
155 _('[started following] repository'),
160 _('[started following] repository'),
156 None, 'icon-heart icon-heart-colored'),
161 None, 'icon-heart icon-heart-colored'),
157 'stopped_following_repo': (
162 'stopped_following_repo': (
158 _('[stopped following] repository'),
163 _('[stopped following] repository'),
159 None, 'icon-heart-empty icon-heart-colored'),
164 None, 'icon-heart-empty icon-heart-colored'),
160 }
165 }
161 return action_map
166 return action_map
162
167
163 def get_fork_name(self):
168 def get_fork_name(self):
164 from rhodecode.lib import helpers as h
169 from rhodecode.lib import helpers as h
165 repo_name = self.action_params
170 repo_name = self.action_params
166 _url = h.route_path('repo_summary', repo_name=repo_name)
171 _url = h.route_path('repo_summary', repo_name=repo_name)
167 return _('fork name %s') % link_to(self.action_params, _url)
172 return _('fork name %s') % link_to(self.action_params, _url)
168
173
169 def get_user_name(self):
174 def get_user_name(self):
170 user_name = self.action_params
175 user_name = self.action_params
171 return user_name
176 return user_name
172
177
173 def get_users_group(self):
178 def get_users_group(self):
174 group_name = self.action_params
179 group_name = self.action_params
175 return group_name
180 return group_name
176
181
177 def get_pull_request(self):
182 def get_pull_request(self):
178 from rhodecode.lib import helpers as h
183 from rhodecode.lib import helpers as h
179 pull_request_id = self.action_params
184 pull_request_id = self.action_params
180 if self.is_deleted():
185 if self.is_deleted():
181 repo_name = self.user_log.repository_name
186 repo_name = self.user_log.repository_name
182 else:
187 else:
183 repo_name = self.user_log.repository.repo_name
188 repo_name = self.user_log.repository.repo_name
184 return link_to(
189 return link_to(
185 _('Pull request #%s') % pull_request_id,
190 _('Pull request #%s') % pull_request_id,
186 h.route_path('pullrequest_show', repo_name=repo_name,
191 h.route_path('pullrequest_show', repo_name=repo_name,
187 pull_request_id=pull_request_id))
192 pull_request_id=pull_request_id))
188
193
189 def get_archive_name(self):
194 def get_archive_name(self):
190 archive_name = self.action_params
195 archive_name = self.action_params
191 return archive_name
196 return archive_name
192
197
193 def action_parser_icon(self):
198 def action_parser_icon(self):
194 tmpl = """<i class="%s" alt="%s"></i>"""
199 tmpl = """<i class="%s" alt="%s"></i>"""
195 ico = self.action_map.get(self.action, ['', '', ''])[2]
200 ico = self.action_map.get(self.action, ['', '', ''])[2]
196 return literal(tmpl % (ico, self.action))
201 return literal(tmpl % (ico, self.action))
197
202
198 def get_cs_links(self):
203 def get_cs_links(self):
199 if self.is_deleted():
204 if self.is_deleted():
200 return self.action_params
205 return self.action_params
201
206
202 repo_name = self.user_log.repository.repo_name
207 repo_name = self.user_log.repository.repo_name
203 commit_ids = self.action_params.split(',')
208 commit_ids = self.action_params.split(',')
204 commits = self.get_commits(commit_ids)
209 commits = self.get_commits(commit_ids)
205
210
206 link_generator = (
211 link_generator = (
207 self.lnk(commit, repo_name)
212 self.lnk(commit, repo_name)
208 for commit in commits[:self.commits_limit])
213 for commit in commits[:self.commits_limit])
209 commit_links = [" " + ', '.join(link_generator)]
214 commit_links = [" " + ', '.join(link_generator)]
210 _op1, _name1 = _get_op(commit_ids[0])
215 _op1, _name1 = _get_op(commit_ids[0])
211 _op2, _name2 = _get_op(commit_ids[-1])
216 _op2, _name2 = _get_op(commit_ids[-1])
212
217
213 commit_id_range = '%s...%s' % (_name1, _name2)
218 commit_id_range = '%s...%s' % (_name1, _name2)
214
219
215 compare_view = (
220 compare_view = (
216 ' <div class="compare_view tooltip" title="%s">'
221 ' <div class="compare_view tooltip" title="%s">'
217 '<a href="%s">%s</a> </div>' % (
222 '<a href="%s">%s</a> </div>' % (
218 _('Show all combined commits %s->%s') % (
223 _('Show all combined commits %s->%s') % (
219 commit_ids[0][:12], commit_ids[-1][:12]
224 commit_ids[0][:12], commit_ids[-1][:12]
220 ),
225 ),
221 url('changeset_home', repo_name=repo_name,
226 url('changeset_home', repo_name=repo_name,
222 revision=commit_id_range), _('compare view')
227 revision=commit_id_range), _('compare view')
223 )
228 )
224 )
229 )
225
230
226 if len(commit_ids) > self.commits_limit:
231 if len(commit_ids) > self.commits_limit:
227 more_count = len(commit_ids) - self.commits_limit
232 more_count = len(commit_ids) - self.commits_limit
228 commit_links.append(
233 commit_links.append(
229 _(' and %(num)s more commits') % {'num': more_count}
234 _(' and %(num)s more commits') % {'num': more_count}
230 )
235 )
231
236
232 if len(commits) > 1:
237 if len(commits) > 1:
233 commit_links.append(compare_view)
238 commit_links.append(compare_view)
234 return ''.join(commit_links)
239 return ''.join(commit_links)
235
240
236 def get_commits(self, commit_ids):
241 def get_commits(self, commit_ids):
237 commits = []
242 commits = []
238 if not filter(lambda v: v != '', commit_ids):
243 if not filter(lambda v: v != '', commit_ids):
239 return commits
244 return commits
240
245
241 repo = None
246 repo = None
242 if self.parse_commits:
247 if self.parse_commits:
243 repo = self.user_log.repository.scm_instance()
248 repo = self.user_log.repository.scm_instance()
244
249
245 for commit_id in commit_ids[:self.commits_top_limit]:
250 for commit_id in commit_ids[:self.commits_top_limit]:
246 _op, _name = _get_op(commit_id)
251 _op, _name = _get_op(commit_id)
247
252
248 # we want parsed commits, or new log store format is bad
253 # we want parsed commits, or new log store format is bad
249 if self.parse_commits:
254 if self.parse_commits:
250 try:
255 try:
251 commit = repo.get_commit(commit_id=commit_id)
256 commit = repo.get_commit(commit_id=commit_id)
252 commits.append(commit)
257 commits.append(commit)
253 except CommitDoesNotExistError:
258 except CommitDoesNotExistError:
254 log.error(
259 log.error(
255 'cannot find commit id %s in this repository',
260 'cannot find commit id %s in this repository',
256 commit_id)
261 commit_id)
257 commits.append(commit_id)
262 commits.append(commit_id)
258 continue
263 continue
259 else:
264 else:
260 fake_commit = AttributeDict({
265 fake_commit = AttributeDict({
261 'short_id': commit_id[:12],
266 'short_id': commit_id[:12],
262 'raw_id': commit_id,
267 'raw_id': commit_id,
263 'message': '',
268 'message': '',
264 'op': _op,
269 'op': _op,
265 'ref_name': _name
270 'ref_name': _name
266 })
271 })
267 commits.append(fake_commit)
272 commits.append(fake_commit)
268
273
269 return commits
274 return commits
270
275
271 def lnk(self, commit_or_id, repo_name):
276 def lnk(self, commit_or_id, repo_name):
272 from rhodecode.lib.helpers import tooltip
277 from rhodecode.lib.helpers import tooltip
273
278
274 if isinstance(commit_or_id, (BaseCommit, AttributeDict)):
279 if isinstance(commit_or_id, (BaseCommit, AttributeDict)):
275 lazy_cs = True
280 lazy_cs = True
276 if (getattr(commit_or_id, 'op', None) and
281 if (getattr(commit_or_id, 'op', None) and
277 getattr(commit_or_id, 'ref_name', None)):
282 getattr(commit_or_id, 'ref_name', None)):
278 lazy_cs = False
283 lazy_cs = False
279 lbl = '?'
284 lbl = '?'
280 if commit_or_id.op == 'delete_branch':
285 if commit_or_id.op == 'delete_branch':
281 lbl = '%s' % _('Deleted branch: %s') % commit_or_id.ref_name
286 lbl = '%s' % _('Deleted branch: %s') % commit_or_id.ref_name
282 title = ''
287 title = ''
283 elif commit_or_id.op == 'tag':
288 elif commit_or_id.op == 'tag':
284 lbl = '%s' % _('Created tag: %s') % commit_or_id.ref_name
289 lbl = '%s' % _('Created tag: %s') % commit_or_id.ref_name
285 title = ''
290 title = ''
286 _url = '#'
291 _url = '#'
287
292
288 else:
293 else:
289 lbl = '%s' % (commit_or_id.short_id[:8])
294 lbl = '%s' % (commit_or_id.short_id[:8])
290 _url = url('changeset_home', repo_name=repo_name,
295 _url = url('changeset_home', repo_name=repo_name,
291 revision=commit_or_id.raw_id)
296 revision=commit_or_id.raw_id)
292 title = tooltip(commit_or_id.message)
297 title = tooltip(commit_or_id.message)
293 else:
298 else:
294 # commit cannot be found/striped/removed etc.
299 # commit cannot be found/striped/removed etc.
295 lbl = ('%s' % commit_or_id)[:12]
300 lbl = ('%s' % commit_or_id)[:12]
296 _url = '#'
301 _url = '#'
297 title = _('Commit not found')
302 title = _('Commit not found')
298 if self.parse_commits:
303 if self.parse_commits:
299 return link_to(lbl, _url, title=title, class_='tooltip')
304 return link_to(lbl, _url, title=title, class_='tooltip')
300 return link_to(lbl, _url, raw_id=commit_or_id.raw_id, repo_name=repo_name,
305 return link_to(lbl, _url, raw_id=commit_or_id.raw_id, repo_name=repo_name,
301 class_='lazy-cs' if lazy_cs else '')
306 class_='lazy-cs' if lazy_cs else '')
302
307
303 def is_deleted(self):
308 def is_deleted(self):
304 return self.user_log.repository is None
309 return self.user_log.repository is None
305
310
306
311
312 class AuditLogParser(object):
313 def __init__(self, audit_log_entry):
314 self.audit_log_entry = audit_log_entry
315
316 def get_icon(self, action):
317 return 'icon-rhodecode'
318
319 def callbacks(self):
320 action_str = self.audit_log_entry.action
321
322 def callback():
323 # returned callbacks we need to call to get
324 action = action_str \
325 .replace('[', '<span class="journal_highlight">')\
326 .replace(']', '</span>')
327 return literal(action)
328
329 def icon():
330 tmpl = """<i class="%s" alt="%s"></i>"""
331 ico = self.get_icon(action_str)
332 return literal(tmpl % (ico, action_str))
333
334 action_params_func = _no_params_func
335
336 return [
337 callback, action_params_func, icon]
338
339
307 def _no_params_func():
340 def _no_params_func():
308 return ""
341 return ""
309
342
310
343
311 def _get_op(commit_id):
344 def _get_op(commit_id):
312 _op = None
345 _op = None
313 _name = commit_id
346 _name = commit_id
314 if len(commit_id.split('=>')) == 2:
347 if len(commit_id.split('=>')) == 2:
315 _op, _name = commit_id.split('=>')
348 _op, _name = commit_id.split('=>')
316 return _op, _name
349 return _op, _name
General Comments 0
You need to be logged in to leave comments. Login now