##// END OF EJS Templates
audit-logs: handle query syntax in whosh query parser....
marcink -
r2520:80b18ba8 stable
parent child Browse files
Show More
@@ -1,123 +1,126 b''
1 1 # -*- coding: utf-8 -*-
2 2
3 3 # Copyright (C) 2010-2018 RhodeCode GmbH
4 4 #
5 5 # This program is free software: you can redistribute it and/or modify
6 6 # it under the terms of the GNU Affero General Public License, version 3
7 7 # (only), as published by the Free Software Foundation.
8 8 #
9 9 # This program is distributed in the hope that it will be useful,
10 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 12 # GNU General Public License for more details.
13 13 #
14 14 # You should have received a copy of the GNU Affero General Public License
15 15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 16 #
17 17 # This program is dual-licensed. If you wish to learn more about the
18 18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20 20
21 21 import logging
22 22
23 23 from whoosh.qparser.default import QueryParser, query
24 24 from whoosh.qparser.dateparse import DateParserPlugin
25 25 from whoosh.fields import (TEXT, Schema, DATETIME)
26 26 from sqlalchemy.sql.expression import or_, and_, not_, func
27 27
28 28 from rhodecode.model.db import UserLog
29 29 from rhodecode.lib.utils2 import remove_prefix, remove_suffix, safe_unicode
30 30
31 31 # JOURNAL SCHEMA used only to generate queries in journal. We use whoosh
32 32 # querylang to build sql queries and filter journals
33 33 JOURNAL_SCHEMA = Schema(
34 34 username=TEXT(),
35 35 date=DATETIME(),
36 36 action=TEXT(),
37 37 repository=TEXT(),
38 38 ip=TEXT(),
39 39 )
40 40
41 41 log = logging.getLogger(__name__)
42 42
43 43
44 44 def user_log_filter(user_log, search_term):
45 45 """
46 46 Filters sqlalchemy user_log based on search_term with whoosh Query language
47 47 http://packages.python.org/Whoosh/querylang.html
48 48
49 49 :param user_log:
50 50 :param search_term:
51 51 """
52 52 log.debug('Initial search term: %r' % search_term)
53 53 qry = None
54 54 if search_term:
55 55 qp = QueryParser('repository', schema=JOURNAL_SCHEMA)
56 56 qp.add_plugin(DateParserPlugin())
57 57 qry = qp.parse(safe_unicode(search_term))
58 58 log.debug('Filtering using parsed query %r' % qry)
59 59
60 60 def wildcard_handler(col, wc_term):
61 61 if wc_term.startswith('*') and not wc_term.endswith('*'):
62 62 # postfix == endswith
63 63 wc_term = remove_prefix(wc_term, prefix='*')
64 64 return func.lower(col).endswith(wc_term)
65 65 elif wc_term.startswith('*') and wc_term.endswith('*'):
66 66 # wildcard == ilike
67 67 wc_term = remove_prefix(wc_term, prefix='*')
68 68 wc_term = remove_suffix(wc_term, suffix='*')
69 69 return func.lower(col).contains(wc_term)
70 70
71 71 def get_filterion(field, val, term):
72 72
73 73 if field == 'repository':
74 74 field = getattr(UserLog, 'repository_name')
75 75 elif field == 'ip':
76 76 field = getattr(UserLog, 'user_ip')
77 77 elif field == 'date':
78 78 field = getattr(UserLog, 'action_date')
79 79 elif field == 'username':
80 80 field = getattr(UserLog, 'username')
81 81 else:
82 82 field = getattr(UserLog, field)
83 83 log.debug('filter field: %s val=>%s' % (field, val))
84 84
85 85 # sql filtering
86 86 if isinstance(term, query.Wildcard):
87 87 return wildcard_handler(field, val)
88 88 elif isinstance(term, query.Prefix):
89 89 return func.lower(field).startswith(func.lower(val))
90 90 elif isinstance(term, query.DateRange):
91 91 return and_(field >= val[0], field <= val[1])
92 92 elif isinstance(term, query.Not):
93 93 return not_(field == val)
94 94 return func.lower(field) == func.lower(val)
95 95
96 96 if isinstance(qry, (query.And, query.Not, query.Term, query.Prefix,
97 97 query.Wildcard, query.DateRange)):
98 98 if not isinstance(qry, query.And):
99 99 qry = [qry]
100 100
101 101 for term in qry:
102 102 if isinstance(term, query.Not):
103 103 not_term = [z for z in term.leaves()][0]
104 104 field = not_term.fieldname
105 105 val = not_term.text
106 106 elif isinstance(term, query.DateRange):
107 107 field = term.fieldname
108 108 val = [term.startdate, term.enddate]
109 elif isinstance(term, query.NullQuery.__class__):
110 field = ''
111 val = ''
109 112 else:
110 113 field = term.fieldname
111 114 val = term.text
112
113 user_log = user_log.filter(get_filterion(field, val, term))
115 if field:
116 user_log = user_log.filter(get_filterion(field, val, term))
114 117 elif isinstance(qry, query.Or):
115 118 filters = []
116 119 for term in qry:
117 120 field = term.fieldname
118 121 val = (term.text if not isinstance(term, query.DateRange)
119 122 else [term.startdate, term.enddate])
120 123 filters.append(get_filterion(field, val, term))
121 124 user_log = user_log.filter(or_(*filters))
122 125
123 126 return user_log
General Comments 0
You need to be logged in to leave comments. Login now