View Issue Details

IDProjectCategoryView StatusLast Update
0009489mantisbtbugtrackerpublic2008-08-05 12:00
Reportergaetan Assigned To 
PrioritynormalSeverityminorReproducibilityalways
Status newResolutionopen 
Product Version1.0.7 
Summary0009489: copy issue doesn't work with attachments and DISK storage
Description

Attachments aren't copies due to a directory separator missing. Moreover , if projects have different "Upload File Path" set , attachments won't be copied to the right directory.

It's related to this bug http://www.mantisbt.org/bugs/view.php?id=6080

I modified bug_copy() in bug_api.php , see attached file.

I hope it'll help those forced to use old version of Mantis.

Steps To Reproduce

1) Configure Mantis for DISK file upload storage
2) Set different "Upload File Path" for origin and destination projects
2) Report an issue with an attachment.
3) Click "View Issues"
4) Select issue.
5) Select "Copy" for issue.
6) Copy Issue.

Additional Information

I managed to reproduced the problem with 1.0.8

TagsNo tags attached.
Attached Files
bug_api.php (50,659 bytes)   
<?php
	# Mantis - a php based bugtracking system
	# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
	# Copyright (C) 2002 - 2004  Mantis Team   - mantisbt-dev@lists.sourceforge.net
	# This program is distributed under the terms and conditions of the GPL
	# See the README and LICENSE files for details

	# --------------------------------------------------------
	# $Id: bug_api.php,v 1.1 2008/05/02 11:31:58 riou Exp $
	# --------------------------------------------------------

	$t_core_dir = dirname( __FILE__ ).DIRECTORY_SEPARATOR;

	require_once( $t_core_dir . 'history_api.php' );
	require_once( $t_core_dir . 'email_api.php' );
	require_once( $t_core_dir . 'bugnote_api.php' );
	require_once( $t_core_dir . 'file_api.php' );
	require_once( $t_core_dir . 'string_api.php' );
	require_once( $t_core_dir . 'sponsorship_api.php' );

	# MASC RELATIONSHIP
	require_once( $t_core_dir.'relationship_api.php' );
	# MASC RELATIONSHIP

	### Bug API ###

	#===================================
	# Bug Data Structure Definition
	#===================================
	class BugData {
		var $project_id = null;
		var $reporter_id = 0;
		var $handler_id = 0;
		var $duplicate_id = 0;
		var $priority = NORMAL;
		var $severity = MINOR;
		var $reproducibility = 10;
		var $status = NEW_;
		var $resolution = OPEN;
		var $projection = 10;
		var $category = '';
		var $date_submitted = '';
		var $last_updated = '';
		var $eta = 10;
		var $os = '';
		var $os_build = '';
		var $platform = '';
		var $version = '';
		var $fixed_in_version = '';
		var $build = '';
		var $view_state = VS_PUBLIC;
		var $summary = '';
		var $sponsorship_total = 0;
		var $sticky = 0;

		# omitted:
		# var $bug_text_id
		var $profile_id;

		# extended info
		var $description = '';
		var $steps_to_reproduce = '';
		var $additional_information = '';
	}

	#===================================
	# Caching
	#===================================

	#########################################
	# SECURITY NOTE: cache globals are initialized here to prevent them
	#   being spoofed if register_globals is turned on

	$g_cache_bug = array();
	$g_cache_bug_text = array();

	# --------------------
	# Cache a bug row if necessary and return the cached copy
	#  If the second parameter is true (default), trigger an error
	#  if the bug can't be found.  If the second parameter is
	#  false, return false if the bug can't be found.
	function bug_cache_row( $p_bug_id, $p_trigger_errors=true ) {
		global $g_cache_bug;

		$c_bug_id		= db_prepare_int( $p_bug_id );
		$t_bug_table	= config_get( 'mantis_bug_table' );

		if ( isset( $g_cache_bug[$c_bug_id] ) ) {
			return $g_cache_bug[$c_bug_id];
		}

		$query = "SELECT *
				  FROM $t_bug_table
				  WHERE id='$c_bug_id'";
		$result = db_query( $query );

		if ( 0 == db_num_rows( $result ) ) {
			$g_cache_bug[$c_bug_id] = false;

			if ( $p_trigger_errors ) {
				error_parameters( $p_bug_id );
				trigger_error( ERROR_BUG_NOT_FOUND, ERROR );
			} else {
				return false;
			}
		}

		$row = db_fetch_array( $result );
		$row['date_submitted']	= db_unixtimestamp( $row['date_submitted'] );
		$row['last_updated']	= db_unixtimestamp( $row['last_updated'] );
		$g_cache_bug[$c_bug_id] = $row;

		return $row;
	}

	# --------------------
	# Inject a bug into the bug cache
	function bug_add_to_cache( $p_bug_row ) {
		global $g_cache_bug;

		if ( !is_array( $p_bug_row ) )
			return false;

		$c_bug_id = db_prepare_int( $p_bug_row['id'] );
		$g_cache_bug[ $c_bug_id ] = $p_bug_row;

		return true;
	}

	# --------------------
	# Clear the bug cache (or just the given id if specified)
	function bug_clear_cache( $p_bug_id = null ) {
		global $g_cache_bug;

		if ( null === $p_bug_id ) {
			$g_cache_bug = array();
		} else {
			$c_bug_id = db_prepare_int( $p_bug_id );
			unset( $g_cache_bug[$c_bug_id] );
		}

		return true;
	}

	# --------------------
	# Cache a bug text row if necessary and return the cached copy
	#  If the second parameter is true (default), trigger an error
	#  if the bug text can't be found.  If the second parameter is
	#  false, return false if the bug text can't be found.
	function bug_text_cache_row( $p_bug_id, $p_trigger_errors=true ) {
		global $g_cache_bug_text;

		$c_bug_id			= db_prepare_int( $p_bug_id );
		$t_bug_table		= config_get( 'mantis_bug_table' );
		$t_bug_text_table	= config_get( 'mantis_bug_text_table' );

		if ( isset ( $g_cache_bug_text[$c_bug_id] ) ) {
			return $g_cache_bug_text[$c_bug_id];
		}

		$query = "SELECT bt.*
				  FROM $t_bug_text_table bt, $t_bug_table b
				  WHERE b.id='$c_bug_id' AND
				  		b.bug_text_id = bt.id";
		$result = db_query( $query );

		if ( 0 == db_num_rows( $result ) ) {
			$g_cache_bug_text[$c_bug_id] = false;

			if ( $p_trigger_errors ) {
				error_parameters( $p_bug_id );
				trigger_error( ERROR_BUG_NOT_FOUND, ERROR );
			} else {
				return false;
			}
		}

		$row = db_fetch_array( $result );

		$g_cache_bug_text[$c_bug_id] = $row;

		return $row;
	}

	# --------------------
	# Clear the bug text cache (or just the given id if specified)
	function bug_text_clear_cache( $p_bug_id = null ) {
		global $g_cache_bug_text;

		if ( null === $p_bug_id ) {
			$g_cache_bug_text = array();
		} else {
			$c_bug_id = db_prepare_int( $p_bug_id );
			unset( $g_cache_bug_text[$c_bug_id] );
		}

		return true;
	}

	#===================================
	# Boolean queries and ensures
	#===================================

	# --------------------
	# check to see if bug exists by id
	# return true if it does, false otherwise
	function bug_exists( $p_bug_id ) {
		if ( false == bug_cache_row( $p_bug_id, false ) ) {
			return false;
		} else {
			return true;
		}
	}

	# --------------------
	# check to see if bug exists by id
	# if it doesn't exist then error
	#  otherwise let execution continue undisturbed
	function bug_ensure_exists( $p_bug_id ) {
		if ( !bug_exists( $p_bug_id ) ) {
			error_parameters( $p_bug_id );
			trigger_error( ERROR_BUG_NOT_FOUND, ERROR );
		}
	}

	# --------------------
	# check if the given user is the reporter of the bug
	# return true if the user is the reporter, false otherwise
	function bug_is_user_reporter( $p_bug_id, $p_user_id ) {
		if ( bug_get_field( $p_bug_id, 'reporter_id' ) == $p_user_id ) {
			return true;
		} else {
			return false;
		}
	}

	# --------------------
	# check if the given user is the handler of the bug
	# return true if the user is the handler, false otherwise
	function bug_is_user_handler( $p_bug_id, $p_user_id ) {
		if ( bug_get_field( $p_bug_id, 'handler_id' ) == $p_user_id ) {
			return true;
		} else {
			return false;
		}
	}

	# --------------------
	# Check if the bug is readonly and shouldn't be modified
	# For a bug to be readonly the status has to be >= bug_readonly_status_threshold and
	# current user access level < update_readonly_bug_threshold.
	function bug_is_readonly( $p_bug_id ) {
		$t_status = bug_get_field( $p_bug_id, 'status' );
		if ( $t_status < config_get( 'bug_readonly_status_threshold' ) ) {
			return false;
		}

		if ( access_has_bug_level( config_get( 'update_readonly_bug_threshold' ), $p_bug_id ) ) {
			return false;
		}

		return true;
	}

	# --------------------
	# Validate workflow state to see if bug can be moved to requested state
	function bug_check_workflow( $p_bug_status, $p_wanted_status ) {
		$t_status_enum_workflow = config_get( 'status_enum_workflow' );

		if ( count( $t_status_enum_workflow ) < 1) {
			# workflow not defined, use default enum
			return true;
		} else if ( $p_bug_status == $p_wanted_status ) {
			# no change in state, allow the transition
			return true;
		} else {
			# workflow defined - find allowed states
			$t_allowed_states = $t_status_enum_workflow[$p_bug_status];
			$t_arr = explode_enum_string( $t_allowed_states );

			$t_enum_count = count( $t_arr );

			for ( $i = 0; $i < $t_enum_count; $i++ ) {
				# check if wanted status is allowed
				$t_elem  = explode_enum_arr( $t_arr[$i] );
				if ( $p_wanted_status == $t_elem[0] ) {
					return true;
				}
			} # end for
		}

		return false;
	}

	#===================================
	# Creation / Deletion / Updating
	#===================================

	# --------------------
	# Create a new bug and return the bug id
	#
	function bug_create( $p_bug_data ) {

		$c_summary				= db_prepare_string( $p_bug_data->summary );
		$c_description			= db_prepare_string( $p_bug_data->description );
		$c_project_id			= db_prepare_int( $p_bug_data->project_id );
		$c_reporter_id			= db_prepare_int( $p_bug_data->reporter_id );
		$c_handler_id			= db_prepare_int( $p_bug_data->handler_id );
		$c_priority				= db_prepare_int( $p_bug_data->priority );
		$c_severity				= db_prepare_int( $p_bug_data->severity );
		$c_reproducibility		= db_prepare_int( $p_bug_data->reproducibility );
		$c_category				= db_prepare_string( $p_bug_data->category );
		$c_os					= db_prepare_string( $p_bug_data->os );
		$c_os_build				= db_prepare_string( $p_bug_data->os_build );
		$c_platform				= db_prepare_string( $p_bug_data->platform );
		$c_version				= db_prepare_string( $p_bug_data->version );
		$c_build				= db_prepare_string( $p_bug_data->build );
		$c_profile_id			= db_prepare_int( $p_bug_data->profile_id );
		$c_view_state			= db_prepare_int( $p_bug_data->view_state );
		$c_steps_to_reproduce	= db_prepare_string( $p_bug_data->steps_to_reproduce );
		$c_additional_info		= db_prepare_string( $p_bug_data->additional_information );
		$c_sponsorship_total 	= 0;
		$c_sticky 				= 0;

		# Summary cannot be blank
		if ( is_blank( $c_summary ) ) {
			error_parameters( lang_get( 'summary' ) );
			trigger_error( ERROR_EMPTY_FIELD, ERROR );
		}

		# Description cannot be blank
		if ( is_blank( $c_description ) ) {
			error_parameters( lang_get( 'description' ) );
			trigger_error( ERROR_EMPTY_FIELD, ERROR );
		}

		$t_bug_table				= config_get( 'mantis_bug_table' );
		$t_bug_text_table			= config_get( 'mantis_bug_text_table' );
		$t_project_category_table	= config_get( 'mantis_project_category_table' );

		# Insert text information
		$query = "INSERT INTO $t_bug_text_table
				    ( description, steps_to_reproduce, additional_information )
				  VALUES
				    ( '$c_description', '$c_steps_to_reproduce',
				      '$c_additional_info' )";
		db_query( $query );

		# Get the id of the text information we just inserted
		# NOTE: this is guarranteed to be the correct one.
		# The value LAST_INSERT_ID is stored on a per connection basis.

		$t_text_id = db_insert_id($t_bug_text_table);

		# check to see if we want to assign this right off
		$t_status = config_get( 'bug_submit_status' );

		# if not assigned, check if it should auto-assigned.
		if ( 0 == $c_handler_id ) {
			# if a default user is associated with the category and we know at this point
			# that that the bug was not assigned to somebody, then assign it automatically.
			$query = "SELECT user_id
					  FROM $t_project_category_table
					  WHERE project_id='$c_project_id' AND category='$c_category'";
			$result = db_query( $query );

			if ( db_num_rows( $result ) > 0 ) {
				$c_handler_id = $p_handler_id = db_result( $result );
			}
		}

		# Check if bug was pre-assigned or auto-assigned.
		if ( ( $c_handler_id != 0 ) && ( ON == config_get( 'auto_set_status_to_assigned' ) ) ) {
			$t_status = config_get( 'bug_assigned_status' );
		}

		# Insert the rest of the data
		$t_resolution = OPEN;

		$query = "INSERT INTO $t_bug_table
				    ( project_id,
				      reporter_id, handler_id,
				      duplicate_id, priority,
				      severity, reproducibility,
				      status, resolution,
				      projection, category,
				      date_submitted, last_updated,
				      eta, bug_text_id,
				      os, os_build,
				      platform, version,
				      build,
				      profile_id, summary, view_state, sponsorship_total, sticky, fixed_in_version )
				  VALUES
				    ( '$c_project_id',
				      '$c_reporter_id', '$c_handler_id',
				      '0', '$c_priority',
				      '$c_severity', '$c_reproducibility',
				      '$t_status', '$t_resolution',
				      10, '$c_category',
				      " . db_now() . "," . db_now() . ",
				      10, '$t_text_id',
				      '$c_os', '$c_os_build',
				      '$c_platform', '$c_version',
				      '$c_build',
				      '$c_profile_id', '$c_summary', '$c_view_state', '$c_sponsorship_total', '$c_sticky', '' )";
		db_query( $query );

		$t_bug_id = db_insert_id($t_bug_table);

		# log new bug
		history_log_event_special( $t_bug_id, NEW_BUG );

		# log changes, if any (compare happens in history_log_event_direct)
		history_log_event_direct( $t_bug_id, 'status', config_get( 'bug_submit_status' ), $t_status );
		history_log_event_direct( $t_bug_id, 'handler_id', 0, $c_handler_id );

		return $t_bug_id;
	}

	# --------------------
	# Copy a bug from one project to another. Also make copies of issue notes, attachments, history,
	# email notifications etc.
	# @@@ Not managed FTP file upload
	# MASC RELATIONSHIP
	function bug_copy( $p_bug_id, $p_target_project_id = null, $p_copy_custom_fields = false, $p_copy_relationships = false,
		$p_copy_history = false, $p_copy_attachments = false, $p_copy_bugnotes = false, $p_copy_monitoring_users = false ) {
		global $g_db;

		$t_mantis_custom_field_string_table	= config_get( 'mantis_custom_field_string_table' );
		$t_mantis_bug_file_table			= config_get( 'mantis_bug_file_table' );
		$t_mantis_bugnote_table				= config_get( 'mantis_bugnote_table' );
		$t_mantis_bugnote_text_table		= config_get( 'mantis_bugnote_text_table' );
		$t_mantis_bug_monitor_table			= config_get( 'mantis_bug_monitor_table' );
		$t_mantis_bug_history_table			= config_get( 'mantis_bug_history_table' );
		$t_mantis_project_table             = config_get( 'mantis_project_table' );
		$t_mantis_db = $g_db;

		$t_bug_id = db_prepare_int( $p_bug_id );
		$t_target_project_id = db_prepare_int( $p_target_project_id );


		$t_bug_data = new BugData;
		$t_bug_data = bug_get( $t_bug_id, true );

		# retrieve the project id associated with the bug
		if ( ( $p_target_project_id == null ) || is_blank( $p_target_project_id ) ) {
			$t_target_project_id = $t_bug_data->project_id;
		}

		$t_bug_data->project_id = $t_target_project_id;

		$t_new_bug_id = bug_create( $t_bug_data );

		# MASC ATTENTION: IF THE SOURCE BUG HAS TO HANDLER THE bug_create FUNCTION CAN TRY TO AUTO-ASSIGN THE BUG
		# WE FORCE HERE TO DUPLICATE THE SAME HANDLER OF THE SOURCE BUG
		# @@@ VB: Shouldn't we check if the handler in the source project is also a handler in the destination project?
		bug_set_field( $t_new_bug_id, 'handler_id', $t_bug_data->handler_id );

		bug_set_field( $t_new_bug_id, 'duplicate_id', $t_bug_data->duplicate_id );
		bug_set_field( $t_new_bug_id, 'status', $t_bug_data->status );
		bug_set_field( $t_new_bug_id, 'resolution', $t_bug_data->resolution );
		bug_set_field( $t_new_bug_id, 'projection', $t_bug_data->projection );
		bug_set_field( $t_new_bug_id, 'date_submitted', $t_mantis_db->DBTimeStamp( $t_bug_data->date_submitted ), false );
		bug_set_field( $t_new_bug_id, 'last_updated', $t_mantis_db->DBTimeStamp( $t_bug_data->last_updated ), false );
		bug_set_field( $t_new_bug_id, 'eta', $t_bug_data->eta );
		bug_set_field( $t_new_bug_id, 'fixed_in_version', $t_bug_data->fixed_in_version );
		bug_set_field( $t_new_bug_id, 'sponsorship_total', 0 );
		bug_set_field( $t_new_bug_id, 'sticky', 0 );

		# COPY CUSTOM FIELDS
		if ( $p_copy_custom_fields ) {
			$query = "SELECT field_id, bug_id, value
					   FROM $t_mantis_custom_field_string_table
					   WHERE bug_id = '$t_bug_id';";
			$result = db_query( $query );
			$t_count = db_num_rows( $result );

			for ( $i = 0 ; $i < $t_count ; $i++ ) {
				$t_bug_custom = db_fetch_array( $result );

				$c_field_id = db_prepare_int( $t_bug_custom['field_id'] );
				$c_new_bug_id = db_prepare_int( $t_new_bug_id );
				$c_value = db_prepare_string( $t_bug_custom['value'] );

				$query = "INSERT INTO $t_mantis_custom_field_string_table
						   ( field_id, bug_id, value )
						   VALUES ('$c_field_id', '$c_new_bug_id', '$c_value')";
				db_query( $query );
			}
		}

		# COPY RELATIONSHIPS
		if ( $p_copy_relationships ) {
			if ( ON == config_get( 'enable_relationship' ) ) {
				relationship_copy_all( $t_bug_id,$t_new_bug_id );
			}
		}

		# Copy bugnotes
		if ( $p_copy_bugnotes ) {
			$query = "SELECT *
					  FROM $t_mantis_bugnote_table
					  WHERE bug_id = '$t_bug_id';";
			$result = db_query( $query );
			$t_count = db_num_rows( $result );

			for ( $i = 0; $i < $t_count; $i++ ) {
				$t_bug_note = db_fetch_array( $result );
				$t_bugnote_text_id = $t_bug_note['bugnote_text_id'];

				$query2 = "SELECT *
						   FROM $t_mantis_bugnote_text_table
						   WHERE id = '$t_bugnote_text_id';";
				$result2 = db_query( $query2 );
				$t_count2 = db_num_rows( $result2 );

				$t_bugnote_text_insert_id = -1;
				if ( $t_count2 > 0 ) {
					$t_bugnote_text = db_fetch_array( $result2 );
					$t_bugnote_text['note'] = db_prepare_string( $t_bugnote_text['note'] );

					$query2 = "INSERT INTO $t_mantis_bugnote_text_table
							   ( note )
							   VALUES ( '" . $t_bugnote_text['note'] . "' );";
					db_query( $query2 );
					$t_bugnote_text_insert_id = db_insert_id( $t_mantis_bugnote_text_table );
				}

				$query2 = "INSERT INTO $t_mantis_bugnote_table
						   ( bug_id, reporter_id, bugnote_text_id, view_state, date_submitted, last_modified )
						   VALUES ( '$t_new_bug_id',
						   			'" . $t_bug_note['reporter_id'] . "',
						   			'$t_bugnote_text_insert_id',
						   			'" . $t_bug_note['view_state'] . "',
						   			'" . $t_bug_note['date_submitted'] . "',
						   			'" . $t_bug_note['last_modified'] . "' );";
				db_query( $query2 );
			}
		}

		# Copy attachments
		if ( $p_copy_attachments ) {
			// get project folder 
		    $query = "SELECT file_path 
		                      FROM $t_mantis_project_table
		                      WHERE id = $t_target_project_id";
		    $result = db_query( $query );
		    $t_project_file_path = db_result( $result );
		    
		    $query = "SELECT *
					  FROM $t_mantis_bug_file_table
					  WHERE bug_id = '$t_bug_id';";
			$result = db_query( $query );
			$t_count = db_num_rows( $result );

			$t_bug_file = array();
			for ( $i = 0; $i < $t_count; $i++ ) {
				$t_bug_file = db_fetch_array( $result );

				# prepare the new diskfile name and then copy the file
				//$t_file_path = dirname( $t_bug_file['folder'] );
				//$t_new_diskfile_name = $t_file_path . file_generate_unique_name( 'bug-' . $p_file_name, $t_file_path );
				// new diskfile name using the project folder and right parameters for file_generate_unique_name() 
				$t_new_diskfile_name = $t_project_file_path. file_generate_unique_name( 'bug-' . $t_bug_file['filename'], $t_project_file_path );
				$t_new_file_name = file_get_display_name( $t_bug_file['filename'] );
				if ( ( config_get( 'file_upload_method' ) == DISK ) ) {
					copy( $t_bug_file['diskfile'], $t_new_diskfile_name );
					chmod( $t_new_diskfile_name, 0400 ); # make file read only in the file system
				}

				$query = "INSERT INTO $t_mantis_bug_file_table
						( bug_id, title, description, diskfile, filename, folder, filesize, file_type, date_added, content )
						VALUES ( '$t_new_bug_id',
								 '" . db_prepare_string( $t_bug_file['title'] ) . "',
								 '" . db_prepare_string( $t_bug_file['description'] ) . "',
								 '" . db_prepare_string( $t_new_diskfile_name ) . "',
								 '" . db_prepare_string( $t_new_file_name ) . "',
								 '" . db_prepare_string( $t_bug_file['folder'] ) . "',
								 '" . db_prepare_int( $t_bug_file['filesize'] ) . "',
								 '" . db_prepare_string( $t_bug_file['file_type'] ) . "',
								 '" . db_prepare_string( $t_bug_file['date_added'] ) . "',
								 '" . db_prepare_string( $t_bug_file['content'] ) . "');";
				db_query( $query );
			}
		}

		# Copy users monitoring bug
		if ( $p_copy_monitoring_users ) {
			$query = "SELECT *
					  FROM $t_mantis_bug_monitor_table
					  WHERE bug_id = '$t_bug_id';";
			$result = db_query( $query );
			$t_count = db_num_rows( $result );

			for ( $i = 0; $i < $t_count; $i++ ) {
				$t_bug_monitor = db_fetch_array( $result );
				$query = "INSERT INTO $t_mantis_bug_monitor_table
						 ( user_id, bug_id )
						 VALUES ( '" . $t_bug_monitor['user_id'] . "', '$t_new_bug_id' );";
				db_query( $query );
			}
		}

		# COPY HISTORY
		history_delete( $t_new_bug_id );	# should history only be deleted inside the if statement below?
		if ( $p_copy_history ) {
			$query = "SELECT *
					  FROM $t_mantis_bug_history_table
					  WHERE bug_id = '$t_bug_id';";
			$result = db_query( $query );
			$t_count = db_num_rows( $result );

			for ( $i = 0; $i < $t_count; $i++ ) {
				$t_bug_history = db_fetch_array( $result );
				$query = "INSERT INTO $t_mantis_bug_history_table
						  ( user_id, bug_id, date_modified, field_name, old_value, new_value, type )
						  VALUES ( '" . db_prepare_int( $t_bug_history['user_id'] ) . "',
						  		   '$t_new_bug_id',
						  		   '" . db_prepare_string( $t_bug_history['date_modified'] ) . "',
						  		   '" . db_prepare_string( $t_bug_history['field_name'] ) . "',
						  		   '" . db_prepare_string( $t_bug_history['old_value'] ) . "',
						  		   '" . db_prepare_string( $t_bug_history['new_value'] ) . "',
						  		   '" . db_prepare_int( $t_bug_history['type'] ) . "' );";
				db_query( $query );
			}
		}

		return $t_new_bug_id;
	}

	# --------------------
	# allows bug deletion :
	# delete the bug, bugtext, bugnote, and bugtexts selected
	# used in bug_delete.php & mass treatments
	function bug_delete( $p_bug_id ) {
		$c_bug_id			= db_prepare_int( $p_bug_id );
		$t_bug_table		= config_get( 'mantis_bug_table' );
		$t_bug_text_table	= config_get( 'mantis_bug_text_table' );

		# log deletion of bug
		history_log_event_special( $p_bug_id, BUG_DELETED, bug_format_id( $p_bug_id ) );

		email_bug_deleted( $p_bug_id );

		# Unmonitor bug for all users
		bug_unmonitor( $p_bug_id, null );

		# Delete custom fields
		custom_field_delete_all_values( $p_bug_id );

		# Delete bugnotes
		bugnote_delete_all( $p_bug_id );

		# Delete all sponsorships
		sponsorship_delete( sponsorship_get_all_ids( $p_bug_id ) );

		# MASC RELATIONSHIP
		# we delete relationships even if the feature is currently off.
		relationship_delete_all( $p_bug_id );
		# MASC RELATIONSHIP

		# Delete files
		file_delete_attachments( $p_bug_id );

		# Delete the bug history
		history_delete( $p_bug_id );

		# Delete the bugnote text
		$t_bug_text_id = bug_get_field( $p_bug_id, 'bug_text_id' );

		$query = "DELETE FROM $t_bug_text_table
				  WHERE id='$t_bug_text_id'";
		db_query( $query );

		# Delete the bug entry
		$query = "DELETE FROM $t_bug_table
				  WHERE id='$c_bug_id'";
		db_query( $query );

		bug_clear_cache( $p_bug_id );
		bug_text_clear_cache( $p_bug_id );

		# db_query() errors on failure so:
		return true;
	}

	# --------------------
	# Delete all bugs associated with a project
	function bug_delete_all( $p_project_id ) {
		$c_project_id = db_prepare_int( $p_project_id );

		$t_bug_table = config_get( 'mantis_bug_table' );

		$query = "SELECT id
				  FROM $t_bug_table
				  WHERE project_id='$c_project_id'";
		$result = db_query( $query );

		$bug_count = db_num_rows( $result );

		for ( $i=0 ; $i < $bug_count ; $i++ ) {
			$row = db_fetch_array( $result );

			bug_delete( $row['id'] );
		}

		# @@@ should we check the return value of each bug_delete() and
		#  return false if any of them return false? Presumable bug_delete()
		#  will eventually trigger an error on failure so it won't matter...

		return true;
	}

	# --------------------
	# Update a bug from the given data structure
	#  If the third parameter is true, also update the longer strings table
	function bug_update( $p_bug_id, $p_bug_data, $p_update_extended = false, $p_bypass_mail = false ) {
		$c_bug_id		= db_prepare_int( $p_bug_id );
		$c_bug_data		= bug_prepare_db( $p_bug_data );

		# Summary cannot be blank
		if ( is_blank( $c_bug_data->summary ) ) {
			error_parameters( lang_get( 'summary' ) );
			trigger_error( ERROR_EMPTY_FIELD, ERROR );
		}

		if ( $p_update_extended ) {
			# Description field cannot be empty
			if ( is_blank( $c_bug_data->description ) ) {
				error_parameters( lang_get( 'description' ) );
				trigger_error( ERROR_EMPTY_FIELD, ERROR );
			}
		}

		if( !is_blank( $p_bug_data->duplicate_id ) && ( $p_bug_data->duplicate_id != 0 ) && ( $p_bug_id == $p_bug_data->duplicate_id ) ) {
			trigger_error( ERROR_BUG_DUPLICATE_SELF, ERROR );  # never returns
	    }

		$t_old_data = bug_get( $p_bug_id, true );

		$t_bug_table = config_get( 'mantis_bug_table' );

		# Update all fields
		# Ignore date_submitted and last_updated since they are pulled out
		#  as unix timestamps which could confuse the history log and they
		#  shouldn't get updated like this anyway.  If you really need to change
		#  them use bug_set_field()
		$query = "UPDATE $t_bug_table
				SET project_id='$c_bug_data->project_id',
					reporter_id='$c_bug_data->reporter_id',
					handler_id='$c_bug_data->handler_id',
					duplicate_id='$c_bug_data->duplicate_id',
					priority='$c_bug_data->priority',
					severity='$c_bug_data->severity',
					reproducibility='$c_bug_data->reproducibility',
					status='$c_bug_data->status',
					resolution='$c_bug_data->resolution',
					projection='$c_bug_data->projection',
					category='$c_bug_data->category',
					eta='$c_bug_data->eta',
					os='$c_bug_data->os',
					os_build='$c_bug_data->os_build',
					platform='$c_bug_data->platform',
					version='$c_bug_data->version',
					build='$c_bug_data->build',
					fixed_in_version='$c_bug_data->fixed_in_version',
					view_state='$c_bug_data->view_state',
					summary='$c_bug_data->summary',
					sponsorship_total='$c_bug_data->sponsorship_total',
					sticky='$c_bug_data->sticky'
				WHERE id='$c_bug_id'";
		db_query( $query );

		bug_clear_cache( $p_bug_id );

		# log changes
		history_log_event_direct( $p_bug_id, 'project_id', $t_old_data->project_id, $p_bug_data->project_id );
		history_log_event_direct( $p_bug_id, 'reporter_id', $t_old_data->reporter_id, $p_bug_data->reporter_id );
		history_log_event_direct( $p_bug_id, 'handler_id', $t_old_data->handler_id, $p_bug_data->handler_id );
		history_log_event_direct( $p_bug_id, 'duplicate_id', $t_old_data->duplicate_id, $p_bug_data->duplicate_id );
		history_log_event_direct( $p_bug_id, 'priority', $t_old_data->priority, $p_bug_data->priority );
		history_log_event_direct( $p_bug_id, 'severity', $t_old_data->severity, $p_bug_data->severity );
		history_log_event_direct( $p_bug_id, 'reproducibility', $t_old_data->reproducibility, $p_bug_data->reproducibility );
		history_log_event_direct( $p_bug_id, 'status', $t_old_data->status, $p_bug_data->status );
		history_log_event_direct( $p_bug_id, 'resolution', $t_old_data->resolution, $p_bug_data->resolution );
		history_log_event_direct( $p_bug_id, 'projection', $t_old_data->projection, $p_bug_data->projection );
		history_log_event_direct( $p_bug_id, 'category', $t_old_data->category, $p_bug_data->category );
		history_log_event_direct( $p_bug_id, 'eta',	$t_old_data->eta, $p_bug_data->eta );
		history_log_event_direct( $p_bug_id, 'os', $t_old_data->os, $p_bug_data->os );
		history_log_event_direct( $p_bug_id, 'os_build', $t_old_data->os_build, $p_bug_data->os_build );
		history_log_event_direct( $p_bug_id, 'platform', $t_old_data->platform, $p_bug_data->platform );
		history_log_event_direct( $p_bug_id, 'version', $t_old_data->version, $p_bug_data->version );
		history_log_event_direct( $p_bug_id, 'build', $t_old_data->build, $p_bug_data->build );
		history_log_event_direct( $p_bug_id, 'fixed_in_version', $t_old_data->fixed_in_version, $p_bug_data->fixed_in_version );
		history_log_event_direct( $p_bug_id, 'view_state', $t_old_data->view_state, $p_bug_data->view_state );
		history_log_event_direct( $p_bug_id, 'summary', $t_old_data->summary, $p_bug_data->summary );
		history_log_event_direct( $p_bug_id, 'sponsorship_total', $t_old_data->sponsorship_total, $p_bug_data->sponsorship_total );
		history_log_event_direct( $p_bug_id, 'sticky', $t_old_data->sticky, $p_bug_data->sticky );

		# Update extended info if requested
		if ( $p_update_extended ) {
			$t_bug_text_table = config_get( 'mantis_bug_text_table' );

			$t_bug_text_id = bug_get_field( $p_bug_id, 'bug_text_id' );

			$query = "UPDATE $t_bug_text_table
						SET description='$c_bug_data->description',
							steps_to_reproduce='$c_bug_data->steps_to_reproduce',
							additional_information='$c_bug_data->additional_information'
						WHERE id='$t_bug_text_id'";
			db_query( $query );

			bug_text_clear_cache( $p_bug_id );

			if ( $t_old_data->description != $p_bug_data->description ) {
				history_log_event_special( $p_bug_id, DESCRIPTION_UPDATED );
			}
			if ( $t_old_data->steps_to_reproduce != $p_bug_data->steps_to_reproduce ) {
				history_log_event_special( $p_bug_id, STEP_TO_REPRODUCE_UPDATED );
			}
			if ( $t_old_data->additional_information != $p_bug_data->additional_information ) {
				history_log_event_special( $p_bug_id, ADDITIONAL_INFO_UPDATED );
			}
		}

		# Update the last update date
		bug_update_date( $p_bug_id );

		if ( false == $p_bypass_mail ) {		# allow bypass if user is sending mail separately
			$t_action_prefix = 'email_notification_title_for_action_bug_';
			$t_status_prefix = 'email_notification_title_for_status_bug_';

			# status changed
			if ( $t_old_data->status != $p_bug_data->status ) {
				$t_status = get_enum_to_string( config_get( 'status_enum_string' ), $p_bug_data->status );
				$t_status = str_replace( ' ', '_', $t_status );
				email_generic( $p_bug_id, $t_status, $t_status_prefix . $t_status );
				return true;
			}

			# bug assigned
			if ( $t_old_data->handler_id != $p_bug_data->handler_id ) {
				email_generic( $p_bug_id, 'owner', $t_action_prefix . 'assigned' );
				return true;
			}

			# @@@ handle priority change if it requires special handling

			# generic update notification
			email_generic( $p_bug_id, 'updated', $t_action_prefix . 'updated' );
		}

		return true;
	}

	#===================================
	# Data Access
	#===================================

	# --------------------
	# Returns the extended record of the specified bug, this includes
	# the bug text fields
	# @@@ include reporter name and handler name, the problem is that
	#      handler can be 0, in this case no corresponding name will be
	#      found.  Use equivalent of (+) in Oracle.
	function bug_get_extended_row( $p_bug_id ) {
		$t_base = bug_cache_row( $p_bug_id );
		$t_text = bug_text_cache_row( $p_bug_id );

		# merge $t_text first so that the 'id' key has the bug id not the bug text id
		return array_merge( $t_text, $t_base );
	}

	# --------------------
	# Returns the record of the specified bug
	function bug_get_row( $p_bug_id ) {
		return bug_cache_row( $p_bug_id );
	}

	# --------------------
	# Returns an object representing the specified bug
	function bug_get( $p_bug_id, $p_get_extended = false ) {
		if ( $p_get_extended ) {
			$row = bug_get_extended_row( $p_bug_id );
		} else {
			$row = bug_get_row( $p_bug_id );
		}

		$t_bug_data = new BugData;
		$t_row_keys = array_keys( $row );
		$t_vars = get_object_vars( $t_bug_data );

		# Check each variable in the class
		foreach ( $t_vars as $var => $val ) {
			# If we got a field from the DB with the same name
			if ( in_array( $var, $t_row_keys, true ) ) {
				# Store that value in the object
				$t_bug_data->$var = $row[$var];
			}
		}

		return $t_bug_data;
	}

	# --------------------
	# return the specified field of the given bug
	#  if the field does not exist, display a warning and return ''
	function bug_get_field( $p_bug_id, $p_field_name ) {
		$row = bug_get_row( $p_bug_id );

		if ( isset( $row[$p_field_name] ) ) {
			return $row[$p_field_name];
		} else {
			error_parameters( $p_field_name );
			trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING );
			return '';
		}
	}

	# --------------------
	# return the specified text field of the given bug
	#  if the field does not exist, display a warning and return ''
	function bug_get_text_field( $p_bug_id, $p_field_name ) {
		$row = bug_text_cache_row( $p_bug_id );

		if ( isset( $row[$p_field_name] ) ) {
			return $row[$p_field_name];
		} else {
			error_parameters( $p_field_name );
			trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING );
			return '';
		}
	}

	# --------------------
	# return the bug summary
	#  this is a wrapper for the custom function
	function bug_format_summary( $p_bug_id, $p_context ) {
		return 	helper_call_custom_function( 'format_issue_summary', array( $p_bug_id , $p_context ) );
	}


	# --------------------
	# Returns the number of bugnotes for the given bug_id
	function bug_get_bugnote_count( $p_bug_id ) {
		$c_bug_id = db_prepare_int( $p_bug_id );

		$t_project_id = bug_get_field( $p_bug_id, 'project_id' );

		if ( !access_has_project_level( config_get( 'private_bugnote_threshold' ), $t_project_id ) ) {
			$t_restriction = 'AND view_state=' . VS_PUBLIC;
		} else {
			$t_restriction = '';
		}

		$t_bugnote_table = config_get( 'mantis_bugnote_table' );
		$query = "SELECT COUNT(*)
				  FROM $t_bugnote_table
				  WHERE bug_id ='$c_bug_id' $t_restriction";
		$result = db_query( $query );

		return db_result( $result );
	}

	# --------------------
	# return the timestamp for the most recent time at which a bugnote
	#  associated wiht the bug was modified
	function bug_get_newest_bugnote_timestamp( $p_bug_id ) {
		$c_bug_id			= db_prepare_int( $p_bug_id );
		$t_bugnote_table	= config_get( 'mantis_bugnote_table' );

		$query = "SELECT last_modified
				  FROM $t_bugnote_table
				  WHERE bug_id='$c_bug_id'
				  ORDER BY last_modified DESC";
		$result = db_query( $query, 1 );
		$row = db_result( $result );

		if ( false === $row ) {
			return false;
		} else {
			return db_unixtimestamp( $row );
		}
	}

	# --------------------
	# return the timestamp for the most recent time at which a bugnote
	#  associated with the bug was modified and the total bugnote
	#  count in one db query
	function bug_get_bugnote_stats( $p_bug_id ) {
		$c_bug_id			= db_prepare_int( $p_bug_id );
		$t_bugnote_table	= config_get( 'mantis_bugnote_table' );

		$query = "SELECT last_modified
				  FROM $t_bugnote_table
				  WHERE bug_id='$c_bug_id'
				  ORDER BY last_modified DESC";
		$result = db_query( $query );
		$row = db_fetch_array( $result );

		if ( false === $row )
			return false;

		$t_stats['last_modified'] = db_unixtimestamp( $row['last_modified'] );
		$t_stats['count'] = db_num_rows( $result );

		return $t_stats;
	}

	# --------------------
	# Get array of attachments associated with the specified bug id.  The array will be
	# sorted in terms of date added (ASC).  The array will include the following fields:
	# id, title, diskfile, filename, filesize, file_type, date_added.
	function bug_get_attachments( $p_bug_id ) {
		if ( !file_can_view_bug_attachments( $p_bug_id ) ) {
	        return;
		}

		$c_bug_id = db_prepare_int( $p_bug_id );

		$t_bug_file_table = config_get( 'mantis_bug_file_table' );

		$query = "SELECT id, title, diskfile, filename, filesize, file_type, date_added
		                FROM $t_bug_file_table
		                WHERE bug_id='$c_bug_id'
		                ORDER BY date_added";
		$db_result = db_query( $query );
		$num_notes = db_num_rows( $db_result );

		$t_result = array();

		for ( $i = 0; $i < $num_notes; $i++ ) {
			$t_result[] = db_fetch_array( $db_result );
		}

		return $t_result;
	}

	#===================================
	# Data Modification
	#===================================

	# --------------------
	# set the value of a bug field
	function bug_set_field( $p_bug_id, $p_field_name, $p_status, $p_prepare = true ) {
		$c_bug_id			= db_prepare_int( $p_bug_id );
		$c_field_name		= db_prepare_string( $p_field_name );
		if( $p_prepare ) {
			$c_status		= '\'' . db_prepare_string( $p_status ) . '\''; #generic, unknown type
		} else {
			$c_status		=  $p_status; #generic, unknown type
		}

		$h_status = bug_get_field( $p_bug_id, $p_field_name );

		# return if status is already set
		if ( $c_status == $h_status ) {
			return true;
		}

		$t_bug_table = config_get( 'mantis_bug_table' );

		# Update fields
		$query = "UPDATE $t_bug_table
				  SET $c_field_name=$c_status
				  WHERE id='$c_bug_id'";
		db_query( $query );

		# updated the last_updated date
		bug_update_date( $p_bug_id );

		# log changes
		history_log_event_direct( $p_bug_id, $p_field_name, $h_status, $p_status );

		bug_clear_cache( $p_bug_id );

		return true;
	}

	# --------------------
	# assign the bug to the given user
	function bug_assign( $p_bug_id, $p_user_id, $p_bugnote_text='', $p_bugnote_private = false ) {
		$c_bug_id	= db_prepare_int( $p_bug_id );
		$c_user_id	= db_prepare_int( $p_user_id );

		if ( ( $c_user_id != NO_USER ) && !access_has_bug_level( config_get( 'handle_bug_threshold' ), $p_bug_id, $p_user_id ) ) {
		    trigger_error( ERROR_USER_DOES_NOT_HAVE_REQ_ACCESS );
		}

		# extract current information into history variables
		$h_status		= bug_get_field( $p_bug_id, 'status' );
		$h_handler_id	= bug_get_field( $p_bug_id, 'handler_id' );

		if ( ( ON == config_get( 'auto_set_status_to_assigned' ) ) &&
			 ( NO_USER != $p_user_id ) ) {
			$t_ass_val = config_get( 'bug_assigned_status' );
		} else {
			$t_ass_val = $h_status;
		}

		$t_bug_table = config_get( 'mantis_bug_table' );

		if ( ( $t_ass_val != $h_status ) || ( $p_user_id != $h_handler_id ) ) {

			# get user id
			$query = "UPDATE $t_bug_table
					  SET handler_id='$c_user_id', status='$t_ass_val'
					  WHERE id='$c_bug_id'";
			db_query( $query );

			# log changes
			history_log_event_direct( $c_bug_id, 'status', $h_status, $t_ass_val );
			history_log_event_direct( $c_bug_id, 'handler_id', $h_handler_id, $p_user_id );

			# Add bugnote if supplied
			if ( !is_blank( $p_bugnote_text ) ) {
				bugnote_add( $p_bug_id, $p_bugnote_text, $p_bugnote_private );
			}

			# updated the last_updated date
			bug_update_date( $p_bug_id );

			bug_clear_cache( $p_bug_id );

			# send assigned to email
			email_assign( $p_bug_id );
		}

		return true;
	}

	# --------------------
	# close the given bug
	function bug_close( $p_bug_id, $p_bugnote_text = '', $p_bugnote_private = false ) {
		$p_bugnote_text = trim( $p_bugnote_text );

		bug_set_field( $p_bug_id, 'status', CLOSED );

		# Add bugnote if supplied
		if ( !is_blank( $p_bugnote_text ) ) {
			bugnote_add( $p_bug_id, $p_bugnote_text, $p_bugnote_private );
		}

		email_close( $p_bug_id );

		# MASC RELATIONSHIP
		if ( ON == config_get( 'enable_relationship' ) ) {
			email_relationship_child_closed( $p_bug_id );
		}
		# MASC RELATIONSHIP

		return true;
	}

	# --------------------
	# resolve the given bug
	function bug_resolve( $p_bug_id, $p_resolution, $p_fixed_in_version = '', $p_bugnote_text = '', $p_duplicate_id = null, $p_handler_id = null, $p_bugnote_private = false ) {
		$p_bugnote_text = trim( $p_bugnote_text );

		if( !is_blank( $p_duplicate_id ) && ( $p_duplicate_id != 0 ) ) {
			# MASC RELATIONSHIP
			if ( $p_bug_id == $p_duplicate_id ) {
			    trigger_error( ERROR_BUG_DUPLICATE_SELF, ERROR );  # never returns
			}

			# the related bug exists...
			bug_ensure_exists( $p_duplicate_id );

			if( ON == config_get( 'enable_relationship' ) ) {
				# check if there is other relationship between the bugs...
				$t_id_relationship = relationship_same_type_exists( $p_bug_id, $p_duplicate_id, BUG_DUPLICATE );

				if ( $t_id_relationship == -1 ) {
					# the relationship type is already set. Nothing to do
				}
				else if ( $t_id_relationship > 0 ) {
					# there is already a relationship between them -> we have to update it and not to add a new one
					helper_ensure_confirmed( lang_get( 'replace_relationship_sure_msg' ), lang_get( 'replace_relationship_button' ) );

					# Update the relationship
					relationship_update( $t_id_relationship, $p_bug_id, $p_duplicate_id, BUG_DUPLICATE );

					# Add log line to the history (both bugs)
					history_log_event_special( $p_bug_id, BUG_REPLACE_RELATIONSHIP, BUG_DUPLICATE, $p_duplicate_id );
					history_log_event_special( $p_duplicate_id, BUG_REPLACE_RELATIONSHIP, BUG_HAS_DUPLICATE, $p_bug_id );
				}
				else {
					# Add the new relationship
					relationship_add( $p_bug_id, $p_duplicate_id, BUG_DUPLICATE );

					# Add log line to the history (both bugs)
					history_log_event_special( $p_bug_id, BUG_ADD_RELATIONSHIP, BUG_DUPLICATE, $p_duplicate_id );
					history_log_event_special( $p_duplicate_id, BUG_ADD_RELATIONSHIP, BUG_HAS_DUPLICATE, $p_bug_id );
				}
			}

			bug_set_field( $p_bug_id, 'duplicate_id', (int)$p_duplicate_id );
			# MASC RELATIONSHIP
		}

		bug_set_field( $p_bug_id, 'status', config_get( 'bug_resolved_status_threshold' ) );
		bug_set_field( $p_bug_id, 'fixed_in_version', $p_fixed_in_version );
		bug_set_field( $p_bug_id, 'resolution', (int)$p_resolution );

		# only set handler if specified explicitly or if bug was not assigned to a handler
		if ( null == $p_handler_id ) {
			if ( bug_get_field( $p_bug_id, 'handler_id' ) == 0 ) {
				$p_handler_id = auth_get_current_user_id();
				bug_set_field( $p_bug_id, 'handler_id', $p_handler_id );
			}
		} else {
			bug_set_field( $p_bug_id, 'handler_id', $p_handler_id );
		}

		# Add bugnote if supplied
		if ( !is_blank( $p_bugnote_text ) ) {
			bugnote_add( $p_bug_id, $p_bugnote_text, $p_bugnote_private );
		}

		email_resolved( $p_bug_id );

		# MASC RELATIONSHIP
		if ( ON == config_get( 'enable_relationship' ) ) {
			email_relationship_child_resolved( $p_bug_id );
		}
		# MASC RELATIONSHIP

		return true;
	}

	# --------------------
	# reopen the given bug
	function bug_reopen( $p_bug_id, $p_bugnote_text='', $p_bugnote_private = false ) {
		$p_bugnote_text = trim( $p_bugnote_text );

		bug_set_field( $p_bug_id, 'status', config_get( 'bug_reopen_status' ) );
		bug_set_field( $p_bug_id, 'resolution', config_get( 'bug_reopen_resolution' ) );

		# Add bugnote if supplied
		if ( !is_blank( $p_bugnote_text ) ) {
			bugnote_add( $p_bug_id, $p_bugnote_text, $p_bugnote_private );
		}

		email_reopen( $p_bug_id );

		return true;
	}

	# --------------------
	# updates the last_updated field
	function bug_update_date( $p_bug_id ) {
		$c_bug_id = db_prepare_int( $p_bug_id );

		$t_bug_table = config_get( 'mantis_bug_table' );

		$query = "UPDATE $t_bug_table
				  SET last_updated= " . db_now() . "
				  WHERE id='$c_bug_id'";
		db_query( $query );

		bug_clear_cache( $p_bug_id );

		return true;
	}

	# --------------------
	# enable monitoring of this bug for the user
	function bug_monitor( $p_bug_id, $p_user_id ) {
		$c_bug_id	= db_prepare_int( $p_bug_id );
		$c_user_id	= db_prepare_int( $p_user_id );

		# Make sure we aren't already monitoring this bug
		if ( user_is_monitoring_bug( $p_user_id, $p_bug_id ) ) {
			return true;
		}

		$t_bug_monitor_table = config_get( 'mantis_bug_monitor_table' );

		# Insert monitoring record
		$query ="INSERT ".
				"INTO $t_bug_monitor_table ".
				"( user_id, bug_id ) ".
				"VALUES ".
				"( '$c_user_id', '$c_bug_id' )";
		db_query( $query );

		# log new monitoring action
		history_log_event_special( $p_bug_id, BUG_MONITOR, $c_user_id );

		return true;
	}

	# --------------------
	# disable monitoring of this bug for the user
	# if $p_user_id = null, then bug is unmonitored for all users.
	function bug_unmonitor( $p_bug_id, $p_user_id ) {
		$c_bug_id	= db_prepare_int( $p_bug_id );
		$c_user_id	= db_prepare_int( $p_user_id );

		$t_bug_monitor_table = config_get( 'mantis_bug_monitor_table' );

		# Delete monitoring record
		$query ="DELETE ".
				"FROM $t_bug_monitor_table ".
				"WHERE bug_id = '$c_bug_id'";

		if ( $p_user_id !== null ) {
			$query .= " AND user_id = '$c_user_id'";
		}

		db_query( $query );

		# log new un-monitor action
		history_log_event_special( $p_bug_id, BUG_UNMONITOR, $p_user_id );

		return true;
	}

	#===================================
	# Other
	#===================================

	# --------------------
	# Pads the bug id with the appropriate number of zeros.
	function bug_format_id( $p_bug_id ) {
		$t_padding = config_get( 'display_bug_padding' );
		return( str_pad( $p_bug_id, $t_padding, '0', STR_PAD_LEFT ) );
	}

	# --------------------
	# Return a copy of the bug structure with all the instvars prepared for db insertion
	function bug_prepare_db( $p_bug_data ) {
		$t_bug_data = new BugData;
		$t_bug_data->project_id			= db_prepare_int( $p_bug_data->project_id );
		$t_bug_data->reporter_id		= db_prepare_int( $p_bug_data->reporter_id );
		$t_bug_data->handler_id			= db_prepare_int( $p_bug_data->handler_id );
		$t_bug_data->duplicate_id		= db_prepare_int( $p_bug_data->duplicate_id );
		$t_bug_data->priority			= db_prepare_int( $p_bug_data->priority );
		$t_bug_data->severity			= db_prepare_int( $p_bug_data->severity );
		$t_bug_data->reproducibility	= db_prepare_int( $p_bug_data->reproducibility );
		$t_bug_data->status				= db_prepare_int( $p_bug_data->status );
		$t_bug_data->resolution			= db_prepare_int( $p_bug_data->resolution );
		$t_bug_data->projection			= db_prepare_int( $p_bug_data->projection );
		$t_bug_data->category			= db_prepare_string( $p_bug_data->category );
		$t_bug_data->date_submitted		= db_prepare_string( $p_bug_data->date_submitted );
		$t_bug_data->last_updated		= db_prepare_string( $p_bug_data->last_updated );
		$t_bug_data->eta				= db_prepare_int( $p_bug_data->eta );
		$t_bug_data->os					= db_prepare_string( $p_bug_data->os );
		$t_bug_data->os_build			= db_prepare_string( $p_bug_data->os_build );
		$t_bug_data->platform			= db_prepare_string( $p_bug_data->platform );
		$t_bug_data->version			= db_prepare_string( $p_bug_data->version );
		$t_bug_data->build				= db_prepare_string( $p_bug_data->build );
		$t_bug_data->fixed_in_version	= db_prepare_string( $p_bug_data->fixed_in_version );
		$t_bug_data->view_state			= db_prepare_int( $p_bug_data->view_state );
		$t_bug_data->summary			= db_prepare_string( $p_bug_data->summary );
		$t_bug_data->sponsorship_total	= db_prepare_int( $p_bug_data->sponsorship_total );
		$t_bug_data->sticky				= db_prepare_int( $p_bug_data->sticky );

		$t_bug_data->description		= db_prepare_string( $p_bug_data->description );
		$t_bug_data->steps_to_reproduce	= db_prepare_string( $p_bug_data->steps_to_reproduce );
		$t_bug_data->additional_information	= db_prepare_string( $p_bug_data->additional_information );

		return $t_bug_data;
	}

	# --------------------
	# Return a copy of the bug structure with all the instvars prepared for editing
	#  in an HTML form
	function bug_prepare_edit( $p_bug_data ) {
		$p_bug_data->category			= string_attribute( $p_bug_data->category );
		$p_bug_data->date_submitted		= string_attribute( $p_bug_data->date_submitted );
		$p_bug_data->last_updated		= string_attribute( $p_bug_data->last_updated );
		$p_bug_data->os					= string_attribute( $p_bug_data->os );
		$p_bug_data->os_build			= string_attribute( $p_bug_data->os_build );
		$p_bug_data->platform			= string_attribute( $p_bug_data->platform );
		$p_bug_data->version			= string_attribute( $p_bug_data->version );
		$p_bug_data->build				= string_attribute( $p_bug_data->build );
		$p_bug_data->fixed_in_version	= string_attribute( $p_bug_data->fixed_in_version );
		$p_bug_data->summary			= string_attribute( $p_bug_data->summary );
		$p_bug_data->sponsorship_total	= string_attribute( $p_bug_data->sponsorship_total );
		$p_bug_data->sticky				= string_attribute( $p_bug_data->sticky );

		$p_bug_data->description		= string_textarea( $p_bug_data->description );
		$p_bug_data->steps_to_reproduce	= string_textarea( $p_bug_data->steps_to_reproduce );
		$p_bug_data->additional_information	= string_textarea( $p_bug_data->additional_information );

		return $p_bug_data;
	}

	# --------------------
	# Return a copy of the bug structure with all the instvars prepared for editing
	#  in an HTML form
	function bug_prepare_display( $p_bug_data ) {
		$p_bug_data->category			= string_display( $p_bug_data->category );
		$p_bug_data->date_submitted		= string_display( $p_bug_data->date_submitted );
		$p_bug_data->last_updated		= string_display( $p_bug_data->last_updated );
		$p_bug_data->os					= string_display( $p_bug_data->os );
		$p_bug_data->os_build			= string_display( $p_bug_data->os_build );
		$p_bug_data->platform			= string_display( $p_bug_data->platform );
		$p_bug_data->version			= string_display( $p_bug_data->version );
		$p_bug_data->build				= string_display( $p_bug_data->build );
		$p_bug_data->fixed_in_version	= string_display( $p_bug_data->fixed_in_version );
		$p_bug_data->summary			= string_display_links( $p_bug_data->summary );
		$p_bug_data->sponsorship_total	= string_display( $p_bug_data->sponsorship_total );
		$p_bug_data->sticky				= string_display( $p_bug_data->sticky );

		$p_bug_data->description		= string_display_links( $p_bug_data->description );
		$p_bug_data->steps_to_reproduce	= string_display_links( $p_bug_data->steps_to_reproduce );
		$p_bug_data->additional_information	= string_display_links( $p_bug_data->additional_information );

		return $p_bug_data;
	}
?>
bug_api.php (50,659 bytes)   

Activities