View Issue Details

IDProjectCategoryView StatusLast Update
0016774mantisbtcustomizationpublic2022-07-13 05:55
ReporterMr.Bricodage Assigned To 
PrioritynormalSeverityfeatureReproducibilityalways
Status newResolutionopen 
Product Version1.2.15 
Summary0016774: Ask for the Target version when an issue is confirmed
Description

With the provided modifications, Mantis can ask for the target version when a bug is confirmed and the status is changed to a predefined status.
The modification can be activated/desactived by using an ON/OFF flag in config file.
I hope that the following modifications may be usefull to others users, and may be integrated into a next Mantis release.

Steps To Reproduce

1) add the following content to "config_inc.php"

/**

  • Status used for a bug when the target version can be defined
  • @global int $gbug confirmed_status_threshold
    */
    $g_bug_confirmed_status_threshold = CONFIRMED;

    /**

  • Ask for target version
  • Set to ON if you wish to ask the target version when the bug is confirmed.
  • @global int $g_ask_target_version
    */
    $g_ask_target_version = ON;

2) Modify the file "bug_change_status_page.php"
2-1) Line 56 - add the following declaration :
$t_confirmed = config_get( 'bug_confirmed_status_threshold', null, null, $t_bug->project_id );

2-2)Line 184 - Add the following content (between "Assigned To" and due date sections)

<!-- Ask for Target Version in a list that contain only FUTURE versions (not released) -->
<?php
if ( config_get( 'ask_target_version' ) == ON ) {
if ( ( $f_new_status == $t_confirmed) ) {?>
<tr <?php echo helper_alternate_class() ?>>
<td class="category">
<?php echo lang_get( 'target_version' ) ?>
</td>
<td>
<select name="target_version">
<?php print_version_option_list( $t_bug->target_version, $t_bug->project_id, VERSION_FUTURE, false, false) ?>
</select>
</td>
</tr>
<?php }
}
?>

Additional Information

The attached file contain the modification made on file "bug_change_status_page.php" from mantis 1.2-15 version

Tagspatch
Attached Files
bug_change_status_page.php (12,516 bytes)   
<?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/>.

	/**
	 * @package MantisBT
	 * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
	 * @copyright Copyright (C) 2002 - 2013  MantisBT Team - mantisbt-dev@lists.sourceforge.net
	 * @link http://www.mantisbt.org
	 */
	 /**
	  * MantisBT Core API's
	  */

	$g_allow_browser_cache = 1;
	require_once( 'core.php' );

	require_once( 'bug_api.php' );
	require_once( 'custom_field_api.php' );

	require_once( 'relationship_api.php' );

	define ( 'BUG_VIEW_INC_ALLOW', true );

	$f_bug_id = gpc_get_int( 'id' );
	$t_bug = bug_get( $f_bug_id );

	$tpl_file = __FILE__;
	$tpl_mantis_dir = dirname( __FILE__ ) . DIRECTORY_SEPARATOR;
	$tpl_show_page_header = false;
	$tpl_force_readonly = true;
	$tpl_fields_config_option = 'bug_change_status_page_fields';

	if( $t_bug->project_id != helper_get_current_project() ) {
		# in case the current project is not the same project of the bug we are viewing...
		# ... override the current project. This to avoid problems with categories and handlers lists etc.
		$g_project_override = $t_bug->project_id;
	}

	$f_new_status = gpc_get_int( 'new_status' );
	$f_reopen_flag = gpc_get_int( 'reopen_flag', OFF );

	$t_reopen = config_get( 'bug_reopen_status', null, null, $t_bug->project_id );
	$t_confirmed = config_get( 'bug_confirmed_status_threshold', null, null, $t_bug->project_id );
	$t_resolved = config_get( 'bug_resolved_status_threshold', null, null, $t_bug->project_id );
	$t_closed = config_get( 'bug_closed_status_threshold', null, null, $t_bug->project_id );
	$t_current_user_id = auth_get_current_user_id();

	# Ensure user has proper access level before proceeding
	if( $f_new_status == $t_reopen && $f_reopen_flag ) {
		access_ensure_can_reopen_bug( $t_bug, $t_current_user_id );
	}
	else if( $f_new_status == $t_closed ) {
		access_ensure_can_close_bug( $t_bug, $t_current_user_id );
	}
	else if ( bug_is_readonly( $f_bug_id )
		|| !access_has_bug_level( access_get_status_threshold( $f_new_status, $t_bug->project_id ), $f_bug_id, $t_current_user_id ) ) {
		access_denied();
	}

	$t_can_update_due_date = access_has_bug_level( config_get( 'due_date_update_threshold' ), $f_bug_id );
	# get new issue handler if set, otherwise default to original handler
	$f_handler_id = gpc_get_int( 'handler_id', $t_bug->handler_id );

	if ( config_get( 'bug_assigned_status' ) == $f_new_status ) {
		$t_bug_sponsored = sponsorship_get_amount( sponsorship_get_all_ids( $f_bug_id ) ) > 0;
		if ( $t_bug_sponsored ) {
			if ( !access_has_bug_level( config_get( 'assign_sponsored_bugs_threshold' ), $f_bug_id ) ) {
				trigger_error( ERROR_SPONSORSHIP_ASSIGNER_ACCESS_LEVEL_TOO_LOW, ERROR );
			}
		}

		if ( $f_handler_id != NO_USER ) {
            if ( !access_has_bug_level( config_get( 'handle_bug_threshold' ), $f_bug_id, $f_handler_id ) ) {
				trigger_error( ERROR_HANDLER_ACCESS_TOO_LOW, ERROR );
			}

			if ( $t_bug_sponsored ) {
				if ( !access_has_bug_level( config_get( 'handle_sponsored_bugs_threshold' ), $f_bug_id, $f_handler_id ) ) {
					trigger_error( ERROR_SPONSORSHIP_HANDLER_ACCESS_LEVEL_TOO_LOW, ERROR );
				}
			}
		}
	}

	$t_status_label = str_replace( " ", "_", MantisEnum::getLabel( config_get( 'status_enum_string' ), $f_new_status ) );

	html_page_top( bug_format_summary( $f_bug_id, SUMMARY_CAPTION ) );

	print_recently_visited();
?>

<br />
<div align="center">
<form method="post" action="bug_update.php">
<?php echo form_security_field( 'bug_update' ) ?>
<table class="width75" cellspacing="1">


<!-- Title -->
<tr>
	<td class="form-title" colspan="2">
		<input type="hidden" name="bug_id" value="<?php echo $f_bug_id ?>" />
		<input type="hidden" name="status" value="<?php echo $f_new_status ?>" />
		<?php echo lang_get( $t_status_label . '_bug_title' ) ?>
	</td>
</tr>

<?php
	if ( $t_resolved <= $f_new_status ) {
		if ( relationship_can_resolve_bug( $f_bug_id ) == false ) {
			echo "<tr><td colspan=\"2\">" . lang_get( 'relationship_warning_blocking_bugs_not_resolved_2' ) . "</td></tr>";
		}
	}
?>

<?php
$t_current_resolution = $t_bug->resolution;
$t_bug_is_open = in_array( $t_current_resolution, array( config_get( 'default_bug_resolution' ), config_get( 'bug_reopen_resolution' ) ) );
if ( ( $t_resolved <= $f_new_status ) && ( ( $t_closed > $f_new_status ) || ( $t_bug_is_open ) ) ) { ?>
<!-- Resolution -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'resolution' ) ?>
	</td>
	<td>
		<select name="resolution">
			<?php
				$t_resolution = $t_bug_is_open ? config_get( 'bug_resolution_fixed_threshold' ) : $t_current_resolution;
				print_enum_string_option_list( "resolution", $t_resolution );
			?>
		</select>
	</td>
</tr>
<?php } ?>

<?php
if ( ( $t_resolved <= $f_new_status ) && ( $t_closed > $f_new_status ) ) { ?>
<!-- Duplicate ID -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'duplicate_id' ) ?>
	</td>
	<td>
		<input type="text" name="duplicate_id" maxlength="10" />
	</td>
</tr>
<?php } ?>

<?php
if ( access_has_bug_level( config_get( 'update_bug_assign_threshold', config_get( 'update_bug_threshold' ) ), $f_bug_id ) ) {
	$t_suggested_handler_id = $t_bug->handler_id;

	if ( $t_suggested_handler_id == NO_USER && access_has_bug_level( config_get( 'handle_bug_threshold' ), $f_bug_id ) ) {
		$t_suggested_handler_id = $t_current_user_id;
	}
?>
<!-- Assigned To -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'assigned_to' ) ?>
	</td>
	<td>
		<select name="handler_id">
			<option value="0"></option>
			<?php print_assign_to_option_list( $t_suggested_handler_id, $t_bug->project_id ) ?>
		</select>
	</td>
</tr>
<?php } ?>

<!-- Ask for Target Version in a list that contain only FUTURE versions (not released) -->
<?php
if ( config_get( 'ask_target_version' ) == ON ) {
	if ( ( $f_new_status == $t_confirmed) ) {?>
		<tr <?php echo helper_alternate_class() ?>>
			<td class="category">
				<?php echo lang_get( 'target_version' ) ?>
			</td>
			<td>
				<select name="target_version">
					<?php print_version_option_list( $t_bug->target_version, $t_bug->project_id, VERSION_FUTURE, false,false ) ?>
				</select>
			</td>
		</tr>
	<?php } 
}
?>

<?php if ( $t_can_update_due_date ) {
	$t_date_to_display = '';
	if ( !date_is_null( $t_bug->due_date ) ) {
			$t_date_to_display = date( config_get( 'calendar_date_format' ), $t_bug->due_date );
	}
?>
<!-- Due date -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php print_documentation_link( 'due_date' ) ?>
	</td>
	<td>
	<?php
	    print "<input ".helper_get_tab_index()." type=\"text\" id=\"due_date\" name=\"due_date\" size=\"20\" maxlength=\"16\" value=\"".$t_date_to_display."\" />";
		date_print_calendar();
	?>
	</td>
</tr>
<?php } ?>

<!-- Custom Fields -->
<?php
/** @todo thraxisp - I undid part of the change for #5068 for #5527
 * We really need to say what fields are shown in which statusses. For now,
 * this page will show required custom fields in update mode, or
 *  display or required fields on resolve or close
 */
$t_custom_status_label = "update"; # Don't show custom fields by default
if ( ( $f_new_status == $t_resolved ) &&
			( $t_closed > $f_new_status ) ) {
	$t_custom_status_label = "resolved";
}
if ( $t_closed == $f_new_status ) {
	$t_custom_status_label = "closed";
}

$t_related_custom_field_ids = custom_field_get_linked_ids( $t_bug->project_id );

foreach( $t_related_custom_field_ids as $t_id ) {
	$t_def = custom_field_get_definition( $t_id );
	$t_display = $t_def['display_' . $t_custom_status_label];
	$t_require = $t_def['require_' . $t_custom_status_label];

	if ( ( "update" == $t_custom_status_label ) && ( !$t_require ) ) {
		continue;
	}
	if ( in_array( $t_custom_status_label, array( "resolved", "closed" ) ) && !( $t_display || $t_require ) ) {
		continue;
	}
	if ( custom_field_has_write_access( $t_id, $f_bug_id ) ) {
?>
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php if ( $t_require ) {?><span class="required">*</span><?php } echo lang_get_defaulted( $t_def['name'] ) ?>
	</td>
	<td>
		<?php
			print_custom_field_input( $t_def, $f_bug_id );
		?>
	</td>
</tr>
<?php
	} #  custom_field_has_write_access( $t_id, $f_bug_id ) )
	else if ( custom_field_has_read_access( $t_id, $f_bug_id ) ) {
?>
	<tr <?php echo helper_alternate_class() ?>>
		<td class="category">
			<?php echo lang_get_defaulted( $t_def['name'] ) ?>
		</td>
		<td>
			<?php print_custom_field_value( $t_def, $t_id, $f_bug_id );			?>
		</td>
	</tr>
<?php
	} # custom_field_has_read_access( $t_id, $f_bug_id ) )
} # foreach( $t_related_custom_field_ids as $t_id )
?>

<?php
if ( ( $f_new_status >= $t_resolved ) ) {
	if (   version_should_show_product_version( $t_bug->project_id )
		&& !bug_is_readonly( $f_bug_id )
		&& access_has_bug_level( config_get( 'update_bug_threshold' ), $f_bug_id )
	) {
?>
<!-- Fixed in Version -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'fixed_in_version' ) ?>
	</td>
	<td>
		<select name="fixed_in_version">
			<?php print_version_option_list( $t_bug->fixed_in_version, $t_bug->project_id, VERSION_ALL ) ?>
		</select>
	</td>
</tr>
<?php
	}
}
?>

<?php
if ( ( $f_new_status >= $t_resolved ) && ( $t_closed > $f_new_status ) ) { ?>
<!-- Close Immediately (if enabled) -->
<?php if ( ( ON == config_get( 'allow_close_immediately' ) )
				&& ( access_has_bug_level( access_get_status_threshold( $t_closed, $t_bug->project_id ), $f_bug_id ) ) ) { ?>
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'close_immediately' ) ?>
	</td>
	<td>
		<input type="checkbox" name="close_now" />
	</td>
</tr>
<?php } ?>
<?php } ?>

<?php
	if ( ON == $f_reopen_flag ) {
?>
<!-- Bug was re-opened -->
<?php
		printf("	<input type=\"hidden\" name=\"resolution\" value=\"%s\" />\n",  config_get( 'bug_reopen_resolution' ) );
	}
?>

<?php event_signal( 'EVENT_UPDATE_BUG_STATUS_FORM', array( $f_bug_id ) ); ?>

<!-- Bugnote -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'add_bugnote_title' ) ?>
	</td>
	<td class="center">
		<textarea name="bugnote_text" cols="80" rows="10"></textarea>
	</td>
</tr>
<?php if ( access_has_bug_level( config_get( 'private_bugnote_threshold' ), $f_bug_id ) ) { ?>
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'view_status' ) ?>
	</td>
	<td>
<?php
		$t_default_bugnote_view_status = config_get( 'default_bugnote_view_status' );
		if ( access_has_bug_level( config_get( 'set_view_status_threshold' ), $f_bug_id ) ) {
?>
			<input type="checkbox" name="private" <?php check_checked( $t_default_bugnote_view_status, VS_PRIVATE ); ?> />
<?php
			echo lang_get( 'private' );
		} else {
			echo get_enum_element( 'project_view_state', $t_default_bugnote_view_status );
		}
?>
	</td>
</tr>
<?php } ?>

<?php if ( config_get('time_tracking_enabled') ) { ?>
<?php if ( access_has_bug_level( config_get( 'private_bugnote_threshold' ), $f_bug_id ) ) { ?>
<?php if ( access_has_bug_level( config_get( 'time_tracking_edit_threshold' ), $f_bug_id ) ) { ?>
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'time_tracking' ) ?> (HH:MM)
	</td>
	<td>
		<input type="text" name="time_tracking" size="5" value="0:00" />
	</td>
</tr>
<?php } ?>
<?php } ?>
<?php } ?>

<?php event_signal( 'EVENT_BUGNOTE_ADD_FORM', array( $f_bug_id ) ); ?>

<!-- Submit Button -->
<tr>
	<td class="center" colspan="2">
		<input type="submit" class="button" value="<?php echo lang_get( $t_status_label . '_bug_button' ) ?>" />
	</td>
</tr>


</table>
</form>
</div>

<?php
if ( $t_can_update_due_date ) {
	date_finish_calendar( 'due_date', 'trigger');
}

echo '<br />';

include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'bug_view_inc.php' );
bug_change_status_page.php (12,516 bytes)   
bug_change_status_page_new.php (12,595 bytes)   
<?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/>.

	/**
	 * @package MantisBT
	 * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
	 * @copyright Copyright (C) 2002 - 2013  MantisBT Team - mantisbt-dev@lists.sourceforge.net
	 * @link http://www.mantisbt.org
	 */
	 /**
	  * MantisBT Core API's
	  */

	$g_allow_browser_cache = 1;
	require_once( 'core.php' );

	require_once( 'bug_api.php' );
	require_once( 'custom_field_api.php' );

	require_once( 'relationship_api.php' );

	define ( 'BUG_VIEW_INC_ALLOW', true );

	$f_bug_id = gpc_get_int( 'id' );
	$t_bug = bug_get( $f_bug_id );

	$tpl_file = __FILE__;
	$tpl_mantis_dir = dirname( __FILE__ ) . DIRECTORY_SEPARATOR;
	$tpl_show_page_header = false;
	$tpl_force_readonly = true;
	$tpl_fields_config_option = 'bug_change_status_page_fields';

	if( $t_bug->project_id != helper_get_current_project() ) {
		# in case the current project is not the same project of the bug we are viewing...
		# ... override the current project. This to avoid problems with categories and handlers lists etc.
		$g_project_override = $t_bug->project_id;
	}

	$f_new_status = gpc_get_int( 'new_status' );
	$f_reopen_flag = gpc_get_int( 'reopen_flag', OFF );

	$t_reopen = config_get( 'bug_reopen_status', null, null, $t_bug->project_id );
	$t_confirmed = config_get( 'bug_confirmed_status', null, null, $t_bug->project_id );
	$t_resolved = config_get( 'bug_resolved_status_threshold', null, null, $t_bug->project_id );
	$t_closed = config_get( 'bug_closed_status_threshold', null, null, $t_bug->project_id );
	$t_current_user_id = auth_get_current_user_id();

	# Ensure user has proper access level before proceeding
	if( $f_new_status == $t_reopen && $f_reopen_flag ) {
		access_ensure_can_reopen_bug( $t_bug, $t_current_user_id );
	}
	else if( $f_new_status == $t_closed ) {
		access_ensure_can_close_bug( $t_bug, $t_current_user_id );
	}
	else if ( bug_is_readonly( $f_bug_id )
		|| !access_has_bug_level( access_get_status_threshold( $f_new_status, $t_bug->project_id ), $f_bug_id, $t_current_user_id ) ) {
		access_denied();
	}

	$t_can_update_due_date = access_has_bug_level( config_get( 'due_date_update_threshold' ), $f_bug_id );
	# get new issue handler if set, otherwise default to original handler
	$f_handler_id = gpc_get_int( 'handler_id', $t_bug->handler_id );

	if ( config_get( 'bug_assigned_status' ) == $f_new_status ) {
		$t_bug_sponsored = sponsorship_get_amount( sponsorship_get_all_ids( $f_bug_id ) ) > 0;
		if ( $t_bug_sponsored ) {
			if ( !access_has_bug_level( config_get( 'assign_sponsored_bugs_threshold' ), $f_bug_id ) ) {
				trigger_error( ERROR_SPONSORSHIP_ASSIGNER_ACCESS_LEVEL_TOO_LOW, ERROR );
			}
		}

		if ( $f_handler_id != NO_USER ) {
            if ( !access_has_bug_level( config_get( 'handle_bug_threshold' ), $f_bug_id, $f_handler_id ) ) {
				trigger_error( ERROR_HANDLER_ACCESS_TOO_LOW, ERROR );
			}

			if ( $t_bug_sponsored ) {
				if ( !access_has_bug_level( config_get( 'handle_sponsored_bugs_threshold' ), $f_bug_id, $f_handler_id ) ) {
					trigger_error( ERROR_SPONSORSHIP_HANDLER_ACCESS_LEVEL_TOO_LOW, ERROR );
				}
			}
		}
	}

	$t_status_label = str_replace( " ", "_", MantisEnum::getLabel( config_get( 'status_enum_string' ), $f_new_status ) );

	html_page_top( bug_format_summary( $f_bug_id, SUMMARY_CAPTION ) );

	print_recently_visited();
?>

<br />
<div align="center">
<form method="post" action="bug_update.php">
<?php echo form_security_field( 'bug_update' ) ?>
<table class="width75" cellspacing="1">


<!-- Title -->
<tr>
	<td class="form-title" colspan="2">
		<input type="hidden" name="bug_id" value="<?php echo $f_bug_id ?>" />
		<input type="hidden" name="status" value="<?php echo $f_new_status ?>" />
		<?php echo lang_get( $t_status_label . '_bug_title' ) ?>
	</td>
</tr>

<?php
	if ( $t_resolved <= $f_new_status ) {
		if ( relationship_can_resolve_bug( $f_bug_id ) == false ) {
			echo "<tr><td colspan=\"2\">" . lang_get( 'relationship_warning_blocking_bugs_not_resolved_2' ) . "</td></tr>";
		}
	}
?>

<?php
$t_current_resolution = $t_bug->resolution;
$t_bug_is_open = in_array( $t_current_resolution, array( config_get( 'default_bug_resolution' ), config_get( 'bug_reopen_resolution' ) ) );
if ( ( $t_resolved <= $f_new_status ) && ( ( $t_closed > $f_new_status ) || ( $t_bug_is_open ) ) ) { ?>
<!-- Resolution -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'resolution' ) ?>
	</td>
	<td>
		<select name="resolution">
			<?php
				$t_resolution = $t_bug_is_open ? config_get( 'bug_resolution_fixed_threshold' ) : $t_current_resolution;
				print_enum_string_option_list( "resolution", $t_resolution );
			?>
		</select>
	</td>
</tr>
<?php } ?>

<?php
if ( ( $t_resolved <= $f_new_status ) && ( $t_closed > $f_new_status ) ) { ?>
<!-- Duplicate ID -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'duplicate_id' ) ?>
	</td>
	<td>
		<input type="text" name="duplicate_id" maxlength="10" />
	</td>
</tr>
<?php } ?>

<?php
if ( access_has_bug_level( config_get( 'update_bug_assign_threshold', config_get( 'update_bug_threshold' ) ), $f_bug_id ) ) {
	$t_suggested_handler_id = $t_bug->handler_id;

	if ( $t_suggested_handler_id == NO_USER && access_has_bug_level( config_get( 'handle_bug_threshold' ), $f_bug_id ) ) {
		$t_suggested_handler_id = $t_current_user_id;
	}
?>
<!-- Assigned To -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'assigned_to' ) ?>
	</td>
	<td>
		<select name="handler_id">
			<option value="0"></option>
			<?php print_assign_to_option_list( $t_suggested_handler_id, $t_bug->project_id ) ?>
		</select>
	</td>
</tr>
<?php } ?>

<!-- Update Target Version (only Future versions are displayed) -->
<?php if ( access_has_bug_level( config_get( 'roadmap_update_threshold' ), $f_bug_id ) ) { ?>

	<?php
	if ( config_get( 'ask_target_version' ) == ON ) {
		if ( ( $f_new_status == $t_confirmed) ) {?>
			<tr <?php echo helper_alternate_class() ?>>
				<td class="category">
					<?php echo lang_get( 'target_version' ) ?>
				</td>
				<td>
					<select name="target_version">
						<?php print_version_option_list( $t_bug->target_version, $t_bug->project_id, VERSION_FUTURE, false,false ) ?>
					</select>
				</td>
			</tr>
		<?php } 
	}
} ?>

<?php if ( $t_can_update_due_date ) {
	$t_date_to_display = '';
	if ( !date_is_null( $t_bug->due_date ) ) {
			$t_date_to_display = date( config_get( 'calendar_date_format' ), $t_bug->due_date );
	}
?>
<!-- Due date -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php print_documentation_link( 'due_date' ) ?>
	</td>
	<td>
	<?php
	    print "<input ".helper_get_tab_index()." type=\"text\" id=\"due_date\" name=\"due_date\" size=\"20\" maxlength=\"16\" value=\"".$t_date_to_display."\" />";
		date_print_calendar();
	?>
	</td>
</tr>
<?php } ?>

<!-- Custom Fields -->
<?php
/** @todo thraxisp - I undid part of the change for #5068 for #5527
 * We really need to say what fields are shown in which statusses. For now,
 * this page will show required custom fields in update mode, or
 *  display or required fields on resolve or close
 */
$t_custom_status_label = "update"; # Don't show custom fields by default
if ( ( $f_new_status == $t_resolved ) &&
			( $t_closed > $f_new_status ) ) {
	$t_custom_status_label = "resolved";
}
if ( $t_closed == $f_new_status ) {
	$t_custom_status_label = "closed";
}

$t_related_custom_field_ids = custom_field_get_linked_ids( $t_bug->project_id );

foreach( $t_related_custom_field_ids as $t_id ) {
	$t_def = custom_field_get_definition( $t_id );
	$t_display = $t_def['display_' . $t_custom_status_label];
	$t_require = $t_def['require_' . $t_custom_status_label];

	if ( ( "update" == $t_custom_status_label ) && ( !$t_require ) ) {
		continue;
	}
	if ( in_array( $t_custom_status_label, array( "resolved", "closed" ) ) && !( $t_display || $t_require ) ) {
		continue;
	}
	if ( custom_field_has_write_access( $t_id, $f_bug_id ) ) {
?>
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php if ( $t_require ) {?><span class="required">*</span><?php } echo lang_get_defaulted( $t_def['name'] ) ?>
	</td>
	<td>
		<?php
			print_custom_field_input( $t_def, $f_bug_id );
		?>
	</td>
</tr>
<?php
	} #  custom_field_has_write_access( $t_id, $f_bug_id ) )
	else if ( custom_field_has_read_access( $t_id, $f_bug_id ) ) {
?>
	<tr <?php echo helper_alternate_class() ?>>
		<td class="category">
			<?php echo lang_get_defaulted( $t_def['name'] ) ?>
		</td>
		<td>
			<?php print_custom_field_value( $t_def, $t_id, $f_bug_id );			?>
		</td>
	</tr>
<?php
	} # custom_field_has_read_access( $t_id, $f_bug_id ) )
} # foreach( $t_related_custom_field_ids as $t_id )
?>

<?php
if ( ( $f_new_status >= $t_resolved ) ) {
	if (   version_should_show_product_version( $t_bug->project_id )
		&& !bug_is_readonly( $f_bug_id )
		&& access_has_bug_level( config_get( 'update_bug_threshold' ), $f_bug_id )
	) {
?>
<!-- Fixed in Version -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'fixed_in_version' ) ?>
	</td>
	<td>
		<select name="fixed_in_version">
			<?php print_version_option_list( $t_bug->fixed_in_version, $t_bug->project_id, VERSION_ALL ) ?>
		</select>
	</td>
</tr>
<?php
	}
}
?>

<?php
if ( ( $f_new_status >= $t_resolved ) && ( $t_closed > $f_new_status ) ) { ?>
<!-- Close Immediately (if enabled) -->
<?php if ( ( ON == config_get( 'allow_close_immediately' ) )
				&& ( access_has_bug_level( access_get_status_threshold( $t_closed, $t_bug->project_id ), $f_bug_id ) ) ) { ?>
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'close_immediately' ) ?>
	</td>
	<td>
		<input type="checkbox" name="close_now" />
	</td>
</tr>
<?php } ?>
<?php } ?>

<?php
	if ( ON == $f_reopen_flag ) {
?>
<!-- Bug was re-opened -->
<?php
		printf("	<input type=\"hidden\" name=\"resolution\" value=\"%s\" />\n",  config_get( 'bug_reopen_resolution' ) );
	}
?>

<?php event_signal( 'EVENT_UPDATE_BUG_STATUS_FORM', array( $f_bug_id ) ); ?>

<!-- Bugnote -->
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'add_bugnote_title' ) ?>
	</td>
	<td class="center">
		<textarea name="bugnote_text" cols="80" rows="10"></textarea>
	</td>
</tr>
<?php if ( access_has_bug_level( config_get( 'private_bugnote_threshold' ), $f_bug_id ) ) { ?>
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'view_status' ) ?>
	</td>
	<td>
<?php
		$t_default_bugnote_view_status = config_get( 'default_bugnote_view_status' );
		if ( access_has_bug_level( config_get( 'set_view_status_threshold' ), $f_bug_id ) ) {
?>
			<input type="checkbox" name="private" <?php check_checked( $t_default_bugnote_view_status, VS_PRIVATE ); ?> />
<?php
			echo lang_get( 'private' );
		} else {
			echo get_enum_element( 'project_view_state', $t_default_bugnote_view_status );
		}
?>
	</td>
</tr>
<?php } ?>

<?php if ( config_get('time_tracking_enabled') ) { ?>
<?php if ( access_has_bug_level( config_get( 'private_bugnote_threshold' ), $f_bug_id ) ) { ?>
<?php if ( access_has_bug_level( config_get( 'time_tracking_edit_threshold' ), $f_bug_id ) ) { ?>
<tr <?php echo helper_alternate_class() ?>>
	<td class="category">
		<?php echo lang_get( 'time_tracking' ) ?> (HH:MM)
	</td>
	<td>
		<input type="text" name="time_tracking" size="5" value="0:00" />
	</td>
</tr>
<?php } ?>
<?php } ?>
<?php } ?>

<?php event_signal( 'EVENT_BUGNOTE_ADD_FORM', array( $f_bug_id ) ); ?>

<!-- Submit Button -->
<tr>
	<td class="center" colspan="2">
		<input type="submit" class="button" value="<?php echo lang_get( $t_status_label . '_bug_button' ) ?>" />
	</td>
</tr>


</table>
</form>
</div>

<?php
if ( $t_can_update_due_date ) {
	date_finish_calendar( 'due_date', 'trigger');
}

echo '<br />';

include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'bug_view_inc.php' );
bug_change_status_page_new.php (12,595 bytes)   
MandatoryFields.php (4,480 bytes)   
<?php

class MandatoryFieldsPlugin extends MantisPlugin {

	function register() {
                $this->name = 'MandatoryFilelds';
                $this->description = 'Mandatory fields severity, projection';
                $this->page = '';
                $this->version = '1.0';
                $this->requires = array(
                    'MantisCore' => '1.3.0',
                    );                
                $this->author = 'carlos proensa';
        }

        function hooks() {
                return array(
                'EVENT_VIEW_BUG_DETAILS' => 'viewBugDetails',
		'EVENT_UPDATE_BUG_STATUS_FORM' => 'updateBugStatusForm',
                'EVENT_UPDATE_BUG_DATA' => 'updateBugData'
                );
        }

	function updateBugStatusForm($p_event,$p_bug_id){
	    $f_bug = bug_get( $p_bug_id, false );
	  ?>
	  <tr <?php echo helper_alternate_class() ?>>
                        <td class="category">
                                <span class="required">*</span><?php echo lang_get( 'severity' ) ?> 
                </td>
                        <td>
                                <select name="severity"> 
                                                <?php print_enum_string_option_list( 'severity', $f_bug->severity )?> 
                                </select>
                        </td>
                </tr>
        
                <tr <?php echo helper_alternate_class() ?>>
                        <td class="category">
                                <span class="required">*</span><?php echo lang_get( 'projection' ) ?>
                </td>
                        <td>
                                <select name="projection">
                                        <?php print_enum_string_option_list( 'projection', $f_bug->projection ) ?>
                                </select>
                        </td>
	  </tr>
	  <?php

	}

        function updateBugData($p_event, $p_bug_upd_data, $p_bug_data){
            if ( $p_bug_upd_data->status == RESOLVED ){
                $t_severity= $p_bug_upd_data->severity;
                $t_projection= $p_bug_upd_data->projection;
                
                if ($t_severity == 0) {
                        error_parameters(lang_get('severity'));
                        trigger_error( ERROR_CUSTOM_FIELD_INVALID_VALUE, ERROR );
                }
                if ($t_projection == 0) {
                        error_parameters(lang_get('projection'));
                        trigger_error( ERROR_CUSTOM_FIELD_INVALID_VALUE, ERROR );
                }
            }
            return $p_bug_upd_data;
        }
        
        #
        # Evento al escribir la pagina de view_bug, para escrbir informacion extra
        #
        function viewBugDetails($p_event, $p_bug_id){
                $f_bug = bug_get( $p_bug_id, false );
                $f_user_id = auth_get_current_user_id();
                $f_access_level =  user_get_access_level($f_user_id, $f_bug->project_id);
                $f_severity = $f_bug->severity;
                $f_projection= $f_bug->projection;
        
                #
                # Muestra un aviso si falta rellenar campos de severity o projection
                # y si el usuario tiene permisos > informador
                #
                if ( $f_access_level > REPORTER && ($f_severity==0 || $f_projection==0) ){
                        $str= '';
                        $num_err= 0;
                        if ($f_severity == 0) {
                                $valid= false;
                                $str= $str . lang_get( 'severity' );
                                $num_err++;
                        }
                        if ($f_projection == 0) {
                                $valid= false;
                                if ($num_err>0) $str= $str . ', ';
                                $str= $str . lang_get( 'projection' );
                                $num_err++;
                        }
                        if ($num_err>1)
                                $str = "Recuerde que los campos: $str, deben estar informados antes de resolver";
                        else
                                $str = "Recuerde que el campo $str debe estar informado antes de resolver";
                        
                echo '<tr><td colspan="6">';
                echo '<span style="color:red">' . $str . '</span>';
                echo '</td></tr>';
                }

        }



}
MandatoryFields.php (4,480 bytes)   

Activities

atrol

atrol

2013-12-31 06:37

developer   ~0038947

Thanks for your contribution.

Some hints:

If you want a threshold ($g_bug_confirmed_status_threshold) you should check $f_new_status >= $t_confirmed
If you want a distinct value you should rename the variable to $g_bug_confirmed_status

You are not checking any access rights, thus the field will also be shown to users without rights to change this field.

Mr.Bricodage

Mr.Bricodage

2014-01-02 23:02

reporter   ~0038953

thank you for your feedback.
the variable "$g_bug_confirmed_status_threshold" has been renamed "$g_bug_confirmed_status"

access rights are now checked by the following line :
<?php if ( access_has_bug_level( config_get( 'roadmap_update_threshold' ), $f_bug_id ) ) { ?>

"roadmap_update_threshold" already exists and is listed in "config_defaults_inc.php" as threshold for updating target_version

The new "bug_change_status_page.php" is attached

atrol

atrol

2014-01-03 13:47

developer   ~0038962

You should consider also the access checks which where used for "Fixed in Version"
<pre>
if ( version_should_show_product_version( $t_bug->project_id )
&& !bug_is_readonly( $f_bug_id )
&& access_has_bug_level( config_get( 'update_bug_threshold' ), $f_bug_id )
) {
</pre>

atrol

atrol

2014-04-06 07:09

developer   ~0039832

PR https://github.com/mantisbt/mantisbt/pull/157

grangeway

grangeway

2014-04-06 07:25

reporter   ~0039837

Can we merge this into one config variable?

grangeway

grangeway

2014-04-06 07:31

reporter   ~0039838

i.e.

$g_bug_confirmed_status_threshold = CLOSED+9999999999
is the same as setting:

$g_ask_target_version = ON;
$g_bug_confirmed_status_threshold = CONFIRMED;

Obviously, we need to work out how to add support for a new constant that represents "CLOSED+9999999999"

I know on the side of access levels/users I did have some patches that try to merge some of the ON+EVERYBODY config's to just EVERYBODY (on the basis that NOBODY exists).

If we had a similar NOSTATUS+EVERYSTATUS concept for status values we could do a similar config simplification exercise. Alternatively, we work on accepting this patch as is, then make merging/renaming/deprecating one of the config options a future change afterwards.

atrol

atrol

2014-04-06 08:26

developer   ~0039839

Can we merge this into one config variable?
Good idea

But we are not talking about a threshold.
Mr.Bricodage implemented a distinct status value in his pull request.

We would need something like: $g_ask_target_version_on_status = STATUS_NONE to disable the functionality.

A more generic approach would be to implement a status functionality similar to the access level functionality (Workflow Thresholds)
Have a matrix which fields are displayed depending on status.

grangeway

grangeway

2014-04-06 09:06

reporter   ~0039840

nod - and thinking about it, you probably need that.

For instance, on our bug tracker, we have 'acknowledged', 'confirmed' and 'assigned' - I'd probably be inclined to think that if you acknowledge an issue you probably are accepting that it exists, but don't know when/how/who is going to fix it.

If you are confirming an issue or assigning and issue, that probably implies there's a good likelihood that you are going to target a fix - and straight away the scope of this patch does not allow that as you'd need to allow an array for target_status - hence, we probably need the "matrix" approach.

Mr.Bricodage

Mr.Bricodage

2015-06-17 17:20

reporter   ~0050926

New PR : https://github.com/mantisbt/mantisbt/pull/611

Kyle_Katarn

Kyle_Katarn

2015-06-21 09:18

reporter   ~0050952

Nice !
Will it be in 1.2.20 ?

atrol

atrol

2015-06-21 14:37

developer   ~0050953

Will it be in 1.2.20 ?
No, maybe in 1.3.x

New PR https://github.com/mantisbt/mantisbt/pull/612

Kyle_Katarn

Kyle_Katarn

2015-06-21 15:30

reporter   ~0050955

ok

Mr.Bricodage

Mr.Bricodage

2016-01-20 14:08

reporter   ~0052340

Hello dev team,

could you please tell me if you plan to merge this PR into Mantis 1.3 ?
My company really need these functionnality, but I don't want to deploy a hack if it is not integrated into mantis master (for future upgrade).

Many thanks in advance for your feedback.

Mr.Bricodage

Mr.Bricodage

2016-01-20 18:19

reporter   ~0052341

PR 612 updated with Mantis 1.3.0-rc.2-dev code to reduce integration effort

atrol

atrol

2016-01-21 02:18

developer   ~0052343

You are breaking some of our coding rules [1] and I am missing documentation in Administrators Guide.

But wait with changing anything as there should be a discussion with other core team members if this approach makes sense in general.

There must also be the discussion if this change should make it's way in 1.3.x.
Keep in mind that we are near 1.3.0 rc2, so this is not a good moment to introduce new features.

[1] https://www.mantisbt.org/wiki/doku.php/mantisbt:coding_guidelines

atrol

atrol

2016-01-21 02:18

developer   ~0052344

Reminder sent to: cproensa, dregad, vboctor

Thoughts?

cproensa

cproensa

2016-01-21 04:14

developer   ~0052345

Hello, my thoughts:
Regarding this functionality, i'd rather see implemented a more general method of configuration for any native field, in the line of what its currently done with custom fields. One can specify if the field is shown and/or required by resolution/state.

Also, if this functionality is implemented (for native fields), this also should be configurable per project, like custom fields are now.
This would make configuration by global variables too cumbersome, so probably better to have it as a manage page and stored in db config.*

(*) If a plugin that can provide all this configuration and functionality is developed, i feel it would be a nice addition as a default plugin!

In summary, i dont feel it's positive to integrate into master the functionality for only one field, and the method proposed is not clean enough to generalize on more fields.

However, what is intended with this PR could be done with a plugin.
I attach a (very crude) plugin that i used to make 'severity' and 'projection' fields shown on bug update, and required to resolve.
That could get an idea of how to proceed with a customized plugin, and can be extended to have proper configuration and more options. Note that html is using the v1.2 styles.

atrol

atrol

2016-01-21 04:29

developer   ~0052346

this also should be configurable per project

Isn't it?
config_get is used to get the enums, which means that you can set the options also in database per project.

cproensa

cproensa

2016-01-21 04:34

developer   ~0052347

config_get is used to get the enums, which means that you can set the options also in database per project.

you are right. I was parallelizing with custom fields functionality, where there is a manage page to easily configure "per project".

vboctor

vboctor

2016-01-21 12:31

manager   ~0052349

We have to similar patterns:

  • $g_bug_view_page_fields (and one for similar pages), we even have $g_bug_change_status_page_fields.
  • $g_view_issues_page_columns (and ones for similar pages)

They both are configs that take the set of fields that are to be displayed for a specific page. So instead of field to pages map, we have page to fields map.

So for this case, I think we can do the following:
$g_whatever_name_we_choose[target_status_code] = array( field1, field2 )

Once we have this, we immediately get the customization that is required here. And for me I don't like that Close doesn't show duplicate_id field, but Resolve does. So if you want to set up a duplicate, you can't close directly.

Now, once the above is in place, the override can happen in the database per project. We can also have a UI that control such config variables. We just have to be careful with the UI, since we typically had a lot of bugs trying to model the concept of global configs and overrides per project. We also have to make sure that when we are retrieving such configs we are passing the right config context that is based on the issue being updated and not current project for example.

vboctor

vboctor

2016-01-21 12:36

manager   ~0052350

One thing I don't like about our pattern is that the customization of a page copies the list of all fields on that page and updates it. Hence, if a new field ever gets added to the default list of fields, it will be OFF by default. The good news is that we haven't done that forever.

The approach recommended here is more friendly to addition of new default fields. Since the new field will have the default set of pages that it appears on, and hence the default intended behavior will be used.

It is likely that this ship has sailed, but thought I would give both sides of the argument, though I'm not in favor of having two ways of doing such configuration. Changing the way we do it, may be painful for upgrades. So sticking with what we have should work.

cproensa

cproensa

2016-01-21 19:27

developer   ~0052351

Last edited: 2016-01-21 19:29

So for this case, I think we can do the following:
$g_whatever_name_we_choose[target_status_code] = array( field1, field2 )

I'd like to see native fields and custom field go closer in capabilities.
This would mean also to be able to configure a native field as required for some status change (and defining what does mean "required", or if it makes sense for all field types)
Note that custom fields currently can be defined as shown/required, not exactly by status, but actions like "on report", "on close", etc.

And... in that scenario, would it make sense to move the show/required options out from custom field management, and integrate them in this more general config schema?

cproensa

cproensa

2016-01-21 19:38

developer   ~0052352

And for actuallly helping @Mr.Bricodage

My company really need these functionnality, but I don't want to deploy a hack if it is not integrated into mantis master (for future upgrade).

I think your should try doing it with a plugin. That way you don't need to modify any code in mantis base, and your upgrade path is clean.

See EVENT_UPDATE_BUG_STATUS_FORM to display fields on the status update form
and EVENT_UPDATE_BUG_DATA if a check for "required" fields is needed.

vboctor

vboctor

2016-01-23 00:28

manager   ~0052365

At we support custom_xyz in the field lists we use for column configuration options for View Issues, Print Issues, CSV, and Excel exports. So we already do support custom fields in such case the same way we support native fields. Users can select the set of fields to show, and in any order.

However, we don't have the same for for the list of fields to show on different forms and we have a restriction of defining the order of custom fields relative to each other and only at the end of the list.

I'm totally with you in providing a UI that enable controlling such configurations from the UI and treats custom fields and native fields the same way. So user can:

  • Configure the fields on report, update, change status, view, etc.
  • Configure the fields on pages like View Issues, Print Issues, Excel, CSV. Our current UI is not really user friendly.
  • In both cases, it should be possible to interleave or work with the unique of all fields (custom/native).
Mr.Bricodage

Mr.Bricodage

2016-09-21 09:16

reporter   ~0054054

@cproensa : thank you for your sample plugin. That helped me a lot ;-)

I attached the modified plugin I use in my company that answer to your needs.
I don't use EVENT_UPDATE_BUG_DATA (Mantis 1.3) cause I'm still on 1.2.x
I'll try to post here a new version after migration.

I didn't understand all responses provided above. I don't know if the attached solution is compliant with your Thoughts that seems to be more complex.

I think that Mantis should display identically at least all versions fields (product_version, target_version, fixed_in_version).

Regards

Mr.Bricodage

Mr.Bricodage

2018-03-02 17:26

reporter   ~0059070

attached : the same plugin for Mantis 1.3

Kyle_Katarn

Kyle_Katarn

2018-03-03 03:08

reporter   ~0059073

What about Mantis 2.11 ?