source: trunk/plugins/dashboardreportsplugin/dashboardreports/patch/trac-query.7385.diff @ 391

Revision 391, 8.5 KB checked in by aculapov, 5 years ago (diff)
  • added patch for trac rev 7385
RevLine 
[391]1Index: trac/ticket/api.py
2===================================================================
3--- trac/ticket/api.py  (revision 7385)
4+++ trac/ticket/api.py  (working copy)
5@@ -183,6 +183,17 @@
6             valid_states.update(controller.get_all_status())
7         return sorted(valid_states)
8 
9+    def get_all_ticket_fields(self):
10+        """New method until full integration of the new fields."""
11+        fields = self.get_ticket_fields()
12+       
13+        # append the new ones
14+        fields.extend([{'name': 'time', 'type': 'date', 'label': 'Created'},
15+                       {'name': 'changetime', 'type': 'date',
16+                            'label': 'Modified'}])
17+       
18+        return fields
19+
20     def get_ticket_fields(self):
21         """Returns the list of fields available for tickets."""
22         from trac.ticket import model
23Index: trac/ticket/query.py
24===================================================================
25--- trac/ticket/query.py        (revision 7385)
26+++ trac/ticket/query.py        (working copy)
27@@ -43,6 +43,8 @@
28 from trac.wiki.api import IWikiSyntaxProvider, parse_args
29 from trac.wiki.macros import WikiMacroBase # TODO: should be moved in .api
30 
31+is_op = lambda x: x in ['!', '<', '>']
32+
33 class QuerySyntaxError(Exception):
34     """Exception raised when a ticket query cannot be parsed from a string."""
35 
36@@ -98,7 +100,7 @@
37             rows = []
38         if verbose and 'description' not in rows: # 0.10 compatibility
39             rows.append('description')
40-        self.fields = TicketSystem(self.env).get_ticket_fields()
41+        self.fields = TicketSystem(self.env).get_all_ticket_fields()
42         field_names = [f['name'] for f in self.fields]
43         self.cols = [c for c in cols or [] if c in field_names or
44                      c in ('id', 'time', 'changetime')]
45@@ -118,6 +120,7 @@
46             self.group = None
47 
48     def from_string(cls, env, string, **kw):
49+        global is_op
50         filters = string.split('&')
51         kw_strs = ['order', 'group', 'page', 'max']
52         kw_arys = ['rows']
53@@ -137,8 +140,8 @@
54             if field[-1] in ('~', '^', '$'):
55                 mode = field[-1]
56                 field = field[:-1]
57-            if field[-1] == '!':
58-                neg = '!'
59+            if is_op(field[-1]):
60+                neg = field[-1]
61                 field = field[:-1]
62             processed_values = []
63             for val in values.split('|'):
64@@ -368,6 +371,7 @@
65 
66     def get_sql(self, req=None, cached_ids=None):
67         """Return a (sql, params) tuple for the query."""
68+        global is_op
69         self.get_columns()
70 
71         enum_columns = ('resolution', 'priority', 'severity')
72@@ -413,6 +417,19 @@
73                        % (col, col, col))
74 
75         def get_constraint_sql(name, value, mode, neg):
76+            # strip the operator from the value
77+            value = value[len(mode) + is_op(neg):]
78+            # convert the value for non string fields
79+            current_field = {}
80+            for field in self.fields  :
81+                if field['name'] == name :
82+                    current_field = field
83+                    break
84+            if current_field.has_key('type') \
85+                and current_field['type'] == 'date' :
86+                    value = int(value)
87+           
88+            # add the table alias to the field name
89             if name not in custom_fields:
90                 name = 't.' + name
91             else:
92@@ -420,8 +437,8 @@
93             value = value[len(mode) + neg:]
94 
95             if mode == '':
96-                return ("COALESCE(%s,'')%s=%%s" % (name, neg and '!' or ''),
97-                        value)
98+                return ("COALESCE(%s,'')%s=%%s" % (name,
99+                                is_op(neg) and neg or ''), value)
100             if not value:
101                 return None
102             db = self.env.get_db_cnx()
103@@ -432,7 +449,7 @@
104                 value = value + '%'
105             elif mode == '$':
106                 value = '%' + value
107-            return ("COALESCE(%s,'') %s%s" % (name, neg and 'NOT ' or '',
108+            return ("COALESCE(%s,'') %s%s" % (name, neg == '!' and 'NOT ' or '',
109                                               db.like()),
110                     value)
111 
112@@ -441,18 +458,22 @@
113         for k, v in self.constraints.items():
114             if req:
115                 v = [val.replace('$USER', req.authname) for val in v]
116-            # Determine the match mode of the constraint (contains,
117-            # starts-with, negation, etc.)
118-            neg = v[0].startswith('!')
119+            # get the first character of the value, determine later if it's an
120+            # operation
121+            neg = ''
122             mode = ''
123-            if len(v[0]) > neg and v[0][neg] in ('~', '^', '$'):
124-                mode = v[0][neg]
125+            if v[0] != '' :
126+                neg = v[0][0]
127+            mode = ''
128+            if len(v[0]) > 1 and is_op(neg) and v[0][is_op(neg)] in ('~', '^', '$'):
129+                    mode = v[0][is_op(neg)]
130 
131             # Special case id ranges
132             if k == 'id':
133                 ranges = Ranges()
134                 for r in v:
135-                    r = r.replace('!', '')
136+                    for ch in ['!', '<', '>'] :
137+                        r = r.replace(ch, '')
138                     ranges.appendrange(r)
139                 ids = []
140                 id_clauses = []
141@@ -466,7 +487,7 @@
142                 if ids:
143                     id_clauses.append('id IN (%s)' % (','.join(ids)))
144                 if id_clauses:
145-                    clauses.append('%s(%s)' % (neg and 'NOT ' or '',
146+                    clauses.append('%s(%s)' % (neg == '!' and 'NOT ' or '',
147                                                ' OR '.join(id_clauses)))
148             # Special case for exact matches on multiple values
149             elif not mode and len(v) > 1:
150@@ -475,16 +496,16 @@
151                 else:
152                     col = k + '.value'
153                 clauses.append("COALESCE(%s,'') %sIN (%s)"
154-                               % (col, neg and 'NOT ' or '',
155+                               % (col, neg == '!' and 'NOT ' or '',
156                                   ','.join(['%s' for val in v])))
157-                args += [val[neg:] for val in v]
158+                args += [val[is_op(neg):] for val in v]
159             elif len(v) > 1:
160                 constraint_sql = filter(None,
161                                         [get_constraint_sql(k, val, mode, neg)
162                                          for val in v])
163                 if not constraint_sql:
164                     continue
165-                if neg:
166+                if is_op(neg):
167                     clauses.append("(" + " AND ".join(
168                         [item[0] for item in constraint_sql]) + ")")
169                 else:
170@@ -562,17 +583,21 @@
171 
172     def template_data(self, context, tickets, orig_list=None, orig_time=None,
173                       req=None):
174+        global is_op
175         constraints = {}
176         for k, v in self.constraints.items():
177             constraint = {'values': [], 'mode': ''}
178             for val in v:
179-                neg = val.startswith('!')
180-                if neg:
181+                neg = ''
182+                mode = ''
183+                if val != '' :
184+                    neg = val[0]
185+                if val != '' and is_op(neg):
186                     val = val[1:]
187                 mode = ''
188-                if val[:1] in ('~', '^', '$'):
189+                if val != '' and val[:1] in ('~', '^', '$'):
190                     mode, val = val[:1], val[1:]
191-                constraint['mode'] = (neg and '!' or '') + mode
192+                constraint['mode'] = (is_op(neg) and neg or '') + mode
193                 constraint['values'].append(val)
194             constraints[k] = constraint
195 
196@@ -605,7 +630,9 @@
197             {'name': _("begins with"), 'value': "^"},
198             {'name': _("ends with"), 'value': "$"},
199             {'name': _("is"), 'value': ""},
200-            {'name': _("is not"), 'value': "!"}
201+            {'name': _("is not"), 'value': "!"},
202+            {'name': _("greater"), 'value': ">"},
203+            {'name': _("lesser"), 'value': "<"}
204         ]
205         modes['select'] = [
206             {'name': _("is"), 'value': ""},
207@@ -811,7 +838,7 @@
208     def _get_constraints(self, req):
209         constraints = {}
210         ticket_fields = [f['name'] for f in
211-                         TicketSystem(self.env).get_ticket_fields()]
212+                         TicketSystem(self.env).get_all_ticket_fields()]
213         ticket_fields.append('id')
214 
215         # For clients without JavaScript, we remove constraints here if
Note: See TracBrowser for help on using the repository browser.