##// 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 import logging
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 from sqlalchemy.orm import joinedload
29 from sqlalchemy.orm import joinedload
30 from webhelpers.paginate import Page
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 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
35 from rhodecode.lib.auth import LoginRequired, HasPermissionAllDecorator
33 from rhodecode.lib.base import BaseController, render
36 from rhodecode.lib.base import BaseController, render
34 from rhodecode.model.db import UserLog
37 from rhodecode.model.db import UserLog, User
35 from rhodecode.lib.utils2 import safe_int
38 from rhodecode.lib.utils2 import safe_int, remove_prefix
39 from rhodecode.lib.indexers import JOURNAL_SCHEMA
40
36
41
37 log = logging.getLogger(__name__)
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 class AdminController(BaseController):
111 class AdminController(BaseController):
41
112
42 @LoginRequired()
113 @LoginRequired()
@@ -45,14 +116,26 b' class AdminController(BaseController):'
45
116
46 @HasPermissionAllDecorator('hg.admin')
117 @HasPermissionAllDecorator('hg.admin')
47 def index(self):
118 def index(self):
48
49 users_log = UserLog.query()\
119 users_log = UserLog.query()\
50 .options(joinedload(UserLog.user))\
120 .options(joinedload(UserLog.user))\
51 .options(joinedload(UserLog.repository))\
121 .options(joinedload(UserLog.repository))
52 .order_by(UserLog.action_date.desc())
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 p = safe_int(request.params.get('page', 1), 1)
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 c.log_data = render('admin/admin_log.html')
139 c.log_data = render('admin/admin_log.html')
57
140
58 if request.environ.get('HTTP_X_PARTIAL_XHR'):
141 if request.environ.get('HTTP_X_PARTIAL_XHR'):
@@ -35,7 +35,7 b' from string import strip'
35 from shutil import rmtree
35 from shutil import rmtree
36
36
37 from whoosh.analysis import RegexTokenizer, LowercaseFilter, StopFilter
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 from whoosh.index import create_in, open_dir
39 from whoosh.index import create_in, open_dir
40 from whoosh.formats import Characters
40 from whoosh.formats import Characters
41 from whoosh.highlight import highlight, HtmlFormatter, ContextFragmenter
41 from whoosh.highlight import highlight, HtmlFormatter, ContextFragmenter
@@ -89,6 +89,15 b' CHGSETS_SCHEMA = Schema('
89
89
90 CHGSET_IDX_NAME = 'CHGSET_INDEX'
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 class MakeIndex(BasePasterCommand):
102 class MakeIndex(BasePasterCommand):
94
103
@@ -6,7 +6,12 b''
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
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 ${_('Admin journal')}
12 ${_('Admin journal')}
13 </form>
14 ${h.end_form()}
10 </%def>
15 </%def>
11
16
12 <%def name="page_nav()">
17 <%def name="page_nav()">
@@ -25,4 +30,16 b''
25 </div>
30 </div>
26 </div>
31 </div>
27 </div>
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 </%def>
44 </%def>
45
General Comments 0
You need to be logged in to leave comments. Login now