Blame Identity/Models/Html/Mantis/1.1.2-1.fc9/core/relationship_api.php

4c79b5
4c79b5
# Mantis - a php based bugtracking system
4c79b5
4c79b5
# Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
4c79b5
# Copyright (C) 2002 - 2007  Mantis Team   - mantisbt-dev@lists.sourceforge.net
4c79b5
4c79b5
# Mantis is free software: you can redistribute it and/or modify
4c79b5
# it under the terms of the GNU General Public License as published by
4c79b5
# the Free Software Foundation, either version 2 of the License, or
4c79b5
# (at your option) any later version.
4c79b5
#
4c79b5
# Mantis is distributed in the hope that it will be useful,
4c79b5
# but WITHOUT ANY WARRANTY; without even the implied warranty of
4c79b5
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
4c79b5
# GNU General Public License for more details.
4c79b5
#
4c79b5
# You should have received a copy of the GNU General Public License
4c79b5
# along with Mantis.  If not, see <http://www.gnu.org/licenses/>.
4c79b5
4c79b5
	# --------------------------------------------------------
4c79b5
	# $Id: relationship_api.php,v 1.45.2.1 2007-10-13 22:35:41 giallu Exp $
4c79b5
	# --------------------------------------------------------
4c79b5
4c79b5
	### Relationship API ###
4c79b5
4c79b5
	$t_core_dir = dirname( __FILE__ ).DIRECTORY_SEPARATOR;
4c79b5
4c79b5
	require_once( $t_core_dir . 'collapse_api.php' );
4c79b5
4c79b5
	# ======================================================================
4c79b5
	# Author: Marcello Scata' <marcelloscata at users.sourceforge.net> ITALY
4c79b5
	# ======================================================================
4c79b5
	# RELATIONSHIP DEFINITIONS
4c79b5
	# * Child/parent relationship:
4c79b5
	#    the child bug is generated by the parent bug or is directly linked with the parent with the following meaning
4c79b5
	#    the child bug has to be resolved before resolving the parent bug (the child bug "blocks" the parent bug)
4c79b5
	#    example: bug A is child bug of bug B. It means: A blocks B and B is blocked by A
4c79b5
	# * General relationship:
4c79b5
	#    two bugs related each other without any hierarchy dependance
4c79b5
	#    bugs A and B are related
4c79b5
	# * Duplicates:
4c79b5
	#    it's used to mark a bug as duplicate of an other bug already stored in the database
4c79b5
	#    bug A is marked as duplicate of B. It means: A duplicates B, B has duplicates
4c79b5
	#
4c79b5
	# Relations are always visible in the email body
4c79b5
	# --------------------------------------------------------------------
4c79b5
	# ADD NEW RELATIONSHIP
4c79b5
	# - Permission: user can update the source bug and at least view the destination bug
4c79b5
	# - Action recorded in the history of both the bugs
4c79b5
	# - Email notification sent to the users of both the bugs based based on the 'updated' bug notify type.
4c79b5
	# --------------------------------------------------------
4c79b5
	# DELETE RELATIONSHIP
4c79b5
	# - Permission: user can update the source bug and at least view the destination bug
4c79b5
	# - Action recorded in the history of both the bugs
4c79b5
	# - Email notification sent to the users of both the bugs based based on the 'updated' bug notify type.
4c79b5
	# --------------------------------------------------------
4c79b5
	# RESOLVE/CLOSE BUGS WITH BLOCKING CHILD BUGS STILL OPEN
4c79b5
	# Just a warning is print out on the form when an user attempts to resolve or close a bug with
4c79b5
	# related bugs in relation BUG_DEPENDANT still not resolved.
4c79b5
	# Anyway the user can force the resolving/closing action.
4c79b5
	# --------------------------------------------------------
4c79b5
	# EMAIL NOTIFICATION TO PARENT BUGS WHEN CHILDREN BUGS ARE RESOLVED/CLOSED
4c79b5
	# Every time a child bug is resolved or closed, an email notification is sent directly to all the handlers
4c79b5
	# of the parent bugs. The notification is sent to bugs not already marked as resolved or closed.
4c79b5
	# --------------------------------------------------------
4c79b5
	# ADD CHILD
4c79b5
	# This function gives the opportunity to generate a child bug. In details the function:
4c79b5
	# - create a new bug with the same basic information of the parent bug (plus the custom fields)
4c79b5
	# - copy all the attachment of the parent bug to the child
4c79b5
	# - not copy history, bugnotes, monitoring users
4c79b5
	# - set a relationship between parent and child
4c79b5
	# --------------------------------------------------------
4c79b5
4c79b5
	class BugRelationshipData {
4c79b5
		var $id;
4c79b5
		var $src_bug_id;
4c79b5
		var $src_project_id;
4c79b5
		var $dest_bug_id;
4c79b5
		var $dest_project_id;
4c79b5
		var $type;
4c79b5
	}
4c79b5
	
4c79b5
	$g_relationships = array();
4c79b5
	$g_relationships[ BUG_DEPENDANT ] = array(
4c79b5
		'#forward' => TRUE,
4c79b5
		'#complementary' => BUG_BLOCKS,
4c79b5
		'#description' => 'dependant_on',
4c79b5
		'#notify_added' => 'email_notification_title_for_action_dependant_on_relationship_added',
4c79b5
		'#notify_deleted' => 'email_notification_title_for_action_dependant_on_relationship_deleted',
4c79b5
		'#edge_style' => array ('color' => '#C00000','dir' => 'back'),
4c79b5
	);
4c79b5
	$g_relationships[ BUG_BLOCKS ] = array(
4c79b5
		'#forward' => FALSE,
4c79b5
		'#complementary' => BUG_DEPENDANT,
4c79b5
		'#description' => 'blocks',
4c79b5
		'#notify_added' => 'email_notification_title_for_action_blocks_relationship_added',
4c79b5
		'#notify_deleted' => 'email_notification_title_for_action_blocks_relationship_deleted',
4c79b5
		'#edge_style' => array ('color' => '#C00000','dir' => 'forward'),
4c79b5
	);
4c79b5
	$g_relationships[ BUG_DUPLICATE ] = array(
4c79b5
		'#forward' => TRUE,
4c79b5
		'#complementary' => BUG_HAS_DUPLICATE,
4c79b5
		'#description' => 'duplicate_of',
4c79b5
		'#notify_added' => 'email_notification_title_for_action_duplicate_of_relationship_added',
4c79b5
		'#notify_deleted' => 'email_notification_title_for_action_duplicate_of_relationship_deleted',
4c79b5
		'#edge_style' => array ('style' => 'dashed','color' => '#808080'),
4c79b5
	);
4c79b5
	$g_relationships[ BUG_HAS_DUPLICATE ] = array(
4c79b5
		'#forward' => FALSE,
4c79b5
		'#complementary' => BUG_DUPLICATE,
4c79b5
		'#description' => 'has_duplicate',
4c79b5
		'#notify_added' => 'email_notification_title_for_action_has_duplicate_relationship_added',
4c79b5
		'#notify_deleted' => 'email_notification_title_for_action_has_duplicate_relationship_deleted',
4c79b5
	);
4c79b5
	$g_relationships[ BUG_RELATED ] = array(
4c79b5
		'#forward' => TRUE,
4c79b5
		'#complementary' => BUG_RELATED,
4c79b5
		'#description' => 'related_to',
4c79b5
		'#notify_added' => 'email_notification_title_for_action_related_to_relationship_added',
4c79b5
		'#notify_deleted' => 'email_notification_title_for_action_related_to_relationship_deleted',
4c79b5
	);
4c79b5
4c79b5
	if ( file_exists( dirname( dirname( __FILE__ ) ).DIRECTORY_SEPARATOR.'custom_relationships_inc.php' ) ) {
4c79b5
		require_once( dirname( dirname( __FILE__ ) ).DIRECTORY_SEPARATOR.'custom_relationships_inc.php' );
4c79b5
	}    
4c79b5
4c79b5
4c79b5
	# --------------------
4c79b5
	# Return the complementary type of the provided relationship
4c79b5
	function relationship_get_complementary_type( $p_relationship_type ) {
4c79b5
		global $g_relationships;
4c79b5
		if ( !isset( $g_relationships[ $p_relationship_type ] ) ) {
4c79b5
			trigger_error( ERROR_GENERIC, ERROR );
4c79b5
		}
4c79b5
		return $g_relationships[ $p_relationship_type ][ '#complementary' ];
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	function relationship_add( $p_src_bug_id, $p_dest_bug_id, $p_relationship_type ) {
4c79b5
		$t_mantis_bug_relationship_table = config_get( 'mantis_bug_relationship_table' );
4c79b5
4c79b5
		global $g_relationships;
4c79b5
		if ( $g_relationships[ $p_relationship_type ][ '#forward' ] === FALSE ) {
4c79b5
			$c_src_bug_id = db_prepare_int( $p_dest_bug_id );
4c79b5
			$c_dest_bug_id = db_prepare_int( $p_src_bug_id );
4c79b5
			$c_relationship_type = db_prepare_int( relationship_get_complementary_type( $p_relationship_type ) );
4c79b5
		} else {
4c79b5
			$c_src_bug_id = db_prepare_int( $p_src_bug_id );
4c79b5
			$c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
4c79b5
			$c_relationship_type = db_prepare_int( $p_relationship_type );
4c79b5
		}
4c79b5
4c79b5
		$query = "INSERT INTO $t_mantis_bug_relationship_table
4c79b5
				( source_bug_id, destination_bug_id, relationship_type )
4c79b5
				VALUES
4c79b5
				( '$c_src_bug_id', '$c_dest_bug_id', '$c_relationship_type' )";
4c79b5
		$result = db_query( $query );
4c79b5
		$t_relationship = db_fetch_array( $result );
4c79b5
4c79b5
		$t_bug_relationship_data = new BugRelationshipData;
4c79b5
		$t_bug_relationship_data->id = $t_relationship['id'];
4c79b5
		$t_bug_relationship_data->src_bug_id = $t_relationship['source_bug_id'];
4c79b5
		$t_bug_relationship_data->dest_bug_id = $t_relationship['destination_bug_id'];
4c79b5
		$t_bug_relationship_data->type = $t_relationship['relationship_type'];
4c79b5
4c79b5
		return $t_bug_relationship_data;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	function relationship_update( $p_relationship_id, $p_src_bug_id, $p_dest_bug_id, $p_relationship_type ) {
4c79b5
		$t_mantis_bug_relationship_table = config_get( 'mantis_bug_relationship_table' );
4c79b5
4c79b5
		global $g_relationships;
4c79b5
		if ( $g_relationships[ $p_relationship_type ][ '#forward' ] === FALSE ) {
4c79b5
			$c_src_bug_id = db_prepare_int( $p_dest_bug_id );
4c79b5
			$c_dest_bug_id = db_prepare_int( $p_src_bug_id );
4c79b5
			$c_relationship_type = db_prepare_int( relationship_get_complementary_type( $p_relationship_type ) );
4c79b5
		} else {
4c79b5
			$c_src_bug_id = db_prepare_int( $p_src_bug_id );
4c79b5
			$c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
4c79b5
			$c_relationship_type = db_prepare_int( $p_relationship_type );
4c79b5
		}
4c79b5
		$c_relationship_id = db_prepare_int( $p_relationship_id );
4c79b5
4c79b5
		$query = "UPDATE $t_mantis_bug_relationship_table
4c79b5
				SET source_bug_id='$c_src_bug_id',
4c79b5
					destination_bug_id='$c_dest_bug_id',
4c79b5
					relationship_type='$c_relationship_type'
4c79b5
				WHERE id='$c_relationship_id'";
4c79b5
		$result = db_query( $query );
4c79b5
		$t_relationship = db_fetch_array( $result );
4c79b5
4c79b5
		$t_bug_relationship_data = new BugRelationshipData;
4c79b5
		$t_bug_relationship_data->id = $t_relationship['id'];
4c79b5
		$t_bug_relationship_data->src_bug_id = $t_relationship['source_bug_id'];
4c79b5
		$t_bug_relationship_data->dest_bug_id = $t_relationship['destination_bug_id'];
4c79b5
		$t_bug_relationship_data->type = $t_relationship['relationship_type'];
4c79b5
4c79b5
		return $t_bug_relationship_data;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	function relationship_delete( $p_relationship_id ) {
4c79b5
		$c_relationship_id = db_prepare_int( $p_relationship_id );
4c79b5
4c79b5
		$t_mantis_bug_relationship_table = config_get( 'mantis_bug_relationship_table' );
4c79b5
4c79b5
		$query = "DELETE FROM $t_mantis_bug_relationship_table
4c79b5
				WHERE id='$c_relationship_id'";
4c79b5
		$result = db_query( $query );
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# Deletes all the relationships related to a specific bug (both source and destination)
4c79b5
	function relationship_delete_all( $p_bug_id ) {
4c79b5
		$c_bug_id = db_prepare_int( $p_bug_id );
4c79b5
4c79b5
		$t_mantis_bug_relationship_table = config_get( 'mantis_bug_relationship_table' );
4c79b5
4c79b5
		$query = "DELETE FROM $t_mantis_bug_relationship_table
4c79b5
				WHERE source_bug_id='$c_bug_id' OR
4c79b5
				destination_bug_id='$c_bug_id'";
4c79b5
		$result = db_query( $query );
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# copy all the relationships related to a specific bug to a new bug
4c79b5
	function relationship_copy_all( $p_bug_id, $p_new_bug_id ) {
4c79b5
		$c_bug_id = db_prepare_int( $p_bug_id );
4c79b5
		$c_new_bug_id = db_prepare_int( $p_new_bug_id );
4c79b5
4c79b5
		$t_mantis_bug_relationship_table = config_get( 'mantis_bug_relationship_table' );
4c79b5
4c79b5
		$t_relationship = relationship_get_all_src( $p_bug_id );
4c79b5
		$t_relationship_count = count( $t_relationship );
4c79b5
		for ( $i = 0 ; $i < $t_relationship_count ; $i++ ) {
4c79b5
			relationship_add($p_new_bug_id, $t_relationship[$i]->dest_bug_id, $t_relationship[$i]->type);
4c79b5
		}
4c79b5
4c79b5
		$t_relationship = relationship_get_all_dest( $p_bug_id );
4c79b5
		$t_relationship_count = count( $t_relationship );
4c79b5
		for ( $i = 0 ; $i < $t_relationship_count ; $i++ ) {
4c79b5
			relationship_add($t_relationship[$i]->src_bug_id, $p_new_bug_id, $t_relationship[$i]->type);
4c79b5
		}
4c79b5
4c79b5
		return;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	function relationship_get( $p_relationship_id ) {
4c79b5
		$c_relationship_id = db_prepare_int( $p_relationship_id );
4c79b5
4c79b5
		$t_mantis_bug_relationship_table = config_get( 'mantis_bug_relationship_table' );
4c79b5
4c79b5
		$query = "SELECT *
4c79b5
				FROM $t_mantis_bug_relationship_table
4c79b5
				WHERE id='$c_relationship_id'";
4c79b5
		$result = db_query( $query, 1 );
4c79b5
4c79b5
		$t_relationship_count = db_num_rows( $result );
4c79b5
4c79b5
		if ( $t_relationship_count == 1 ) {
4c79b5
			$t_relationship = db_fetch_array( $result );
4c79b5
4c79b5
			$t_bug_relationship_data = new BugRelationshipData;
4c79b5
			$t_bug_relationship_data->id = $t_relationship['id'];
4c79b5
			$t_bug_relationship_data->src_bug_id = $t_relationship['source_bug_id'];
4c79b5
			$t_bug_relationship_data->dest_bug_id = $t_relationship['destination_bug_id'];
4c79b5
			$t_bug_relationship_data->type = $t_relationship['relationship_type'];
4c79b5
		}
4c79b5
		else {
4c79b5
			$t_bug_relationship_data = null;
4c79b5
		}
4c79b5
4c79b5
		return $t_bug_relationship_data;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	function relationship_get_all_src( $p_src_bug_id ) {
4c79b5
		$c_src_bug_id = db_prepare_int( $p_src_bug_id );
4c79b5
4c79b5
		$t_mantis_bug_relationship_table = config_get( 'mantis_bug_relationship_table' );
4c79b5
		$t_mantis_bug_table = config_get( 'mantis_bug_table' );
4c79b5
4c79b5
		$query = "SELECT $t_mantis_bug_relationship_table.id, $t_mantis_bug_relationship_table.relationship_type,
4c79b5
				$t_mantis_bug_relationship_table.source_bug_id, $t_mantis_bug_relationship_table.destination_bug_id,
4c79b5
				$t_mantis_bug_table.project_id
4c79b5
				FROM $t_mantis_bug_relationship_table
4c79b5
				INNER JOIN $t_mantis_bug_table ON $t_mantis_bug_relationship_table.destination_bug_id = $t_mantis_bug_table.id
4c79b5
				WHERE source_bug_id='$c_src_bug_id'
4c79b5
				ORDER BY relationship_type, $t_mantis_bug_relationship_table.id";
4c79b5
		$result = db_query( $query );
4c79b5
4c79b5
		$t_src_project_id = bug_get_field( $p_src_bug_id, 'project_id' );
4c79b5
4c79b5
		$t_bug_relationship_data = array( new BugRelationshipData );
4c79b5
		$t_relationship_count = db_num_rows( $result );
4c79b5
		for ( $i = 0 ; $i < $t_relationship_count ; $i++ ) {
4c79b5
			$row = db_fetch_array( $result );
4c79b5
			$t_bug_relationship_data[$i]->id = $row['id'];
4c79b5
			$t_bug_relationship_data[$i]->src_bug_id = $row['source_bug_id'];
4c79b5
			$t_bug_relationship_data[$i]->src_project_id = $t_src_project_id;
4c79b5
			$t_bug_relationship_data[$i]->dest_bug_id = $row['destination_bug_id'];
4c79b5
			$t_bug_relationship_data[$i]->dest_project_id = $row['project_id'];
4c79b5
			$t_bug_relationship_data[$i]->type = $row['relationship_type'];
4c79b5
		}
4c79b5
		unset( $t_bug_relationship_data[$t_relationship_count] );
4c79b5
4c79b5
		return $t_bug_relationship_data;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	function relationship_get_all_dest( $p_dest_bug_id ) {
4c79b5
		$c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
4c79b5
4c79b5
		$t_mantis_bug_relationship_table = config_get( 'mantis_bug_relationship_table' );
4c79b5
		$t_mantis_bug_table = config_get( 'mantis_bug_table' );
4c79b5
4c79b5
		$query = "SELECT $t_mantis_bug_relationship_table.id, $t_mantis_bug_relationship_table.relationship_type,
4c79b5
				$t_mantis_bug_relationship_table.source_bug_id, $t_mantis_bug_relationship_table.destination_bug_id,
4c79b5
				$t_mantis_bug_table.project_id
4c79b5
				FROM $t_mantis_bug_relationship_table
4c79b5
				INNER JOIN $t_mantis_bug_table ON $t_mantis_bug_relationship_table.source_bug_id = $t_mantis_bug_table.id
4c79b5
				WHERE destination_bug_id='$c_dest_bug_id'
4c79b5
				ORDER BY relationship_type, $t_mantis_bug_relationship_table.id";
4c79b5
		$result = db_query( $query );
4c79b5
4c79b5
		$t_dest_project_id = bug_get_field( $p_dest_bug_id, 'project_id' );
4c79b5
4c79b5
		$t_bug_relationship_data = array( new BugRelationshipData );
4c79b5
		$t_relationship_count = db_num_rows( $result );
4c79b5
		for ( $i = 0 ; $i < $t_relationship_count ; $i++ ) {
4c79b5
			$row = db_fetch_array( $result );
4c79b5
			$t_bug_relationship_data[$i]->id = $row['id'];
4c79b5
			$t_bug_relationship_data[$i]->src_bug_id = $row['source_bug_id'];
4c79b5
			$t_bug_relationship_data[$i]->src_project_id = $row['project_id'];
4c79b5
			$t_bug_relationship_data[$i]->dest_bug_id = $row['destination_bug_id'];
4c79b5
			$t_bug_relationship_data[$i]->dest_project_id = $t_dest_project_id;
4c79b5
			$t_bug_relationship_data[$i]->type = $row['relationship_type'];
4c79b5
		}
4c79b5
		unset( $t_bug_relationship_data[$t_relationship_count] );
4c79b5
4c79b5
		return $t_bug_relationship_data;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	function relationship_get_all( $p_bug_id, &$p_is_different_projects ) {
4c79b5
		$t_src = relationship_get_all_src( $p_bug_id );
4c79b5
		$t_dest = relationship_get_all_dest( $p_bug_id );
4c79b5
		$t_all = array_merge( $t_src, $t_dest );
4c79b5
4c79b5
		$p_is_different_projects = false;
4c79b5
		for ( $i = 0 ; $i < count( $t_all ) ; $i++ ) {
4c79b5
			$p_is_different_projects |= ( $t_all[$i]->src_project_id != $t_all[$i]->dest_project_id );
4c79b5
		}
4c79b5
		return $t_all;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# convert the relationship type in the type from the src/dest issues point of view
4c79b5
	# i.e. issue A  is dependent (BUG_DEPENDANT) on issue B
4c79b5
	#      passing B, A and this relationship as parameters, the return value will be BUG_BLOCKS
4c79b5
	#      (issue B blocks issue A)
4c79b5
	# return the relationship type using the information in the p_rel structure but src/dest issues as indicated
4c79b5
	function relationship_conv_type_to_this_src_dest( $p_src_bug_id, $p_dest_bug_id, $p_rel ) {
4c79b5
		if ( $p_rel->src_bug_id == $p_src_bug_id && $p_rel->dest_bug_id == $p_dest_bug_id ) {
4c79b5
			return $p_rel->type;
4c79b5
		}
4c79b5
		else if ( $p_rel->src_bug_id == $p_dest_bug_id && $p_rel->dest_bug_id == $p_src_bug_id ) {
4c79b5
			return relationship_get_complementary_type( $p_rel->type );
4c79b5
		}
4c79b5
		else {
4c79b5
			trigger_error( ERROR_RELATIONSHIP_NOT_FOUND, ERROR );
4c79b5
		}
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# check if there is a relationship between two bugs
4c79b5
	# return id if found 0 otherwise
4c79b5
	function relationship_exists( $p_src_bug_id, $p_dest_bug_id ) {
4c79b5
		$c_src_bug_id = db_prepare_int( $p_src_bug_id );
4c79b5
		$c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
4c79b5
4c79b5
		$t_mantis_bug_relationship_table = config_get( 'mantis_bug_relationship_table' );
4c79b5
4c79b5
		$t_query = "SELECT *
4c79b5
				FROM $t_mantis_bug_relationship_table
4c79b5
				WHERE
4c79b5
				(source_bug_id='$c_src_bug_id'
4c79b5
				AND destination_bug_id='$c_dest_bug_id')
4c79b5
				OR
4c79b5
				(source_bug_id='$c_dest_bug_id'
4c79b5
				AND destination_bug_id='$c_src_bug_id')";
4c79b5
		$result = db_query( $t_query, 1 );
4c79b5
4c79b5
		$t_relationship_count = db_num_rows( $result );
4c79b5
4c79b5
		if ( $t_relationship_count == 1 ) {
4c79b5
			# return the first id
4c79b5
			$row = db_fetch_array( $result );
4c79b5
			return $row['id'];
4c79b5
		}
4c79b5
		else {
4c79b5
			# no relationship found
4c79b5
			return 0;
4c79b5
		}
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# check if there is a relationship between two bugs
4c79b5
	# return:
4c79b5
	#   0 if the relationship is not found
4c79b5
	#  -1 if the relationship is found and it's of the same type $p_rel_type
4c79b5
	#  id if the relationship is found and it's of a different time (this means it can be replaced with the new type $p_rel_type
4c79b5
	function relationship_same_type_exists( $p_src_bug_id, $p_dest_bug_id, $p_rel_type ) {
4c79b5
		# Check if there is already a relationship set between them
4c79b5
		$t_id_relationship = relationship_exists( $p_src_bug_id, $p_dest_bug_id );
4c79b5
4c79b5
		if ( $t_id_relationship > 0 ) {
4c79b5
			# if there is...
4c79b5
4c79b5
			# get all the relationship info
4c79b5
			$t_relationship = relationship_get( $t_id_relationship );
4c79b5
4c79b5
			if ( $t_relationship->src_bug_id == $p_src_bug_id && $t_relationship->dest_bug_id == $p_dest_bug_id ) {
4c79b5
				if( $t_relationship->type == $p_rel_type ) $t_id_relationship = -1;
4c79b5
			}
4c79b5
			else {
4c79b5
				if( $t_relationship->type == relationship_get_complementary_type( $p_rel_type ) ) $t_id_relationship = -1;
4c79b5
			}
4c79b5
		}
4c79b5
		return $t_id_relationship;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# retrieve the linked bug id of the relationship: provide src -> return dest; provide dest -> return src
4c79b5
	function relationship_get_linked_bug_id( $p_relationship_id, $p_bug_id ) {
4c79b5
4c79b5
		$t_bug_relationship_data = relationship_get( $p_relationship_id );
4c79b5
4c79b5
		if ( $t_bug_relationship_data->src_bug_id == $p_bug_id ) {
4c79b5
			return $t_bug_relationship_data->dest_bug_id;
4c79b5
		}
4c79b5
4c79b5
		if ( $t_bug_relationship_data->dest_bug_id == $p_bug_id ) {
4c79b5
			return $t_bug_relationship_data->src_bug_id;
4c79b5
		}
4c79b5
4c79b5
		trigger_error( ERROR_RELATIONSHIP_NOT_FOUND, ERROR );
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# get class description of a relationship (source side)
4c79b5
	function relationship_get_description_src_side( $p_relationship_type ) {
4c79b5
		global $g_relationships;
4c79b5
		if ( !isset( $g_relationships[ $p_relationship_type ] ) ) {
4c79b5
			trigger_error( ERROR_RELATIONSHIP_NOT_FOUND, ERROR );
4c79b5
		}
4c79b5
		return lang_get( $g_relationships[ $p_relationship_type ][ '#description' ] ); 
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# get class description of a relationship (destination side)
4c79b5
	function relationship_get_description_dest_side( $p_relationship_type ) {
4c79b5
		global $g_relationships;
4c79b5
		if ( !isset( $g_relationships[ $p_relationship_type ] ) ||
4c79b5
		     !isset( $g_relationships[ $g_relationships[ $p_relationship_type ][ '#complementary' ] ] ) ) {
4c79b5
			trigger_error( ERROR_RELATIONSHIP_NOT_FOUND, ERROR );
4c79b5
		}
4c79b5
		return lang_get( $g_relationships[ $g_relationships[ $p_relationship_type ][ '#complementary' ] ][ '#description' ] ); 
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# get class description of a relationship as it's stored in the history
4c79b5
	function relationship_get_description_for_history( $p_relationship_code ) {
4c79b5
		return relationship_get_description_src_side( $p_relationship_code );
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# return false if there are child bugs not resolved/closed
4c79b5
	# N.B. we don't check if the parent bug is read-only. This is because the answer of this function is indepent from
4c79b5
	# the state of the parent bug itself.
4c79b5
	function relationship_can_resolve_bug( $p_bug_id ) {
4c79b5
4c79b5
		# retrieve all the relationships in which the bug is the source bug
4c79b5
		$t_relationship = relationship_get_all_src( $p_bug_id );
4c79b5
		$t_relationship_count = count( $t_relationship );
4c79b5
		if ( $t_relationship_count == 0 ) {
4c79b5
			return true;
4c79b5
		}
4c79b5
4c79b5
		for ( $i = 0 ; $i < $t_relationship_count ; $i++ ) {
4c79b5
			# verify if each bug in relation BUG_DEPENDANT is already marked as resolved
4c79b5
			if ( $t_relationship[$i]->type == BUG_DEPENDANT ) {
4c79b5
				$t_dest_bug_id = $t_relationship[$i]->dest_bug_id;
4c79b5
				$t_status = bug_get_field( $t_dest_bug_id, 'status' );
4c79b5
				if ( $t_status < config_get( 'bug_resolved_status_threshold' ) ) {
4c79b5
					# the bug is NOT marked as resolved/closed
4c79b5
					return false;
4c79b5
				}
4c79b5
			}
4c79b5
		}
4c79b5
4c79b5
		return true;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# return formatted string with all the details on the requested relationship
4c79b5
	function relationship_get_details( $p_bug_id, $p_relationship, $p_html = false, $p_html_preview = false, $p_show_project = false ) {
4c79b5
		$t_summary_wrap_at = strlen( config_get( 'email_separator2' ) ) - 28;
4c79b5
		$t_icon_path = config_get( 'icon_path' );
4c79b5
4c79b5
		$p_user_id = auth_get_current_user_id();
4c79b5
4c79b5
		if ( $p_bug_id == $p_relationship->src_bug_id ) {
4c79b5
			# root bug is in the src side, related bug in the dest side
4c79b5
			$t_related_bug_id = $p_relationship->dest_bug_id;
4c79b5
			$t_related_project_name = project_get_name( $p_relationship->dest_project_id );
4c79b5
			$t_relationship_descr = relationship_get_description_src_side( $p_relationship->type );
4c79b5
		}
4c79b5
		else {
4c79b5
			# root bug is in the dest side, related bug in the src side
4c79b5
			$t_related_bug_id = $p_relationship->src_bug_id;
4c79b5
			$t_related_project_name = project_get_name( $p_relationship->src_project_id );
4c79b5
			$t_relationship_descr = relationship_get_description_dest_side( $p_relationship->type );
4c79b5
		}
4c79b5
4c79b5
		# related bug not existing...
4c79b5
		if ( !bug_exists( $t_related_bug_id ) ) {
4c79b5
			return '';
4c79b5
		}
4c79b5
4c79b5
		# user can access to the related bug at least as a viewer
4c79b5
		if ( !access_has_bug_level( VIEWER, $t_related_bug_id ) ) {
4c79b5
			return '';
4c79b5
		}
4c79b5
4c79b5
		if ( $p_html_preview == false ) {
4c79b5
			$t_td = '';
4c79b5
		}
4c79b5
		else {
4c79b5
			$t_td = '';
4c79b5
		}
4c79b5
4c79b5
		# get the information from the related bug and prepare the link
4c79b5
		$t_bug = bug_prepare_display( bug_get( $t_related_bug_id, true ) );
4c79b5
		$t_status = string_attribute( get_enum_element( 'status', $t_bug->status ) );
4c79b5
		$t_resolution = string_attribute( get_enum_element( 'resolution', $t_bug->resolution ) );
4c79b5
4c79b5
		$t_relationship_info_html = $t_td . string_no_break( $t_relationship_descr ) . ' ';
4c79b5
		if ( $p_html_preview == false ) {
4c79b5
			$t_relationship_info_html .= '' . bug_format_id( $t_related_bug_id ) . '';
4c79b5
			$t_relationship_info_html .= '' . $t_status . '';
4c79b5
		}
4c79b5
		else {
4c79b5
			$t_relationship_info_html .= $t_td . bug_format_id( $t_related_bug_id ) . '';
4c79b5
			$t_relationship_info_html .= $t_td . $t_status . ' ';
4c79b5
		}
4c79b5
4c79b5
		$t_relationship_info_text = str_pad( $t_relationship_descr, 20 );
4c79b5
		$t_relationship_info_text .= str_pad( bug_format_id( $t_related_bug_id ), 8 );
4c79b5
4c79b5
		# get the handler name of the related bug
4c79b5
		$t_relationship_info_html .= $t_td;
4c79b5
		if ( $t_bug->handler_id > 0 )  {
4c79b5
			$t_relationship_info_html .= string_no_break( prepare_user_name( $t_bug->handler_id ) );
4c79b5
		}
4c79b5
		$t_relationship_info_html .= ' ';
4c79b5
4c79b5
		# add project name
4c79b5
		if( $p_show_project ) {
4c79b5
			$t_relationship_info_html .= $t_td . $t_related_project_name . ' ';
4c79b5
		}
4c79b5
4c79b5
		# add summary
4c79b5
		$t_relationship_info_html .= $t_td . $t_bug->summary;
4c79b5
		if ( VS_PRIVATE == $t_bug->view_state ) {
4c79b5
			$t_relationship_info_html .= sprintf( ' (%s)', $t_icon_path . 'protected.gif', lang_get( 'private' ), lang_get( 'private' ) );
4c79b5
		}
4c79b5
		if( strlen( $t_bug->summary ) <= $t_summary_wrap_at ) {
4c79b5
			$t_relationship_info_text .= $t_bug->summary;
4c79b5
		}
4c79b5
		else {
4c79b5
			$t_relationship_info_text .= substr( $t_bug->summary, 0, $t_summary_wrap_at - 3 ) . '...';
4c79b5
		}
4c79b5
4c79b5
		# add delete link if bug not read only and user has access level
4c79b5
		if ( !bug_is_readonly( $p_bug_id ) && !current_user_is_anonymous() && ( $p_html_preview == false ) ) {
4c79b5
			if ( access_has_bug_level( config_get( 'update_bug_threshold' ), $p_bug_id ) ) {
4c79b5
				$t_relationship_info_html .= " [id\">" . lang_get('delete_link') . ']';
4c79b5
			}
4c79b5
		}
4c79b5
4c79b5
		$t_relationship_info_html .= ' ';
4c79b5
		$t_relationship_info_text .= "\n";
4c79b5
4c79b5
		if ( $p_html_preview == false ) {
4c79b5
			$t_relationship_info_html = '' . $t_relationship_info_html . '' . "\n";
4c79b5
		}
4c79b5
		else {
4c79b5
			$t_relationship_info_html = '' . $t_relationship_info_html . '';
4c79b5
		}
4c79b5
4c79b5
		if ( $p_html == true ) {
4c79b5
			return $t_relationship_info_html;
4c79b5
		}
4c79b5
		else {
4c79b5
			return $t_relationship_info_text;
4c79b5
		}
4c79b5
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# print ALL the RELATIONSHIPS OF A SPECIFIC BUG
4c79b5
	function relationship_get_summary_html( $p_bug_id ) {
4c79b5
		$t_summary = '';
4c79b5
		$t_show_project = false;
4c79b5
4c79b5
		$t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
4c79b5
		$t_relationship_all_count = count( $t_relationship_all );
4c79b5
4c79b5
		#prepare the relationships table
4c79b5
		for ( $i = 0 ; $i < $t_relationship_all_count ; $i++ ) {
4c79b5
			$t_summary .= relationship_get_details ( $p_bug_id, $t_relationship_all[$i], true, false, $t_show_project );
4c79b5
		}
4c79b5
4c79b5
		if ( !is_blank( $t_summary ) ) {
4c79b5
			if ( relationship_can_resolve_bug( $p_bug_id ) == false ) {
4c79b5
				$t_summary .= '' . lang_get( 'relationship_warning_blocking_bugs_not_resolved' ) . '';
4c79b5
			}
4c79b5
			$t_summary = '' . $t_summary . '
';
4c79b5
		}
4c79b5
4c79b5
		return $t_summary;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# print ALL the RELATIONSHIPS OF A SPECIFIC BUG
4c79b5
	function relationship_get_summary_html_preview( $p_bug_id ) {
4c79b5
		$t_summary = '';
4c79b5
		$t_show_project = false;
4c79b5
4c79b5
		$t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
4c79b5
		$t_relationship_all_count = count( $t_relationship_all );
4c79b5
4c79b5
		#prepare the relationships table
4c79b5
		for ( $i = 0 ; $i < $t_relationship_all_count ; $i++ ) {
4c79b5
			$t_summary .= relationship_get_details ( $p_bug_id, $t_relationship_all[$i], true, true, $t_show_project );
4c79b5
		}
4c79b5
4c79b5
		if ( !is_blank( $t_summary ) ) {
4c79b5
			if ( relationship_can_resolve_bug( $p_bug_id ) == false ) {
4c79b5
				$t_summary .= '' . lang_get( 'relationship_warning_blocking_bugs_not_resolved' ) . '';
4c79b5
			}
4c79b5
			$t_summary = '' . $t_summary . '
';
4c79b5
		}
4c79b5
4c79b5
		return $t_summary;
4c79b5
	}
4c79b5
4c79b5
	# --------------------
4c79b5
	# print ALL the RELATIONSHIPS OF A SPECIFIC BUG in text format (used by email_api.php
4c79b5
	function relationship_get_summary_text( $p_bug_id ) {
4c79b5
		$t_email_separator1 = config_get( 'email_separator1' );
4c79b5
		$t_email_separator2 = config_get( 'email_separator2' );
4c79b5
4c79b5
		$t_summary = "";
4c79b5
		$t_show_project = false;
4c79b5
4c79b5
		$t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
4c79b5
		$t_relationship_all_count = count( $t_relationship_all );
4c79b5
4c79b5
		#prepare the relationships table
4c79b5
		for ( $i = 0 ; $i < $t_relationship_all_count ; $i++ ) {
4c79b5
			$t_summary .= relationship_get_details ( $p_bug_id, $t_relationship_all[$i], false );
4c79b5
		}
4c79b5
4c79b5
		if ($t_summary != "") {
4c79b5
			$t_summary =
4c79b5
				$t_email_separator1 . "\n" .
4c79b5
				str_pad( lang_get( 'bug_relationships' ), 20 ) .
4c79b5
				str_pad( lang_get( 'id' ), 8 ) .
4c79b5
				lang_get( 'summary' ) . "\n" .
4c79b5
				$t_email_separator2 . "\n" . $t_summary;
4c79b5
		}
4c79b5
4c79b5
		return $t_summary;
4c79b5
	}
4c79b5
4c79b5
 	# --------------------
4c79b5
 	# print HTML relationship listbox
4c79b5
	function relationship_list_box( $p_default_rel_type = -1, $p_select_name = "rel_type", $p_include_any = false, $p_include_none = false ) {
4c79b5
		global $g_relationships;
4c79b5
?>
4c79b5
<select name="<?php echo $p_select_name ?>">
4c79b5
4c79b5
<option value="-1" <?php echo ( $p_default_rel_type == -1 ? ' selected="selected"' : '' ) ?>>[]</option>
4c79b5
4c79b5
    }
4c79b5
4c79b5
	if ( $p_include_none ) { ?>
4c79b5
<option value="-2" <?php echo ( $p_default_rel_type == -2 ? ' selected="selected"' : '' ) ?>>[]</option>
4c79b5
4c79b5
    }
4c79b5
4c79b5
	foreach ( $g_relationships as $type => $relationship ) { 
4c79b5
?>
4c79b5
<option value="<?php echo $type ?>"<?php echo ( $p_default_rel_type == $type ? ' selected="selected"' : '' ) ?>></option>
4c79b5
4c79b5
</select>
4c79b5
4c79b5
	}
4c79b5
4c79b5
 	# --------------------
4c79b5
 	# print HTML relationship form
4c79b5
	function relationship_view_box( $p_bug_id ) {
4c79b5
?>
4c79b5

4c79b5
4c79b5
4c79b5
4c79b5
4c79b5
	
4c79b5
		
4c79b5
			collapse_icon( 'relationships' );
4c79b5
			echo lang_get( 'bug_relationships' );
4c79b5
			if ( ON == config_get( 'relationship_graph_enable' ) ) {
4c79b5
		?>
4c79b5
		
4c79b5
		
4c79b5
		
4c79b5
			}
4c79b5
		?>
4c79b5
	
4c79b5
4c79b5
4c79b5
		# bug not read-only and user authenticated
4c79b5
		if ( !bug_is_readonly( $p_bug_id ) ) {
4c79b5
4c79b5
			# user access level at least updater
4c79b5
			if ( access_has_bug_level( config_get( 'update_bug_threshold' ), $p_bug_id ) ) {
4c79b5
?>
4c79b5
4c79b5
	
4c79b5
	
4c79b5
		<form method="post" action="bug_relationship_add.php">
4c79b5
		<input type="hidden" name="src_bug_id" value="<?php echo $p_bug_id ?>" size="4" />
4c79b5
		
4c79b5
		<input type="text" name="dest_bug_id" value="" />
4c79b5
		<input type="submit" name="add_relationship" class="button" value="<?php echo lang_get( 'add_new_relationship_button' ) ?>" />
4c79b5
		</form>
4c79b5
	
4c79b5
4c79b5
			}
4c79b5
		}
4c79b5
?>
4c79b5
4c79b5
	
4c79b5
4c79b5
4c79b5
4c79b5
4c79b5
4c79b5
4c79b5
	
4c79b5
		
4c79b5
			collapse_icon( 'relationships' );
4c79b5
			echo lang_get( 'bug_relationships' );
4c79b5
		?>
4c79b5
	
4c79b5
4c79b5
4c79b5
4c79b5
4c79b5
		collapse_end( 'relationships' );
4c79b5
	}
4c79b5
?>