r1389: Forgot to add the template diff
[bugdar.git] / search.php
1 <?php
2 /*=====================================================================*\
3 || ###################################################################
4 || # Bugdar [#]version[#]
5 || # Copyright 2002-[#]year[#] Blue Static
6 || #
7 || # This program is free software; you can redistribute it and/or modify
8 || # it under the terms of the GNU General Public License as published by
9 || # the Free Software Foundation; version [#]gpl[#] of the License.
10 || #
11 || # This program is distributed in the hope that it will be useful, but
12 || # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 || # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 || # more details.
15 || #
16 || # You should have received a copy of the GNU General Public License along
17 || # with this program; if not, write to the Free Software Foundation, Inc.,
18 || # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 || ###################################################################
20 \*=====================================================================*/
21
22 $fetchtemplates = array(
23 'search',
24 'search_results',
25 'trackerhome_bits',
26 'pagenav_bit',
27 'pagenav'
28 );
29
30 define('SVN', '$Id$');
31
32 $focus['search'] = 'focus';
33
34 require_once('./global.php');
35 require_once('./includes/functions_product.php');
36 require_once('./includes/class_pagination.php');
37
38 if (!can_perform('cansearch'))
39 {
40 $message->error_permission();
41 }
42
43 define('MODE_ANY', ($bugsys->in['mode'] == 1));
44 define('MODE_ALL', ($bugsys->in['mode'] == 2));
45 define('MODE_RAW', ($bugsys->in['mode'] == 3));
46
47 $var = $db->query_first("SHOW VARIABLES LIKE 'ft_min_word_len'");
48 define('SEARCH_WORD_MIN', $var['Value']);
49
50 $show['search'] = true;
51
52 // ###################################################################
53
54 if (empty($_REQUEST['do']))
55 {
56 $_REQUEST['do'] = 'search';
57 }
58
59 // ###################################################################
60
61 if ($_REQUEST['do'] == 'process')
62 {
63 // -------------------------------------------------------------------
64 // handle keywords
65 if ($bugsys->in['summary'])
66 {
67 $keywords = preg_split('#\s+#', $bugsys->in['summary']);
68
69 // TODO - need to have some str to bool conversions
70
71 foreach ($keywords AS $word)
72 {
73 if (strlen($word) < SEARCH_WORD_MIN)
74 {
75 continue;
76 }
77
78 if (MODE_ALL)
79 {
80 $querybuild['text'] .= " +$word";
81 }
82 else
83 {
84 $querybuild['text'] .= " $word";
85 }
86
87 if (!preg_match('#-(.+?)#', trim($word)))
88 {
89 $hilight .= " $word";
90 }
91 }
92
93 $hilight = preg_replace('#[^0-9a-zA-Z_ ]#', '', $hilight);
94 $hilight = trim($hilight);
95 $hilight = preg_replace('#\s#', '+', $hilight);
96
97 $temp = trim($querybuild['text']);
98
99 if (MODE_ALL OR MODE_RAW)
100 {
101 $bool_flag = ' IN BOOLEAN MODE';
102 }
103
104 $querybuild['text'] = "AND\n\t\t\t(\n\t\t\t\tMATCH (bug.summary) AGAINST ('$temp'$bool_flag)\n\t\t\t\tOR MATCH (comment.comment) AGAINST ('$temp'$bool_flag)\n\t\t\t)";
105 }
106
107 // -------------------------------------------------------------------
108 // reporter
109 if ($bugsys->in['reporter'])
110 {
111 // force email or name?? make a distinction?
112 // more elegant way to do this? probably
113 $user = $db->query_first("SELECT * FROM " . TABLE_PREFIX . "user WHERE email LIKE '%" . str_replace('%', '\%', $bugsys->input_escape('reporter')) . "' OR displayname LIKE '%" . str_replace('%', '\%', $bugsys->input_escape('reporter')) . "%'");
114 if ($user['userid'])
115 {
116 $querybuild['reporter'] = "AND bug.userid = $user[userid] OR comment.userid = $user[userid]";
117 }
118 }
119
120 // -------------------------------------------------------------------
121 // product/component/version stuff
122 if (is_array($bugsys->in['pcv_select']))
123 {
124 foreach ($bugsys->in['pcv_select'] AS $pcv)
125 {
126 $pcv = parse_pcv_select($pcv, true);
127 $products[] = $pcv['product'];
128 $components[] = $pcv['component'];
129 $versions[] = $pcv['version'];
130 }
131 $querybuild['pcv'] = "AND bug.product IN (" . implode(',', $products) . ") AND bug.component IN (" . implode(',', $components) . ") AND bug.version IN (" . implode(',', $versions) . ")";
132 }
133
134 // -------------------------------------------------------------------
135 // severity, priority, status, resolution, assignedto
136
137 // severity
138 if ($bugsys->in['severity'])
139 {
140 $bugsys->input_clean('severity', TYPE_UINT);
141 $querybuild['severity'] = "AND bug.severity IN (" . implode(',', $bugsys->in['severity']) . ")";
142 }
143
144 // priority
145 if ($bugsys->in['priority'])
146 {
147 $bugsys->input_clean('priority', TYPE_UINT);
148 $querybuild['priority'] = "AND bug.priority IN (" . implode(',', $bugsys->in['priority']) . ")";
149 }
150
151 // status
152 if ($bugsys->in['status'])
153 {
154 $bugsys->input_clean('status', TYPE_UINT);
155 $querybuild['status'] = "AND bug.status IN (" . implode(',', $bugsys->in['status']) . ")";
156 }
157
158 // resolution
159 if ($bugsys->in['resolution'])
160 {
161 $bugsys->input_clean('resolution', TYPE_UINT);
162 $querybuild['resolution'] = "AND bug.resolution IN (" . implode(',', $bugsys->in['resolution']) . ")";
163 }
164
165 // assignment
166 if ($bugsys->in['assignedto'])
167 {
168 $bugsys->input_clean('assignedto', TYPE_UINT);
169 $querybuild['assignedto'] = "AND bug.assignedto IN (" . implode(',', $bugsys->in['assignedto']) . ")";
170 }
171
172 // -------------------------------------------------------------------
173 // date
174 if ($bugsys->in['date'])
175 {
176 // now - (seconds/day * number of days)
177 $dateline = time() - ($bugsys->input_clean('date', TYPE_INT) * 3600);
178 $querybuild['date'] = "AND bug.dateline >= $dateline";
179 }
180
181 // -------------------------------------------------------------------
182 // favoritess
183 if (($bugsys->in['favorite'] == 1 OR $bugsys->in['favorite'] == 0) AND $bugsys->userinfo['userid'])
184 {
185 $favorites = $db->query("SELECT * FROM " . TABLE_PREFIX . "favorite WHERE userid = " . $bugsys->userinfo['userid']);
186 while ($favorite = $db->fetch_array($favorites))
187 {
188 $ids[] = $favorite['bugid'];
189 }
190 $querybuild['favorites'] = "AND bug.bugid " . ($bugsys->in['favorite'] == 0 ? "NOT IN" : "IN") . " (" . implode(', ', $ids) . ")";
191 }
192
193 // -------------------------------------------------------------------
194 // sort by
195 $sortby = array('bugid', 'severity', 'priority', 'status', 'resolution', 'dateline');
196 $orderby = array('ASC', 'DESC');
197 $bugsys->in['orderby'] = strtoupper($bugsys->in['orderby']);
198 if (in_array($bugsys->in['sortby'], $sortby) AND in_array($bugsys->in['orderby'], $orderby))
199 {
200 $sortclause = "ORDER BY " . $bugsys->in['sortby'] . ' ' . $bugsys->in['orderby'];
201 }
202 else if ($bugsys->in['sortby'] == 'relevance')
203 {
204 $sortclause = '';
205 }
206 else
207 {
208 $sortclause = '';
209 }
210
211 // -------------------------------------------------------------------
212 // custom fields
213 $fields_fetch = $bugsys->db->query("
214 SELECT bugfield.*
215 FROM " . TABLE_PREFIX . "bugfield AS bugfield
216 LEFT JOIN " . TABLE_PREFIX . "bugfieldpermission AS permission
217 ON (bugfield.fieldid = permission.fieldid)
218 WHERE permission.mask <> 0
219 AND permission.usergroupid = {$bugsys->userinfo['usergroupid']}
220 AND bugfield.cansearch = 1"
221 );
222 while ($field = $bugsys->db->fetch_array($fields_fetch))
223 {
224 if (!empty($bugsys->in["field$field[fieldid]"]) OR ($field['type'] == 'select_single' AND isset($bugsys->in["field$field[fieldid]"])))
225 {
226 if ($field['type'] == 'input_checkbox')
227 {
228 $querybuild[] = "AND bugfieldvalue.field$field[fieldid] = " . (($bugsys->in["field$field[fieldid]"] == 1) ? 0 : 1);
229 }
230 else if ($field['type'] == 'input_text')
231 {
232 $querybuild[] = "AND bugfieldvalue.field$field[fieldid] LIKE '%" . $bugsys->in["field$field[fieldid]"] . "%'";
233 }
234 else if ($field['type'] == 'select_single' AND $bugsys->in["field$field[fieldid]"] != -1)
235 {
236 $temp = unserialize($field['selects']);
237 $querybuild[] = "AND bugfieldvalue.field$field[fieldid] = '" . trim($temp[ intval($bugsys->in["field$field[fieldid]"]) ]) . "'";
238 }
239 }
240 }
241
242 // -------------------------------------------------------------------
243 // have to search something
244 if (sizeof($querybuild) < 1)
245 {
246 $message->error(sprintf(_('You have to enter some criteria to search for. Note that words less than %1$d characters are ignored by the search engine (and some other very common words, too).'), SEARCH_WORD_MIN));
247 }
248
249 // -------------------------------------------------------------------
250 // do the search
251 $query = "
252 SELECT bug.*, comment.commentid
253 FROM " . TABLE_PREFIX . "bug AS bug
254 LEFT JOIN " . TABLE_PREFIX . "comment AS comment
255 ON (bug.bugid = comment.bugid)
256 LEFT JOIN " . TABLE_PREFIX . "bugvaluefill AS bugfieldvalue
257 ON (bug.bugid = bugfieldvalue.bugid)
258 WHERE bug.bugid <> 0
259 AND bug.product IN (#<'ONBITS:VIEW'>#)
260 AND (!bug.hidden OR (bug.hidden AND bug.product IN (#<'ONBITS:HIDDEN'>#))" . (can_perform('canviewownhidden') ? " OR (bug.hidden AND bug.userid = " . $bugsys->userinfo['userid'] . " AND bug.product IN (#<'ONBITS:OWNHIDDEN'>#))" : "") . ")
261 " . implode("\n\t\t", $querybuild) . "
262 GROUP BY bug.bugid
263 $sortclause";
264
265 $runquery = str_replace(array("#<'ONBITS:VIEW'>#", "#<'ONBITS:HIDDEN'>#", "#<'ONBITS:OWNHIDDEN'>#"), array(fetch_on_bits('canviewbugs'), fetch_on_bits('canviewhidden'), fetch_on_bits('canviewonhidden')), $query);
266
267 $search = $db->query($runquery);
268
269 $numrows = $db->num_rows($search);
270
271 if ($numrows < 1)
272 {
273 $message->error(_('No search results were returned that matched your criteria.'));
274 }
275
276 while ($result = $db->fetch_array($search))
277 {
278 $ids[] = $result['bugid'];
279 $results[] = $result;
280 }
281
282 if ($bugsys->userinfo['userid'])
283 {
284 $db->query("
285 REPLACE INTO " . TABLE_PREFIX . "search
286 (userid, dateline, query, ids, orderby, hilight, resultcount)
287 VALUES
288 (" . $bugsys->userinfo['userid'] . ",
289 " . TIMENOW . ", '" . $bugsys->escape($query) . "',
290 '" . implode(',', $ids) . "', '" . $bugsys->escape($sortclause) . "',
291 '" . $bugsys->escape($hilight) . "',
292 " . sizeof($results) . "
293 )"
294 );
295 }
296
297 $justprocess = true;
298 $search = array('ids' => implode(',', $ids), 'orderby' => $sortclause);
299
300 $_REQUEST['do'] = 'results';
301 }
302
303 // ###################################################################
304
305 if ($_REQUEST['do'] == 'search')
306 {
307 if ($bugsys->userinfo['userid'] AND !$bugsys->in['new'])
308 {
309 if ($cachedsearch = $db->query_first("SELECT * FROM " . TABLE_PREFIX . "search WHERE userid = " . $bugsys->userinfo['userid']))
310 {
311 $_REQUEST['do'] = 'results';
312 }
313 else
314 {
315 $newsearch = true;
316 }
317 }
318 else
319 {
320 $newsearch = true;
321 }
322
323 if ($newsearch)
324 {
325 if (!is_array($bugsys->datastore['product']))
326 {
327 $message->error(_('No products are setup, therefore there can be no bugs and thus search cannot function.'));
328 }
329
330 if (!is_array($bugsys->datastore['version']))
331 {
332 $message->error(_('No versions have been added underneath your product(s), there can be no bugs and thus search cannot function.'));
333 }
334
335 $pcv_select = construct_pcv_select();
336
337 // -------------------------------------------------------------------
338 // custom fields
339 $fields = construct_custom_fields(null, true);
340 $i = 0;
341 foreach ($fields AS $field)
342 {
343 if ($i % 2 == 0)
344 {
345 $customfields['left'] .= $field;
346 }
347 else
348 {
349 $customfields['right'] .= $field;
350 }
351 $i++;
352 }
353
354 // -------------------------------------------------------------------
355 // built-in fields
356 $select['severity'] = construct_datastore_select('severity', 'severity', 'severityid');
357 $select['priority'] = construct_datastore_select('priority', 'priority', 'priorityid');
358 $select['status'] = construct_datastore_select('status', 'status', 'statusid');
359 $select['resolution'] = construct_datastore_select('resolution', 'resolution', 'resolutionid');
360
361 $select['dev'] = '';
362 foreach ($bugsys->datastore['assignto'] AS $dev)
363 {
364 $value = $dev['userid'];
365 $label = construct_user_display($dev, false);
366 eval('$select[dev] .= "' . $template->fetch('selectoption') . '";');
367 }
368
369 eval('$template->flush("' . $template->fetch('search') . '");');
370 }
371 }
372
373 // ###################################################################
374
375 if ($_REQUEST['do'] == 'results')
376 {
377 $show['cached'] = false;
378 if ($bugsys->userinfo['userid'] AND !$justprocess)
379 {
380 $search = $cachedsearch;
381 if ($search['dateline'] < TIMENOW - 900 OR $bugsys->in['rerun'])
382 {
383 $research = $db->query(str_replace(array("#<'ONBITS:VIEW'>#", "#<'ONBITS:HIDDEN'>#", "#<'ONBITS:OWNHIDDEN'>#"), array(fetch_on_bits('canviewbugs'), fetch_on_bits('canviewhidden'), fetch_on_bits('canviewownhidden')), $search['query']));
384 while ($bug = $db->fetch_array($research))
385 {
386 $ids[] = $bug['bugid'];
387 $results[] = $bug;
388 }
389 $search['ids'] = implode(',', $ids);
390 $db->query("UPDATE " . TABLE_PREFIX . "search SET ids = '" . implode(',', $ids) . "', dateline = " . TIMENOW . ", resultcount = " . sizeof($results) . " WHERE userid = " . $bugsys->userinfo['userid']);
391 }
392 $show['cached'] = true;
393 $hilight = $search['hilight'];
394 }
395
396 $pagination = new Pagination('p', 'pp');
397 $pagination->total = $search['resultcount'];
398 $pagination->split_pages();
399
400 if (!$search['ids'])
401 {
402 $message->error(_('No bugs matched your search criteria. Please <a href="search.php?new=1">try again</a> with different search requirements.'));
403 }
404
405 $search = $db->query("SELECT * FROM " . TABLE_PREFIX . "bug WHERE bugid IN ($search[ids]) $search[orderby] LIMIT " . $pagination->fetch_limit($pagination->page - 1) . ", " . $pagination->perpage);
406 while ($bug = $db->fetch_array($search))
407 {
408 $funct->exec_swap_bg($stylevar['alt_color'], '');
409 $bug['bgcolor'] = ($bugsys->userinfo['showcolors'] ? $bugsys->datastore['status']["$bug[status]"]['color'] : $funct->bgcolour);
410 $bug['hiddendisplay'] = ((can_perform('canviewhidden', $bug['product']) OR (can_perform('canviewownhidden') AND $bug['userid'] == $bugsys->userinfo['userid'])) ? false : true);
411 $bug['product'] = $bugsys->datastore['product']["$bug[product]"]['title'];
412 $bug['version'] = $bugsys->datastore['version']["$bug[version]"]['version'];
413 $bug['status'] = $bugsys->datastore['status']["$bug[status]"]['status'];
414 $bug['resolution'] = $bugsys->datastore['resolution']["$bug[resolution]"]['resolution'];
415 $bug['priority'] = $bugsys->datastore['priority']["$bug[priority]"]['priority'];
416 $bug['severity'] = $bugsys->datastore['severity']["$bug[severity]"]['severity'];
417 $bug['lastposttime'] = ($bug['hiddendisplay'] ? $bug['hiddenlastposttime'] : $bug['lastposttime']);
418 $bug['lastpost'] = ($bug['hiddendisplay'] ? $bug['hiddenlastpostbyname'] : $bug['lastpostbyname']);
419 $bug['lastposttime'] = $datef->format($bugsys->options['dateformat'], $bug['lastposttime']);
420 $bug['urladd'] = "&amp;hilight=$hilight";
421 eval('$bugs .= "' . $template->fetch('trackerhome_bits') . '";');
422 }
423
424 $show['pagenav'] = ($pagination->pagecount > 1 ? true : false);
425 $pagenav = $pagination->construct_page_nav('search.php');
426
427 eval('$template->flush("' . $template->fetch('search_results') . '");');
428 }
429
430 /*=====================================================================*\
431 || ###################################################################
432 || # $HeadURL$
433 || # $Id$
434 || ###################################################################
435 \*=====================================================================*/
436 ?>