View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0011097 | mantisbt | custom fields | public | 2009-10-29 04:52 | 2010-04-23 23:22 |
Reporter | liebscher | Assigned To | vboctor | ||
Priority | high | Severity | minor | Reproducibility | always |
Status | closed | Resolution | duplicate | ||
Platform | Linux | ||||
Product Version | 1.1.6 | ||||
Summary | 0011097: Offer Custom Fields (String) with maxLength > 255 characters and displayed as TEXTAREA | ||||
Description | Custom fields should have a maxLength of 1024 characters. | ||||
Steps To Reproduce | Custom fields can be set to a length > 255 characters, but are always displayed as single line INPUT and cut at 255 characters during save. | ||||
Additional Information | We customized our Mantis installation this way: Modify the file mantis/core/custom_field_api.php (changed marked with '# MX'): MX START: treat maxLength > 255 as textarea
| ||||
Tags | patch | ||||
Attached Files | custom_field_api.php.patch (93,489 bytes)
--- C:/mX_fileshares/Projects/mobileX-MIP/Misc/Mantis/custom_field_api.php Mi Okt 28 07:36:07 2009 +++ C:/mX_fileshares/Projects/mobileX-MIP/Misc/Mantis/custom_field_api_1.1.6.php Di Dez 9 20:20:28 2008 @@ -1,1340 +1,1332 @@ -<?php -# Mantis - a php based bugtracking system - -# Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org -# Copyright (C) 2002 - 2007 Mantis Team - mantisbt-dev@lists.sourceforge.net - -# Mantis 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. -# -# Mantis 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 Mantis. If not, see <http://www.gnu.org/licenses/>. - - # -------------------------------------------------------- - # $Id: custom_field_api.php,v 1.66.2.1 2007-10-13 22:35:21 giallu Exp $ - # -------------------------------------------------------- - - $t_core_dir = dirname( __FILE__ ).DIRECTORY_SEPARATOR; - - require_once( $t_core_dir . 'bug_api.php' ); - require_once( $t_core_dir . 'helper_api.php' ); - require_once( $t_core_dir . 'date_api.php' ); - - ### Custom Fields API ### - -#******************************************* -# TODO -# - add an object to store field data like BugData and UserPrefs ? -# - add caching functions like user, bug, etc -# - make existing api functions use caching functions -# - add functions to return individual db columns for a field definition -#******************************************* - - #=================================== - # Caching - #=================================== - - ######################################### - # SECURITY NOTE: cache globals are initialized here to prevent them - # being spoofed if register_globals is turned on - - $g_cache_custom_field = array(); - $g_cache_cf_list = NULL; - $g_cache_cf_linked = array(); - - # Cache a custom field row if necessary and return the cached copy - # If the second parameter is true (default), trigger an error - # if the field can't be found. If the second parameter is - # false, return false if the field can't be found. - function custom_field_cache_row( $p_field_id, $p_trigger_errors=true ) { - global $g_cache_custom_field; - - $c_field_id = db_prepare_int( $p_field_id ); - - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - - if ( isset ( $g_cache_custom_field[$c_field_id] ) ) { - return $g_cache_custom_field[$c_field_id]; - } - - $query = "SELECT * - FROM $t_custom_field_table - WHERE id='$c_field_id'"; - $result = db_query( $query ); - - if ( 0 == db_num_rows( $result ) ) { - if ( $p_trigger_errors ) { - error_parameters( 'Custom ' . $p_field_id ); - trigger_error( ERROR_CUSTOM_FIELD_NOT_FOUND, ERROR ); - } else { - return false; - } - } - - $row = db_fetch_array( $result ); - - $g_cache_custom_field[$c_field_id] = $row; - - return $row; - } - - # -------------------- - # Clear the custom field cache (or just the given id if specified) - function custom_field_clear_cache( $p_field_id = null ) { - global $g_cache_custom_field, $g_cached_custom_field_lists; - - $g_cached_custom_field_lists = null; - - if ( null === $p_field_id ) { - $g_cache_custom_field = array(); - } else { - $c_field_id = db_prepare_int( $p_field_id ); - unset( $g_cache_custom_field[$c_field_id] ); - } - - return true; - } - - - #=================================== - # Boolean queries and ensures - #=================================== - - # -------------------- - # Check to see whether the field is included in the given project - # return true if the field is included, false otherwise - # - function custom_field_is_linked( $p_field_id, $p_project_id ) { - $c_project_id = db_prepare_int( $p_project_id ); - $c_field_id = db_prepare_int( $p_field_id ); - - # figure out if this bug_id/field_id combination exists - $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); - $query = "SELECT COUNT(*) - FROM $t_custom_field_project_table - WHERE field_id='$c_field_id' AND - project_id='$c_project_id'"; - $result = db_query( $query ); - $count = db_result( $result ); - - if ( $count > 0 ) { - return true; - } else { - return false; - } - } - - # -------------------- - # Check to see whether the field id is defined - # return true if the field is defined, false otherwise - function custom_field_exists( $p_field_id ) { - if ( false == custom_field_cache_row( $p_field_id, false ) ) { - return false; - } else { - return true; - } - } - - # -------------------- - # Return the type of a custom field if it exists. - function custom_field_type( $p_field_id ) { - $t_field = custom_field_cache_row( $p_field_id, false ) ; - if ( $t_field == false ) { - return -1 ; - } else { - return $t_field[ 'type' ] ; - } - } - - # -------------------- - # Check to see whether the field id is defined - # return true if the field is defined, error otherwise - function custom_field_ensure_exists( $p_field_id ) { - if ( custom_field_exists( $p_field_id ) ) { - return true; - } else { - error_parameters( 'Custom ' . $p_field_id ); - trigger_error( ERROR_CUSTOM_FIELD_NOT_FOUND, ERROR ); - } - } - - # -------------------- - # Check to see whether the name is unique - # return false if a field with the name already exists, true otherwise - # if an id is specified, then the corresponding record is excluded from the - # uniqueness test. - function custom_field_is_name_unique( $p_name, $p_custom_field_id = null ) { - $c_name = db_prepare_string( $p_name ); - - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - $query = "SELECT COUNT(*) - FROM $t_custom_field_table - WHERE name='$c_name'"; - if ( $p_custom_field_id !== null ) { - $c_id = db_prepare_int( $p_custom_field_id ); - $query .= " AND (id <> $c_id)"; - } - $result = db_query( $query ); - $count = db_result( $result ); - - if ( $count > 0 ) { - return false; - } else { - return true; - } - } - - # -------------------- - # Check to see whether the name is unique - # return true if the name has not been used, error otherwise - function custom_field_ensure_name_unique( $p_name ) { - if ( custom_field_is_name_unique( $p_name ) ) { - return true; - } else { - trigger_error( ERROR_CUSTOM_FIELD_NAME_NOT_UNIQUE, ERROR ); - } - } - - # -------------------- - # Return true if the user can read the value of the field for the given bug, - # false otherwise. - function custom_field_has_read_access( $p_field_id, $p_bug_id, $p_user_id = null ) { - custom_field_ensure_exists( $p_field_id ); - - if ( null === $p_user_id ) { - $p_user_id = auth_get_current_user_id(); - } - - $t_access_level_r = custom_field_get_field( $p_field_id, 'access_level_r' ); - - $t_project_id = bug_get_field( $p_bug_id, 'project_id' ); - - return access_has_project_level( $t_access_level_r, $t_project_id, $p_user_id ); - } - - # -------------------- - # Return true if the user can modify the value of the field for the given project, - # false otherwise. - function custom_field_has_write_access_to_project( $p_field_id, $p_project_id, $p_user_id = null ) { - custom_field_ensure_exists( $p_field_id ); - - if ( null === $p_user_id ) { - $p_user_id = auth_get_current_user_id(); - } - - $t_access_level_rw = custom_field_get_field( $p_field_id, 'access_level_rw' ); - - return access_has_project_level( $t_access_level_rw, $p_project_id, $p_user_id ); - } - - # -------------------- - # Return true if the user can modify the value of the field for the given bug, - # false otherwise. - function custom_field_has_write_access( $p_field_id, $p_bug_id, $p_user_id = null ) { - $t_project_id = bug_get_field( $p_bug_id, 'project_id' ); - return ( custom_field_has_write_access_to_project( $p_field_id, $t_project_id, $p_user_id ) ); - } - - #=================================== - # Creation / Deletion / Updating - #=================================== - - # -------------------- - # create a new custom field with the name $p_name - # the definition are the default values and can be changes later - # return the ID of the new definition - function custom_field_create( $p_name ) { - if ( string_contains_scripting_chars( $p_name ) ) { - trigger_error( ERROR_CUSTOM_FIELD_INVALID_DEFINITION, ERROR ); - } - - $c_name = db_prepare_string( trim( $p_name ) ); - - if ( is_blank( $c_name ) ) { - error_parameters( 'name' ); - trigger_error( ERROR_EMPTY_FIELD, ERROR ); - } - - custom_field_ensure_name_unique( $c_name ); - - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - $query = "INSERT INTO $t_custom_field_table - ( name ) - VALUES - ( '$c_name' )"; - - db_query( $query ); - - return db_insert_id( $t_custom_field_table ); - } - - # -------------------- - # Update the field definition - # return true on success, false on failure - function custom_field_update( $p_field_id, $p_def_array ) { - if ( string_contains_scripting_chars( $p_def_array['name'] ) ) { - trigger_error( ERROR_CUSTOM_FIELD_INVALID_DEFINITION, ERROR ); - } - - $c_field_id = db_prepare_int( $p_field_id ); - $c_name = db_prepare_string( trim( $p_def_array['name'] ) ); - $c_type = db_prepare_int( $p_def_array['type'] ); - $c_possible_values = db_prepare_string( $p_def_array['possible_values'] ); - $c_default_value = db_prepare_string( $p_def_array['default_value'] ); - $c_valid_regexp = db_prepare_string( $p_def_array['valid_regexp'] ); - $c_access_level_r = db_prepare_int( $p_def_array['access_level_r'] ); - $c_access_level_rw = db_prepare_int( $p_def_array['access_level_rw'] ); - $c_length_min = db_prepare_int( $p_def_array['length_min'] ); - $c_length_max = db_prepare_int( $p_def_array['length_max'] ); - $c_advanced = db_prepare_bool( $p_def_array['advanced'] ); - $c_display_report = db_prepare_bool( $p_def_array['display_report'] ); - $c_display_update = db_prepare_bool( $p_def_array['display_update'] ); - $c_display_resolved = db_prepare_bool( $p_def_array['display_resolved'] ); - $c_display_closed = db_prepare_bool( $p_def_array['display_closed'] ); - $c_require_report = db_prepare_bool( $p_def_array['require_report'] ); - $c_require_update = db_prepare_bool( $p_def_array['require_update'] ); - $c_require_resolved = db_prepare_bool( $p_def_array['require_resolved'] ); - $c_require_closed = db_prepare_bool( $p_def_array['require_closed'] ); - - if ( is_blank( $c_name ) ) { - error_parameters( 'name' ); - trigger_error( ERROR_EMPTY_FIELD, ERROR ); - } - - if (( $c_access_level_rw < $c_access_level_r ) || - ( $c_length_min < 0 ) || - ( ( $c_length_max != 0 ) && ( $c_length_min > $c_length_max ) ) ) { - trigger_error( ERROR_CUSTOM_FIELD_INVALID_DEFINITION, ERROR ); - } - - if ( $c_advanced == true && ( $c_require_report == true || $c_require_update ) ) { - trigger_error( ERROR_CUSTOM_FIELD_INVALID_DEFINITION, ERROR ); - } - - if ( !custom_field_is_name_unique( $c_name, $c_field_id ) ) { - trigger_error( ERROR_CUSTOM_FIELD_NAME_NOT_UNIQUE, ERROR ); - } - - $t_update_something = false; - $t_mantis_custom_field_table = config_get( 'mantis_custom_field_table' ); - $query = "UPDATE $t_mantis_custom_field_table - SET "; - if( array_key_exists( 'name', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "name='$c_name'"; - } - if( array_key_exists( 'type', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "type='$c_type'"; - } - if( array_key_exists( 'possible_values', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "possible_values='$c_possible_values'"; - } - if( array_key_exists( 'default_value', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "default_value='$c_default_value'"; - } - if( array_key_exists( 'valid_regexp', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "valid_regexp='$c_valid_regexp'"; - } - if( array_key_exists( 'access_level_r', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "access_level_r='$c_access_level_r'"; - } - if( array_key_exists( 'access_level_rw', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "access_level_rw='$c_access_level_rw'"; - } - if( array_key_exists( 'length_min', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "length_min='$c_length_min'"; - } - if( array_key_exists( 'length_max', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "length_max='$c_length_max'"; - } - if( array_key_exists( 'advanced', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "advanced='$c_advanced'"; - } - if( array_key_exists( 'display_report', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "display_report='$c_display_report'"; - } - if( array_key_exists( 'display_update', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "display_update='$c_display_update'"; - } - if( array_key_exists( 'display_resolved', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "display_resolved='$c_display_resolved'"; - } - if( array_key_exists( 'display_closed', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "display_closed='$c_display_closed'"; - } - if( array_key_exists( 'require_report', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "require_report='$c_require_report'"; - } - if( array_key_exists( 'require_update', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "require_update='$c_require_update'"; - } - if( array_key_exists( 'require_resolved', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "require_resolved='$c_require_resolved'"; - } - if( array_key_exists( 'require_closed', $p_def_array ) ) { - if ( !$t_update_something ) { - $t_update_something = true; - } else { - $query .= ', '; - } - $query .= "require_closed='$c_require_closed'"; - } - - - $query .= " WHERE id='$c_field_id'"; - - if( $t_update_something ) { - db_query( $query ); - custom_field_clear_cache( $p_field_id ); - } else { - return false; # there is nothing to update... - } - - # db_query() errors on failure so: - return true; - } - - # -------------------- - # Add a custom field to a project - # return true on success, false on failure or if already added - function custom_field_link( $p_field_id, $p_project_id ) { - $c_field_id = db_prepare_int( $p_field_id ); - $c_project_id = db_prepare_int( $p_project_id ); - - custom_field_ensure_exists( $p_field_id ); - project_ensure_exists( $p_project_id ); - - if ( custom_field_is_linked( $p_field_id, $p_project_id ) ) { - return false; - } - - $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); - $query = "INSERT INTO $t_custom_field_project_table - ( field_id, project_id ) - VALUES - ( '$c_field_id', '$c_project_id' )"; - db_query( $query ); - - # db_query() errors on failure so: - return true; - } - - # -------------------- - # Remove a custom field from a project - # return true on success, false on failure - # - # The values for the custom fields are not deleted. This is to allow for the - # case where a bug is moved to another project that has the field, or the - # field is linked again to the project. - function custom_field_unlink( $p_field_id, $p_project_id ) { - $c_field_id = db_prepare_int( $p_field_id ); - $c_project_id = db_prepare_int( $p_project_id ); - - $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); - $query = "DELETE FROM $t_custom_field_project_table - WHERE field_id = '$c_field_id' AND - project_id = '$c_project_id'"; - db_query( $query ); - - # db_query() errors on failure so: - return true; - } - - # -------------------- - # Delete the field definition and all associated values and project - # associations - # return true on success, false on failure - function custom_field_destroy( $p_field_id ) { - $c_field_id = db_prepare_int( $p_field_id ); - - # delete all values - $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); - $query = "DELETE FROM $t_custom_field_string_table - WHERE field_id='$c_field_id'"; - db_query( $query ); - - # delete all project associations - $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); - $query = "DELETE FROM $t_custom_field_project_table - WHERE field_id='$c_field_id'"; - db_query( $query ); - - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - # delete the definition - $query = "DELETE FROM $t_custom_field_table - WHERE id='$c_field_id'"; - db_query( $query ); - - custom_field_clear_cache( $p_field_id ); - - # db_query() errors on failure so: - return true; - } - - # -------------------- - # Delete all associations of custom fields to the specified project - # return true on success, false on failure - # - # To be called from within project_delete(). - function custom_field_unlink_all( $p_project_id ) { - $c_project_id = db_prepare_int( $p_project_id ); - - # delete all project associations - $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); - $query = "DELETE FROM $t_custom_field_project_table - WHERE project_id='$c_project_id'"; - db_query( $query ); - - # db_query() errors on failure so: - return true; - } - - # -------------------- - # Delete all custom values associated with the specified bug. - # return true on success, false on failure - # - # To be called from bug_delete(). - function custom_field_delete_all_values( $p_bug_id ) { - $c_bug_id = db_prepare_int( $p_bug_id ); - - $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); - $query = "DELETE FROM $t_custom_field_string_table - WHERE bug_id='$c_bug_id'"; - db_query( $query ); - - #db_query() errors on failure so: - return true; - } - - #=================================== - # Data Access - #=================================== - - # -------------------- - # Get the id of the custom field with the specified name. - # false is returned if no custom field found with the specified name. - function custom_field_get_id_from_name( $p_field_name, $p_truncated_length = null ) { - if ( $p_field_name == '' ) { - return false; - } - - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - - $c_field_name = db_prepare_string( $p_field_name ); - - if ( ( null === $p_truncated_length ) || ( strlen( $c_field_name ) != $p_truncated_length ) ) { - $query = "SELECT id FROM $t_custom_field_table WHERE name = '$c_field_name'"; - } else { - # @@@ This is to handle the case where we only have a truncated part of the name. This happens in the case where - # we are getting the custom field name from the history logs, since history is 32 and custom field name is 64. - # This fix will handle entries already in the database, future entries should be handled by making the field name max lengths match. - $query = "SELECT id FROM $t_custom_field_table WHERE name LIKE '$c_field_name%'"; - } - - $t_result = db_query( $query, 1 ); - - if ( db_num_rows( $t_result ) == 0 ) { - return false; - } - - $row = db_fetch_array( $t_result ); - - return $row['id']; - } - - # -------------------- - # Return an array of ids of custom fields bound to the specified project - # - # The ids will be sorted based on the sequence number associated with the binding - function custom_field_get_linked_ids( $p_project_id = ALL_PROJECTS ) { - global $g_cache_cf_linked; - - if ( ! isset( $g_cache_cf_linked[$p_project_id] ) ) { - - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); - - if ( ALL_PROJECTS == $p_project_id ) { - $t_project_user_list_table = config_get( 'mantis_project_user_list_table' ); - $t_project_table = config_get( 'mantis_project_table' ); - $t_user_table = config_get( 'mantis_user_table' ); - $t_user_id = auth_get_current_user_id(); - $t_pub = VS_PUBLIC; - $t_priv = VS_PRIVATE; - - $t_private_access = config_get( 'private_project_threshold' ); - if ( is_array( $t_private_access ) ) { - if ( 1 == count( $t_private_access ) ) { - $t_access_clause = "= " . array_shift( $t_private_access ) . " "; - } else { - $t_access_clause = "IN (" . implode( ',', $t_private_access ) . ")"; - } - } else { - $t_access_clause = ">= $t_private_access "; - } - - - # select only the ids that the user has some access to - # e.g., all fields in public projects, or private projects where the user is listed - # or private projects where the user is implicitly listed - $query = "SELECT cft.id as id, cft.name as name - FROM $t_custom_field_table as cft, $t_user_table ut, $t_project_table pt, $t_custom_field_project_table cfpt - LEFT JOIN $t_project_user_list_table pult - on cfpt.project_id = pult.project_id and pult.user_id = $t_user_id - WHERE cft.id = cfpt.field_id AND cfpt.project_id = pt.id AND ut.id = $t_user_id AND - ( pt.view_state = $t_pub OR - ( pt.view_state = $t_priv and pult.user_id = $t_user_id ) OR - ( pult.user_id is null and ut.access_level $t_access_clause ) ) - GROUP BY cft.id, cft.name - ORDER BY cft.name ASC"; - } else { - if ( is_array( $p_project_id ) ) { - if ( 1 == count( $p_project_id ) ) { - $t_project_clause = "= " . array_shift( $p_project_id ) . " "; - } else { - $t_project_clause = "IN (" . implode( ',', $p_project_id ) . ")"; - } - } else { - $t_project_clause = "= $p_project_id "; - } - $query = "SELECT cft.id, cft.name, cfpt.sequence - FROM $t_custom_field_table cft, $t_custom_field_project_table cfpt - WHERE cfpt.project_id $t_project_clause AND - cft.id = cfpt.field_id - ORDER BY sequence ASC, name ASC"; - } - $result = db_query( $query ); - $t_row_count = db_num_rows( $result ); - $t_ids = array(); - - for ( $i=0 ; $i < $t_row_count ; $i++ ) { - $row = db_fetch_array( $result ); - - array_push( $t_ids, $row['id'] ); - } - $g_cache_cf_linked[$p_project_id] = $t_ids; - } else { - $t_ids = $g_cache_cf_linked[$p_project_id]; - } - - return $t_ids; - } - - # -------------------- - # Return an array all custom field ids sorted by name - function custom_field_get_ids( ) { - global $g_cache_cf_list; - - if ( $g_cache_cf_list === NULL ) { - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - $query = "SELECT id, name - FROM $t_custom_field_table - ORDER BY name ASC"; - $result = db_query( $query ); - $t_row_count = db_num_rows( $result ); - $t_ids = array(); - - for ( $i=0 ; $i < $t_row_count ; $i++ ) { - $row = db_fetch_array( $result ); - - array_push( $t_ids, $row['id'] ); - } - $g_cache_cf_list = $t_ids; - - } else { - $t_ids = $g_cache_cf_list; - } - return $t_ids; - } - - # -------------------- - # Return an array of ids of projects related to the specified custom field - # (the array may be empty) - function custom_field_get_project_ids( $p_field_id ) { - $c_field_id = db_prepare_int( $p_field_id ); - - $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); - $query = "SELECT project_id - FROM $t_custom_field_project_table - WHERE field_id = '$c_field_id'"; - $result = db_query( $query ); - - $t_row_count = db_num_rows( $result ); - $t_ids = array(); - - for ( $i=0 ; $i < $t_row_count ; $i++ ) { - $row = db_fetch_array( $result ); - - array_push( $t_ids, $row['project_id'] ); - } - - return $t_ids; - } - - # -------------------- - # Return a field definition row for the field or error if the field does - # not exist - function custom_field_get_definition( $p_field_id ) { - return custom_field_cache_row( $p_field_id ); - } - - # -------------------- - # Return a single database field from a custom field definition row - # for the field - # if the database field does not exist, display a warning and return '' - function custom_field_get_field( $p_field_id, $p_field_name ) { - $row = custom_field_get_definition( $p_field_id ); - - if ( isset( $row[$p_field_name] ) ) { - return $row[$p_field_name]; - } else { - error_parameters( $p_field_name ); - trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING ); - return ''; - } - } - - # -------------------- - # Get the value of a custom field for the given bug - # - # @@@ return values are unclear... should we error when access is denied - # and provide an api to check whether it will be? - function custom_field_get_value( $p_field_id, $p_bug_id ) { - $c_field_id = db_prepare_int( $p_field_id ); - $c_bug_id = db_prepare_int( $p_bug_id ); - - custom_field_ensure_exists( $p_field_id ); - - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - $query = "SELECT access_level_r, default_value, type - FROM $t_custom_field_table - WHERE id='$c_field_id'"; - $result = db_query( $query ); - $row = db_fetch_array( $result ); - - $t_access_level_r = $row['access_level_r']; - $t_default_value = $row['default_value']; - - if( !custom_field_has_read_access( $p_field_id, $p_bug_id, auth_get_current_user_id() ) ) { - return false; - } - - $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); - $query = "SELECT value - FROM $t_custom_field_string_table - WHERE bug_id='$c_bug_id' AND - field_id='$c_field_id'"; - $result = db_query( $query ); - - if( db_num_rows( $result ) > 0 ) { - return custom_field_database_to_value( db_result( $result ) , $row['type'] ); - } else { - return $t_default_value; - } - } - - # -------------------- - # Gets the custom fields array for the given bug readable by specified level. - # Array keys are custom field names. Array is sorted by custom field sequence number; - # Array items are arrays with the next keys: - # 'type', 'value', 'access_level_r' - function custom_field_get_linked_fields( $p_bug_id, $p_user_access_level ) { - $t_custom_fields = custom_field_get_all_linked_fields( $p_bug_id ); - - # removing restricted fields - foreach ( $t_custom_fields as $t_custom_field_name => $t_custom_field_data ) { - if ( $p_user_access_level < $t_custom_field_data['access_level_r'] ) { - unset( $t_custom_fields[$t_custom_field_name] ); - } - } - return $t_custom_fields; - } - - # -------------------- - # Gets the custom fields array for the given bug. Array keys are custom field names. - # Array is sorted by custom field sequence number; Array items are arrays with the next keys: - # 'type', 'value', 'access_level_r' - function custom_field_get_all_linked_fields( $p_bug_id ) { - global $g_cached_custom_field_lists; - - if ( !is_array( $g_cached_custom_field_lists ) ) { - $g_cached_custom_field_lists = array(); - } - - # is the list in cache ? - if( !array_key_exists( $p_bug_id, $g_cached_custom_field_lists ) ) { - $c_bug_id = db_prepare_int( $p_bug_id ); - $c_project_id = db_prepare_int( bug_get_field( $p_bug_id, 'project_id' ) ); - - $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); - - $query = "SELECT f.name, f.type, f.access_level_r, f.default_value, f.type, s.value - FROM $t_custom_field_project_table p INNER JOIN $t_custom_field_table f - ON p.field_id = f.id - LEFT JOIN $t_custom_field_string_table s - ON p.field_id=s.field_id AND s.bug_id='$c_bug_id' - WHERE p.project_id = '$c_project_id' - ORDER BY p.sequence ASC, f.name ASC"; - - $result = db_query( $query ); - - $t_row_count = db_num_rows( $result ); - - $t_custom_fields = array(); - - for ( $i=0 ; $i < $t_row_count ; ++$i ) { - $row = db_fetch_array( $result ); - - if( is_null( $row['value'] ) ) { - $t_value = $row['default_value']; - } else { - $t_value = custom_field_database_to_value( $row['value'], $row['type'] ); - } - - $t_custom_fields[$row['name']] = array( 'type' => $row['type'], - 'value' => $t_value, - 'access_level_r' => $row['access_level_r'] ); - } - - $g_cached_custom_field_lists[$p_bug_id] = $t_custom_fields; - } - - return $g_cached_custom_field_lists[$p_bug_id]; - } - - - # -------------------- - # Gets the sequence number for the specified custom field for the specified - # project. Returns false in case of error. - function custom_field_get_sequence( $p_field_id, $p_project_id ) { - $c_field_id = db_prepare_int( $p_field_id ); - $c_project_id = db_prepare_int( $p_project_id ); - - $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); - $query = "SELECT sequence - FROM $t_custom_field_project_table - WHERE field_id='$c_field_id' AND - project_id='$c_project_id'"; - $result = db_query( $query, 1 ); - - if ( 0 == db_num_rows( $result ) ) { - return false; - } - - $t_row = db_fetch_array( $result ); - - return $t_row['sequence']; - } - - # -------------------- - # Allows the validation of a custom field value without setting it - # or needing a bug to exist. - function custom_field_validate( $p_field_id, $p_value ) { - $c_field_id = db_prepare_int( $p_field_id ); - $c_value = db_prepare_string( $p_value ); - - custom_field_ensure_exists( $p_field_id ); - - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - $query = "SELECT name, type, possible_values, valid_regexp, - access_level_rw, length_min, length_max, default_value - FROM $t_custom_field_table - WHERE id='$c_field_id'"; - $result = db_query( $query ); - $row = db_fetch_array( $result ); - - $t_name = $row['name']; - $t_type = $row['type']; - $t_possible_values = $row['possible_values']; - $t_valid_regexp = $row['valid_regexp']; - $t_length_min = $row['length_min']; - $t_length_max = $row['length_max']; - $t_default_value = $row['default_value']; - - # check for valid value - if ( !is_blank( $t_valid_regexp ) ) { - if ( !ereg( $t_valid_regexp, $p_value ) ) { - return false; - } - } - - if ( strlen( $p_value ) < $t_length_min ) { - return false; - } - - if ( ( 0 != $t_length_max ) && ( strlen( $p_value ) > $t_length_max ) ) { - return false; - } - - return true; - } - - # -------------------- - # $p_possible_values: possible values to be pre-processed. If it has enum values, - # it will be left as is. If it has a method, it will be replaced - # by the list. - function custom_field_prepare_possible_values( $p_possible_values ) { - $t_possible_values = $p_possible_values; - - if ( !is_blank( $t_possible_values ) && ( $t_possible_values[0] == '=' ) ) { - $t_possible_values = helper_call_custom_function( 'enum_' . substr( $t_possible_values, 1 ), array() ); - } - - return $t_possible_values; - } - - # -------------------- - # Get All Possible Values for a Field. - function custom_field_distinct_values( $p_field_id, $p_project_id = ALL_PROJECTS ) { - $c_field_id = db_prepare_int( $p_field_id ); - $c_project_id = db_prepare_int( $p_project_id ); - $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - $t_mantis_bug_table = config_get( 'mantis_bug_table' ); - $t_return_arr = array(); - - $query = "SELECT type, possible_values - FROM $t_custom_field_table - WHERE id='$c_field_id'"; - $result = db_query( $query ); - - $t_row_count = db_num_rows( $result ); - if ( 0 == $t_row_count ) { - return false; - } - $row = db_fetch_array( $result ); - - # If an enumeration type, we get all possible values, not just used values - if ( CUSTOM_FIELD_TYPE_ENUM == $row['type'] || - CUSTOM_FIELD_TYPE_CHECKBOX == $row['type'] || - CUSTOM_FIELD_TYPE_LIST == $row['type'] || - CUSTOM_FIELD_TYPE_MULTILIST == $row['type'] - ) { - $t_possible_values = custom_field_prepare_possible_values( $row['possible_values'] ); - - $t_values_arr = explode( '|', $t_possible_values ); - - foreach( $t_values_arr as $t_option ) { - array_push( $t_return_arr, $t_option ); - } - } else { - $t_where = ''; - $t_from = $t_custom_field_string_table; - if ( ALL_PROJECTS != $p_project_id ) { - $t_where = " AND $t_mantis_bug_table.id = $t_custom_field_string_table.bug_id AND - $t_mantis_bug_table.project_id = '$p_project_id'"; - $t_from = $t_from . ", $t_mantis_bug_table"; - } - $query2 = "SELECT $t_custom_field_string_table.value FROM $t_from - WHERE $t_custom_field_string_table.field_id='$c_field_id' $t_where - GROUP BY $t_custom_field_string_table.value"; - $result2 = db_query( $query2 ); - $t_row_count = db_num_rows( $result2 ); - if ( 0 == $t_row_count ) { - return false; - } - - for ( $i = 0; $i < $t_row_count; $i++ ) { - $row = db_fetch_array( $result2 ); - if( !is_blank( trim( $row['value'] ) ) ) { - array_push( $t_return_arr, $row['value'] ); - } - } - } - return $t_return_arr; - } - - #=================================== - # Data Modification - #=================================== - - # -------------------- - # Convert the value to save it into the database, depending of the type - # return value for database - function custom_field_value_to_database( $p_value, $p_type ) { - switch ($p_type) { - case CUSTOM_FIELD_TYPE_MULTILIST: - case CUSTOM_FIELD_TYPE_CHECKBOX: - if ( '' == $p_value ) { - $result = ''; - } else { - $result = '|' . $p_value . '|'; - } - break; - default: - $result = $p_value; - } - return $result; - } - - # -------------------- - # Convert the database-value to value, depending of the type - # return value for further operation - function custom_field_database_to_value( $p_value, $p_type ) { - switch ($p_type) { - case CUSTOM_FIELD_TYPE_MULTILIST: - case CUSTOM_FIELD_TYPE_CHECKBOX: - $result = str_replace( '||', '', '|' . $p_value . '|' ); - break; - default: - $result = $p_value; - } - return $result; - } - - # -------------------- - # Set the value of a custom field for a given bug - # return true on success, false on failure - function custom_field_set_value( $p_field_id, $p_bug_id, $p_value ) { - $c_field_id = db_prepare_int( $p_field_id ); - $c_bug_id = db_prepare_int( $p_bug_id ); - - custom_field_ensure_exists( $p_field_id ); - - $t_custom_field_table = config_get( 'mantis_custom_field_table' ); - $query = "SELECT name, type, possible_values, valid_regexp, - access_level_rw, length_min, length_max, default_value - FROM $t_custom_field_table - WHERE id='$c_field_id'"; - $result = db_query( $query ); - $row = db_fetch_array( $result ); - - $t_name = $row['name']; - $t_type = $row['type']; - $t_possible_values = $row['possible_values']; - $t_valid_regexp = $row['valid_regexp']; - $t_access_level_rw = $row['access_level_rw']; - $t_length_min = $row['length_min']; - $t_length_max = $row['length_max']; - $t_default_value = $row['default_value']; - - $c_value = db_prepare_string( custom_field_value_to_database( $p_value, $t_type ) ); - - # check for valid value - if ( !is_blank( $t_valid_regexp ) ) { - if ( !ereg( $t_valid_regexp, $p_value ) ) { - return false; - } - } - - if ( strlen( $p_value ) < $t_length_min ) { - return false; - } - - if ( ( 0 != $t_length_max ) && ( strlen( $p_value ) > $t_length_max ) ) { - return false; - } - - if( !custom_field_has_write_access( $p_field_id, $p_bug_id, auth_get_current_user_id() ) ) { - return false; - } - - $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); - - # do I need to update or insert this value? - $query = "SELECT value - FROM $t_custom_field_string_table - WHERE field_id='$c_field_id' AND - bug_id='$c_bug_id'"; - $result = db_query( $query ); - - if ( db_num_rows( $result ) > 0 ) { - $query = "UPDATE $t_custom_field_string_table - SET value='$c_value' - WHERE field_id='$c_field_id' AND - bug_id='$c_bug_id'"; - db_query( $query ); - - $row = db_fetch_array( $result ); - history_log_event_direct( $c_bug_id, $t_name, custom_field_database_to_value( $row['value'], $t_type ), $p_value ); - } else { - # Always store the value, even if it's the dafault value - # This is important, as the definitions might change but the - # values stored with a bug must not change - $query = "INSERT INTO $t_custom_field_string_table - ( field_id, bug_id, value ) - VALUES - ( '$c_field_id', '$c_bug_id', '$c_value' )"; - db_query( $query ); - history_log_event_direct( $c_bug_id, $t_name, '', $p_value ); - } - - custom_field_clear_cache( $p_field_id ); - - #db_query() errors on failure so: - return true; - } - - # -------------------- - # Sets the sequence number for the specified custom field for the specified - # project. - function custom_field_set_sequence( $p_field_id, $p_project_id, $p_sequence ) { - $c_field_id = db_prepare_int( $p_field_id ); - $c_project_id = db_prepare_int( $p_project_id ); - $c_sequence = db_prepare_int( $p_sequence ); - - $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); - - $query = "UPDATE $t_custom_field_project_table - SET sequence='$c_sequence' - WHERE field_id='$c_field_id' AND - project_id='$c_project_id'"; - $result = db_query( $query ); - - custom_field_clear_cache( $p_field_id ); - - return true; - } - - #=================================== - # Output - #=================================== - - # -------------------- - # Print an input field - # $p_field_def contains the definition of the custom field (including it's - # field id - # $p_bug_id contains the bug where this field belongs to. If it's left - # away, it'll default to 0 and thus belongs to a new (i.e. - # non-existant) bug - # NOTE: This probably belongs in the print_api.php - function print_custom_field_input( $p_field_def, $p_bug_id = null ) { - $t_id = $p_field_def['id']; - - if( null === $p_bug_id ) { - $t_custom_field_value = $p_field_def['default_value']; - } else { - $t_custom_field_value = custom_field_get_value( $t_id, $p_bug_id ); - } - - $t_custom_field_value = string_attribute( $t_custom_field_value ); - - switch ($p_field_def['type']) { - case CUSTOM_FIELD_TYPE_ENUM: - case CUSTOM_FIELD_TYPE_LIST: - case CUSTOM_FIELD_TYPE_MULTILIST: - $t_values = explode( '|', custom_field_prepare_possible_values( $p_field_def['possible_values'] ) ); - $t_list_size = $t_possible_values_count = count( $t_values ); - - if ( $t_possible_values_count > 5 ) { - $t_list_size = 5; - } - - if ( $p_field_def['type'] == CUSTOM_FIELD_TYPE_ENUM ) { - $t_list_size = 0; # for enums the size is 0 - } - - if ( $p_field_def['type'] == CUSTOM_FIELD_TYPE_MULTILIST ) { - echo '<select ', helper_get_tab_index(), ' name="custom_field_' . $t_id . '[]" size="' . $t_list_size . '" multiple="multiple">'; - } else { - echo '<select ', helper_get_tab_index(), ' name="custom_field_' . $t_id . '" size="' . $t_list_size . '">'; - } - - $t_selected_values = explode( '|', $t_custom_field_value ); - foreach( $t_values as $t_option ) { - if( in_array( $t_option, $t_selected_values, true ) ) { - echo '<option value="' . $t_option . '" selected="selected"> ' . $t_option . '</option>'; - } else { - echo '<option value="' . $t_option . '">' . $t_option . '</option>'; - } - } - echo '</select>'; - break; - case CUSTOM_FIELD_TYPE_CHECKBOX: - $t_values = explode( '|', custom_field_prepare_possible_values( $p_field_def['possible_values'] ) ); - $t_checked_values = explode( '|', $t_custom_field_value ); - foreach( $t_values as $t_option ) { - echo '<input ', helper_get_tab_index(), ' type="checkbox" name="custom_field_' . $t_id . '[]"'; - if( in_array( $t_option, $t_checked_values, true ) ) { - echo ' value="' . $t_option . '" checked="checked"> ' . $t_option . ' '; - } else { - echo ' value="' . $t_option . '"> ' . $t_option . ' '; - } - } - break; - case CUSTOM_FIELD_TYPE_NUMERIC: - case CUSTOM_FIELD_TYPE_FLOAT: - case CUSTOM_FIELD_TYPE_EMAIL: - case CUSTOM_FIELD_TYPE_STRING: - # START MX: treat maxLength > 255 as textarea - if( 255 < $p_field_def['length_max'] ) { - echo '<textarea cols="80" rows="10" name="custom_field_' . $t_id . '">'; - echo '' . $t_custom_field_value .''; - echo '</textarea>'; - } else { - # END MX - echo '<input ', helper_get_tab_index(), ' type="text" name="custom_field_' . $t_id . '" size="80"'; - if( 0 < $p_field_def['length_max'] ) { - echo ' maxlength="' . $p_field_def['length_max'] . '"'; - } else { - echo ' maxlength="255"'; - } - echo ' value="' . $t_custom_field_value .'"></input>'; - } # MX - break ; - - case CUSTOM_FIELD_TYPE_DATE: - print_date_selection_set("custom_field_" . $t_id, config_get('short_date_format'), $t_custom_field_value, false, true) ; - break ; - } - } - - # -------------------- - # Prepare a string containing a custom field value for display - # $p_def contains the definition of the custom field - # $p_field_id contains the id of the field - # $p_bug_id contains the bug id to display the custom field value for - # NOTE: This probably belongs in the string_api.php - function string_custom_field_value( $p_def, $p_field_id, $p_bug_id ) { - $t_custom_field_value = custom_field_get_value( $p_field_id, $p_bug_id ); - switch( $p_def['type'] ) { - case CUSTOM_FIELD_TYPE_EMAIL: - return "<a href=\"mailto:$t_custom_field_value\">$t_custom_field_value</a>"; - break; - case CUSTOM_FIELD_TYPE_ENUM: - case CUSTOM_FIELD_TYPE_LIST: - case CUSTOM_FIELD_TYPE_MULTILIST: - case CUSTOM_FIELD_TYPE_CHECKBOX: - return str_replace( '|', ', ', $t_custom_field_value ); - break; - case CUSTOM_FIELD_TYPE_DATE: - if ($t_custom_field_value != null) { - return date( config_get( 'short_date_format'), $t_custom_field_value) ; - } - break ; - default: - return string_display_links( $t_custom_field_value ); - } - } - - # -------------------- - # Print a custom field value for display - # $p_def contains the definition of the custom field - # $p_field_id contains the id of the field - # $p_bug_id contains the bug id to display the custom field value for - # NOTE: This probably belongs in the print_api.php - function print_custom_field_value( $p_def, $p_field_id, $p_bug_id ) { - echo string_custom_field_value( $p_def, $p_field_id, $p_bug_id ); - } - - # -------------------- - # Prepare a string containing a custom field value for email - # $p_value value of custom field - # $p_type type of custom field - # NOTE: This probably belongs in the string_api.php - function string_custom_field_value_for_email( $p_value, $p_type ) { - switch( $p_type ) { - case CUSTOM_FIELD_TYPE_EMAIL: - return 'mailto:'.$p_value; - break; - case CUSTOM_FIELD_TYPE_ENUM: - case CUSTOM_FIELD_TYPE_LIST: - case CUSTOM_FIELD_TYPE_MULTILIST: - case CUSTOM_FIELD_TYPE_CHECKBOX: - return str_replace( '|', ', ', $p_value ); - break; - case CUSTOM_FIELD_TYPE_DATE: - if ($p_value != null) { - return date( config_get( 'short_date_format' ), $p_value) ; - } - break ; - default: - return $p_value; - } - return $p_value; - } - -?> +<?php +# Mantis - a php based bugtracking system + +# Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org +# Copyright (C) 2002 - 2007 Mantis Team - mantisbt-dev@lists.sourceforge.net + +# Mantis 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. +# +# Mantis 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 Mantis. If not, see <http://www.gnu.org/licenses/>. + + # -------------------------------------------------------- + # $Id: custom_field_api.php,v 1.66.2.1 2007-10-13 22:35:21 giallu Exp $ + # -------------------------------------------------------- + + $t_core_dir = dirname( __FILE__ ).DIRECTORY_SEPARATOR; + + require_once( $t_core_dir . 'bug_api.php' ); + require_once( $t_core_dir . 'helper_api.php' ); + require_once( $t_core_dir . 'date_api.php' ); + + ### Custom Fields API ### + +#******************************************* +# TODO +# - add an object to store field data like BugData and UserPrefs ? +# - add caching functions like user, bug, etc +# - make existing api functions use caching functions +# - add functions to return individual db columns for a field definition +#******************************************* + + #=================================== + # Caching + #=================================== + + ######################################### + # SECURITY NOTE: cache globals are initialized here to prevent them + # being spoofed if register_globals is turned on + + $g_cache_custom_field = array(); + $g_cache_cf_list = NULL; + $g_cache_cf_linked = array(); + + # Cache a custom field row if necessary and return the cached copy + # If the second parameter is true (default), trigger an error + # if the field can't be found. If the second parameter is + # false, return false if the field can't be found. + function custom_field_cache_row( $p_field_id, $p_trigger_errors=true ) { + global $g_cache_custom_field; + + $c_field_id = db_prepare_int( $p_field_id ); + + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + + if ( isset ( $g_cache_custom_field[$c_field_id] ) ) { + return $g_cache_custom_field[$c_field_id]; + } + + $query = "SELECT * + FROM $t_custom_field_table + WHERE id='$c_field_id'"; + $result = db_query( $query ); + + if ( 0 == db_num_rows( $result ) ) { + if ( $p_trigger_errors ) { + error_parameters( 'Custom ' . $p_field_id ); + trigger_error( ERROR_CUSTOM_FIELD_NOT_FOUND, ERROR ); + } else { + return false; + } + } + + $row = db_fetch_array( $result ); + + $g_cache_custom_field[$c_field_id] = $row; + + return $row; + } + + # -------------------- + # Clear the custom field cache (or just the given id if specified) + function custom_field_clear_cache( $p_field_id = null ) { + global $g_cache_custom_field, $g_cached_custom_field_lists; + + $g_cached_custom_field_lists = null; + + if ( null === $p_field_id ) { + $g_cache_custom_field = array(); + } else { + $c_field_id = db_prepare_int( $p_field_id ); + unset( $g_cache_custom_field[$c_field_id] ); + } + + return true; + } + + + #=================================== + # Boolean queries and ensures + #=================================== + + # -------------------- + # Check to see whether the field is included in the given project + # return true if the field is included, false otherwise + # + function custom_field_is_linked( $p_field_id, $p_project_id ) { + $c_project_id = db_prepare_int( $p_project_id ); + $c_field_id = db_prepare_int( $p_field_id ); + + # figure out if this bug_id/field_id combination exists + $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); + $query = "SELECT COUNT(*) + FROM $t_custom_field_project_table + WHERE field_id='$c_field_id' AND + project_id='$c_project_id'"; + $result = db_query( $query ); + $count = db_result( $result ); + + if ( $count > 0 ) { + return true; + } else { + return false; + } + } + + # -------------------- + # Check to see whether the field id is defined + # return true if the field is defined, false otherwise + function custom_field_exists( $p_field_id ) { + if ( false == custom_field_cache_row( $p_field_id, false ) ) { + return false; + } else { + return true; + } + } + + # -------------------- + # Return the type of a custom field if it exists. + function custom_field_type( $p_field_id ) { + $t_field = custom_field_cache_row( $p_field_id, false ) ; + if ( $t_field == false ) { + return -1 ; + } else { + return $t_field[ 'type' ] ; + } + } + + # -------------------- + # Check to see whether the field id is defined + # return true if the field is defined, error otherwise + function custom_field_ensure_exists( $p_field_id ) { + if ( custom_field_exists( $p_field_id ) ) { + return true; + } else { + error_parameters( 'Custom ' . $p_field_id ); + trigger_error( ERROR_CUSTOM_FIELD_NOT_FOUND, ERROR ); + } + } + + # -------------------- + # Check to see whether the name is unique + # return false if a field with the name already exists, true otherwise + # if an id is specified, then the corresponding record is excluded from the + # uniqueness test. + function custom_field_is_name_unique( $p_name, $p_custom_field_id = null ) { + $c_name = db_prepare_string( $p_name ); + + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + $query = "SELECT COUNT(*) + FROM $t_custom_field_table + WHERE name='$c_name'"; + if ( $p_custom_field_id !== null ) { + $c_id = db_prepare_int( $p_custom_field_id ); + $query .= " AND (id <> $c_id)"; + } + $result = db_query( $query ); + $count = db_result( $result ); + + if ( $count > 0 ) { + return false; + } else { + return true; + } + } + + # -------------------- + # Check to see whether the name is unique + # return true if the name has not been used, error otherwise + function custom_field_ensure_name_unique( $p_name ) { + if ( custom_field_is_name_unique( $p_name ) ) { + return true; + } else { + trigger_error( ERROR_CUSTOM_FIELD_NAME_NOT_UNIQUE, ERROR ); + } + } + + # -------------------- + # Return true if the user can read the value of the field for the given bug, + # false otherwise. + function custom_field_has_read_access( $p_field_id, $p_bug_id, $p_user_id = null ) { + custom_field_ensure_exists( $p_field_id ); + + if ( null === $p_user_id ) { + $p_user_id = auth_get_current_user_id(); + } + + $t_access_level_r = custom_field_get_field( $p_field_id, 'access_level_r' ); + + $t_project_id = bug_get_field( $p_bug_id, 'project_id' ); + + return access_has_project_level( $t_access_level_r, $t_project_id, $p_user_id ); + } + + # -------------------- + # Return true if the user can modify the value of the field for the given project, + # false otherwise. + function custom_field_has_write_access_to_project( $p_field_id, $p_project_id, $p_user_id = null ) { + custom_field_ensure_exists( $p_field_id ); + + if ( null === $p_user_id ) { + $p_user_id = auth_get_current_user_id(); + } + + $t_access_level_rw = custom_field_get_field( $p_field_id, 'access_level_rw' ); + + return access_has_project_level( $t_access_level_rw, $p_project_id, $p_user_id ); + } + + # -------------------- + # Return true if the user can modify the value of the field for the given bug, + # false otherwise. + function custom_field_has_write_access( $p_field_id, $p_bug_id, $p_user_id = null ) { + $t_project_id = bug_get_field( $p_bug_id, 'project_id' ); + return ( custom_field_has_write_access_to_project( $p_field_id, $t_project_id, $p_user_id ) ); + } + + #=================================== + # Creation / Deletion / Updating + #=================================== + + # -------------------- + # create a new custom field with the name $p_name + # the definition are the default values and can be changes later + # return the ID of the new definition + function custom_field_create( $p_name ) { + if ( string_contains_scripting_chars( $p_name ) ) { + trigger_error( ERROR_CUSTOM_FIELD_INVALID_DEFINITION, ERROR ); + } + + $c_name = db_prepare_string( trim( $p_name ) ); + + if ( is_blank( $c_name ) ) { + error_parameters( 'name' ); + trigger_error( ERROR_EMPTY_FIELD, ERROR ); + } + + custom_field_ensure_name_unique( $c_name ); + + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + $query = "INSERT INTO $t_custom_field_table + ( name ) + VALUES + ( '$c_name' )"; + + db_query( $query ); + + return db_insert_id( $t_custom_field_table ); + } + + # -------------------- + # Update the field definition + # return true on success, false on failure + function custom_field_update( $p_field_id, $p_def_array ) { + if ( string_contains_scripting_chars( $p_def_array['name'] ) ) { + trigger_error( ERROR_CUSTOM_FIELD_INVALID_DEFINITION, ERROR ); + } + + $c_field_id = db_prepare_int( $p_field_id ); + $c_name = db_prepare_string( trim( $p_def_array['name'] ) ); + $c_type = db_prepare_int( $p_def_array['type'] ); + $c_possible_values = db_prepare_string( $p_def_array['possible_values'] ); + $c_default_value = db_prepare_string( $p_def_array['default_value'] ); + $c_valid_regexp = db_prepare_string( $p_def_array['valid_regexp'] ); + $c_access_level_r = db_prepare_int( $p_def_array['access_level_r'] ); + $c_access_level_rw = db_prepare_int( $p_def_array['access_level_rw'] ); + $c_length_min = db_prepare_int( $p_def_array['length_min'] ); + $c_length_max = db_prepare_int( $p_def_array['length_max'] ); + $c_advanced = db_prepare_bool( $p_def_array['advanced'] ); + $c_display_report = db_prepare_bool( $p_def_array['display_report'] ); + $c_display_update = db_prepare_bool( $p_def_array['display_update'] ); + $c_display_resolved = db_prepare_bool( $p_def_array['display_resolved'] ); + $c_display_closed = db_prepare_bool( $p_def_array['display_closed'] ); + $c_require_report = db_prepare_bool( $p_def_array['require_report'] ); + $c_require_update = db_prepare_bool( $p_def_array['require_update'] ); + $c_require_resolved = db_prepare_bool( $p_def_array['require_resolved'] ); + $c_require_closed = db_prepare_bool( $p_def_array['require_closed'] ); + + if ( is_blank( $c_name ) ) { + error_parameters( 'name' ); + trigger_error( ERROR_EMPTY_FIELD, ERROR ); + } + + if (( $c_access_level_rw < $c_access_level_r ) || + ( $c_length_min < 0 ) || + ( ( $c_length_max != 0 ) && ( $c_length_min > $c_length_max ) ) ) { + trigger_error( ERROR_CUSTOM_FIELD_INVALID_DEFINITION, ERROR ); + } + + if ( $c_advanced == true && ( $c_require_report == true || $c_require_update ) ) { + trigger_error( ERROR_CUSTOM_FIELD_INVALID_DEFINITION, ERROR ); + } + + if ( !custom_field_is_name_unique( $c_name, $c_field_id ) ) { + trigger_error( ERROR_CUSTOM_FIELD_NAME_NOT_UNIQUE, ERROR ); + } + + $t_update_something = false; + $t_mantis_custom_field_table = config_get( 'mantis_custom_field_table' ); + $query = "UPDATE $t_mantis_custom_field_table + SET "; + if( array_key_exists( 'name', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "name='$c_name'"; + } + if( array_key_exists( 'type', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "type='$c_type'"; + } + if( array_key_exists( 'possible_values', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "possible_values='$c_possible_values'"; + } + if( array_key_exists( 'default_value', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "default_value='$c_default_value'"; + } + if( array_key_exists( 'valid_regexp', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "valid_regexp='$c_valid_regexp'"; + } + if( array_key_exists( 'access_level_r', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "access_level_r='$c_access_level_r'"; + } + if( array_key_exists( 'access_level_rw', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "access_level_rw='$c_access_level_rw'"; + } + if( array_key_exists( 'length_min', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "length_min='$c_length_min'"; + } + if( array_key_exists( 'length_max', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "length_max='$c_length_max'"; + } + if( array_key_exists( 'advanced', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "advanced='$c_advanced'"; + } + if( array_key_exists( 'display_report', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "display_report='$c_display_report'"; + } + if( array_key_exists( 'display_update', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "display_update='$c_display_update'"; + } + if( array_key_exists( 'display_resolved', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "display_resolved='$c_display_resolved'"; + } + if( array_key_exists( 'display_closed', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "display_closed='$c_display_closed'"; + } + if( array_key_exists( 'require_report', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "require_report='$c_require_report'"; + } + if( array_key_exists( 'require_update', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "require_update='$c_require_update'"; + } + if( array_key_exists( 'require_resolved', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "require_resolved='$c_require_resolved'"; + } + if( array_key_exists( 'require_closed', $p_def_array ) ) { + if ( !$t_update_something ) { + $t_update_something = true; + } else { + $query .= ', '; + } + $query .= "require_closed='$c_require_closed'"; + } + + + $query .= " WHERE id='$c_field_id'"; + + if( $t_update_something ) { + db_query( $query ); + custom_field_clear_cache( $p_field_id ); + } else { + return false; # there is nothing to update... + } + + # db_query() errors on failure so: + return true; + } + + # -------------------- + # Add a custom field to a project + # return true on success, false on failure or if already added + function custom_field_link( $p_field_id, $p_project_id ) { + $c_field_id = db_prepare_int( $p_field_id ); + $c_project_id = db_prepare_int( $p_project_id ); + + custom_field_ensure_exists( $p_field_id ); + project_ensure_exists( $p_project_id ); + + if ( custom_field_is_linked( $p_field_id, $p_project_id ) ) { + return false; + } + + $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); + $query = "INSERT INTO $t_custom_field_project_table + ( field_id, project_id ) + VALUES + ( '$c_field_id', '$c_project_id' )"; + db_query( $query ); + + # db_query() errors on failure so: + return true; + } + + # -------------------- + # Remove a custom field from a project + # return true on success, false on failure + # + # The values for the custom fields are not deleted. This is to allow for the + # case where a bug is moved to another project that has the field, or the + # field is linked again to the project. + function custom_field_unlink( $p_field_id, $p_project_id ) { + $c_field_id = db_prepare_int( $p_field_id ); + $c_project_id = db_prepare_int( $p_project_id ); + + $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); + $query = "DELETE FROM $t_custom_field_project_table + WHERE field_id = '$c_field_id' AND + project_id = '$c_project_id'"; + db_query( $query ); + + # db_query() errors on failure so: + return true; + } + + # -------------------- + # Delete the field definition and all associated values and project + # associations + # return true on success, false on failure + function custom_field_destroy( $p_field_id ) { + $c_field_id = db_prepare_int( $p_field_id ); + + # delete all values + $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); + $query = "DELETE FROM $t_custom_field_string_table + WHERE field_id='$c_field_id'"; + db_query( $query ); + + # delete all project associations + $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); + $query = "DELETE FROM $t_custom_field_project_table + WHERE field_id='$c_field_id'"; + db_query( $query ); + + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + # delete the definition + $query = "DELETE FROM $t_custom_field_table + WHERE id='$c_field_id'"; + db_query( $query ); + + custom_field_clear_cache( $p_field_id ); + + # db_query() errors on failure so: + return true; + } + + # -------------------- + # Delete all associations of custom fields to the specified project + # return true on success, false on failure + # + # To be called from within project_delete(). + function custom_field_unlink_all( $p_project_id ) { + $c_project_id = db_prepare_int( $p_project_id ); + + # delete all project associations + $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); + $query = "DELETE FROM $t_custom_field_project_table + WHERE project_id='$c_project_id'"; + db_query( $query ); + + # db_query() errors on failure so: + return true; + } + + # -------------------- + # Delete all custom values associated with the specified bug. + # return true on success, false on failure + # + # To be called from bug_delete(). + function custom_field_delete_all_values( $p_bug_id ) { + $c_bug_id = db_prepare_int( $p_bug_id ); + + $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); + $query = "DELETE FROM $t_custom_field_string_table + WHERE bug_id='$c_bug_id'"; + db_query( $query ); + + #db_query() errors on failure so: + return true; + } + + #=================================== + # Data Access + #=================================== + + # -------------------- + # Get the id of the custom field with the specified name. + # false is returned if no custom field found with the specified name. + function custom_field_get_id_from_name( $p_field_name, $p_truncated_length = null ) { + if ( $p_field_name == '' ) { + return false; + } + + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + + $c_field_name = db_prepare_string( $p_field_name ); + + if ( ( null === $p_truncated_length ) || ( strlen( $c_field_name ) != $p_truncated_length ) ) { + $query = "SELECT id FROM $t_custom_field_table WHERE name = '$c_field_name'"; + } else { + # @@@ This is to handle the case where we only have a truncated part of the name. This happens in the case where + # we are getting the custom field name from the history logs, since history is 32 and custom field name is 64. + # This fix will handle entries already in the database, future entries should be handled by making the field name max lengths match. + $query = "SELECT id FROM $t_custom_field_table WHERE name LIKE '$c_field_name%'"; + } + + $t_result = db_query( $query, 1 ); + + if ( db_num_rows( $t_result ) == 0 ) { + return false; + } + + $row = db_fetch_array( $t_result ); + + return $row['id']; + } + + # -------------------- + # Return an array of ids of custom fields bound to the specified project + # + # The ids will be sorted based on the sequence number associated with the binding + function custom_field_get_linked_ids( $p_project_id = ALL_PROJECTS ) { + global $g_cache_cf_linked; + + if ( ! isset( $g_cache_cf_linked[$p_project_id] ) ) { + + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); + + if ( ALL_PROJECTS == $p_project_id ) { + $t_project_user_list_table = config_get( 'mantis_project_user_list_table' ); + $t_project_table = config_get( 'mantis_project_table' ); + $t_user_table = config_get( 'mantis_user_table' ); + $t_user_id = auth_get_current_user_id(); + $t_pub = VS_PUBLIC; + $t_priv = VS_PRIVATE; + + $t_private_access = config_get( 'private_project_threshold' ); + if ( is_array( $t_private_access ) ) { + if ( 1 == count( $t_private_access ) ) { + $t_access_clause = "= " . array_shift( $t_private_access ) . " "; + } else { + $t_access_clause = "IN (" . implode( ',', $t_private_access ) . ")"; + } + } else { + $t_access_clause = ">= $t_private_access "; + } + + + # select only the ids that the user has some access to + # e.g., all fields in public projects, or private projects where the user is listed + # or private projects where the user is implicitly listed + $query = "SELECT cft.id as id, cft.name as name + FROM $t_custom_field_table as cft, $t_user_table ut, $t_project_table pt, $t_custom_field_project_table cfpt + LEFT JOIN $t_project_user_list_table pult + on cfpt.project_id = pult.project_id and pult.user_id = $t_user_id + WHERE cft.id = cfpt.field_id AND cfpt.project_id = pt.id AND ut.id = $t_user_id AND + ( pt.view_state = $t_pub OR + ( pt.view_state = $t_priv and pult.user_id = $t_user_id ) OR + ( pult.user_id is null and ut.access_level $t_access_clause ) ) + GROUP BY cft.id, cft.name + ORDER BY cft.name ASC"; + } else { + if ( is_array( $p_project_id ) ) { + if ( 1 == count( $p_project_id ) ) { + $t_project_clause = "= " . array_shift( $p_project_id ) . " "; + } else { + $t_project_clause = "IN (" . implode( ',', $p_project_id ) . ")"; + } + } else { + $t_project_clause = "= $p_project_id "; + } + $query = "SELECT cft.id, cft.name, cfpt.sequence + FROM $t_custom_field_table cft, $t_custom_field_project_table cfpt + WHERE cfpt.project_id $t_project_clause AND + cft.id = cfpt.field_id + ORDER BY sequence ASC, name ASC"; + } + $result = db_query( $query ); + $t_row_count = db_num_rows( $result ); + $t_ids = array(); + + for ( $i=0 ; $i < $t_row_count ; $i++ ) { + $row = db_fetch_array( $result ); + + array_push( $t_ids, $row['id'] ); + } + $g_cache_cf_linked[$p_project_id] = $t_ids; + } else { + $t_ids = $g_cache_cf_linked[$p_project_id]; + } + + return $t_ids; + } + + # -------------------- + # Return an array all custom field ids sorted by name + function custom_field_get_ids( ) { + global $g_cache_cf_list; + + if ( $g_cache_cf_list === NULL ) { + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + $query = "SELECT id, name + FROM $t_custom_field_table + ORDER BY name ASC"; + $result = db_query( $query ); + $t_row_count = db_num_rows( $result ); + $t_ids = array(); + + for ( $i=0 ; $i < $t_row_count ; $i++ ) { + $row = db_fetch_array( $result ); + + array_push( $t_ids, $row['id'] ); + } + $g_cache_cf_list = $t_ids; + + } else { + $t_ids = $g_cache_cf_list; + } + return $t_ids; + } + + # -------------------- + # Return an array of ids of projects related to the specified custom field + # (the array may be empty) + function custom_field_get_project_ids( $p_field_id ) { + $c_field_id = db_prepare_int( $p_field_id ); + + $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); + $query = "SELECT project_id + FROM $t_custom_field_project_table + WHERE field_id = '$c_field_id'"; + $result = db_query( $query ); + + $t_row_count = db_num_rows( $result ); + $t_ids = array(); + + for ( $i=0 ; $i < $t_row_count ; $i++ ) { + $row = db_fetch_array( $result ); + + array_push( $t_ids, $row['project_id'] ); + } + + return $t_ids; + } + + # -------------------- + # Return a field definition row for the field or error if the field does + # not exist + function custom_field_get_definition( $p_field_id ) { + return custom_field_cache_row( $p_field_id ); + } + + # -------------------- + # Return a single database field from a custom field definition row + # for the field + # if the database field does not exist, display a warning and return '' + function custom_field_get_field( $p_field_id, $p_field_name ) { + $row = custom_field_get_definition( $p_field_id ); + + if ( isset( $row[$p_field_name] ) ) { + return $row[$p_field_name]; + } else { + error_parameters( $p_field_name ); + trigger_error( ERROR_DB_FIELD_NOT_FOUND, WARNING ); + return ''; + } + } + + # -------------------- + # Get the value of a custom field for the given bug + # + # @@@ return values are unclear... should we error when access is denied + # and provide an api to check whether it will be? + function custom_field_get_value( $p_field_id, $p_bug_id ) { + $c_field_id = db_prepare_int( $p_field_id ); + $c_bug_id = db_prepare_int( $p_bug_id ); + + custom_field_ensure_exists( $p_field_id ); + + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + $query = "SELECT access_level_r, default_value, type + FROM $t_custom_field_table + WHERE id='$c_field_id'"; + $result = db_query( $query ); + $row = db_fetch_array( $result ); + + $t_access_level_r = $row['access_level_r']; + $t_default_value = $row['default_value']; + + if( !custom_field_has_read_access( $p_field_id, $p_bug_id, auth_get_current_user_id() ) ) { + return false; + } + + $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); + $query = "SELECT value + FROM $t_custom_field_string_table + WHERE bug_id='$c_bug_id' AND + field_id='$c_field_id'"; + $result = db_query( $query ); + + if( db_num_rows( $result ) > 0 ) { + return custom_field_database_to_value( db_result( $result ) , $row['type'] ); + } else { + return $t_default_value; + } + } + + # -------------------- + # Gets the custom fields array for the given bug readable by specified level. + # Array keys are custom field names. Array is sorted by custom field sequence number; + # Array items are arrays with the next keys: + # 'type', 'value', 'access_level_r' + function custom_field_get_linked_fields( $p_bug_id, $p_user_access_level ) { + $t_custom_fields = custom_field_get_all_linked_fields( $p_bug_id ); + + # removing restricted fields + foreach ( $t_custom_fields as $t_custom_field_name => $t_custom_field_data ) { + if ( $p_user_access_level < $t_custom_field_data['access_level_r'] ) { + unset( $t_custom_fields[$t_custom_field_name] ); + } + } + return $t_custom_fields; + } + + # -------------------- + # Gets the custom fields array for the given bug. Array keys are custom field names. + # Array is sorted by custom field sequence number; Array items are arrays with the next keys: + # 'type', 'value', 'access_level_r' + function custom_field_get_all_linked_fields( $p_bug_id ) { + global $g_cached_custom_field_lists; + + if ( !is_array( $g_cached_custom_field_lists ) ) { + $g_cached_custom_field_lists = array(); + } + + # is the list in cache ? + if( !array_key_exists( $p_bug_id, $g_cached_custom_field_lists ) ) { + $c_bug_id = db_prepare_int( $p_bug_id ); + $c_project_id = db_prepare_int( bug_get_field( $p_bug_id, 'project_id' ) ); + + $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); + + $query = "SELECT f.name, f.type, f.access_level_r, f.default_value, f.type, s.value + FROM $t_custom_field_project_table p INNER JOIN $t_custom_field_table f + ON p.field_id = f.id + LEFT JOIN $t_custom_field_string_table s + ON p.field_id=s.field_id AND s.bug_id='$c_bug_id' + WHERE p.project_id = '$c_project_id' + ORDER BY p.sequence ASC, f.name ASC"; + + $result = db_query( $query ); + + $t_row_count = db_num_rows( $result ); + + $t_custom_fields = array(); + + for ( $i=0 ; $i < $t_row_count ; ++$i ) { + $row = db_fetch_array( $result ); + + if( is_null( $row['value'] ) ) { + $t_value = $row['default_value']; + } else { + $t_value = custom_field_database_to_value( $row['value'], $row['type'] ); + } + + $t_custom_fields[$row['name']] = array( 'type' => $row['type'], + 'value' => $t_value, + 'access_level_r' => $row['access_level_r'] ); + } + + $g_cached_custom_field_lists[$p_bug_id] = $t_custom_fields; + } + + return $g_cached_custom_field_lists[$p_bug_id]; + } + + + # -------------------- + # Gets the sequence number for the specified custom field for the specified + # project. Returns false in case of error. + function custom_field_get_sequence( $p_field_id, $p_project_id ) { + $c_field_id = db_prepare_int( $p_field_id ); + $c_project_id = db_prepare_int( $p_project_id ); + + $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); + $query = "SELECT sequence + FROM $t_custom_field_project_table + WHERE field_id='$c_field_id' AND + project_id='$c_project_id'"; + $result = db_query( $query, 1 ); + + if ( 0 == db_num_rows( $result ) ) { + return false; + } + + $t_row = db_fetch_array( $result ); + + return $t_row['sequence']; + } + + # -------------------- + # Allows the validation of a custom field value without setting it + # or needing a bug to exist. + function custom_field_validate( $p_field_id, $p_value ) { + $c_field_id = db_prepare_int( $p_field_id ); + $c_value = db_prepare_string( $p_value ); + + custom_field_ensure_exists( $p_field_id ); + + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + $query = "SELECT name, type, possible_values, valid_regexp, + access_level_rw, length_min, length_max, default_value + FROM $t_custom_field_table + WHERE id='$c_field_id'"; + $result = db_query( $query ); + $row = db_fetch_array( $result ); + + $t_name = $row['name']; + $t_type = $row['type']; + $t_possible_values = $row['possible_values']; + $t_valid_regexp = $row['valid_regexp']; + $t_length_min = $row['length_min']; + $t_length_max = $row['length_max']; + $t_default_value = $row['default_value']; + + # check for valid value + if ( !is_blank( $t_valid_regexp ) ) { + if ( !ereg( $t_valid_regexp, $p_value ) ) { + return false; + } + } + + if ( strlen( $p_value ) < $t_length_min ) { + return false; + } + + if ( ( 0 != $t_length_max ) && ( strlen( $p_value ) > $t_length_max ) ) { + return false; + } + + return true; + } + + # -------------------- + # $p_possible_values: possible values to be pre-processed. If it has enum values, + # it will be left as is. If it has a method, it will be replaced + # by the list. + function custom_field_prepare_possible_values( $p_possible_values ) { + $t_possible_values = $p_possible_values; + + if ( !is_blank( $t_possible_values ) && ( $t_possible_values[0] == '=' ) ) { + $t_possible_values = helper_call_custom_function( 'enum_' . substr( $t_possible_values, 1 ), array() ); + } + + return $t_possible_values; + } + + # -------------------- + # Get All Possible Values for a Field. + function custom_field_distinct_values( $p_field_id, $p_project_id = ALL_PROJECTS ) { + $c_field_id = db_prepare_int( $p_field_id ); + $c_project_id = db_prepare_int( $p_project_id ); + $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + $t_mantis_bug_table = config_get( 'mantis_bug_table' ); + $t_return_arr = array(); + + $query = "SELECT type, possible_values + FROM $t_custom_field_table + WHERE id='$c_field_id'"; + $result = db_query( $query ); + + $t_row_count = db_num_rows( $result ); + if ( 0 == $t_row_count ) { + return false; + } + $row = db_fetch_array( $result ); + + # If an enumeration type, we get all possible values, not just used values + if ( CUSTOM_FIELD_TYPE_ENUM == $row['type'] || + CUSTOM_FIELD_TYPE_CHECKBOX == $row['type'] || + CUSTOM_FIELD_TYPE_LIST == $row['type'] || + CUSTOM_FIELD_TYPE_MULTILIST == $row['type'] + ) { + $t_possible_values = custom_field_prepare_possible_values( $row['possible_values'] ); + + $t_values_arr = explode( '|', $t_possible_values ); + + foreach( $t_values_arr as $t_option ) { + array_push( $t_return_arr, $t_option ); + } + } else { + $t_where = ''; + $t_from = $t_custom_field_string_table; + if ( ALL_PROJECTS != $p_project_id ) { + $t_where = " AND $t_mantis_bug_table.id = $t_custom_field_string_table.bug_id AND + $t_mantis_bug_table.project_id = '$p_project_id'"; + $t_from = $t_from . ", $t_mantis_bug_table"; + } + $query2 = "SELECT $t_custom_field_string_table.value FROM $t_from + WHERE $t_custom_field_string_table.field_id='$c_field_id' $t_where + GROUP BY $t_custom_field_string_table.value"; + $result2 = db_query( $query2 ); + $t_row_count = db_num_rows( $result2 ); + if ( 0 == $t_row_count ) { + return false; + } + + for ( $i = 0; $i < $t_row_count; $i++ ) { + $row = db_fetch_array( $result2 ); + if( !is_blank( trim( $row['value'] ) ) ) { + array_push( $t_return_arr, $row['value'] ); + } + } + } + return $t_return_arr; + } + + #=================================== + # Data Modification + #=================================== + + # -------------------- + # Convert the value to save it into the database, depending of the type + # return value for database + function custom_field_value_to_database( $p_value, $p_type ) { + switch ($p_type) { + case CUSTOM_FIELD_TYPE_MULTILIST: + case CUSTOM_FIELD_TYPE_CHECKBOX: + if ( '' == $p_value ) { + $result = ''; + } else { + $result = '|' . $p_value . '|'; + } + break; + default: + $result = $p_value; + } + return $result; + } + + # -------------------- + # Convert the database-value to value, depending of the type + # return value for further operation + function custom_field_database_to_value( $p_value, $p_type ) { + switch ($p_type) { + case CUSTOM_FIELD_TYPE_MULTILIST: + case CUSTOM_FIELD_TYPE_CHECKBOX: + $result = str_replace( '||', '', '|' . $p_value . '|' ); + break; + default: + $result = $p_value; + } + return $result; + } + + # -------------------- + # Set the value of a custom field for a given bug + # return true on success, false on failure + function custom_field_set_value( $p_field_id, $p_bug_id, $p_value ) { + $c_field_id = db_prepare_int( $p_field_id ); + $c_bug_id = db_prepare_int( $p_bug_id ); + + custom_field_ensure_exists( $p_field_id ); + + $t_custom_field_table = config_get( 'mantis_custom_field_table' ); + $query = "SELECT name, type, possible_values, valid_regexp, + access_level_rw, length_min, length_max, default_value + FROM $t_custom_field_table + WHERE id='$c_field_id'"; + $result = db_query( $query ); + $row = db_fetch_array( $result ); + + $t_name = $row['name']; + $t_type = $row['type']; + $t_possible_values = $row['possible_values']; + $t_valid_regexp = $row['valid_regexp']; + $t_access_level_rw = $row['access_level_rw']; + $t_length_min = $row['length_min']; + $t_length_max = $row['length_max']; + $t_default_value = $row['default_value']; + + $c_value = db_prepare_string( custom_field_value_to_database( $p_value, $t_type ) ); + + # check for valid value + if ( !is_blank( $t_valid_regexp ) ) { + if ( !ereg( $t_valid_regexp, $p_value ) ) { + return false; + } + } + + if ( strlen( $p_value ) < $t_length_min ) { + return false; + } + + if ( ( 0 != $t_length_max ) && ( strlen( $p_value ) > $t_length_max ) ) { + return false; + } + + if( !custom_field_has_write_access( $p_field_id, $p_bug_id, auth_get_current_user_id() ) ) { + return false; + } + + $t_custom_field_string_table = config_get( 'mantis_custom_field_string_table' ); + + # do I need to update or insert this value? + $query = "SELECT value + FROM $t_custom_field_string_table + WHERE field_id='$c_field_id' AND + bug_id='$c_bug_id'"; + $result = db_query( $query ); + + if ( db_num_rows( $result ) > 0 ) { + $query = "UPDATE $t_custom_field_string_table + SET value='$c_value' + WHERE field_id='$c_field_id' AND + bug_id='$c_bug_id'"; + db_query( $query ); + + $row = db_fetch_array( $result ); + history_log_event_direct( $c_bug_id, $t_name, custom_field_database_to_value( $row['value'], $t_type ), $p_value ); + } else { + # Always store the value, even if it's the dafault value + # This is important, as the definitions might change but the + # values stored with a bug must not change + $query = "INSERT INTO $t_custom_field_string_table + ( field_id, bug_id, value ) + VALUES + ( '$c_field_id', '$c_bug_id', '$c_value' )"; + db_query( $query ); + history_log_event_direct( $c_bug_id, $t_name, '', $p_value ); + } + + custom_field_clear_cache( $p_field_id ); + + #db_query() errors on failure so: + return true; + } + + # -------------------- + # Sets the sequence number for the specified custom field for the specified + # project. + function custom_field_set_sequence( $p_field_id, $p_project_id, $p_sequence ) { + $c_field_id = db_prepare_int( $p_field_id ); + $c_project_id = db_prepare_int( $p_project_id ); + $c_sequence = db_prepare_int( $p_sequence ); + + $t_custom_field_project_table = config_get( 'mantis_custom_field_project_table' ); + + $query = "UPDATE $t_custom_field_project_table + SET sequence='$c_sequence' + WHERE field_id='$c_field_id' AND + project_id='$c_project_id'"; + $result = db_query( $query ); + + custom_field_clear_cache( $p_field_id ); + + return true; + } + + #=================================== + # Output + #=================================== + + # -------------------- + # Print an input field + # $p_field_def contains the definition of the custom field (including it's + # field id + # $p_bug_id contains the bug where this field belongs to. If it's left + # away, it'll default to 0 and thus belongs to a new (i.e. + # non-existant) bug + # NOTE: This probably belongs in the print_api.php + function print_custom_field_input( $p_field_def, $p_bug_id = null ) { + $t_id = $p_field_def['id']; + + if( null === $p_bug_id ) { + $t_custom_field_value = $p_field_def['default_value']; + } else { + $t_custom_field_value = custom_field_get_value( $t_id, $p_bug_id ); + } + + $t_custom_field_value = string_attribute( $t_custom_field_value ); + + switch ($p_field_def['type']) { + case CUSTOM_FIELD_TYPE_ENUM: + case CUSTOM_FIELD_TYPE_LIST: + case CUSTOM_FIELD_TYPE_MULTILIST: + $t_values = explode( '|', custom_field_prepare_possible_values( $p_field_def['possible_values'] ) ); + $t_list_size = $t_possible_values_count = count( $t_values ); + + if ( $t_possible_values_count > 5 ) { + $t_list_size = 5; + } + + if ( $p_field_def['type'] == CUSTOM_FIELD_TYPE_ENUM ) { + $t_list_size = 0; # for enums the size is 0 + } + + if ( $p_field_def['type'] == CUSTOM_FIELD_TYPE_MULTILIST ) { + echo '<select ', helper_get_tab_index(), ' name="custom_field_' . $t_id . '[]" size="' . $t_list_size . '" multiple="multiple">'; + } else { + echo '<select ', helper_get_tab_index(), ' name="custom_field_' . $t_id . '" size="' . $t_list_size . '">'; + } + + $t_selected_values = explode( '|', $t_custom_field_value ); + foreach( $t_values as $t_option ) { + if( in_array( $t_option, $t_selected_values, true ) ) { + echo '<option value="' . $t_option . '" selected="selected"> ' . $t_option . '</option>'; + } else { + echo '<option value="' . $t_option . '">' . $t_option . '</option>'; + } + } + echo '</select>'; + break; + case CUSTOM_FIELD_TYPE_CHECKBOX: + $t_values = explode( '|', custom_field_prepare_possible_values( $p_field_def['possible_values'] ) ); + $t_checked_values = explode( '|', $t_custom_field_value ); + foreach( $t_values as $t_option ) { + echo '<input ', helper_get_tab_index(), ' type="checkbox" name="custom_field_' . $t_id . '[]"'; + if( in_array( $t_option, $t_checked_values, true ) ) { + echo ' value="' . $t_option . '" checked="checked"> ' . $t_option . ' '; + } else { + echo ' value="' . $t_option . '"> ' . $t_option . ' '; + } + } + break; + case CUSTOM_FIELD_TYPE_NUMERIC: + case CUSTOM_FIELD_TYPE_FLOAT: + case CUSTOM_FIELD_TYPE_EMAIL: + case CUSTOM_FIELD_TYPE_STRING: + echo '<input ', helper_get_tab_index(), ' type="text" name="custom_field_' . $t_id . '" size="80"'; + if( 0 < $p_field_def['length_max'] ) { + echo ' maxlength="' . $p_field_def['length_max'] . '"'; + } else { + echo ' maxlength="255"'; + } + echo ' value="' . $t_custom_field_value .'"></input>'; + break ; + + case CUSTOM_FIELD_TYPE_DATE: + print_date_selection_set("custom_field_" . $t_id, config_get('short_date_format'), $t_custom_field_value, false, true) ; + break ; + } + } + + # -------------------- + # Prepare a string containing a custom field value for display + # $p_def contains the definition of the custom field + # $p_field_id contains the id of the field + # $p_bug_id contains the bug id to display the custom field value for + # NOTE: This probably belongs in the string_api.php + function string_custom_field_value( $p_def, $p_field_id, $p_bug_id ) { + $t_custom_field_value = custom_field_get_value( $p_field_id, $p_bug_id ); + switch( $p_def['type'] ) { + case CUSTOM_FIELD_TYPE_EMAIL: + return "<a href=\"mailto:$t_custom_field_value\">$t_custom_field_value</a>"; + break; + case CUSTOM_FIELD_TYPE_ENUM: + case CUSTOM_FIELD_TYPE_LIST: + case CUSTOM_FIELD_TYPE_MULTILIST: + case CUSTOM_FIELD_TYPE_CHECKBOX: + return str_replace( '|', ', ', $t_custom_field_value ); + break; + case CUSTOM_FIELD_TYPE_DATE: + if ($t_custom_field_value != null) { + return date( config_get( 'short_date_format'), $t_custom_field_value) ; + } + break ; + default: + return string_display_links( $t_custom_field_value ); + } + } + + # -------------------- + # Print a custom field value for display + # $p_def contains the definition of the custom field + # $p_field_id contains the id of the field + # $p_bug_id contains the bug id to display the custom field value for + # NOTE: This probably belongs in the print_api.php + function print_custom_field_value( $p_def, $p_field_id, $p_bug_id ) { + echo string_custom_field_value( $p_def, $p_field_id, $p_bug_id ); + } + + # -------------------- + # Prepare a string containing a custom field value for email + # $p_value value of custom field + # $p_type type of custom field + # NOTE: This probably belongs in the string_api.php + function string_custom_field_value_for_email( $p_value, $p_type ) { + switch( $p_type ) { + case CUSTOM_FIELD_TYPE_EMAIL: + return 'mailto:'.$p_value; + break; + case CUSTOM_FIELD_TYPE_ENUM: + case CUSTOM_FIELD_TYPE_LIST: + case CUSTOM_FIELD_TYPE_MULTILIST: + case CUSTOM_FIELD_TYPE_CHECKBOX: + return str_replace( '|', ', ', $p_value ); + break; + case CUSTOM_FIELD_TYPE_DATE: + if ($p_value != null) { + return date( config_get( 'short_date_format' ), $p_value) ; + } + break ; + default: + return $p_value; + } + return $p_value; + } + +?> | ||||
@liebscher, thanks for your contribution. Why does it look like each line in the file has changed? Will you be able to provide a new patch that doesn't have this issue? |
|
Resolved as duplicate of 0006626. Please add the new patch there. |
|