From d5629ce8efa656cd9ffd5577308bca5e6dcaab9b Mon Sep 17 00:00:00 2001 From: Conrad Vermeulen Date: Wed, 8 Oct 2008 13:37:12 +0000 Subject: [PATCH] KTS-3583 "CLONE -Two Files with Same Name, Different DocID but both listings in KTExplorer point to one file, and not the other.(SUP-963)" Fixed. --- ktapi/KTAPIDocument.inc.php | 52 ++++++++++++++++++++++++++++++++++------------------ lib/documentmanagement/documentutil.inc.php | 214 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------------------------------------------------------- 2 files changed, 168 insertions(+), 98 deletions(-) diff --git a/ktapi/KTAPIDocument.inc.php b/ktapi/KTAPIDocument.inc.php index 4893098..fbc27ed 100644 --- a/ktapi/KTAPIDocument.inc.php +++ b/ktapi/KTAPIDocument.inc.php @@ -6,31 +6,31 @@ * Document Management Made Simple * Copyright (C) 2008 KnowledgeTree Inc. * Portions copyright The Jam Warehouse Software (Pty) Limited - * + * * This program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License version 3 as published by the * Free Software Foundation. - * + * * This program 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 this program. If not, see . - * - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, + * + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, * California 94120-7775, or email info@knowledgetree.com. - * + * * The interactive user interfaces in modified source and object code versions * of this program must display Appropriate Legal Notices, as required under * Section 5 of the GNU General Public License version 3. - * + * * In accordance with Section 7(b) of the GNU General Public License version 3, * these Appropriate Legal Notices must retain the display of the "Powered by - * KnowledgeTree" logo and retain the original copyright notice. If the display of the + * KnowledgeTree" logo and retain the original copyright notice. If the display of the * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices - * must display the words "Powered by KnowledgeTree" and retain the original + * must display the words "Powered by KnowledgeTree" and retain the original * copyright notice. * Contributor( s): ______________________________________ * @@ -113,7 +113,7 @@ class KTAPI_Document extends KTAPI_FolderItem { return ($this->document->getStatusID() == 3); } - + /** * Checks if the document is a shortcut * @@ -132,8 +132,8 @@ class KTAPI_Document extends KTAPI_FolderItem { return $this->document->getSymbolicLinks(); } - - + + /** * This is the constructor for the KTAPI_Folder. * @@ -379,7 +379,7 @@ class KTAPI_Document extends KTAPI_FolderItem //if the document is checked-out by the current user, just return //as no need to check-out again BUT we do need to download //returning here will allow download, but skip check-out - if ( ($this->document->getIsCheckedOut()) && + if ( ($this->document->getIsCheckedOut()) && ($this->document->getCheckedOutUserID() == $_SESSION['userID']) ) { return; @@ -517,6 +517,8 @@ class KTAPI_Document extends KTAPI_FolderItem return $result; } + $tgt_folder = $target_folder->get_folder(); + $name = $this->document->getName(); $clash = KTDocumentUtil::nameExists($target_folder, $name); if ($clash && !is_null($newname)) @@ -526,7 +528,14 @@ class KTAPI_Document extends KTAPI_FolderItem } if ($clash) { - return new PEAR_Error('A document with this title already exists in your chosen folder. Please choose a different folder, or specify a new title for the copied document.'); + if (is_null($newname)) + { + $name = KTDocumentUtil::getUniqueDocumentName($tgt_folder, $name); + } + else + { + return new PEAR_Error('A document with this title already exists in your chosen folder. Please choose a different folder, or specify a new title for the copied document.'); + } } $filename=$this->document->getFilename(); @@ -539,7 +548,14 @@ class KTAPI_Document extends KTAPI_FolderItem } if ($clash) { - return new PEAR_Error('A document with this filename already exists in your chosen folder. Please choose a different folder, or specify a new filename for the copied document.'); + if (is_null($newfilename)) + { + $filename = KTDocumentUtil::getUniqueFilename($tgt_folder, $newfilename); + } + else + { + return new PEAR_Error('A document with this filename already exists in your chosen folder. Please choose a different folder, or specify a new filename for the copied document.'); + } } DBUtil::startTransaction(); @@ -1502,7 +1518,7 @@ class KTAPI_Document extends KTAPI_FolderItem $detail = array(); $document = $this->document; - + // get the document id $detail['document_id'] = (int) $document->getId(); @@ -1625,7 +1641,7 @@ class KTAPI_Document extends KTAPI_FolderItem { $detail['version'] = (float) $detail['version']; } - + //might be unset at the bottom in case of old webservice version //make sure we're using the real document for this one $this->document->switchToRealCore(); @@ -1684,7 +1700,7 @@ class KTAPI_Document extends KTAPI_FolderItem if($wsversion < 3){ unset($detail['linked_document_id']); } - + return $detail; } diff --git a/lib/documentmanagement/documentutil.inc.php b/lib/documentmanagement/documentutil.inc.php index c1d2e8a..6b5a458 100644 --- a/lib/documentmanagement/documentutil.inc.php +++ b/lib/documentmanagement/documentutil.inc.php @@ -683,20 +683,37 @@ $sourceDocument->getName(), } // }}} + function getUniqueFilename($oFolder, $sFilename) { + // this is just a quick refactoring. We should look at a more optimal way of doing this as there are + // quite a lot of queries. + $iFolderId = $oFolder->getId(); + while (KTDocumentUtil::fileExists($oFolder, $sFilename)) { + $oDoc = Document::getByFilenameAndFolder($sFilename, $iFolderId); + $sFilename = KTDocumentUtil::generateNewDocumentFilename($oDoc->getFileName()); + } + return $sFilename; + } + + function getUniqueDocumentName($oFolder, $sFilename) + { + // this is just a quick refactoring. We should look at a more optimal way of doing this as there are + // quite a lot of queries. + $iFolderId = $oFolder->getId(); + while(KTDocumentUtil::nameExists($oFolder, $sFilename)) { + $oDoc = Document::getByNameAndFolder($sFilename, $iFolderId); + $sFilename = KTDocumentUtil::generateNewDocumentName($oDoc->getName()); + } + return $sFilename; + } // {{{ _in_add function &_in_add($oFolder, $sFilename, $oUser, $aOptions) { $aOrigOptions = $aOptions; - while(KTDocumentUtil::fileExists($oFolder, $sFilename)) { - $oDoc = Document::getByFilenameAndFolder($sFilename, $oFolder->getId()); - $sFilename = KTDocumentUtil::generateNewDocumentFilename($oDoc->getFileName()); - } + + $sFilename = KTDocumentUtil::getUniqueFilename($oFolder, $sFilename); $sName = KTUtil::arrayGet($aOptions, 'description', $sFilename); - while(KTDocumentUtil::nameExists($oFolder, $sName)) { - $oDoc = Document::getByNameAndFolder($sName, $oFolder->getId()); - $aOptions['description'] = KTDocumentUtil::generateNewDocumentName($oDoc->getName()); - $sName = KTDocumentUtil::generateNewDocumentName($oDoc->getName()); - } + $sName = KTDocumentUtil::getUniqueDocumentName($oFolder, $sName); + $aOptions['description'] = $sName; $oUploadChannel =& KTUploadChannel::getSingleton(); $oUploadChannel->sendMessage(new KTUploadNewFile($sFilename)); @@ -780,43 +797,48 @@ $sourceDocument->getName(), } // }}} - function generateNewDocumentFilename($sDocFilename){ - if(preg_match("/\([0-9]+\)(\.[^\.]+){1,}$/", $sDocFilename)){ - preg_match("/\([0-9]+\)\./", $sDocFilename, $matches); - $new_one = substr($matches[0], 1); - $new_two = explode(')', $new_one); - $new = $new_two[0]+1; - - $pattern[0] = '/\([0-9]+\)\./'; - $replacement[0] = ' ('.$new.').'; - $sFilename = preg_replace($pattern, $replacement, $sDocFilename); - }else{ - $matches = explode('.', $sDocFilename); - $prefix = $matches[0].' (2)'; - for($i = 1; $i < count($matches); $i++ ){ - $suffix .= '.'.$matches[$i]; - } - $sFilename = $prefix.$suffix; - } - - return $sFilename; + function incrementNameCollissionNumbering($sDocFilename, $skipExtension = false){ + + $iDot = strpos($sDocFilename, '.'); + if ($skipExtension || $iDot === false) + { + if(preg_match("/\(([0-9]+)\)$/", $sDocFilename, $matches, PREG_OFFSET_CAPTURE)) { + + $iCount = $matches[1][0]; + $iPos = $matches[1][1]; + + $iNewCount = $iCount + 1; + $sDocFilename = substr($sDocFilename, 0, $iPos) . $iNewCount . substr($sDocFilename, $iPos + strlen($iCount)); + } + else { + $sDocFilename = $sDocFilename . '(1)'; + } + } + else + { + if(preg_match("/\(([0-9]+)\)(\.[^\.]+)+$/", $sDocFilename, $matches, PREG_OFFSET_CAPTURE)) { + + $iCount = $matches[1][0]; + $iPos = $matches[1][1]; + + $iNewCount = $iCount + 1; + $sDocFilename = substr($sDocFilename, 0, $iPos) . $iNewCount . substr($sDocFilename, $iPos + strlen($iCount)); + } + else { + $sDocFilename = substr($sDocFilename, 0, $iDot) . '(1)' . substr($sDocFilename, $iDot); + } + } + return $sDocFilename; + } + + + function generateNewDocumentFilename($sDocFilename) { + return self::incrementNameCollissionNumbering($sDocFilename, false); } function generateNewDocumentName($sDocName){ - if(preg_match("/\([0-9]+\)$/", $sDocName)){ - preg_match("/\([0-9]+\)$/", $sDocName, $matches); - $new_one = substr($matches[0], 1); - $new_two = explode(')', $new_one); - $new = $new_two[0]+1; - - $pattern[0] = '/\([0-9]+\)$/'; - $replacement[0] = '('.$new.')'; - $sName = preg_replace($pattern, $replacement, $sDocName); - }else{ - $sName = $sDocName.' (2)'; - } - - return $sName; + return self::incrementNameCollissionNumbering($sDocName, true); + } // {{{ fileExists @@ -1039,61 +1061,89 @@ $sourceDocument->getName(), //print '--------------------------------- BEFORE'; //print_r($oDocument); - // grab the "source "data - $sTable = KTUtil::getTableName('documents'); - $sQuery = 'SELECT * FROM ' . $sTable . ' WHERE id = ?'; + // TODO: this is not optimal. we have get() functions that will do SELECT when we already have the data in arrays + + // get the core record to be copied + $sDocumentTable = KTUtil::getTableName('documents'); + $sQuery = 'SELECT * FROM ' . $sDocumentTable . ' WHERE id = ?'; $aParams = array($oDocument->getId()); $aCoreRow = DBUtil::getOneResult(array($sQuery, $aParams)); + // we unset the id as a new one will be created on insert unset($aCoreRow['id']); - $aCoreRow['modified'] = date('Y-m-d H:i:s'); - $aCoreRow['folder_id'] = $oDestinationFolder->getId(); // new location. - $id = DBUtil::autoInsert($sTable, $aCoreRow); - if (PEAR::isError($id)) { return $id; } - // we still have a bogus md_version, but integrity holds, so fix it now. - $oCore = KTDocumentCore::get($id); - - // Get the metadata version for the source document - $sTable = KTUtil::getTableName('document_metadata_version'); - $sQuery = 'SELECT * FROM ' . $sTable . ' WHERE id = ?'; - $aParams = array($oDocument->getMetadataVersionId()); + // get a copy of the latest metadata version for the copied document + $iOldMetadataId = $aCoreRow['metadata_version_id']; + $sMetadataTable = KTUtil::getTableName('document_metadata_version'); + $sQuery = 'SELECT * FROM ' . $sMetadataTable . ' WHERE id = ?'; + $aParams = array($iOldMetadataId); $aMDRow = DBUtil::getOneResult(array($sQuery, $aParams)); + // we unset the id as a new one will be created on insert unset($aMDRow['id']); - // Copy the source metadata into the destination document - $aMDRow['document_id'] = $oCore->getId(); - if(!empty($sDestinationDocName)){ + // set the name for the document, possibly using name collission + if (empty($sDestinationDocName)){ + $aMDRow['name'] = KTDocumentUtil::getUniqueDocumentName($oDestinationFolder, $aMDRow['name']); + } + else { $aMDRow['name'] = $sDestinationDocName; - $aMDRow['description'] = $sDestinationDocName; } - $id = DBUtil::autoInsert($sTable, $aMDRow); - if (PEAR::isError($id)) { return $id; } - $oCore->setMetadataVersionId($id); - $oMDV = KTDocumentMetadataVersion::get($id); - // Get the content version for the source document - $sTable = KTUtil::getTableName('document_content_version'); - $sQuery = 'SELECT * FROM ' . $sTable . ' WHERE id = ?'; - $aParams = array($oDocument->_oDocumentContentVersion->getId()); + // get a copy of the latest content version for the copied document + $iOldContentId = $aMDRow['content_version_id']; + $sContentTable = KTUtil::getTableName('document_content_version'); + $sQuery = 'SELECT * FROM ' . $sContentTable . ' WHERE id = ?'; + $aParams = array($iOldContentId); $aContentRow = DBUtil::getOneResult(array($sQuery, $aParams)); + // we unset the id as a new one will be created on insert unset($aContentRow['id']); - // Copy the source content into the destination document - $aContentRow['document_id'] = $oCore->getId(); - if(!empty($sDestinationDocName)){ + // set the filename for the document, possibly using name collission + if(empty($sDestinationDocName)) { + $aContentRow['filename'] = KTDocumentUtil::getUniqueFilename($oDestinationFolder, $aContentRow['filename']); + } + else { $aContentRow['filename'] = $sDestinationDocName; } - $id = DBUtil::autoInsert($sTable, $aContentRow); + + // create the new document record + $aCoreRow['modified'] = date('Y-m-d H:i:s'); + $aCoreRow['folder_id'] = $oDestinationFolder->getId(); // new location. + $id = DBUtil::autoInsert($sDocumentTable, $aCoreRow); + if (PEAR::isError($id)) { return $id; } + $iNewDocumentId = $id; + + // create the new metadata record + $aMDRow['document_id'] = $iNewDocumentId; + $aMDRow['description'] = $aMDRow['name']; + $id = DBUtil::autoInsert($sMetadataTable, $aMDRow); + if (PEAR::isError($id)) { return $id; } + $iNewMetadataId = $id; + + // the document metadata version is still pointing to the original + $aCoreUpdate = array(); + $aCoreUpdate['metadata_version_id'] = $iNewMetadataId; + $aCoreUpdate['metadata_version'] = 0; + + // create the new content version + $aContentRow['document_id'] = $iNewDocumentId; + $id = DBUtil::autoInsert($sContentTable, $aContentRow); if (PEAR::isError($id)) { return $id; } - $oMDV->setContentVersionId($id); + $iNewContentId = $id; - $res = $oCore->update(); + // the metadata content version is still pointing to the original + $aMetadataUpdate = array(); + $aMetadataUpdate['content_version_id'] = $iNewContentId; + $aMetadataUpdate['metadata_version'] = 0; + + // apply the updates to the document and metadata records + $res = DBUtil::autoUpdate($sDocumentTable, $aCoreUpdate, $iNewDocumentId); if (PEAR::isError($res)) { return $res; } - $res = $oMDV->update(); + + $res = DBUtil::autoUpdate($sMetadataTable, $aMetadataUpdate, $iNewMetadataId); if (PEAR::isError($res)) { return $res; } // now, we have a semi-sane document object. get it. - $oNewDocument = Document::get($oCore->getId()); + $oNewDocument = Document::get($iNewDocumentId); //print '--------------------------------- AFTER'; //print_r($oDocument); @@ -1101,7 +1151,7 @@ $sourceDocument->getName(), //print_r($oNewDocument); // copy the metadata from old to new. - $res = KTDocumentUtil::copyMetadata($oNewDocument, $oDocument->getMetadataVersionId()); + $res = KTDocumentUtil::copyMetadata($oNewDocument, $iOldMetadataId); if (PEAR::isError($res)) { return $res; } // Ensure the copied document is not checked out @@ -1112,7 +1162,6 @@ $sourceDocument->getName(), $oStorage =& KTStorageManagerUtil::getSingleton(); $res = $oStorage->copy($oDocument, $oNewDocument); - $oOriginalFolder = Folder::get($oDocument->getFolderId()); $iOriginalFolderPermissionObjectId = $oOriginalFolder->getPermissionObjectId(); $iDocumentPermissionObjectId = $oDocument->getPermissionObjectId(); @@ -1227,12 +1276,17 @@ $sourceDocument->getName(), //put the document in the new folder $oDocument->setFolderID($oFolder->getId()); + $sName = $oDocument->getName(); + $sFilename = $oDocument->getFileName(); + + $oDocument->setFileName(KTDocumentUtil::getUniqueFilename($oToFolder, $sFilename)); + $oDocument->setName(KTDocumentUtil::getUniqueDocumentName($oToFolder, $sName)); + $res = $oDocument->update(); if (PEAR::isError($res)) { return $res; } - //move the document on the file system(not if it's a symlink) if(!$oDocument->isSymbolicLink()){ $oStorage =& KTStorageManagerUtil::getSingleton(); -- libgit2 0.21.4