Current File : /home/escuelai/public_html/mantis/core/relationship_api.php |
<?php
# MantisBT - A PHP based bugtracking system
# MantisBT is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# MantisBT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with MantisBT. If not, see <http://www.gnu.org/licenses/>.
/**
* Relationship API
*
* RELATIONSHIP DEFINITIONS
* * Child/parent relationship:
* the child bug is generated by the parent bug or is directly linked with the parent with the following meaning
* the child bug has to be resolved before resolving the parent bug (the child bug "blocks" the parent bug)
* example: bug A is child bug of bug B. It means: A blocks B and B is blocked by A
* * General relationship:
* two bugs related each other without any hierarchy dependance
* bugs A and B are related
* * Duplicates:
* it's used to mark a bug as duplicate of an other bug already stored in the database
* bug A is marked as duplicate of B. It means: A duplicates B, B has duplicates
*
* Relations are always visible in the email body
* --------------------------------------------------------------------
* ADD NEW RELATIONSHIP
* - Permission: user can update the source bug and at least view the destination bug
* - Action recorded in the history of both the bugs
* - Email notification sent to the users of both the bugs based based on the 'updated' bug notify type.
* --------------------------------------------------------
* DELETE RELATIONSHIP
* - Permission: user can update the source bug and at least view the destination bug
* - Action recorded in the history of both the bugs
* - Email notification sent to the users of both the bugs based based on the 'updated' bug notify type.
* --------------------------------------------------------
* RESOLVE/CLOSE BUGS WITH BLOCKING CHILD BUGS STILL OPEN
* Just a warning is print out on the form when an user attempts to resolve or close a bug with
* related bugs in relation BUG_DEPENDANT still not resolved.
* Anyway the user can force the resolving/closing action.
* --------------------------------------------------------
* EMAIL NOTIFICATION TO PARENT BUGS WHEN CHILDREN BUGS ARE RESOLVED/CLOSED
* Every time a child bug is resolved or closed, an email notification is sent directly to all the handlers
* of the parent bugs. The notification is sent to bugs not already marked as resolved or closed.
* --------------------------------------------------------
* ADD CHILD
* This function gives the opportunity to generate a child bug. In details the function:
* - create a new bug with the same basic information of the parent bug (plus the custom fields)
* - copy all the attachment of the parent bug to the child
* - not copy history, bugnotes, monitoring users
* - set a relationship between parent and child
*
* @package CoreAPI
* @subpackage RelationshipAPI
* @author Marcello Scata' <marcelloscata at users.sourceforge.net> ITALY
* @copyright Copyright 2000 - 2002 Kenzaburo Ito - kenito@300baud.org
* @copyright Copyright 2002 MantisBT Team - mantisbt-dev@lists.sourceforge.net
* @link http://www.mantisbt.org
*
* @uses access_api.php
* @uses bug_api.php
* @uses collapse_api.php
* @uses config_api.php
* @uses constant_api.php
* @uses current_user_api.php
* @uses database_api.php
* @uses form_api.php
* @uses helper_api.php
* @uses lang_api.php
* @uses prepare_api.php
* @uses print_api.php
* @uses project_api.php
* @uses string_api.php
* @uses utility_api.php
*/
require_api( 'access_api.php' );
require_api( 'bug_api.php' );
require_api( 'collapse_api.php' );
require_api( 'config_api.php' );
require_api( 'constant_inc.php' );
require_api( 'current_user_api.php' );
require_api( 'database_api.php' );
require_api( 'form_api.php' );
require_api( 'helper_api.php' );
require_api( 'lang_api.php' );
require_api( 'prepare_api.php' );
require_api( 'print_api.php' );
require_api( 'project_api.php' );
require_api( 'string_api.php' );
require_api( 'utility_api.php' );
require_css( 'status_config.php' );
/**
* RelationshipData Structure Definition
*/
class BugRelationshipData {
/**
* Relationship id
*/
public $id;
/**
* Source Bug id
*/
public $src_bug_id;
/**
* Source project id
*/
public $src_project_id;
/**
* Destination Bug id
*/
public $dest_bug_id;
/**
* Destination project id
*/
public $dest_project_id;
/**
* Type
*/
public $type;
}
$g_relationships = array();
$g_relationships[BUG_DEPENDANT] = array(
'#forward' => true,
'#complementary' => BUG_BLOCKS,
'#description' => 'dependant_on',
'#notify_added' => 'email_notification_title_for_action_dependant_on_relationship_added',
'#notify_deleted' => 'email_notification_title_for_action_dependant_on_relationship_deleted',
'#edge_style' => array(
'color' => '#C00000',
'dir' => 'back',
),
);
$g_relationships[BUG_BLOCKS] = array(
'#forward' => false,
'#complementary' => BUG_DEPENDANT,
'#description' => 'blocks',
'#notify_added' => 'email_notification_title_for_action_blocks_relationship_added',
'#notify_deleted' => 'email_notification_title_for_action_blocks_relationship_deleted',
'#edge_style' => array(
'color' => '#C00000',
'dir' => 'forward',
),
);
$g_relationships[BUG_DUPLICATE] = array(
'#forward' => true,
'#complementary' => BUG_HAS_DUPLICATE,
'#description' => 'duplicate_of',
'#notify_added' => 'email_notification_title_for_action_duplicate_of_relationship_added',
'#notify_deleted' => 'email_notification_title_for_action_duplicate_of_relationship_deleted',
'#edge_style' => array(
'style' => 'dashed',
'color' => '#808080',
),
);
$g_relationships[BUG_HAS_DUPLICATE] = array(
'#forward' => false,
'#complementary' => BUG_DUPLICATE,
'#description' => 'has_duplicate',
'#notify_added' => 'email_notification_title_for_action_has_duplicate_relationship_added',
'#notify_deleted' => 'email_notification_title_for_action_has_duplicate_relationship_deleted',
);
$g_relationships[BUG_RELATED] = array(
'#forward' => true,
'#complementary' => BUG_RELATED,
'#description' => 'related_to',
'#notify_added' => 'email_notification_title_for_action_related_to_relationship_added',
'#notify_deleted' => 'email_notification_title_for_action_related_to_relationship_deleted',
);
if( file_exists( config_get_global( 'config_path' ) . 'custom_relationships_inc.php' ) ) {
include_once( config_get_global( 'config_path' ) . 'custom_relationships_inc.php' );
}
/**
* Return the complementary type of the provided relationship
* @param integer $p_relationship_type A Relationship type.
* @return integer Complementary type
*/
function relationship_get_complementary_type( $p_relationship_type ) {
global $g_relationships;
if( !isset( $g_relationships[$p_relationship_type] ) ) {
trigger_error( ERROR_GENERIC, ERROR );
}
return $g_relationships[$p_relationship_type]['#complementary'];
}
/**
* Add a new relationship
* @param integer $p_src_bug_id Source Bug Id.
* @param integer $p_dest_bug_id Destination Bug Id.
* @param integer $p_relationship_type Relationship type.
* @return BugRelationshipData Bug Relationship
*/
function relationship_add( $p_src_bug_id, $p_dest_bug_id, $p_relationship_type ) {
global $g_relationships;
if( $g_relationships[$p_relationship_type]['#forward'] === false ) {
$c_src_bug_id = (int)$p_dest_bug_id;
$c_dest_bug_id = (int)$p_src_bug_id;
$c_relationship_type = (int)relationship_get_complementary_type( $p_relationship_type );
} else {
$c_src_bug_id = (int)$p_src_bug_id;
$c_dest_bug_id = (int)$p_dest_bug_id;
$c_relationship_type = (int)$p_relationship_type;
}
db_param_push();
$t_query = 'INSERT INTO {bug_relationship}
( source_bug_id, destination_bug_id, relationship_type )
VALUES
( ' . db_param() . ',' . db_param() . ',' . db_param() . ')';
$t_result = db_query( $t_query, array( $c_src_bug_id, $c_dest_bug_id, $c_relationship_type ) );
$t_relationship = db_fetch_array( $t_result );
$t_bug_relationship_data = new BugRelationshipData;
$t_bug_relationship_data->id = $t_relationship['id'];
$t_bug_relationship_data->src_bug_id = $t_relationship['source_bug_id'];
$t_bug_relationship_data->dest_bug_id = $t_relationship['destination_bug_id'];
$t_bug_relationship_data->type = $t_relationship['relationship_type'];
return $t_bug_relationship_data;
}
/**
* Update a relationship
* @param integer $p_relationship_id Relationship Id to update.
* @param integer $p_src_bug_id Source Bug Id.
* @param integer $p_dest_bug_id Destination Bug Id.
* @param integer $p_relationship_type Relationship type.
* @return BugRelationshipData Bug Relationship
*/
function relationship_update( $p_relationship_id, $p_src_bug_id, $p_dest_bug_id, $p_relationship_type ) {
global $g_relationships;
if( $g_relationships[$p_relationship_type]['#forward'] === false ) {
$c_src_bug_id = (int)$p_dest_bug_id;
$c_dest_bug_id = (int)$p_src_bug_id;
$c_relationship_type = (int)relationship_get_complementary_type( $p_relationship_type );
} else {
$c_src_bug_id = (int)$p_src_bug_id;
$c_dest_bug_id = (int)$p_dest_bug_id;
$c_relationship_type = (int)$p_relationship_type;
}
db_param_push();
$t_query = 'UPDATE {bug_relationship}
SET source_bug_id=' . db_param() . ',
destination_bug_id=' . db_param() . ',
relationship_type=' . db_param() . '
WHERE id=' . db_param();
$t_result = db_query( $t_query, array( $c_src_bug_id, $c_dest_bug_id, $c_relationship_type, (int)$p_relationship_id ) );
$t_relationship = db_fetch_array( $t_result );
$t_bug_relationship_data = new BugRelationshipData;
$t_bug_relationship_data->id = $t_relationship['id'];
$t_bug_relationship_data->src_bug_id = $t_relationship['source_bug_id'];
$t_bug_relationship_data->dest_bug_id = $t_relationship['destination_bug_id'];
$t_bug_relationship_data->type = $t_relationship['relationship_type'];
return $t_bug_relationship_data;
}
/**
* Delete a relationship
* @param integer $p_relationship_id Relationship Id to update.
* @return void
*/
function relationship_delete( $p_relationship_id ) {
db_param_push();
$t_query = 'DELETE FROM {bug_relationship} WHERE id=' . db_param();
db_query( $t_query, array( (int)$p_relationship_id ) );
}
/**
* Deletes all the relationships related to a specific bug (both source and destination)
* @param integer $p_bug_id A bug Identifier.
* @return void
*/
function relationship_delete_all( $p_bug_id ) {
db_param_push();
$t_query = 'DELETE FROM {bug_relationship}
WHERE source_bug_id=' . db_param() . ' OR
destination_bug_id=' . db_param();
db_query( $t_query, array( (int)$p_bug_id, (int)$p_bug_id ) );
}
/**
* copy all the relationships related to a specific bug to a new bug
* @param integer $p_bug_id Source bug identifier.
* @param integer $p_new_bug_id Destination bug identifier.
* @return void
*/
function relationship_copy_all( $p_bug_id, $p_new_bug_id ) {
$t_relationship = relationship_get_all_src( $p_bug_id );
$t_relationship_count = count( $t_relationship );
for( $i = 0;$i < $t_relationship_count;$i++ ) {
relationship_add( $p_new_bug_id, $t_relationship[$i]->dest_bug_id, $t_relationship[$i]->type );
}
$t_relationship = relationship_get_all_dest( $p_bug_id );
$t_relationship_count = count( $t_relationship );
for( $i = 0;$i < $t_relationship_count;$i++ ) {
relationship_add( $t_relationship[$i]->src_bug_id, $p_new_bug_id, $t_relationship[$i]->type );
}
}
/**
* get a relationship from id
* @param integer $p_relationship_id Relationship Identifier.
* @return null|BugRelationshipData BugRelationshipData object
*/
function relationship_get( $p_relationship_id ) {
db_param_push();
$t_query = 'SELECT * FROM {bug_relationship} WHERE id=' . db_param();
$t_result = db_query( $t_query, array( (int)$p_relationship_id ) );
$t_relationship = db_fetch_array( $t_result );
if( $t_relationship ) {
$t_bug_relationship_data = new BugRelationshipData;
$t_bug_relationship_data->id = $t_relationship['id'];
$t_bug_relationship_data->src_bug_id = $t_relationship['source_bug_id'];
$t_bug_relationship_data->dest_bug_id = $t_relationship['destination_bug_id'];
$t_bug_relationship_data->type = $t_relationship['relationship_type'];
} else {
$t_bug_relationship_data = null;
}
return $t_bug_relationship_data;
}
/**
* get all relationships with the given bug as source
* @param integer $p_src_bug_id Source Bug identifier.
* @return array Array of BugRelationshipData objects
*/
function relationship_get_all_src( $p_src_bug_id ) {
db_param_push();
$t_query = 'SELECT {bug_relationship}.id, {bug_relationship}.relationship_type,
{bug_relationship}.source_bug_id, {bug_relationship}.destination_bug_id,
{bug}.project_id
FROM {bug_relationship}
INNER JOIN {bug} ON {bug_relationship}.destination_bug_id = {bug}.id
WHERE source_bug_id=' . db_param() . '
ORDER BY relationship_type, {bug_relationship}.id';
$t_result = db_query( $t_query, array( $p_src_bug_id ) );
$t_src_project_id = bug_get_field( $p_src_bug_id, 'project_id' );
$t_bug_relationship_data = array();
$t_bug_array = array();
$i = 0;
while( $t_row = db_fetch_array( $t_result ) ) {
$t_bug_relationship_data[$i] = new BugRelationshipData;
$t_bug_relationship_data[$i]->id = $t_row['id'];
$t_bug_relationship_data[$i]->src_bug_id = $t_row['source_bug_id'];
$t_bug_relationship_data[$i]->src_project_id = $t_src_project_id;
$t_bug_relationship_data[$i]->dest_bug_id = $t_row['destination_bug_id'];
$t_bug_relationship_data[$i]->dest_project_id = $t_row['project_id'];
$t_bug_relationship_data[$i]->type = $t_row['relationship_type'];
$t_bug_array[] = $t_row['destination_bug_id'];
$i++;
}
if( !empty( $t_bug_array ) ) {
bug_cache_array_rows( $t_bug_array );
}
return $t_bug_relationship_data;
}
/**
* get all relationships with the given bug as destination
* @param integer $p_dest_bug_id Destination bug identifier.
* @return array Array of BugRelationshipData objects
*/
function relationship_get_all_dest( $p_dest_bug_id ) {
db_param_push();
$t_query = 'SELECT {bug_relationship}.id, {bug_relationship}.relationship_type,
{bug_relationship}.source_bug_id, {bug_relationship}.destination_bug_id,
{bug}.project_id
FROM {bug_relationship}
INNER JOIN {bug} ON {bug_relationship}.source_bug_id = {bug}.id
WHERE destination_bug_id=' . db_param() . '
ORDER BY relationship_type, {bug_relationship}.id';
$t_result = db_query( $t_query, array( (int)$p_dest_bug_id ) );
$t_dest_project_id = bug_get_field( $p_dest_bug_id, 'project_id' );
$t_bug_relationship_data = array();
$t_bug_array = array();
$i = 0;
while( $t_row = db_fetch_array( $t_result ) ) {
$t_bug_relationship_data[$i] = new BugRelationshipData;
$t_bug_relationship_data[$i]->id = $t_row['id'];
$t_bug_relationship_data[$i]->src_bug_id = $t_row['source_bug_id'];
$t_bug_relationship_data[$i]->src_project_id = $t_row['project_id'];
$t_bug_relationship_data[$i]->dest_bug_id = $t_row['destination_bug_id'];
$t_bug_relationship_data[$i]->dest_project_id = $t_dest_project_id;
$t_bug_relationship_data[$i]->type = $t_row['relationship_type'];
$t_bug_array[] = $t_row['source_bug_id'];
$i++;
}
if( !empty( $t_bug_array ) ) {
bug_cache_array_rows( $t_bug_array );
}
return $t_bug_relationship_data;
}
/**
* get all relationships associated with the given bug
* @param integer $p_bug_id A bug identifier.
* @param boolean &$p_is_different_projects Returned Boolean value indicating if some relationships cross project boundaries.
* @return array Array of BugRelationshipData objects
*/
function relationship_get_all( $p_bug_id, &$p_is_different_projects ) {
$t_src = relationship_get_all_src( $p_bug_id );
$t_dest = relationship_get_all_dest( $p_bug_id );
$t_all = array_merge( $t_src, $t_dest );
$p_is_different_projects = false;
$t_count = count( $t_all );
for( $i = 0;$i < $t_count;$i++ ) {
$p_is_different_projects |= ( $t_all[$i]->src_project_id != $t_all[$i]->dest_project_id );
}
return $t_all;
}
/**
* check if there is a relationship between two bugs
* return id if found 0 otherwise
* @param integer $p_src_bug_id Source bug identifier.
* @param integer $p_dest_bug_id Destination bug identifier.
* @return integer Relationship ID
*/
function relationship_exists( $p_src_bug_id, $p_dest_bug_id ) {
$c_src_bug_id = (int)$p_src_bug_id;
$c_dest_bug_id = (int)$p_dest_bug_id;
db_param_push();
$t_query = 'SELECT * FROM {bug_relationship}
WHERE (source_bug_id=' . db_param() . ' AND destination_bug_id=' . db_param() . ')
OR
(source_bug_id=' . db_param() . '
AND destination_bug_id=' . db_param() . ')';
$t_result = db_query( $t_query, array( $c_src_bug_id, $c_dest_bug_id, $c_dest_bug_id, $c_src_bug_id ), 1 );
if( $t_row = db_fetch_array( $t_result ) ) {
# return the first id
return $t_row['id'];
} else {
# no relationship found
return 0;
}
}
/**
* check if there is a relationship between two bugs
* return:
* 0 if the relationship is not found
* -1 if the relationship is found and it's of the same type $p_rel_type
* 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
* @param integer $p_src_bug_id Source Bug Id.
* @param integer $p_dest_bug_id Destination Bug Id.
* @param integer $p_rel_type Relationship Type.
* @return integer 0, -1 or id
*/
function relationship_same_type_exists( $p_src_bug_id, $p_dest_bug_id, $p_rel_type ) {
# Check if there is already a relationship set between them
$t_id_relationship = relationship_exists( $p_src_bug_id, $p_dest_bug_id );
if( $t_id_relationship > 0 ) {
# if there is...
# get all the relationship info
$t_relationship = relationship_get( $t_id_relationship );
if( $t_relationship->src_bug_id == $p_src_bug_id && $t_relationship->dest_bug_id == $p_dest_bug_id ) {
if( $t_relationship->type == $p_rel_type ) {
$t_id_relationship = -1;
}
} else {
if( $t_relationship->type == relationship_get_complementary_type( $p_rel_type ) ) {
$t_id_relationship = -1;
}
}
}
return $t_id_relationship;
}
/**
* retrieve the linked bug id of the relationship: provide source -> return destination; provide destination -> return source
* @param integer $p_relationship_id Relationship id.
* @param integer $p_bug_id A bug identifier.
* @return int Complementary bug id
*/
function relationship_get_linked_bug_id( $p_relationship_id, $p_bug_id ) {
$t_bug_relationship_data = relationship_get( $p_relationship_id );
if( $t_bug_relationship_data->src_bug_id == $p_bug_id ) {
return $t_bug_relationship_data->dest_bug_id;
}
if( $t_bug_relationship_data->dest_bug_id == $p_bug_id ) {
return $t_bug_relationship_data->src_bug_id;
}
trigger_error( ERROR_RELATIONSHIP_NOT_FOUND, ERROR );
}
/**
* get class description of a relationship (source side)
* @param integer $p_relationship_type Relationship type.
* @return string Relationship description
*/
function relationship_get_description_src_side( $p_relationship_type ) {
global $g_relationships;
if( !isset( $g_relationships[$p_relationship_type] ) ) {
trigger_error( ERROR_RELATIONSHIP_NOT_FOUND, ERROR );
}
return lang_get( $g_relationships[$p_relationship_type]['#description'] );
}
/**
* get class description of a relationship (destination side)
* @param integer $p_relationship_type Relationship type.
* @return string Relationship description
*/
function relationship_get_description_dest_side( $p_relationship_type ) {
global $g_relationships;
if( !isset( $g_relationships[$p_relationship_type] ) || !isset( $g_relationships[$g_relationships[$p_relationship_type]['#complementary']] ) ) {
trigger_error( ERROR_RELATIONSHIP_NOT_FOUND, ERROR );
}
return lang_get( $g_relationships[$g_relationships[$p_relationship_type]['#complementary']]['#description'] );
}
/**
* get class description of a relationship as it's stored in the history
* @param integer $p_relationship_code Relationship Type.
* @return string Relationship description
*/
function relationship_get_description_for_history( $p_relationship_code ) {
return relationship_get_description_src_side( $p_relationship_code );
}
/**
* return false if there are child bugs not resolved/closed
* N.B. we don't check if the parent bug is read-only. This is because the answer of this function is indepedent from
* the state of the parent bug itself.
* @param integer $p_bug_id A bug identifier.
* @return boolean
*/
function relationship_can_resolve_bug( $p_bug_id ) {
# retrieve all the relationships in which the bug is the source bug
$t_relationship = relationship_get_all_src( $p_bug_id );
$t_relationship_count = count( $t_relationship );
if( $t_relationship_count == 0 ) {
return true;
}
for( $i = 0;$i < $t_relationship_count;$i++ ) {
# verify if each bug in relation BUG_DEPENDANT is already marked as resolved
if( $t_relationship[$i]->type == BUG_DEPENDANT ) {
$t_dest_bug_id = $t_relationship[$i]->dest_bug_id;
$t_status = bug_get_field( $t_dest_bug_id, 'status' );
if( $t_status < config_get( 'bug_resolved_status_threshold' ) ) {
# the bug is NOT marked as resolved/closed
return false;
}
}
}
return true;
}
/**
* return formatted string with all the details on the requested relationship
* @param integer $p_bug_id A bug identifier.
* @param BugRelationshipData $p_relationship A bug relationship object.
* @param boolean $p_html Whether to return html or text output.
* @param boolean $p_html_preview Whether to include style/hyperlinks - if preview is false, we prettify the output.
* @param boolean $p_show_project Show Project details.
* @return string
*/
function relationship_get_details( $p_bug_id, BugRelationshipData $p_relationship, $p_html = false, $p_html_preview = false, $p_show_project = false ) {
$t_summary_wrap_at = utf8_strlen( config_get( 'email_separator2' ) ) - 28;
if( $p_bug_id == $p_relationship->src_bug_id ) {
# root bug is in the source side, related bug in the destination side
$t_related_project_id = $p_relationship->dest_bug_id;
$t_related_bug_id = $p_relationship->dest_bug_id;
$t_related_project_name = project_get_name( $p_relationship->dest_project_id );
$t_relationship_descr = relationship_get_description_src_side( $p_relationship->type );
} else {
# root bug is in the dest side, related bug in the source side
$t_related_project_id = $p_relationship->src_bug_id;
$t_related_bug_id = $p_relationship->src_bug_id;
$t_related_project_name = project_get_name( $p_relationship->src_project_id );
$t_relationship_descr = relationship_get_description_dest_side( $p_relationship->type );
}
# related bug not existing...
if( !bug_exists( $t_related_bug_id ) ) {
return '';
}
# user can access to the related bug at least as a viewer
if( !access_has_bug_level( config_get( 'view_bug_threshold', null, null, $t_related_project_id ), $t_related_bug_id ) ) {
return '';
}
if( $p_html_preview == false ) {
$t_td = '<td>';
} else {
$t_td = '<td class="print">';
}
# get the information from the related bug and prepare the link
$t_bug = bug_get( $t_related_bug_id, false );
$t_status_string = get_enum_element( 'status', $t_bug->status, auth_get_current_user_id(), $t_bug->project_id );
$t_resolution_string = get_enum_element( 'resolution', $t_bug->resolution, auth_get_current_user_id(), $t_bug->project_id );
$t_relationship_info_html = $t_td . string_no_break( $t_relationship_descr ) . ' </td>';
if( $p_html_preview == false ) {
# choose color based on status
$status_label = html_get_status_css_class( $t_bug->status, auth_get_current_user_id(), $t_bug->project_id );
$t_relationship_info_html .= '<td><a href="' . string_get_bug_view_url( $t_related_bug_id ) . '">' . string_display_line( bug_format_id( $t_related_bug_id ) ) . '</a></td>';
$t_relationship_info_html .= '<td><i class="fa fa-square-o fa-xlg ' . $status_label . '"></i> ';
$t_relationship_info_html .= '<span class="issue-status" title="' . string_attribute( $t_resolution_string ) . '">' . string_display_line( $t_status_string ) . '</span></td>';
} else {
$t_relationship_info_html .= $t_td . string_display_line( bug_format_id( $t_related_bug_id ) ) . '</td>';
$t_relationship_info_html .= $t_td . string_display_line( $t_status_string ) . ' </td>';
}
$t_relationship_info_text = utf8_str_pad( $t_relationship_descr, 20 );
$t_relationship_info_text .= utf8_str_pad( bug_format_id( $t_related_bug_id ), 8 );
# get the handler name of the related bug
$t_relationship_info_html .= $t_td;
if( $t_bug->handler_id > 0 ) {
$t_relationship_info_html .= string_no_break( prepare_user_name( $t_bug->handler_id ) );
}
$t_relationship_info_html .= ' </td>';
# add project name
if( $p_show_project ) {
$t_relationship_info_html .= $t_td . string_display_line( $t_related_project_name ) . ' </td>';
}
# add summary
if( $p_html == true ) {
$t_relationship_info_html .= $t_td . string_display_line_links( $t_bug->summary );
if( VS_PRIVATE == $t_bug->view_state ) {
$t_relationship_info_html .= sprintf( ' <i class="fa fa-lock" alt="(%s)" title="%s" />', lang_get( 'private' ), lang_get( 'private' ) );
}
} else {
if( utf8_strlen( $t_bug->summary ) <= $t_summary_wrap_at ) {
$t_relationship_info_text .= string_email_links( $t_bug->summary );
} else {
$t_relationship_info_text .= utf8_substr( string_email_links( $t_bug->summary ), 0, $t_summary_wrap_at - 3 ) . '...';
}
}
# add delete link if bug not read only and user has access level
if( !bug_is_readonly( $p_bug_id ) && !current_user_is_anonymous() && ( $p_html_preview == false ) ) {
if( access_has_bug_level( config_get( 'update_bug_threshold' ), $p_bug_id ) ) {
$t_relationship_info_html .= ' <a class="btn btn-primary btn-xs btn-white btn-round noprint"
href="bug_relationship_delete.php?bug_id=' . $p_bug_id . '&rel_id=' . $p_relationship->id . htmlspecialchars( form_security_param( 'bug_relationship_delete' ) ) . '">' .
lang_get( 'delete_link' ) . '</a>';
}
}
$t_relationship_info_html .= ' </td>';
$t_relationship_info_text .= "\n";
$t_relationship_info_html = '<tr>' . $t_relationship_info_html . '</tr>';
if( $p_html == true ) {
return $t_relationship_info_html;
} else {
return $t_relationship_info_text;
}
}
/**
* print ALL the RELATIONSHIPS OF A SPECIFIC BUG
* @param integer $p_bug_id A bug identifier.
* @return string
*/
function relationship_get_summary_html( $p_bug_id ) {
$t_summary = '';
$t_show_project = false;
$t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
$t_relationship_all_count = count( $t_relationship_all );
# prepare the relationships table
for( $i = 0; $i < $t_relationship_all_count; $i++ ) {
$t_summary .= relationship_get_details( $p_bug_id, $t_relationship_all[$i], true, false, $t_show_project );
}
if( !is_blank( $t_summary ) ) {
if( relationship_can_resolve_bug( $p_bug_id ) == false ) {
$t_summary .= '<tr><td colspan="' . ( 5 + $t_show_project ) . '"><strong>' .
lang_get( 'relationship_warning_blocking_bugs_not_resolved' ) . '</strong></td></tr>';
}
$t_summary = '<table class="table table-bordered table-condensed table-hover">' . $t_summary . '</table>';
}
return $t_summary;
}
/**
* print ALL the RELATIONSHIPS OF A SPECIFIC BUG
* @param integer $p_bug_id A bug identifier.
* @return string
*/
function relationship_get_summary_html_preview( $p_bug_id ) {
$t_summary = '';
$t_show_project = false;
$t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
$t_relationship_all_count = count( $t_relationship_all );
# prepare the relationships table
for( $i = 0;$i < $t_relationship_all_count;$i++ ) {
$t_summary .= relationship_get_details( $p_bug_id, $t_relationship_all[$i], true, true, $t_show_project );
}
if( !is_blank( $t_summary ) ) {
if( relationship_can_resolve_bug( $p_bug_id ) == false ) {
$t_summary .= '<tr class="print"><td class="print" colspan=' . ( 5 + $t_show_project ) . '><strong>' . lang_get( 'relationship_warning_blocking_bugs_not_resolved' ) . '</strong></td></tr>';
}
$t_summary = '<table width="100%" cellpadding="0" cellspacing="1">' . $t_summary . '</table>';
}
return $t_summary;
}
/**
* print ALL the RELATIONSHIPS OF A SPECIFIC BUG in text format (used by email_api.php
* @param integer $p_bug_id A bug identifier.
* @return string
*/
function relationship_get_summary_text( $p_bug_id ) {
$t_summary = '';
$t_show_project = false;
$t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
$t_relationship_all_count = count( $t_relationship_all );
# prepare the relationships table
for( $i = 0;$i < $t_relationship_all_count;$i++ ) {
$t_summary .= relationship_get_details( $p_bug_id, $t_relationship_all[$i], false );
}
return $t_summary;
}
/**
* print HTML relationship listbox
* @param integer $p_default_rel_type Relationship Type (default -1).
* @param string $p_select_name List box name (default "rel_type").
* @param boolean $p_include_any Include an ANY option in list box (default false).
* @param boolean $p_include_none Include a NONE option in list box (default false).
* @return void
*/
function relationship_list_box( $p_default_rel_type = BUG_REL_ANY, $p_select_name = 'rel_type', $p_include_any = false, $p_include_none = false ) {
global $g_relationships;
?>
<select class="input-sm" name="<?php echo $p_select_name?>">
<?php if( $p_include_any ) {?>
<option value="<?php echo BUG_REL_ANY ?>" <?php echo( $p_default_rel_type == BUG_REL_ANY ? ' selected="selected"' : '' )?>>[<?php echo lang_get( 'any' )?>]</option>
<?php
}
if( $p_include_none ) {?>
<option value="<?php echo BUG_REL_NONE ?>" <?php echo( $p_default_rel_type == BUG_REL_NONE ? ' selected="selected"' : '' )?>>[<?php echo lang_get( 'none' )?>]</option>
<?php
}
foreach( $g_relationships as $t_type => $t_relationship ) {
?>
<option value="<?php echo $t_type?>"<?php echo( $p_default_rel_type == $t_type ? ' selected="selected"' : '' )?>><?php echo lang_get( $t_relationship['#description'] )?></option>
<?php
}?>
</select>
<?php
}
/**
* print HTML relationship form
* @param integer $p_bug_id A bug identifier.
* @return void
*/
function relationship_view_box( $p_bug_id ) {
?>
<div class="col-md-12 col-xs-12">
<div class="space-10"></div>
<?php
$t_collapse_block = is_collapsed( 'relationships' );
$t_block_css = $t_collapse_block ? 'collapsed' : '';
$t_block_icon = $t_collapse_block ? 'fa-chevron-down' : 'fa-chevron-up';
?>
<div id="relationships" class="widget-box widget-color-blue2 <?php echo $t_block_css ?>">
<div class="widget-header widget-header-small">
<h4 class="widget-title lighter">
<i class="ace-icon fa fa-sitemap"></i>
<?php echo lang_get( 'bug_relationships' ) ?>
</h4>
<div class="widget-toolbar">
<a data-action="collapse" href="#">
<i class="1 ace-icon fa <?php echo $t_block_icon ?> bigger-125"></i>
</a>
</div>
</div>
<div class="widget-body">
<div class="widget-toolbox padding-8 clearfix">
<?php
if( ON == config_get( 'relationship_graph_enable' ) ) {
?>
<div class="btn-group pull-right noprint">
<span class="small"><?php print_small_button( 'bug_relationship_graph.php?bug_id=' . $p_bug_id . '&graph=relation', lang_get( 'relation_graph' ) )?></span>
<span class="small"><?php print_small_button( 'bug_relationship_graph.php?bug_id=' . $p_bug_id . '&graph=dependency', lang_get( 'dependency_graph' ) )?></span>
</div>
<?php
}
?>
<?php
# bug not read-only and user authenticated
if( !bug_is_readonly( $p_bug_id ) ) {
# user access level at least updater
if( access_has_bug_level( config_get( 'update_bug_threshold' ), $p_bug_id ) ) {
?>
<form method="post" action="bug_relationship_add.php" class="form-inline noprint">
<?php echo form_security_field( 'bug_relationship_add' ) ?>
<input type="hidden" name="src_bug_id" value="<?php echo $p_bug_id?>" />
<label class="inline"><?php echo lang_get( 'this_bug' ) ?>  </label>
<?php relationship_list_box( config_get( 'default_bug_relationship' ) )?>
<input type="text" class="input-sm" name="dest_bug_id" value="" />
<input type="submit" class="btn btn-primary btn-sm btn-white btn-round" name="add_relationship" value="<?php echo lang_get( 'add_new_relationship_button' )?>" />
</form>
<?php
}
}
?>
</div>
<div class="widget-main no-padding">
<div class="table-responsive">
<?php echo relationship_get_summary_html( $p_bug_id )?>
</div>
</div>
</div>
</div>
</div>
<?php
}