Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved filter : none and not empty are available on custom fields a… #1670

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 42 additions & 16 deletions core/classes/BugFilterQuery.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,8 @@ protected function build_prop_reporter() {
* @return void
*/
protected function build_prop_handler() {
if( filter_field_is_any( $this->filter[FILTER_PROPERTY_HANDLER_ID] ) ) {
if( filter_field_is_any( $this->filter[FILTER_PROPERTY_HANDLER_ID] ) ||
( filter_field_is_not_empty( $this->filter[FILTER_PROPERTY_HANDLER_ID] ) && filter_field_is_none( $this->filter[FILTER_PROPERTY_HANDLER_ID] ) ) ) {
return;
}

Expand All @@ -850,10 +851,17 @@ protected function build_prop_handler() {
$t_view_condition = ' AND ' . $t_view_condition;
}

$t_user_ids = $this->helper_process_users_property( $this->filter[FILTER_PROPERTY_HANDLER_ID] );
$t_query = $this->sql_in( '{bug}.handler_id', $t_user_ids ) . $t_view_condition;
log_event( LOG_FILTERING, 'handler query = ' . $t_query );
$this->add_where( $t_query );
if( filter_field_is_not_empty( $this->filter[FILTER_PROPERTY_HANDLER_ID] ) ) {
//if empty, handler_id value is 0
$t_query = '{bug}.handler_id <> 0 ' . $t_view_condition;
log_event( LOG_FILTERING, 'handler query = ' . $t_query );
$this->add_where( $t_query );
} else {
$t_user_ids = $this->helper_process_users_property( $this->filter[FILTER_PROPERTY_HANDLER_ID] );
$t_query = $this->sql_in( '{bug}.handler_id', $t_user_ids ) . $t_view_condition;
log_event( LOG_FILTERING, 'handler query = ' . $t_query );
$this->add_where( $t_query );
}
}

/**
Expand Down Expand Up @@ -1074,11 +1082,10 @@ protected function build_prop_target_version() {
* @return void
*/
protected function build_prop_monitor_by() {
if( filter_field_is_any( $this->filter[FILTER_PROPERTY_MONITOR_USER_ID] ) ) {
if( filter_field_is_any( $this->filter[FILTER_PROPERTY_MONITOR_USER_ID] ) ||
( filter_field_is_not_empty( $this->filter[FILTER_PROPERTY_MONITOR_USER_ID] ) && filter_field_is_none( $this->filter[FILTER_PROPERTY_MONITOR_USER_ID] ) ) ) {
return;
}
$t_user_ids = $this->helper_process_users_property( $this->filter[FILTER_PROPERTY_MONITOR_USER_ID] );
$t_use_none = ( in_array( 0, $t_user_ids ) );

# Build a condition for determining monitoring visibility, the user can view:
# - his own monitored issues
Expand All @@ -1098,14 +1105,21 @@ protected function build_prop_monitor_by() {
}

$this->add_join( 'LEFT JOIN {bug_monitor} ON {bug}.id = {bug_monitor}.bug_id' . $t_view_condition );
if( $t_use_none ) {
$t_expr = 'COALESCE( {bug_monitor}.user_id, 0 )';
} else {
$t_expr = '{bug_monitor}.user_id';
if (filter_field_is_not_empty( $this->filter[FILTER_PROPERTY_MONITOR_USER_ID] ) ) {
$this->add_where('{bug_monitor}.user_id <> 0 ' );
} else {
$t_user_ids = $this->helper_process_users_property( $this->filter[FILTER_PROPERTY_MONITOR_USER_ID] );
$t_use_none = ( in_array( 0, $t_user_ids ) );

if( $t_use_none ) {
$t_expr = 'COALESCE( {bug_monitor}.user_id, 0 )';
} else {
$t_expr = '{bug_monitor}.user_id';
}
$t_where = $this->sql_in( $t_expr, $t_user_ids );
$this->add_where( $t_where );
}

$t_where = $this->sql_in( $t_expr, $t_user_ids );
$this->add_where( $t_where );
}

/**
Expand Down Expand Up @@ -1456,7 +1470,9 @@ protected function build_prop_custom_fields() {
continue;
}
# Ignore custom fields that are not set, or that are set to '' or "any"
if( filter_field_is_any( $t_field ) ) {
# Also ignore if "none" and "not empty" are both selected
if( filter_field_is_any( $t_field )
|| ( filter_field_is_not_empty( $t_field ) && filter_field_is_none( $t_field ) )) {
continue;
}

Expand Down Expand Up @@ -1488,8 +1504,18 @@ protected function build_prop_custom_fields() {
$t_filter_array = array();
foreach( $t_field as $t_filter_member ) {
$t_filter_member = stripslashes( $t_filter_member );
if( filter_field_is_none( $t_filter_member ) ) {
if( filter_field_is_not_empty( $t_filter_member ) ) {
switch( $t_def['type'] ) {
case CUSTOM_FIELD_TYPE_TEXTAREA:
array_push( $t_filter_array, $t_table_name . '.text <> "" AND ' . $t_table_name . '.text IS NOT NULL' );
break;
default;
array_push( $t_filter_array, $t_table_name . '.value <> "" AND ' . $t_table_name . '.value IS NOT NULL' );
}
continue;
} else if( filter_field_is_none( $t_filter_member ) ) {
# but also add those _not_ present in the custom field string table
#Note: custom_field_string_table.value is never null
$t_filter_array[] = $t_table_name . '.value IS NULL';

switch( $t_def['type'] ) {
Expand Down
1 change: 1 addition & 0 deletions core/constant_inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,7 @@
define( 'META_FILTER_MYSELF', -1 );
define( 'META_FILTER_NONE', - 2 );
define( 'META_FILTER_CURRENT', - 3 );
define( 'META_FILTER_NOT_EMPTY', - 4 );
define( 'META_FILTER_ANY', 0 );

# Filter view types
Expand Down
29 changes: 29 additions & 0 deletions core/filter_api.php
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,32 @@ function filter_field_is_none( $p_field_value ) {
return false;
}

/**
* Checks the supplied value to see if it is a NOT_EMPTY value.
* @param string $p_field_value The value to check.
* @return boolean true for "NOT_EMPTY" values and false for others.
* @todo is a check for these necessary? if( ( $t_filter_value === 'none' ) || ( $t_filter_value === '[none]' ) )
*/
function filter_field_is_not_empty( $p_field_value ) {
if( is_array( $p_field_value ) ) {
foreach( $p_field_value as $t_value ) {
if( ( META_FILTER_NOT_EMPTY == $t_value ) && ( is_numeric( $t_value ) ) ) {
return true;
}
}
} else {
if( is_string( $p_field_value ) && is_blank( $p_field_value ) ) {
return false;
}

if( ( META_FILTER_NOT_EMPTY == $p_field_value ) && ( is_numeric( $p_field_value ) ) ) {
return true;
}
}

return false;
}

/**
* Checks the supplied value to see if it is a MYSELF value.
* @param string $p_field_value The value to check.
Expand Down Expand Up @@ -673,6 +699,9 @@ function filter_ensure_valid_filter( array $p_filter_arr ) {
if( ( $t_value === 'none' ) || ( $t_value === '[none]' ) ) {
$t_value = META_FILTER_NONE;
}
if( ( $t_value === 'not empty' ) || ( $t_value === '[not empty]' ) ) {
$t_value = META_FILTER_EMPTY;
}
# Ensure the filter property has the right type - see #20087
switch( $p_type ) {
case 'string' :
Expand Down
139 changes: 47 additions & 92 deletions core/filter_form_api.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,31 +133,38 @@ function filter_select_modifier( array $p_filter ) {
}

/**
* Print the current value of this filter field, as visible string, and as a hidden form input.
* @param array $p_filter Filter array
* @internal Print the current value of this filter field, as visible string, and as a hidden form input.
* This function is used for reporter, handler and monitor filter
* @param array $p_filter Filter array
* @param string $p_filter_property property associated to the wanted field
* @param string $p_treshold the matching project level threshold
* @return void
*/
function print_filter_values_reporter_id( array $p_filter ) {
function print_filter_values_user_common( array $p_filter, $p_filter_property, $p_treshold) {
$t_filter = $p_filter;
$t_output = '';
$t_any_found = false;
if( count( $t_filter[FILTER_PROPERTY_REPORTER_ID] ) == 0 ) {
$t_none_found = false;
$t_not_empty_found = false;
if( count( $t_filter[$p_filter_property] ) == 0 ) {
echo lang_get( 'any' );
} else {
$t_first_flag = true;
foreach( $t_filter[FILTER_PROPERTY_REPORTER_ID] as $t_current ) {
foreach( $t_filter[$p_filter_property] as $t_current ) {
echo '<input type="hidden" name="', $p_filter_property, '[]" value="', string_attribute( $t_current ), '" />';
$t_this_name = '';
echo '<input type="hidden" name="', FILTER_PROPERTY_REPORTER_ID, '[]" value="', string_attribute( $t_current ), '" />';
if( filter_field_is_any( $t_current ) ) {
$t_any_found = true;
} else if( filter_field_is_not_empty( $t_current ) ) {
$t_not_empty_found = true;
} else if( filter_field_is_none( $t_current ) ) {
$t_none_found = true;
} else if( filter_field_is_myself( $t_current ) ) {
if( access_has_project_level( config_get( 'report_bug_threshold' ) ) ) {
if( access_has_project_level( config_get( $p_treshold ) ) ) {
$t_this_name = '[' . lang_get( 'myself' ) . ']';
} else {
$t_any_found = true;
}
} else if( filter_field_is_none( $t_current ) ) {
$t_this_name = lang_get( 'none' );
} else {
$t_this_name = user_get_name( $t_current );
}
Expand All @@ -168,14 +175,28 @@ function print_filter_values_reporter_id( array $p_filter ) {
}
$t_output = $t_output . string_display_line( $t_this_name );
}
if( true == $t_any_found ) {
#if none and not_empty are selected, any will be displayed
if( true == $t_any_found || (true == $t_none_found && true == $t_not_empty_found) ) {
echo lang_get( 'any' );
} else if( true == $t_none_found ) {
echo lang_get( 'none' );
} else if( true == $t_not_empty_found ) {
echo lang_get( 'not_empty' );
} else {
echo $t_output;
echo string_display( $t_output );
}
}
}

/**
* Print the current value of this filter field, as visible string, and as a hidden form input.
* @param array $p_filter Filter array
* @return void
*/
function print_filter_values_reporter_id( array $p_filter ) {
print_filter_values_user_common($p_filter, FILTER_PROPERTY_REPORTER_ID, 'report_bug_threshold');
}

/**
* Print the reporter field
* @global array $g_filter
Expand All @@ -190,8 +211,8 @@ function print_filter_reporter_id( array $p_filter = null ) {
?>
<select class="input-xs" <?php echo filter_select_modifier( $p_filter ) ?> name="<?php echo FILTER_PROPERTY_REPORTER_ID;?>[]">
<?php
# if current user is a reporter, and limited_reporters is set to ON, only display that name
if( access_has_limited_view() ) {
# if current user is a reporter, and limited_reporters is set to ON, only display that name
if( access_has_limited_view() ) {
$t_id = auth_get_current_user_id();
$t_username = user_get_name( $t_id );
$t_display_name = string_attribute( $t_username );
Expand All @@ -217,45 +238,7 @@ function print_filter_reporter_id( array $p_filter = null ) {
* @return void
*/
function print_filter_values_user_monitor( array $p_filter ) {
$t_filter = $p_filter;
$t_output = '';
$t_any_found = false;
$t_none_found = false;
if( count( $t_filter[FILTER_PROPERTY_MONITOR_USER_ID] ) == 0 ) {
echo lang_get( 'any' );
} else {
$t_first_flag = true;
foreach( $t_filter[FILTER_PROPERTY_MONITOR_USER_ID] as $t_current ) {
echo '<input type="hidden" name="', FILTER_PROPERTY_MONITOR_USER_ID, '[]" value="', string_attribute( $t_current ), '" />';
$t_this_name = '';
if( filter_field_is_any( $t_current ) ) {
$t_any_found = true;
} else if( filter_field_is_none( $t_current ) ) {
$t_none_found = true;
} else if( filter_field_is_myself( $t_current ) ) {
if( access_has_project_level( config_get( 'monitor_bug_threshold' ) ) ) {
$t_this_name = '[' . lang_get( 'myself' ) . ']';
} else {
$t_any_found = true;
}
} else {
$t_this_name = user_get_name( $t_current );
}
if( $t_first_flag != true ) {
$t_output = $t_output . '<br />';
} else {
$t_first_flag = false;
}
$t_output = $t_output . string_display_line( $t_this_name );
}
if( true == $t_any_found ) {
echo lang_get( 'any' );
} else if( true == $t_none_found ) {
echo lang_get( 'none' );
} else {
echo string_display( $t_output );
}
}
print_filter_values_user_common($p_filter, FILTER_PROPERTY_MONITOR_USER_ID, 'monitor_bug_threshold');
}

/**
Expand All @@ -273,6 +256,7 @@ function print_filter_user_monitor( array $p_filter = null ) {
<!-- Monitored by -->
<select class="input-xs" <?php echo filter_select_modifier( $p_filter ) ?> name="<?php echo FILTER_PROPERTY_MONITOR_USER_ID;?>[]">
<option value="<?php echo META_FILTER_ANY?>"<?php check_selected( $p_filter[FILTER_PROPERTY_MONITOR_USER_ID], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
<option value="<?php echo META_FILTER_NOT_EMPTY?>"<?php check_selected( $p_filter[FILTER_PROPERTY_MONITOR_USER_ID], META_FILTER_NOT_EMPTY );?>>[<?php echo lang_get( 'not_empty' )?>]</option>
<option value="<?php echo META_FILTER_NONE?>"<?php check_selected( $p_filter[FILTER_PROPERTY_MONITOR_USER_ID], META_FILTER_NONE );?>>[<?php echo lang_get( 'none' )?>]</option>
<?php
if( access_has_project_level( config_get( 'monitor_bug_threshold' ) ) ) {
Expand All @@ -296,42 +280,7 @@ function print_filter_user_monitor( array $p_filter = null ) {
* @return void
*/
function print_filter_values_handler_id( array $p_filter ) {
$t_filter = $p_filter;
$t_output = '';
$t_any_found = false;
if( count( $t_filter[FILTER_PROPERTY_HANDLER_ID] ) == 0 ) {
echo lang_get( 'any' );
} else {
$t_first_flag = true;
foreach( $t_filter[FILTER_PROPERTY_HANDLER_ID] as $t_current ) {
echo '<input type="hidden" name="', FILTER_PROPERTY_HANDLER_ID, '[]" value="', string_attribute( $t_current ), '" />';
$t_this_name = '';
if( filter_field_is_none( $t_current ) ) {
$t_this_name = lang_get( 'none' );
} else if( filter_field_is_any( $t_current ) ) {
$t_any_found = true;
} else if( filter_field_is_myself( $t_current ) ) {
if( access_has_project_level( config_get( 'handle_bug_threshold' ) ) ) {
$t_this_name = '[' . lang_get( 'myself' ) . ']';
} else {
$t_any_found = true;
}
} else {
$t_this_name = user_get_name( $t_current );
}
if( $t_first_flag != true ) {
$t_output = $t_output . '<br />';
} else {
$t_first_flag = false;
}
$t_output = $t_output . string_display_line( $t_this_name );
}
if( true == $t_any_found ) {
echo lang_get( 'any' );
} else {
echo string_display( $t_output );
}
}
print_filter_values_user_common($p_filter, FILTER_PROPERTY_HANDLER_ID, 'handle_bug_threshold');
}

/**
Expand All @@ -350,6 +299,7 @@ function print_filter_handler_id( array $p_filter = null ) {
<select class="input-xs" <?php echo filter_select_modifier( $p_filter ) ?> name="<?php echo FILTER_PROPERTY_HANDLER_ID;?>[]">
<option value="<?php echo META_FILTER_ANY?>"<?php check_selected( $p_filter[FILTER_PROPERTY_HANDLER_ID], META_FILTER_ANY );?>>[<?php echo lang_get( 'any' )?>]</option>
<?php if( access_has_project_level( config_get( 'view_handler_threshold' ) ) ) {?>
<option value="<?php echo META_FILTER_NOT_EMPTY?>"<?php check_selected( $p_filter[FILTER_PROPERTY_HANDLER_ID], META_FILTER_NOT_EMPTY );?>>[<?php echo lang_get( 'not_empty' )?>]</option>
<option value="<?php echo META_FILTER_NONE?>"<?php check_selected( $p_filter[FILTER_PROPERTY_HANDLER_ID], META_FILTER_NONE );?>>[<?php echo lang_get( 'none' )?>]</option>
<?php
if( access_has_project_level( config_get( 'handle_bug_threshold' ) ) ) {
Expand Down Expand Up @@ -1854,6 +1804,8 @@ function print_filter_values_custom_field( array $p_filter, $p_field_id ) {
$t_val = stripslashes( $t_val );
if( filter_field_is_none( $t_val ) ) {
$t_strings[] = lang_get( 'none' );
} else if( filter_field_is_not_empty( $t_val ) ) {
$t_strings[] = lang_get( 'not_empty' );
} else {
$t_strings[] = $t_val;
}
Expand Down Expand Up @@ -1954,19 +1906,22 @@ function print_filter_custom_field( $p_field_id, array $p_filter = null ) {
echo '<option value="' . META_FILTER_ANY . '"';
check_selected( $p_filter['custom_fields'][$p_field_id], META_FILTER_ANY, false );
echo '>[' . lang_get( 'any' ) . ']</option>';
# don't show META_FILTER_NONE for enumerated types as it's not possible for them to be blank
if( !in_array( $t_cfdef['type'], array( CUSTOM_FIELD_TYPE_ENUM, CUSTOM_FIELD_TYPE_LIST ) ) ) {
# don't show META_FILTER_NONE and META_FILTER_NOT_EMPTY for custom fields that are required at bug report
if(!$t_cfdef['require_report']) {
echo '<option value="' . META_FILTER_NONE . '"';
check_selected( $p_filter['custom_fields'][$p_field_id], META_FILTER_NONE, false );
echo '>[' . lang_get( 'none' ) . ']</option>';
}
echo '<option value="' . META_FILTER_NOT_EMPTY . '"';
check_selected( $p_filter['custom_fields'][$p_field_id], META_FILTER_NOT_EMPTY, false );
echo '>[' . lang_get( 'not_empty' ) . ']</option>';
}
# Print possible values
$t_included_projects = filter_get_included_projects( $p_filter );
$t_values = custom_field_distinct_values( $t_cfdef, $t_included_projects );
if( is_array( $t_values ) ){
$t_max_length = config_get( 'max_dropdown_length' );
foreach( $t_values as $t_val ) {
if( filter_field_is_any($t_val) || filter_field_is_none( $t_val ) ) {
if( filter_field_is_any($t_val) || filter_field_is_none( $t_val ) || filter_field_is_not_empty( $t_val ) ) {
continue;
}
echo '<option value="' . string_attribute( $t_val ) . '"';
Expand Down
1 change: 1 addition & 0 deletions core/helper_api.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ function helper_check_variables_equal( $p_var1, $p_var2, $p_strict ) {
# META_FILTER_MYSELF = -1
# META_FILTER_NONE = -2
# META_FILTER_CURRENT = -3
# META_FILTER_NOT_EMPTY = -4
# META_FILTER_ANY = 0
#
# For these reasons, a === comparison is required.
Expand Down