##// END OF EJS Templates
Implemented filtering of admin journal based on Whoosh Query language...
marcink -
r3062:a08624dd beta
parent child Browse files
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