2 # MantisBT - A PHP based bugtracking system
4 # MantisBT is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation, either version 2 of the License, or
7 # (at your option) any later version.
9 # MantisBT is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with MantisBT. If not, see <http://www.gnu.org/licenses/>.
20 * RELATIONSHIP DEFINITIONS
21 * * Child/parent relationship:
22 * the child bug is generated by the parent bug or is directly linked with the parent with the following meaning
23 * the child bug has to be resolved before resolving the parent bug (the child bug "blocks" the parent bug)
24 * example: bug A is child bug of bug B. It means: A blocks B and B is blocked by A
25 * * General relationship:
26 * two bugs related each other without any hierarchy dependance
27 * bugs A and B are related
29 * it's used to mark a bug as duplicate of an other bug already stored in the database
30 * bug A is marked as duplicate of B. It means: A duplicates B, B has duplicates
32 * Relations are always visible in the email body
33 * --------------------------------------------------------------------
34 * ADD NEW RELATIONSHIP
35 * - Permission: user can update the source bug and at least view the destination bug
36 * - Action recorded in the history of both the bugs
37 * - Email notification sent to the users of both the bugs based based on the 'updated' bug notify type.
38 * --------------------------------------------------------
40 * - Permission: user can update the source bug and at least view the destination bug
41 * - Action recorded in the history of both the bugs
42 * - Email notification sent to the users of both the bugs based based on the 'updated' bug notify type.
43 * --------------------------------------------------------
44 * RESOLVE/CLOSE BUGS WITH BLOCKING CHILD BUGS STILL OPEN
45 * Just a warning is print out on the form when an user attempts to resolve or close a bug with
46 * related bugs in relation BUG_DEPENDANT still not resolved.
47 * Anyway the user can force the resolving/closing action.
48 * --------------------------------------------------------
49 * EMAIL NOTIFICATION TO PARENT BUGS WHEN CHILDREN BUGS ARE RESOLVED/CLOSED
50 * Every time a child bug is resolved or closed, an email notification is sent directly to all the handlers
51 * of the parent bugs. The notification is sent to bugs not already marked as resolved or closed.
52 * --------------------------------------------------------
54 * This function gives the opportunity to generate a child bug. In details the function:
55 * - create a new bug with the same basic information of the parent bug (plus the custom fields)
56 * - copy all the attachment of the parent bug to the child
57 * - not copy history, bugnotes, monitoring users
58 * - set a relationship between parent and child
61 * @subpackage RelationshipAPI
62 * @author Marcello Scata' <marcelloscata at users.sourceforge.net> ITALY
63 * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org
64 * @copyright Copyright (C) 2002 - 2011 MantisBT Team - mantisbt-dev@lists.sourceforge.net
65 * @link http://www.mantisbt.org
67 * @uses access_api.php
69 * @uses collapse_api.php
70 * @uses config_api.php
71 * @uses constant_api.php
72 * @uses current_user_api.php
73 * @uses database_api.php
75 * @uses helper_api.php
77 * @uses prepare_api.php
79 * @uses project_api.php
80 * @uses string_api.php
81 * @uses utility_api.php
84 require_api( 'access_api.php' );
85 require_api( 'bug_api.php' );
86 require_api( 'collapse_api.php' );
87 require_api( 'config_api.php' );
88 require_api( 'constant_inc.php' );
89 require_api( 'current_user_api.php' );
90 require_api( 'database_api.php' );
91 require_api( 'form_api.php' );
92 require_api( 'helper_api.php' );
93 require_api( 'lang_api.php' );
94 require_api( 'prepare_api.php' );
95 require_api( 'print_api.php' );
96 require_api( 'project_api.php' );
97 require_api( 'string_api.php' );
98 require_api( 'utility_api.php' );
100 require_css( 'status_config.php' );
103 * RelationshipData Structure Definition
105 * @subpackage classes
107 class BugRelationshipData
{
112 var $dest_project_id;
116 $g_relationships = array();
117 $g_relationships[BUG_DEPENDANT
] = array(
119 '#complementary' => BUG_BLOCKS
,
120 '#description' => 'dependant_on',
121 '#notify_added' => 'email_notification_title_for_action_dependant_on_relationship_added',
122 '#notify_deleted' => 'email_notification_title_for_action_dependant_on_relationship_deleted',
123 '#edge_style' => array(
124 'color' => '#C00000',
128 $g_relationships[BUG_BLOCKS
] = array(
130 '#complementary' => BUG_DEPENDANT
,
131 '#description' => 'blocks',
132 '#notify_added' => 'email_notification_title_for_action_blocks_relationship_added',
133 '#notify_deleted' => 'email_notification_title_for_action_blocks_relationship_deleted',
134 '#edge_style' => array(
135 'color' => '#C00000',
139 $g_relationships[BUG_DUPLICATE
] = array(
141 '#complementary' => BUG_HAS_DUPLICATE
,
142 '#description' => 'duplicate_of',
143 '#notify_added' => 'email_notification_title_for_action_duplicate_of_relationship_added',
144 '#notify_deleted' => 'email_notification_title_for_action_duplicate_of_relationship_deleted',
145 '#edge_style' => array(
147 'color' => '#808080',
150 $g_relationships[BUG_HAS_DUPLICATE
] = array(
152 '#complementary' => BUG_DUPLICATE
,
153 '#description' => 'has_duplicate',
154 '#notify_added' => 'email_notification_title_for_action_has_duplicate_relationship_added',
155 '#notify_deleted' => 'email_notification_title_for_action_has_duplicate_relationship_deleted',
157 $g_relationships[BUG_RELATED
] = array(
159 '#complementary' => BUG_RELATED
,
160 '#description' => 'related_to',
161 '#notify_added' => 'email_notification_title_for_action_related_to_relationship_added',
162 '#notify_deleted' => 'email_notification_title_for_action_related_to_relationship_deleted',
165 if( file_exists( config_get_global( 'absolute_path' ) . 'custom_relationships_inc.php' ) ) {
166 require_once( config_get_global( 'absolute_path' ) . 'custom_relationships_inc.php' );
170 * Return the complementary type of the provided relationship
171 * @param int $p_relationship_type Relationship type
172 * @return int Complementary type
174 function relationship_get_complementary_type( $p_relationship_type ) {
175 global $g_relationships;
176 if( !isset( $g_relationships[$p_relationship_type] ) ) {
177 trigger_error( ERROR_GENERIC
, ERROR
);
179 return $g_relationships[$p_relationship_type]['#complementary'];
183 * Add a new relationship
184 * @param int $p_src_bug_id Source Bug Id
185 * @param int $p_dest_bug_id Destination Bug Id
186 * @param int $p_relationship_type Relationship type
187 * @return BugRelationshipData Bug Relationship
189 function relationship_add( $p_src_bug_id, $p_dest_bug_id, $p_relationship_type ) {
190 $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
192 global $g_relationships;
193 if( $g_relationships[$p_relationship_type]['#forward'] === FALSE ) {
194 $c_src_bug_id = db_prepare_int( $p_dest_bug_id );
195 $c_dest_bug_id = db_prepare_int( $p_src_bug_id );
196 $c_relationship_type = db_prepare_int( relationship_get_complementary_type( $p_relationship_type ) );
198 $c_src_bug_id = db_prepare_int( $p_src_bug_id );
199 $c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
200 $c_relationship_type = db_prepare_int( $p_relationship_type );
203 $query = "INSERT INTO $t_mantis_bug_relationship_table
204 ( source_bug_id, destination_bug_id, relationship_type )
206 ( " . db_param() . ',' . db_param() . ',' . db_param() . ')';
207 $result = db_query_bound( $query, Array( $c_src_bug_id, $c_dest_bug_id, $c_relationship_type ) );
208 $t_relationship = db_fetch_array( $result );
210 $t_bug_relationship_data = new BugRelationshipData
;
211 $t_bug_relationship_data->id
= $t_relationship['id'];
212 $t_bug_relationship_data->src_bug_id
= $t_relationship['source_bug_id'];
213 $t_bug_relationship_data->dest_bug_id
= $t_relationship['destination_bug_id'];
214 $t_bug_relationship_data->type
= $t_relationship['relationship_type'];
216 return $t_bug_relationship_data;
220 * Update a relationship
221 * @param int $p_relationship_id Relationship Id to update
222 * @param int $p_src_bug_id Source Bug Id
223 * @param int $p_dest_bug_id Destination Bug Id
224 * @param int $p_relationship_type Relationship type
225 * @return BugRelationshipData Bug Relationship
227 function relationship_update( $p_relationship_id, $p_src_bug_id, $p_dest_bug_id, $p_relationship_type ) {
228 $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
230 global $g_relationships;
231 if( $g_relationships[$p_relationship_type]['#forward'] === FALSE ) {
232 $c_src_bug_id = db_prepare_int( $p_dest_bug_id );
233 $c_dest_bug_id = db_prepare_int( $p_src_bug_id );
234 $c_relationship_type = db_prepare_int( relationship_get_complementary_type( $p_relationship_type ) );
236 $c_src_bug_id = db_prepare_int( $p_src_bug_id );
237 $c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
238 $c_relationship_type = db_prepare_int( $p_relationship_type );
240 $c_relationship_id = db_prepare_int( $p_relationship_id );
242 $query = "UPDATE $t_mantis_bug_relationship_table
243 SET source_bug_id=" . db_param() . ",
244 destination_bug_id=" . db_param() . ",
245 relationship_type=" . db_param() . "
246 WHERE id=" . db_param();
247 $result = db_query_bound( $query, array( $c_src_bug_id, $c_dest_bug_id, $c_relationship_type, $c_relationship_id ) );
248 $t_relationship = db_fetch_array( $result );
250 $t_bug_relationship_data = new BugRelationshipData
;
251 $t_bug_relationship_data->id
= $t_relationship['id'];
252 $t_bug_relationship_data->src_bug_id
= $t_relationship['source_bug_id'];
253 $t_bug_relationship_data->dest_bug_id
= $t_relationship['destination_bug_id'];
254 $t_bug_relationship_data->type
= $t_relationship['relationship_type'];
256 return $t_bug_relationship_data;
260 * Delete a relationship
261 * @param int $p_relationship_id Relationship Id to update
263 function relationship_delete( $p_relationship_id ) {
264 $c_relationship_id = db_prepare_int( $p_relationship_id );
266 $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
268 $query = "DELETE FROM $t_mantis_bug_relationship_table
269 WHERE id=" . db_param();
270 $result = db_query_bound( $query, array( $c_relationship_id ) );
274 * Deletes all the relationships related to a specific bug (both source and destination)
275 * @param int $p_bug_id Bug Id
277 function relationship_delete_all( $p_bug_id ) {
278 $c_bug_id = db_prepare_int( $p_bug_id );
280 $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
282 $query = "DELETE FROM $t_mantis_bug_relationship_table
283 WHERE source_bug_id=" . db_param() . " OR
284 destination_bug_id=" . db_param();
285 $result = db_query_bound( $query, array( $c_bug_id, $c_bug_id ) );
289 * copy all the relationships related to a specific bug to a new bug
290 * @param int $p_bug_id Source Bug Id
291 * @param int $p_new_bug_id Destination Bug Id
293 function relationship_copy_all( $p_bug_id, $p_new_bug_id ) {
294 $c_bug_id = db_prepare_int( $p_bug_id );
295 $c_new_bug_id = db_prepare_int( $p_new_bug_id );
297 $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
299 $t_relationship = relationship_get_all_src( $p_bug_id );
300 $t_relationship_count = count( $t_relationship );
301 for( $i = 0;$i < $t_relationship_count;$i++
) {
302 relationship_add( $p_new_bug_id, $t_relationship[$i]->dest_bug_id
, $t_relationship[$i]->type
);
305 $t_relationship = relationship_get_all_dest( $p_bug_id );
306 $t_relationship_count = count( $t_relationship );
307 for( $i = 0;$i < $t_relationship_count;$i++
) {
308 relationship_add( $t_relationship[$i]->src_bug_id
, $p_new_bug_id, $t_relationship[$i]->type
);
315 * get a relationship from id
316 * @param int $p_relationship_id Relationship ID
317 * @return null|BugRelationshipData BugRelationshipData object
319 function relationship_get( $p_relationship_id ) {
320 $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
323 FROM $t_mantis_bug_relationship_table
324 WHERE id=" . db_param();
325 $result = db_query_bound( $query, array( (int) $p_relationship_id ) );
327 $t_relationship_count = db_num_rows( $result );
329 if( $t_relationship_count == 1 ) {
330 $t_relationship = db_fetch_array( $result );
332 $t_bug_relationship_data = new BugRelationshipData
;
333 $t_bug_relationship_data->id
= $t_relationship['id'];
334 $t_bug_relationship_data->src_bug_id
= $t_relationship['source_bug_id'];
335 $t_bug_relationship_data->dest_bug_id
= $t_relationship['destination_bug_id'];
336 $t_bug_relationship_data->type
= $t_relationship['relationship_type'];
338 $t_bug_relationship_data = null;
341 return $t_bug_relationship_data;
345 * get all relationships with the given bug as source
346 * @param int $p_src_bug_id Source Bug id
347 * @return array Array of BugRelationshipData objects
349 function relationship_get_all_src( $p_src_bug_id ) {
350 $c_src_bug_id = db_prepare_int( $p_src_bug_id );
352 $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
353 $t_mantis_bug_table = db_get_table( 'bug' );
355 $query = "SELECT $t_mantis_bug_relationship_table.id, $t_mantis_bug_relationship_table.relationship_type,
356 $t_mantis_bug_relationship_table.source_bug_id, $t_mantis_bug_relationship_table.destination_bug_id,
357 $t_mantis_bug_table.project_id
358 FROM $t_mantis_bug_relationship_table
359 INNER JOIN $t_mantis_bug_table ON $t_mantis_bug_relationship_table.destination_bug_id = $t_mantis_bug_table.id
360 WHERE source_bug_id=" . db_param() . "
361 ORDER BY relationship_type, $t_mantis_bug_relationship_table.id";
362 $result = db_query_bound( $query, array( $c_src_bug_id ) );
364 $t_src_project_id = bug_get_field( $p_src_bug_id, 'project_id' );
366 $t_bug_relationship_data = array();
367 $t_relationship_count = db_num_rows( $result );
368 $t_bug_array = Array();
369 for( $i = 0;$i < $t_relationship_count;$i++
) {
370 $row = db_fetch_array( $result );
371 $t_bug_relationship_data[$i] = new BugRelationshipData
;
372 $t_bug_relationship_data[$i]->id
= $row['id'];
373 $t_bug_relationship_data[$i]->src_bug_id
= $row['source_bug_id'];
374 $t_bug_relationship_data[$i]->src_project_id
= $t_src_project_id;
375 $t_bug_relationship_data[$i]->dest_bug_id
= $row['destination_bug_id'];
376 $t_bug_relationship_data[$i]->dest_project_id
= $row['project_id'];
377 $t_bug_relationship_data[$i]->type
= $row['relationship_type'];
378 $t_bug_array[] = $row['destination_bug_id'];
380 unset( $t_bug_relationship_data[$t_relationship_count] );
381 if( !empty( $t_bug_array ) ) {
382 bug_cache_array_rows( $t_bug_array );
385 return $t_bug_relationship_data;
389 * get all relationships with the given bug as destination
390 * @param int $p_dest_bug_id Destination Bug id
391 * @return array Array of BugRelationshipData objects
393 function relationship_get_all_dest( $p_dest_bug_id ) {
394 $c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
396 $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
397 $t_mantis_bug_table = db_get_table( 'bug' );
399 $query = "SELECT $t_mantis_bug_relationship_table.id, $t_mantis_bug_relationship_table.relationship_type,
400 $t_mantis_bug_relationship_table.source_bug_id, $t_mantis_bug_relationship_table.destination_bug_id,
401 $t_mantis_bug_table.project_id
402 FROM $t_mantis_bug_relationship_table
403 INNER JOIN $t_mantis_bug_table ON $t_mantis_bug_relationship_table.source_bug_id = $t_mantis_bug_table.id
404 WHERE destination_bug_id=" . db_param() . "
405 ORDER BY relationship_type, $t_mantis_bug_relationship_table.id";
406 $result = db_query_bound( $query, Array( $c_dest_bug_id ) );
408 $t_dest_project_id = bug_get_field( $p_dest_bug_id, 'project_id' );
410 $t_bug_relationship_data = array();
411 $t_relationship_count = db_num_rows( $result );
412 $t_bug_array = Array();
413 for( $i = 0;$i < $t_relationship_count;$i++
) {
414 $row = db_fetch_array( $result );
415 $t_bug_relationship_data[$i] = new BugRelationshipData
;
416 $t_bug_relationship_data[$i]->id
= $row['id'];
417 $t_bug_relationship_data[$i]->src_bug_id
= $row['source_bug_id'];
418 $t_bug_relationship_data[$i]->src_project_id
= $row['project_id'];
419 $t_bug_relationship_data[$i]->dest_bug_id
= $row['destination_bug_id'];
420 $t_bug_relationship_data[$i]->dest_project_id
= $t_dest_project_id;
421 $t_bug_relationship_data[$i]->type
= $row['relationship_type'];
422 $t_bug_array[] = $row['source_bug_id'];
424 unset( $t_bug_relationship_data[$t_relationship_count] );
426 if( !empty( $t_bug_array ) ) {
427 bug_cache_array_rows( $t_bug_array );
429 return $t_bug_relationship_data;
433 * get all relationships associated with the given bug
434 * @param int $p_bug_id Bug id
435 * @param bool &$p_is_different_projects Returned Boolean value indicating if some relationships cross project boundaries
436 * @return array Array of BugRelationshipData objects
438 function relationship_get_all( $p_bug_id, &$p_is_different_projects ) {
439 $t_src = relationship_get_all_src( $p_bug_id );
440 $t_dest = relationship_get_all_dest( $p_bug_id );
441 $t_all = array_merge( $t_src, $t_dest );
443 $p_is_different_projects = false;
444 $t_count = count( $t_all );
445 for( $i = 0;$i < $t_count;$i++
) {
446 $p_is_different_projects |
= ( $t_all[$i]->src_project_id
!= $t_all[$i]->dest_project_id
);
452 * check if there is a relationship between two bugs
453 * return id if found 0 otherwise
454 * @param int $p_src_bug_id Source Bug Id
455 * @param int $p_dest_bug_id Destination Bug Id
456 * @return int Relationship ID
458 function relationship_exists( $p_src_bug_id, $p_dest_bug_id ) {
459 $c_src_bug_id = db_prepare_int( $p_src_bug_id );
460 $c_dest_bug_id = db_prepare_int( $p_dest_bug_id );
462 $t_mantis_bug_relationship_table = db_get_table( 'bug_relationship' );
465 FROM $t_mantis_bug_relationship_table
467 (source_bug_id=" . db_param() . "
468 AND destination_bug_id=" . db_param() . ")
470 (source_bug_id=" . db_param() . "
471 AND destination_bug_id=" . db_param() . ')';
472 $result = db_query_bound( $t_query, array( $c_src_bug_id, $c_dest_bug_id, $c_dest_bug_id, $c_src_bug_id ), 1 );
474 $t_relationship_count = db_num_rows( $result );
476 if( $t_relationship_count == 1 ) {
478 # return the first id
479 $row = db_fetch_array( $result );
483 # no relationship found
489 * check if there is a relationship between two bugs
491 * 0 if the relationship is not found
492 * -1 if the relationship is found and it's of the same type $p_rel_type
493 * 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
494 * @param int $p_src_bug_id Source Bug Id
495 * @param int $p_dest_bug_id Destination Bug Id
496 * @param int $p_rel_type Relationship Type
497 * @return int 0, -1 or id
499 function relationship_same_type_exists( $p_src_bug_id, $p_dest_bug_id, $p_rel_type ) {
501 # Check if there is already a relationship set between them
502 $t_id_relationship = relationship_exists( $p_src_bug_id, $p_dest_bug_id );
504 if( $t_id_relationship > 0 ) {
507 # get all the relationship info
508 $t_relationship = relationship_get( $t_id_relationship );
510 if( $t_relationship->src_bug_id
== $p_src_bug_id && $t_relationship->dest_bug_id
== $p_dest_bug_id ) {
511 if( $t_relationship->type
== $p_rel_type ) {
512 $t_id_relationship = -1;
515 if( $t_relationship->type
== relationship_get_complementary_type( $p_rel_type ) ) {
516 $t_id_relationship = -1;
520 return $t_id_relationship;
524 * retrieve the linked bug id of the relationship: provide src -> return dest; provide dest -> return src
525 * @param int $p_relationship_id Relationship id
526 * @param int $p_bug_id Bug Id
527 * @return int Complementary bug id
529 function relationship_get_linked_bug_id( $p_relationship_id, $p_bug_id ) {
531 $t_bug_relationship_data = relationship_get( $p_relationship_id );
533 if( $t_bug_relationship_data->src_bug_id
== $p_bug_id ) {
534 return $t_bug_relationship_data->dest_bug_id
;
537 if( $t_bug_relationship_data->dest_bug_id
== $p_bug_id ) {
538 return $t_bug_relationship_data->src_bug_id
;
541 trigger_error( ERROR_RELATIONSHIP_NOT_FOUND
, ERROR
);
545 * get class description of a relationship (source side)
546 * @param int $p_relationship_type Relationship type
547 * @return string Relationship description
549 function relationship_get_description_src_side( $p_relationship_type ) {
550 global $g_relationships;
551 if( !isset( $g_relationships[$p_relationship_type] ) ) {
552 trigger_error( ERROR_RELATIONSHIP_NOT_FOUND
, ERROR
);
554 return lang_get( $g_relationships[$p_relationship_type]['#description'] );
558 * get class description of a relationship (destination side)
559 * @param int $p_relationship_type Relationship type
560 * @return string Relationship description
562 function relationship_get_description_dest_side( $p_relationship_type ) {
563 global $g_relationships;
564 if( !isset( $g_relationships[$p_relationship_type] ) ||
!isset( $g_relationships[$g_relationships[$p_relationship_type]['#complementary']] ) ) {
565 trigger_error( ERROR_RELATIONSHIP_NOT_FOUND
, ERROR
);
567 return lang_get( $g_relationships[$g_relationships[$p_relationship_type]['#complementary']]['#description'] );
571 * get class description of a relationship as it's stored in the history
572 * @param int $p_relationship_code Relationship Type
573 * @return string Relationship description
575 function relationship_get_description_for_history( $p_relationship_code ) {
576 return relationship_get_description_src_side( $p_relationship_code );
580 * return false if there are child bugs not resolved/closed
581 * N.B. we don't check if the parent bug is read-only. This is because the answer of this function is indepedent from
582 * the state of the parent bug itself.
583 * @param int $p_bug_id Bug id
586 function relationship_can_resolve_bug( $p_bug_id ) {
588 # retrieve all the relationships in which the bug is the source bug
589 $t_relationship = relationship_get_all_src( $p_bug_id );
590 $t_relationship_count = count( $t_relationship );
591 if( $t_relationship_count == 0 ) {
595 for( $i = 0;$i < $t_relationship_count;$i++
) {
597 # verify if each bug in relation BUG_DEPENDANT is already marked as resolved
598 if( $t_relationship[$i]->type
== BUG_DEPENDANT
) {
599 $t_dest_bug_id = $t_relationship[$i]->dest_bug_id
;
600 $t_status = bug_get_field( $t_dest_bug_id, 'status' );
601 if( $t_status < config_get( 'bug_resolved_status_threshold' ) ) {
603 # the bug is NOT marked as resolved/closed
613 * return formatted string with all the details on the requested relationship
614 * @param int $p_bug_id Bug id
615 * @param BugRelationshipData $p_relationship Relationsip object
616 * @param bool $p_html Generate html
617 * @param bool $p_html_preview ???? generate printable version???
618 * @param bool $p_show_project Show Project details
621 function relationship_get_details( $p_bug_id, $p_relationship, $p_html = false, $p_html_preview = false, $p_show_project = false ) {
622 $t_summary_wrap_at = utf8_strlen( config_get( 'email_separator2' ) ) - 28;
623 $t_icon_path = config_get( 'icon_path' );
625 if( $p_bug_id == $p_relationship->src_bug_id
) {
627 # root bug is in the src side, related bug in the dest side
628 $t_related_bug_id = $p_relationship->dest_bug_id
;
629 $t_related_project_name = project_get_name( $p_relationship->dest_project_id
);
630 $t_relationship_descr = relationship_get_description_src_side( $p_relationship->type
);
633 # root bug is in the dest side, related bug in the src side
634 $t_related_bug_id = $p_relationship->src_bug_id
;
635 $t_related_project_name = project_get_name( $p_relationship->src_project_id
);
636 $t_relationship_descr = relationship_get_description_dest_side( $p_relationship->type
);
639 # related bug not existing...
640 if( !bug_exists( $t_related_bug_id ) ) {
644 # user can access to the related bug at least as a viewer
645 if( !access_has_bug_level( VIEWER
, $t_related_bug_id ) ) {
649 if( $p_html_preview == false ) {
652 $t_td = '<td class="print">';
655 # get the information from the related bug and prepare the link
656 $t_bug = bug_get( $t_related_bug_id, false );
657 $t_status_string = get_enum_element( 'status', $t_bug->status
);
658 $t_resolution_string = get_enum_element( 'resolution', $t_bug->resolution
);
660 $t_relationship_info_html = $t_td . string_no_break( $t_relationship_descr ) . ' </td>';
661 if( $p_html_preview == false ) {
662 $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>';
663 $t_relationship_info_html .= '<td><span class="issue-status" title="' . string_attribute( $t_resolution_string ) . '">' . string_display_line( $t_status_string ) . '</span></td>';
665 $t_relationship_info_html .= $t_td . string_display_line( bug_format_id( $t_related_bug_id ) ) . '</td>';
666 $t_relationship_info_html .= $t_td . string_display_line( $t_status_string ) . ' </td>';
669 $t_relationship_info_text = utf8_str_pad( $t_relationship_descr, 20 );
670 $t_relationship_info_text .= utf8_str_pad( bug_format_id( $t_related_bug_id ), 8 );
672 # get the handler name of the related bug
673 $t_relationship_info_html .= $t_td;
674 if( $t_bug->handler_id
> 0 ) {
675 $t_relationship_info_html .= string_no_break( prepare_user_name( $t_bug->handler_id
) );
677 $t_relationship_info_html .= ' </td>';
680 if( $p_show_project ) {
681 $t_relationship_info_html .= $t_td . string_display_line( $t_related_project_name ) . ' </td>';
685 if( $p_html == true ) {
686 $t_relationship_info_html .= $t_td . string_display_line_links( $t_bug->summary
);
687 if( VS_PRIVATE
== $t_bug->view_state
) {
688 $t_relationship_info_html .= sprintf( ' <img src="%s" alt="(%s)" title="%s" />', $t_icon_path . 'protected.gif', lang_get( 'private' ), lang_get( 'private' ) );
691 if( utf8_strlen( $t_bug->summary
) <= $t_summary_wrap_at ) {
692 $t_relationship_info_text .= string_email_links( $t_bug->summary
);
694 $t_relationship_info_text .= utf8_substr( string_email_links( $t_bug->summary
), 0, $t_summary_wrap_at - 3 ) . '...';
698 # add delete link if bug not read only and user has access level
699 if( !bug_is_readonly( $p_bug_id ) && !current_user_is_anonymous() && ( $p_html_preview == false ) ) {
700 if( access_has_bug_level( config_get( 'update_bug_threshold' ), $p_bug_id ) ) {
701 $t_relationship_info_html .= ' [<a class="small" 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>]';
705 $t_relationship_info_html .= ' </td>';
706 $t_relationship_info_text .= "\n";
708 if( $p_html_preview == false ) {
709 # choose color based on status
710 $status_label = html_get_status_css_class( $t_bug->status
);
712 $t_relationship_info_html = '<tr class="' . $status_label . '">' . $t_relationship_info_html . '</tr>' . "\n";
714 $t_relationship_info_html = '<tr>' . $t_relationship_info_html . '</tr>';
717 if( $p_html == true ) {
718 return $t_relationship_info_html;
720 return $t_relationship_info_text;
725 * print ALL the RELATIONSHIPS OF A SPECIFIC BUG
726 * @param int $p_bug_id Bug id
729 function relationship_get_summary_html( $p_bug_id ) {
731 $t_show_project = false;
733 $t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
734 $t_relationship_all_count = count( $t_relationship_all );
736 # prepare the relationships table
737 for( $i = 0;$i < $t_relationship_all_count;$i++
) {
738 $t_summary .= relationship_get_details( $p_bug_id, $t_relationship_all[$i], true, false, $t_show_project );
741 if( !is_blank( $t_summary ) ) {
742 if( relationship_can_resolve_bug( $p_bug_id ) == false ) {
743 $t_summary .= '<tr class="row-2"><td colspan="' . ( 5 +
$t_show_project ) . '"><strong>' . lang_get( 'relationship_warning_blocking_bugs_not_resolved' ) . '</strong></td></tr>';
745 $t_summary = '<table width="100%" cellpadding="0" cellspacing="1">' . $t_summary . '</table>';
752 * print ALL the RELATIONSHIPS OF A SPECIFIC BUG
753 * @param int $p_bug_id Bug id
756 function relationship_get_summary_html_preview( $p_bug_id ) {
758 $t_show_project = false;
760 $t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
761 $t_relationship_all_count = count( $t_relationship_all );
763 # prepare the relationships table
764 for( $i = 0;$i < $t_relationship_all_count;$i++
) {
765 $t_summary .= relationship_get_details( $p_bug_id, $t_relationship_all[$i], true, true, $t_show_project );
768 if( !is_blank( $t_summary ) ) {
769 if( relationship_can_resolve_bug( $p_bug_id ) == false ) {
770 $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>';
772 $t_summary = '<table width="100%" cellpadding="0" cellspacing="1">' . $t_summary . '</table>';
779 * print ALL the RELATIONSHIPS OF A SPECIFIC BUG in text format (used by email_api.php
780 * @param int $p_bug_id Bug id
783 function relationship_get_summary_text( $p_bug_id ) {
785 $t_show_project = false;
787 $t_relationship_all = relationship_get_all( $p_bug_id, $t_show_project );
788 $t_relationship_all_count = count( $t_relationship_all );
790 # prepare the relationships table
791 for( $i = 0;$i < $t_relationship_all_count;$i++
) {
792 $t_summary .= relationship_get_details( $p_bug_id, $t_relationship_all[$i], false );
799 * print HTML relationship listbox
800 * @param int $p_default_rel_type Relationship Type (default -1)
801 * @param string $p_select_name List box name (default "rel_type")
802 * @param bool $p_include_any Include an ANY option in list box (default false)
803 * @param bool $p_include_none Include a NONE option in list box (default false)
804 * @param int $p_bug_id Bug id
807 function relationship_list_box( $p_default_rel_type = -1, $p_select_name = "rel_type", $p_include_any = false, $p_include_none = false ) {
808 global $g_relationships;
810 <select name
="<?php echo $p_select_name?>">
811 <?php
if( $p_include_any ) {?
>
812 <option value
="-1" <?php
echo( $p_default_rel_type == -1 ?
' selected="selected"' : '' )?
>>[<?php
echo lang_get( 'any' )?
>]</option
>
816 if( $p_include_none ) {?
>
817 <option value
="-2" <?php
echo( $p_default_rel_type == -2 ?
' selected="selected"' : '' )?
>>[<?php
echo lang_get( 'none' )?
>]</option
>
821 foreach( $g_relationships as $type => $relationship ) {
823 <option value
="<?php echo $type?>"<?php
echo( $p_default_rel_type == $type ?
' selected="selected"' : '' )?
>><?php
echo lang_get( $relationship['#description'] )?
></option
>
831 * print HTML relationship form
832 * @param int $p_bug_id Bug id
835 function relationship_view_box( $p_bug_id ) {
839 <?php
collapse_open( 'relationships' );?
>
840 <table
class="width100" cellspacing
="1">
842 <td width
="15%" class="form-title" colspan
="2">
844 collapse_icon( 'relationships' );
845 echo lang_get( 'bug_relationships' );
846 if( ON
== config_get( 'relationship_graph_enable' ) ) {
848 <span
class="small"><?php
print_bracket_link( "bug_relationship_graph.php?bug_id=$p_bug_id&graph=relation", lang_get( 'relation_graph' ) )?
></span
>
849 <span
class="small"><?php
print_bracket_link( "bug_relationship_graph.php?bug_id=$p_bug_id&graph=dependency", lang_get( 'dependency_graph' ) )?
></span
>
856 # bug not read-only and user authenticated
857 if( !bug_is_readonly( $p_bug_id ) ) {
859 # user access level at least updater
860 if( access_has_bug_level( config_get( 'update_bug_threshold' ), $p_bug_id ) ) {
863 <th
class="category"><?php
echo lang_get( 'add_new_relationship' )?
></th
>
864 <td
><?php
echo lang_get( 'this_bug' )?
>
865 <form method
="post" action
="bug_relationship_add.php">
866 <?php
echo form_security_field( 'bug_relationship_add' ) ?
>
867 <input type
="hidden" name
="src_bug_id" value
="<?php echo $p_bug_id?>" size
="4" />
868 <?php
relationship_list_box( -1 )?
>
869 <input type
="text" name
="dest_bug_id" value
="" />
870 <input type
="submit" name
="add_relationship" class="button" value
="<?php echo lang_get( 'add_new_relationship_button' )?>" />
878 <td colspan
="2"><?php
echo relationship_get_summary_html( $p_bug_id )?
></td
>
882 <?php
collapse_closed( 'relationships' );?
>
883 <table
class="width100" cellspacing
="1">
885 <td
class="form-title">
887 collapse_icon( 'relationships' );
888 echo lang_get( 'bug_relationships' );
895 collapse_end( 'relationships' );