PageRenderTime 48ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/core/history_api.php

https://github.com/markkimsal/mantisbt
PHP | 591 lines | 419 code | 51 blank | 121 comment | 75 complexity | 5df2af464d5c68bb231960729d3802d1 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. * History API
  17. *
  18. * @package CoreAPI
  19. * @subpackage HistoryAPI
  20. * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org
  21. * @copyright Copyright (C) 2002 - 2010 MantisBT Team - mantisbt-dev@lists.sourceforge.net
  22. * @link http://www.mantisbt.org
  23. *
  24. * @uses access_api.php
  25. * @uses authentication_api.php
  26. * @uses bug_api.php
  27. * @uses bug_revision_api.php
  28. * @uses bugnote_api.php
  29. * @uses columns_api.php
  30. * @uses config_api.php
  31. * @uses constant_inc.php
  32. * @uses custom_field_api.php
  33. * @uses database_api.php
  34. * @uses gpc_api.php
  35. * @uses helper_api.php
  36. * @uses lang_api.php
  37. * @uses project_api.php
  38. * @uses relationship_api.php
  39. * @uses sponsorship_api.php
  40. * @uses user_api.php
  41. * @uses utility_api.php
  42. */
  43. require_api( 'access_api.php' );
  44. require_api( 'authentication_api.php' );
  45. require_api( 'bug_api.php' );
  46. require_api( 'bug_revision_api.php' );
  47. require_api( 'bugnote_api.php' );
  48. require_api( 'columns_api.php' );
  49. require_api( 'config_api.php' );
  50. require_api( 'constant_inc.php' );
  51. require_api( 'custom_field_api.php' );
  52. require_api( 'database_api.php' );
  53. require_api( 'gpc_api.php' );
  54. require_api( 'helper_api.php' );
  55. require_api( 'lang_api.php' );
  56. require_api( 'project_api.php' );
  57. require_api( 'relationship_api.php' );
  58. require_api( 'sponsorship_api.php' );
  59. require_api( 'user_api.php' );
  60. require_api( 'utility_api.php' );
  61. /**
  62. * log the changes (old / new value are supplied to reduce db access)
  63. * events should be logged *after* the modification
  64. * @param int $p_bug_id
  65. * @param string $p_field_name
  66. * @param string $p_old_value
  67. * @param string $p_new_value
  68. * @param int $p_user_id
  69. * @param int $p_type
  70. */
  71. function history_log_event_direct( $p_bug_id, $p_field_name, $p_old_value, $p_new_value, $p_user_id = null, $p_type = 0 ) {
  72. # Only log events that change the value
  73. if( $p_new_value != $p_old_value ) {
  74. if( null === $p_user_id ) {
  75. $p_user_id = auth_get_current_user_id();
  76. }
  77. $c_field_name = $p_field_name;
  78. $c_old_value = ( is_null( $p_old_value ) ? '' : $p_old_value );
  79. $c_new_value = ( is_null( $p_new_value ) ? '' : $p_new_value );
  80. $c_bug_id = db_prepare_int( $p_bug_id );
  81. $c_user_id = db_prepare_int( $p_user_id );
  82. $c_type = db_prepare_int( $p_type );
  83. $t_mantis_bug_history_table = db_get_table( 'bug_history' );
  84. $query = "INSERT INTO $t_mantis_bug_history_table
  85. ( user_id, bug_id, date_modified, field_name, old_value, new_value, type )
  86. VALUES
  87. ( " . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ' )';
  88. $result = db_query_bound( $query, Array( $c_user_id, $c_bug_id, db_now(), $c_field_name, $c_old_value, $c_new_value, $c_type ) );
  89. }
  90. }
  91. /**
  92. * log the changes
  93. * events should be logged *after* the modification
  94. * @param int $p_bug_id
  95. * @param string $p_field_name
  96. * @param string $p_old_value
  97. * @return null
  98. */
  99. function history_log_event( $p_bug_id, $p_field_name, $p_old_value ) {
  100. history_log_event_direct( $p_bug_id, $p_field_name, $p_old_value, bug_get_field( $p_bug_id, $p_field_name ) );
  101. }
  102. /**
  103. * log the changes
  104. * events should be logged *after* the modification
  105. * These are special case logs (new bug, deleted bugnote, etc.)
  106. * @param int $p_bug_id
  107. * @param int $p_type
  108. * @param string $p_optional
  109. * @param string $p_optional2
  110. * @return null
  111. */
  112. function history_log_event_special( $p_bug_id, $p_type, $p_optional = '', $p_optional2 = '' ) {
  113. $c_bug_id = db_prepare_int( $p_bug_id );
  114. $c_type = db_prepare_int( $p_type );
  115. $c_optional = ( $p_optional );
  116. $c_optional2 = ( $p_optional2 );
  117. $t_user_id = auth_get_current_user_id();
  118. $t_mantis_bug_history_table = db_get_table( 'bug_history' );
  119. $query = "INSERT INTO $t_mantis_bug_history_table
  120. ( user_id, bug_id, date_modified, type, old_value, new_value, field_name )
  121. VALUES
  122. ( " . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ',' . db_param() . ', ' . db_param() . ')';
  123. $result = db_query_bound( $query, Array( $t_user_id, $c_bug_id, db_now(), $c_type, $c_optional, $c_optional2, '' ) );
  124. }
  125. /**
  126. * Retrieves the history events for the specified bug id and returns it in an array
  127. * The array is indexed from 0 to N-1. The second dimension is: 'date', 'username',
  128. * 'note', 'change'.
  129. * @param int $p_bug_id
  130. * @param int $p_user_id
  131. * @return array
  132. */
  133. function history_get_events_array( $p_bug_id, $p_user_id = null ) {
  134. $t_normal_date_format = config_get( 'normal_date_format' );
  135. $raw_history = history_get_raw_events_array( $p_bug_id, $p_user_id );
  136. $raw_history_count = count( $raw_history );
  137. $history = array();
  138. for( $i = 0;$i < $raw_history_count;$i++ ) {
  139. $history[$i] = history_localize_item( $raw_history[$i]['field'], $raw_history[$i]['type'], $raw_history[$i]['old_value'], $raw_history[$i]['new_value'] );
  140. $history[$i]['date'] = date( $t_normal_date_format, $raw_history[$i]['date'] );
  141. $history[$i]['userid'] = $raw_history[$i]['userid'];
  142. $history[$i]['username'] = $raw_history[$i]['username'];
  143. }
  144. return( $history );
  145. }
  146. /**
  147. * Retrieves the raw history events for the specified bug id and returns it in an array
  148. * The array is indexed from 0 to N-1. The second dimension is: 'date', 'userid', 'username',
  149. * 'field','type','old_value','new_value'
  150. * @param int $p_bug_id
  151. * @param int $p_user_id
  152. * @return array
  153. */
  154. function history_get_raw_events_array( $p_bug_id, $p_user_id = null ) {
  155. $t_mantis_bug_history_table = db_get_table( 'bug_history' );
  156. $t_mantis_user_table = db_get_table( 'user' );
  157. $t_history_order = config_get( 'history_order' );
  158. $c_bug_id = db_prepare_int( $p_bug_id );
  159. $t_user_id = (( null === $p_user_id ) ? auth_get_current_user_id() : $p_user_id );
  160. $t_roadmap_view_access_level = config_get( 'roadmap_view_threshold' );
  161. $t_due_date_view_threshold = config_get( 'due_date_view_threshold' );
  162. # grab history and display by date_modified then field_name
  163. # @@@ by MASC I guess it's better by id then by field_name. When we have more history lines with the same
  164. # date, it's better to respect the storing order otherwise we should risk to mix different information
  165. # I give you an example. We create a child of a bug with different custom fields. In the history of the child
  166. # bug we will find the line related to the relationship mixed with the custom fields (the history is creted
  167. # for the new bug with the same timestamp...)
  168. $query = "SELECT *
  169. FROM $t_mantis_bug_history_table
  170. WHERE bug_id=" . db_param() . "
  171. ORDER BY date_modified $t_history_order,id";
  172. $result = db_query_bound( $query, Array( $c_bug_id ) );
  173. $raw_history_count = db_num_rows( $result );
  174. $raw_history = array();
  175. $t_private_bugnote_threshold = config_get( 'private_bugnote_threshold' );
  176. $t_private_bugnote_visible = access_has_bug_level( config_get( 'private_bugnote_threshold' ), $p_bug_id, $t_user_id );
  177. $t_standard_fields = columns_get_standard();
  178. for( $i = 0, $j = 0;$i < $raw_history_count;++$i ) {
  179. $t_row = db_fetch_array( $result );
  180. $v_type = $t_row['type'];
  181. $v_field_name = $t_row['field_name'];
  182. $v_user_id = $t_row['user_id'];
  183. $v_new_value = $t_row['new_value'];
  184. $v_old_value = $t_row['old_value'];
  185. $v_date_modified = $t_row['date_modified'];
  186. if ( $v_type == NORMAL_TYPE ) {
  187. if ( !in_array( $v_field_name, $t_standard_fields ) ) {
  188. // check that the item should be visible to the user
  189. // custom fields - we are passing 32 here to notify the API that the custom field name is truncated by the history column from 64 to 32 characters.
  190. $t_field_id = custom_field_get_id_from_name( $v_field_name, 32 );
  191. if( false !== $t_field_id && !custom_field_has_read_access( $t_field_id, $p_bug_id, $t_user_id ) ) {
  192. continue;
  193. }
  194. }
  195. if ( ( $v_field_name == 'target_version' ) && !access_has_bug_level( $t_roadmap_view_access_level, $p_bug_id, $t_user_id ) ) {
  196. continue;
  197. }
  198. if ( ( $v_field_name == 'due_date' ) && !access_has_bug_level( $t_due_date_view_threshold, $p_bug_id, $t_user_id ) ) {
  199. continue;
  200. }
  201. }
  202. // bugnotes
  203. if( $t_user_id != $v_user_id ) {
  204. // bypass if user originated note
  205. if(( $v_type == BUGNOTE_ADDED ) || ( $v_type == BUGNOTE_UPDATED ) || ( $v_type == BUGNOTE_DELETED ) ) {
  206. if( !$t_private_bugnote_visible && ( bugnote_get_field( $v_old_value, 'view_state' ) == VS_PRIVATE ) ) {
  207. continue;
  208. }
  209. }
  210. if( $v_type == BUGNOTE_STATE_CHANGED ) {
  211. if( !$t_private_bugnote_visible && ( bugnote_get_field( $v_new_value, 'view_state' ) == VS_PRIVATE ) ) {
  212. continue;
  213. }
  214. }
  215. }
  216. // tags
  217. if( $v_type == TAG_ATTACHED || $v_type == TAG_DETACHED || $v_type == TAG_RENAMED ) {
  218. if( !access_has_global_level( config_get( 'tag_view_threshold' ) ) ) {
  219. continue;
  220. }
  221. }
  222. $raw_history[$j]['date'] = $v_date_modified;
  223. $raw_history[$j]['userid'] = $v_user_id;
  224. # user_get_name handles deleted users, and username vs realname
  225. $raw_history[$j]['username'] = user_get_name( $v_user_id );
  226. $raw_history[$j]['field'] = $v_field_name;
  227. $raw_history[$j]['type'] = $v_type;
  228. $raw_history[$j]['old_value'] = $v_old_value;
  229. $raw_history[$j]['new_value'] = $v_new_value;
  230. $j++;
  231. }
  232. # end for loop
  233. return $raw_history;
  234. }
  235. /**
  236. * Localizes one raw history item specified by set the next parameters: $p_field_name, $p_type, $p_old_value, $p_new_value
  237. * Returns array with two elements indexed as 'note' and 'change'
  238. * @param string $p_field_name
  239. * @param int $p_type
  240. * @param string $p_old_value
  241. * @param string $p_new_value
  242. * @param bool $p_linkify
  243. * @return array
  244. */
  245. function history_localize_item( $p_field_name, $p_type, $p_old_value, $p_new_value, $p_linkify=true ) {
  246. $t_note = '';
  247. $t_change = '';
  248. $t_field_localized = $p_field_name;
  249. $t_raw = true;
  250. if( PLUGIN_HISTORY == $p_type ) {
  251. $t_note = lang_get_defaulted( "plugin_$p_field_name", $p_field_name );
  252. $t_change = ( isset( $p_new_value ) ? "$p_old_value => $p_new_value" : $p_old_value );
  253. return array( 'note' => $t_note, 'change' => $t_change, 'raw' => true );
  254. }
  255. switch( $p_field_name ) {
  256. case 'category':
  257. $t_field_localized = lang_get( 'category' );
  258. break;
  259. case 'status':
  260. $p_old_value = get_enum_element( 'status', $p_old_value );
  261. $p_new_value = get_enum_element( 'status', $p_new_value );
  262. $t_field_localized = lang_get( 'status' );
  263. break;
  264. case 'severity':
  265. $p_old_value = get_enum_element( 'severity', $p_old_value );
  266. $p_new_value = get_enum_element( 'severity', $p_new_value );
  267. $t_field_localized = lang_get( 'severity' );
  268. break;
  269. case 'reproducibility':
  270. $p_old_value = get_enum_element( 'reproducibility', $p_old_value );
  271. $p_new_value = get_enum_element( 'reproducibility', $p_new_value );
  272. $t_field_localized = lang_get( 'reproducibility' );
  273. break;
  274. case 'resolution':
  275. $p_old_value = get_enum_element( 'resolution', $p_old_value );
  276. $p_new_value = get_enum_element( 'resolution', $p_new_value );
  277. $t_field_localized = lang_get( 'resolution' );
  278. break;
  279. case 'priority':
  280. $p_old_value = get_enum_element( 'priority', $p_old_value );
  281. $p_new_value = get_enum_element( 'priority', $p_new_value );
  282. $t_field_localized = lang_get( 'priority' );
  283. break;
  284. case 'eta':
  285. $p_old_value = get_enum_element( 'eta', $p_old_value );
  286. $p_new_value = get_enum_element( 'eta', $p_new_value );
  287. $t_field_localized = lang_get( 'eta' );
  288. break;
  289. case 'view_state':
  290. $p_old_value = get_enum_element( 'view_state', $p_old_value );
  291. $p_new_value = get_enum_element( 'view_state', $p_new_value );
  292. $t_field_localized = lang_get( 'view_status' );
  293. break;
  294. case 'projection':
  295. $p_old_value = get_enum_element( 'projection', $p_old_value );
  296. $p_new_value = get_enum_element( 'projection', $p_new_value );
  297. $t_field_localized = lang_get( 'projection' );
  298. break;
  299. case 'sticky':
  300. $p_old_value = gpc_string_to_bool( $p_old_value ) ? lang_get( 'yes' ) : lang_get( 'no' );
  301. $p_new_value = gpc_string_to_bool( $p_new_value ) ? lang_get( 'yes' ) : lang_get( 'no' );
  302. $t_field_localized = lang_get( 'sticky_issue' );
  303. break;
  304. case 'project_id':
  305. if( project_exists( $p_old_value ) ) {
  306. $p_old_value = project_get_field( $p_old_value, 'name' );
  307. } else {
  308. $p_old_value = '@' . $p_old_value . '@';
  309. }
  310. # Note that the new value maybe an intermediately project and not the
  311. # current one.
  312. if( project_exists( $p_new_value ) ) {
  313. $p_new_value = project_get_field( $p_new_value, 'name' );
  314. } else {
  315. $p_new_value = '@' . $p_new_value . '@';
  316. }
  317. $t_field_localized = lang_get( 'email_project' );
  318. break;
  319. case 'handler_id':
  320. $t_field_localized = lang_get( 'assigned_to' );
  321. case 'reporter_id':
  322. if( 'reporter_id' == $p_field_name ) {
  323. $t_field_localized = lang_get( 'reporter' );
  324. }
  325. if( 0 == $p_old_value ) {
  326. $p_old_value = '';
  327. } else {
  328. $p_old_value = user_get_name( $p_old_value );
  329. }
  330. if( 0 == $p_new_value ) {
  331. $p_new_value = '';
  332. } else {
  333. $p_new_value = user_get_name( $p_new_value );
  334. }
  335. break;
  336. case 'version':
  337. $t_field_localized = lang_get( 'product_version' );
  338. break;
  339. case 'fixed_in_version':
  340. $t_field_localized = lang_get( 'fixed_in_version' );
  341. break;
  342. case 'target_version':
  343. $t_field_localized = lang_get( 'target_version' );
  344. break;
  345. case 'date_submitted':
  346. $t_field_localized = lang_get( 'date_submitted' );
  347. break;
  348. case 'last_updated':
  349. $t_field_localized = lang_get( 'last_update' );
  350. break;
  351. case 'os':
  352. $t_field_localized = lang_get( 'os' );
  353. break;
  354. case 'os_build':
  355. $t_field_localized = lang_get( 'os_version' );
  356. break;
  357. case 'build':
  358. $t_field_localized = lang_get( 'build' );
  359. break;
  360. case 'platform':
  361. $t_field_localized = lang_get( 'platform' );
  362. break;
  363. case 'summary':
  364. $t_field_localized = lang_get( 'summary' );
  365. break;
  366. case 'duplicate_id':
  367. $t_field_localized = lang_get( 'duplicate_id' );
  368. break;
  369. case 'sponsorship_total':
  370. $t_field_localized = lang_get( 'sponsorship_total' );
  371. break;
  372. case 'due_date':
  373. if( $p_old_value !== '' ) {
  374. $p_old_value = date( config_get( 'normal_date_format' ), (int) $p_old_value );
  375. }
  376. if( $p_new_value !== '' ) {
  377. $p_new_value = date( config_get( 'normal_date_format' ), (int) $p_new_value );
  378. }
  379. $t_field_localized = lang_get( 'due_date' );
  380. break;
  381. default:
  382. # assume it's a custom field name
  383. $t_field_id = custom_field_get_id_from_name( $p_field_name );
  384. if( false !== $t_field_id ) {
  385. $t_cf_type = custom_field_type( $t_field_id );
  386. if( '' != $p_old_value ) {
  387. $p_old_value = string_custom_field_value_for_email( $p_old_value, $t_cf_type );
  388. }
  389. $p_new_value = string_custom_field_value_for_email( $p_new_value, $t_cf_type );
  390. }
  391. }
  392. if( NORMAL_TYPE != $p_type ) {
  393. switch( $p_type ) {
  394. case NEW_BUG:
  395. $t_note = lang_get( 'new_bug' );
  396. break;
  397. case BUGNOTE_ADDED:
  398. $t_note = lang_get( 'bugnote_added' ) . ': ' . $p_old_value;
  399. break;
  400. case BUGNOTE_UPDATED:
  401. $t_note = lang_get( 'bugnote_edited' ) . ': ' . $p_old_value;
  402. if ( $p_linkify && bug_revision_exists( $p_new_value ) ) {
  403. if ( bugnote_exists( $p_old_value ) ) {
  404. $t_bug_revision_view_page_argument = 'bugnote_id=' . $p_old_value . '#r' . $p_new_value;
  405. } else {
  406. $t_bug_revision_view_page_argument = 'rev_id=' . $p_new_value;
  407. }
  408. $t_change = '<a href="bug_revision_view_page.php?' . $t_bug_revision_view_page_argument . '">' .
  409. lang_get( 'view_revisions' ) . '</a>';
  410. $t_raw = false;
  411. }
  412. break;
  413. case BUGNOTE_DELETED:
  414. $t_note = lang_get( 'bugnote_deleted' ) . ': ' . $p_old_value;
  415. break;
  416. case DESCRIPTION_UPDATED:
  417. $t_note = lang_get( 'description_updated' );
  418. if ( $p_linkify && bug_revision_exists( $p_old_value ) ) {
  419. $t_change = '<a href="bug_revision_view_page.php?rev_id=' . $p_old_value . '#r' . $p_old_value . '">' .
  420. lang_get( 'view_revisions' ) . '</a>';
  421. $t_raw = false;
  422. }
  423. break;
  424. case ADDITIONAL_INFO_UPDATED:
  425. $t_note = lang_get( 'additional_information_updated' );
  426. if ( $p_linkify && bug_revision_exists( $p_old_value ) ) {
  427. $t_change = '<a href="bug_revision_view_page.php?rev_id=' . $p_old_value . '#r' . $p_old_value . '">' .
  428. lang_get( 'view_revisions' ) . '</a>';
  429. $t_raw = false;
  430. }
  431. break;
  432. case STEP_TO_REPRODUCE_UPDATED:
  433. $t_note = lang_get( 'steps_to_reproduce_updated' );
  434. if ( $p_linkify && bug_revision_exists( $p_old_value ) ) {
  435. $t_change = '<a href="bug_revision_view_page.php?rev_id=' . $p_old_value . '#r' . $p_old_value . '">' .
  436. lang_get( 'view_revisions' ) . '</a>';
  437. $t_raw = false;
  438. }
  439. break;
  440. case FILE_ADDED:
  441. $t_note = lang_get( 'file_added' ) . ': ' . $p_old_value;
  442. break;
  443. case FILE_DELETED:
  444. $t_note = lang_get( 'file_deleted' ) . ': ' . $p_old_value;
  445. break;
  446. case BUGNOTE_STATE_CHANGED:
  447. $p_old_value = get_enum_element( 'view_state', $p_old_value );
  448. $t_note = lang_get( 'bugnote_view_state' ) . ': ' . $p_new_value . ': ' . $p_old_value;
  449. break;
  450. case BUG_MONITOR:
  451. $p_old_value = user_get_name( $p_old_value );
  452. $t_note = lang_get( 'bug_monitor' ) . ': ' . $p_old_value;
  453. break;
  454. case BUG_UNMONITOR:
  455. $p_old_value = user_get_name( $p_old_value );
  456. $t_note = lang_get( 'bug_end_monitor' ) . ': ' . $p_old_value;
  457. break;
  458. case BUG_DELETED:
  459. $t_note = lang_get( 'bug_deleted' ) . ': ' . $p_old_value;
  460. break;
  461. case BUG_ADD_SPONSORSHIP:
  462. $t_note = lang_get( 'sponsorship_added' );
  463. $t_change = user_get_name( $p_old_value ) . ': ' . sponsorship_format_amount( $p_new_value );
  464. break;
  465. case BUG_UPDATE_SPONSORSHIP:
  466. $t_note = lang_get( 'sponsorship_updated' );
  467. $t_change = user_get_name( $p_old_value ) . ': ' . sponsorship_format_amount( $p_new_value );
  468. break;
  469. case BUG_DELETE_SPONSORSHIP:
  470. $t_note = lang_get( 'sponsorship_deleted' );
  471. $t_change = user_get_name( $p_old_value ) . ': ' . sponsorship_format_amount( $p_new_value );
  472. break;
  473. case BUG_PAID_SPONSORSHIP:
  474. $t_note = lang_get( 'sponsorship_paid' );
  475. $t_change = user_get_name( $p_old_value ) . ': ' . get_enum_element( 'sponsorship', $p_new_value );
  476. break;
  477. case BUG_ADD_RELATIONSHIP:
  478. $t_note = lang_get( 'relationship_added' );
  479. $t_change = relationship_get_description_for_history( $p_old_value ) . ' ' . bug_format_id( $p_new_value );
  480. break;
  481. case BUG_REPLACE_RELATIONSHIP:
  482. $t_note = lang_get( 'relationship_replaced' );
  483. $t_change = relationship_get_description_for_history( $p_old_value ) . ' ' . bug_format_id( $p_new_value );
  484. break;
  485. case BUG_DEL_RELATIONSHIP:
  486. $t_note = lang_get( 'relationship_deleted' );
  487. # Fix for #7846: There are some cases where old value is empty, this may be due to an old bug.
  488. if( !is_blank( $p_old_value ) && $p_old_value > 0 ) {
  489. $t_change = relationship_get_description_for_history( $p_old_value ) . ' ' . bug_format_id( $p_new_value );
  490. } else {
  491. $t_change = bug_format_id( $p_new_value );
  492. }
  493. break;
  494. case BUG_CLONED_TO:
  495. $t_note = lang_get( 'bug_cloned_to' );
  496. $t_change = bug_format_id( $p_new_value );
  497. break;
  498. case BUG_CREATED_FROM:
  499. $t_note = lang_get( 'bug_created_from' );
  500. $t_change = bug_format_id( $p_new_value );
  501. break;
  502. case TAG_ATTACHED:
  503. $t_note = lang_get( 'tag_history_attached' ) . ': ' . $p_old_value;
  504. break;
  505. case TAG_DETACHED:
  506. $t_note = lang_get( 'tag_history_detached' ) . ': ' . $p_old_value;
  507. break;
  508. case TAG_RENAMED:
  509. $t_note = lang_get( 'tag_history_renamed' );
  510. $t_change = $p_old_value . ' => ' . $p_new_value;
  511. break;
  512. case BUG_REVISION_DROPPED:
  513. $t_note = lang_get( 'bug_revision_dropped_history' ) . ': ' . bug_revision_get_type_name( $p_new_value ) . ': ' . $p_old_value;
  514. break;
  515. case BUGNOTE_REVISION_DROPPED:
  516. $t_note = lang_get( 'bugnote_revision_dropped_history' ) . ': ' . $p_new_value . ': ' . $p_old_value;
  517. break;
  518. }
  519. }
  520. # output special cases
  521. if( NORMAL_TYPE == $p_type ) {
  522. $t_note = $t_field_localized;
  523. $t_change = $p_old_value . ' => ' . $p_new_value;
  524. }
  525. # end if DEFAULT
  526. return array( 'note' => $t_note, 'change' => $t_change, 'raw' => $t_raw );
  527. }
  528. /**
  529. * delete all history associated with a bug
  530. * @param int $p_bug_id
  531. * @return true
  532. */
  533. function history_delete( $p_bug_id ) {
  534. $c_bug_id = db_prepare_int( $p_bug_id );
  535. $t_bug_history_table = db_get_table( 'bug_history' );
  536. $query = 'DELETE FROM ' . $t_bug_history_table . ' WHERE bug_id=' . db_param();
  537. db_query_bound( $query, Array( $c_bug_id ) );
  538. # db_query errors on failure so:
  539. return true;
  540. }