PageRenderTime 35ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/core/filter_api.php

https://github.com/vincentsels/mantisbt
PHP | 4776 lines | 4260 code | 247 blank | 269 comment | 411 complexity | 687da9769bf1eed89ced5cbcf300e8c6 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. # MantisBT - a php based bugtracking system
  3. # MantisBT is free software: you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation, either version 2 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # MantisBT is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with MantisBT. If not, see <http://www.gnu.org/licenses/>.
  15. /**
  16. * @package CoreAPI
  17. * @subpackage FilterAPI
  18. * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org
  19. * @copyright Copyright (C) 2002 - 2013 MantisBT Team - mantisbt-dev@lists.sourceforge.net
  20. * @link http://www.mantisbt.org
  21. */
  22. /**
  23. * requires current_user_api
  24. */
  25. require_once( 'current_user_api.php' );
  26. /**
  27. * requires user_api
  28. */
  29. require_once( 'user_api.php' );
  30. /**
  31. * requires bug_api
  32. */
  33. require_once( 'bug_api.php' );
  34. /**
  35. * requires collapse_api
  36. */
  37. require_once( 'collapse_api.php' );
  38. /**
  39. * requires relationship_api
  40. */
  41. require_once( 'relationship_api.php' );
  42. /**
  43. * requires tag_api
  44. */
  45. require_once( 'tag_api.php' );
  46. /**
  47. * requires config_filter_defaults_inc
  48. */
  49. require_once( $g_absolute_path . 'config_filter_defaults_inc.php' );
  50. /**
  51. * Allow plugins to define a set of class-based filters, and register/load
  52. * them here to be used by the rest of filter_api.
  53. * @return array Mapping of field name to filter object
  54. */
  55. function filter_get_plugin_filters() {
  56. static $s_field_array = null;
  57. if ( is_null( $s_field_array ) ) {
  58. $s_field_array = array();
  59. $t_all_plugin_filters = event_signal( 'EVENT_FILTER_FIELDS' );
  60. foreach( $t_all_plugin_filters as $t_plugin => $t_plugin_filters ) {
  61. foreach( $t_plugin_filters as $t_callback => $t_plugin_filter_array ) {
  62. if ( is_array( $t_plugin_filter_array ) ) {
  63. foreach( $t_plugin_filter_array as $t_filter_class ) {
  64. if ( class_exists( $t_filter_class ) && is_subclass_of( $t_filter_class, 'MantisFilter' ) ) {
  65. $t_filter_object = new $t_filter_class();
  66. $t_field_name = $t_plugin . '_' . $t_filter_object->field;
  67. $s_field_array[ $t_field_name ] = $t_filter_object;
  68. }
  69. }
  70. }
  71. }
  72. }
  73. }
  74. return $s_field_array;
  75. }
  76. /**
  77. * Get a permalink for the current active filter. The results of using these fields by other users
  78. * can be inconsistent with the original results due to fields like "Myself", "Current Project",
  79. * and due to access level.
  80. * @param array $p_custom_filter
  81. * @return string the search.php?xxxx or an empty string if no criteria applied.
  82. */
  83. function filter_get_url( $p_custom_filter ) {
  84. $t_query = array();
  85. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_PROJECT_ID] ) ) {
  86. $t_project_id = $p_custom_filter[FILTER_PROPERTY_PROJECT_ID];
  87. if( count( $t_project_id ) == 1 && $t_project_id[0] == META_FILTER_CURRENT ) {
  88. $t_project_id = array(
  89. helper_get_current_project(),
  90. );
  91. }
  92. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_PROJECT_ID, $t_project_id );
  93. }
  94. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_FREE_TEXT] ) ) {
  95. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_FREE_TEXT, $p_custom_filter[FILTER_PROPERTY_FREE_TEXT] );
  96. }
  97. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_CATEGORY] ) ) {
  98. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_CATEGORY, $p_custom_filter[FILTER_PROPERTY_CATEGORY] );
  99. }
  100. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_REPORTER_ID] ) ) {
  101. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_REPORTER_ID, $p_custom_filter[FILTER_PROPERTY_REPORTER_ID] );
  102. }
  103. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_STATUS_ID] ) ) {
  104. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_STATUS_ID, $p_custom_filter[FILTER_PROPERTY_STATUS_ID] );
  105. }
  106. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_MONITOR_USER_ID] ) ) {
  107. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_MONITOR_USER_ID, $p_custom_filter[FILTER_PROPERTY_MONITOR_USER_ID] );
  108. }
  109. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_HANDLER_ID] ) ) {
  110. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_HANDLER_ID, $p_custom_filter[FILTER_PROPERTY_HANDLER_ID] );
  111. }
  112. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_NOTE_USER_ID] ) ) {
  113. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_NOTE_USER_ID, $p_custom_filter[FILTER_PROPERTY_NOTE_USER_ID] );
  114. }
  115. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_SEVERITY_ID] ) ) {
  116. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_SEVERITY_ID, $p_custom_filter[FILTER_PROPERTY_SEVERITY_ID] );
  117. }
  118. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_RESOLUTION_ID] ) ) {
  119. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_RESOLUTION_ID, $p_custom_filter[FILTER_PROPERTY_RESOLUTION_ID] );
  120. }
  121. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_PRIORITY_ID] ) ) {
  122. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_PRIORITY_ID, $p_custom_filter[FILTER_PROPERTY_PRIORITY_ID] );
  123. }
  124. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_VIEW_STATE_ID] ) ) {
  125. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_VIEW_STATE_ID, $p_custom_filter[FILTER_PROPERTY_VIEW_STATE_ID] );
  126. }
  127. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_SHOW_STICKY_ISSUES] ) ) {
  128. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_SHOW_STICKY_ISSUES, $p_custom_filter[FILTER_PROPERTY_SHOW_STICKY_ISSUES] );
  129. }
  130. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_PRODUCT_VERSION] ) ) {
  131. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_PRODUCT_VERSION, $p_custom_filter[FILTER_PROPERTY_PRODUCT_VERSION] );
  132. }
  133. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_PRODUCT_BUILD] ) ) {
  134. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_PRODUCT_BUILD, $p_custom_filter[FILTER_PROPERTY_PRODUCT_BUILD] );
  135. }
  136. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_FIXED_IN_VERSION] ) ) {
  137. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_FIXED_IN_VERSION, $p_custom_filter[FILTER_PROPERTY_FIXED_IN_VERSION] );
  138. }
  139. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_TARGET_VERSION] ) ) {
  140. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_TARGET_VERSION, $p_custom_filter[FILTER_PROPERTY_TARGET_VERSION] );
  141. }
  142. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_SORT_FIELD_NAME] ) ) {
  143. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_SORT_FIELD_NAME, $p_custom_filter[FILTER_PROPERTY_SORT_FIELD_NAME] );
  144. }
  145. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_SORT_DIRECTION] ) ) {
  146. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_SORT_DIRECTION, $p_custom_filter[FILTER_PROPERTY_SORT_DIRECTION] );
  147. }
  148. if( !filter_field_is_any( $p_custom_filter[FILTER_SEARCH_ISSUES_PER_PAGE] ) ) {
  149. if( $p_custom_filter[FILTER_SEARCH_ISSUES_PER_PAGE] != config_get( 'default_limit_view' ) ) {
  150. $t_query[] = filter_encode_field_and_value( FILTER_PROPERTY_ISSUES_PER_PAGE, $p_custom_filter[FILTER_SEARCH_ISSUES_PER_PAGE] );
  151. }
  152. }
  153. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_HIGHLIGHT_CHANGED] ) ) {
  154. if( $p_custom_filter[FILTER_PROPERTY_HIGHLIGHT_CHANGED] != config_get( 'default_show_changed' ) ) {
  155. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_HIGHLIGHT_CHANGED, $p_custom_filter[FILTER_PROPERTY_HIGHLIGHT_CHANGED] );
  156. }
  157. }
  158. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_HIDE_STATUS_ID] ) ) {
  159. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_HIDE_STATUS_ID, $p_custom_filter[FILTER_PROPERTY_HIDE_STATUS_ID] );
  160. }
  161. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_NOT_ASSIGNED] ) ) {
  162. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_NOT_ASSIGNED, $p_custom_filter[FILTER_PROPERTY_NOT_ASSIGNED] );
  163. }
  164. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_FILTER_BY_DATE] ) ) {
  165. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_FILTER_BY_DATE, $p_custom_filter[FILTER_PROPERTY_FILTER_BY_DATE] );
  166. # The start and end dates are only applicable if filter by date is set.
  167. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_START_DAY] ) ) {
  168. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_START_DAY, $p_custom_filter[FILTER_PROPERTY_START_DAY] );
  169. }
  170. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_END_DAY] ) ) {
  171. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_END_DAY, $p_custom_filter[FILTER_PROPERTY_END_DAY] );
  172. }
  173. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_START_MONTH] ) ) {
  174. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_START_MONTH, $p_custom_filter[FILTER_PROPERTY_START_MONTH] );
  175. }
  176. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_END_MONTH] ) ) {
  177. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_END_MONTH, $p_custom_filter[FILTER_PROPERTY_END_MONTH] );
  178. }
  179. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_START_YEAR] ) ) {
  180. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_START_YEAR, $p_custom_filter[FILTER_PROPERTY_START_YEAR] );
  181. }
  182. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_END_YEAR] ) ) {
  183. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_END_YEAR, $p_custom_filter[FILTER_PROPERTY_END_YEAR] );
  184. }
  185. }
  186. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_RELATIONSHIP_TYPE] ) ) {
  187. if( $p_custom_filter[FILTER_PROPERTY_RELATIONSHIP_TYPE] != -1 ) {
  188. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_RELATIONSHIP_TYPE, $p_custom_filter[FILTER_PROPERTY_RELATIONSHIP_TYPE] );
  189. }
  190. }
  191. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_RELATIONSHIP_BUG] ) ) {
  192. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_RELATIONSHIP_BUG, $p_custom_filter[FILTER_PROPERTY_RELATIONSHIP_BUG] );
  193. }
  194. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_PLATFORM] ) ) {
  195. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_PLATFORM, $p_custom_filter[FILTER_PROPERTY_PLATFORM] );
  196. }
  197. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_OS] ) ) {
  198. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_OS, $p_custom_filter[FILTER_PROPERTY_OS] );
  199. }
  200. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_OS_BUILD] ) ) {
  201. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_OS_BUILD, $p_custom_filter[FILTER_PROPERTY_OS_BUILD] );
  202. }
  203. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_TAG_STRING] ) ) {
  204. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_TAG_STRING, $p_custom_filter[FILTER_PROPERTY_TAG_STRING] );
  205. }
  206. if( !filter_field_is_any( $p_custom_filter[FILTER_PROPERTY_TAG_SELECT] ) ) {
  207. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_TAG_SELECT, $p_custom_filter[FILTER_PROPERTY_TAG_SELECT] );
  208. }
  209. $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_MATCH_TYPE, $p_custom_filter[FILTER_PROPERTY_MATCH_TYPE] );
  210. if( isset( $p_custom_filter['custom_fields'] ) ) {
  211. foreach( $p_custom_filter['custom_fields'] as $t_custom_field_id => $t_custom_field_values ) {
  212. if( !filter_field_is_any( $t_custom_field_values ) ) {
  213. $t_query[] = filter_encode_field_and_value( 'custom_field_' . $t_custom_field_id, $t_custom_field_values );
  214. }
  215. }
  216. }
  217. # Allow plugins to add filter fields
  218. $t_plugin_filter_array = filter_get_plugin_filters();
  219. foreach( $t_plugin_filter_array as $t_field_name => $t_filter_object ) {
  220. if( !filter_field_is_any( $p_custom_filter[ $t_field_name ] ) ) {
  221. $t_query[] = filter_encode_field_and_value( $t_field_name, $p_custom_filter[ $t_field_name ], $t_filter_object->type );
  222. }
  223. }
  224. if( count( $t_query ) > 0 ) {
  225. $t_query_str = implode( $t_query, '&' );
  226. $t_url = config_get( 'path' ) . 'search.php?' . $t_query_str;
  227. } else {
  228. $t_url = '';
  229. }
  230. return $t_url;
  231. }
  232. /**
  233. * Encodes a field and it's value for the filter URL. This handles the URL encoding
  234. * and arrays.
  235. * @param string $p_field_name The field name.
  236. * @param string $p_field_value The field value (can be an array)
  237. * @return string url encoded string
  238. */
  239. function filter_encode_field_and_value( $p_field_name, $p_field_value, $p_field_type=null ) {
  240. $t_query_array = array();
  241. if( is_array( $p_field_value ) ) {
  242. $t_count = count( $p_field_value );
  243. if( $t_count > 1 || $p_field_type == FILTER_TYPE_MULTI_STRING || $p_field_type == FILTER_TYPE_MULTI_INT ) {
  244. foreach( $p_field_value as $t_value ) {
  245. $t_query_array[] = urlencode( $p_field_name . '[]' ) . '=' . urlencode( $t_value );
  246. }
  247. }
  248. else if( $t_count == 1 ) {
  249. $t_query_array[] = urlencode( $p_field_name ) . '=' . urlencode( $p_field_value[0] );
  250. }
  251. } else {
  252. $t_query_array[] = urlencode( $p_field_name ) . '=' . urlencode( $p_field_value );
  253. }
  254. return implode( $t_query_array, '&' );
  255. }
  256. # ==========================================================================
  257. # GENERAL FUNCTIONS =
  258. # ==========================================================================
  259. /**
  260. * Checks the supplied value to see if it is an ANY value.
  261. * @param string $p_field_value - The value to check.
  262. * @return bool true for "ANY" values and false for others. "ANY" means filter criteria not active.
  263. */
  264. function filter_field_is_any( $p_field_value ) {
  265. if( is_array( $p_field_value ) ) {
  266. if( count( $p_field_value ) == 0 ) {
  267. return true;
  268. }
  269. foreach( $p_field_value as $t_value ) {
  270. if(( META_FILTER_ANY == $t_value ) && ( is_numeric( $t_value ) ) ) {
  271. return true;
  272. }
  273. }
  274. } else {
  275. if( is_string( $p_field_value ) && is_blank( $p_field_value ) ) {
  276. return true;
  277. }
  278. if( is_bool( $p_field_value ) && !$p_field_value ) {
  279. return true;
  280. }
  281. if(( META_FILTER_ANY == $p_field_value ) && ( is_numeric( $p_field_value ) ) ) {
  282. return true;
  283. }
  284. }
  285. return false;
  286. }
  287. /**
  288. * Checks the supplied value to see if it is a NONE value.
  289. * @param string $p_field_value - The value to check.
  290. * @return bool true for "NONE" values and false for others.
  291. * @todo is a check for these necessary? if ( ( $t_filter_value === 'none' ) || ( $t_filter_value === '[none]' ) )
  292. */
  293. function filter_field_is_none( $p_field_value ) {
  294. if( is_array( $p_field_value ) ) {
  295. foreach( $p_field_value as $t_value ) {
  296. if(( META_FILTER_NONE == $t_value ) && ( is_numeric( $t_value ) ) ) {
  297. return true;
  298. }
  299. }
  300. } else {
  301. if( is_string( $p_field_value ) && is_blank( $p_field_value ) ) {
  302. return false;
  303. }
  304. if(( META_FILTER_NONE == $p_field_value ) && ( is_numeric( $p_field_value ) ) ) {
  305. return true;
  306. }
  307. }
  308. return false;
  309. }
  310. /**
  311. * Checks the supplied value to see if it is a MYSELF value.
  312. * @param string $p_field_value - The value to check.
  313. * @return bool true for "MYSELF" values and false for others.
  314. */
  315. function filter_field_is_myself( $p_field_value ) {
  316. return( META_FILTER_MYSELF == $p_field_value ? TRUE : FALSE );
  317. }
  318. /**
  319. * @param $p_count
  320. * @param $p_per_page
  321. * @return int
  322. */
  323. function filter_per_page( $p_filter, $p_count, $p_per_page ) {
  324. $p_per_page = (( NULL == $p_per_page ) ? (int) $p_filter[FILTER_PROPERTY_ISSUES_PER_PAGE] : $p_per_page );
  325. $p_per_page = (( 0 == $p_per_page || -1 == $p_per_page ) ? $p_count : $p_per_page );
  326. return (int) abs( $p_per_page );
  327. }
  328. /**
  329. * Use $p_count and $p_per_page to determine how many pages to split this list up into.
  330. * For the sake of consistency have at least one page, even if it is empty.
  331. * @param $p_count
  332. * @param $p_per_page
  333. * @return $t_page_count
  334. */
  335. function filter_page_count( $p_count, $p_per_page ) {
  336. $t_page_count = ceil( $p_count / $p_per_page );
  337. if( $t_page_count < 1 ) {
  338. $t_page_count = 1;
  339. }
  340. return $t_page_count;
  341. }
  342. /**
  343. * Checks to make sure $p_page_number isn't past the last page.
  344. * and that $p_page_number isn't before the first page
  345. * @param $p_page_number
  346. * @param $p_page_count
  347. */
  348. function filter_valid_page_number( $p_page_number, $p_page_count ) {
  349. if( $p_page_number > $p_page_count ) {
  350. $p_page_number = $p_page_count;
  351. }
  352. if( $p_page_number < 1 ) {
  353. $p_page_number = 1;
  354. }
  355. return $p_page_number;
  356. }
  357. /**
  358. * Figure out the offset into the db query, offset is which record to start querying from
  359. * @param int $p_page_number
  360. * @param int $p_per_page
  361. * @return int
  362. */
  363. function filter_offset( $p_page_number, $p_per_page ) {
  364. return(( (int) $p_page_number -1 ) * (int) $p_per_page );
  365. }
  366. /**
  367. * Make sure that our filters are entirely correct and complete (it is possible that they are not).
  368. * We need to do this to cover cases where we don't have complete control over the filters given.s
  369. * @param array $p_filter_arr
  370. * @return mixed
  371. * @todo function needs to be abstracted
  372. */
  373. function filter_ensure_valid_filter( $p_filter_arr ) {
  374. # extend current filter to add information passed via POST
  375. if( !isset( $p_filter_arr['_version'] ) ) {
  376. $p_filter_arr['_version'] = config_get( 'cookie_version' );
  377. }
  378. $t_cookie_vers = (int) utf8_substr( $p_filter_arr['_version'], 1 );
  379. if( utf8_substr( config_get( 'cookie_version' ), 1 ) > $t_cookie_vers ) {
  380. # if the version is old, update it
  381. $p_filter_arr['_version'] = config_get( 'cookie_version' );
  382. }
  383. if( !isset( $p_filter_arr['_view_type'] ) ) {
  384. $p_filter_arr['_view_type'] = gpc_get_string( 'view_type', 'simple' );
  385. }
  386. if( !isset( $p_filter_arr[FILTER_PROPERTY_ISSUES_PER_PAGE] ) ) {
  387. $p_filter_arr[FILTER_PROPERTY_ISSUES_PER_PAGE] = gpc_get_int( FILTER_PROPERTY_ISSUES_PER_PAGE, config_get( 'default_limit_view' ) );
  388. }
  389. if( !isset( $p_filter_arr[FILTER_PROPERTY_HIGHLIGHT_CHANGED] ) ) {
  390. $p_filter_arr[FILTER_PROPERTY_HIGHLIGHT_CHANGED] = config_get( 'default_show_changed' );
  391. }
  392. if( !isset( $p_filter_arr[FILTER_PROPERTY_SHOW_STICKY_ISSUES] ) ) {
  393. $p_filter_arr[FILTER_PROPERTY_SHOW_STICKY_ISSUES] = gpc_string_to_bool( config_get( 'show_sticky_issues' ) );
  394. }
  395. if( !isset( $p_filter_arr[FILTER_PROPERTY_SORT_FIELD_NAME] ) ) {
  396. $p_filter_arr[FILTER_PROPERTY_SORT_FIELD_NAME] = "last_updated";
  397. }
  398. if( !isset( $p_filter_arr[FILTER_PROPERTY_SORT_DIRECTION] ) ) {
  399. $p_filter_arr[FILTER_PROPERTY_SORT_DIRECTION] = "DESC";
  400. }
  401. if( !isset( $p_filter_arr[FILTER_PROPERTY_PLATFORM] ) ) {
  402. $p_filter_arr[FILTER_PROPERTY_PLATFORM] = array(
  403. 0 => META_FILTER_ANY,
  404. );
  405. }
  406. if( !isset( $p_filter_arr[FILTER_PROPERTY_OS] ) ) {
  407. $p_filter_arr[FILTER_PROPERTY_OS] = array(
  408. 0 => META_FILTER_ANY,
  409. );
  410. }
  411. if( !isset( $p_filter_arr[FILTER_PROPERTY_OS_BUILD] ) ) {
  412. $p_filter_arr[FILTER_PROPERTY_OS_BUILD] = array(
  413. 0 => META_FILTER_ANY,
  414. );
  415. }
  416. if( !isset( $p_filter_arr[FILTER_PROPERTY_PROJECT_ID] ) ) {
  417. $p_filter_arr[FILTER_PROPERTY_PROJECT_ID] = array(
  418. 0 => META_FILTER_CURRENT,
  419. );
  420. }
  421. if( !isset( $p_filter_arr[FILTER_PROPERTY_START_MONTH] ) ) {
  422. $p_filter_arr[FILTER_PROPERTY_START_MONTH] = gpc_get_string( FILTER_PROPERTY_START_MONTH, date( 'm' ) );
  423. }
  424. if( !isset( $p_filter_arr[FILTER_PROPERTY_START_DAY] ) ) {
  425. $p_filter_arr[FILTER_PROPERTY_START_DAY] = gpc_get_string( FILTER_PROPERTY_START_DAY, 1 );
  426. }
  427. if( !isset( $p_filter_arr[FILTER_PROPERTY_START_YEAR] ) ) {
  428. $p_filter_arr[FILTER_PROPERTY_START_YEAR] = gpc_get_string( FILTER_PROPERTY_START_YEAR, date( 'Y' ) );
  429. }
  430. if( !isset( $p_filter_arr[FILTER_PROPERTY_END_MONTH] ) ) {
  431. $p_filter_arr[FILTER_PROPERTY_END_MONTH] = gpc_get_string( FILTER_PROPERTY_END_MONTH, date( 'm' ) );
  432. }
  433. if( !isset( $p_filter_arr[FILTER_PROPERTY_END_DAY] ) ) {
  434. $p_filter_arr[FILTER_PROPERTY_END_DAY] = gpc_get_string( FILTER_PROPERTY_END_DAY, date( 'd' ) );
  435. }
  436. if( !isset( $p_filter_arr[FILTER_PROPERTY_END_YEAR] ) ) {
  437. $p_filter_arr[FILTER_PROPERTY_END_YEAR] = gpc_get_string( FILTER_PROPERTY_END_YEAR, date( 'Y' ) );
  438. }
  439. if( !isset( $p_filter_arr[FILTER_PROPERTY_FREE_TEXT] ) ) {
  440. $p_filter_arr[FILTER_PROPERTY_FREE_TEXT] = '';
  441. }
  442. if( !isset( $p_filter_arr[FILTER_PROPERTY_NOT_ASSIGNED] ) ) {
  443. $p_filter_arr[FILTER_PROPERTY_NOT_ASSIGNED] = gpc_get_bool( FILTER_PROPERTY_NOT_ASSIGNED, false );
  444. }
  445. if( !isset( $p_filter_arr[FILTER_PROPERTY_FILTER_BY_DATE] ) ) {
  446. $p_filter_arr[FILTER_PROPERTY_FILTER_BY_DATE] = gpc_get_bool( FILTER_PROPERTY_FILTER_BY_DATE, false );
  447. }
  448. if( !isset( $p_filter_arr[FILTER_PROPERTY_VIEW_STATE_ID] ) ) {
  449. $p_filter_arr[FILTER_PROPERTY_VIEW_STATE_ID] = gpc_get( FILTER_PROPERTY_VIEW_STATE_ID, '' );
  450. }
  451. else if( filter_field_is_any( $p_filter_arr[FILTER_PROPERTY_VIEW_STATE_ID] ) ) {
  452. $p_filter_arr[FILTER_PROPERTY_VIEW_STATE_ID] = META_FILTER_ANY;
  453. }
  454. if( !isset( $p_filter_arr[FILTER_PROPERTY_RELATIONSHIP_TYPE] ) ) {
  455. $p_filter_arr[FILTER_PROPERTY_RELATIONSHIP_TYPE] = gpc_get_int( FILTER_PROPERTY_RELATIONSHIP_TYPE, -1 );
  456. }
  457. if( !isset( $p_filter_arr[FILTER_PROPERTY_RELATIONSHIP_BUG] ) ) {
  458. $p_filter_arr[FILTER_PROPERTY_RELATIONSHIP_BUG] = gpc_get_int( FILTER_PROPERTY_RELATIONSHIP_BUG, 0 );
  459. }
  460. if( !isset( $p_filter_arr[FILTER_PROPERTY_TARGET_VERSION] ) ) {
  461. $p_filter_arr[FILTER_PROPERTY_TARGET_VERSION] = META_FILTER_ANY;
  462. }
  463. if( !isset( $p_filter_arr[FILTER_PROPERTY_TAG_STRING] ) ) {
  464. $p_filter_arr[FILTER_PROPERTY_TAG_STRING] = gpc_get_string( FILTER_PROPERTY_TAG_STRING, '' );
  465. }
  466. if( !isset( $p_filter_arr[FILTER_PROPERTY_TAG_SELECT] ) ) {
  467. $p_filter_arr[FILTER_PROPERTY_TAG_SELECT] = gpc_get_string( FILTER_PROPERTY_TAG_SELECT, '' );
  468. }
  469. if( !isset( $p_filter_arr[FILTER_PROPERTY_MATCH_TYPE] ) ) {
  470. $p_filter_arr[FILTER_PROPERTY_MATCH_TYPE] = gpc_get_int( FILTER_PROPERTY_MATCH_TYPE, FILTER_MATCH_ALL );
  471. }
  472. # initialize plugin filters
  473. $t_plugin_filters = filter_get_plugin_filters();
  474. foreach( $t_plugin_filters as $t_field_name => $t_filter_object ) {
  475. if( !isset( $p_filter_arr[ $t_field_name ] ) ) {
  476. switch( $t_filter_object->type ) {
  477. case FILTER_TYPE_STRING:
  478. $p_filter_arr[ $t_field_name ] = gpc_get_string( $t_field_name, $t_filter_object->default );
  479. break;
  480. case FILTER_TYPE_INT:
  481. $p_filter_arr[ $t_field_name ] = gpc_get_int( $t_field_name, (int)$t_filter_object->default );
  482. break;
  483. case FILTER_TYPE_BOOLEAN:
  484. $p_filter_arr[ $t_field_name ] = gpc_get_bool( $t_field_name, (bool)$t_filter_object->default );
  485. break;
  486. case FILTER_TYPE_MULTI_STRING:
  487. $p_filter_arr[ $t_field_name ] = gpc_get_string_array( $t_field_name, array( 0 => META_FILTER_ANY ) );
  488. break;
  489. case FILTER_TYPE_MULTI_INT:
  490. $p_filter_arr[ $t_field_name ] = gpc_get_int_array( $t_field_name, array( 0 => META_FILTER_ANY ) );
  491. break;
  492. default:
  493. $p_filter_arr[ $t_field_name ] = META_FILTER_ANY;
  494. }
  495. }
  496. if ( ! $t_filter_object->validate( $p_filter_arr[ $t_field_name ] ) ) {
  497. $p_filter_arr[ $t_field_name ] = $t_filter_object->default;
  498. }
  499. }
  500. $t_custom_fields = custom_field_get_ids();
  501. # @@@ (thraxisp) This should really be the linked ids, but we don't know the project
  502. $f_custom_fields_data = array();
  503. if( is_array( $t_custom_fields ) && ( count( $t_custom_fields ) > 0 ) ) {
  504. foreach( $t_custom_fields as $t_cfid ) {
  505. if( is_array( gpc_get( 'custom_field_' . $t_cfid, null ) ) ) {
  506. $f_custom_fields_data[$t_cfid] = gpc_get_string_array( 'custom_field_' . $t_cfid, META_FILTER_ANY );
  507. } else {
  508. $f_custom_fields_data[$t_cfid] = gpc_get_string( 'custom_field_' . $t_cfid, META_FILTER_ANY );
  509. $f_custom_fields_data[$t_cfid] = array(
  510. $f_custom_fields_data[$t_cfid],
  511. );
  512. }
  513. }
  514. }
  515. # validate sorting
  516. $t_fields = helper_get_columns_to_view();
  517. $t_n_fields = count( $t_fields );
  518. for( $i = 0;$i < $t_n_fields;$i++ ) {
  519. if( isset( $t_fields[$i] ) && in_array( $t_fields[$i], array( 'selection', 'edit', 'bugnotes_count', 'attachment_count' ) ) ) {
  520. unset( $t_fields[$i] );
  521. }
  522. }
  523. $t_sort_fields = explode( ',', $p_filter_arr['sort'] );
  524. $t_dir_fields = explode( ',', $p_filter_arr['dir'] );
  525. for( $i = 0;$i < 2;$i++ ) {
  526. if( isset( $t_sort_fields[$i] ) ) {
  527. $t_drop = false;
  528. $t_sort = $t_sort_fields[$i];
  529. if( strpos( $t_sort, 'custom_' ) === 0 ) {
  530. if( false === custom_field_get_id_from_name( utf8_substr( $t_sort, utf8_strlen( 'custom_' ) ) ) ) {
  531. $t_drop = true;
  532. }
  533. } else {
  534. if( !in_array( $t_sort, $t_fields ) ) {
  535. $t_drop = true;
  536. }
  537. }
  538. if( !in_array( $t_dir_fields[$i], array( "ASC", "DESC" ) ) ) {
  539. $t_drop = true;
  540. }
  541. if( $t_drop ) {
  542. unset( $t_sort_fields[$i] );
  543. unset( $t_dir_fields[$i] );
  544. }
  545. }
  546. }
  547. if( count( $t_sort_fields ) > 0 ) {
  548. $p_filter_arr['sort'] = implode( ',', $t_sort_fields );
  549. $p_filter_arr['dir'] = implode( ',', $t_dir_fields );
  550. } else {
  551. $p_filter_arr['sort'] = "last_updated";
  552. $p_filter_arr['dir'] = "DESC";
  553. }
  554. # validate or filter junk from other fields
  555. $t_multi_select_list = array(
  556. FILTER_PROPERTY_CATEGORY => 'string',
  557. FILTER_PROPERTY_SEVERITY_ID => 'int',
  558. FILTER_PROPERTY_STATUS_ID => 'int',
  559. FILTER_PROPERTY_REPORTER_ID => 'int',
  560. FILTER_PROPERTY_HANDLER_ID => 'int',
  561. FILTER_PROPERTY_NOTE_USER_ID => 'int',
  562. FILTER_PROPERTY_RESOLUTION_ID => 'int',
  563. FILTER_PROPERTY_PRIORITY_ID => 'int',
  564. FILTER_PROPERTY_PRODUCT_BUILD => 'string',
  565. FILTER_PROPERTY_PRODUCT_VERSION => 'string',
  566. FILTER_PROPERTY_HIDE_STATUS_ID => 'int',
  567. FILTER_PROPERTY_FIXED_IN_VERSION => 'string',
  568. FILTER_PROPERTY_TARGET_VERSION => 'string',
  569. FILTER_PROPERTY_MONITOR_USER_ID => 'int',
  570. 'show_profile' => 'int',
  571. );
  572. foreach( $t_multi_select_list as $t_multi_field_name => $t_multi_field_type ) {
  573. if( !isset( $p_filter_arr[$t_multi_field_name] ) ) {
  574. if( FILTER_PROPERTY_HIDE_STATUS_ID == $t_multi_field_name ) {
  575. $p_filter_arr[$t_multi_field_name] = array(
  576. config_get( 'hide_status_default' ),
  577. );
  578. }
  579. else if( 'custom_fields' == $t_multi_field_name ) {
  580. $p_filter_arr[$t_multi_field_name] = array(
  581. $f_custom_fields_data,
  582. );
  583. } else {
  584. $p_filter_arr[$t_multi_field_name] = array(
  585. META_FILTER_ANY,
  586. );
  587. }
  588. } else {
  589. if( !is_array( $p_filter_arr[$t_multi_field_name] ) ) {
  590. $p_filter_arr[$t_multi_field_name] = array(
  591. $p_filter_arr[$t_multi_field_name],
  592. );
  593. }
  594. $t_checked_array = array();
  595. foreach( $p_filter_arr[$t_multi_field_name] as $t_filter_value ) {
  596. $t_filter_value = stripslashes( $t_filter_value );
  597. if(( $t_filter_value === 'any' ) || ( $t_filter_value === '[any]' ) ) {
  598. $t_filter_value = META_FILTER_ANY;
  599. }
  600. if(( $t_filter_value === 'none' ) || ( $t_filter_value === '[none]' ) ) {
  601. $t_filter_value = META_FILTER_NONE;
  602. }
  603. if( 'string' == $t_multi_field_type ) {
  604. $t_checked_array[] = $t_filter_value;
  605. }
  606. else if( 'int' == $t_multi_field_type ) {
  607. $t_checked_array[] = (int)$t_filter_value;
  608. }
  609. else if( 'array' == $t_multi_field_type ) {
  610. $t_checked_array[] = $t_filter_value;
  611. }
  612. }
  613. $p_filter_arr[$t_multi_field_name] = $t_checked_array;
  614. }
  615. }
  616. if( is_array( $t_custom_fields ) && ( count( $t_custom_fields ) > 0 ) ) {
  617. foreach( $t_custom_fields as $t_cfid ) {
  618. if( !isset( $p_filter_arr['custom_fields'][$t_cfid] ) ) {
  619. $p_filter_arr['custom_fields'][$t_cfid] = array(
  620. META_FILTER_ANY,
  621. );
  622. } else {
  623. if( !is_array( $p_filter_arr['custom_fields'][$t_cfid] ) ) {
  624. $p_filter_arr['custom_fields'][$t_cfid] = array(
  625. $p_filter_arr['custom_fields'][$t_cfid],
  626. );
  627. }
  628. $t_checked_array = array();
  629. foreach( $p_filter_arr['custom_fields'][$t_cfid] as $t_filter_value ) {
  630. $t_filter_value = stripslashes( $t_filter_value );
  631. if(( $t_filter_value === 'any' ) || ( $t_filter_value === '[any]' ) ) {
  632. $t_filter_value = META_FILTER_ANY;
  633. }
  634. $t_checked_array[] = $t_filter_value;
  635. }
  636. $p_filter_arr['custom_fields'][$t_cfid] = $t_checked_array;
  637. }
  638. }
  639. }
  640. # all of our filter values are now guaranteed to be there, and correct.
  641. return $p_filter_arr;
  642. }
  643. /**
  644. * Get the standard filter that is to be used when no filter was previously saved.
  645. * When creating specific filters, this can be used as a basis for the filter, where
  646. * specific entries can be overridden.
  647. * @return mixed
  648. */
  649. function filter_get_default() {
  650. $t_hide_status_default = config_get( 'hide_status_default' );
  651. $t_default_show_changed = config_get( 'default_show_changed' );
  652. $t_filter = array(
  653. FILTER_PROPERTY_CATEGORY => Array(
  654. '0' => META_FILTER_ANY,
  655. ),
  656. FILTER_PROPERTY_SEVERITY_ID => Array(
  657. '0' => META_FILTER_ANY,
  658. ),
  659. FILTER_PROPERTY_STATUS_ID => Array(
  660. '0' => META_FILTER_ANY,
  661. ),
  662. FILTER_PROPERTY_HIGHLIGHT_CHANGED => $t_default_show_changed,
  663. FILTER_PROPERTY_REPORTER_ID => Array(
  664. '0' => META_FILTER_ANY,
  665. ),
  666. FILTER_PROPERTY_HANDLER_ID => Array(
  667. '0' => META_FILTER_ANY,
  668. ),
  669. FILTER_PROPERTY_PROJECT_ID => Array(
  670. '0' => META_FILTER_CURRENT,
  671. ),
  672. FILTER_PROPERTY_RESOLUTION_ID => Array(
  673. '0' => META_FILTER_ANY,
  674. ),
  675. FILTER_PROPERTY_PRODUCT_BUILD => Array(
  676. '0' => META_FILTER_ANY,
  677. ),
  678. FILTER_PROPERTY_PRODUCT_VERSION => Array(
  679. '0' => META_FILTER_ANY,
  680. ),
  681. FILTER_PROPERTY_HIDE_STATUS_ID => Array(
  682. '0' => $t_hide_status_default,
  683. ),
  684. FILTER_PROPERTY_MONITOR_USER_ID => Array(
  685. '0' => META_FILTER_ANY,
  686. ),
  687. FILTER_PROPERTY_SORT_FIELD_NAME => 'last_updated',
  688. FILTER_PROPERTY_SORT_DIRECTION => 'DESC',
  689. FILTER_PROPERTY_ISSUES_PER_PAGE => config_get( 'default_limit_view' ),
  690. FILTER_PROPERTY_MATCH_TYPE => FILTER_MATCH_ALL
  691. );
  692. return filter_ensure_valid_filter( $t_filter );
  693. }
  694. /**
  695. * Deserialize filter string
  696. * @param string $p_serialized_filter
  697. * @return mixed $t_filter array
  698. * @see filter_ensure_valid_filter
  699. */
  700. function filter_deserialize( $p_serialized_filter ) {
  701. if( is_blank( $p_serialized_filter ) ) {
  702. return false;
  703. }
  704. # check to see if new cookie is needed
  705. $t_setting_arr = explode( '#', $p_serialized_filter, 2 );
  706. if(( $t_setting_arr[0] == 'v1' ) || ( $t_setting_arr[0] == 'v2' ) || ( $t_setting_arr[0] == 'v3' ) || ( $t_setting_arr[0] == 'v4' ) ) {
  707. # these versions can't be salvaged, they are too old to update
  708. return false;
  709. }
  710. # We shouldn't need to do this anymore, as filters from v5 onwards should cope with changing
  711. # filter indices dynamically
  712. $t_filter_array = array();
  713. if( isset( $t_setting_arr[1] ) ) {
  714. $t_filter_array = unserialize( $t_setting_arr[1] );
  715. } else {
  716. return false;
  717. }
  718. if( $t_filter_array['_version'] != config_get( 'cookie_version' ) ) {
  719. # if the version is not new enough, update it using defaults
  720. return filter_ensure_valid_filter( $t_filter_array );
  721. }
  722. return $t_filter_array;
  723. }
  724. /**
  725. * Check if the filter cookie exists and is of the correct version.
  726. * @return bool
  727. */
  728. function filter_is_cookie_valid() {
  729. $t_view_all_cookie_id = gpc_get_cookie( config_get( 'view_all_cookie' ), '' );
  730. $t_view_all_cookie = filter_db_get_filter( $t_view_all_cookie_id );
  731. # check to see if the cookie does not exist
  732. if( is_blank( $t_view_all_cookie ) ) {
  733. return false;
  734. }
  735. # check to see if new cookie is needed
  736. $t_setting_arr = explode( '#', $t_view_all_cookie, 2 );
  737. if(( $t_setting_arr[0] == 'v1' ) || ( $t_setting_arr[0] == 'v2' ) || ( $t_setting_arr[0] == 'v3' ) || ( $t_setting_arr[0] == 'v4' ) ) {
  738. return false;
  739. }
  740. # We shouldn't need to do this anymore, as filters from v5 onwards should cope with changing
  741. # filter indices dynamically
  742. $t_filter_cookie_arr = array();
  743. if( isset( $t_setting_arr[1] ) ) {
  744. $t_filter_cookie_arr = unserialize( $t_setting_arr[1] );
  745. } else {
  746. return false;
  747. }
  748. if( $t_filter_cookie_arr['_version'] != config_get( 'cookie_version' ) ) {
  749. return false;
  750. }
  751. return true;
  752. }
  753. /**
  754. * Get the array fields specified by $p_filter_id
  755. * using the cached row if it's available
  756. * @param int $p_filter_id
  757. * @return mixed a filter row
  758. */
  759. function filter_get_row( $p_filter_id ) {
  760. return filter_cache_row( $p_filter_id );
  761. }
  762. /**
  763. * Get the value of the filter field specified by filter id and field name
  764. * @param int $p_filter_id
  765. * @param string $p_field_name
  766. * @return string
  767. */
  768. function filter_get_field( $p_filter_id, $p_field_name ) {
  769. $row = filter_get_row( $p_filter_id );
  770. if( isset( $row[$p_field_name] ) ) {
  771. return $row[$p_field_name];
  772. } else {
  773. error_parameters( $p_field_name );
  774. trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING );
  775. return '';
  776. }
  777. }
  778. /**
  779. * Add sort parameters to the query clauses
  780. * @param array $p_filter
  781. * @param bool $p_show_sticky
  782. * @param array $p_query_clauses
  783. * @return array $p_query_clauses
  784. */
  785. function filter_get_query_sort_data( &$p_filter, $p_show_sticky, $p_query_clauses ) {
  786. $t_bug_table = db_get_table( 'mantis_bug_table' );
  787. $t_custom_field_string_table = db_get_table( 'mantis_custom_field_string_table' );
  788. # if sort is blank then default the sort and direction. This is to fix the
  789. # symptoms of #3953. Note that even if the main problem is fixed, we may
  790. # have to keep this code for a while to handle filters saved with this blank field.
  791. if( is_blank( $p_filter[FILTER_PROPERTY_SORT_FIELD_NAME] ) ) {
  792. $p_filter[FILTER_PROPERTY_SORT_FIELD_NAME] = 'last_updated';
  793. $p_filter[FILTER_PROPERTY_SORT_DIRECTION] = 'DESC';
  794. }
  795. $p_query_clauses['order'] = array();
  796. $t_sort_fields = explode( ',', $p_filter[FILTER_PROPERTY_SORT_FIELD_NAME] );
  797. $t_dir_fields = explode( ',', $p_filter[FILTER_PROPERTY_SORT_DIRECTION] );
  798. $t_plugin_columns = columns_get_plugin_columns();
  799. if ( gpc_string_to_bool( $p_filter[FILTER_PROPERTY_SHOW_STICKY_ISSUES] ) && ( NULL !== $p_show_sticky ) ) {
  800. $p_query_clauses['order'][] = "$t_bug_table.sticky DESC";
  801. }
  802. $t_count = count( $t_sort_fields );
  803. for( $i = 0;$i < $t_count;$i++ ) {
  804. $c_sort = $t_sort_fields[$i];
  805. $c_dir = 'DESC' == $t_dir_fields[$i] ? 'DESC' : 'ASC';
  806. if( !in_array( $t_sort_fields[$i], array_slice( $t_sort_fields, $i + 1 ) ) ) {
  807. # if sorting by a custom field
  808. if( strpos( $c_sort, 'custom_' ) === 0 ) {
  809. $t_custom_field = utf8_substr( $c_sort, utf8_strlen( 'custom_' ) );
  810. $t_custom_field_id = custom_field_get_id_from_name( $t_custom_field );
  811. $c_cf_alias = 'custom_field_' . $t_custom_field_id;
  812. $t_cf_table_alias = $t_custom_field_string_table . '_' . $t_custom_field_id;
  813. $t_cf_select = "$t_cf_table_alias.value $c_cf_alias";
  814. # check to be sure this field wasn't already added to the query.
  815. if( !in_array( $t_cf_select, $p_query_clauses['select'] ) ) {
  816. $p_query_clauses['select'][] = $t_cf_select;
  817. $p_query_clauses['join'][] = "LEFT JOIN $t_custom_field_string_table $t_cf_table_alias ON $t_bug_table.id = $t_cf_table_alias.bug_id AND $t_cf_table_alias.field_id = $t_custom_field_id";
  818. }
  819. $p_query_clauses['order'][] = "$c_cf_alias $c_dir";
  820. # if sorting by plugin columns
  821. } else if ( isset( $t_plugin_columns[ $t_sort_fields[$i] ] ) ) {
  822. $t_column_object = $t_plugin_columns[ $t_sort_fields[$i] ];
  823. if ( $t_column_object->sortable ) {
  824. $t_clauses = $t_column_object->sortquery( $c_dir );
  825. if ( is_array( $t_clauses ) ) {
  826. if ( isset( $t_clauses['join'] ) ) {
  827. $p_query_clauses['join'][] = $t_clauses['join'];
  828. }
  829. if ( isset( $t_clauses['order'] ) ) {
  830. $p_query_clauses['order'][] = $t_clauses['order'];
  831. }
  832. }
  833. }
  834. # standard column
  835. } else {
  836. if ( 'last_updated' == $c_sort ) {
  837. $c_sort = "last_updated";
  838. }
  839. $p_query_clauses['order'][] = "$t_bug_table.$c_sort $c_dir";
  840. }
  841. }
  842. }
  843. # add basic sorting if necessary
  844. if( !in_array( 'last_updated', $t_sort_fields ) ) {
  845. $p_query_clauses['order'][] = "$t_bug_table.last_updated DESC";
  846. }
  847. if( !in_array( 'date_submitted', $t_sort_fields ) ) {
  848. $p_query_clauses['order'][] = "$t_bug_table.date_submitted DESC";
  849. }
  850. return $p_query_clauses;
  851. }
  852. /**
  853. * Remove any duplicate values in certain elements of query_clauses
  854. * Do not loop over query clauses as some keys may contain valid duplicate values.
  855. * We basically want unique values for just the base query elements select, from, and join
  856. * 'where' and 'where_values' key should not have duplicates as that is handled earlier and applying
  857. * array_unique here could cause problems with the query.
  858. * @param $p_query_clauses
  859. * @return $p_query_clauses
  860. */
  861. function filter_unique_query_clauses( $p_query_clauses ) {
  862. $p_query_clauses['select'] = array_unique( $p_query_clauses['select'] );
  863. $p_query_clauses['from'] = array_unique( $p_query_clauses['from'] );
  864. $p_query_clauses['join'] = array_unique( $p_query_clauses['join'] );
  865. return $p_query_clauses;
  866. }
  867. /**
  868. * Build a query with the query clauses array, query for bug count and return the result
  869. * @param array $p_query_clauses
  870. * @return int
  871. */
  872. function filter_get_bug_count( $p_query_clauses ) {
  873. $t_bug_table = db_get_table( 'mantis_bug_table' );
  874. $p_query_clauses = filter_unique_query_clauses( $p_query_clauses );
  875. $t_select_string = "SELECT Count( DISTINCT $t_bug_table.id ) as idcnt ";
  876. $t_from_string = " FROM " . implode( ', ', $p_query_clauses['from'] );
  877. $t_join_string = (( count( $p_query_clauses['join'] ) > 0 ) ? implode( ' ', $p_query_clauses['join'] ) : '' );
  878. $t_where_string = count( $p_query_clauses['project_where']) > 0 ? 'WHERE '. implode( ' AND ', $p_query_clauses['project_where'] ) : '';
  879. if ( count( $p_query_clauses['where'] ) > 0 ) {
  880. $t_where_string .= ' AND ( ';
  881. $t_where_string .= implode( $p_query_clauses['operator'], $p_query_clauses['where'] );
  882. $t_where_string .= ' ) ';
  883. }
  884. $t_result = db_query_bound( "$t_select_string $t_from_string $t_join_string $t_where_string", $p_query_clauses['where_values'] );
  885. return db_result( $t_result );
  886. }
  887. /**
  888. * @todo Had to make all these parameters required because we can't use
  889. * call-time pass by reference anymore. I really preferred not having
  890. * to pass all the params in if you didn't want to, but I wanted to get
  891. * rid of the errors for now. If we can think of a better way later
  892. * (maybe return an object) that would be great.
  893. *
  894. * @param int $p_page_number the page you want to see (set to the actual page on return)
  895. * @param int $p_per_page the number of bugs to see per page (set to actual on return)
  896. * -1 indicates you want to see all bugs
  897. * null indicates you want to use the value specified in the filter
  898. * @param int $p_page_count you don't need to give a value here, the number of pages will be stored here on return
  899. * @param int $p_bug_count you don't need to give a value here, the number of bugs will be stored here on return
  900. * @param mixed $p_custom_filter Filter to use.
  901. * @param int $p_project_id project id to use in filtering.
  902. * @param int $p_user_id user id to use as current user when filtering.
  903. * @param bool $p_show_sticky get sticky issues only.
  904. */
  905. function filter_get_bug_rows( &$p_page_number, &$p_per_page, &$p_page_count, &$p_bug_count, $p_custom_filter = null, $p_project_id = null, $p_user_id = null, $p_show_sticky = null ) {
  906. log_event( LOG_FILTERING, 'START NEW FILTER QUERY' );
  907. $t_bug_table = db_get_table( 'mantis_bug_table' );
  908. $t_bug_text_table = db_get_table( 'mantis_bug_text_table' );
  909. $t_bugnote_table = db_get_table( 'mantis_bugnote_table' );
  910. $t_category_table = db_get_table( 'mantis_category_table' );
  911. $t_custom_field_string_table = db_get_table( 'mantis_custom_field_string_table' );
  912. $t_bugnote_text_table = db_get_table( 'mantis_bugnote_text_table' );
  913. $t_project_table = db_get_table( 'mantis_project_table' );
  914. $t_bug_monitor_table = db_get_table( 'mantis_bug_monitor_table' );
  915. $t_limit_reporters = config_get( 'limit_reporters' );
  916. $t_bug_relationship_table = db_get_table( 'mantis_bug_relationship_table' );
  917. $t_report_bug_threshold = config_get( 'report_bug_threshold' );
  918. $t_where_param_count = 0;
  919. $t_current_user_id = auth_get_current_user_id();
  920. if( null === $p_user_id ) {
  921. $t_user_id = $t_current_user_id;
  922. } else {
  923. $t_user_id = $p_user_id;
  924. }
  925. $c_user_id = db_prepare_int( $t_user_id );
  926. if( null === $p_project_id ) {
  927. # @@@ If project_id is not specified, then use the project id(s) in the filter if set, otherwise, use current project.
  928. $t_project_id = helper_get_current_project();
  929. } else {
  930. $t_project_id = $p_project_id;
  931. }
  932. if( $p_custom_filter === null ) {
  933. # Prefer current_user_get_bug_filter() over user_get_filter() when applicable since it supports
  934. # cookies set by previous version of the code.
  935. if( $t_user_id == $t_current_user_id ) {
  936. $t_filter = current_user_get_bug_filter();
  937. } else {
  938. $t_filter = user_get_bug_filter( $t_user_id, $t_project_id );
  939. }
  940. } else {
  941. $t_filter = $p_custom_filter;
  942. }
  943. $t_filter = filter_ensure_valid_filter( $t_filter );
  944. if( false === $t_filter ) {
  945. return false;
  946. # signify a need to create a cookie
  947. # @@@ error instead?
  948. }
  949. $t_view_type = $t_filter['_view_type'];
  950. // project query clauses must be AND-ed always, irrespective of how the filter
  951. // clauses are requested by the user ( all matching -> AND, any matching -> OR )
  952. $t_where_clauses = array();
  953. $t_project_where_clauses = array(
  954. "$t_project_table.enabled = " . db_param(),
  955. );
  956. $t_where_params = array(
  957. 1,
  958. );
  959. $t_select_clauses = array(
  960. "$t_bug_table.*",
  961. );
  962. $t_from_clauses = array(
  963. $t_bug_table,
  964. );
  965. $t_join_clauses = array(
  966. "JOIN $t_project_table ON $t_project_table.id = $t_bug_table.project_id",
  967. );
  968. // normalize the project filtering into an array $t_project_ids
  969. if( 'simple' == $t_view_type ) {
  970. log_event( LOG_FILTERING, 'Simple Filter' );
  971. $t_project_ids = array(
  972. $t_project_id,
  973. );
  974. $t_include_sub_projects = true;
  975. } else {
  976. log_event( LOG_FILTERING, 'Advanced Filter' );
  977. if( !is_array( $t_filter[FILTER_PROPERTY_PROJECT_ID] ) ) {
  978. $t_project_ids = array(
  979. db_prepare_int( $t_filter[FILTER_PROPERTY_PROJECT_ID] ),
  980. );
  981. } else {
  982. $t_project_ids = array_map( 'db_prepare_int', $t_filter[FILTER_PROPERTY_PROJECT_ID] );
  983. }
  984. $t_include_sub_projects = (( count( $t_project_ids ) == 1 ) && ( ( $t_project_ids[0] == META_FILTER_CURRENT ) || ( $t_project_ids[0] == ALL_PROJECTS ) ) );
  985. }
  986. log_event( LOG_FILTERING, 'project_ids = @P' . implode( ', @P', $t_project_ids ) );
  987. log_event( LOG_FILTERING, 'include sub-projects = ' . ( $t_include_sub_projects ? '1' : '0' ) );
  988. // if the array has ALL_PROJECTS, then reset the array to only contain ALL_PROJECTS.
  989. // replace META_FILTER_CURRENT with the actualy current project id.
  990. $t_all_projects_found = false;
  991. $t_new_project_ids = array();
  992. foreach( $t_project_ids as $t_pid ) {
  993. if( $t_pid == META_FILTER_CURRENT ) {
  994. $t_pid = $t_project_id;
  995. }
  996. if( $t_pid == ALL_PROJECTS ) {
  997. $t_all_projects_found = true;
  998. log_event( LOG_FILTERING, 'all projects selected' );
  999. break;
  1000. }
  1001. // filter out inaccessible projects.
  1002. if( !access_has_project_level( VIEWER, $t_pid, $t_user_id ) ) {
  1003. continue;
  1004. }
  1005. $t_new_project_ids[] = $t_pid;
  1006. }
  1007. $t_projects_query_required = true;
  1008. if( $t_all_projects_found ) {
  1009. if( user_is_administrator( $t_user_id ) ) {
  1010. log_event( LOG_FILTERING, 'all projects + administrator, hence no project filter.' );
  1011. $t_projects_query_required = false;
  1012. } else {
  1013. $t_project_ids = user_get_accessible_projects( $t_user_id );
  1014. }
  1015. } else {
  1016. $t_project_ids = $t_new_project_ids;
  1017. }
  1018. if( $t_projects_query_required ) {
  1019. // expand project ids to include sub-projects
  1020. if( $t_include_sub_projects ) {
  1021. $t_top_project_ids = $t_project_ids;
  1022. foreach( $t_top_project_ids as $t_pid ) {
  1023. log_event( LOG_FILTERING, 'Getting sub-projects for project id @P' . $t_pid );
  1024. $t_subproject_ids = user_get_all_accessible_subprojects( $t_user_id, $t_pid );
  1025. if (!$t_subproject_ids) continue;
  1026. $t_project_ids = array_merge( $t_project_ids, $t_subproject_ids );
  1027. }
  1028. $t_project_ids = array_unique( $t_project_ids );
  1029. }
  1030. // if no projects are accessible, then return an empty array.
  1031. if( count( $t_project_ids ) == 0 ) {
  1032. log_event( LOG_FILTERING, 'no accessible projects' );
  1033. return array();
  1034. }
  1035. log_event( LOG_FILTERING, 'project_ids after including sub-projects = @P' . implode( ', @P', $t_project_ids ) );
  1036. // this array is to be populated with project ids for which we only want to show public issues. This is due to the limited
  1037. // access of the current user.
  1038. $t_public_only_project_ids = array();
  1039. // this array is populated with project ids that the current user has full access to.
  1040. $t_private_and_public_project_ids = array();
  1041. foreach( $t_project_ids as $t_pid ) {
  1042. $t_access_required_to_view_private_bugs = config_get( 'private_bug_threshold', null, null, $t_pid );
  1043. if( access_has_project_level( $t_access_required_to_view_private_bugs, $t_pid, $t_user_id ) ) {
  1044. $t_private_and_public_project_ids[] = $t_pid;
  1045. } else {
  1046. $t_public_only_project_ids[] = $t_pid;
  1047. }
  1048. }
  1049. log_event( LOG_FILTERING, 'project_ids (with public/private access) = @P' . implode( ', @P', $t_private_and_public_project_ids ) );
  1050. log_event( LOG_FILTERING, 'project_ids (with public access) = @P' . implode( ', @P', $t_public_only_project_ids ) );
  1051. $t_count_private_and_public_project_ids = count( $t_private_and_public_project_ids );
  1052. if( $t_count_private_and_public_project_ids == 1 ) {
  1053. $t_private_and_public_query = "( $t_bug_table.project_id = " . $t_private_and_public_project_ids[0] . " )";
  1054. }
  1055. else if( $t_count_private_and_public_project_ids > 1 ) {
  1056. $t_private_and_public_query = "( $t_bug_table.project_id in (" . implode( ', ', $t_private_and_public_project_ids ) . ") )";
  1057. } else {
  1058. $t_private_and_public_query = null;
  1059. }
  1060. $t_count_public_only_project_ids = count( $t_public_only_project_ids );
  1061. $t_public_view_state_check = "( ( $t_bug_table.view_state = " . VS_PUBLIC . " ) OR ( $t_bug_table.reporter_id = $t_user_id ) )";
  1062. if( $t_count_public_only_project_ids == 1 ) {
  1063. $t_public_only_query = "( ( $t_bug_table.project_id = " . $t_public_only_project_ids[0] . " ) AND $t_public_view_state_check )";
  1064. }
  1065. else if( $t_count_public_only_project_ids > 1 ) {
  1066. $t_public_only_query = "( ( $t_bug_table.project_id in (" . implode( ', ', $t_public_only_project_ids ) . ") ) AND $t_public_view_state_check )";
  1067. } else {
  1068. $t_public_only_query = null;
  1069. }
  1070. // both queries can't be null, so we either have one of them or both.
  1071. if( $t_private_and_public_query === null ) {
  1072. $t_project_query = $t_public_only_query;
  1073. } else if( $t_public_only_query === null ) {
  1074. $t_project_query = $t_private_and_public_query;
  1075. } else {
  1076. $t_project_query = "( $t_public_only_query OR $t_private_and_public_query )";
  1077. }
  1078. log_event( LOG_FILTERING, 'project query = ' . $t_project_query );
  1079. array_push( $t_project_where_clauses, $t_project_query );
  1080. }
  1081. # date filter
  1082. if(( 'on' == $t_filter[FILTER_PROPERTY_FILTER_BY_DATE] ) && is_numeric( $t_filter[FILTER_PROPERTY_START_MONTH] ) && is_numeric( $t_filter[FILTER_PROPERTY_START_DAY] ) && is_numeric( $t_filter[FILTER_PROPERTY_START_YEAR] ) && is_numeric( $t_filter[FILTER_PROPERTY_END_MONTH] ) && is_numeric( $t_filter[FILTER_PROPERTY_END_DAY] ) && is_numeric( $t_filter[FILTER_PROPERTY_END_YEAR] ) ) {
  1083. $t_start_string = $t_filter[FILTER_PROPERTY_START_YEAR] . "-" . $t_filter[FILTER_PROPERTY_START_MONTH] . "-" . $t_filter[FILTER_PROPERTY_START_DAY] . " 00:00:00";
  1084. $t_end_string = $t_filter[FILTER_PROPERTY_END_YEAR] . "-" . $t_filter[FILTER_PROPERTY_END_MONTH] . "-" . $t_filter[FILTER_PROPERTY_END_DAY] . " 23:59:59";
  1085. $t_where_params[] = strtotime( $t_start_string );
  1086. $t_where_params[] = strtotime( $t_end_string );
  1087. array_push( $t_project_where_clauses, "($t_bug_table.date_submitted BETWEEN " . db_param() . " AND " . db_param() . " )" );
  1088. }
  1089. # view state
  1090. $t_view_state = db_prepare_int( $t_filter[FILTER_PROPERTY_VIEW_STATE_ID] );
  1091. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_VIEW_STATE_ID] ) ) {
  1092. $t_view_state_query = "($t_bug_table.view_state=" . db_param() . ')';
  1093. log_event( LOG_FILTERING, 'view_state query = ' . $t_view_state_query );
  1094. $t_where_params[] = $t_view_state;
  1095. array_push( $t_where_clauses, $t_view_state_query );
  1096. } else {
  1097. log_event( LOG_FILTERING, 'no view_state query' );
  1098. }
  1099. # reporter
  1100. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_REPORTER_ID] ) ) {
  1101. $t_clauses = array();
  1102. foreach( $t_filter[FILTER_PROPERTY_REPORTER_ID] as $t_filter_member ) {
  1103. if( filter_field_is_none( $t_filter_member ) ) {
  1104. array_push( $t_clauses, "0" );
  1105. } else {
  1106. $c_reporter_id = db_prepare_int( $t_filter_member );
  1107. if( filter_field_is_myself( $c_reporter_id ) ) {
  1108. array_push( $t_clauses, $c_user_id );
  1109. } else {
  1110. array_push( $t_clauses, $c_reporter_id );
  1111. }
  1112. }
  1113. }
  1114. if( 1 < count( $t_clauses ) ) {
  1115. $t_reporter_query = "( $t_bug_table.reporter_id in (" . implode( ', ', $t_clauses ) . ") )";
  1116. } else {
  1117. $t_reporter_query = "( $t_bug_table.reporter_id=$t_clauses[0] )";
  1118. }
  1119. log_event( LOG_FILTERING, 'reporter query = ' . $t_reporter_query );
  1120. array_push( $t_where_clauses, $t_reporter_query );
  1121. } else {
  1122. log_event( LOG_FILTERING, 'no reporter query' );
  1123. }
  1124. # limit reporter
  1125. # @@@ thraxisp - access_has_project_level checks greater than or equal to,
  1126. # this assumed that there aren't any holes above REPORTER where the limit would apply
  1127. #
  1128. if(( ON === $t_limit_reporters ) && ( !access_has_project_level( REPORTER + 1, $t_project_id, $t_user_id ) ) ) {
  1129. $c_reporter_id = $c_user_id;
  1130. $t_where_params[] = $c_reporter_id;
  1131. array_push( $t_where_clauses, "($t_bug_table.reporter_id=" . db_param() . ')' );
  1132. }
  1133. # handler
  1134. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_HANDLER_ID] ) ) {
  1135. $t_clauses = array();
  1136. foreach( $t_filter[FILTER_PROPERTY_HANDLER_ID] as $t_filter_member ) {
  1137. if( filter_field_is_none( $t_filter_member ) ) {
  1138. array_push( $t_clauses, 0 );
  1139. } else {
  1140. $c_handler_id = db_prepare_int( $t_filter_member );
  1141. if( filter_field_is_myself( $c_handler_id ) ) {
  1142. array_push( $t_clauses, $c_user_id );
  1143. } else {
  1144. array_push( $t_clauses, $c_handler_id );
  1145. }
  1146. }
  1147. }
  1148. if( 1 < count( $t_clauses ) ) {
  1149. $t_handler_query = "( $t_bug_table.handler_id in (" . implode( ', ', $t_clauses ) . ") )";
  1150. } else {
  1151. $t_handler_query = "( $t_bug_table.handler_id=$t_clauses[0] )";
  1152. }
  1153. log_event( LOG_FILTERING, 'handler query = ' . $t_handler_query );
  1154. array_push( $t_where_clauses, $t_handler_query );
  1155. } else {
  1156. log_event( LOG_FILTERING, 'no handler query' );
  1157. }
  1158. # category
  1159. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_CATEGORY] ) ) {
  1160. $t_clauses = array();
  1161. foreach( $t_filter[FILTER_PROPERTY_CATEGORY] as $t_filter_member ) {
  1162. if( !filter_field_is_none( $t_filter_member ) ) {
  1163. array_push( $t_clauses, $t_filter_member );
  1164. }
  1165. }
  1166. if( 1 < count( $t_clauses ) ) {
  1167. $t_where_tmp = array();
  1168. foreach( $t_clauses as $t_clause ) {
  1169. $t_where_tmp[] = db_param();
  1170. $t_where_params[] = $t_clause;
  1171. }
  1172. array_push( $t_where_clauses, "( $t_bug_table.category_id in ( SELECT id FROM $t_category_table WHERE name in (" . implode( ', ', $t_where_tmp ) . ") ) )" );
  1173. } else {
  1174. $t_where_params[] = $t_clauses[0];
  1175. array_push( $t_where_clauses, "( $t_bug_table.category_id in ( SELECT id FROM $t_category_table WHERE name=" . db_param() . ") )" );
  1176. }
  1177. }
  1178. # severity
  1179. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_SEVERITY_ID] ) ) {
  1180. $t_clauses = array();
  1181. foreach( $t_filter[FILTER_PROPERTY_SEVERITY_ID] as $t_filter_member ) {
  1182. $c_show_severity = db_prepare_int( $t_filter_member );
  1183. array_push( $t_clauses, $c_show_severity );
  1184. }
  1185. if( 1 < count( $t_clauses ) ) {
  1186. $t_where_tmp = array();
  1187. foreach( $t_clauses as $t_clause ) {
  1188. $t_where_tmp[] = db_param();
  1189. $t_where_params[] = $t_clause;
  1190. }
  1191. array_push( $t_where_clauses, "( $t_bug_table.severity in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1192. } else {
  1193. $t_where_params[] = $t_clauses[0];
  1194. array_push( $t_where_clauses, "( $t_bug_table.severity=" . db_param() . " )" );
  1195. }
  1196. }
  1197. # show / hide status
  1198. # take a list of all available statuses then remove the ones that we want hidden, then make sure
  1199. # the ones we want shown are still available
  1200. $t_desired_statuses = array();
  1201. $t_available_statuses = MantisEnum::getValues( config_get( 'status_enum_string' ) );
  1202. if( 'simple' == $t_filter['_view_type'] ) {
  1203. # simple filtering: if showing any, restrict by the hide status value, otherwise ignore the hide
  1204. $t_any_found = false;
  1205. $t_this_status = $t_filter[FILTER_PROPERTY_STATUS_ID][0];
  1206. $t_this_hide_status = $t_filter[FILTER_PROPERTY_HIDE_STATUS_ID][0];
  1207. if( filter_field_is_any( $t_this_status ) ) {
  1208. foreach( $t_available_statuses as $t_this_available_status ) {
  1209. if( $t_this_hide_status > $t_this_available_status ) {
  1210. $t_desired_statuses[] = $t_this_available_status;
  1211. }
  1212. }
  1213. } else {
  1214. $t_desired_statuses[] = $t_this_status;
  1215. }
  1216. } else {
  1217. # advanced filtering: ignore the hide
  1218. if( filter_field_is_any( $t_filter[FILTER_PROPERTY_STATUS_ID] ) ) {
  1219. $t_desired_statuses = array();
  1220. } else {
  1221. foreach( $t_filter[FILTER_PROPERTY_STATUS_ID] as $t_this_status ) {
  1222. $t_desired_statuses[] = $t_this_status;
  1223. }
  1224. }
  1225. }
  1226. if( count( $t_desired_statuses ) > 0 ) {
  1227. $t_clauses = array();
  1228. foreach( $t_desired_statuses as $t_filter_member ) {
  1229. $c_show_status = db_prepare_int( $t_filter_member );
  1230. array_push( $t_clauses, $c_show_status );
  1231. }
  1232. if( 1 < count( $t_clauses ) ) {
  1233. $t_where_tmp = array();
  1234. foreach( $t_clauses as $t_clause ) {
  1235. $t_where_tmp[] = db_param();
  1236. $t_where_params[] = $t_clause;
  1237. }
  1238. array_push( $t_where_clauses, "( $t_bug_table.status in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1239. } else {
  1240. $t_where_params[] = $t_clauses[0];
  1241. array_push( $t_where_clauses, "( $t_bug_table.status=" . db_param() . " )" );
  1242. }
  1243. }
  1244. # resolution
  1245. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_RESOLUTION_ID] ) ) {
  1246. $t_clauses = array();
  1247. foreach( $t_filter[FILTER_PROPERTY_RESOLUTION_ID] as $t_filter_member ) {
  1248. $c_show_resolution = db_prepare_int( $t_filter_member );
  1249. array_push( $t_clauses, $c_show_resolution );
  1250. }
  1251. if( 1 < count( $t_clauses ) ) {
  1252. $t_where_tmp = array();
  1253. foreach( $t_clauses as $t_clause ) {
  1254. $t_where_tmp[] = db_param();
  1255. $t_where_params[] = $t_clause;
  1256. }
  1257. array_push( $t_where_clauses, "( $t_bug_table.resolution in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1258. } else {
  1259. $t_where_params[] = $t_clauses[0];
  1260. array_push( $t_where_clauses, "( $t_bug_table.resolution=" . db_param() . " )" );
  1261. }
  1262. }
  1263. # priority
  1264. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_PRIORITY_ID] ) ) {
  1265. $t_clauses = array();
  1266. foreach( $t_filter[FILTER_PROPERTY_PRIORITY_ID] as $t_filter_member ) {
  1267. $c_show_priority = db_prepare_int( $t_filter_member );
  1268. array_push( $t_clauses, $c_show_priority );
  1269. }
  1270. if( 1 < count( $t_clauses ) ) {
  1271. $t_where_tmp = array();
  1272. foreach( $t_clauses as $t_clause ) {
  1273. $t_where_tmp[] = db_param();
  1274. $t_where_params[] = $t_clause;
  1275. }
  1276. array_push( $t_where_clauses, "( $t_bug_table.priority in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1277. } else {
  1278. $t_where_params[] = $t_clauses[0];
  1279. array_push( $t_where_clauses, "( $t_bug_table.priority=" . db_param() . " )" );
  1280. }
  1281. }
  1282. # product build
  1283. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_PRODUCT_BUILD] ) ) {
  1284. $t_clauses = array();
  1285. foreach( $t_filter[FILTER_PROPERTY_PRODUCT_BUILD] as $t_filter_member ) {
  1286. $t_filter_member = stripslashes( $t_filter_member );
  1287. if( filter_field_is_none( $t_filter_member ) ) {
  1288. array_push( $t_clauses, '' );
  1289. } else {
  1290. $c_show_build = db_prepare_string( $t_filter_member );
  1291. array_push( $t_clauses, $c_show_build );
  1292. }
  1293. }
  1294. if( 1 < count( $t_clauses ) ) {
  1295. $t_where_tmp = array();
  1296. foreach( $t_clauses as $t_clause ) {
  1297. $t_where_tmp[] = db_param();
  1298. $t_where_params[] = $t_clause;
  1299. }
  1300. array_push( $t_where_clauses, "( $t_bug_table.build in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1301. } else {
  1302. $t_where_params[] = $t_clauses[0];
  1303. array_push( $t_where_clauses, "( $t_bug_table.build=" . db_param() . " )" );
  1304. }
  1305. }
  1306. # product version
  1307. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_PRODUCT_VERSION] ) ) {
  1308. $t_clauses = array();
  1309. foreach( $t_filter[FILTER_PROPERTY_PRODUCT_VERSION] as $t_filter_member ) {
  1310. $t_filter_member = stripslashes( $t_filter_member );
  1311. if( filter_field_is_none( $t_filter_member ) ) {
  1312. array_push( $t_clauses, '' );
  1313. } else {
  1314. $c_show_version = db_prepare_string( $t_filter_member );
  1315. array_push( $t_clauses, $c_show_version );
  1316. }
  1317. }
  1318. if( 1 < count( $t_clauses ) ) {
  1319. $t_where_tmp = array();
  1320. foreach( $t_clauses as $t_clause ) {
  1321. $t_where_tmp[] = db_param();
  1322. $t_where_params[] = $t_clause;
  1323. }
  1324. array_push( $t_where_clauses, "( $t_bug_table.version in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1325. } else {
  1326. $t_where_params[] = $t_clauses[0];
  1327. array_push( $t_where_clauses, "( $t_bug_table.version=" . db_param() . " )" );
  1328. }
  1329. }
  1330. # profile
  1331. if( !filter_field_is_any( $t_filter['show_profile'] ) ) {
  1332. $t_clauses = array();
  1333. foreach( $t_filter['show_profile'] as $t_filter_member ) {
  1334. $t_filter_member = stripslashes( $t_filter_member );
  1335. if( filter_field_is_none( $t_filter_member ) ) {
  1336. array_push( $t_clauses, "0" );
  1337. } else {
  1338. $c_show_profile = db_prepare_int( $t_filter_member );
  1339. array_push( $t_clauses, "$c_show_profile" );
  1340. }
  1341. }
  1342. if( 1 < count( $t_clauses ) ) {
  1343. $t_where_tmp = array();
  1344. foreach( $t_clauses as $t_clause ) {
  1345. $t_where_tmp[] = db_param();
  1346. $t_where_params[] = $t_clause;
  1347. }
  1348. array_push( $t_where_clauses, "( $t_bug_table.profile_id in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1349. } else {
  1350. $t_where_params[] = $t_clauses[0];
  1351. array_push( $t_where_clauses, "( $t_bug_table.profile_id=" . db_param() . " )" );
  1352. }
  1353. }
  1354. # platform
  1355. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_PLATFORM] ) ) {
  1356. $t_clauses = array();
  1357. foreach( $t_filter[FILTER_PROPERTY_PLATFORM] as $t_filter_member ) {
  1358. $t_filter_member = stripslashes( $t_filter_member );
  1359. if( filter_field_is_none( $t_filter_member ) ) {
  1360. array_push( $t_clauses, '' );
  1361. } else {
  1362. $c_platform = db_prepare_string( $t_filter_member );
  1363. array_push( $t_clauses, $c_platform );
  1364. }
  1365. }
  1366. if( 1 < count( $t_clauses ) ) {
  1367. $t_where_tmp = array();
  1368. foreach( $t_clauses as $t_clause ) {
  1369. $t_where_tmp[] = db_param();
  1370. $t_where_params[] = $t_clause;
  1371. }
  1372. array_push( $t_where_clauses, "( $t_bug_table.platform in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1373. } else {
  1374. $t_where_params[] = $t_clauses[0];
  1375. array_push( $t_where_clauses, "( $t_bug_table.platform = " . db_param() . " )" );
  1376. }
  1377. }
  1378. # os
  1379. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_OS] ) ) {
  1380. $t_clauses = array();
  1381. foreach( $t_filter[FILTER_PROPERTY_OS] as $t_filter_member ) {
  1382. $t_filter_member = stripslashes( $t_filter_member );
  1383. if( filter_field_is_none( $t_filter_member ) ) {
  1384. array_push( $t_clauses, '' );
  1385. } else {
  1386. $c_os = db_prepare_string( $t_filter_member );
  1387. array_push( $t_clauses, $c_os );
  1388. }
  1389. }
  1390. if( 1 < count( $t_clauses ) ) {
  1391. $t_where_tmp = array();
  1392. foreach( $t_clauses as $t_clause ) {
  1393. $t_where_tmp[] = db_param();
  1394. $t_where_params[] = $t_clause;
  1395. }
  1396. array_push( $t_where_clauses, "( $t_bug_table.os in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1397. } else {
  1398. $t_where_params[] = $t_clauses[0];
  1399. array_push( $t_where_clauses, "( $t_bug_table.os = " . db_param() . " )" );
  1400. }
  1401. }
  1402. # os_build
  1403. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_OS_BUILD] ) ) {
  1404. $t_clauses = array();
  1405. foreach( $t_filter[FILTER_PROPERTY_OS_BUILD] as $t_filter_member ) {
  1406. $t_filter_member = stripslashes( $t_filter_member );
  1407. if( filter_field_is_none( $t_filter_member ) ) {
  1408. array_push( $t_clauses, '' );
  1409. } else {
  1410. $c_os_build = db_prepare_string( $t_filter_member );
  1411. array_push( $t_clauses, $c_os_build );
  1412. }
  1413. }
  1414. if( 1 < count( $t_clauses ) ) {
  1415. $t_where_tmp = array();
  1416. foreach( $t_clauses as $t_clause ) {
  1417. $t_where_tmp[] = db_param();
  1418. $t_where_params[] = $t_clause;
  1419. }
  1420. array_push( $t_where_clauses, "( $t_bug_table.os_build in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1421. } else {
  1422. $t_where_params[] = $t_clauses[0];
  1423. array_push( $t_where_clauses, "( $t_bug_table.os_build = " . db_param() . " )" );
  1424. }
  1425. }
  1426. # fixed in version
  1427. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_FIXED_IN_VERSION] ) ) {
  1428. $t_clauses = array();
  1429. foreach( $t_filter[FILTER_PROPERTY_FIXED_IN_VERSION] as $t_filter_member ) {
  1430. $t_filter_member = stripslashes( $t_filter_member );
  1431. if( filter_field_is_none( $t_filter_member ) ) {
  1432. array_push( $t_clauses, '' );
  1433. } else {
  1434. $c_fixed_in_version = db_prepare_string( $t_filter_member );
  1435. array_push( $t_clauses, $c_fixed_in_version );
  1436. }
  1437. }
  1438. if( 1 < count( $t_clauses ) ) {
  1439. $t_where_tmp = array();
  1440. foreach( $t_clauses as $t_clause ) {
  1441. $t_where_tmp[] = db_param();
  1442. $t_where_params[] = $t_clause;
  1443. }
  1444. array_push( $t_where_clauses, "( $t_bug_table.fixed_in_version in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1445. } else {
  1446. $t_where_params[] = $t_clauses[0];
  1447. array_push( $t_where_clauses, "( $t_bug_table.fixed_in_version=" . db_param() . " )" );
  1448. }
  1449. }
  1450. # target version
  1451. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_TARGET_VERSION] ) ) {
  1452. $t_clauses = array();
  1453. foreach( $t_filter[FILTER_PROPERTY_TARGET_VERSION] as $t_filter_member ) {
  1454. $t_filter_member = stripslashes( $t_filter_member );
  1455. if( filter_field_is_none( $t_filter_member ) ) {
  1456. array_push( $t_clauses, '' );
  1457. } else {
  1458. $c_target_version = db_prepare_string( $t_filter_member );
  1459. array_push( $t_clauses, $c_target_version );
  1460. }
  1461. }
  1462. # echo var_dump( $t_clauses ); exit;
  1463. if( 1 < count( $t_clauses ) ) {
  1464. $t_where_tmp = array();
  1465. foreach( $t_clauses as $t_clause ) {
  1466. $t_where_tmp[] = db_param();
  1467. $t_where_params[] = $t_clause;
  1468. }
  1469. array_push( $t_where_clauses, "( $t_bug_table.target_version in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1470. } else {
  1471. $t_where_params[] = $t_clauses[0];
  1472. array_push( $t_where_clauses, "( $t_bug_table.target_version=" . db_param() . " )" );
  1473. }
  1474. }
  1475. # users monitoring a bug
  1476. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_MONITOR_USER_ID] ) ) {
  1477. $t_clauses = array();
  1478. $t_table_name = 'user_monitor';
  1479. array_push( $t_join_clauses, "LEFT JOIN $t_bug_monitor_table $t_table_name ON $t_table_name.bug_id = $t_bug_table.id" );
  1480. foreach( $t_filter[FILTER_PROPERTY_MONITOR_USER_ID] as $t_filter_member ) {
  1481. $c_user_monitor = db_prepare_int( $t_filter_member );
  1482. if( filter_field_is_myself( $c_user_monitor ) ) {
  1483. array_push( $t_clauses, $c_user_id );
  1484. } else {
  1485. array_push( $t_clauses, $c_user_monitor );
  1486. }
  1487. }
  1488. if( 1 < count( $t_clauses ) ) {
  1489. $t_where_tmp = array();
  1490. foreach( $t_clauses as $t_clause ) {
  1491. $t_where_tmp[] = db_param();
  1492. $t_where_params[] = $t_clause;
  1493. }
  1494. array_push( $t_where_clauses, "( $t_table_name.user_id in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1495. } else {
  1496. $t_where_params[] = $t_clauses[0];
  1497. array_push( $t_where_clauses, "( $t_table_name.user_id=" . db_param() . " )" );
  1498. }
  1499. }
  1500. # bug relationship
  1501. $t_any_found = false;
  1502. $c_rel_type = $t_filter[FILTER_PROPERTY_RELATIONSHIP_TYPE];
  1503. $c_rel_bug = $t_filter[FILTER_PROPERTY_RELATIONSHIP_BUG];
  1504. if( -1 == $c_rel_type || 0 == $c_rel_bug ) {
  1505. $t_any_found = true;
  1506. }
  1507. if( !$t_any_found ) {
  1508. # use the complementary type
  1509. $t_comp_type = relationship_get_complementary_type( $c_rel_type );
  1510. $t_clauses = array();
  1511. $t_table_name = 'relationship';
  1512. array_push( $t_join_clauses, "LEFT JOIN $t_bug_relationship_table $t_table_name ON $t_table_name.destination_bug_id = $t_bug_table.id" );
  1513. array_push( $t_join_clauses, "LEFT JOIN $t_bug_relationship_table ${t_table_name}2 ON ${t_table_name}2.source_bug_id = $t_bug_table.id" );
  1514. // get reverse relationships
  1515. $t_where_params[] = $t_comp_type;
  1516. $t_where_params[] = $c_rel_bug;
  1517. $t_where_params[] = $c_rel_type;
  1518. $t_where_params[] = $c_rel_bug;
  1519. array_push( $t_clauses, "($t_table_name.relationship_type=" . db_param() . " AND $t_table_name.source_bug_id=" . db_param() . ')' );
  1520. array_push( $t_clauses, "($t_table_name" . "2.relationship_type=" . db_param() . " AND $t_table_name" . "2.destination_bug_id=" . db_param() . ')' );
  1521. array_push( $t_where_clauses, '(' . implode( ' OR ', $t_clauses ) . ')' );
  1522. }
  1523. # tags
  1524. $c_tag_string = trim( $t_filter[FILTER_PROPERTY_TAG_STRING] );
  1525. $c_tag_select = trim( $t_filter[FILTER_PROPERTY_TAG_SELECT] );
  1526. if( is_blank( $c_tag_string ) && !is_blank( $c_tag_select ) && $c_tag_select != 0 ) {
  1527. $t_tag = tag_get( $c_tag_select );
  1528. $c_tag_string = $t_tag['name'];
  1529. }
  1530. if( !is_blank( $c_tag_string ) ) {
  1531. $t_tags = tag_parse_filters( $c_tag_string );
  1532. if( count( $t_tags ) ) {
  1533. $t_tags_all = array();
  1534. $t_tags_any = array();
  1535. $t_tags_none = array();
  1536. foreach( $t_tags as $t_tag_row ) {
  1537. switch( $t_tag_row['filter'] ) {
  1538. case 1:
  1539. $t_tags_all[] = $t_tag_row;
  1540. break;
  1541. case 0:
  1542. $t_tags_any[] = $t_tag_row;
  1543. break;
  1544. case -1:
  1545. $t_tags_none[] = $t_tag_row;
  1546. break;
  1547. }
  1548. }
  1549. if( 0 < $t_filter[FILTER_PROPERTY_TAG_SELECT] && tag_exists( $t_filter[FILTER_PROPERTY_TAG_SELECT] ) ) {
  1550. $t_tags_any[] = tag_get( $t_filter[FILTER_PROPERTY_TAG_SELECT] );
  1551. }
  1552. $t_bug_tag_table = db_get_table( 'mantis_bug_tag_table' );
  1553. if( count( $t_tags_all ) ) {
  1554. $t_clauses = array();
  1555. foreach( $t_tags_all as $t_tag_row ) {
  1556. array_push( $t_clauses, "$t_bug_table.id IN ( SELECT bug_id FROM $t_bug_tag_table WHERE $t_bug_tag_table.tag_id = $t_tag_row[id] )" );
  1557. }
  1558. array_push( $t_where_clauses, '(' . implode( ' AND ', $t_clauses ) . ')' );
  1559. }
  1560. if( count( $t_tags_any ) ) {
  1561. $t_clauses = array();
  1562. foreach( $t_tags_any as $t_tag_row ) {
  1563. array_push( $t_clauses, "$t_bug_tag_table.tag_id = $t_tag_row[id]" );
  1564. }
  1565. array_push( $t_where_clauses, "$t_bug_table.id IN ( SELECT bug_id FROM $t_bug_tag_table WHERE ( " . implode( ' OR ', $t_clauses ) . ') )' );
  1566. }
  1567. if( count( $t_tags_none ) ) {
  1568. $t_clauses = array();
  1569. foreach( $t_tags_none as $t_tag_row ) {
  1570. array_push( $t_clauses, "$t_bug_tag_table.tag_id = $t_tag_row[id]" );
  1571. }
  1572. array_push( $t_where_clauses, "$t_bug_table.id NOT IN ( SELECT bug_id FROM $t_bug_tag_table WHERE ( " . implode( ' OR ', $t_clauses ) . ') )' );
  1573. }
  1574. }
  1575. }
  1576. # note user id
  1577. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_NOTE_USER_ID] ) ) {
  1578. $t_bugnote_table_alias = 'mbnt';
  1579. $t_clauses = array();
  1580. array_push( $t_join_clauses, "LEFT JOIN $t_bugnote_table $t_bugnote_table_alias ON $t_bug_table.id = $t_bugnote_table_alias.bug_id" );
  1581. foreach( $t_filter[FILTER_PROPERTY_NOTE_USER_ID] as $t_filter_member ) {
  1582. $c_note_user_id = db_prepare_int( $t_filter_member );
  1583. if( filter_field_is_myself( $c_note_user_id ) ) {
  1584. array_push( $t_clauses, $c_user_id );
  1585. } else {
  1586. array_push( $t_clauses, $c_note_user_id );
  1587. }
  1588. }
  1589. if( 1 < count( $t_clauses ) ) {
  1590. $t_where_tmp = array();
  1591. foreach( $t_clauses as $t_clause ) {
  1592. $t_where_tmp[] = db_param();
  1593. $t_where_params[] = $t_clause;
  1594. }
  1595. array_push( $t_where_clauses, "( $t_bugnote_table_alias.reporter_id in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1596. } else {
  1597. $t_where_params[] = $t_clauses[0];
  1598. array_push( $t_where_clauses, "( $t_bugnote_table_alias.reporter_id=" . db_param() . " )" );
  1599. }
  1600. }
  1601. # plugin filters
  1602. $t_plugin_filters = filter_get_plugin_filters();
  1603. foreach( $t_plugin_filters as $t_field_name => $t_filter_object ) {
  1604. if ( !filter_field_is_any( $t_filter[ $t_field_name ] ) || $t_filter_object->type == FILTER_TYPE_BOOLEAN ) {
  1605. $t_filter_query = $t_filter_object->query( $t_filter[ $t_field_name ] );
  1606. if ( is_array( $t_filter_query ) ) {
  1607. if ( isset( $t_filter_query['join'] ) ) {
  1608. array_push( $t_join_clauses, $t_filter_query['join'] );
  1609. }
  1610. if ( isset( $t_filter_query['where'] ) ) {
  1611. array_push( $t_where_clauses, $t_filter_query['where'] );
  1612. }
  1613. if ( isset( $t_filter_query['params'] ) && is_array( $t_filter_query['params'] ) ) {
  1614. $t_where_params = array_merge( $t_where_params, $t_filter_query['params'] );
  1615. }
  1616. }
  1617. }
  1618. }
  1619. # custom field filters
  1620. if( ON == config_get( 'filter_by_custom_fields' ) ) {
  1621. # custom field filtering
  1622. # @@@ At the moment this gets the linked fields relating to the current project
  1623. # It should get the ones relating to the project in the filter or all projects
  1624. # if multiple projects.
  1625. $t_custom_fields = custom_field_get_linked_ids( $t_project_id );
  1626. foreach( $t_custom_fields as $t_cfid ) {
  1627. $t_field_info = custom_field_cache_row( $t_cfid, true );
  1628. if( !$t_field_info['filter_by'] ) {
  1629. continue;
  1630. # skip this custom field it shouldn't be filterable
  1631. }
  1632. $t_custom_where_clause = '';
  1633. # Ignore all custom filters that are not set, or that are set to '' or "any"
  1634. if( !filter_field_is_any( $t_filter['custom_fields'][$t_cfid] ) ) {
  1635. $t_def = custom_field_get_definition( $t_cfid );
  1636. $t_table_name = $t_custom_field_string_table . '_' . $t_cfid;
  1637. # We need to filter each joined table or the result query will explode in dimensions
  1638. # Each custom field will result in a exponential growth like Number_of_Issues^Number_of_Custom_Fields
  1639. # and only after this process ends (if it is able to) the result query will be filtered
  1640. # by the WHERE clause and by the DISTINCT clause
  1641. $t_cf_join_clause = "LEFT JOIN $t_custom_field_string_table $t_table_name ON $t_bug_table.id = $t_table_name.bug_id AND $t_table_name.field_id = $t_cfid";
  1642. if( $t_def['type'] == CUSTOM_FIELD_TYPE_DATE ) {
  1643. switch( $t_filter['custom_fields'][$t_cfid][0] ) {
  1644. case CUSTOM_FIELD_DATE_ANY:
  1645. break;
  1646. case CUSTOM_FIELD_DATE_NONE:
  1647. array_push( $t_join_clauses, $t_cf_join_clause );
  1648. $t_custom_where_clause = '(( ' . $t_table_name . '.bug_id is null) OR ( ' . $t_table_name . '.value = 0)';
  1649. break;
  1650. case CUSTOM_FIELD_DATE_BEFORE:
  1651. array_push( $t_join_clauses, $t_cf_join_clause );
  1652. $t_custom_where_clause = '(( ' . $t_table_name . '.value != 0 AND (' . $t_table_name . '.value+0) < ' . ( $t_filter['custom_fields'][$t_cfid][2] ) . ')';
  1653. break;
  1654. case CUSTOM_FIELD_DATE_AFTER:
  1655. array_push( $t_join_clauses, $t_cf_join_clause );
  1656. $t_custom_where_clause = '( (' . $t_table_name . '.value+0) > ' . ( $t_filter['custom_fields'][$t_cfid][1] + 1 );
  1657. break;
  1658. default:
  1659. array_push( $t_join_clauses, $t_cf_join_clause );
  1660. $t_custom_where_clause = '( (' . $t_table_name . '.value+0) BETWEEN ' . $t_filter['custom_fields'][$t_cfid][1] . ' AND ' . $t_filter['custom_fields'][$t_cfid][2];
  1661. break;
  1662. }
  1663. } else {
  1664. array_push( $t_join_clauses, $t_cf_join_clause );
  1665. $t_filter_array = array();
  1666. foreach( $t_filter['custom_fields'][$t_cfid] as $t_filter_member ) {
  1667. $t_filter_member = stripslashes( $t_filter_member );
  1668. if( filter_field_is_none( $t_filter_member ) ) {
  1669. # coerce filter value if selecting META_FILTER_NONE so it will match empty fields
  1670. $t_filter_member = '';
  1671. # but also add those _not_ present in the custom field string table
  1672. array_push( $t_filter_array, "$t_bug_table.id NOT IN (SELECT bug_id FROM $t_custom_field_string_table WHERE field_id=$t_cfid)" );
  1673. }
  1674. switch( $t_def['type'] ) {
  1675. case CUSTOM_FIELD_TYPE_CHECKBOX:
  1676. case CUSTOM_FIELD_TYPE_MULTILIST:
  1677. if( $t_filter_member != '' ) {
  1678. $t_filter_member = '%|' . $t_filter_member . '|%';
  1679. }
  1680. $t_where_params[] = $t_filter_member;
  1681. array_push( $t_filter_array, db_helper_like( "$t_table_name.value" ) );
  1682. break;
  1683. default:
  1684. $t_where_params[] = $t_filter_member;
  1685. array_push( $t_filter_array, "$t_table_name.value = " . db_param() );
  1686. }
  1687. }
  1688. $t_custom_where_clause .= '(' . implode( ' OR ', $t_filter_array );
  1689. }
  1690. if( !is_blank( $t_custom_where_clause ) ) {
  1691. array_push( $t_where_clauses, $t_custom_where_clause . ')' );
  1692. }
  1693. }
  1694. }
  1695. }
  1696. # Text search
  1697. if( !is_blank( $t_filter[FILTER_PROPERTY_FREE_TEXT] ) ) {
  1698. # break up search terms by spacing or quoting
  1699. preg_match_all( "/-?([^'\"\s]+|\"[^\"]+\"|'[^']+')/", $t_filter[FILTER_PROPERTY_FREE_TEXT], $t_matches, PREG_SET_ORDER );
  1700. # organize terms without quoting, paying attention to negation
  1701. $t_search_terms = array();
  1702. foreach( $t_matches as $t_match ) {
  1703. $t_search_terms[ trim( $t_match[1], "\'\"" ) ] = ( $t_match[0][0] == '-' );
  1704. }
  1705. # build a big where-clause and param list for all search terms, including negations
  1706. $t_first = true;
  1707. $t_textsearch_where_clause = "( ";
  1708. foreach( $t_search_terms as $t_search_term => $t_negate ) {
  1709. if ( !$t_first ) {
  1710. $t_textsearch_where_clause .= ' AND ';
  1711. }
  1712. if ( $t_negate ) {
  1713. $t_textsearch_where_clause .= 'NOT ';
  1714. }
  1715. $c_search = '%' . $t_search_term . '%';
  1716. $t_textsearch_where_clause .= '( ' . db_helper_like( 'summary' ) .
  1717. ' OR ' . db_helper_like( "$t_bug_text_table.description" ) .
  1718. ' OR ' . db_helper_like( "$t_bug_text_table.steps_to_reproduce" ) .
  1719. ' OR ' . db_helper_like( "$t_bug_text_table.additional_information" ) .
  1720. ' OR ' . db_helper_like( "$t_bugnote_text_table.note" );
  1721. $t_where_params[] = $c_search;
  1722. $t_where_params[] = $c_search;
  1723. $t_where_params[] = $c_search;
  1724. $t_where_params[] = $c_search;
  1725. $t_where_params[] = $c_search;
  1726. if( is_numeric( $t_search_term ) ) {
  1727. // PostgreSQL on 64-bit OS hack (see #14014)
  1728. if( PHP_INT_MAX > 0x7FFFFFFF && db_is_pgsql() ) {
  1729. $t_search_max = 0x7FFFFFFF;
  1730. } else {
  1731. $t_search_max = PHP_INT_MAX;
  1732. }
  1733. // Note: no need to test negative values, '-' sign has been removed
  1734. if( $t_search_term <= $t_search_max ) {
  1735. $c_search_int = (int) $t_search_term;
  1736. $t_textsearch_where_clause .= " OR $t_bug_table.id = " . db_param();
  1737. $t_textsearch_where_clause .= " OR $t_bugnote_table.id = " . db_param();
  1738. $t_where_params[] = $c_search_int;
  1739. $t_where_params[] = $c_search_int;
  1740. }
  1741. }
  1742. $t_textsearch_where_clause .= ' )';
  1743. $t_first = false;
  1744. }
  1745. $t_textsearch_where_clause .= ' )';
  1746. # add text query elements to arrays
  1747. if ( !$t_first ) {
  1748. $t_join_clauses[] = "JOIN $t_bug_text_table ON $t_bug_table.bug_text_id = $t_bug_text_table.id";
  1749. $t_join_clauses[] = "LEFT JOIN $t_bugnote_table ON $t_bug_table.id = $t_bugnote_table.bug_id";
  1750. # Outer join required otherwise we don't retrieve issues without notes
  1751. $t_join_clauses[] = "LEFT JOIN $t_bugnote_text_table ON $t_bugnote_table.bugnote_text_id = $t_bugnote_text_table.id";
  1752. $t_where_clauses[] = $t_textsearch_where_clause;
  1753. }
  1754. }
  1755. # End text search
  1756. # Determine join operator
  1757. if ( $t_filter[FILTER_PROPERTY_MATCH_TYPE] == FILTER_MATCH_ANY )
  1758. $t_join_operator = ' OR ';
  1759. else
  1760. $t_join_operator = ' AND ';
  1761. log_event(LOG_FILTERING, 'Join operator : ' . $t_join_operator);
  1762. $t_query_clauses['select'] = $t_select_clauses;
  1763. $t_query_clauses['from'] = $t_from_clauses;
  1764. $t_query_clauses['join'] = $t_join_clauses;
  1765. $t_query_clauses['where'] = $t_where_clauses;
  1766. $t_query_clauses['where_values'] = $t_where_params;
  1767. $t_query_clauses['project_where'] = $t_project_where_clauses;
  1768. $t_query_clauses['operator'] = $t_join_operator;
  1769. $t_query_clauses = filter_get_query_sort_data( $t_filter, $p_show_sticky, $t_query_clauses );
  1770. # assigning to $p_* for this function writes the values back in case the caller wants to know
  1771. # Get the total number of bugs that meet the criteria.
  1772. $p_bug_count = filter_get_bug_count( $t_query_clauses );
  1773. if( 0 == $p_bug_count ) {
  1774. return array();
  1775. }
  1776. $p_per_page = filter_per_page( $t_filter, $p_bug_count, $p_per_page );
  1777. $p_page_count = filter_page_count( $p_bug_count, $p_per_page );
  1778. $p_page_number = filter_valid_page_number( $p_page_number, $p_page_count );
  1779. $t_offset = filter_offset( $p_page_number, $p_per_page );
  1780. $t_query_clauses = filter_unique_query_clauses( $t_query_clauses );
  1781. $t_select_string = "SELECT DISTINCT " . implode( ', ', $t_query_clauses['select'] );
  1782. $t_from_string = " FROM " . implode( ', ', $t_query_clauses['from'] );
  1783. $t_order_string = " ORDER BY " . implode( ', ', $t_query_clauses['order'] );
  1784. $t_join_string = count( $t_query_clauses['join'] ) > 0 ? implode( ' ', $t_query_clauses['join'] ) : '';
  1785. $t_where_string = 'WHERE '. implode( ' AND ', $t_query_clauses['project_where'] );
  1786. if ( count( $t_query_clauses['where'] ) > 0 ) {
  1787. $t_where_string .= ' AND ( ';
  1788. $t_where_string .= implode( $t_join_operator, $t_query_clauses['where'] );
  1789. $t_where_string .= ' ) ';
  1790. }
  1791. $t_result = db_query_bound( "$t_select_string $t_from_string $t_join_string $t_where_string $t_order_string", $t_query_clauses['where_values'], $p_per_page, $t_offset );
  1792. $t_row_count = db_num_rows( $t_result );
  1793. $t_id_array_lastmod = array();
  1794. for( $i = 0;$i < $t_row_count;$i++ ) {
  1795. $t_row = db_fetch_array( $t_result );
  1796. $t_id_array_lastmod[] = (int) $t_row['id'];
  1797. $t_rows[] = $t_row;
  1798. }
  1799. return filter_cache_result( $t_rows, $t_id_array_lastmod );
  1800. }
  1801. /**
  1802. * Cache the filter results with bugnote stats for later use
  1803. * @param array $p_rows results of the filter query
  1804. * @param array $p_id_array_lastmod array of bug ids
  1805. * @return array
  1806. */
  1807. function filter_cache_result( $p_rows, $p_id_array_lastmod ) {
  1808. $t_bugnote_table = db_get_table( 'mantis_bugnote_table' );
  1809. $t_id_array_lastmod = array_unique( $p_id_array_lastmod );
  1810. $t_where_string = "WHERE $t_bugnote_table.bug_id in (" . implode( ", ", $t_id_array_lastmod ) . ')';
  1811. $t_query = "SELECT DISTINCT bug_id,MAX(last_modified) as last_modified, COUNT(last_modified) as count FROM $t_bugnote_table $t_where_string GROUP BY bug_id";
  1812. # perform query
  1813. $t_result = db_query_bound( $t_query );
  1814. $t_row_count = db_num_rows( $t_result );
  1815. for( $i = 0;$i < $t_row_count;$i++ ) {
  1816. $t_row = db_fetch_array( $t_result );
  1817. $t_stats[$t_row['bug_id']] = $t_row;
  1818. }
  1819. $t_rows = array();
  1820. foreach( $p_rows as $t_row ) {
  1821. if( !isset( $t_stats[$t_row['id']] ) ) {
  1822. $t_rows[] = bug_row_to_object( bug_cache_database_result( $t_row, false ) );
  1823. } else {
  1824. $t_rows[] = bug_row_to_object( bug_cache_database_result( $t_row, $t_stats[ $t_row['id'] ] ) );
  1825. }
  1826. }
  1827. return $t_rows;
  1828. }
  1829. /**
  1830. * Mainly based on filter_draw_selection_area2() but adds the support for the collapsible
  1831. * filter display.
  1832. * @param int $p_page_number
  1833. * @param bool $p_for_screen
  1834. * @see filter_draw_selection_area2
  1835. */
  1836. function filter_draw_selection_area( $p_page_number, $p_for_screen = true ) {
  1837. collapse_open( 'filter' );
  1838. filter_draw_selection_area2( $p_page_number, $p_for_screen, true );
  1839. collapse_closed( 'filter' );
  1840. filter_draw_selection_area2( $p_page_number, $p_for_screen, false );
  1841. collapse_end( 'filter' );
  1842. }
  1843. /**
  1844. * Prints the filter selection area for both the bug list view screen and
  1845. * the bug list print screen. This function was an attempt to make it easier to
  1846. * add new filters and rearrange them on screen for both pages.
  1847. * @param int $p_page_number
  1848. * @param bool $p_for_screen
  1849. * @param bool $p_expanded
  1850. */
  1851. function filter_draw_selection_area2( $p_page_number, $p_for_screen = true, $p_expanded = true ) {
  1852. $t_form_name_suffix = $p_expanded ? '_open' : '_closed';
  1853. $t_filter = current_user_get_bug_filter();
  1854. $t_filter = filter_ensure_valid_filter( $t_filter );
  1855. $t_project_id = helper_get_current_project();
  1856. $t_page_number = (int) $p_page_number;
  1857. $t_view_type = $t_filter['_view_type'];
  1858. $t_tdclass = 'small-caption';
  1859. $t_trclass = 'row-category2';
  1860. $t_action = 'view_all_set.php?f=3';
  1861. if( $p_for_screen == false ) {
  1862. $t_tdclass = 'print';
  1863. $t_trclass = '';
  1864. $t_action = 'view_all_set.php';
  1865. }
  1866. ?>
  1867. <br />
  1868. <form method="post" name="filters<?php echo $t_form_name_suffix?>" id="filters_form<?php echo $t_form_name_suffix?>" action="<?php echo $t_action;?>">
  1869. <?php # CSRF protection not required here - form does not result in modifications ?>
  1870. <input type="hidden" name="type" value="1" />
  1871. <?php
  1872. if( $p_for_screen == false ) {
  1873. echo '<input type="hidden" name="print" value="1" />';
  1874. echo '<input type="hidden" name="offset" value="0" />';
  1875. }
  1876. ?>
  1877. <input type="hidden" name="page_number" value="<?php echo $t_page_number?>" />
  1878. <input type="hidden" name="view_type" value="<?php echo $t_view_type?>" />
  1879. <table class="width100" cellspacing="1">
  1880. <?php
  1881. $t_filter_cols = config_get( 'filter_custom_fields_per_row' );
  1882. if( $p_expanded ) {
  1883. $t_custom_cols = $t_filter_cols;
  1884. $t_current_user_access_level = current_user_get_access_level();
  1885. $t_accessible_custom_fields_ids = array();
  1886. $t_accessible_custom_fields_names = array();
  1887. $t_accessible_custom_fields_values = array();
  1888. $t_num_custom_rows = 0;
  1889. $t_per_row = 0;
  1890. if( ON == config_get( 'filter_by_custom_fields' ) ) {
  1891. $t_custom_fields = custom_field_get_linked_ids( $t_project_id );
  1892. foreach( $t_custom_fields as $t_cfid ) {
  1893. $t_field_info = custom_field_cache_row( $t_cfid, true );
  1894. if( $t_field_info['access_level_r'] <= $t_current_user_access_level && $t_field_info['filter_by'] ) {
  1895. $t_accessible_custom_fields_ids[] = $t_cfid;
  1896. $t_accessible_custom_fields_names[] = $t_field_info['name'];
  1897. $t_accessible_custom_fields_types[] = $t_field_info['type'];
  1898. $t_accessible_custom_fields_values[] = custom_field_distinct_values( $t_field_info );
  1899. }
  1900. }
  1901. if( count( $t_accessible_custom_fields_ids ) > 0 ) {
  1902. $t_per_row = config_get( 'filter_custom_fields_per_row' );
  1903. $t_num_custom_rows = ceil( count( $t_accessible_custom_fields_ids ) / $t_per_row );
  1904. }
  1905. }
  1906. $t_filters_url = 'view_filters_page.php?for_screen=' . $p_for_screen;
  1907. if( 'advanced' == $t_view_type ) {
  1908. $t_filters_url = $t_filters_url . '&amp;view_type=advanced';
  1909. }
  1910. $t_filters_url = $t_filters_url . '&amp;target_field=';
  1911. $t_show_product_version = version_should_show_product_version( $t_project_id );
  1912. $t_show_build = $t_show_product_version && ( config_get( 'enable_product_build' ) == ON );
  1913. # overload handler_id setting if user isn't supposed to see them (ref #6189)
  1914. if( !access_has_any_project( config_get( 'view_handler_threshold' ) ) ) {
  1915. $t_filter[FILTER_PROPERTY_HANDLER_ID] = array(
  1916. META_FILTER_ANY,
  1917. );
  1918. }
  1919. ?>
  1920. <tr <?php echo "class=\"" . $t_trclass . "\"";?>>
  1921. <td class="small-caption" valign="top">
  1922. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_REPORTER_ID . '[]';?>" id="reporter_id_filter"><?php echo lang_get( 'reporter' )?>:</a>
  1923. </td>
  1924. <td class="small-caption" valign="top">
  1925. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_MONITOR_USER_ID . '[]';?>" id="user_monitor_filter"><?php echo lang_get( 'monitored_by' )?>:</a>
  1926. </td>
  1927. <td class="small-caption" valign="top">
  1928. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_HANDLER_ID . '[]';?>" id="handler_id_filter"><?php echo lang_get( 'assigned_to' )?>:</a>
  1929. </td>
  1930. <td colspan="2" class="small-caption" valign="top">
  1931. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_CATEGORY . '[]';?>" id="show_category_filter"><?php echo lang_get( 'category' )?>:</a>
  1932. </td>
  1933. <td class="small-caption" valign="top">
  1934. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_SEVERITY_ID . '[]';?>" id="show_severity_filter"><?php echo lang_get( 'severity' )?>:</a>
  1935. </td>
  1936. <td class="small-caption" valign="top">
  1937. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_RESOLUTION_ID . '[]';?>" id="show_resolution_filter"><?php echo lang_get( 'resolution' )?>:</a>
  1938. </td>
  1939. <td class="small-caption" valign="top">
  1940. <?php if( ON == config_get( 'enable_profiles' ) ) { ?>
  1941. <a href="<?php echo $t_filters_url . 'show_profile[]';?>" id="show_profile_filter"><?php echo lang_get( 'profile' )?>:</a>
  1942. <?php } ?>
  1943. </td>
  1944. <?php if( $t_filter_cols > 8 ) {
  1945. echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 8 ) . '">&#160;</td>';
  1946. }?>
  1947. </tr>
  1948. <tr class="row-1">
  1949. <td class="small-caption" valign="top" id="reporter_id_filter_target">
  1950. <?php
  1951. $t_output = '';
  1952. $t_any_found = false;
  1953. if( count( $t_filter[FILTER_PROPERTY_REPORTER_ID] ) == 0 ) {
  1954. echo lang_get( 'any' );
  1955. } else {
  1956. $t_first_flag = true;
  1957. foreach( $t_filter[FILTER_PROPERTY_REPORTER_ID] as $t_current ) {
  1958. $t_this_name = '';
  1959. echo '<input type="hidden" name="', FILTER_PROPERTY_REPORTER_ID, '[]" value="', string_attribute( $t_current ), '" />';
  1960. if( filter_field_is_any( $t_current ) ) {
  1961. $t_any_found = true;
  1962. }
  1963. else if( filter_field_is_myself( $t_current ) ) {
  1964. if( access_has_project_level( config_get( 'report_bug_threshold' ) ) ) {
  1965. $t_this_name = '[' . lang_get( 'myself' ) . ']';
  1966. } else {
  1967. $t_any_found = true;
  1968. }
  1969. } else if( filter_field_is_none( $t_current ) ) {
  1970. $t_this_name = lang_get( 'none' );
  1971. } else {
  1972. $t_this_name = user_get_name( $t_current );
  1973. }
  1974. if( $t_first_flag != true ) {
  1975. $t_output = $t_output . '<br />';
  1976. } else {
  1977. $t_first_flag = false;
  1978. }
  1979. $t_output = $t_output . string_display_line( $t_this_name );
  1980. }
  1981. if( true == $t_any_found ) {
  1982. echo lang_get( 'any' );
  1983. } else {
  1984. echo $t_output;
  1985. }
  1986. }
  1987. ?>
  1988. </td>
  1989. <td class="small-caption" valign="top" id="user_monitor_filter_target">
  1990. <?php
  1991. $t_output = '';
  1992. $t_any_found = false;
  1993. if( count( $t_filter[FILTER_PROPERTY_MONITOR_USER_ID] ) == 0 ) {
  1994. echo lang_get( 'any' );
  1995. } else {
  1996. $t_first_flag = true;
  1997. foreach( $t_filter[FILTER_PROPERTY_MONITOR_USER_ID] as $t_current ) {
  1998. echo '<input type="hidden" name="', FILTER_PROPERTY_MONITOR_USER_ID, '[]" value="', string_attribute( $t_current ), '" />';
  1999. $t_this_name = '';
  2000. if( filter_field_is_any( $t_current ) ) {
  2001. $t_any_found = true;
  2002. }
  2003. else if( filter_field_is_myself( $t_current ) ) {
  2004. if( access_has_project_level( config_get( 'monitor_bug_threshold' ) ) ) {
  2005. $t_this_name = '[' . lang_get( 'myself' ) . ']';
  2006. } else {
  2007. $t_any_found = true;
  2008. }
  2009. } else {
  2010. $t_this_name = user_get_name( $t_current );
  2011. }
  2012. if( $t_first_flag != true ) {
  2013. $t_output = $t_output . '<br />';
  2014. } else {
  2015. $t_first_flag = false;
  2016. }
  2017. $t_output = $t_output . string_display_line( $t_this_name );
  2018. }
  2019. if( true == $t_any_found ) {
  2020. echo lang_get( 'any' );
  2021. } else {
  2022. echo string_display( $t_output );
  2023. }
  2024. }
  2025. ?>
  2026. </td>
  2027. <td class="small-caption" valign="top" id="handler_id_filter_target">
  2028. <?php
  2029. $t_output = '';
  2030. $t_any_found = false;
  2031. if( count( $t_filter[FILTER_PROPERTY_HANDLER_ID] ) == 0 ) {
  2032. echo lang_get( 'any' );
  2033. } else {
  2034. $t_first_flag = true;
  2035. foreach( $t_filter[FILTER_PROPERTY_HANDLER_ID] as $t_current ) {
  2036. echo '<input type="hidden" name="', FILTER_PROPERTY_HANDLER_ID, '[]" value="', string_attribute( $t_current ), '" />';
  2037. $t_this_name = '';
  2038. if( filter_field_is_none( $t_current ) ) {
  2039. $t_this_name = lang_get( 'none' );
  2040. } else if( filter_field_is_any( $t_current ) ) {
  2041. $t_any_found = true;
  2042. } else if( filter_field_is_myself( $t_current ) ) {
  2043. if( access_has_project_level( config_get( 'handle_bug_threshold' ) ) ) {
  2044. $t_this_name = '[' . lang_get( 'myself' ) . ']';
  2045. } else {
  2046. $t_any_found = true;
  2047. }
  2048. } else {
  2049. $t_this_name = user_get_name( $t_current );
  2050. }
  2051. if( $t_first_flag != true ) {
  2052. $t_output = $t_output . '<br />';
  2053. } else {
  2054. $t_first_flag = false;
  2055. }
  2056. $t_output = $t_output . string_display_line( $t_this_name );
  2057. }
  2058. if( true == $t_any_found ) {
  2059. echo lang_get( 'any' );
  2060. } else {
  2061. echo string_display( $t_output );
  2062. }
  2063. }
  2064. ?>
  2065. </td>
  2066. <td colspan="2" class="small-caption" valign="top" id="show_category_filter_target">
  2067. <?php
  2068. $t_output = '';
  2069. $t_any_found = false;
  2070. if( count( $t_filter[FILTER_PROPERTY_CATEGORY] ) == 0 ) {
  2071. echo lang_get( 'any' );
  2072. } else {
  2073. $t_first_flag = true;
  2074. foreach( $t_filter[FILTER_PROPERTY_CATEGORY] as $t_current ) {
  2075. echo '<input type="hidden" name="', FILTER_PROPERTY_CATEGORY, '[]" value="', string_attribute( $t_current ), '" />';
  2076. $t_this_string = '';
  2077. if( filter_field_is_any( $t_current ) ) {
  2078. $t_any_found = true;
  2079. } else {
  2080. $t_this_string = $t_current;
  2081. }
  2082. if( $t_first_flag != true ) {
  2083. $t_output = $t_output . '<br />';
  2084. } else {
  2085. $t_first_flag = false;
  2086. }
  2087. $t_output = $t_output . string_display_line( $t_this_string );
  2088. }
  2089. if( true == $t_any_found ) {
  2090. echo lang_get( 'any' );
  2091. } else {
  2092. echo $t_output;
  2093. }
  2094. }
  2095. ?>
  2096. </td>
  2097. <td class="small-caption" valign="top" id="show_severity_filter_target">
  2098. <?php
  2099. $t_output = '';
  2100. $t_any_found = false;
  2101. if( count( $t_filter[FILTER_PROPERTY_SEVERITY_ID] ) == 0 ) {
  2102. echo lang_get( 'any' );
  2103. } else {
  2104. $t_first_flag = true;
  2105. foreach( $t_filter[FILTER_PROPERTY_SEVERITY_ID] as $t_current ) {
  2106. echo '<input type="hidden" name="', FILTER_PROPERTY_SEVERITY_ID, '[]" value="', string_attribute( $t_current ), '" />';
  2107. $t_this_string = '';
  2108. if( filter_field_is_any( $t_current ) ) {
  2109. $t_any_found = true;
  2110. } else {
  2111. $t_this_string = get_enum_element( 'severity', $t_current );
  2112. }
  2113. if( $t_first_flag != true ) {
  2114. $t_output = $t_output . '<br />';
  2115. } else {
  2116. $t_first_flag = false;
  2117. }
  2118. $t_output = $t_output . string_display_line( $t_this_string );
  2119. }
  2120. if( true == $t_any_found ) {
  2121. echo lang_get( 'any' );
  2122. } else {
  2123. echo $t_output;
  2124. }
  2125. }
  2126. ?>
  2127. </td>
  2128. <td class="small-caption" valign="top" id="show_resolution_filter_target">
  2129. <?php
  2130. $t_output = '';
  2131. $t_any_found = false;
  2132. if( count( $t_filter[FILTER_PROPERTY_RESOLUTION_ID] ) == 0 ) {
  2133. echo lang_get( 'any' );
  2134. } else {
  2135. $t_first_flag = true;
  2136. foreach( $t_filter[FILTER_PROPERTY_RESOLUTION_ID] as $t_current ) {
  2137. ?>
  2138. <input type="hidden" name="show_resolution[]" value="<?php echo string_attribute( $t_current );?>" />
  2139. <?php
  2140. $t_this_string = '';
  2141. if( filter_field_is_any( $t_current ) ) {
  2142. $t_any_found = true;
  2143. } else {
  2144. $t_this_string = get_enum_element( 'resolution', $t_current );
  2145. }
  2146. if( $t_first_flag != true ) {
  2147. $t_output = $t_output . '<br />';
  2148. } else {
  2149. $t_first_flag = false;
  2150. }
  2151. $t_output = $t_output . string_display_line( $t_this_string );
  2152. }
  2153. if( true == $t_any_found ) {
  2154. echo lang_get( 'any' );
  2155. } else {
  2156. echo $t_output;
  2157. }
  2158. }
  2159. ?>
  2160. </td>
  2161. <?php if( ON == config_get( 'enable_profiles' ) ) { ?>
  2162. <td class="small-caption" valign="top" id="show_profile_filter_target">
  2163. <?php
  2164. $t_output = '';
  2165. $t_any_found = false;
  2166. if( count( $t_filter['show_profile'] ) == 0 ) {
  2167. echo lang_get( 'any' );
  2168. } else {
  2169. $t_first_flag = true;
  2170. foreach( $t_filter['show_profile'] as $t_current ) {
  2171. ?>
  2172. <input type="hidden" name="show_profile[]" value="<?php echo string_attribute( $t_current );?>" />
  2173. <?php
  2174. $t_this_string = '';
  2175. if( filter_field_is_any( $t_current ) ) {
  2176. $t_any_found = true;
  2177. } else {
  2178. $t_profile = profile_get_row_direct( $t_current );
  2179. $t_this_string = "${t_profile['platform']} ${t_profile['os']} ${t_profile['os_build']}";
  2180. }
  2181. if( $t_first_flag != true ) {
  2182. $t_output = $t_output . '<br />';
  2183. } else {
  2184. $t_first_flag = false;
  2185. }
  2186. $t_output = $t_output . string_display_line( $t_this_string );
  2187. }
  2188. if( true == $t_any_found ) {
  2189. echo lang_get( 'any' );
  2190. } else {
  2191. echo $t_output;
  2192. }
  2193. }
  2194. ?>
  2195. </td>
  2196. <?php } else { ?>
  2197. <td></td>
  2198. <?php }
  2199. if( $t_filter_cols > 8 ) {
  2200. echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 8 ) . '">&#160;</td>';
  2201. }?>
  2202. </tr>
  2203. <tr <?php echo "class=\"" . $t_trclass . "\"";?>>
  2204. <td class="small-caption" valign="top">
  2205. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_STATUS_ID . '[]';?>" id="show_status_filter"><?php echo lang_get( 'status' )?>:</a>
  2206. </td>
  2207. <td class="small-caption" valign="top">
  2208. <?php if( 'simple' == $t_view_type ) {?>
  2209. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_HIDE_STATUS_ID . '[]';?>" id="hide_status_filter"><?php echo lang_get( 'hide_status' )?>:</a>
  2210. <?php
  2211. }?>
  2212. </td>
  2213. <td class="small-caption" valign="top">
  2214. <?php if ( $t_show_build ) { ?>
  2215. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_PRODUCT_BUILD . '[]';?>" id="show_build_filter"><?php echo lang_get( 'product_build' )?>:</a>
  2216. <?php } ?>
  2217. </td>
  2218. <?php if( $t_show_product_version ) {?>
  2219. <td colspan="2" class="small-caption" valign="top">
  2220. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_PRODUCT_VERSION . '[]';?>" id="show_version_filter"><?php echo lang_get( 'product_version' )?>:</a>
  2221. </td>
  2222. <td colspan="1" class="small-caption" valign="top">
  2223. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_FIXED_IN_VERSION . '[]';?>" id="show_fixed_in_version_filter"><?php echo lang_get( 'fixed_in_version' )?>:</a>
  2224. </td>
  2225. <td colspan="1" class="small-caption" valign="top">
  2226. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_TARGET_VERSION . '[]';?>" id="show_target_version_filter"><?php echo lang_get( 'target_version' )?>:</a>
  2227. </td>
  2228. <?php
  2229. } else {?>
  2230. <td colspan="2" class="small-caption" valign="top">
  2231. &#160;
  2232. </td>
  2233. <td colspan="1" class="small-caption" valign="top">
  2234. &#160;
  2235. </td>
  2236. <td colspan="1" class="small-caption" valign="top">
  2237. &nbsp;
  2238. </td>
  2239. <?php
  2240. }?>
  2241. <td colspan="1" class="small-caption" valign="top">
  2242. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_PRIORITY_ID . '[]';?>" id="show_priority_filter"><?php echo lang_get( 'priority' )?>:</a>
  2243. </td>
  2244. <?php if( $t_filter_cols > 8 ) {
  2245. echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 7 ) . '">&#160;</td>';
  2246. }?>
  2247. </tr>
  2248. <tr class="row-1">
  2249. <td class="small-caption" valign="top" id="show_status_filter_target">
  2250. <?php
  2251. $t_output = '';
  2252. $t_any_found = false;
  2253. if( count( $t_filter[FILTER_PROPERTY_STATUS_ID] ) == 0 ) {
  2254. echo lang_get( 'any' );
  2255. } else {
  2256. $t_first_flag = true;
  2257. foreach( $t_filter[FILTER_PROPERTY_STATUS_ID] as $t_current ) {
  2258. echo '<input type="hidden" name="', FILTER_PROPERTY_STATUS_ID, '[]" value="', string_attribute( $t_current ), '" />';
  2259. $t_this_string = '';
  2260. if( filter_field_is_any( $t_current ) ) {
  2261. $t_any_found = true;
  2262. } else {
  2263. $t_this_string = get_enum_element( 'status', $t_current );
  2264. }
  2265. if( $t_first_flag != true ) {
  2266. $t_output = $t_output . '<br />';
  2267. } else {
  2268. $t_first_flag = false;
  2269. }
  2270. $t_output = $t_output . string_display_line( $t_this_string );
  2271. }
  2272. if( true == $t_any_found ) {
  2273. echo lang_get( 'any' );
  2274. } else {
  2275. echo $t_output;
  2276. }
  2277. }
  2278. ?>
  2279. </td>
  2280. <td class="small-caption" valign="top" id="hide_status_filter_target">
  2281. <?php
  2282. if( 'simple' == $t_view_type ) {
  2283. $t_output = '';
  2284. $t_none_found = false;
  2285. if( count( $t_filter[FILTER_PROPERTY_HIDE_STATUS_ID] ) == 0 ) {
  2286. echo lang_get( 'none' );
  2287. } else {
  2288. $t_first_flag = true;
  2289. foreach( $t_filter[FILTER_PROPERTY_HIDE_STATUS_ID] as $t_current ) {
  2290. echo '<input type="hidden" name="', FILTER_PROPERTY_HIDE_STATUS_ID, '[]" value="', string_attribute( $t_current ), '" />';
  2291. $t_this_string = '';
  2292. if( filter_field_is_none( $t_current ) ) {
  2293. $t_none_found = true;
  2294. } else {
  2295. $t_this_string = get_enum_element( 'status', $t_current );
  2296. }
  2297. if( $t_first_flag != true ) {
  2298. $t_output = $t_output . '<br />';
  2299. } else {
  2300. $t_first_flag = false;
  2301. }
  2302. $t_output = $t_output . string_display_line( $t_this_string );
  2303. }
  2304. $t_hide_status_post = '';
  2305. if( count( $t_filter[FILTER_PROPERTY_HIDE_STATUS_ID] ) == 1 ) {
  2306. $t_hide_status_post = ' (' . lang_get( 'and_above' ) . ')';
  2307. }
  2308. if( true == $t_none_found ) {
  2309. echo lang_get( 'none' );
  2310. } else {
  2311. echo $t_output . string_display_line( $t_hide_status_post );
  2312. }
  2313. }
  2314. }
  2315. ?>
  2316. </td>
  2317. <?php if ( $t_show_build ) { ?>
  2318. <td class="small-caption" valign="top" id="show_build_filter_target">
  2319. <?php
  2320. $t_output = '';
  2321. $t_any_found = false;
  2322. if( count( $t_filter[FILTER_PROPERTY_PRODUCT_BUILD] ) == 0 ) {
  2323. echo lang_get( 'any' );
  2324. } else {
  2325. $t_first_flag = true;
  2326. foreach( $t_filter[FILTER_PROPERTY_PRODUCT_BUILD] as $t_current ) {
  2327. $t_current = stripslashes( $t_current );
  2328. echo '<input type="hidden" name="', FILTER_PROPERTY_PRODUCT_BUILD, '[]" value="', string_attribute( $t_current ), '" />';
  2329. $t_this_string = '';
  2330. if( filter_field_is_any( $t_current ) ) {
  2331. $t_any_found = true;
  2332. } else if( filter_field_is_none( $t_current ) ) {
  2333. $t_this_string = lang_get( 'none' );
  2334. } else {
  2335. $t_this_string = $t_current;
  2336. }
  2337. if( $t_first_flag != true ) {
  2338. $t_output = $t_output . '<br />';
  2339. } else {
  2340. $t_first_flag = false;
  2341. }
  2342. $t_output = $t_output . string_display_line( $t_this_string );
  2343. }
  2344. if( true == $t_any_found ) {
  2345. echo lang_get( 'any' );
  2346. } else {
  2347. echo $t_output;
  2348. }
  2349. }
  2350. ?>
  2351. </td>
  2352. <?php } else { ?>
  2353. <td class="small-caption" valign="top"></td>
  2354. <?php }
  2355. if( $t_show_product_version ) {
  2356. ?>
  2357. <td colspan="2" class="small-caption" valign="top" id="show_version_filter_target">
  2358. <?php
  2359. $t_output = '';
  2360. $t_any_found = false;
  2361. if( count( $t_filter[FILTER_PROPERTY_PRODUCT_VERSION] ) == 0 ) {
  2362. echo lang_get( 'any' );
  2363. } else {
  2364. $t_first_flag = true;
  2365. foreach( $t_filter[FILTER_PROPERTY_PRODUCT_VERSION] as $t_current ) {
  2366. $t_current = stripslashes( $t_current );
  2367. echo '<input type="hidden" name="', FILTER_PROPERTY_PRODUCT_VERSION, '[]" value="', string_attribute( $t_current ), '" />';
  2368. $t_this_string = '';
  2369. if( filter_field_is_any( $t_current ) ) {
  2370. $t_any_found = true;
  2371. }
  2372. else if( filter_field_is_none( $t_current ) ) {
  2373. $t_this_string = lang_get( 'none' );
  2374. } else {
  2375. $t_this_string = $t_current;
  2376. }
  2377. if( $t_first_flag != true ) {
  2378. $t_output = $t_output . '<br />';
  2379. } else {
  2380. $t_first_flag = false;
  2381. }
  2382. $t_output = $t_output . string_display_line( $t_this_string );
  2383. }
  2384. if( true == $t_any_found ) {
  2385. echo lang_get( 'any' );
  2386. } else {
  2387. echo $t_output;
  2388. }
  2389. }
  2390. ?>
  2391. </td>
  2392. <td colspan="1" class="small-caption" valign="top" id="show_fixed_in_version_filter_target">
  2393. <?php
  2394. $t_output = '';
  2395. $t_any_found = false;
  2396. if( count( $t_filter[FILTER_PROPERTY_FIXED_IN_VERSION] ) == 0 ) {
  2397. echo lang_get( 'any' );
  2398. } else {
  2399. $t_first_flag = true;
  2400. foreach( $t_filter[FILTER_PROPERTY_FIXED_IN_VERSION] as $t_current ) {
  2401. $t_current = stripslashes( $t_current );
  2402. echo '<input type="hidden" name="', FILTER_PROPERTY_FIXED_IN_VERSION, '[]" value="', string_attribute( $t_current ), '" />';
  2403. $t_this_string = '';
  2404. if( filter_field_is_any( $t_current ) ) {
  2405. $t_any_found = true;
  2406. } else if( filter_field_is_none( $t_current ) ) {
  2407. $t_this_string = lang_get( 'none' );
  2408. } else {
  2409. $t_this_string = $t_current;
  2410. }
  2411. if( $t_first_flag != true ) {
  2412. $t_output = $t_output . '<br />';
  2413. } else {
  2414. $t_first_flag = false;
  2415. }
  2416. $t_output = $t_output . string_display_line( $t_this_string );
  2417. }
  2418. if( true == $t_any_found ) {
  2419. echo lang_get( 'any' );
  2420. } else {
  2421. echo $t_output;
  2422. }
  2423. }
  2424. ?>
  2425. </td>
  2426. <td colspan="1" class="small-caption" valign="top" id="show_target_version_filter_target">
  2427. <?php
  2428. $t_output = '';
  2429. $t_any_found = false;
  2430. if( count( $t_filter[FILTER_PROPERTY_TARGET_VERSION] ) == 0 ) {
  2431. echo lang_get( 'any' );
  2432. } else {
  2433. $t_first_flag = true;
  2434. foreach( $t_filter[FILTER_PROPERTY_TARGET_VERSION] as $t_current ) {
  2435. $t_current = stripslashes( $t_current );
  2436. echo '<input type="hidden" name="', FILTER_PROPERTY_TARGET_VERSION, '[]" value="', string_attribute( $t_current ), '" />';
  2437. $t_this_string = '';
  2438. if( filter_field_is_any( $t_current ) ) {
  2439. $t_any_found = true;
  2440. } else if( filter_field_is_none( $t_current ) ) {
  2441. $t_this_string = lang_get( 'none' );
  2442. } else {
  2443. $t_this_string = $t_current;
  2444. }
  2445. if( $t_first_flag != true ) {
  2446. $t_output = $t_output . '<br />';
  2447. } else {
  2448. $t_first_flag = false;
  2449. }
  2450. $t_output = $t_output . string_display_line( $t_this_string );
  2451. }
  2452. if( true == $t_any_found ) {
  2453. echo lang_get( 'any' );
  2454. } else {
  2455. echo $t_output;
  2456. }
  2457. }
  2458. ?>
  2459. </td>
  2460. <?php
  2461. } else {?>
  2462. <td colspan="2" class="small-caption" valign="top">
  2463. &#160;
  2464. </td>
  2465. <td colspan="1" class="small-caption" valign="top">
  2466. &#160;
  2467. </td>
  2468. <td colspan="1" class="small-caption" valign="top">
  2469. &nbsp;
  2470. </td>
  2471. <?php
  2472. }?>
  2473. <td colspan="1" class="small-caption" valign="top" id="show_priority_filter_target">
  2474. <?php
  2475. $t_output = '';
  2476. $t_any_found = false;
  2477. if( count( $t_filter[FILTER_PROPERTY_PRIORITY_ID] ) == 0 ) {
  2478. echo lang_get( 'any' );
  2479. } else {
  2480. $t_first_flag = true;
  2481. foreach( $t_filter[FILTER_PROPERTY_PRIORITY_ID] as $t_current ) {
  2482. echo '<input type="hidden" name="', FILTER_PROPERTY_PRIORITY_ID, '[]" value="', string_attribute( $t_current ), '" />';
  2483. $t_this_string = '';
  2484. if( filter_field_is_any( $t_current ) ) {
  2485. $t_any_found = true;
  2486. } else {
  2487. $t_this_string = get_enum_element( 'priority', $t_current );
  2488. }
  2489. if( $t_first_flag != true ) {
  2490. $t_output = $t_output . '<br />';
  2491. } else {
  2492. $t_first_flag = false;
  2493. }
  2494. $t_output = $t_output . string_display_line( $t_this_string );
  2495. }
  2496. if( true == $t_any_found ) {
  2497. echo lang_get( 'any' );
  2498. } else {
  2499. echo $t_output;
  2500. }
  2501. }
  2502. ?>
  2503. </td>
  2504. <?php if( $t_filter_cols > 8 ) {
  2505. echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 7 ) . '">&#160;</td>';
  2506. }?>
  2507. </tr>
  2508. <tr <?php echo "class=\"" . $t_trclass . "\"";?>>
  2509. <td class="small-caption" valign="top">
  2510. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_ISSUES_PER_PAGE;?>" id="per_page_filter"><?php echo lang_get( 'show' )?>:</a>
  2511. </td>
  2512. <td class="small-caption" valign="top">
  2513. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_VIEW_STATE_ID;?>" id="view_state_filter"><?php echo lang_get( 'view_status' )?>:</a>
  2514. </td>
  2515. <td class="small-caption" valign="top">
  2516. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_SHOW_STICKY_ISSUES;?>" id="sticky_issues_filter"><?php echo lang_get( 'sticky' )?>:</a>
  2517. </td>
  2518. <td class="small-caption" valign="top" colspan="2">
  2519. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_HIGHLIGHT_CHANGED;?>" id="highlight_changed_filter"><?php echo lang_get( 'changed' )?>:</a>
  2520. </td>
  2521. <td class="small-caption" valign="top" >
  2522. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_FILTER_BY_DATE;?>" id="do_filter_by_date_filter"><?php echo lang_get( 'use_date_filters' )?>:</a>
  2523. </td>
  2524. <td class="small-caption" valign="top" colspan="2">
  2525. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_RELATIONSHIP_TYPE;?>" id="relationship_type_filter"><?php echo lang_get( 'bug_relationships' )?>:</a>
  2526. </td>
  2527. <?php if( $t_filter_cols > 8 ) {
  2528. echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 8 ) . '">&#160;</td>';
  2529. }?>
  2530. </tr>
  2531. <tr class="row-1">
  2532. <td class="small-caption" valign="top" id="per_page_filter_target">
  2533. <?php
  2534. echo( $t_filter[FILTER_PROPERTY_ISSUES_PER_PAGE] == 0 ) ? lang_get( 'all' ) : string_display_line( $t_filter[FILTER_PROPERTY_ISSUES_PER_PAGE] );
  2535. echo '<input type="hidden" name="', FILTER_PROPERTY_ISSUES_PER_PAGE, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_ISSUES_PER_PAGE] ), '" />';
  2536. ?>
  2537. </td>
  2538. <td class="small-caption" valign="top" id="view_state_filter_target">
  2539. <?php
  2540. if( VS_PUBLIC === $t_filter[FILTER_PROPERTY_VIEW_STATE_ID] ) {
  2541. echo lang_get( 'public' );
  2542. } else if( VS_PRIVATE === $t_filter[FILTER_PROPERTY_VIEW_STATE_ID] ) {
  2543. echo lang_get( 'private' );
  2544. } else {
  2545. echo lang_get( 'any' );
  2546. $t_filter[FILTER_PROPERTY_VIEW_STATE_ID] = META_FILTER_ANY;
  2547. }
  2548. echo '<input type="hidden" name="', FILTER_PROPERTY_VIEW_STATE_ID, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_VIEW_STATE_ID] ), '" />';
  2549. ?>
  2550. </td>
  2551. <td class="small-caption" valign="top" id="sticky_issues_filter_target">
  2552. <?php
  2553. $t_sticky_filter_state = gpc_string_to_bool( $t_filter[FILTER_PROPERTY_SHOW_STICKY_ISSUES] );
  2554. print( $t_sticky_filter_state ? lang_get( 'yes' ) : lang_get( 'no' ) );
  2555. ?>
  2556. <input type="hidden" name="sticky_issues" value="<?php echo $t_sticky_filter_state ? 'on' : 'off';?>" />
  2557. </td>
  2558. <td class="small-caption" valign="top" colspan="2" id="highlight_changed_filter_target">
  2559. <?php
  2560. echo $t_filter[FILTER_PROPERTY_HIGHLIGHT_CHANGED];
  2561. echo '<input type="hidden" name="', FILTER_PROPERTY_HIGHLIGHT_CHANGED, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_HIGHLIGHT_CHANGED] ), '" />';
  2562. ?>
  2563. </td>
  2564. <td class="small-caption" valign="top" id="do_filter_by_date_filter_target">
  2565. <?php
  2566. if(( ON == config_get( 'dhtml_filters' ) ) && ( ON == config_get( 'use_javascript' ) ) ) {
  2567. ?>
  2568. <script type="text/javascript" language="JavaScript">
  2569. <!--
  2570. function SwitchDateFields() {
  2571. // All fields need to be enabled to go back to the script
  2572. document.filters_open.start_month.disabled = ! document.filters_open.do_filter_by_date.checked;
  2573. document.filters_open.start_day.disabled = ! document.filters_open.do_filter_by_date.checked;
  2574. document.filters_open.start_year.disabled = ! document.filters_open.do_filter_by_date.checked;
  2575. document.filters_open.end_month.disabled = ! document.filters_open.do_filter_by_date.checked;
  2576. document.filters_open.end_day.disabled = ! document.filters_open.do_filter_by_date.checked;
  2577. document.filters_open.end_year.disabled = ! document.filters_open.do_filter_by_date.checked;
  2578. return true;
  2579. }
  2580. // -->
  2581. </script>
  2582. <?php
  2583. }
  2584. # end if dhtml_filters
  2585. if( 'on' == $t_filter[FILTER_PROPERTY_FILTER_BY_DATE] ) {
  2586. echo '<input type="hidden" name="', FILTER_PROPERTY_FILTER_BY_DATE, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_FILTER_BY_DATE] ), '" />';
  2587. echo '<input type="hidden" name="', FILTER_PROPERTY_START_MONTH, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_START_MONTH] ), '" />';
  2588. echo '<input type="hidden" name="', FILTER_PROPERTY_START_DAY, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_START_DAY] ), '" />';
  2589. echo '<input type="hidden" name="', FILTER_PROPERTY_START_YEAR, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_START_YEAR] ), '" />';
  2590. echo '<input type="hidden" name="', FILTER_PROPERTY_END_MONTH, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_END_MONTH] ), '" />';
  2591. echo '<input type="hidden" name="', FILTER_PROPERTY_END_DAY, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_END_DAY] ), '" />';
  2592. echo '<input type="hidden" name="', FILTER_PROPERTY_END_YEAR, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_END_YEAR] ), '" />';
  2593. $t_chars = preg_split( '//', config_get( 'short_date_format' ), -1, PREG_SPLIT_NO_EMPTY );
  2594. $t_time = mktime( 0, 0, 0, $t_filter[FILTER_PROPERTY_START_MONTH], $t_filter[FILTER_PROPERTY_START_DAY], $t_filter[FILTER_PROPERTY_START_YEAR] );
  2595. foreach( $t_chars as $t_char ) {
  2596. if( strcasecmp( $t_char, "M" ) == 0 ) {
  2597. echo ' ';
  2598. echo date( 'F', $t_time );
  2599. }
  2600. if( strcasecmp( $t_char, "D" ) == 0 ) {
  2601. echo ' ';
  2602. echo date( 'd', $t_time );
  2603. }
  2604. if( strcasecmp( $t_char, "Y" ) == 0 ) {
  2605. echo ' ';
  2606. echo date( 'Y', $t_time );
  2607. }
  2608. }
  2609. echo ' - ';
  2610. $t_time = mktime( 0, 0, 0, $t_filter[FILTER_PROPERTY_END_MONTH], $t_filter[FILTER_PROPERTY_END_DAY], $t_filter[FILTER_PROPERTY_END_YEAR] );
  2611. foreach( $t_chars as $t_char ) {
  2612. if( strcasecmp( $t_char, "M" ) == 0 ) {
  2613. echo ' ';
  2614. echo date( 'F', $t_time );
  2615. }
  2616. if( strcasecmp( $t_char, "D" ) == 0 ) {
  2617. echo ' ';
  2618. echo date( 'd', $t_time );
  2619. }
  2620. if( strcasecmp( $t_char, "Y" ) == 0 ) {
  2621. echo ' ';
  2622. echo date( 'Y', $t_time );
  2623. }
  2624. }
  2625. } else {
  2626. echo lang_get( 'no' );
  2627. }
  2628. ?>
  2629. </td>
  2630. <td class="small-caption" valign="top" colspan="2" id="relationship_type_filter_target">
  2631. <?php
  2632. echo '<input type="hidden" name="', FILTER_PROPERTY_RELATIONSHIP_TYPE, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_RELATIONSHIP_TYPE]), '" />';
  2633. echo '<input type="hidden" name="', FILTER_PROPERTY_RELATIONSHIP_BUG, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_RELATIONSHIP_BUG] ), '" />';
  2634. $c_rel_type = $t_filter[FILTER_PROPERTY_RELATIONSHIP_TYPE];
  2635. $c_rel_bug = $t_filter[FILTER_PROPERTY_RELATIONSHIP_BUG];
  2636. if( -1 == $c_rel_type || 0 == $c_rel_bug ) {
  2637. echo lang_get( 'any' );
  2638. } else {
  2639. echo relationship_get_description_for_history( $c_rel_type ) . ' ' . $c_rel_bug;
  2640. }
  2641. ?>
  2642. </td>
  2643. <?php if( $t_filter_cols > 8 ) {
  2644. echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 8 ) . '">&#160;</td>';
  2645. }?>
  2646. </tr>
  2647. <tr <?php echo "class=\"" . $t_trclass . "\"";?>>
  2648. <td class="small-caption" valign="top">
  2649. <?php if( ON == config_get( 'enable_profiles' ) ) { ?>
  2650. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_PLATFORM;?>" id="platform_filter"><?php echo lang_get( 'platform' )?>:</a>
  2651. <?php } ?>
  2652. </td>
  2653. <td class="small-caption" valign="top">
  2654. <?php if( ON == config_get( 'enable_profiles' ) ) { ?>
  2655. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_OS;?>" id="os_filter"><?php echo lang_get( 'os' )?>:</a>
  2656. <?php } ?>
  2657. </td>
  2658. <td class="small-caption" valign="top">
  2659. <?php if( ON == config_get( 'enable_profiles' ) ) { ?>
  2660. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_OS_BUILD;?>" id="os_build_filter"><?php echo lang_get( 'os_version' )?>:</a>
  2661. <?php } ?>
  2662. </td>
  2663. <td class="small-caption" valign="top" colspan="5">
  2664. <?php if ( access_has_global_level( config_get( 'tag_view_threshold' ) ) ) { ?>
  2665. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_TAG_STRING;?>" id="tag_string_filter"><?php echo lang_get( 'tags' )?>:</a>
  2666. <?php } ?>
  2667. </td>
  2668. <?php if( $t_filter_cols > 8 ) {
  2669. echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 8 ) . '">&#160;</td>';
  2670. }?>
  2671. </tr>
  2672. <tr class="row-1">
  2673. <?php if( ON == config_get( 'enable_profiles' ) ) { ?>
  2674. <td class="small-caption" valign="top" id="platform_filter_target">
  2675. <?php
  2676. print_multivalue_field( FILTER_PROPERTY_PLATFORM, $t_filter[FILTER_PROPERTY_PLATFORM] );
  2677. ?>
  2678. </td>
  2679. <td class="small-caption" valign="top" id="os_filter_target">
  2680. <?php
  2681. print_multivalue_field( FILTER_PROPERTY_OS, $t_filter[FILTER_PROPERTY_OS] );
  2682. ?>
  2683. </td>
  2684. <td class="small-caption" valign="top" id="os_build_filter_target">
  2685. <?php
  2686. print_multivalue_field( FILTER_PROPERTY_OS_BUILD, $t_filter[FILTER_PROPERTY_OS_BUILD] );
  2687. ?>
  2688. </td>
  2689. <?php } else {?>
  2690. <td colspan="3">&#160;</td>
  2691. <?php } ?>
  2692. <td class="small-caption" valign="top" id="tag_string_filter_target" colspan="5">
  2693. <?php
  2694. $t_tag_string = $t_filter[FILTER_PROPERTY_TAG_STRING];
  2695. if( $t_filter[FILTER_PROPERTY_TAG_SELECT] != 0 && tag_exists( $t_filter[FILTER_PROPERTY_TAG_SELECT] ) ) {
  2696. $t_tag_string .= ( is_blank( $t_tag_string ) ? '' : config_get( 'tag_separator' ) );
  2697. $t_tag_string .= tag_get_field( $t_filter[FILTER_PROPERTY_TAG_SELECT], 'name' );
  2698. }
  2699. echo string_html_entities( $t_tag_string );
  2700. echo '<input type="hidden" name="', FILTER_PROPERTY_TAG_STRING, '" value="', string_attribute( $t_tag_string ), '" />';
  2701. ?>
  2702. </td>
  2703. </tr>
  2704. <?php
  2705. # get plugin filters
  2706. $t_plugin_filters = filter_get_plugin_filters();
  2707. $t_column = 0;
  2708. $t_fields = '';
  2709. $t_values = '';
  2710. # output a filter form element for each plugin filter
  2711. foreach( $t_plugin_filters as $t_field_name => $t_filter_object ) {
  2712. $t_fields .= '<td class="small-caption" valign="top"> <a href="' . $t_filters_url . string_attribute( $t_field_name ) .
  2713. '" id="' . string_attribute( $t_field_name ) . '_filter">' . string_display_line( $t_filter_object->title ) . '</a> </td>';
  2714. $t_values .= '<td class="small-caption" valign="top" id="' . string_attribute( $t_field_name ) . '_filter_target"> ';
  2715. if ( !isset( $t_filter[ $t_field_name ] ) ) {
  2716. $t_values .= lang_get( 'any' );
  2717. } else {
  2718. switch( $t_filter_object->type ) {
  2719. case FILTER_TYPE_STRING:
  2720. case FILTER_TYPE_INT:
  2721. if ( filter_field_is_any( $t_filter[ $t_field_name ] ) ) {
  2722. $t_values .= lang_get( 'any' );
  2723. } else {
  2724. $t_values .= string_display_line( $t_filter[ $t_field_name ] );
  2725. }
  2726. $t_values .= '<input type="hidden" name="' . string_attribute( $t_field_name ) . '" value="' . string_attribute( $t_filter[ $t_field_name ] ) . '"/>';
  2727. break;
  2728. case FILTER_TYPE_BOOLEAN:
  2729. $t_values .= string_display_line( $t_filter_object->display( (bool)$t_filter[ $t_field_name ] ) );
  2730. $t_values .= '<input type="hidden" name="' . string_attribute( $t_field_name ) . '" value="' . (bool)$t_filter[ $t_field_name ] . '"/>';
  2731. break;
  2732. case FILTER_TYPE_MULTI_STRING:
  2733. case FILTER_TYPE_MULTI_INT:
  2734. $t_first = true;
  2735. $t_output = '';
  2736. if ( !is_array( $t_filter[ $t_field_name ] ) ) {
  2737. $t_filter[ $t_field_name ] = array( $t_filter[ $t_field_name ] );
  2738. }
  2739. foreach( $t_filter[ $t_field_name ] as $t_current ) {
  2740. if ( filter_field_is_any( $t_current ) ) {
  2741. $t_output .= lang_get( 'any' );
  2742. } else {
  2743. $t_output .= ( $t_first ? '' : '<br />' ) . string_display_line( $t_filter_object->display( $t_current ) );
  2744. $t_first = false;
  2745. }
  2746. $t_values .= '<input type="hidden" name="' . string_attribute( $t_field_name ) . '[]" value="' . string_attribute( $t_current ) . '"/>';
  2747. }
  2748. $t_values .= $t_output;
  2749. break;
  2750. }
  2751. }
  2752. $t_values .= '</td>';
  2753. $t_column++;
  2754. # wrap at the appropriate column
  2755. if ( $t_column >= $t_filter_cols ) {
  2756. echo '<tr class="', $t_trclass, '">', $t_fields, '</tr>';
  2757. echo '<tr class="row-1">', $t_values, '</tr>';
  2758. $t_fields = '';
  2759. $t_values = '';
  2760. $t_column = 0;
  2761. }
  2762. }
  2763. # output any remaining plugin filters
  2764. if ( $t_column > 0 ) {
  2765. if ( $t_column < $t_filter_cols ) {
  2766. $t_fields .= '<td class="small-caption" colspan="' . ( $t_filter_cols - $t_column ) . '">&#160;</td>';
  2767. $t_values .= '<td class="small-caption" colspan="' . ( $t_filter_cols - $t_column ) . '">&#160;</td>';
  2768. }
  2769. echo '<tr class="', $t_trclass, '">', $t_fields, '</tr>';
  2770. echo '<tr class="row-1">', $t_values, '</tr>';
  2771. }
  2772. if( ON == config_get( 'filter_by_custom_fields' ) ) {
  2773. # -- Custom Field Searching --
  2774. if( count( $t_accessible_custom_fields_ids ) > 0 ) {
  2775. $t_per_row = config_get( 'filter_custom_fields_per_row' );
  2776. $t_num_fields = count( $t_accessible_custom_fields_ids );
  2777. $t_row_idx = 0;
  2778. $t_col_idx = 0;
  2779. $t_fields = '';
  2780. $t_values = '';
  2781. for( $i = 0;$i < $t_num_fields;$i++ ) {
  2782. if( $t_col_idx == 0 ) {
  2783. $t_fields = '<tr class="' . $t_trclass . '">';
  2784. $t_values = '<tr class="row-1">';
  2785. }
  2786. if( isset( $t_accessible_custom_fields_names[$i] ) ) {
  2787. $t_fields .= '<td class="small-caption" valign="top"> ';
  2788. $t_fields .= '<a href="' . $t_filters_url . 'custom_field_' . $t_accessible_custom_fields_ids[$i] . '[]" id="custom_field_' . $t_accessible_custom_fields_ids[$i] . '_filter">';
  2789. $t_fields .= string_display_line( lang_get_defaulted( $t_accessible_custom_fields_names[$i] ) );
  2790. $t_fields .= '</a> </td> ';
  2791. }
  2792. $t_output = '';
  2793. $t_any_found = false;
  2794. $t_values .= '<td class="small-caption" valign="top" id="custom_field_' . $t_accessible_custom_fields_ids[$i] . '_filter_target"> ';
  2795. if( !isset( $t_filter['custom_fields'][$t_accessible_custom_fields_ids[$i]] ) ) {
  2796. $t_values .= lang_get( 'any' );
  2797. } else {
  2798. if( $t_accessible_custom_fields_types[$i] == CUSTOM_FIELD_TYPE_DATE ) {
  2799. /** @todo moved embedded javascript here from print_filter_custom_field_date
  2800. * it appears not to load properly on Firefox and other browsers if loaded through the httpxmlreq
  2801. */
  2802. $t_field_id = $t_accessible_custom_fields_ids[$i];
  2803. $t_js_toggle_func = "toggle_custom_date_field_" . $t_field_id . "_controls";
  2804. if(( ON == config_get( 'dhtml_filters' ) ) && ( ON == config_get( 'use_javascript' ) ) ) {
  2805. ?>
  2806. <script type="text/javascript" language="JavaScript">
  2807. <!--
  2808. function <?php echo $t_js_toggle_func . "_start";?>(disable) {
  2809. document.filters_open.custom_field_<?php echo $t_field_id;?>_start_year.disabled = disable ;
  2810. document.filters_open.custom_field_<?php echo $t_field_id;?>_start_month.disabled = disable ;
  2811. document.filters_open.custom_field_<?php echo $t_field_id;?>_start_day.disabled = disable ;
  2812. } ;
  2813. function <?php echo $t_js_toggle_func . "_end";?>(disable) {
  2814. document.filters_open.custom_field_<?php echo $t_field_id;?>_end_year.disabled = disable ;
  2815. document.filters_open.custom_field_<?php echo $t_field_id;?>_end_month.disabled = disable ;
  2816. document.filters_open.custom_field_<?php echo $t_field_id;?>_end_day.disabled = disable ;
  2817. } ;
  2818. function <?php echo $t_js_toggle_func;?>() {
  2819. switch (document.filters_open.custom_field_<?php echo $t_field_id;?>_control.selectedIndex) {
  2820. case <?php echo CUSTOM_FIELD_DATE_ANY;?>:
  2821. case <?php echo CUSTOM_FIELD_DATE_NONE;?>:
  2822. <?php echo $t_js_toggle_func . "_start";?>(true) ;
  2823. <?php echo $t_js_toggle_func . "_end";?>(true) ;
  2824. break ;
  2825. case <?php echo CUSTOM_FIELD_DATE_BETWEEN;?>:
  2826. <?php echo $t_js_toggle_func . "_start";?>(false) ;
  2827. <?php echo $t_js_toggle_func . "_end";?>(false) ;
  2828. break ;
  2829. default:
  2830. <?php echo $t_js_toggle_func . "_start";?>(false) ;
  2831. <?php echo $t_js_toggle_func . "_end";?>(true) ;
  2832. break ;
  2833. }
  2834. }
  2835. // -->
  2836. </script>
  2837. <?php
  2838. }
  2839. # end if dhtml_filters
  2840. $t_short_date_format = config_get( 'short_date_format' );
  2841. if( !isset( $t_filter['custom_fields'][$t_accessible_custom_fields_ids[$i]][1] ) ) {
  2842. $t_filter['custom_fields'][$t_accessible_custom_fields_ids[$i]][1] = 0;
  2843. }
  2844. $t_start = date( $t_short_date_format, $t_filter['custom_fields'][$t_accessible_custom_fields_ids[$i]][1] );
  2845. if( !isset( $t_filter['custom_fields'][$t_accessible_custom_fields_ids[$i]][2] ) ) {
  2846. $t_filter['custom_fields'][$t_accessible_custom_fields_ids[$i]][2] = 0;
  2847. }
  2848. $t_end = date( $t_short_date_format, $t_filter['custom_fields'][$t_accessible_custom_fields_ids[$i]][2] );
  2849. switch( $t_filter['custom_fields'][$t_accessible_custom_fields_ids[$i]][0] ) {
  2850. case CUSTOM_FIELD_DATE_ANY:
  2851. $t_values .= lang_get( 'any' );
  2852. break;
  2853. case CUSTOM_FIELD_DATE_NONE:
  2854. $t_values .= lang_get( 'none' );
  2855. break;
  2856. case CUSTOM_FIELD_DATE_BETWEEN:
  2857. $t_values .= lang_get( 'between_date' ) . '<br />';
  2858. $t_values .= $t_start . '<br />' . $t_end;
  2859. break;
  2860. case CUSTOM_FIELD_DATE_ONORBEFORE:
  2861. $t_values .= lang_get( 'on_or_before_date' ) . '<br />';
  2862. $t_values .= $t_end;
  2863. break;
  2864. case CUSTOM_FIELD_DATE_BEFORE:
  2865. $t_values .= lang_get( 'before_date' ) . '<br />';
  2866. $t_values .= $t_end;
  2867. break;
  2868. case CUSTOM_FIELD_DATE_ON:
  2869. $t_values .= lang_get( 'on_date' ) . '<br />';
  2870. $t_values .= $t_start;
  2871. break;
  2872. case CUSTOM_FIELD_DATE_AFTER:
  2873. $t_values .= lang_get( 'after_date' ) . '<br />';
  2874. $t_values .= $t_start;
  2875. break;
  2876. case CUSTOM_FIELD_DATE_ONORAFTER:
  2877. $t_values .= lang_get( 'on_or_after_date' ) . '<br />';
  2878. $t_values .= $t_start;
  2879. break;
  2880. }
  2881. } else {
  2882. $t_first_flag = true;
  2883. foreach( $t_filter['custom_fields'][$t_accessible_custom_fields_ids[$i]] as $t_current ) {
  2884. $t_current = stripslashes( $t_current );
  2885. $t_this_string = '';
  2886. if( filter_field_is_any( $t_current ) ) {
  2887. $t_any_found = true;
  2888. } else if( filter_field_is_none( $t_current ) ) {
  2889. $t_this_string = lang_get( 'none' );
  2890. } else {
  2891. $t_this_string = $t_current;
  2892. }
  2893. if( $t_first_flag != true ) {
  2894. $t_output = $t_output . '<br />';
  2895. } else {
  2896. $t_first_flag = false;
  2897. }
  2898. $t_output = $t_output . string_display_line( $t_this_string );
  2899. $t_values .= '<input type="hidden" name="custom_field_' . $t_accessible_custom_fields_ids[$i] . '[]" value="' . string_attribute( $t_current ) . '" />';
  2900. }
  2901. }
  2902. if( true == $t_any_found ) {
  2903. $t_values .= lang_get( 'any' );
  2904. } else {
  2905. $t_values .= $t_output;
  2906. }
  2907. }
  2908. $t_values .= ' </td>';
  2909. $t_col_idx++;
  2910. if( $t_col_idx == $t_per_row ) {
  2911. if( $t_filter_cols > $t_per_row ) {
  2912. $t_fields .= '<td colspan="' . ( $t_filter_cols - $t_per_row ) . '">&#160;</td> ';
  2913. $t_values .= '<td colspan="' . ( $t_filter_cols - $t_per_row ) . '">&#160;</td> ';
  2914. }
  2915. $t_fields .= '</tr>' . "\n";
  2916. $t_values .= '</tr>' . "\n";
  2917. echo $t_fields;
  2918. echo $t_values;
  2919. $t_col_idx = 0;
  2920. $t_row_idx++;
  2921. }
  2922. }
  2923. if( $t_col_idx > 0 ) {
  2924. if( $t_col_idx < $t_per_row ) {
  2925. $t_fields .= '<td colspan="' . ( $t_per_row - $t_col_idx ) . '">&#160;</td> ';
  2926. $t_values .= '<td colspan="' . ( $t_per_row - $t_col_idx ) . '">&#160;</td> ';
  2927. }
  2928. if( $t_filter_cols > $t_per_row ) {
  2929. $t_fields .= '<td colspan="' . ( $t_filter_cols - $t_per_row ) . '">&#160;</td> ';
  2930. $t_values .= '<td colspan="' . ( $t_filter_cols - $t_per_row ) . '">&#160;</td> ';
  2931. }
  2932. $t_fields .= '</tr>' . "\n";
  2933. $t_values .= '</tr>' . "\n";
  2934. echo $t_fields;
  2935. echo $t_values;
  2936. }
  2937. }
  2938. }
  2939. ?>
  2940. <tr class="row-1">
  2941. <td class="small-caption category2" valign="top">
  2942. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_NOTE_USER_ID;?>" id="note_user_id_filter"><?php echo lang_get( 'note_user_id' )?>:</a>
  2943. </td>
  2944. <td class="small-caption" valign="top" id="note_user_id_filter_target">
  2945. <?php
  2946. $t_output = '';
  2947. $t_any_found = false;
  2948. if( count( $t_filter[FILTER_PROPERTY_NOTE_USER_ID] ) == 0 ) {
  2949. echo lang_get( 'any' );
  2950. } else {
  2951. $t_first_flag = true;
  2952. foreach( $t_filter[FILTER_PROPERTY_NOTE_USER_ID] as $t_current ) {
  2953. echo '<input type="hidden" name="', FILTER_PROPERTY_NOTE_USER_ID, '[]" value="', string_attribute( $t_current ), '" />';
  2954. $t_this_name = '';
  2955. if( filter_field_is_none( $t_current ) ) {
  2956. $t_this_name = lang_get( 'none' );
  2957. } else if( filter_field_is_any( $t_current ) ) {
  2958. $t_any_found = true;
  2959. } else if( filter_field_is_myself( $t_current ) ) {
  2960. if( access_has_project_level( config_get( 'handle_bug_threshold' ) ) ) {
  2961. $t_this_name = '[' . lang_get( 'myself' ) . ']';
  2962. } else {
  2963. $t_any_found = true;
  2964. }
  2965. } else {
  2966. $t_this_name = user_get_name( $t_current );
  2967. }
  2968. if( $t_first_flag != true ) {
  2969. $t_output = $t_output . '<br />';
  2970. } else {
  2971. $t_first_flag = false;
  2972. }
  2973. $t_output = $t_output . string_display_line( $t_this_name );
  2974. }
  2975. if( true == $t_any_found ) {
  2976. echo lang_get( 'any' );
  2977. } else {
  2978. echo $t_output;
  2979. }
  2980. }
  2981. ?>
  2982. </td>
  2983. <td class="small-caption" valign="top">
  2984. <a href="<?php echo $t_filters_url . 'show_sort';?>" id="show_sort_filter"><?php echo lang_get( 'sort' )?>:</a>
  2985. </td>
  2986. <td class="small-caption" valign="top" id="show_sort_filter_target">
  2987. <?php
  2988. $t_sort_fields = explode( ',', $t_filter[FILTER_PROPERTY_SORT_FIELD_NAME] );
  2989. $t_dir_fields = explode( ',', $t_filter[FILTER_PROPERTY_SORT_DIRECTION] );
  2990. for( $i = 0;$i < 2;$i++ ) {
  2991. if( isset( $t_sort_fields[$i] ) ) {
  2992. if( 0 < $i ) {
  2993. echo ', ';
  2994. }
  2995. $t_sort = $t_sort_fields[$i];
  2996. if( strpos( $t_sort, 'custom_' ) === 0 ) {
  2997. $t_field_name = string_display( lang_get_defaulted( utf8_substr( $t_sort, utf8_strlen( 'custom_' ) ) ) );
  2998. } else {
  2999. $t_field_name = string_get_field_name( $t_sort );
  3000. }
  3001. echo $t_field_name . ' ' . lang_get( 'bugnote_order_' . utf8_strtolower( $t_dir_fields[$i] ) );
  3002. echo '<input type="hidden" name="', FILTER_PROPERTY_SORT_FIELD_NAME, '_', $i, '" value="', string_attribute( $t_sort_fields[$i] ), '" />';
  3003. echo '<input type="hidden" name="', FILTER_PROPERTY_SORT_DIRECTION, '_', $i, '" value="', string_attribute( $t_dir_fields[$i] ), '" />';
  3004. }
  3005. }
  3006. ?>
  3007. </td>
  3008. <?php
  3009. if( 'advanced' == $t_view_type ) {
  3010. ?>
  3011. <td class="small-caption" valign="top" colspan="2">
  3012. <a href="<?php echo $t_filters_url . FILTER_PROPERTY_PROJECT_ID;?>" id="project_id_filter"><?php echo lang_get( 'email_project' )?>:</a>
  3013. </td>
  3014. <td class="small-caption" valign="top" id="project_id_filter_target">
  3015. <?php
  3016. $t_output = '';
  3017. if( !is_array( $t_filter[FILTER_PROPERTY_PROJECT_ID] ) ) {
  3018. $t_filter[FILTER_PROPERTY_PROJECT_ID] = Array(
  3019. $t_filter[FILTER_PROPERTY_PROJECT_ID],
  3020. );
  3021. }
  3022. if( count( $t_filter[FILTER_PROPERTY_PROJECT_ID] ) == 0 ) {
  3023. echo lang_get( 'current' );
  3024. } else {
  3025. $t_first_flag = true;
  3026. foreach( $t_filter[FILTER_PROPERTY_PROJECT_ID] as $t_current ) {
  3027. echo '<input type="hidden" name="', FILTER_PROPERTY_PROJECT_ID, '[]" value="', string_attribute( $t_current ), '" />';
  3028. $t_this_name = '';
  3029. if( META_FILTER_CURRENT == $t_current ) {
  3030. $t_this_name = lang_get( 'current' );
  3031. } else {
  3032. $t_this_name = project_get_name( $t_current, false );
  3033. }
  3034. if( $t_first_flag != true ) {
  3035. $t_output = $t_output . '<br />';
  3036. } else {
  3037. $t_first_flag = false;
  3038. }
  3039. $t_output = $t_output . string_display_line( $t_this_name );
  3040. }
  3041. echo $t_output;
  3042. }
  3043. ?>
  3044. </td>
  3045. <?php
  3046. if( $t_filter_cols > 6 ) {
  3047. echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 5 ) . '">&#160;</td>';
  3048. }
  3049. } else {
  3050. if( $t_filter_cols > 3 ) {
  3051. echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 2 ) . '">&#160;</td>';
  3052. }
  3053. }
  3054. ?>
  3055. </tr>
  3056. <tr class="row-1">
  3057. <td class="small-caption" valign="top"><a href="<?php echo $t_filters_url . FILTER_PROPERTY_MATCH_TYPE;?>" id="match_type_filter"><?php echo lang_get( 'filter_match_type' )?>:</a></td>
  3058. <td class="small-caption" valign="top" id="match_type_filter_target">
  3059. <?php
  3060. switch( $t_filter[FILTER_PROPERTY_MATCH_TYPE] ) {
  3061. case FILTER_MATCH_ANY:
  3062. echo lang_get ('filter_match_any');
  3063. break;
  3064. case FILTER_MATCH_ALL:
  3065. default:
  3066. echo lang_get ('filter_match_all');
  3067. break;
  3068. }
  3069. ?>
  3070. <input type="hidden" name="match_type" value="<?php echo $t_filter[FILTER_PROPERTY_MATCH_TYPE] ?>"/>
  3071. </td>
  3072. <td colspan="6">&#160;</td>
  3073. </tr>
  3074. <?php
  3075. }
  3076. // expanded
  3077. ?>
  3078. <tr>
  3079. <td colspan="2">
  3080. <?php
  3081. collapse_icon( 'filter' );
  3082. echo lang_get( 'search' ) . '&#160;';
  3083. echo '<input type="text" size="16" name="', FILTER_PROPERTY_FREE_TEXT, '" value="', string_attribute( $t_filter[FILTER_PROPERTY_FREE_TEXT] ), '" />';
  3084. ?>
  3085. <input type="submit" name="filter" class="button-small" value="<?php echo lang_get( 'filter_button' )?>" />
  3086. </td>
  3087. </form>
  3088. <td class="center" colspan="<?php echo( $t_filter_cols - 6 )?>"> <!-- use this label for padding -->
  3089. <?php
  3090. if( ON == config_get( 'dhtml_filters' ) ) {
  3091. $f_switch_view_link = 'view_all_set.php?type=6&view_type=';
  3092. } else {
  3093. $f_switch_view_link = 'view_filters_page.php?view_type=';
  3094. }
  3095. $t_view_filters = config_get( 'view_filters' );
  3096. if(( SIMPLE_ONLY != $t_view_filters ) && ( ADVANCED_ONLY != $t_view_filters ) ) {
  3097. if( 'advanced' == $t_view_type ) {
  3098. print_bracket_link( $f_switch_view_link . 'simple', lang_get( 'simple_filters' ) );
  3099. } else {
  3100. print_bracket_link( $f_switch_view_link . 'advanced', lang_get( 'advanced_filters' ) );
  3101. }
  3102. }
  3103. if( access_has_project_level( config_get( 'create_permalink_threshold' ) ) ) {
  3104. print_bracket_link( 'permalink_page.php?url=' . urlencode( filter_get_url( $t_filter ) ), lang_get( 'create_filter_link' ),
  3105. /* new window = */
  3106. true );
  3107. }
  3108. ?>
  3109. </td>
  3110. <td class="right" colspan="4">
  3111. <?php
  3112. $t_stored_queries_arr = array();
  3113. $t_stored_queries_arr = filter_db_get_available_queries();
  3114. if( count( $t_stored_queries_arr ) > 0 ) {
  3115. ?>
  3116. <form method="get" name="list_queries<?php echo $t_form_name_suffix;?>" action="view_all_set.php">
  3117. <?php # CSRF protection not required here - form does not result in modifications ?>
  3118. <input type="hidden" name="type" value="3" />
  3119. <?php
  3120. if( ON == config_get( 'use_javascript' ) ) {
  3121. echo "<select name=\"source_query_id\" onchange=\"document.forms.list_queries$t_form_name_suffix.submit();\">";
  3122. } else {
  3123. echo '<select name="source_query_id">';
  3124. }
  3125. ?>
  3126. <option value="-1"><?php echo '[' . lang_get( 'reset_query' ) . ']'?></option>
  3127. <option value="-1"></option>
  3128. <?php
  3129. $t_source_query_id = isset( $t_filter['_source_query_id'] ) ? (int)$t_filter['_source_query_id'] : -1;
  3130. foreach( $t_stored_queries_arr as $t_query_id => $t_query_name ) {
  3131. echo '<option value="' . $t_query_id . '" ';
  3132. check_selected( $t_query_id, $t_source_query_id );
  3133. echo '>' . string_display_line( $t_query_name ) . '</option>';
  3134. }
  3135. ?>
  3136. </select>
  3137. <input type="submit" name="switch_to_query_button" class="button-small" value="<?php echo lang_get( 'use_query' )?>" />
  3138. </form>
  3139. <form method="post" name="open_queries" action="query_view_page.php">
  3140. <?php # CSRF protection not required here - form does not result in modifications ?>
  3141. <input type="submit" name="switch_to_query_button" class="button-small" value="<?php echo lang_get( 'open_queries' )?>" />
  3142. </form>
  3143. <?php
  3144. } else {
  3145. ?>
  3146. <form method="get" name="reset_query" action="view_all_set.php">
  3147. <?php # CSRF protection not required here - form does not result in modifications ?>
  3148. <input type="hidden" name="type" value="3" />
  3149. <input type="hidden" name="source_query_id" value="-1" />
  3150. <input type="submit" name="reset_query_button" class="button-small" value="<?php echo lang_get( 'reset_query' )?>" />
  3151. </form>
  3152. <?php
  3153. }
  3154. if( access_has_project_level( config_get( 'stored_query_create_threshold' ) ) ) {
  3155. ?>
  3156. <form method="post" name="save_query" action="query_store_page.php">
  3157. <?php # CSRF protection not required here - form does not result in modifications ?>
  3158. <input type="submit" name="save_query_button" class="button-small" value="<?php echo lang_get( 'save_query' )?>" />
  3159. </form>
  3160. <?php
  3161. }
  3162. ?>
  3163. </td>
  3164. </tr>
  3165. </table>
  3166. <?php
  3167. }
  3168. /**
  3169. * @internal The following functions each print out filter field inputs.
  3170. * They are derived from view_filters_page.php
  3171. * The functions follow a strict naming convention:
  3172. *
  3173. * print_filter_[filter_name]
  3174. *
  3175. * Where [filter_name] is the same as the "name" of the form element for
  3176. * that filter. This naming convention is depended upon by the controller
  3177. * at the end of the script.
  3178. *
  3179. * @todo print functions should be abstracted. Many of these functions
  3180. * are virtually identical except for the property name.
  3181. * Perhaps this code could be made simpler by refactoring into a
  3182. * class so as to avoid all those calls to global(which are pretty ugly)
  3183. * These functions could also be shared by view_filters_page.php
  3184. */
  3185. /**
  3186. * Print the reporter field
  3187. */
  3188. function print_filter_reporter_id() {
  3189. global $t_select_modifier, $t_filter;
  3190. ?>
  3191. <select <?php echo $t_select_modifier;?> name="reporter_id[]">
  3192. <?php
  3193. # if current user is a reporter, and limited reports set to ON, only display that name
  3194. # @@@ thraxisp - access_has_project_level checks greater than or equal to,
  3195. # this assumed that there aren't any holes above REPORTER where the limit would apply
  3196. #
  3197. if(( ON === config_get( 'limit_reporters' ) ) && ( !access_has_project_level( REPORTER + 1 ) ) ) {
  3198. $t_id = auth_get_current_user_id();
  3199. $t_username = user_get_field( $t_id, 'username' );
  3200. $t_realname = user_get_field( $t_id, 'realname' );
  3201. $t_display_name = string_attribute( $t_username );
  3202. if(( isset( $t_realname ) ) && ( $t_realname > '' ) && ( ON == config_get( 'show_realname' ) ) ) {
  3203. $t_display_name = string_attribute( $t_realname );
  3204. }
  3205. echo '<option value="' . $t_id . '" selected="selected">' . $t_display_name . '</option>';
  3206. } else {
  3207. ?>
  3208. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_REPORTER_ID], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3209. <?php
  3210. if( access_has_project_level( config_get( 'report_bug_threshold' ) ) ) {
  3211. echo '<option value="' . META_FILTER_MYSELF . '" ';
  3212. check_selected( $t_filter[FILTER_PROPERTY_REPORTER_ID], META_FILTER_MYSELF );
  3213. echo '>[' . lang_get( 'myself' ) . ']</option>';
  3214. }
  3215. print_reporter_option_list( $t_filter[FILTER_PROPERTY_REPORTER_ID] );
  3216. }?>
  3217. </select>
  3218. <?php
  3219. }
  3220. /**
  3221. * Print the user monitor field
  3222. */
  3223. function print_filter_user_monitor() {
  3224. global $t_select_modifier, $t_filter;
  3225. ?>
  3226. <!-- Monitored by -->
  3227. <select <?php echo $t_select_modifier;?> name="user_monitor[]">
  3228. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_MONITOR_USER_ID], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3229. <?php
  3230. if( access_has_project_level( config_get( 'monitor_bug_threshold' ) ) ) {
  3231. echo '<option value="' . META_FILTER_MYSELF . '" ';
  3232. check_selected( $t_filter[FILTER_PROPERTY_MONITOR_USER_ID], META_FILTER_MYSELF );
  3233. echo '>[' . lang_get( 'myself' ) . ']</option>';
  3234. }
  3235. $t_threshold = config_get( 'show_monitor_list_threshold' );
  3236. $t_has_project_level = access_has_project_level( $t_threshold );
  3237. if( $t_has_project_level ) {
  3238. print_reporter_option_list( $t_filter[FILTER_PROPERTY_MONITOR_USER_ID] );
  3239. }
  3240. ?>
  3241. </select>
  3242. <?php
  3243. }
  3244. /**
  3245. * print the handler field
  3246. */
  3247. function print_filter_handler_id() {
  3248. global $t_select_modifier, $t_filter, $f_view_type;
  3249. ?>
  3250. <!-- Handler -->
  3251. <select <?php echo $t_select_modifier;?> name="handler_id[]">
  3252. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_HANDLER_ID], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3253. <?php if( access_has_project_level( config_get( 'view_handler_threshold' ) ) ) {?>
  3254. <option value="<?php echo META_FILTER_NONE?>" <?php check_selected( $t_filter[FILTER_PROPERTY_HANDLER_ID], META_FILTER_NONE );?>>[<?php echo lang_get( 'none' )?>]</option>
  3255. <?php
  3256. if( access_has_project_level( config_get( 'handle_bug_threshold' ) ) ) {
  3257. echo '<option value="' . META_FILTER_MYSELF . '" ';
  3258. check_selected( $t_filter[FILTER_PROPERTY_HANDLER_ID], META_FILTER_MYSELF );
  3259. echo '>[' . lang_get( 'myself' ) . ']</option>';
  3260. }
  3261. print_assign_to_option_list( $t_filter[FILTER_PROPERTY_HANDLER_ID] );
  3262. }?>
  3263. </select>
  3264. <?php
  3265. }
  3266. /**
  3267. * print the category field
  3268. */
  3269. function print_filter_show_category() {
  3270. global $t_select_modifier, $t_filter;
  3271. ?>
  3272. <!-- Category -->
  3273. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_CATEGORY;?>[]">
  3274. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_CATEGORY], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3275. <?php print_category_filter_option_list( $t_filter[FILTER_PROPERTY_CATEGORY] )?>
  3276. </select>
  3277. <?php
  3278. }
  3279. /**
  3280. * print the platform field
  3281. */
  3282. function print_filter_platform() {
  3283. global $t_select_modifier, $t_filter;
  3284. ?>
  3285. <!-- Platform -->
  3286. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_PLATFORM;?>[]">
  3287. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_PLATFORM], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3288. <?php
  3289. log_event( LOG_FILTERING, 'Platform = ' . var_export( $t_filter[FILTER_PROPERTY_PLATFORM], true ) );
  3290. print_platform_option_list( $t_filter[FILTER_PROPERTY_PLATFORM] );
  3291. ?>
  3292. </select>
  3293. <?php
  3294. }
  3295. /**
  3296. * print the os field
  3297. */
  3298. function print_filter_os() {
  3299. global $t_select_modifier, $t_filter;
  3300. ?>
  3301. <!-- OS -->
  3302. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_OS;?>[]">
  3303. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_OS], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3304. <?php print_os_option_list( $t_filter[FILTER_PROPERTY_OS] )?>
  3305. </select>
  3306. <?php
  3307. }
  3308. /**
  3309. * print the os build field
  3310. */
  3311. function print_filter_os_build() {
  3312. global $t_select_modifier, $t_filter;
  3313. ?>
  3314. <!-- OS Build -->
  3315. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_OS_BUILD;?>[]">
  3316. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_OS_BUILD], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3317. <?php print_os_build_option_list( $t_filter[FILTER_PROPERTY_OS_BUILD] )?>
  3318. </select>
  3319. <?php
  3320. }
  3321. /**
  3322. * print the severity field
  3323. */
  3324. function print_filter_show_severity() {
  3325. global $t_select_modifier, $t_filter;
  3326. ?><!-- Severity -->
  3327. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_SEVERITY_ID;?>[]">
  3328. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_SEVERITY_ID], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3329. <?php print_enum_string_option_list( 'severity', $t_filter[FILTER_PROPERTY_SEVERITY_ID] )?>
  3330. </select>
  3331. <?php
  3332. }
  3333. /**
  3334. * print resolution field
  3335. */
  3336. function print_filter_show_resolution() {
  3337. global $t_select_modifier, $t_filter;
  3338. ?><!-- Resolution -->
  3339. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_RESOLUTION_ID;?>[]">
  3340. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_RESOLUTION_ID], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3341. <?php print_enum_string_option_list( 'resolution', $t_filter[FILTER_PROPERTY_RESOLUTION_ID] )?>
  3342. </select>
  3343. <?php
  3344. }
  3345. /**
  3346. * print status field
  3347. */
  3348. function print_filter_show_status() {
  3349. global $t_select_modifier, $t_filter;
  3350. ?> <!-- Status -->
  3351. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_STATUS_ID;?>[]">
  3352. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_STATUS_ID], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3353. <?php print_enum_string_option_list( 'status', $t_filter[FILTER_PROPERTY_STATUS_ID] )?>
  3354. </select>
  3355. <?php
  3356. }
  3357. /**
  3358. * print hide status field
  3359. */
  3360. function print_filter_hide_status() {
  3361. global $t_select_modifier, $t_filter;
  3362. ?><!-- Hide Status -->
  3363. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_HIDE_STATUS_ID;?>[]">
  3364. <option value="<?php echo META_FILTER_NONE?>">[<?php echo lang_get( 'none' )?>]</option>
  3365. <?php print_enum_string_option_list( 'status', $t_filter[FILTER_PROPERTY_HIDE_STATUS_ID] )?>
  3366. </select>
  3367. <?php
  3368. }
  3369. /**
  3370. * print build field
  3371. */
  3372. function print_filter_show_build() {
  3373. global $t_select_modifier, $t_filter;
  3374. ?><!-- Build -->
  3375. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_PRODUCT_BUILD;?>[]">
  3376. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_PRODUCT_BUILD], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3377. <option value="<?php echo META_FILTER_NONE?>" <?php check_selected( $t_filter[FILTER_PROPERTY_PRODUCT_BUILD], META_FILTER_NONE );?>>[<?php echo lang_get( 'none' )?>]</option>
  3378. <?php print_build_option_list( $t_filter[FILTER_PROPERTY_PRODUCT_BUILD] )?>
  3379. </select>
  3380. <?php
  3381. }
  3382. /**
  3383. * print version field
  3384. */
  3385. function print_filter_show_version() {
  3386. global $t_select_modifier, $t_filter;
  3387. ?><!-- Version -->
  3388. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_PRODUCT_VERSION;?>[]">
  3389. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_PRODUCT_VERSION], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3390. <option value="<?php echo META_FILTER_NONE?>" <?php check_selected( $t_filter[FILTER_PROPERTY_PRODUCT_VERSION], META_FILTER_NONE );?>>[<?php echo lang_get( 'none' )?>]</option>
  3391. <?php print_version_option_list( $t_filter[FILTER_PROPERTY_PRODUCT_VERSION], /* projectId */ null, /* released */ VERSION_ALL, /* leadingBlank */ false, /* withSubs */ true )?>
  3392. </select>
  3393. <?php
  3394. }
  3395. /**
  3396. * print fixed in version field
  3397. */
  3398. function print_filter_show_fixed_in_version() {
  3399. global $t_select_modifier, $t_filter;
  3400. ?><!-- Fixed in Version -->
  3401. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_FIXED_IN_VERSION;?>[]">
  3402. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_FIXED_IN_VERSION], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3403. <option value="<?php echo META_FILTER_NONE?>" <?php check_selected( $t_filter[FILTER_PROPERTY_FIXED_IN_VERSION], META_FILTER_NONE );?>>[<?php echo lang_get( 'none' )?>]</option>
  3404. <?php print_version_option_list( $t_filter[FILTER_PROPERTY_FIXED_IN_VERSION], /* projectId */ null, /* released */ VERSION_ALL, /* leadingBlank */ false, /* withSubs */ true )?>
  3405. </select>
  3406. <?php
  3407. }
  3408. /**
  3409. * print target version field
  3410. */
  3411. function print_filter_show_target_version() {
  3412. global $t_select_modifier, $t_filter;
  3413. ?><!-- Fixed in Version -->
  3414. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_TARGET_VERSION;?>[]">
  3415. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_TARGET_VERSION], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3416. <option value="<?php echo META_FILTER_NONE?>" <?php check_selected( $t_filter[FILTER_PROPERTY_TARGET_VERSION], META_FILTER_NONE );?>>[<?php echo lang_get( 'none' )?>]</option>
  3417. <?php print_version_option_list( $t_filter[FILTER_PROPERTY_TARGET_VERSION], /* projectId */ null, /* released */ VERSION_ALL, /* leadingBlank */ false, /* withSubs */ true )?>
  3418. </select>
  3419. <?php
  3420. }
  3421. /**
  3422. * print priority field
  3423. */
  3424. function print_filter_show_priority() {
  3425. global $t_select_modifier, $t_filter;
  3426. ?><!-- Priority -->
  3427. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_PRIORITY_ID;?>[]">
  3428. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_PRIORITY_ID], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3429. <?php print_enum_string_option_list( 'priority', $t_filter[FILTER_PROPERTY_PRIORITY_ID] )?>
  3430. </select>
  3431. <?php
  3432. }
  3433. /**
  3434. * print profile field
  3435. */
  3436. function print_filter_show_profile() {
  3437. global $t_select_modifier, $t_filter;
  3438. ?><!-- Profile -->
  3439. <select <?php echo $t_select_modifier;?> name="show_profile[]">
  3440. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter['show_profile'], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3441. <?php print_profile_option_list_for_project( helper_get_current_project(), $t_filter['show_profile'] );?>
  3442. </select>
  3443. <?php
  3444. }
  3445. /**
  3446. * print issues per page field
  3447. */
  3448. function print_filter_per_page() {
  3449. global $t_filter;
  3450. ?><!-- Number of bugs per page -->
  3451. <input type="text" name="<?php echo FILTER_PROPERTY_ISSUES_PER_PAGE;?>" size="3" maxlength="7" value="<?php echo $t_filter[FILTER_PROPERTY_ISSUES_PER_PAGE]?>" />
  3452. <?php
  3453. }
  3454. /**
  3455. * print view state field
  3456. */
  3457. function print_filter_view_state() {
  3458. global $t_select_modifier, $t_filter;
  3459. ?><!-- View Status -->
  3460. <select name="<?php echo FILTER_PROPERTY_VIEW_STATE_ID;?>">
  3461. <?php
  3462. echo '<option value="' . META_FILTER_ANY . '" ';
  3463. check_selected( $t_filter[FILTER_PROPERTY_VIEW_STATE_ID], META_FILTER_ANY );
  3464. echo '>[' . lang_get( 'any' ) . ']</option>';
  3465. echo '<option value="' . VS_PUBLIC . '" ';
  3466. check_selected( $t_filter[FILTER_PROPERTY_VIEW_STATE_ID], VS_PUBLIC );
  3467. echo '>' . lang_get( 'public' ) . '</option>';
  3468. echo '<option value="' . VS_PRIVATE . '" ';
  3469. check_selected( $t_filter[FILTER_PROPERTY_VIEW_STATE_ID], VS_PRIVATE );
  3470. echo '>' . lang_get( 'private' ) . '</option>';
  3471. ?>
  3472. </select>
  3473. <?php
  3474. }
  3475. /**
  3476. * print sticky issues field
  3477. */
  3478. function print_filter_sticky_issues() {
  3479. global $t_filter;
  3480. ?><!-- Show or hide sticky bugs -->
  3481. <input type="checkbox" name="<?php echo FILTER_PROPERTY_SHOW_STICKY_ISSUES;?>" <?php check_checked( gpc_string_to_bool( $t_filter[FILTER_PROPERTY_SHOW_STICKY_ISSUES] ), true );?> />
  3482. <?php
  3483. }
  3484. /**
  3485. * print highlight changed field
  3486. */
  3487. function print_filter_highlight_changed() {
  3488. global $t_filter;
  3489. ?><!-- Highlight changed bugs -->
  3490. <input type="text" name="<?php echo FILTER_PROPERTY_HIGHLIGHT_CHANGED;?>" size="3" maxlength="7" value="<?php echo $t_filter[FILTER_PROPERTY_HIGHLIGHT_CHANGED]?>" />
  3491. <?php
  3492. }
  3493. /**
  3494. * print filter by date fields with javascript
  3495. * @todo Javascript should be removed and added dynamically
  3496. * via external script
  3497. */
  3498. function print_filter_do_filter_by_date( $p_hide_checkbox = false ) {
  3499. global $t_filter;
  3500. ?>
  3501. <table cellspacing="0" cellpadding="0">
  3502. <?php if( !$p_hide_checkbox ) {
  3503. ?>
  3504. <tr><td colspan="2">
  3505. <input type="checkbox" name="<?php echo FILTER_PROPERTY_FILTER_BY_DATE;?>" <?php
  3506. check_checked( $t_filter[FILTER_PROPERTY_FILTER_BY_DATE], 'on' );
  3507. if( ON == config_get( 'use_javascript' ) ) {
  3508. print "onclick=\"SwitchDateFields();\"";
  3509. }?> />
  3510. <?php echo lang_get( 'use_date_filters' )?>
  3511. </td></tr>
  3512. <?php
  3513. }
  3514. # Make sure the date selection controls are enabled by default
  3515. # if we do not use javascript
  3516. $t_menu_disabled =
  3517. !config_get( 'use_javascript' )
  3518. || 'on' == $t_filter[FILTER_PROPERTY_FILTER_BY_DATE]
  3519. ? ''
  3520. : ' disabled ';
  3521. ?>
  3522. <!-- Start date -->
  3523. <tr>
  3524. <td>
  3525. <?php echo lang_get( 'start_date' )?>:
  3526. </td>
  3527. <td nowrap="nowrap">
  3528. <?php
  3529. $t_chars = preg_split( '//', config_get( 'short_date_format' ), -1, PREG_SPLIT_NO_EMPTY );
  3530. foreach( $t_chars as $t_char ) {
  3531. if( strcasecmp( $t_char, "M" ) == 0 ) {
  3532. echo '<select name="', FILTER_PROPERTY_START_MONTH, '"', $t_menu_disabled, '>';
  3533. print_month_option_list( $t_filter[FILTER_PROPERTY_START_MONTH] );
  3534. print "</select>\n";
  3535. }
  3536. if( strcasecmp( $t_char, "D" ) == 0 ) {
  3537. echo '<select name="', FILTER_PROPERTY_START_DAY, '"', $t_menu_disabled, '>';
  3538. print_day_option_list( $t_filter[FILTER_PROPERTY_START_DAY] );
  3539. print "</select>\n";
  3540. }
  3541. if( strcasecmp( $t_char, "Y" ) == 0 ) {
  3542. echo '<select name="', FILTER_PROPERTY_START_YEAR, '"', $t_menu_disabled, '>';
  3543. print_year_option_list( $t_filter[FILTER_PROPERTY_START_YEAR] );
  3544. print "</select>\n";
  3545. }
  3546. }
  3547. ?>
  3548. </td>
  3549. </tr>
  3550. <!-- End date -->
  3551. <tr>
  3552. <td>
  3553. <?php echo lang_get( 'end_date' )?>:
  3554. </td>
  3555. <td>
  3556. <?php
  3557. $t_chars = preg_split( '//', config_get( 'short_date_format' ), -1, PREG_SPLIT_NO_EMPTY );
  3558. foreach( $t_chars as $t_char ) {
  3559. if( strcasecmp( $t_char, "M" ) == 0 ) {
  3560. echo '<select name="', FILTER_PROPERTY_END_MONTH, '"', $t_menu_disabled, '>';
  3561. print_month_option_list( $t_filter[FILTER_PROPERTY_END_MONTH] );
  3562. print "</select>\n";
  3563. }
  3564. if( strcasecmp( $t_char, "D" ) == 0 ) {
  3565. echo '<select name="', FILTER_PROPERTY_END_DAY, '"', $t_menu_disabled, '>';
  3566. print_day_option_list( $t_filter[FILTER_PROPERTY_END_DAY] );
  3567. print "</select>\n";
  3568. }
  3569. if( strcasecmp( $t_char, "Y" ) == 0 ) {
  3570. echo '<select name="', FILTER_PROPERTY_END_YEAR, '"', $t_menu_disabled, '>';
  3571. print_year_option_list( $t_filter[FILTER_PROPERTY_END_YEAR] );
  3572. print "</select>\n";
  3573. }
  3574. }
  3575. ?>
  3576. </td>
  3577. </tr>
  3578. </table>
  3579. <?php
  3580. }
  3581. /**
  3582. * print relationship fields
  3583. */
  3584. function print_filter_relationship_type() {
  3585. global $t_filter;
  3586. $c_reltype_value = $t_filter[FILTER_PROPERTY_RELATIONSHIP_TYPE];
  3587. if( !$c_reltype_value ) {
  3588. $c_reltype_value = -1;
  3589. }
  3590. relationship_list_box( $c_reltype_value, "relationship_type", true );
  3591. echo '<input type="text" name="', FILTER_PROPERTY_RELATIONSHIP_BUG, '" size="5" maxlength="10" value="', $t_filter[FILTER_PROPERTY_RELATIONSHIP_BUG], '" />';
  3592. }
  3593. /**
  3594. * print tag fields
  3595. */
  3596. function print_filter_tag_string() {
  3597. if ( !access_has_global_level( config_get( 'tag_view_threshold' ) ) ) {
  3598. return;
  3599. }
  3600. global $t_filter;
  3601. $t_tag_string = $t_filter[FILTER_PROPERTY_TAG_STRING];
  3602. if( $t_filter[FILTER_PROPERTY_TAG_SELECT] != 0 && tag_exists( $t_filter[FILTER_PROPERTY_TAG_SELECT] ) ) {
  3603. $t_tag_string .= ( is_blank( $t_tag_string ) ? '' : config_get( 'tag_separator' ) );
  3604. $t_tag_string .= tag_get_field( $t_filter[FILTER_PROPERTY_TAG_SELECT], 'name' );
  3605. }
  3606. ?>
  3607. <input type="hidden" id="tag_separator" value="<?php echo config_get( 'tag_separator' )?>" />
  3608. <input type="text" name="<?php echo FILTER_PROPERTY_TAG_STRING;?>" id="<?php echo FILTER_PROPERTY_TAG_STRING;?>" size="40" value="<?php echo string_attribute( $t_tag_string )?>" />
  3609. <select <?php echo helper_get_tab_index()?> name="<?php echo FILTER_PROPERTY_TAG_SELECT;?>" id="<?php echo FILTER_PROPERTY_TAG_SELECT;?>">
  3610. <?php print_tag_option_list();?>
  3611. </select>
  3612. <?php
  3613. }
  3614. /**
  3615. * print note reporter field
  3616. */
  3617. function print_filter_note_user_id() {
  3618. global $t_select_modifier, $t_filter, $f_view_type;
  3619. ?>
  3620. <!-- BUGNOTE REPORTER -->
  3621. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_NOTE_USER_ID;?>[]">
  3622. <option value="<?php echo META_FILTER_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_NOTE_USER_ID], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
  3623. <?php if( access_has_project_level( config_get( 'view_handler_threshold' ) ) ) {?>
  3624. <option value="<?php echo META_FILTER_NONE?>" <?php check_selected( $t_filter[FILTER_PROPERTY_NOTE_USER_ID], META_FILTER_NONE );?>>[<?php echo lang_get( 'none' )?>]</option>
  3625. <?php
  3626. if( access_has_project_level( config_get( 'handle_bug_threshold' ) ) ) {
  3627. echo '<option value="' . META_FILTER_MYSELF . '" ';
  3628. check_selected( $t_filter[FILTER_PROPERTY_NOTE_USER_ID], META_FILTER_MYSELF );
  3629. echo '>[' . lang_get( 'myself' ) . ']</option>';
  3630. }
  3631. print_note_option_list( $t_filter[FILTER_PROPERTY_NOTE_USER_ID] );
  3632. }
  3633. ?>
  3634. </select>
  3635. <?php
  3636. }
  3637. /**
  3638. * Print plugin filter fields as defined by MantisFilter objects.
  3639. * @param string Field name
  3640. * @param object Filter object
  3641. */
  3642. function print_filter_plugin_field( $p_field_name, $p_filter_object ) {
  3643. global $t_select_modifier, $t_filter, $f_view_type;
  3644. $t_size = (int)$p_filter_object->size;
  3645. switch( $p_filter_object->type ) {
  3646. case FILTER_TYPE_STRING:
  3647. echo '<input name="', string_attribute( $p_field_name ), '"',
  3648. ( $t_size > 0 ? " size=\"$t_size\"" : '' ), ' value="',
  3649. string_attribute( $t_filter[ $p_field_name ] ), '"/>';
  3650. break;
  3651. case FILTER_TYPE_INT:
  3652. echo '<input name="', string_attribute( $p_field_name ), '"',
  3653. ( $t_size > 0 ? " size=\"$t_size\"" : '' ), ' value="',
  3654. (int) $t_filter[ $p_field_name ], '"/>';
  3655. break;
  3656. case FILTER_TYPE_BOOLEAN:
  3657. echo '<input name="', string_attribute( $p_field_name ), '" type="checkbox"',
  3658. ( $t_size > 0 ? " size=\"$t_size\"" : '' ), check_checked( (bool) $t_filter[ $p_field_name ] ) , '"/>';
  3659. break;
  3660. case FILTER_TYPE_MULTI_STRING:
  3661. echo '<select ', $t_select_modifier, ( $t_size > 0 ? " size=\"$t_size\"" : '' ), ' name="',
  3662. string_attribute( $p_field_name ), '[]">', '<option value="', META_FILTER_ANY, '" ',
  3663. check_selected( $t_filter[ $p_field_name ], META_FILTER_ANY ), '>[', lang_get( 'any' ), ']</option>';
  3664. foreach( $p_filter_object->options() as $t_option_value => $t_option_name ) {
  3665. echo '<option value="', string_attribute( $t_option_value ), '" ',
  3666. check_selected( $t_filter[ $p_field_name ], $t_option_value ), '>',
  3667. string_display_line( $t_option_name ), '</option>';
  3668. }
  3669. echo '</select>';
  3670. break;
  3671. case FILTER_TYPE_MULTI_INT:
  3672. echo '<select ', $t_select_modifier, ( $t_size > 0 ? " size=\"$t_size\"" : '' ), ' name="',
  3673. string_attribute( $p_field_name ), '[]">', '<option value="', META_FILTER_ANY, '" ',
  3674. check_selected( $t_filter[ $p_field_name ], META_FILTER_ANY ), '>[', lang_get( 'any' ), ']</option>';
  3675. foreach( $p_filter_object->options() as $t_option_value => $t_option_name ) {
  3676. echo '<option value="', (int)$t_option_value, '" ',
  3677. check_selected( $t_filter[ $p_field_name ], (int)$t_option_value ), '>',
  3678. string_display_line( $t_option_name ), '</option>';
  3679. }
  3680. echo '</select>';
  3681. break;
  3682. }
  3683. }
  3684. /**
  3685. * print custom fields
  3686. * @param int $p_field_id
  3687. */
  3688. function print_filter_custom_field( $p_field_id ) {
  3689. global $t_filter, $t_accessible_custom_fields_names, $t_accessible_custom_fields_types, $t_accessible_custom_fields_values, $t_accessible_custom_fields_ids, $t_select_modifier;
  3690. $j = array_search( $p_field_id, $t_accessible_custom_fields_ids );
  3691. if( $j === null || $j === false ) {
  3692. # Note: Prior to PHP 4.2.0, array_search() returns NULL on failure instead of FALSE.
  3693. ?>
  3694. <span style="color:red;weight:bold;">
  3695. unknown custom filter (custom <?php $p_field_id;?>)
  3696. </span>
  3697. <?php
  3698. } else if( isset( $t_accessible_custom_fields_names[$j] ) ) {
  3699. if( $t_accessible_custom_fields_types[$j] == CUSTOM_FIELD_TYPE_DATE ) {
  3700. print_filter_custom_field_date( $j, $p_field_id );
  3701. } else {
  3702. echo '<select ' . $t_select_modifier . ' name="custom_field_' . $p_field_id . '[]">';
  3703. echo '<option value="' . META_FILTER_ANY . '" ';
  3704. check_selected( $t_filter['custom_fields'][$p_field_id], META_FILTER_ANY );
  3705. echo '>[' . lang_get( 'any' ) . ']</option>';
  3706. # don't show META_FILTER_NONE for enumerated types as it's not possible for them to be blank
  3707. if( !in_array( $t_accessible_custom_fields_types[$j], array( CUSTOM_FIELD_TYPE_ENUM, CUSTOM_FIELD_TYPE_LIST, CUSTOM_FIELD_TYPE_MULTILIST ) ) ) {
  3708. echo '<option value="' . META_FILTER_NONE . '" ';
  3709. check_selected( $t_filter['custom_fields'][$p_field_id], META_FILTER_NONE );
  3710. echo '>[' . lang_get( 'none' ) . ']</option>';
  3711. }
  3712. if( is_array( $t_accessible_custom_fields_values[$j] ) ) {
  3713. $t_max_length = config_get( 'max_dropdown_length' );
  3714. foreach( $t_accessible_custom_fields_values[$j] as $t_item ) {
  3715. if(( utf8_strtolower( $t_item ) !== META_FILTER_ANY ) && ( utf8_strtolower( $t_item ) !== META_FILTER_NONE ) ) {
  3716. echo '<option value="' . string_attribute( $t_item ) . '" ';
  3717. if( isset( $t_filter['custom_fields'][$p_field_id] ) ) {
  3718. check_selected( $t_filter['custom_fields'][$p_field_id], $t_item );
  3719. }
  3720. echo '>' . string_attribute( string_shorten( $t_item, $t_max_length ) ) . '</option>' . "\n";
  3721. }
  3722. }
  3723. }
  3724. echo '</select>';
  3725. }
  3726. }
  3727. }
  3728. /**
  3729. * print sort fields
  3730. */
  3731. function print_filter_show_sort() {
  3732. global $t_filter;
  3733. # get all of the displayed fields for sort, then drop ones that
  3734. # are not appropriate and translate the rest
  3735. $t_fields = helper_get_columns_to_view();
  3736. $t_n_fields = count( $t_fields );
  3737. $t_shown_fields[''] = '';
  3738. for( $i = 0;$i < $t_n_fields;$i++ ) {
  3739. if( !in_array( $t_fields[$i], array( 'selection', 'edit', 'bugnotes_count', 'attachment_count' ) ) ) {
  3740. if( strpos( $t_fields[$i], 'custom_' ) === 0 ) {
  3741. $t_field_name = string_display( lang_get_defaulted( utf8_substr( $t_fields[$i], utf8_strlen( 'custom_' ) ) ) );
  3742. } else {
  3743. $t_field_name = string_get_field_name( $t_fields[$i] );
  3744. }
  3745. $t_shown_fields[$t_fields[$i]] = $t_field_name;
  3746. }
  3747. }
  3748. $t_shown_dirs[''] = '';
  3749. $t_shown_dirs['ASC'] = lang_get( 'bugnote_order_asc' );
  3750. $t_shown_dirs['DESC'] = lang_get( 'bugnote_order_desc' );
  3751. # get default values from filter structure
  3752. $t_sort_fields = explode( ',', $t_filter[FILTER_PROPERTY_SORT_FIELD_NAME] );
  3753. $t_dir_fields = explode( ',', $t_filter[FILTER_PROPERTY_SORT_DIRECTION] );
  3754. if( !isset( $t_sort_fields[1] ) ) {
  3755. $t_sort_fields[1] = '';
  3756. $t_dir_fields[1] = '';
  3757. }
  3758. # if there are fields to display, show the dropdowns
  3759. if( count( $t_fields ) > 0 ) {
  3760. # display a primary and secondary sort fields
  3761. echo '<select name="', FILTER_PROPERTY_SORT_FIELD_NAME, '_0">';
  3762. foreach( $t_shown_fields as $key => $val ) {
  3763. echo '<option value="' . $key . '"';
  3764. check_selected( $key, $t_sort_fields[0] );
  3765. echo '>' . $val . '</option>';
  3766. }
  3767. echo '</select>';
  3768. echo '<select name="', FILTER_PROPERTY_SORT_DIRECTION, '_0">';
  3769. foreach( $t_shown_dirs as $key => $val ) {
  3770. echo '<option value="' . $key . '"';
  3771. check_selected( $key, $t_dir_fields[0] );
  3772. echo '>' . $val . '</option>';
  3773. }
  3774. echo '</select>';
  3775. echo ', ';
  3776. # for secondary sort
  3777. echo '<select name="', FILTER_PROPERTY_SORT_FIELD_NAME, '_1">';
  3778. foreach( $t_shown_fields as $key => $val ) {
  3779. echo '<option value="' . $key . '"';
  3780. check_selected( $key, $t_sort_fields[1] );
  3781. echo '>' . $val . '</option>';
  3782. }
  3783. echo '</select>';
  3784. echo '<select name="', FILTER_PROPERTY_SORT_DIRECTION, '_1">';
  3785. foreach( $t_shown_dirs as $key => $val ) {
  3786. echo '<option value="' . $key . '"';
  3787. check_selected( $key, $t_dir_fields[1] );
  3788. echo '>' . $val . '</option>';
  3789. }
  3790. echo '</select>';
  3791. } else {
  3792. echo lang_get_defaulted( 'last_updated' ) . lang_get( 'bugnote_order_desc' );
  3793. echo '<input type="hidden" name="', FILTER_PROPERTY_SORT_FIELD_NAME, '_1" value="last_updated" />';
  3794. echo '<input type="hidden" name="', FILTER_PROPERTY_SORT_DIRECTION, '_1" value="DESC" />';
  3795. }
  3796. }
  3797. /**
  3798. * print custom field date fields
  3799. * @param int $p_field_num
  3800. * @param int $p_field_id
  3801. */
  3802. function print_filter_custom_field_date( $p_field_num, $p_field_id ) {
  3803. global $t_filter, $t_accessible_custom_fields_names, $t_accessible_custom_fields_types, $t_accessible_custom_fields_values, $t_accessible_custom_fields_ids, $t_select_modifier;
  3804. $t_js_toggle_func = 'toggle_custom_date_field_' . $p_field_id . '_controls';
  3805. # Resort the values so there ordered numerically, they are sorted as strings otherwise which
  3806. # may be wrong for dates before early 2001.
  3807. if( is_array( $t_accessible_custom_fields_values[$p_field_num] ) ) {
  3808. array_multisort( $t_accessible_custom_fields_values[$p_field_num], SORT_NUMERIC, SORT_ASC );
  3809. }
  3810. $t_sel_start_year = null;
  3811. $t_sel_end_year = null;
  3812. if( isset( $t_accessible_custom_fields_values[$p_field_num][0] ) ) {
  3813. $t_sel_start_year = date( 'Y', $t_accessible_custom_fields_values[$p_field_num][0] );
  3814. }
  3815. $t_count = count( $t_accessible_custom_fields_values[$p_field_num] );
  3816. if( isset( $t_accessible_custom_fields_values[$p_field_num][$t_count - 1] ) ) {
  3817. $t_sel_end_year = date( 'Y', $t_accessible_custom_fields_values[$p_field_num][$t_count - 1] );
  3818. }
  3819. $t_start = date( 'U' );
  3820. # Default to today in filters..
  3821. $t_end = $t_start;
  3822. if( isset( $t_filter['custom_fields'][$p_field_id][1] ) ) {
  3823. $t_start_time = $t_filter['custom_fields'][$p_field_id][1];
  3824. } else {
  3825. $t_start_time = 0;
  3826. }
  3827. if( isset( $t_filter['custom_fields'][$p_field_id][2] ) ) {
  3828. $t_end_time = $t_filter['custom_fields'][$p_field_id][2];
  3829. } else {
  3830. $t_end_time = 0;
  3831. }
  3832. if( OFF == config_get( 'use_javascript' ) ) {
  3833. $t_start_disable = false;
  3834. $t_end_disable = false;
  3835. } else {
  3836. $t_start_disable = true;
  3837. $t_end_disable = true;
  3838. # if $t_filter['custom_fields'][$p_field_id][0] is not set (ie no filter),
  3839. # we will drop through the following switch and use the default values
  3840. # above, so no need to check if stuff is set or not.
  3841. switch( $t_filter['custom_fields'][$p_field_id][0] ) {
  3842. case CUSTOM_FIELD_DATE_ANY:
  3843. case CUSTOM_FIELD_DATE_NONE:
  3844. break;
  3845. case CUSTOM_FIELD_DATE_BETWEEN:
  3846. $t_start_disable = false;
  3847. $t_end_disable = false;
  3848. $t_start = $t_start_time;
  3849. $t_end = $t_end_time;
  3850. break;
  3851. case CUSTOM_FIELD_DATE_ONORBEFORE:
  3852. $t_start_disable = false;
  3853. $t_start = $t_end_time;
  3854. break;
  3855. case CUSTOM_FIELD_DATE_BEFORE:
  3856. $t_start_disable = false;
  3857. $t_start = $t_end_time;
  3858. break;
  3859. case CUSTOM_FIELD_DATE_ON:
  3860. $t_start_disable = false;
  3861. $t_start = $t_start_time;
  3862. break;
  3863. case CUSTOM_FIELD_DATE_AFTER:
  3864. $t_start_disable = false;
  3865. $t_start = $t_start_time;
  3866. break;
  3867. case CUSTOM_FIELD_DATE_ONORAFTER:
  3868. $t_start_disable = false;
  3869. $t_start = $t_start_time;
  3870. break;
  3871. }
  3872. }
  3873. echo "\n<table cellspacing=\"0\" cellpadding=\"0\"><tr><td>\n";
  3874. echo "<select size=\"1\" name=\"custom_field_" . $p_field_id . "_control\" OnChange=\"" . $t_js_toggle_func . "();\">\n";
  3875. echo '<option value="' . CUSTOM_FIELD_DATE_ANY . '"';
  3876. check_selected( $t_filter['custom_fields'][$p_field_id][0], CUSTOM_FIELD_DATE_ANY );
  3877. echo '>' . lang_get( 'any' ) . '</option>' . "\n";
  3878. echo '<option value="' . CUSTOM_FIELD_DATE_NONE . '"';
  3879. check_selected( $t_filter['custom_fields'][$p_field_id][0], CUSTOM_FIELD_DATE_NONE );
  3880. echo '>' . lang_get( 'none' ) . '</option>' . "\n";
  3881. echo '<option value="' . CUSTOM_FIELD_DATE_BETWEEN . '"';
  3882. check_selected( $t_filter['custom_fields'][$p_field_id][0], CUSTOM_FIELD_DATE_BETWEEN );
  3883. echo '>' . lang_get( 'between_date' ) . '</option>' . "\n";
  3884. echo '<option value="' . CUSTOM_FIELD_DATE_ONORBEFORE . '"';
  3885. check_selected( $t_filter['custom_fields'][$p_field_id][0], CUSTOM_FIELD_DATE_ONORBEFORE );
  3886. echo '>' . lang_get( 'on_or_before_date' ) . '</option>' . "\n";
  3887. echo '<option value="' . CUSTOM_FIELD_DATE_BEFORE . '"';
  3888. check_selected( $t_filter['custom_fields'][$p_field_id][0], CUSTOM_FIELD_DATE_BEFORE );
  3889. echo '>' . lang_get( 'before_date' ) . '</option>' . "\n";
  3890. echo '<option value="' . CUSTOM_FIELD_DATE_ON . '"';
  3891. check_selected( $t_filter['custom_fields'][$p_field_id][0], CUSTOM_FIELD_DATE_ON );
  3892. echo '>' . lang_get( 'on_date' ) . '</option>' . "\n";
  3893. echo '<option value="' . CUSTOM_FIELD_DATE_AFTER . '"';
  3894. check_selected( $t_filter['custom_fields'][$p_field_id][0], CUSTOM_FIELD_DATE_AFTER );
  3895. echo '>' . lang_get( 'after_date' ) . '</option>' . "\n";
  3896. echo '<option value="' . CUSTOM_FIELD_DATE_ONORAFTER . '"';
  3897. check_selected( $t_filter['custom_fields'][$p_field_id][0], CUSTOM_FIELD_DATE_ONORAFTER );
  3898. echo '>' . lang_get( 'on_or_after_date' ) . '</option>' . "\n";
  3899. echo '</select>' . "\n";
  3900. echo "</td></tr>\n<tr><td>";
  3901. print_date_selection_set( 'custom_field_' . $p_field_id . '_start', config_get( 'short_date_format' ), $t_start, $t_start_disable, false, $t_sel_start_year, $t_sel_end_year );
  3902. print "</td></tr>\n<tr><td>";
  3903. print_date_selection_set( 'custom_field_' . $p_field_id . '_end', config_get( 'short_date_format' ), $t_end, $t_end_disable, false, $t_sel_start_year, $t_sel_end_year );
  3904. print "</td></tr>\n</table>";
  3905. }
  3906. /**
  3907. * print project field
  3908. */
  3909. function print_filter_project_id() {
  3910. global $t_select_modifier, $t_filter, $f_view_type;
  3911. ?>
  3912. <!-- Project -->
  3913. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_PROJECT_ID;?>[]">
  3914. <option value="<?php echo META_FILTER_CURRENT?>" <?php check_selected( $t_filter[FILTER_PROPERTY_PROJECT_ID], META_FILTER_CURRENT );?>>[<?php echo lang_get( 'current' )?>]</option>
  3915. <?php print_project_option_list( $t_filter[FILTER_PROPERTY_PROJECT_ID] )?>
  3916. </select>
  3917. <?php
  3918. }
  3919. function print_filter_match_type() {
  3920. global $t_select_modifier, $t_filter, $f_view_type;
  3921. ?>
  3922. <!-- Project -->
  3923. <select <?php echo $t_select_modifier;?> name="<?php echo FILTER_PROPERTY_MATCH_TYPE;?>">
  3924. <option value="<?php echo FILTER_MATCH_ALL?>" <?php check_selected( $t_filter[FILTER_PROPERTY_MATCH_TYPE], FILTER_MATCH_ALL );?>>[<?php echo lang_get( 'filter_match_all' )?>]</option>
  3925. <option value="<?php echo FILTER_MATCH_ANY?>" <?php check_selected( $t_filter[FILTER_PROPERTY_MATCH_TYPE], FILTER_MATCH_ANY );?>>[<?php echo lang_get( 'filter_match_any' )?>]</option>
  3926. </select>
  3927. <?php
  3928. }
  3929. /**
  3930. * Prints a multi-value filter field.
  3931. * @param string $p_field_name
  3932. * @param mixed $p_field_value
  3933. */
  3934. function print_multivalue_field( $p_field_name, $p_field_value ) {
  3935. $t_output = '';
  3936. $t_any_found = false;
  3937. if( count( $p_field_value ) == 0 ) {
  3938. echo lang_get( 'any' );
  3939. } else {
  3940. $t_first_flag = true;
  3941. $t_field_value = is_array( $p_field_value ) ? $p_field_value : array( $p_field_value );
  3942. foreach( $t_field_value as $t_current ) {
  3943. $t_current = stripslashes( $t_current );
  3944. ?>
  3945. <input type="hidden" name="<?php echo string_attribute( $p_field_name )?>[]" value="<?php echo string_attribute( $t_current );?>" />
  3946. <?php
  3947. $t_this_string = '';
  3948. if((( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) || ( is_blank( $t_current ) ) ) {
  3949. $t_any_found = true;
  3950. } else {
  3951. $t_this_string = string_display( $t_current );
  3952. }
  3953. if( $t_first_flag != true ) {
  3954. $t_output .= '<br />';
  3955. } else {
  3956. $t_first_flag = false;
  3957. }
  3958. $t_output .= $t_this_string;
  3959. }
  3960. if( true == $t_any_found ) {
  3961. echo lang_get( 'any' );
  3962. } else {
  3963. echo $t_output;
  3964. }
  3965. }
  3966. }
  3967. # ==========================================================================
  3968. # CACHING
  3969. # ==========================================================================
  3970. /**
  3971. * @internal SECURITY NOTE: cache globals are initialized here to prevent them
  3972. * being spoofed if register_globals is turned on.
  3973. * We cache filter requests to reduce the number of SQL queries
  3974. * @global mixed $g_cache_filter
  3975. * @global mixed $g_cache_filter_db_filters
  3976. */
  3977. $g_cache_filter = array();
  3978. $g_cache_filter_db_filters = array();
  3979. /**
  3980. * Cache a filter row if necessary and return the cached copy
  3981. * If the second parameter is true (default), trigger an error
  3982. * if the filter can't be found. If the second parameter is
  3983. * false, return false if the filter can't be found.
  3984. * @param int $p_filter_id
  3985. * @param bool $p_trigger_errors
  3986. * @return mixed
  3987. */
  3988. function filter_cache_row( $p_filter_id, $p_trigger_errors = true ) {
  3989. global $g_cache_filter;
  3990. $c_filter_id = db_prepare_int( $p_filter_id );
  3991. $t_filters_table = db_get_table( 'mantis_filters_table' );
  3992. if( isset( $g_cache_filter[$c_filter_id] ) ) {
  3993. return $g_cache_filter[$c_filter_id];
  3994. }
  3995. $query = 'SELECT *
  3996. FROM ' . $t_filters_table . '
  3997. WHERE id=' . db_param();
  3998. $result = db_query_bound( $query, Array( $c_filter_id ) );
  3999. if( 0 == db_num_rows( $result ) ) {
  4000. if( $p_trigger_errors ) {
  4001. error_parameters( $p_filter_id );
  4002. trigger_error( ERROR_FILTER_NOT_FOUND, ERROR );
  4003. } else {
  4004. return false;
  4005. }
  4006. }
  4007. $row = db_fetch_array( $result );
  4008. $g_cache_filter[$c_filter_id] = $row;
  4009. return $row;
  4010. }
  4011. /**
  4012. * Clear the filter cache (or just the given id if specified)
  4013. * @param int $p_filter_id
  4014. * @return bool
  4015. */
  4016. function filter_clear_cache( $p_filter_id = null ) {
  4017. global $g_cache_filter;
  4018. if( null === $p_filter_id ) {
  4019. $g_cache_filter = array();
  4020. } else {
  4021. $c_filter_id = db_prepare_int( $p_filter_id );
  4022. unset( $g_cache_filter[$c_filter_id] );
  4023. }
  4024. return true;
  4025. }
  4026. # ==========================================================================
  4027. # FILTER DB FUNCTIONS
  4028. # ==========================================================================
  4029. /**
  4030. * Add a filter to the database for the current user
  4031. * @param int $p_project_id
  4032. * @param bool $p_is_public
  4033. * @param string $p_name
  4034. * @param string $p_filter_string
  4035. * @return int
  4036. */
  4037. function filter_db_set_for_current_user( $p_project_id, $p_is_public, $p_name, $p_filter_string ) {
  4038. $t_user_id = auth_get_current_user_id();
  4039. $c_project_id = db_prepare_int( $p_project_id );
  4040. $c_is_public = db_prepare_bool( $p_is_public );
  4041. $t_filters_table = db_get_table( 'mantis_filters_table' );
  4042. # check that the user can save non current filters (if required)
  4043. if(( ALL_PROJECTS <= $c_project_id ) && ( !is_blank( $p_name ) ) && ( !access_has_project_level( config_get( 'stored_query_create_threshold' ) ) ) ) {
  4044. return -1;
  4045. }
  4046. # ensure that we're not making this filter public if we're not allowed
  4047. if( !access_has_project_level( config_get( 'stored_query_create_shared_threshold' ) ) ) {
  4048. $c_is_public = db_prepare_bool( false );
  4049. }
  4050. # Do I need to update or insert this value?
  4051. $query = "SELECT id FROM $t_filters_table
  4052. WHERE user_id=" . db_param() . "
  4053. AND project_id=" . db_param() . "
  4054. AND name=" . db_param();
  4055. $result = db_query_bound( $query, Array( $t_user_id, $c_project_id, $p_name ) );
  4056. if( db_num_rows( $result ) > 0 ) {
  4057. $row = db_fetch_array( $result );
  4058. $query = "UPDATE $t_filters_table
  4059. SET is_public=" . db_param() . ",
  4060. filter_string=" . db_param() . "
  4061. WHERE id=" . db_param();
  4062. db_query_bound( $query, Array( $c_is_public, $p_filter_string, $row['id'] ) );
  4063. return $row['id'];
  4064. } else {
  4065. $query = "INSERT INTO $t_filters_table
  4066. ( user_id, project_id, is_public, name, filter_string )
  4067. VALUES
  4068. ( " . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ' )';
  4069. db_query_bound( $query, Array( $t_user_id, $c_project_id, $c_is_public, $p_name, $p_filter_string ) );
  4070. # Recall the query, we want the filter ID
  4071. $query = "SELECT id
  4072. FROM $t_filters_table
  4073. WHERE user_id=" . db_param() . "
  4074. AND project_id=" . db_param() . "
  4075. AND name=" . db_param();
  4076. $result = db_query_bound( $query, Array( $t_user_id, $c_project_id, $p_name ) );
  4077. if( db_num_rows( $result ) > 0 ) {
  4078. $row = db_fetch_array( $result );
  4079. return $row['id'];
  4080. }
  4081. return -1;
  4082. }
  4083. }
  4084. /**
  4085. * This function returns the filter string that is
  4086. * tied to the unique id parameter. If the user doesn't
  4087. * have permission to see this filter, the function
  4088. * returns null
  4089. * @param int $p_filter_id
  4090. * @param int $p_user_id
  4091. * @return mixed
  4092. */
  4093. function filter_db_get_filter( $p_filter_id, $p_user_id = null ) {
  4094. global $g_cache_filter_db_filters;
  4095. $t_filters_table = db_get_table( 'mantis_filters_table' );
  4096. $c_filter_id = db_prepare_int( $p_filter_id );
  4097. if( isset( $g_cache_filter_db_filters[$p_filter_id] ) ) {
  4098. if( $g_cache_filter_db_filters[$p_filter_id] === false ) {
  4099. return null;
  4100. }
  4101. return $g_cache_filter_db_filters[$p_filter_id];
  4102. }
  4103. if( null === $p_user_id ) {
  4104. $t_user_id = auth_get_current_user_id();
  4105. } else {
  4106. $t_user_id = $p_user_id;
  4107. }
  4108. $query = 'SELECT * FROM ' . $t_filters_table . ' WHERE id=' . db_param();
  4109. $result = db_query_bound( $query, Array( $c_filter_id ) );
  4110. if( db_num_rows( $result ) > 0 ) {
  4111. $row = db_fetch_array( $result );
  4112. if( $row['user_id'] != $t_user_id ) {
  4113. if( $row['is_public'] != true ) {
  4114. return null;
  4115. }
  4116. }
  4117. # check that the user has access to non current filters
  4118. if(( ALL_PROJECTS <= $row['project_id'] ) && ( !is_blank( $row['name'] ) ) && ( !access_has_project_level( config_get( 'stored_query_use_threshold', null, $t_user_id, $row['project_id'] ) ) ) ) {
  4119. return null;
  4120. }
  4121. $g_cache_filter_db_filters[$p_filter_id] = $row['filter_string'];
  4122. return $row['filter_string'];
  4123. } else {
  4124. $g_cache_filter_db_filters[$p_filter_id] = false;
  4125. return false;
  4126. }
  4127. }
  4128. /**
  4129. * @param int $p_project_id
  4130. * @param int $p_user_id
  4131. * @return int
  4132. */
  4133. function filter_db_get_project_current( $p_project_id, $p_user_id = null ) {
  4134. $t_filters_table = db_get_table( 'mantis_filters_table' );
  4135. $c_project_id = db_prepare_int( $p_project_id );
  4136. $c_project_id = $c_project_id * -1;
  4137. if( null === $p_user_id ) {
  4138. $c_user_id = auth_get_current_user_id();
  4139. } else {
  4140. $c_user_id = db_prepare_int( $p_user_id );
  4141. }
  4142. # we store current filters for each project with a special project index
  4143. $query = "SELECT *
  4144. FROM $t_filters_table
  4145. WHERE user_id=" . db_param() . "
  4146. AND project_id=" . db_param() . "
  4147. AND name=" . db_param();
  4148. $result = db_query_bound( $query, Array( $c_user_id, $c_project_id, '' ) );
  4149. if( db_num_rows( $result ) > 0 ) {
  4150. $row = db_fetch_array( $result );
  4151. return $row['id'];
  4152. }
  4153. return null;
  4154. }
  4155. /**
  4156. * Query for the filter name using the filter id
  4157. * @param int $p_filter_id
  4158. * @return string
  4159. */
  4160. function filter_db_get_name( $p_filter_id ) {
  4161. $t_filters_table = db_get_table( 'mantis_filters_table' );
  4162. $c_filter_id = db_prepare_int( $p_filter_id );
  4163. $query = 'SELECT * FROM ' . $t_filters_table . ' WHERE id=' . db_param();
  4164. $result = db_query_bound( $query, Array( $c_filter_id ) );
  4165. if( db_num_rows( $result ) > 0 ) {
  4166. $row = db_fetch_array( $result );
  4167. if( $row['user_id'] != auth_get_current_user_id() ) {
  4168. if( $row['is_public'] != true ) {
  4169. return null;
  4170. }
  4171. }
  4172. return $row['name'];
  4173. }
  4174. return null;
  4175. }
  4176. /**
  4177. * Check if the current user has permissions to delete the stored query
  4178. * @param $p_filter_id
  4179. * @return bool
  4180. */
  4181. function filter_db_can_delete_filter( $p_filter_id ) {
  4182. $t_filters_table = db_get_table( 'mantis_filters_table' );
  4183. $c_filter_id = db_prepare_int( $p_filter_id );
  4184. $t_user_id = auth_get_current_user_id();
  4185. # Administrators can delete any filter
  4186. if( user_is_administrator( $t_user_id ) ) {
  4187. return true;
  4188. }
  4189. $query = "SELECT id
  4190. FROM $t_filters_table
  4191. WHERE id=" . db_param() . "
  4192. AND user_id=" . db_param() . "
  4193. AND project_id!=" . db_param();
  4194. $result = db_query_bound( $query, Array( $c_filter_id, $t_user_id, -1 ) );
  4195. if( db_num_rows( $result ) > 0 ) {
  4196. return true;
  4197. }
  4198. return false;
  4199. }
  4200. /**
  4201. * Delete the filter specified by $p_filter_id
  4202. * @param $p_filter_id
  4203. * @return bool
  4204. */
  4205. function filter_db_delete_filter( $p_filter_id ) {
  4206. $t_filters_table = db_get_table( 'mantis_filters_table' );
  4207. $c_filter_id = db_prepare_int( $p_filter_id );
  4208. $t_user_id = auth_get_current_user_id();
  4209. if( !filter_db_can_delete_filter( $c_filter_id ) ) {
  4210. return false;
  4211. }
  4212. $query = 'DELETE FROM ' . $t_filters_table . ' WHERE id=' . db_param();
  4213. $result = db_query_bound( $query, Array( $c_filter_id ) );
  4214. if( db_affected_rows( $result ) > 0 ) {
  4215. return true;
  4216. }
  4217. return false;
  4218. }
  4219. /**
  4220. * Delete all the unnamed filters
  4221. */
  4222. function filter_db_delete_current_filters() {
  4223. $t_filters_table = db_get_table( 'mantis_filters_table' );
  4224. $t_all_id = ALL_PROJECTS;
  4225. $query = "DELETE FROM $t_filters_table
  4226. WHERE project_id<=" . db_param() . "
  4227. AND name=" . db_param();
  4228. $result = db_query_bound( $query, Array( $t_all_id, '' ) );
  4229. }
  4230. /**
  4231. * Note: any changes made in this function should be reflected in
  4232. * mci_filter_db_get_available_queries())
  4233. * @param int $p_project_id
  4234. * @param int $p_user_id
  4235. * @return mixed
  4236. */
  4237. function filter_db_get_available_queries( $p_project_id = null, $p_user_id = null ) {
  4238. $t_filters_table = db_get_table( 'mantis_filters_table' );
  4239. $t_overall_query_arr = array();
  4240. if( null === $p_project_id ) {
  4241. $t_project_id = helper_get_current_project();
  4242. } else {
  4243. $t_project_id = db_prepare_int( $p_project_id );
  4244. }
  4245. if( null === $p_user_id ) {
  4246. $t_user_id = auth_get_current_user_id();
  4247. } else {
  4248. $t_user_id = db_prepare_int( $p_user_id );
  4249. }
  4250. # If the user doesn't have access rights to stored queries, just return
  4251. if( !access_has_project_level( config_get( 'stored_query_use_threshold' ) ) ) {
  4252. return $t_overall_query_arr;
  4253. }
  4254. # Get the list of available queries. By sorting such that public queries are
  4255. # first, we can override any query that has the same name as a private query
  4256. # with that private one
  4257. $query = "SELECT * FROM $t_filters_table
  4258. WHERE (project_id=" . db_param() . "
  4259. OR project_id=0)
  4260. AND name!=''
  4261. AND (is_public = " . db_prepare_bool(true) . "
  4262. OR user_id = " . db_param() . ")
  4263. ORDER BY is_public DESC, name ASC";
  4264. $result = db_query_bound( $query, Array( $t_project_id, $t_user_id ) );
  4265. $query_count = db_num_rows( $result );
  4266. for( $i = 0;$i < $query_count;$i++ ) {
  4267. $row = db_fetch_array( $result );
  4268. $t_overall_query_arr[$row['id']] = $row['name'];
  4269. }
  4270. $t_overall_query_arr = array_unique( $t_overall_query_arr );
  4271. asort( $t_overall_query_arr );
  4272. return $t_overall_query_arr;
  4273. }
  4274. /**
  4275. * @param str $p_name
  4276. * @return bool true when under max_length (64) and false when over
  4277. */
  4278. function filter_name_valid_length( $p_name ) {
  4279. if( utf8_strlen( $p_name ) > 64 ) {
  4280. return false;
  4281. } else {
  4282. return true;
  4283. }
  4284. }