PageRenderTime 63ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/MantisBT/core/filter_api.php

https://bitbucket.org/crypticrod/sr_wp_code
PHP | 4685 lines | 4175 code | 243 blank | 267 comment | 409 complexity | 7d7a1ad67a7a71e514e4cddea3dc9153 MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0, LGPL-2.1, GPL-3.0, LGPL-2.0, AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  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 - 2011 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. if( isset( $p_custom_filter['custom_fields'] ) ) {
  210. foreach( $p_custom_filter['custom_fields'] as $t_custom_field_id => $t_custom_field_values ) {
  211. if( !filter_field_is_any( $t_custom_field_values ) ) {
  212. $t_query[] = filter_encode_field_and_value( 'custom_field_' . $t_custom_field_id, $t_custom_field_values );
  213. }
  214. }
  215. }
  216. # Allow plugins to add filter fields
  217. $t_plugin_filter_array = filter_get_plugin_filters();
  218. foreach( $t_plugin_filter_array as $t_field_name => $t_filter_object ) {
  219. if( !filter_field_is_any( $p_custom_filter[ $t_field_name ] ) ) {
  220. $t_query[] = filter_encode_field_and_value( $t_field_name, $p_custom_filter[ $t_field_name ], $t_filter_object->type );
  221. }
  222. }
  223. if( count( $t_query ) > 0 ) {
  224. $t_query_str = implode( $t_query, '&' );
  225. $t_url = config_get( 'path' ) . 'search.php?' . $t_query_str;
  226. } else {
  227. $t_url = '';
  228. }
  229. return $t_url;
  230. }
  231. /**
  232. * Encodes a field and it's value for the filter URL. This handles the URL encoding
  233. * and arrays.
  234. * @param string $p_field_name The field name.
  235. * @param string $p_field_value The field value (can be an array)
  236. * @return string url encoded string
  237. */
  238. function filter_encode_field_and_value( $p_field_name, $p_field_value, $p_field_type=null ) {
  239. $t_query_array = array();
  240. if( is_array( $p_field_value ) ) {
  241. $t_count = count( $p_field_value );
  242. if( $t_count > 1 || $p_field_type == FILTER_TYPE_MULTI_STRING || $p_field_type == FILTER_TYPE_MULTI_INT ) {
  243. foreach( $p_field_value as $t_value ) {
  244. $t_query_array[] = urlencode( $p_field_name . '[]' ) . '=' . urlencode( $t_value );
  245. }
  246. }
  247. else if( $t_count == 1 ) {
  248. $t_query_array[] = urlencode( $p_field_name ) . '=' . urlencode( $p_field_value[0] );
  249. }
  250. } else {
  251. $t_query_array[] = urlencode( $p_field_name ) . '=' . urlencode( $p_field_value );
  252. }
  253. return implode( $t_query_array, '&' );
  254. }
  255. # ==========================================================================
  256. # GENERAL FUNCTIONS =
  257. # ==========================================================================
  258. /**
  259. * Checks the supplied value to see if it is an ANY value.
  260. * @param string $p_field_value - The value to check.
  261. * @return bool true for "ANY" values and false for others. "ANY" means filter criteria not active.
  262. */
  263. function filter_field_is_any( $p_field_value ) {
  264. if( is_array( $p_field_value ) ) {
  265. if( count( $p_field_value ) == 0 ) {
  266. return true;
  267. }
  268. foreach( $p_field_value as $t_value ) {
  269. if(( META_FILTER_ANY == $t_value ) && ( is_numeric( $t_value ) ) ) {
  270. return true;
  271. }
  272. }
  273. } else {
  274. if( is_string( $p_field_value ) && is_blank( $p_field_value ) ) {
  275. return true;
  276. }
  277. if( is_bool( $p_field_value ) && !$p_field_value ) {
  278. return true;
  279. }
  280. if(( META_FILTER_ANY == $p_field_value ) && ( is_numeric( $p_field_value ) ) ) {
  281. return true;
  282. }
  283. }
  284. return false;
  285. }
  286. /**
  287. * Checks the supplied value to see if it is a NONE value.
  288. * @param string $p_field_value - The value to check.
  289. * @return bool true for "NONE" values and false for others.
  290. * @todo is a check for these necessary? if ( ( $t_filter_value === 'none' ) || ( $t_filter_value === '[none]' ) )
  291. */
  292. function filter_field_is_none( $p_field_value ) {
  293. if( is_array( $p_field_value ) ) {
  294. foreach( $p_field_value as $t_value ) {
  295. if(( META_FILTER_NONE == $t_value ) && ( is_numeric( $t_value ) ) ) {
  296. return true;
  297. }
  298. }
  299. } else {
  300. if( is_string( $p_field_value ) && is_blank( $p_field_value ) ) {
  301. return false;
  302. }
  303. if(( META_FILTER_NONE == $p_field_value ) && ( is_numeric( $p_field_value ) ) ) {
  304. return true;
  305. }
  306. }
  307. return false;
  308. }
  309. /**
  310. * Checks the supplied value to see if it is a MYSELF value.
  311. * @param string $p_field_value - The value to check.
  312. * @return bool true for "MYSELF" values and false for others.
  313. */
  314. function filter_field_is_myself( $p_field_value ) {
  315. return( META_FILTER_MYSELF == $p_field_value ? TRUE : FALSE );
  316. }
  317. /**
  318. * @param $p_count
  319. * @param $p_per_page
  320. * @return int
  321. */
  322. function filter_per_page( $p_filter, $p_count, $p_per_page ) {
  323. $p_per_page = (( NULL == $p_per_page ) ? (int) $p_filter[FILTER_PROPERTY_ISSUES_PER_PAGE] : $p_per_page );
  324. $p_per_page = (( 0 == $p_per_page || -1 == $p_per_page ) ? $p_count : $p_per_page );
  325. return (int) abs( $p_per_page );
  326. }
  327. /**
  328. * Use $p_count and $p_per_page to determine how many pages to split this list up into.
  329. * For the sake of consistency have at least one page, even if it is empty.
  330. * @param $p_count
  331. * @param $p_per_page
  332. * @return $t_page_count
  333. */
  334. function filter_page_count( $p_count, $p_per_page ) {
  335. $t_page_count = ceil( $p_count / $p_per_page );
  336. if( $t_page_count < 1 ) {
  337. $t_page_count = 1;
  338. }
  339. return $t_page_count;
  340. }
  341. /**
  342. * Checks to make sure $p_page_number isn't past the last page.
  343. * and that $p_page_number isn't before the first page
  344. * @param $p_page_number
  345. * @param $p_page_count
  346. */
  347. function filter_valid_page_number( $p_page_number, $p_page_count ) {
  348. if( $p_page_number > $p_page_count ) {
  349. $p_page_number = $p_page_count;
  350. }
  351. if( $p_page_number < 1 ) {
  352. $p_page_number = 1;
  353. }
  354. return $p_page_number;
  355. }
  356. /**
  357. * Figure out the offset into the db query, offset is which record to start querying from
  358. * @param int $p_page_number
  359. * @param int $p_per_page
  360. * @return int
  361. */
  362. function filter_offset( $p_page_number, $p_per_page ) {
  363. return(( (int) $p_page_number -1 ) * (int) $p_per_page );
  364. }
  365. /**
  366. * Make sure that our filters are entirely correct and complete (it is possible that they are not).
  367. * We need to do this to cover cases where we don't have complete control over the filters given.s
  368. * @param array $p_filter_arr
  369. * @return mixed
  370. * @todo function needs to be abstracted
  371. */
  372. function filter_ensure_valid_filter( $p_filter_arr ) {
  373. # extend current filter to add information passed via POST
  374. if( !isset( $p_filter_arr['_version'] ) ) {
  375. $p_filter_arr['_version'] = config_get( 'cookie_version' );
  376. }
  377. $t_cookie_vers = (int) utf8_substr( $p_filter_arr['_version'], 1 );
  378. if( utf8_substr( config_get( 'cookie_version' ), 1 ) > $t_cookie_vers ) {
  379. # if the version is old, update it
  380. $p_filter_arr['_version'] = config_get( 'cookie_version' );
  381. }
  382. if( !isset( $p_filter_arr['_view_type'] ) ) {
  383. $p_filter_arr['_view_type'] = gpc_get_string( 'view_type', 'simple' );
  384. }
  385. if( !isset( $p_filter_arr[FILTER_PROPERTY_ISSUES_PER_PAGE] ) ) {
  386. $p_filter_arr[FILTER_PROPERTY_ISSUES_PER_PAGE] = gpc_get_int( FILTER_PROPERTY_ISSUES_PER_PAGE, config_get( 'default_limit_view' ) );
  387. }
  388. if( !isset( $p_filter_arr[FILTER_PROPERTY_HIGHLIGHT_CHANGED] ) ) {
  389. $p_filter_arr[FILTER_PROPERTY_HIGHLIGHT_CHANGED] = config_get( 'default_show_changed' );
  390. }
  391. if( !isset( $p_filter_arr[FILTER_PROPERTY_SHOW_STICKY_ISSUES] ) ) {
  392. $p_filter_arr[FILTER_PROPERTY_SHOW_STICKY_ISSUES] = gpc_string_to_bool( config_get( 'show_sticky_issues' ) );
  393. }
  394. if( !isset( $p_filter_arr[FILTER_PROPERTY_SORT_FIELD_NAME] ) ) {
  395. $p_filter_arr[FILTER_PROPERTY_SORT_FIELD_NAME] = "last_updated";
  396. }
  397. if( !isset( $p_filter_arr[FILTER_PROPERTY_SORT_DIRECTION] ) ) {
  398. $p_filter_arr[FILTER_PROPERTY_SORT_DIRECTION] = "DESC";
  399. }
  400. if( !isset( $p_filter_arr[FILTER_PROPERTY_PLATFORM] ) ) {
  401. $p_filter_arr[FILTER_PROPERTY_PLATFORM] = array(
  402. 0 => META_FILTER_ANY,
  403. );
  404. }
  405. if( !isset( $p_filter_arr[FILTER_PROPERTY_OS] ) ) {
  406. $p_filter_arr[FILTER_PROPERTY_OS] = array(
  407. 0 => META_FILTER_ANY,
  408. );
  409. }
  410. if( !isset( $p_filter_arr[FILTER_PROPERTY_OS_BUILD] ) ) {
  411. $p_filter_arr[FILTER_PROPERTY_OS_BUILD] = array(
  412. 0 => META_FILTER_ANY,
  413. );
  414. }
  415. if( !isset( $p_filter_arr[FILTER_PROPERTY_PROJECT_ID] ) ) {
  416. $p_filter_arr[FILTER_PROPERTY_PROJECT_ID] = array(
  417. 0 => META_FILTER_CURRENT,
  418. );
  419. }
  420. if( !isset( $p_filter_arr[FILTER_PROPERTY_START_MONTH] ) ) {
  421. $p_filter_arr[FILTER_PROPERTY_START_MONTH] = gpc_get_string( FILTER_PROPERTY_START_MONTH, date( 'm' ) );
  422. }
  423. if( !isset( $p_filter_arr[FILTER_PROPERTY_START_DAY] ) ) {
  424. $p_filter_arr[FILTER_PROPERTY_START_DAY] = gpc_get_string( FILTER_PROPERTY_START_DAY, 1 );
  425. }
  426. if( !isset( $p_filter_arr[FILTER_PROPERTY_START_YEAR] ) ) {
  427. $p_filter_arr[FILTER_PROPERTY_START_YEAR] = gpc_get_string( FILTER_PROPERTY_START_YEAR, date( 'Y' ) );
  428. }
  429. if( !isset( $p_filter_arr[FILTER_PROPERTY_END_MONTH] ) ) {
  430. $p_filter_arr[FILTER_PROPERTY_END_MONTH] = gpc_get_string( FILTER_PROPERTY_END_MONTH, date( 'm' ) );
  431. }
  432. if( !isset( $p_filter_arr[FILTER_PROPERTY_END_DAY] ) ) {
  433. $p_filter_arr[FILTER_PROPERTY_END_DAY] = gpc_get_string( FILTER_PROPERTY_END_DAY, date( 'd' ) );
  434. }
  435. if( !isset( $p_filter_arr[FILTER_PROPERTY_END_YEAR] ) ) {
  436. $p_filter_arr[FILTER_PROPERTY_END_YEAR] = gpc_get_string( FILTER_PROPERTY_END_YEAR, date( 'Y' ) );
  437. }
  438. if( !isset( $p_filter_arr[FILTER_PROPERTY_FREE_TEXT] ) ) {
  439. $p_filter_arr[FILTER_PROPERTY_FREE_TEXT] = '';
  440. }
  441. if( !isset( $p_filter_arr[FILTER_PROPERTY_NOT_ASSIGNED] ) ) {
  442. $p_filter_arr[FILTER_PROPERTY_NOT_ASSIGNED] = gpc_get_bool( FILTER_PROPERTY_NOT_ASSIGNED, false );
  443. }
  444. if( !isset( $p_filter_arr[FILTER_PROPERTY_FILTER_BY_DATE] ) ) {
  445. $p_filter_arr[FILTER_PROPERTY_FILTER_BY_DATE] = gpc_get_bool( FILTER_PROPERTY_FILTER_BY_DATE, false );
  446. }
  447. if( !isset( $p_filter_arr[FILTER_PROPERTY_VIEW_STATE_ID] ) ) {
  448. $p_filter_arr[FILTER_PROPERTY_VIEW_STATE_ID] = gpc_get( FILTER_PROPERTY_VIEW_STATE_ID, '' );
  449. }
  450. else if( filter_field_is_any( $p_filter_arr[FILTER_PROPERTY_VIEW_STATE_ID] ) ) {
  451. $p_filter_arr[FILTER_PROPERTY_VIEW_STATE_ID] = META_FILTER_ANY;
  452. }
  453. if( !isset( $p_filter_arr[FILTER_PROPERTY_RELATIONSHIP_TYPE] ) ) {
  454. $p_filter_arr[FILTER_PROPERTY_RELATIONSHIP_TYPE] = gpc_get_int( FILTER_PROPERTY_RELATIONSHIP_TYPE, -1 );
  455. }
  456. if( !isset( $p_filter_arr[FILTER_PROPERTY_RELATIONSHIP_BUG] ) ) {
  457. $p_filter_arr[FILTER_PROPERTY_RELATIONSHIP_BUG] = gpc_get_int( FILTER_PROPERTY_RELATIONSHIP_BUG, 0 );
  458. }
  459. if( !isset( $p_filter_arr[FILTER_PROPERTY_TARGET_VERSION] ) ) {
  460. $p_filter_arr[FILTER_PROPERTY_TARGET_VERSION] = META_FILTER_ANY;
  461. }
  462. if( !isset( $p_filter_arr[FILTER_PROPERTY_TAG_STRING] ) ) {
  463. $p_filter_arr[FILTER_PROPERTY_TAG_STRING] = gpc_get_string( FILTER_PROPERTY_TAG_STRING, '' );
  464. }
  465. if( !isset( $p_filter_arr[FILTER_PROPERTY_TAG_SELECT] ) ) {
  466. $p_filter_arr[FILTER_PROPERTY_TAG_SELECT] = gpc_get_string( FILTER_PROPERTY_TAG_SELECT, '' );
  467. }
  468. # initialize plugin filters
  469. $t_plugin_filters = filter_get_plugin_filters();
  470. foreach( $t_plugin_filters as $t_field_name => $t_filter_object ) {
  471. if( !isset( $p_filter_arr[ $t_field_name ] ) ) {
  472. switch( $t_filter_object->type ) {
  473. case FILTER_TYPE_STRING:
  474. $p_filter_arr[ $t_field_name ] = gpc_get_string( $t_field_name, $t_filter_object->default );
  475. break;
  476. case FILTER_TYPE_INT:
  477. $p_filter_arr[ $t_field_name ] = gpc_get_int( $t_field_name, (int)$t_filter_object->default );
  478. break;
  479. case FILTER_TYPE_BOOLEAN:
  480. $p_filter_arr[ $t_field_name ] = gpc_get_bool( $t_field_name, (bool)$t_filter_object->default );
  481. break;
  482. case FILTER_TYPE_MULTI_STRING:
  483. $p_filter_arr[ $t_field_name ] = gpc_get_string_array( $t_field_name, array( 0 => META_FILTER_ANY ) );
  484. break;
  485. case FILTER_TYPE_MULTI_INT:
  486. $p_filter_arr[ $t_field_name ] = gpc_get_int_array( $t_field_name, array( 0 => META_FILTER_ANY ) );
  487. break;
  488. default:
  489. $p_filter_arr[ $t_field_name ] = META_FILTER_ANY;
  490. }
  491. }
  492. if ( ! $t_filter_object->validate( $p_filter_arr[ $t_field_name ] ) ) {
  493. $p_filter_arr[ $t_field_name ] = $t_filter_object->default;
  494. }
  495. }
  496. $t_custom_fields = custom_field_get_ids();
  497. # @@@ (thraxisp) This should really be the linked ids, but we don't know the project
  498. $f_custom_fields_data = array();
  499. if( is_array( $t_custom_fields ) && ( count( $t_custom_fields ) > 0 ) ) {
  500. foreach( $t_custom_fields as $t_cfid ) {
  501. if( is_array( gpc_get( 'custom_field_' . $t_cfid, null ) ) ) {
  502. $f_custom_fields_data[$t_cfid] = gpc_get_string_array( 'custom_field_' . $t_cfid, META_FILTER_ANY );
  503. } else {
  504. $f_custom_fields_data[$t_cfid] = gpc_get_string( 'custom_field_' . $t_cfid, META_FILTER_ANY );
  505. $f_custom_fields_data[$t_cfid] = array(
  506. $f_custom_fields_data[$t_cfid],
  507. );
  508. }
  509. }
  510. }
  511. # validate sorting
  512. $t_fields = helper_get_columns_to_view();
  513. $t_n_fields = count( $t_fields );
  514. for( $i = 0;$i < $t_n_fields;$i++ ) {
  515. if( isset( $t_fields[$i] ) && in_array( $t_fields[$i], array( 'selection', 'edit', 'bugnotes_count', 'attachment' ) ) ) {
  516. unset( $t_fields[$i] );
  517. }
  518. }
  519. $t_sort_fields = explode( ',', $p_filter_arr['sort'] );
  520. $t_dir_fields = explode( ',', $p_filter_arr['dir'] );
  521. for( $i = 0;$i < 2;$i++ ) {
  522. if( isset( $t_sort_fields[$i] ) ) {
  523. $t_drop = false;
  524. $t_sort = $t_sort_fields[$i];
  525. if( strpos( $t_sort, 'custom_' ) === 0 ) {
  526. if( false === custom_field_get_id_from_name( utf8_substr( $t_sort, utf8_strlen( 'custom_' ) ) ) ) {
  527. $t_drop = true;
  528. }
  529. } else {
  530. if( !in_array( $t_sort, $t_fields ) ) {
  531. $t_drop = true;
  532. }
  533. }
  534. if( !in_array( $t_dir_fields[$i], array( "ASC", "DESC" ) ) ) {
  535. $t_drop = true;
  536. }
  537. if( $t_drop ) {
  538. unset( $t_sort_fields[$i] );
  539. unset( $t_dir_fields[$i] );
  540. }
  541. }
  542. }
  543. if( count( $t_sort_fields ) > 0 ) {
  544. $p_filter_arr['sort'] = implode( ',', $t_sort_fields );
  545. $p_filter_arr['dir'] = implode( ',', $t_dir_fields );
  546. } else {
  547. $p_filter_arr['sort'] = "last_updated";
  548. $p_filter_arr['dir'] = "DESC";
  549. }
  550. # validate or filter junk from other fields
  551. $t_multi_select_list = array(
  552. FILTER_PROPERTY_CATEGORY => 'string',
  553. FILTER_PROPERTY_SEVERITY_ID => 'int',
  554. FILTER_PROPERTY_STATUS_ID => 'int',
  555. FILTER_PROPERTY_REPORTER_ID => 'int',
  556. FILTER_PROPERTY_HANDLER_ID => 'int',
  557. FILTER_PROPERTY_NOTE_USER_ID => 'int',
  558. FILTER_PROPERTY_RESOLUTION_ID => 'int',
  559. FILTER_PROPERTY_PRIORITY_ID => 'int',
  560. FILTER_PROPERTY_PRODUCT_BUILD => 'string',
  561. FILTER_PROPERTY_PRODUCT_VERSION => 'string',
  562. FILTER_PROPERTY_HIDE_STATUS_ID => 'int',
  563. FILTER_PROPERTY_FIXED_IN_VERSION => 'string',
  564. FILTER_PROPERTY_TARGET_VERSION => 'string',
  565. FILTER_PROPERTY_MONITOR_USER_ID => 'int',
  566. 'show_profile' => 'int',
  567. );
  568. foreach( $t_multi_select_list as $t_multi_field_name => $t_multi_field_type ) {
  569. if( !isset( $p_filter_arr[$t_multi_field_name] ) ) {
  570. if( FILTER_PROPERTY_HIDE_STATUS_ID == $t_multi_field_name ) {
  571. $p_filter_arr[$t_multi_field_name] = array(
  572. config_get( 'hide_status_default' ),
  573. );
  574. }
  575. else if( 'custom_fields' == $t_multi_field_name ) {
  576. $p_filter_arr[$t_multi_field_name] = array(
  577. $f_custom_fields_data,
  578. );
  579. } else {
  580. $p_filter_arr[$t_multi_field_name] = array(
  581. META_FILTER_ANY,
  582. );
  583. }
  584. } else {
  585. if( !is_array( $p_filter_arr[$t_multi_field_name] ) ) {
  586. $p_filter_arr[$t_multi_field_name] = array(
  587. $p_filter_arr[$t_multi_field_name],
  588. );
  589. }
  590. $t_checked_array = array();
  591. foreach( $p_filter_arr[$t_multi_field_name] as $t_filter_value ) {
  592. $t_filter_value = stripslashes( $t_filter_value );
  593. if(( $t_filter_value === 'any' ) || ( $t_filter_value === '[any]' ) ) {
  594. $t_filter_value = META_FILTER_ANY;
  595. }
  596. if(( $t_filter_value === 'none' ) || ( $t_filter_value === '[none]' ) ) {
  597. $t_filter_value = META_FILTER_NONE;
  598. }
  599. if( 'string' == $t_multi_field_type ) {
  600. $t_checked_array[] = db_prepare_string( $t_filter_value );
  601. }
  602. else if( 'int' == $t_multi_field_type ) {
  603. $t_checked_array[] = db_prepare_int( $t_filter_value );
  604. }
  605. else if( 'array' == $t_multi_field_type ) {
  606. $t_checked_array[] = $t_filter_value;
  607. }
  608. }
  609. $p_filter_arr[$t_multi_field_name] = $t_checked_array;
  610. }
  611. }
  612. if( is_array( $t_custom_fields ) && ( count( $t_custom_fields ) > 0 ) ) {
  613. foreach( $t_custom_fields as $t_cfid ) {
  614. if( !isset( $p_filter_arr['custom_fields'][$t_cfid] ) ) {
  615. $p_filter_arr['custom_fields'][$t_cfid] = array(
  616. META_FILTER_ANY,
  617. );
  618. } else {
  619. if( !is_array( $p_filter_arr['custom_fields'][$t_cfid] ) ) {
  620. $p_filter_arr['custom_fields'][$t_cfid] = array(
  621. $p_filter_arr['custom_fields'][$t_cfid],
  622. );
  623. }
  624. $t_checked_array = array();
  625. foreach( $p_filter_arr['custom_fields'][$t_cfid] as $t_filter_value ) {
  626. $t_filter_value = stripslashes( $t_filter_value );
  627. if(( $t_filter_value === 'any' ) || ( $t_filter_value === '[any]' ) ) {
  628. $t_filter_value = META_FILTER_ANY;
  629. }
  630. $t_checked_array[] = db_prepare_string( $t_filter_value );
  631. }
  632. $p_filter_arr['custom_fields'][$t_cfid] = $t_checked_array;
  633. }
  634. }
  635. }
  636. # all of our filter values are now guaranteed to be there, and correct.
  637. return $p_filter_arr;
  638. }
  639. /**
  640. * Get the standard filter that is to be used when no filter was previously saved.
  641. * When creating specific filters, this can be used as a basis for the filter, where
  642. * specific entries can be overridden.
  643. * @return mixed
  644. */
  645. function filter_get_default() {
  646. $t_hide_status_default = config_get( 'hide_status_default' );
  647. $t_default_show_changed = config_get( 'default_show_changed' );
  648. $t_filter = array(
  649. FILTER_PROPERTY_CATEGORY => Array(
  650. '0' => META_FILTER_ANY,
  651. ),
  652. FILTER_PROPERTY_SEVERITY_ID => Array(
  653. '0' => META_FILTER_ANY,
  654. ),
  655. FILTER_PROPERTY_STATUS_ID => Array(
  656. '0' => META_FILTER_ANY,
  657. ),
  658. FILTER_PROPERTY_HIGHLIGHT_CHANGED => $t_default_show_changed,
  659. FILTER_PROPERTY_REPORTER_ID => Array(
  660. '0' => META_FILTER_ANY,
  661. ),
  662. FILTER_PROPERTY_HANDLER_ID => Array(
  663. '0' => META_FILTER_ANY,
  664. ),
  665. FILTER_PROPERTY_PROJECT_ID => Array(
  666. '0' => META_FILTER_CURRENT,
  667. ),
  668. FILTER_PROPERTY_RESOLUTION_ID => Array(
  669. '0' => META_FILTER_ANY,
  670. ),
  671. FILTER_PROPERTY_PRODUCT_BUILD => Array(
  672. '0' => META_FILTER_ANY,
  673. ),
  674. FILTER_PROPERTY_PRODUCT_VERSION => Array(
  675. '0' => META_FILTER_ANY,
  676. ),
  677. FILTER_PROPERTY_HIDE_STATUS_ID => Array(
  678. '0' => $t_hide_status_default,
  679. ),
  680. FILTER_PROPERTY_MONITOR_USER_ID => Array(
  681. '0' => META_FILTER_ANY,
  682. ),
  683. FILTER_PROPERTY_SORT_FIELD_NAME => 'last_updated',
  684. FILTER_PROPERTY_SORT_DIRECTION => 'DESC',
  685. FILTER_PROPERTY_ISSUES_PER_PAGE => config_get( 'default_limit_view' ),
  686. );
  687. return filter_ensure_valid_filter( $t_filter );
  688. }
  689. /**
  690. * Deserialize filter string
  691. * @param string $p_serialized_filter
  692. * @return mixed $t_filter array
  693. * @see filter_ensure_valid_filter
  694. */
  695. function filter_deserialize( $p_serialized_filter ) {
  696. if( is_blank( $p_serialized_filter ) ) {
  697. return false;
  698. }
  699. # check to see if new cookie is needed
  700. $t_setting_arr = explode( '#', $p_serialized_filter, 2 );
  701. if(( $t_setting_arr[0] == 'v1' ) || ( $t_setting_arr[0] == 'v2' ) || ( $t_setting_arr[0] == 'v3' ) || ( $t_setting_arr[0] == 'v4' ) ) {
  702. # these versions can't be salvaged, they are too old to update
  703. return false;
  704. }
  705. # We shouldn't need to do this anymore, as filters from v5 onwards should cope with changing
  706. # filter indices dynamically
  707. $t_filter_array = array();
  708. if( isset( $t_setting_arr[1] ) ) {
  709. $t_filter_array = unserialize( $t_setting_arr[1] );
  710. } else {
  711. return false;
  712. }
  713. if( $t_filter_array['_version'] != config_get( 'cookie_version' ) ) {
  714. # if the version is not new enough, update it using defaults
  715. return filter_ensure_valid_filter( $t_filter_array );
  716. }
  717. return $t_filter_array;
  718. }
  719. /**
  720. * Check if the filter cookie exists and is of the correct version.
  721. * @return bool
  722. */
  723. function filter_is_cookie_valid() {
  724. $t_view_all_cookie_id = gpc_get_cookie( config_get( 'view_all_cookie' ), '' );
  725. $t_view_all_cookie = filter_db_get_filter( $t_view_all_cookie_id );
  726. # check to see if the cookie does not exist
  727. if( is_blank( $t_view_all_cookie ) ) {
  728. return false;
  729. }
  730. # check to see if new cookie is needed
  731. $t_setting_arr = explode( '#', $t_view_all_cookie, 2 );
  732. if(( $t_setting_arr[0] == 'v1' ) || ( $t_setting_arr[0] == 'v2' ) || ( $t_setting_arr[0] == 'v3' ) || ( $t_setting_arr[0] == 'v4' ) ) {
  733. return false;
  734. }
  735. # We shouldn't need to do this anymore, as filters from v5 onwards should cope with changing
  736. # filter indices dynamically
  737. $t_filter_cookie_arr = array();
  738. if( isset( $t_setting_arr[1] ) ) {
  739. $t_filter_cookie_arr = unserialize( $t_setting_arr[1] );
  740. } else {
  741. return false;
  742. }
  743. if( $t_filter_cookie_arr['_version'] != config_get( 'cookie_version' ) ) {
  744. return false;
  745. }
  746. return true;
  747. }
  748. /**
  749. * Get the array fields specified by $p_filter_id
  750. * using the cached row if it's available
  751. * @param int $p_filter_id
  752. * @return mixed a filter row
  753. */
  754. function filter_get_row( $p_filter_id ) {
  755. return filter_cache_row( $p_filter_id );
  756. }
  757. /**
  758. * Get the value of the filter field specified by filter id and field name
  759. * @param int $p_filter_id
  760. * @param string $p_field_name
  761. * @return string
  762. */
  763. function filter_get_field( $p_filter_id, $p_field_name ) {
  764. $row = filter_get_row( $p_filter_id );
  765. if( isset( $row[$p_field_name] ) ) {
  766. return $row[$p_field_name];
  767. } else {
  768. error_parameters( $p_field_name );
  769. trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING );
  770. return '';
  771. }
  772. }
  773. /**
  774. * Add sort parameters to the query clauses
  775. * @param array $p_filter
  776. * @param bool $p_show_sticky
  777. * @param array $p_query_clauses
  778. * @return array $p_query_clauses
  779. */
  780. function filter_get_query_sort_data( &$p_filter, $p_show_sticky, $p_query_clauses ) {
  781. $t_bug_table = db_get_table( 'mantis_bug_table' );
  782. $t_custom_field_string_table = db_get_table( 'mantis_custom_field_string_table' );
  783. # if sort is blank then default the sort and direction. This is to fix the
  784. # symptoms of #3953. Note that even if the main problem is fixed, we may
  785. # have to keep this code for a while to handle filters saved with this blank field.
  786. if( is_blank( $p_filter[FILTER_PROPERTY_SORT_FIELD_NAME] ) ) {
  787. $p_filter[FILTER_PROPERTY_SORT_FIELD_NAME] = 'last_updated';
  788. $p_filter[FILTER_PROPERTY_SORT_DIRECTION] = 'DESC';
  789. }
  790. $p_query_clauses['order'] = array();
  791. $t_sort_fields = explode( ',', $p_filter[FILTER_PROPERTY_SORT_FIELD_NAME] );
  792. $t_dir_fields = explode( ',', $p_filter[FILTER_PROPERTY_SORT_DIRECTION] );
  793. $t_plugin_columns = columns_get_plugin_columns();
  794. if ( gpc_string_to_bool( $p_filter[FILTER_PROPERTY_SHOW_STICKY_ISSUES] ) && ( NULL !== $p_show_sticky ) ) {
  795. $p_query_clauses['order'][] = "$t_bug_table.sticky DESC";
  796. }
  797. $t_count = count( $t_sort_fields );
  798. for( $i = 0;$i < $t_count;$i++ ) {
  799. $c_sort = db_prepare_string( $t_sort_fields[$i] );
  800. $c_dir = 'DESC' == $t_dir_fields[$i] ? 'DESC' : 'ASC';
  801. if( !in_array( $t_sort_fields[$i], array_slice( $t_sort_fields, $i + 1 ) ) ) {
  802. # if sorting by a custom field
  803. if( strpos( $c_sort, 'custom_' ) === 0 ) {
  804. $t_custom_field = utf8_substr( $c_sort, utf8_strlen( 'custom_' ) );
  805. $t_custom_field_id = custom_field_get_id_from_name( $t_custom_field );
  806. $c_cf_alias = str_replace( ' ', '_', $t_custom_field );
  807. $t_cf_table_alias = $t_custom_field_string_table . '_' . $t_custom_field_id;
  808. $t_cf_select = "$t_cf_table_alias.value $c_cf_alias";
  809. # check to be sure this field wasn't already added to the query.
  810. if( !in_array( $t_cf_select, $p_query_clauses['select'] ) ) {
  811. $p_query_clauses['select'][] = $t_cf_select;
  812. $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";
  813. }
  814. $p_query_clauses['order'][] = "$c_cf_alias $c_dir";
  815. # if sorting by plugin columns
  816. } else if ( isset( $t_plugin_columns[ $t_sort_fields[$i] ] ) ) {
  817. $t_column_object = $t_plugin_columns[ $t_sort_fields[$i] ];
  818. if ( $t_column_object->sortable ) {
  819. $t_clauses = $t_column_object->sortquery( $c_dir );
  820. if ( is_array( $t_clauses ) ) {
  821. if ( isset( $t_clauses['join'] ) ) {
  822. $p_query_clauses['join'][] = $t_clauses['join'];
  823. }
  824. if ( isset( $t_clauses['order'] ) ) {
  825. $p_query_clauses['order'][] = $t_clauses['order'];
  826. }
  827. }
  828. }
  829. # standard column
  830. } else {
  831. if ( 'last_updated' == $c_sort ) {
  832. $c_sort = "last_updated";
  833. }
  834. $p_query_clauses['order'][] = "$t_bug_table.$c_sort $c_dir";
  835. }
  836. }
  837. }
  838. # add basic sorting if necessary
  839. if( !in_array( 'last_updated', $t_sort_fields ) ) {
  840. $p_query_clauses['order'][] = "$t_bug_table.last_updated DESC";
  841. }
  842. if( !in_array( 'date_submitted', $t_sort_fields ) ) {
  843. $p_query_clauses['order'][] = "$t_bug_table.date_submitted DESC";
  844. }
  845. return $p_query_clauses;
  846. }
  847. /**
  848. * Remove any duplicate values in certain elements of query_clauses
  849. * Do not loop over query clauses as some keys may contain valid duplicate values.
  850. * We basically want unique values for just the base query elements select, from, and join
  851. * 'where' and 'where_values' key should not have duplicates as that is handled earlier and applying
  852. * array_unique here could cause problems with the query.
  853. * @param $p_query_clauses
  854. * @return $p_query_clauses
  855. */
  856. function filter_unique_query_clauses( $p_query_clauses ) {
  857. $p_query_clauses['select'] = array_unique( $p_query_clauses['select'] );
  858. $p_query_clauses['from'] = array_unique( $p_query_clauses['from'] );
  859. $p_query_clauses['join'] = array_unique( $p_query_clauses['join'] );
  860. return $p_query_clauses;
  861. }
  862. /**
  863. * Build a query with the query clauses array, query for bug count and return the result
  864. * @param array $p_query_clauses
  865. * @return int
  866. */
  867. function filter_get_bug_count( $p_query_clauses ) {
  868. $t_bug_table = db_get_table( 'mantis_bug_table' );
  869. $p_query_clauses = filter_unique_query_clauses( $p_query_clauses );
  870. $t_select_string = "SELECT Count( DISTINCT $t_bug_table.id ) as idcnt ";
  871. $t_from_string = " FROM " . implode( ', ', $p_query_clauses['from'] );
  872. $t_join_string = (( count( $p_query_clauses['join'] ) > 0 ) ? implode( ' ', $p_query_clauses['join'] ) : '' );
  873. $t_where_string = (( count( $p_query_clauses['where'] ) > 0 ) ? 'WHERE ' . implode( ' AND ', $p_query_clauses['where'] ) : '' );
  874. $t_result = db_query_bound( "$t_select_string $t_from_string $t_join_string $t_where_string", $p_query_clauses['where_values'] );
  875. return db_result( $t_result );
  876. }
  877. /**
  878. * @todo Had to make all these parameters required because we can't use
  879. * call-time pass by reference anymore. I really preferred not having
  880. * to pass all the params in if you didn't want to, but I wanted to get
  881. * rid of the errors for now. If we can think of a better way later
  882. * (maybe return an object) that would be great.
  883. *
  884. * @param int $p_page_number the page you want to see (set to the actual page on return)
  885. * @param int $p_per_page the number of bugs to see per page (set to actual on return)
  886. * -1 indicates you want to see all bugs
  887. * null indicates you want to use the value specified in the filter
  888. * @param int $p_page_count you don't need to give a value here, the number of pages will be stored here on return
  889. * @param int $p_bug_count you don't need to give a value here, the number of bugs will be stored here on return
  890. * @param mixed $p_custom_filter Filter to use.
  891. * @param int $p_project_id project id to use in filtering.
  892. * @param int $p_user_id user id to use as current user when filtering.
  893. * @param bool $p_show_sticky get sticky issues only.
  894. */
  895. 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 ) {
  896. log_event( LOG_FILTERING, 'START NEW FILTER QUERY' );
  897. $t_bug_table = db_get_table( 'mantis_bug_table' );
  898. $t_bug_text_table = db_get_table( 'mantis_bug_text_table' );
  899. $t_bugnote_table = db_get_table( 'mantis_bugnote_table' );
  900. $t_category_table = db_get_table( 'mantis_category_table' );
  901. $t_custom_field_string_table = db_get_table( 'mantis_custom_field_string_table' );
  902. $t_bugnote_text_table = db_get_table( 'mantis_bugnote_text_table' );
  903. $t_project_table = db_get_table( 'mantis_project_table' );
  904. $t_bug_monitor_table = db_get_table( 'mantis_bug_monitor_table' );
  905. $t_limit_reporters = config_get( 'limit_reporters' );
  906. $t_bug_relationship_table = db_get_table( 'mantis_bug_relationship_table' );
  907. $t_report_bug_threshold = config_get( 'report_bug_threshold' );
  908. $t_where_param_count = 0;
  909. $t_current_user_id = auth_get_current_user_id();
  910. if( null === $p_user_id ) {
  911. $t_user_id = $t_current_user_id;
  912. } else {
  913. $t_user_id = $p_user_id;
  914. }
  915. $c_user_id = db_prepare_int( $t_user_id );
  916. if( null === $p_project_id ) {
  917. # @@@ If project_id is not specified, then use the project id(s) in the filter if set, otherwise, use current project.
  918. $t_project_id = helper_get_current_project();
  919. } else {
  920. $t_project_id = $p_project_id;
  921. }
  922. if( $p_custom_filter === null ) {
  923. # Prefer current_user_get_bug_filter() over user_get_filter() when applicable since it supports
  924. # cookies set by previous version of the code.
  925. if( $t_user_id == $t_current_user_id ) {
  926. $t_filter = current_user_get_bug_filter();
  927. } else {
  928. $t_filter = user_get_bug_filter( $t_user_id, $t_project_id );
  929. }
  930. } else {
  931. $t_filter = $p_custom_filter;
  932. }
  933. $t_filter = filter_ensure_valid_filter( $t_filter );
  934. if( false === $t_filter ) {
  935. return false;
  936. # signify a need to create a cookie
  937. # @@@ error instead?
  938. }
  939. $t_view_type = $t_filter['_view_type'];
  940. $t_where_clauses = array(
  941. "$t_project_table.enabled = " . db_param(),
  942. "$t_project_table.id = $t_bug_table.project_id",
  943. );
  944. $t_where_params = array(
  945. 1,
  946. );
  947. $t_select_clauses = array(
  948. "$t_bug_table.*",
  949. );
  950. $t_join_clauses = array();
  951. $t_from_clauses = array();
  952. // normalize the project filtering into an array $t_project_ids
  953. if( 'simple' == $t_view_type ) {
  954. log_event( LOG_FILTERING, 'Simple Filter' );
  955. $t_project_ids = array(
  956. $t_project_id,
  957. );
  958. $t_include_sub_projects = true;
  959. } else {
  960. log_event( LOG_FILTERING, 'Advanced Filter' );
  961. if( !is_array( $t_filter[FILTER_PROPERTY_PROJECT_ID] ) ) {
  962. $t_project_ids = array(
  963. db_prepare_int( $t_filter[FILTER_PROPERTY_PROJECT_ID] ),
  964. );
  965. } else {
  966. $t_project_ids = array_map( 'db_prepare_int', $t_filter[FILTER_PROPERTY_PROJECT_ID] );
  967. }
  968. $t_include_sub_projects = (( count( $t_project_ids ) == 1 ) && ( ( $t_project_ids[0] == META_FILTER_CURRENT ) || ( $t_project_ids[0] == ALL_PROJECTS ) ) );
  969. }
  970. log_event( LOG_FILTERING, 'project_ids = @P' . implode( ', @P', $t_project_ids ) );
  971. log_event( LOG_FILTERING, 'include sub-projects = ' . ( $t_include_sub_projects ? '1' : '0' ) );
  972. // if the array has ALL_PROJECTS, then reset the array to only contain ALL_PROJECTS.
  973. // replace META_FILTER_CURRENT with the actualy current project id.
  974. $t_all_projects_found = false;
  975. $t_new_project_ids = array();
  976. foreach( $t_project_ids as $t_pid ) {
  977. if( $t_pid == META_FILTER_CURRENT ) {
  978. $t_pid = $t_project_id;
  979. }
  980. if( $t_pid == ALL_PROJECTS ) {
  981. $t_all_projects_found = true;
  982. log_event( LOG_FILTERING, 'all projects selected' );
  983. break;
  984. }
  985. // filter out inaccessible projects.
  986. if( !access_has_project_level( VIEWER, $t_pid, $t_user_id ) ) {
  987. continue;
  988. }
  989. $t_new_project_ids[] = $t_pid;
  990. }
  991. $t_projects_query_required = true;
  992. if( $t_all_projects_found ) {
  993. if( user_is_administrator( $t_user_id ) ) {
  994. log_event( LOG_FILTERING, 'all projects + administrator, hence no project filter.' );
  995. $t_projects_query_required = false;
  996. } else {
  997. $t_project_ids = user_get_accessible_projects( $t_user_id );
  998. }
  999. } else {
  1000. $t_project_ids = $t_new_project_ids;
  1001. }
  1002. if( $t_projects_query_required ) {
  1003. // expand project ids to include sub-projects
  1004. if( $t_include_sub_projects ) {
  1005. $t_top_project_ids = $t_project_ids;
  1006. foreach( $t_top_project_ids as $t_pid ) {
  1007. log_event( LOG_FILTERING, 'Getting sub-projects for project id @P' . $t_pid );
  1008. $t_subproject_ids = user_get_all_accessible_subprojects( $t_user_id, $t_pid );
  1009. if (!$t_subproject_ids) continue;
  1010. $t_project_ids = array_merge( $t_project_ids, $t_subproject_ids );
  1011. }
  1012. $t_project_ids = array_unique( $t_project_ids );
  1013. }
  1014. // if no projects are accessible, then return an empty array.
  1015. if( count( $t_project_ids ) == 0 ) {
  1016. log_event( LOG_FILTERING, 'no accessible projects' );
  1017. return array();
  1018. }
  1019. log_event( LOG_FILTERING, 'project_ids after including sub-projects = @P' . implode( ', @P', $t_project_ids ) );
  1020. // this array is to be populated with project ids for which we only want to show public issues. This is due to the limited
  1021. // access of the current user.
  1022. $t_public_only_project_ids = array();
  1023. // this array is populated with project ids that the current user has full access to.
  1024. $t_private_and_public_project_ids = array();
  1025. foreach( $t_project_ids as $t_pid ) {
  1026. $t_access_required_to_view_private_bugs = config_get( 'private_bug_threshold', null, null, $t_pid );
  1027. if( access_has_project_level( $t_access_required_to_view_private_bugs, $t_pid, $t_user_id ) ) {
  1028. $t_private_and_public_project_ids[] = $t_pid;
  1029. } else {
  1030. $t_public_only_project_ids[] = $t_pid;
  1031. }
  1032. }
  1033. log_event( LOG_FILTERING, 'project_ids (with public/private access) = @P' . implode( ', @P', $t_private_and_public_project_ids ) );
  1034. log_event( LOG_FILTERING, 'project_ids (with public access) = @P' . implode( ', @P', $t_public_only_project_ids ) );
  1035. $t_count_private_and_public_project_ids = count( $t_private_and_public_project_ids );
  1036. if( $t_count_private_and_public_project_ids == 1 ) {
  1037. $t_private_and_public_query = "( $t_bug_table.project_id = " . $t_private_and_public_project_ids[0] . " )";
  1038. }
  1039. else if( $t_count_private_and_public_project_ids > 1 ) {
  1040. $t_private_and_public_query = "( $t_bug_table.project_id in (" . implode( ', ', $t_private_and_public_project_ids ) . ") )";
  1041. } else {
  1042. $t_private_and_public_query = null;
  1043. }
  1044. $t_count_public_only_project_ids = count( $t_public_only_project_ids );
  1045. $t_public_view_state_check = "( ( $t_bug_table.view_state = " . VS_PUBLIC . " ) OR ( $t_bug_table.reporter_id = $t_user_id ) )";
  1046. if( $t_count_public_only_project_ids == 1 ) {
  1047. $t_public_only_query = "( ( $t_bug_table.project_id = " . $t_public_only_project_ids[0] . " ) AND $t_public_view_state_check )";
  1048. }
  1049. else if( $t_count_public_only_project_ids > 1 ) {
  1050. $t_public_only_query = "( ( $t_bug_table.project_id in (" . implode( ', ', $t_public_only_project_ids ) . ") ) AND $t_public_view_state_check )";
  1051. } else {
  1052. $t_public_only_query = null;
  1053. }
  1054. // both queries can't be null, so we either have one of them or both.
  1055. if( $t_private_and_public_query === null ) {
  1056. $t_project_query = $t_public_only_query;
  1057. } else if( $t_public_only_query === null ) {
  1058. $t_project_query = $t_private_and_public_query;
  1059. } else {
  1060. $t_project_query = "( $t_public_only_query OR $t_private_and_public_query )";
  1061. }
  1062. log_event( LOG_FILTERING, 'project query = ' . $t_project_query );
  1063. array_push( $t_where_clauses, $t_project_query );
  1064. }
  1065. # view state
  1066. $t_view_state = db_prepare_int( $t_filter[FILTER_PROPERTY_VIEW_STATE_ID] );
  1067. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_VIEW_STATE_ID] ) ) {
  1068. $t_view_state_query = "($t_bug_table.view_state=" . db_param() . ')';
  1069. log_event( LOG_FILTERING, 'view_state query = ' . $t_view_state_query );
  1070. $t_where_params[] = $t_view_state;
  1071. array_push( $t_where_clauses, $t_view_state_query );
  1072. } else {
  1073. log_event( LOG_FILTERING, 'no view_state query' );
  1074. }
  1075. # reporter
  1076. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_REPORTER_ID] ) ) {
  1077. $t_clauses = array();
  1078. foreach( $t_filter[FILTER_PROPERTY_REPORTER_ID] as $t_filter_member ) {
  1079. if( filter_field_is_none( $t_filter_member ) ) {
  1080. array_push( $t_clauses, "0" );
  1081. } else {
  1082. $c_reporter_id = db_prepare_int( $t_filter_member );
  1083. if( filter_field_is_myself( $c_reporter_id ) ) {
  1084. array_push( $t_clauses, $c_user_id );
  1085. } else {
  1086. array_push( $t_clauses, $c_reporter_id );
  1087. }
  1088. }
  1089. }
  1090. if( 1 < count( $t_clauses ) ) {
  1091. $t_reporter_query = "( $t_bug_table.reporter_id in (" . implode( ', ', $t_clauses ) . ") )";
  1092. } else {
  1093. $t_reporter_query = "( $t_bug_table.reporter_id=$t_clauses[0] )";
  1094. }
  1095. log_event( LOG_FILTERING, 'reporter query = ' . $t_reporter_query );
  1096. array_push( $t_where_clauses, $t_reporter_query );
  1097. } else {
  1098. log_event( LOG_FILTERING, 'no reporter query' );
  1099. }
  1100. # limit reporter
  1101. # @@@ thraxisp - access_has_project_level checks greater than or equal to,
  1102. # this assumed that there aren't any holes above REPORTER where the limit would apply
  1103. #
  1104. if(( ON === $t_limit_reporters ) && ( !access_has_project_level( REPORTER + 1, $t_project_id, $t_user_id ) ) ) {
  1105. $c_reporter_id = $c_user_id;
  1106. $t_where_params[] = $c_reporter_id;
  1107. array_push( $t_where_clauses, "($t_bug_table.reporter_id=" . db_param() . ')' );
  1108. }
  1109. # handler
  1110. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_HANDLER_ID] ) ) {
  1111. $t_clauses = array();
  1112. foreach( $t_filter[FILTER_PROPERTY_HANDLER_ID] as $t_filter_member ) {
  1113. if( filter_field_is_none( $t_filter_member ) ) {
  1114. array_push( $t_clauses, 0 );
  1115. } else {
  1116. $c_handler_id = db_prepare_int( $t_filter_member );
  1117. if( filter_field_is_myself( $c_handler_id ) ) {
  1118. array_push( $t_clauses, $c_user_id );
  1119. } else {
  1120. array_push( $t_clauses, $c_handler_id );
  1121. }
  1122. }
  1123. }
  1124. if( 1 < count( $t_clauses ) ) {
  1125. $t_handler_query = "( $t_bug_table.handler_id in (" . implode( ', ', $t_clauses ) . ") )";
  1126. } else {
  1127. $t_handler_query = "( $t_bug_table.handler_id=$t_clauses[0] )";
  1128. }
  1129. log_event( LOG_FILTERING, 'handler query = ' . $t_handler_query );
  1130. array_push( $t_where_clauses, $t_handler_query );
  1131. } else {
  1132. log_event( LOG_FILTERING, 'no handler query' );
  1133. }
  1134. # category
  1135. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_CATEGORY] ) ) {
  1136. $t_clauses = array();
  1137. foreach( $t_filter[FILTER_PROPERTY_CATEGORY] as $t_filter_member ) {
  1138. if( !filter_field_is_none( $t_filter_member ) ) {
  1139. array_push( $t_clauses, $t_filter_member );
  1140. }
  1141. }
  1142. if( 1 < count( $t_clauses ) ) {
  1143. $t_where_tmp = array();
  1144. foreach( $t_clauses as $t_clause ) {
  1145. $t_where_tmp[] = db_param();
  1146. $t_where_params[] = $t_clause;
  1147. }
  1148. array_push( $t_where_clauses, "( $t_bug_table.category_id in ( SELECT id FROM $t_category_table WHERE name in (" . implode( ', ', $t_where_tmp ) . ") ) )" );
  1149. } else {
  1150. $t_where_params[] = $t_clauses[0];
  1151. array_push( $t_where_clauses, "( $t_bug_table.category_id in ( SELECT id FROM $t_category_table WHERE name=" . db_param() . ") )" );
  1152. }
  1153. }
  1154. # severity
  1155. if( !filter_field_is_any( $t_filter[FILTER_PROPERTY_SEVERITY_ID] ) ) {
  1156. $t_clauses = array();
  1157. foreach( $t_filter[FILTER_PROPERTY_SEVERITY_ID] as $t_filter_member ) {
  1158. $c_show_severity = db_prepare_int( $t_filter_member );
  1159. array_push( $t_clauses, $c_show_severity );
  1160. }
  1161. if( 1 < count( $t_clauses ) ) {
  1162. $t_where_tmp = array();
  1163. foreach( $t_clauses as $t_clause ) {
  1164. $t_where_tmp[] = db_param();
  1165. $t_where_params[] = $t_clause;
  1166. }
  1167. array_push( $t_where_clauses, "( $t_bug_table.severity in (" . implode( ', ', $t_where_tmp ) . ") )" );
  1168. } else {
  1169. $t_where_params[] = $t_clauses[0];

Large files files are truncated, but you can click here to view the full file