Show More
@@ -25,18 +25,89 b'' | |||
|
25 | 25 | |
|
26 | 26 | import logging |
|
27 | 27 | |
|
28 | from pylons import request, tmpl_context as c | |
|
28 | from pylons import request, tmpl_context as c, url | |
|
29 | 29 | from sqlalchemy.orm import joinedload |
|
30 | 30 | from webhelpers.paginate import Page |
|
31 | from whoosh.qparser.default import QueryParser | |
|
32 | from whoosh import query | |
|
33 | from sqlalchemy.sql.expression import or_ | |
|
31 | 34 | |
|
32 | 35 | from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator |
|
33 | 36 | from rhodecode.lib.base import BaseController, render |
|
34 | from rhodecode.model.db import UserLog | |
|
35 | from rhodecode.lib.utils2 import safe_int | |
|
37 | from rhodecode.model.db import UserLog, User | |
|
38 | from rhodecode.lib.utils2 import safe_int, remove_prefix | |
|
39 | from rhodecode.lib.indexers import JOURNAL_SCHEMA | |
|
40 | ||
|
36 | 41 | |
|
37 | 42 | log = logging.getLogger(__name__) |
|
38 | 43 | |
|
39 | 44 | |
|
45 | def _filter(user_log, search_term): | |
|
46 | """ | |
|
47 | Filters sqlalchemy user_log based on search_term with whoosh Query language | |
|
48 | http://packages.python.org/Whoosh/querylang.html | |
|
49 | ||
|
50 | :param user_log: | |
|
51 | :param search_term: | |
|
52 | """ | |
|
53 | qry = None | |
|
54 | if search_term: | |
|
55 | qp = QueryParser('repository', schema=JOURNAL_SCHEMA) | |
|
56 | qry = qp.parse(unicode(search_term)) | |
|
57 | log.debug('Filtering using query %r' % qry) | |
|
58 | ||
|
59 | def get_filterion(field, val, term): | |
|
60 | if field == 'repository': | |
|
61 | field = getattr(UserLog, 'repository_name') | |
|
62 | elif field == 'ip': | |
|
63 | field = getattr(UserLog, 'user_ip') | |
|
64 | elif field == 'date': | |
|
65 | field = getattr(UserLog, 'action_date') | |
|
66 | elif field == 'username': | |
|
67 | ##special case for username | |
|
68 | if isinstance(term, query.Wildcard): | |
|
69 | #only support wildcards with * at beggining | |
|
70 | val = remove_prefix(val, prefix='*') | |
|
71 | return getattr(UserLog, 'user_id').in_( | |
|
72 | [x.user_id for x in | |
|
73 | User.query().filter(User.username.endswith(val))]) | |
|
74 | elif isinstance(term, query.Prefix): | |
|
75 | return getattr(UserLog, 'user_id').in_( | |
|
76 | [x.user_id for x in | |
|
77 | User.query().filter(User.username.startswith(val))]) | |
|
78 | # term == exact match, case insensitive | |
|
79 | field = getattr(UserLog, 'user') | |
|
80 | val = User.get_by_username(val, case_insensitive=True) | |
|
81 | ||
|
82 | else: | |
|
83 | field = getattr(UserLog, field) | |
|
84 | ||
|
85 | #sql filtering | |
|
86 | if isinstance(term, query.Wildcard): | |
|
87 | return field.endsswith(val) | |
|
88 | elif isinstance(term, query.Prefix): | |
|
89 | return field.startswith(val) | |
|
90 | return field == val | |
|
91 | ||
|
92 | if isinstance(qry, (query.And, query.Term, query.Prefix, query.Wildcard)): | |
|
93 | if not isinstance(qry, query.And): | |
|
94 | qry = [qry] | |
|
95 | for term in qry: | |
|
96 | field = term.fieldname | |
|
97 | val = term.text | |
|
98 | user_log = user_log.filter(get_filterion(field, val, term)) | |
|
99 | elif isinstance(qry, query.Or): | |
|
100 | filters = [] | |
|
101 | for term in qry: | |
|
102 | field = term.fieldname | |
|
103 | val = term.text | |
|
104 | if isinstance(term, query.Term): | |
|
105 | filters.append(get_filterion(field, val, term)) | |
|
106 | user_log = user_log.filter(or_(*filters)) | |
|
107 | ||
|
108 | return user_log | |
|
109 | ||
|
110 | ||
|
40 | 111 | class AdminController(BaseController): |
|
41 | 112 | |
|
42 | 113 | @LoginRequired() |
@@ -45,14 +116,26 b' class AdminController(BaseController):' | |||
|
45 | 116 | |
|
46 | 117 | @HasPermissionAllDecorator('hg.admin') |
|
47 | 118 | def index(self): |
|
48 | ||
|
49 | 119 | users_log = UserLog.query()\ |
|
50 | 120 | .options(joinedload(UserLog.user))\ |
|
51 |
.options(joinedload(UserLog.repository)) |
|
|
52 | .order_by(UserLog.action_date.desc()) | |
|
121 | .options(joinedload(UserLog.repository)) | |
|
122 | ||
|
123 | #FILTERING | |
|
124 | c.search_term = request.GET.get('filter') | |
|
125 | try: | |
|
126 | users_log = _filter(users_log, c.search_term) | |
|
127 | except: | |
|
128 | # we want this to crash for now | |
|
129 | raise | |
|
130 | ||
|
131 | users_log = users_log.order_by(UserLog.action_date.desc()) | |
|
53 | 132 | |
|
54 | 133 | p = safe_int(request.params.get('page', 1), 1) |
|
55 | c.users_log = Page(users_log, page=p, items_per_page=10) | |
|
134 | ||
|
135 | def url_generator(**kw): | |
|
136 | return url.current(filter=c.search_term, **kw) | |
|
137 | ||
|
138 | c.users_log = Page(users_log, page=p, items_per_page=10, url=url_generator) | |
|
56 | 139 | c.log_data = render('admin/admin_log.html') |
|
57 | 140 | |
|
58 | 141 | if request.environ.get('HTTP_X_PARTIAL_XHR'): |
@@ -35,7 +35,7 b' from string import strip' | |||
|
35 | 35 | from shutil import rmtree |
|
36 | 36 | |
|
37 | 37 | from whoosh.analysis import RegexTokenizer, LowercaseFilter, StopFilter |
|
38 | from whoosh.fields import TEXT, ID, STORED, NUMERIC, BOOLEAN, Schema, FieldType | |
|
38 | from whoosh.fields import TEXT, ID, STORED, NUMERIC, BOOLEAN, Schema, FieldType, DATETIME | |
|
39 | 39 | from whoosh.index import create_in, open_dir |
|
40 | 40 | from whoosh.formats import Characters |
|
41 | 41 | from whoosh.highlight import highlight, HtmlFormatter, ContextFragmenter |
@@ -89,6 +89,15 b' CHGSETS_SCHEMA = Schema(' | |||
|
89 | 89 | |
|
90 | 90 | CHGSET_IDX_NAME = 'CHGSET_INDEX' |
|
91 | 91 | |
|
92 | # used only to generate queries in journal | |
|
93 | JOURNAL_SCHEMA = Schema( | |
|
94 | username=TEXT(), | |
|
95 | date=DATETIME(), | |
|
96 | action=TEXT(), | |
|
97 | repository=TEXT(), | |
|
98 | ip=TEXT(), | |
|
99 | ) | |
|
100 | ||
|
92 | 101 | |
|
93 | 102 | class MakeIndex(BasePasterCommand): |
|
94 | 103 |
@@ -6,7 +6,12 b'' | |||
|
6 | 6 | </%def> |
|
7 | 7 | |
|
8 | 8 | <%def name="breadcrumbs_links()"> |
|
9 | <form id="filter_form"> | |
|
10 | <input class="q_filter_box" id="q_filter" size="15" type="text" name="filter" value="${c.search_term or _('quick filter...')}"/> | |
|
11 | <input type='submit' value="${_('filter')}" class="ui-btn"/> | |
|
9 | 12 | ${_('Admin journal')} |
|
13 | </form> | |
|
14 | ${h.end_form()} | |
|
10 | 15 | </%def> |
|
11 | 16 | |
|
12 | 17 | <%def name="page_nav()"> |
@@ -25,4 +30,16 b'' | |||
|
25 | 30 | </div> |
|
26 | 31 | </div> |
|
27 | 32 | </div> |
|
33 | ||
|
34 | <script> | |
|
35 | YUE.on('q_filter','click',function(){ | |
|
36 | YUD.get('q_filter').value = ''; | |
|
37 | }); | |
|
38 | YUE.on('filter_form','submit',function(e){ | |
|
39 | YUE.preventDefault(e) | |
|
40 | var val = YUD.get('q_filter').value; | |
|
41 | window.location = "${url.current(filter='__FILTER__')}".replace('__FILTER__',val); | |
|
42 | }); | |
|
43 | </script> | |
|
28 | 44 | </%def> |
|
45 |
General Comments 0
You need to be logged in to leave comments.
Login now