View Issue Details

IDProjectCategoryView StatusLast Update
0008878mantisbtadministrationpublic2008-07-31 17:43
Reporterebenius Assigned Togiallu  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
Product Version1.1.1 
Summary0008878: Copy Versions scrambles Timestamp
Description

When copying versions from one project to another one (in Manage Project), the timestamp is being scrambled. Possibly there is a problem in time format conversions, from unixtimstamp to db_timestamp or vice versa.

Additional Information

Might be related to: 0008526

TagsNo tags attached.
Attached Files
version_api.php (13,900 bytes)   
<?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: version_api.php,v 1.24.2.1 2007-10-13 22:35:48 giallu Exp $
	# --------------------------------------------------------

	### Version API ###

	#=========================================
	# Version Data Structure Definition
	#===================================
	class VersionData {
		var $id = 0;
		var $project_id = 0;
		var $version = '';
		var $description = '';
		var $released = 1;
		var $date_order = '';
	}

	#===================================
	# Boolean queries and ensures
	#===================================

	$g_cache_versions = array();

	# --------------------
	# Cache a version row if necessary and return the cached copy
	#  If the second parameter is true (default), trigger an error
	#  if the version can't be found.  If the second parameter is
	#  false, return false if the version can't be found.
	function version_cache_row( $p_version_id, $p_trigger_errors = true ) {
		global $g_cache_versions;

		$c_version_id = db_prepare_int( $p_version_id );
		$t_project_version_table = config_get( 'mantis_project_version_table' );

		if ( isset( $g_cache_versions[$c_version_id] ) ) {
			return $g_cache_versions[$c_version_id];
		}

		$query = "SELECT *
				  FROM $t_project_version_table
				  WHERE id='$c_version_id'";
		$result = db_query( $query );

		if ( 0 == db_num_rows( $result ) ) {
			$g_cache_versions[$c_version_id] = false;

			if ( $p_trigger_errors ) {
				error_parameters( $p_version_id );
				trigger_error( ERROR_VERSION_NOT_FOUND, ERROR );
			} else {
				return false;
			}
		}

		$row = db_fetch_array( $result );
		$row['date_order'] = db_unixtimestamp( $row['date_order'] );
		$g_cache_versions[$c_version_id] = $row;

		return $row;
	}

	# --------------------
	# Check whether the version exists
	# $p_project_id : null will use the current project, otherwise the specified project
	# Returns true if the version exists, false otherwise
	function version_exists( $p_version_id ) {
		return version_cache_row( $p_version_id, false ) !== false;
	}

	# --------------------
	# Check whether the version name is unique
	# Returns true if the name is unique, false otherwise
	function version_is_unique( $p_version, $p_project_id = null ) {
		return version_get_id( $p_version, $p_project_id ) === false;
	}

	# --------------------
	# Check whether the version exists
	# Trigger an error if it does not
	function version_ensure_exists( $p_version_id ) {
		if ( !version_exists( $p_version_id ) ) {
			error_parameters( $p_version_id );
			trigger_error( ERROR_VERSION_NOT_FOUND, ERROR );
		}
	}

	# --------------------
	# Check whether the version is unique within a project
	# Trigger an error if it is not
	function version_ensure_unique( $p_version, $p_project_id = null ) {
		if ( !version_is_unique( $p_version, $p_project_id ) ) {
			trigger_error( ERROR_VERSION_DUPLICATE, ERROR );
		}
	}


	#===================================
	# Creation / Deletion / Updating
	#===================================

	# --------------------
	# Add a version to the project
	function version_add( $p_project_id, $p_version, $p_released = VERSION_RELEASED, $p_description = '', $p_date_order = null) {
		$c_project_id   = db_prepare_int( $p_project_id );
		$c_released     = db_prepare_int( $p_released );
		$c_version      = db_prepare_string( $p_version );
		$c_description  = db_prepare_string( $p_description );

		if ( null === $p_date_order ) {
			#$c_date_order = db_now();
      $c_date_order = db_date(time());
		} else {
			#$c_date_order = db_timestamp( $p_date_order );
			$c_date_order =  db_date( $p_date_order );
		}

		version_ensure_unique( $p_version, $p_project_id );

		$t_project_version_table = config_get( 'mantis_project_version_table' );

		$query = "INSERT INTO $t_project_version_table
					( project_id, version, date_order, description, released )
				  VALUES
					( '$c_project_id', '$c_version', '$c_date_order', '$c_description', '$c_released' )";
					#( '$c_project_id', '$c_version', " . $c_date_order . ", '$c_description', '$c_released' )";
		db_query( $query );

		# db_query() errors on failure so:
		return true;
	}

	# --------------------
	# Update the definition of a version
	function version_update( $p_version_info ) {
		version_ensure_exists( $p_version_info->id );

		$t_old_version_name = version_get_field( $p_version_info->id, 'version' );

		# check for duplicates
		if ( ( strtolower( $t_old_version_name ) != strtolower( $p_version_info->version ) ) &&
			 !version_is_unique( $p_version_info->version, $p_version_info->project_id ) ) {
			trigger_error( ERROR_VERSION_DUPLICATE, ERROR );
		}

		$c_version_id   = db_prepare_int( $p_version_info->id );
		$c_version_name = db_prepare_string( $p_version_info->version );
		$c_old_version_name = db_prepare_string( $t_old_version_name );
		$c_description  = db_prepare_string( $p_version_info->description );
		$c_released     = db_prepare_int( $p_version_info->released );
		#$c_date_order   = db_timestamp( $p_version_info->date_order );
		$c_date_order   =  db_date ($p_version_info->date_order );
		$c_project_id	= db_prepare_int( $p_version_info->project_id );

		$t_project_version_table	= config_get( 'mantis_project_version_table' );
		$t_bug_table				= config_get( 'mantis_bug_table' );

		$query = "UPDATE $t_project_version_table
				  SET version='$c_version_name',
					description='$c_description',
					released='$c_released',
					#date_order=$c_date_order
					date_order='$c_date_order'
				  WHERE id='$c_version_id'";
		db_query( $query );

		if ( $c_version_name != $c_old_version_name ) {
			$query = "UPDATE $t_bug_table
					  SET version='$c_version_name'
					  WHERE ( project_id='$c_project_id' ) AND ( version='$c_old_version_name' )";
			db_query( $query );

			$query = "UPDATE $t_bug_table
					  SET fixed_in_version='$c_version_name'
					  WHERE ( project_id='$c_project_id' ) AND ( fixed_in_version='$c_old_version_name' )";
			db_query( $query );

			$query = "UPDATE $t_bug_table
					  SET target_version='$c_version_name'
					  WHERE ( project_id='$c_project_id' ) AND ( target_version='$c_old_version_name' )";
			db_query( $query );

			# @@@ We should consider using ids instead of names for foreign keys.  The main advantage of using the names are:
			# 		- for history the version history entries will still be valid even if the version is deleted in the future. --  we can ban deleting referenced versions.
			#		- when an issue is copied or moved from one project to another, we can keep the last version with the issue even if it doesn't exist in the new project.  Also previous history entries remain valid.
			# @@@ We should update the history for version, fixed_in_version, and target_version.
			# @@@ We probably need to update the saved filters too?
		}

		# db_query() errors on failure so:
		return true;
	}

	# --------------------
	# Remove a version from the project
	function version_remove( $p_version_id, $p_new_version='' ) {
		$c_version_id	= db_prepare_int( $p_version_id );
		$c_new_version	= db_prepare_string( $p_new_version );

		version_ensure_exists( $p_version_id );

		$t_old_version = version_get_field( $p_version_id, 'version' );
		$t_project_id = version_get_field( $p_version_id, 'project_id' );

		$c_old_version = db_prepare_string( $t_old_version );
		$c_project_id = db_prepare_int( $t_project_id );

		$t_project_version_table	= config_get( 'mantis_project_version_table' );
		$t_bug_table				= config_get( 'mantis_bug_table' );

		$query = "DELETE FROM $t_project_version_table
				  WHERE id='$c_version_id'";
		db_query( $query );

		$query = "UPDATE $t_bug_table
				  SET version='$c_new_version'
				  WHERE project_id='$c_project_id' AND version='$c_old_version'";
		db_query( $query );

		$query = "UPDATE $t_bug_table
				  SET fixed_in_version='$c_new_version'
				  WHERE ( project_id='$c_project_id' ) AND ( fixed_in_version='$c_old_version' )";
		db_query( $query );

		# db_query() errors on failure so:
		return true;
	}

	# --------------------
	# Remove all versions associated with a project
	function version_remove_all( $p_project_id ) {
		$c_project_id = db_prepare_int( $p_project_id );

		$t_project_version_table	= config_get( 'mantis_project_version_table' );
		$t_bug_table				= config_get( 'mantis_bug_table' );

		$query = "DELETE FROM $t_project_version_table
	  			  WHERE project_id='$c_project_id'";

		db_query( $query );

		$query = "UPDATE $t_bug_table
				  SET version=''
				  WHERE project_id='$c_project_id'";
		db_query( $query );

		$query = "UPDATE $t_bug_table
				  SET fixed_in_version=''
				  WHERE project_id='$c_project_id'";
		db_query( $query );

		# db_query() errors on failure so:
		return true;
	}


	#===================================
	# Data Access
	#===================================

	# --------------------
	# Return all versions for the specified project
	function version_get_all_rows( $p_project_id, $p_released = null ) {
		$c_project_id = db_prepare_int( $p_project_id );

		if ( $p_released === null ) {
			$t_released_where = '';
		} else {
			$c_released = db_prepare_int( $p_released );
			$t_released_where = "AND ( released = $c_released )";
		}

		$t_project_version_table = config_get( 'mantis_project_version_table' );

		$query = "SELECT *
				  FROM $t_project_version_table
				  WHERE project_id='$c_project_id' $t_released_where
				  ORDER BY date_order DESC";
		$result = db_query( $query );
		$count = db_num_rows( $result );
		$rows = array();
		for ( $i = 0 ; $i < $count ; $i++ ) {
			$row = db_fetch_array( $result );
			$row['date_order'] = db_unixtimestamp( $row['date_order'] );
			$rows[] = $row;
		}
		return $rows;
	}
	
	# --------------------
	# Return all versions for the specified project, including subprojects
	function version_get_all_rows_with_subs( $p_project_id, $p_released = null ) {
		$t_project_where = helper_project_specific_where( $p_project_id );

		if ( $p_released === null ) {
			$t_released_where = '';
		} else {
			$c_released = db_prepare_int( $p_released );
			$t_released_where = "AND ( released = $c_released )";
		}

		$t_project_version_table = config_get( 'mantis_project_version_table' );

		$query = "SELECT *
				  FROM $t_project_version_table
				  WHERE $t_project_where $t_released_where
				  ORDER BY date_order DESC";
		$result = db_query( $query );
		$count = db_num_rows( $result );
		$rows = array();
		for ( $i = 0 ; $i < $count ; $i++ ) {
			$row = db_fetch_array( $result );
			$row['date_order'] = db_unixtimestamp( $row['date_order'] );
			$rows[] = $row;
		}
		return $rows;
	}	

	# --------------------
	# Get the version_id, given the project_id and $p_version_id
	# returns false if not found, otherwise returns the id.
	function version_get_id( $p_version, $p_project_id = null ) {
		$c_version       = db_prepare_string( $p_version );

		if ( $p_project_id === null ) {
			$c_project_id = helper_get_current_project();
		} else {
			$c_project_id = db_prepare_int( $p_project_id );
		}

		$t_project_version_table = config_get( 'mantis_project_version_table' );

		$query = "SELECT id
					FROM $t_project_version_table
					WHERE project_id='$c_project_id' AND
						version='$c_version'";

		$result = db_query( $query );

		if ( 0 == db_num_rows( $result ) ) {
			return false;
		} else {
			return db_result( $result );
		}
	}

	# --------------------
	# Get the specified field name for the specified version id.
	# triggers an error if version not found, otherwise returns the field value.
	function version_get_field( $p_version_id, $p_field_name ) {
		$row = version_cache_row( $p_version_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 information about a version given its id
	function version_get( $p_version_id ) {
		$row = version_cache_row( $p_version_id );

		$t_version_data = new VersionData;
		$t_row_keys = array_keys( $row );
		$t_vars = get_object_vars( $t_version_data );

		# Check each variable in the class
		foreach ( $t_vars as $var => $val ) {
			# If we got a field from the DB with the same name
			if ( in_array( $var, $t_row_keys, true ) ) {
				# Store that value in the object
				$t_version_data->$var = $row[$var];
			}
		}

		return $t_version_data;
	}

	# --------------------
	# Return a copy of the version structure with all the instvars prepared for db insertion
	function version_prepare_db( $p_version_info ) {
		$p_version_info->id		= db_prepare_int( $p_version_info->id );
		$p_version_info->project_id	= db_prepare_int( $p_version_info->project_id );
		$p_version_info->version	= db_prepare_string( $p_version_info->version );
		$p_version_info->description	= db_prepare_string( $p_version_info->description );
		$p_version_info->released	= db_prepare_int( $p_version_info->released );
		$p_version_info->date_order	= db_prepare_string( $p_version_info->date_order );

		return $p_version_info;
	}
?>
version_api.php (13,900 bytes)   

Relationships

has duplicate 0008792 closedgiallu "Copy version from" inserts bogus date 
child of 0008880 closedgiallu Problem with date formatting in db_prepare_date function 

Activities

alpoplavsky

alpoplavsky

2008-02-12 05:51

reporter   ~0017016

Change done in core/version_api.php using db_date function in version_add and version_update
See version_api.php attached (modification done on version 1.1.0)

giallu

giallu

2008-02-12 06:09

reporter   ~0017017

maybe child of 0008880?

jamiei

jamiei

2008-03-03 05:17

reporter   ~0017248

Is there a reason that alpoplavsky's patch isn't in version 1.1.1? The patch seems to work and it's a pain to copy versions without it!

giallu

giallu

2008-03-03 05:57

reporter   ~0017249

ok, I need to be more verbose.

Can you please check if the patch submitted in 0008880 also fixes this problem?

If not, can you please submit a patch made with "diff -u" ? With the full file I can't spot easily where the changes are.

Thank you in advance for your help

jamiei

jamiei

2008-03-03 06:15

reporter   ~0017250

The patch in issue 0008880 has fixed the issue.

Thanks, Jamie

Borszczuk

Borszczuk

2008-03-05 08:16

reporter   ~0017259

this is dupe of 0008792 (or one of them can be flagged as dupe)

giallu

giallu

2008-03-05 19:39

reporter   ~0017264

I applied the patch in 0008880.

Thanks for the help

Related Changesets

MantisBT: master-1.1.x 5cf74fea

2008-03-05 19:34

giallu


Details Diff
Fix 8880: Problem with date formatting in db_prepare_date function

This should also fix 8878 and 8792

git-svn-id: http://mantisbt.svn.sourceforge.net/svnroot/mantisbt/branches/BRANCH_1_1_0@5089 <a class="text" href="/?p=mantisbt.git;a=object;h=f5dc347c">f5dc347c</a>-c33d-0410-90a0-b07cc1902cb9
Affected Issues
0008878, 0008880
mod - core/database_api.php Diff File