diff --git a/browse.php b/browse.php index 6bb1b66..4179468 100644 --- a/browse.php +++ b/browse.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): ______________________________________ */ @@ -68,196 +68,209 @@ $sectionName = 'browse'; class BrowseDispatcher extends KTStandardDispatcher { - var $sName = 'ktcore.actions.folder.view'; - - var $oFolder = null; - var $sSection = 'browse'; - var $browse_mode = null; - var $query = null; - var $resultURL; - var $sHelpPage = 'ktcore/browse.html'; - var $editable; - - function BrowseDispatcher() { - $this->aBreadcrumbs = array( - array('action' => 'browse', 'name' => _kt('Browse')), - ); - return parent::KTStandardDispatcher(); - } - - function check() { - $this->browse_mode = KTUtil::arrayGet($_REQUEST, 'fBrowseMode', 'folder'); - $action = KTUtil::arrayGet($_REQUEST, $this->event_var, 'main'); - $this->editable = false; - - - // catch the alternative actions. - if ($action != 'main') { - return true; - } - - // if we're going to main ... - - // folder browse mode - if ($this->browse_mode == 'folder') { - $in_folder_id = KTUtil::arrayGet($_REQUEST, 'fFolderId'); - if (empty($in_folder_id)) { - $oConfig = KTConfig::getSingleton(); - if ($oConfig->get('tweaks/browseToUnitFolder')) { - $iHomeFolderId = $this->oUser->getHomeFolderId(); - if ($iHomeFolderId) { - $in_folder_id = $iHomeFolderId; - } - } - } - - $folder_id = (int) $in_folder_id; // conveniently, will be 0 if not possible. - if ($folder_id == 0) { - $folder_id = 1; - } - - $_REQUEST['fBrowseMode'] = 'folder'; - - // here we need the folder object to do the breadcrumbs. - $oFolder =& Folder::get($folder_id); - if (PEAR::isError($oFolder)) { - return false; // just fail. - } - - // check whether the user can edit this folder - $oPerm = KTPermission::getByName('ktcore.permissions.write'); - if (KTPermissionUtil::userHasPermissionOnItem($this->oUser, $oPerm, $oFolder)) { - $this->editable = true; - } else { - $this->editable = false; - } - - // set the title and breadcrumbs... - $this->oPage->setTitle(_kt('Browse')); - - if (KTPermissionUtil::userHasPermissionOnItem($this->oUser, 'ktcore.permissions.folder_details', $oFolder)) { - $this->oPage->setSecondaryTitle($oFolder->getName()); - } else { - if (KTBrowseUtil::inAdminMode($this->oUser, $oFolder)) { - $this->oPage->setSecondaryTitle(sprintf('(%s)', $oFolder->getName())); - } else { - $this->oPage->setSecondaryTitle('...'); - } - } - - $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForFolder($oFolder)); - $this->oFolder =& $oFolder; - - - // we now have a folder, and need to create the query. - $aOptions = array( + var $sName = 'ktcore.actions.folder.view'; + + var $oFolder = null; + var $sSection = 'browse'; + var $browse_mode = null; + var $query = null; + var $resultURL; + var $sHelpPage = 'ktcore/browse.html'; + var $editable; + + function BrowseDispatcher() { + $this->aBreadcrumbs = array( + array('action' => 'browse', 'name' => _kt('Browse')), + ); + return parent::KTStandardDispatcher(); + } + + function check() { + $this->browse_mode = KTUtil::arrayGet($_REQUEST, 'fBrowseMode', 'folder'); + $action = KTUtil::arrayGet($_REQUEST, $this->event_var, 'main'); + $this->editable = false; + + + // catch the alternative actions. + if ($action != 'main') { + return true; + } + + // if we're going to main ... + + // folder browse mode + if ($this->browse_mode == 'folder') { + $in_folder_id = KTUtil::arrayGet($_REQUEST, 'fFolderId'); + if (empty($in_folder_id)) { + $oConfig = KTConfig::getSingleton(); + if ($oConfig->get('tweaks/browseToUnitFolder')) { + $iHomeFolderId = $this->oUser->getHomeFolderId(); + if ($iHomeFolderId) { + $in_folder_id = $iHomeFolderId; + } + } + } + + $folder_id = (int) $in_folder_id; // conveniently, will be 0 if not possible. + if ($folder_id == 0) { + $folder_id = 1; + } + + $_REQUEST['fBrowseMode'] = 'folder'; + + // here we need the folder object to do the breadcrumbs. + $oFolder =& Folder::get($folder_id); + if (PEAR::isError($oFolder)) { + return false; // just fail. + } + + // check whether the user can edit this folder + $oPerm = KTPermission::getByName('ktcore.permissions.write'); + if (KTPermissionUtil::userHasPermissionOnItem($this->oUser, $oPerm, $oFolder)) { + $this->editable = true; + } else { + $this->editable = false; + } + + // set the title and breadcrumbs... + $this->oPage->setTitle(_kt('Browse')); + + if (KTPermissionUtil::userHasPermissionOnItem($this->oUser, 'ktcore.permissions.folder_details', $oFolder)) { + $this->oPage->setSecondaryTitle($oFolder->getName()); + } else { + if (KTBrowseUtil::inAdminMode($this->oUser, $oFolder)) { + $this->oPage->setSecondaryTitle(sprintf('(%s)', $oFolder->getName())); + } else { + $this->oPage->setSecondaryTitle('...'); + } + } + + //Figure out if we came here by navigating trough a shortcut. + //If we came here from a shortcut, the breadcrumbspath should be relative + //to the shortcut folder. + $iSymLinkFolderId = KTUtil::arrayGet($_REQUEST, 'fShortcutFolder', null); + if(is_numeric($iSymLinkFolderId)){ + $oBreadcrumbsFolder = Folder::get($iSymLinkFolderId); + $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForFolder($oBreadcrumbsFolder,array('final' => false))); + $this->aBreadcrumbs[] = array('name'=>$oFolder->getName()); + }else{ + $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForFolder($oFolder)); + } + $this->oFolder =& $oFolder; + + + // we now have a folder, and need to create the query. + $aOptions = array( 'ignorepermissions' => KTBrowseUtil::inAdminMode($this->oUser, $oFolder), - ); - $this->oQuery = new BrowseQuery($oFolder->getId(), $this->oUser, $aOptions); - $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fFolderId=%d', $oFolder->getId())); - - // and the portlets - $portlet = new KTActionPortlet(sprintf(_kt('About this folder'))); - $aActions = KTFolderActionUtil::getFolderInfoActionsForFolder($this->oFolder, $this->oUser); - $portlet->setActions($aActions,$this->sName); - $this->oPage->addPortlet($portlet); - - $portlet = new KTActionPortlet(sprintf(_kt('Actions on this folder'))); - $aActions = KTFolderActionUtil::getFolderActionsForFolder($oFolder, $this->oUser); - $portlet->setActions($aActions,null); - $this->oPage->addPortlet($portlet); - - - - } else if ($this->browse_mode == 'lookup_value') { - // browsing by a lookup value - - $this->editable = false; - - // check the inputs - $field = KTUtil::arrayGet($_REQUEST, 'fField', null); - $oField = DocumentField::get($field); - if (PEAR::isError($oField) || ($oField == false)) { - $this->errorRedirectToMain('No Field selected.'); - exit(0); - } - $value = KTUtil::arrayGet($_REQUEST, 'fValue', null); - $oValue = MetaData::get($value); - if (PEAR::isError($oValue) || ($oValue == false)) { - $this->errorRedirectToMain('No Value selected.'); - exit(0); - } - - - $this->oQuery = new ValueBrowseQuery($oField, $oValue); - $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'], - sprintf('fBrowseMode=lookup_value&fField=%d&fValue=%d', $field, $value)); - - // setup breadcrumbs - $this->aBreadcrumbs = - array( - array('name' => _kt('Lookup Values'), + ); + $this->oQuery = new BrowseQuery($oFolder->getId(), $this->oUser, $aOptions); + + $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fFolderId=%d', $oFolder->getId())); + + // and the portlets + $portlet = new KTActionPortlet(sprintf(_kt('About this folder'))); + $aActions = KTFolderActionUtil::getFolderInfoActionsForFolder($this->oFolder, $this->oUser); + $portlet->setActions($aActions,$this->sName); + $this->oPage->addPortlet($portlet); + + $portlet = new KTActionPortlet(sprintf(_kt('Actions on this folder'))); + $aActions = KTFolderActionUtil::getFolderActionsForFolder($oFolder, $this->oUser); + $portlet->setActions($aActions,null); + $this->oPage->addPortlet($portlet); + + + + } else if ($this->browse_mode == 'lookup_value') { + // browsing by a lookup value + + $this->editable = false; + + // check the inputs + $field = KTUtil::arrayGet($_REQUEST, 'fField', null); + $oField = DocumentField::get($field); + if (PEAR::isError($oField) || ($oField == false)) { + $this->errorRedirectToMain('No Field selected.'); + exit(0); + } + $value = KTUtil::arrayGet($_REQUEST, 'fValue', null); + $oValue = MetaData::get($value); + if (PEAR::isError($oValue) || ($oValue == false)) { + $this->errorRedirectToMain('No Value selected.'); + exit(0); + } + + + $this->oQuery = new ValueBrowseQuery($oField, $oValue); + $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'], + sprintf('fBrowseMode=lookup_value&fField=%d&fValue=%d', $field, $value)); + + // setup breadcrumbs + $this->aBreadcrumbs = + array( + array('name' => _kt('Lookup Values'), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectField')), - array('name' => $oField->getName(), + array('name' => $oField->getName(), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectLookup&fField=' . $oField->getId())), - array('name' => $oValue->getName(), + array('name' => $oValue->getName(), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fBrowseMode=lookup_value&fField=%d&fValue=%d', $field, $value)))); - } else if ($this->browse_mode == 'document_type') { - // browsing by document type + } else if ($this->browse_mode == 'document_type') { + // browsing by document type + + $this->editable = false; + $doctype = KTUtil::arrayGet($_REQUEST, 'fType',null); + $oDocType = DocumentType::get($doctype); + if (PEAR::isError($oDocType) || ($oDocType == false)) { + $this->errorRedirectToMain('No Document Type selected.'); + exit(0); + } - $this->editable = false; - $doctype = KTUtil::arrayGet($_REQUEST, 'fType',null); - $oDocType = DocumentType::get($doctype); - if (PEAR::isError($oDocType) || ($oDocType == false)) { - $this->errorRedirectToMain('No Document Type selected.'); - exit(0); - } + $this->oQuery = new TypeBrowseQuery($oDocType); - $this->oQuery = new TypeBrowseQuery($oDocType); + // FIXME probably want to redirect to self + action=selectType + $this->aBreadcrumbs[] = array('name' => _kt('Document Types'), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectType')); + $this->aBreadcrumbs[] = array('name' => $oDocType->getName(), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'fBrowseMode=document_type&fType=' . $oDocType->getId())); - // FIXME probably want to redirect to self + action=selectType - $this->aBreadcrumbs[] = array('name' => _kt('Document Types'), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectType')); - $this->aBreadcrumbs[] = array('name' => $oDocType->getName(), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'fBrowseMode=document_type&fType=' . $oDocType->getId())); + $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fType=%s&fBrowseMode=document_type', $doctype));; - $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fType=%s&fBrowseMode=document_type', $doctype));; + } else { + // FIXME what should we do if we can't initiate the browse? we "pretend" to have no perms. + return false; + } - } else { - // FIXME what should we do if we can't initiate the browse? we "pretend" to have no perms. - return false; - } + return true; + } - return true; - } + function do_main() { + $oColumnRegistry =& KTColumnRegistry::getSingleton(); - function do_main() { - $oColumnRegistry =& KTColumnRegistry::getSingleton(); + $collection = new AdvancedCollection; + $collection->addColumns($oColumnRegistry->getColumnsForView('ktcore.views.browse')); - $collection = new AdvancedCollection; - $collection->addColumns($oColumnRegistry->getColumnsForView('ktcore.views.browse')); + $aOptions = $collection->getEnvironOptions(); // extract data from the environment + $aOptions['result_url'] = $this->resultURL; + $aOptions['is_browse'] = true; - $aOptions = $collection->getEnvironOptions(); // extract data from the environment - $aOptions['result_url'] = $this->resultURL; - $aOptions['is_browse'] = true; + - $collection->setOptions($aOptions); - $collection->setQueryObject($this->oQuery); - $collection->setColumnOptions('ktcore.columns.selection', array( + $collection->setOptions($aOptions); + $collection->setQueryObject($this->oQuery); + $collection->setColumnOptions('ktcore.columns.selection', array( 'rangename' => 'selection', 'show_folders' => true, 'show_documents' => true, - )); + )); - // get bulk actions - $aBulkActions = KTBulkActionUtil::getAllBulkActions(); + // get bulk actions + $aBulkActions = KTBulkActionUtil::getAllBulkActions(); - $oTemplating =& KTTemplating::getSingleton(); - $oTemplate = $oTemplating->loadTemplate('kt3/browse'); - $aTemplateData = array( + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('kt3/browse'); + $aTemplateData = array( 'context' => $this, 'collection' => $collection, 'browse_mode' => $this->browse_mode, @@ -265,160 +278,160 @@ class BrowseDispatcher extends KTStandardDispatcher { 'bulkactions' => $aBulkActions, 'browseutil' => new KTBrowseUtil(), 'returnaction' => 'browse', - ); - if ($this->oFolder) { - $aTemplateData['returndata'] = $this->oFolder->getId(); - } - return $oTemplate->render($aTemplateData); - } + ); + if ($this->oFolder) { + $aTemplateData['returndata'] = $this->oFolder->getId(); + } + return $oTemplate->render($aTemplateData); + } - function do_selectField() { - $aFields = DocumentField::getList('has_lookup = 1'); + function do_selectField() { + $aFields = DocumentField::getList('has_lookup = 1'); - if (empty($aFields)) { - $this->errorRedirectToMain(_kt('No lookup fields available.')); - exit(0); - } + if (empty($aFields)) { + $this->errorRedirectToMain(_kt('No lookup fields available.')); + exit(0); + } - $_REQUEST['fBrowseMode'] = 'lookup_value'; + $_REQUEST['fBrowseMode'] = 'lookup_value'; - $oTemplating =& KTTemplating::getSingleton(); - $oTemplate = $oTemplating->loadTemplate('kt3/browse_lookup_selection'); - $aTemplateData = array( + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('kt3/browse_lookup_selection'); + $aTemplateData = array( 'context' => $this, 'fields' => $aFields, - ); - return $oTemplate->render($aTemplateData); - } + ); + return $oTemplate->render($aTemplateData); + } - function do_selectLookup() { - $field = KTUtil::arrayGet($_REQUEST, 'fField', null); - $oField = DocumentField::get($field); - if (PEAR::isError($oField) || ($oField == false) || (!$oField->getHasLookup())) { - $this->errorRedirectToMain('No Field selected.'); - exit(0); - } + function do_selectLookup() { + $field = KTUtil::arrayGet($_REQUEST, 'fField', null); + $oField = DocumentField::get($field); + if (PEAR::isError($oField) || ($oField == false) || (!$oField->getHasLookup())) { + $this->errorRedirectToMain('No Field selected.'); + exit(0); + } - $_REQUEST['fBrowseMode'] = 'lookup_value'; + $_REQUEST['fBrowseMode'] = 'lookup_value'; - $aValues = MetaData::getByDocumentField($oField); + $aValues = MetaData::getByDocumentField($oField); - $oTemplating =& KTTemplating::getSingleton(); - $oTemplate = $oTemplating->loadTemplate('kt3/browse_lookup_value'); - $aTemplateData = array( + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('kt3/browse_lookup_value'); + $aTemplateData = array( 'context' => $this, 'oField' => $oField, 'values' => $aValues, - ); - return $oTemplate->render($aTemplateData); - } + ); + return $oTemplate->render($aTemplateData); + } - function do_selectType() { - $aTypes = DocumentType::getList(); - // FIXME what is the error message? + function do_selectType() { + $aTypes = DocumentType::getList(); + // FIXME what is the error message? - $_REQUEST['fBrowseMode'] = 'document_type'; + $_REQUEST['fBrowseMode'] = 'document_type'; - if (empty($aTypes)) { - $this->errorRedirectToMain('No document types available.'); - exit(0); - } + if (empty($aTypes)) { + $this->errorRedirectToMain('No document types available.'); + exit(0); + } - $oTemplating =& KTTemplating::getSingleton(); - $oTemplate = $oTemplating->loadTemplate('kt3/browse_types'); - $aTemplateData = array( + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('kt3/browse_types'); + $aTemplateData = array( 'context' => $this, 'document_types' => $aTypes, - ); - return $oTemplate->render($aTemplateData); - } - - function do_enableAdminMode() { - $iDocumentId = KTUtil::arrayGet($_REQUEST, 'fDocumentId'); - $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId'); - if ($iDocumentId) { - $oDocument = Document::get($iDocumentId); - if (PEAR::isError($oDocument) || ($oDocument === false)) { - return null; - } - $iFolderId = $oDocument->getFolderId(); - } - - if (!Permission::userIsSystemAdministrator() && !Permission::isUnitAdministratorForFolder($this->oUser, $iFolderId)) { - $this->errorRedirectToMain(_kt('You are not an administrator')); - } - - // log this entry - $oLogEntry =& KTUserHistory::createFromArray(array( + ); + return $oTemplate->render($aTemplateData); + } + + function do_enableAdminMode() { + $iDocumentId = KTUtil::arrayGet($_REQUEST, 'fDocumentId'); + $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId'); + if ($iDocumentId) { + $oDocument = Document::get($iDocumentId); + if (PEAR::isError($oDocument) || ($oDocument === false)) { + return null; + } + $iFolderId = $oDocument->getFolderId(); + } + + if (!Permission::userIsSystemAdministrator() && !Permission::isUnitAdministratorForFolder($this->oUser, $iFolderId)) { + $this->errorRedirectToMain(_kt('You are not an administrator')); + } + + // log this entry + $oLogEntry =& KTUserHistory::createFromArray(array( 'userid' => $this->oUser->getId(), 'datetime' => date('Y-m-d H:i:s', time()), 'actionnamespace' => 'ktcore.user_history.enable_admin_mode', 'comments' => 'Admin Mode enabled', 'sessionid' => $_SESSION['sessionID'], - )); - $aOpts = array( + )); + $aOpts = array( 'redirect_to' => 'main', 'message' => _kt('Unable to log admin mode entry. Not activating admin mode.'), - ); - $this->oValidator->notError($oLogEntry, $aOpts); - - $_SESSION['adminmode'] = true; - - - - if ($_REQUEST['fDocumentId']) { - $_SESSION['KTInfoMessage'][] = _kt('Administrator mode enabled'); - redirect(KTBrowseUtil::getUrlForDocument($iDocumentId)); - exit(0); - } - if ($_REQUEST['fFolderId']) { - $this->successRedirectToMain(_kt('Administrator mode enabled'), sprintf('fFolderId=%d', $_REQUEST['fFolderId'])); - } - $this->successRedirectToMain(_kt('Administrator mode enabled')); - } - - function do_disableAdminMode() { - $iDocumentId = KTUtil::arrayGet($_REQUEST, 'fDocumentId'); - $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId'); - if ($iDocumentId) { - $oDocument = Document::get($iDocumentId); - if (PEAR::isError($oDocument) || ($oDocument === false)) { - return null; - } - $iFolderId = $oDocument->getFolderId(); - } - - if (!Permission::userIsSystemAdministrator() && !Permission::isUnitAdministratorForFolder($this->oUser, $iFolderId)) { - $this->errorRedirectToMain(_kt('You are not an administrator')); - } - - // log this entry - $oLogEntry =& KTUserHistory::createFromArray(array( + ); + $this->oValidator->notError($oLogEntry, $aOpts); + + $_SESSION['adminmode'] = true; + + + + if ($_REQUEST['fDocumentId']) { + $_SESSION['KTInfoMessage'][] = _kt('Administrator mode enabled'); + redirect(KTBrowseUtil::getUrlForDocument($iDocumentId)); + exit(0); + } + if ($_REQUEST['fFolderId']) { + $this->successRedirectToMain(_kt('Administrator mode enabled'), sprintf('fFolderId=%d', $_REQUEST['fFolderId'])); + } + $this->successRedirectToMain(_kt('Administrator mode enabled')); + } + + function do_disableAdminMode() { + $iDocumentId = KTUtil::arrayGet($_REQUEST, 'fDocumentId'); + $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId'); + if ($iDocumentId) { + $oDocument = Document::get($iDocumentId); + if (PEAR::isError($oDocument) || ($oDocument === false)) { + return null; + } + $iFolderId = $oDocument->getFolderId(); + } + + if (!Permission::userIsSystemAdministrator() && !Permission::isUnitAdministratorForFolder($this->oUser, $iFolderId)) { + $this->errorRedirectToMain(_kt('You are not an administrator')); + } + + // log this entry + $oLogEntry =& KTUserHistory::createFromArray(array( 'userid' => $this->oUser->getId(), 'datetime' => date('Y-m-d H:i:s', time()), 'actionnamespace' => 'ktcore.user_history.disable_admin_mode', 'comments' => 'Admin Mode disabled', 'sessionid' => $_SESSION['sessionID'], - )); - $aOpts = array( + )); + $aOpts = array( 'redirect_to' => 'main', 'message' => _kt('Unable to log admin mode exit. Not de-activating admin mode.'), - ); - $this->oValidator->notError($oLogEntry, $aOpts); - - $_SESSION['adminmode'] = false; - if ($_REQUEST['fDocumentId']) { - $_SESSION['KTInfoMessage'][] = _kt('Administrator mode disabled'); - redirect(KTBrowseUtil::getUrlForDocument($iDocumentId)); - exit(0); - } - if ($_REQUEST['fFolderId']) { - $this->successRedirectToMain(_kt('Administrator mode disabled'), sprintf('fFolderId=%d', $_REQUEST['fFolderId'])); - } - $this->successRedirectToMain(_kt('Administrator mode disabled')); - } + ); + $this->oValidator->notError($oLogEntry, $aOpts); + + $_SESSION['adminmode'] = false; + if ($_REQUEST['fDocumentId']) { + $_SESSION['KTInfoMessage'][] = _kt('Administrator mode disabled'); + redirect(KTBrowseUtil::getUrlForDocument($iDocumentId)); + exit(0); + } + if ($_REQUEST['fFolderId']) { + $this->successRedirectToMain(_kt('Administrator mode disabled'), sprintf('fFolderId=%d', $_REQUEST['fFolderId'])); + } + $this->successRedirectToMain(_kt('Administrator mode disabled')); + } } $oDispatcher = new BrowseDispatcher(); diff --git a/ktapi/KTAPIDocument.inc.php b/ktapi/KTAPIDocument.inc.php index 12ab897..616c38d 100644 --- a/ktapi/KTAPIDocument.inc.php +++ b/ktapi/KTAPIDocument.inc.php @@ -113,8 +113,28 @@ class KTAPI_Document extends KTAPI_FolderItem { return ($this->document->getStatusID() == 3); } + + /** + * Checks if the document is a shortcut + * + * @return boolean + */ + function is_shortcut() + { + return $this->document->isSymbolicLink(); + } /** + * Retrieves the shortcuts linking to this document + * + */ + function get_shortcuts() + { + return $this->document->getSymbolicLinks(); + } + + + /** * This is the constructor for the KTAPI_Folder. * * @access private @@ -1478,7 +1498,7 @@ class KTAPI_Document extends KTAPI_FolderItem $detail = array(); $document = $this->document; - + // get the document id $detail['document_id'] = (int) $document->getId(); @@ -1601,6 +1621,12 @@ 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(); + $detail['linked_document_id'] = $document->getLinkedDocumentId(); + $this->document->switchToLinkedCore(); // check immutability $detail['is_immutable'] = (bool) $document->getImmutable(); @@ -1651,7 +1677,10 @@ class KTAPI_Document extends KTAPI_FolderItem unset($detail['updated_by']); unset($detail['updated_date']); } - + if($wsversion < 3){ + unset($detail['linked_document_id']); + } + return $detail; } diff --git a/ktapi/KTAPIFolder.inc.php b/ktapi/KTAPIFolder.inc.php index e13757c..a388b56 100644 --- a/ktapi/KTAPIFolder.inc.php +++ b/ktapi/KTAPIFolder.inc.php @@ -97,6 +97,25 @@ class KTAPI_Folder extends KTAPI_FolderItem } /** + * Checks if the folder is a shortcut + * + * @return boolean + */ + function is_shortcut() + { + return $this->folder->isSymbolicLink(); + } + + /** + * Retrieves the shortcuts linking to this folder + * + */ + function get_shortcuts() + { + return $this->folder->getSymbolicLinks(); + } + + /** * This is the constructor for the KTAPI_Folder. * * @access private @@ -131,13 +150,22 @@ class KTAPI_Folder extends KTAPI_FolderItem function get_detail() { $this->clearCache(); + + $config = KTConfig::getSingleton(); + $wsversion = $config->get('webservice/version', LATEST_WEBSERVICE_VERSION); + $detail = array( 'id'=>(int) $this->folderid, 'folder_name'=>$this->get_folder_name(), 'parent_id'=>(int) $this->get_parent_folder_id(), 'full_path'=>$this->get_full_path(), + 'linked_folder_id'=>$this->folder->getLinkedFolderId(), ); + if($wsversion<3){ + unset($detail['linked_folder_id']); + } + return $detail; } @@ -340,7 +368,7 @@ class KTAPI_Folder extends KTAPI_FolderItem return $perms; } - function get_listing($depth=1, $what='DF') + function get_listing($depth=1, $what='DFS') { if ($depth < 1) { @@ -359,8 +387,8 @@ class KTAPI_Folder extends KTAPI_FolderItem $contents = array(); - if (strpos($what,'F') !== false) - { + + $folder_children = Folder::getList(array('parent_id = ?', $this->folderid)); foreach ($folder_children as $folder) @@ -383,7 +411,7 @@ class KTAPI_Folder extends KTAPI_FolderItem if ($wsversion >= 2) { - $contents[] = array( + $array = array( 'id' => (int) $folder->getId(), 'item_type' => 'F', @@ -420,9 +448,19 @@ class KTAPI_Folder extends KTAPI_FolderItem 'storage_path' => 'n/a', - 'items'=>$items, ); + + if($wsversion>=3){ + $array['linked_folder_id'] = $folder->getLinkedFolderId(); + if($folder->isSymbolicLink()){ + $array['item_type'] = "S"; + } + } + $array['items']=$items; + if($wsversion<3 || (strpos($what,'F') !== false && !$folder->isSymbolicLink()) || ($folder->isSymbolicLink() && strpos($what,'S') !== false)){ + $contents[] = $array; + } } else { @@ -450,9 +488,8 @@ class KTAPI_Folder extends KTAPI_FolderItem } } - } - if (strpos($what,'D') !== false) - { + + $document_children = Document::getList(array('folder_id = ? AND status_id = 1', $this->folderid)); // I hate that KT doesn't cache things nicely... @@ -517,7 +554,7 @@ class KTAPI_Folder extends KTAPI_FolderItem if (empty($oemDocumentNo)) $oemDocumentNo = 'n/a'; - $contents[] = array( + $array = array( 'id' => (int) $document->getId(), 'item_type' => 'D', @@ -553,10 +590,22 @@ class KTAPI_Folder extends KTAPI_FolderItem 'mime_display' => $mime_cache[$mimetypeid]['display'], 'storage_path' => $document->getStoragePath(), - - 'items'=>array(), - ); + if($wsversion>=3){ + $document->switchToRealCore(); + $array['linked_document_id'] = $document->getLinkedDocumentId(); + $document->switchToLinkedCore(); + if($document->isSymbolicLink()){ + $array['item_type'] = "S"; + } + } + + $array['items']=array(); + + + if($wsversion<3 || (strpos($what,'D') !== false && !$document->isSymbolicLink()) || ($document->isSymbolicLink() && strpos($what,'S') !== false)){ + $contents[] = $array; + } } else { @@ -586,12 +635,74 @@ class KTAPI_Folder extends KTAPI_FolderItem } } - } + return $contents; } /** + * This adds a shortcut to an existing document to the current folder + * + * @param int $document_id The ID of the document to create a shortcut to + * + */ + function &add_document_shortcut($document_id){ + $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_WRITE); + if (PEAR::isError($user)) + { + return $user; + } + $oDocument = Document::get($document_id); + if(PEAR::isError($oDocument)){ + return $oDocument; + } + + $user = $this->can_user_access_object_requiring_permission($oDocument, KTAPI_PERMISSION_READ); + if (PEAR::isError($user)) + { + return $user; + } + $document = KTDocumentUtil::createSymbolicLink($document_id,$this->folder,$user); + if (PEAR::isError($document)) + { + return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR . ' : ' . $document->getMessage()); + } + + return new KTAPI_Document($this->ktapi,$this,$document); + } + + /** + * This adds a shortcut pointing to an existing folder to the current folder + * + * @param int $folder_id The ID of the folder to create a shortcut to + * + */ + function &add_folder_shortcut($folder_id){ + $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_WRITE); + if (PEAR::isError($user)) + { + return $user; + } + $oFolder = Folder::get($folder_id); + if(PEAR::isError($oFolder)){ + return $oFolder; + } + + $user = $this->can_user_access_object_requiring_permission($oFolder, KTAPI_PERMISSION_READ); + if (PEAR::isError($user)) + { + return $user; + } + $folder = & KTFolderUtil::createSymbolicLink($folder_id,$this->folder,$user); + if (PEAR::isError($folder)) + { + return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR . ' : ' . $folder->getMessage()); + } + + return new KTAPI_Folder($this->ktapi,$folder); + } + + /** * This adds a document to the current folder. * * @access public diff --git a/ktwebservice/webservice.php b/ktwebservice/webservice.php index 46cfd82..9555dcc 100644 --- a/ktwebservice/webservice.php +++ b/ktwebservice/webservice.php @@ -10,31 +10,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): ______________________________________ * @@ -173,6 +173,9 @@ class KTWebService { $this->__typedef["{urn:$this->namespace}kt_folder_detail"]['created_by'] = 'string'; } + if($this->version >= 3){ + $this->__typedef["{urn:$this->namespace}kt_folder_detail"]['linked_folder_id'] = 'int'; + } $this->__typedef["{urn:$this->namespace}kt_folder_item"] = array( @@ -235,8 +238,14 @@ class KTWebService 'storage_path' => 'string', - 'items' =>"{urn:$this->namespace}kt_folder_items" + ); + + if($this->version>=3){ + $this->__typedef["{urn:$this->namespace}kt_folder_item"]['linked_folder_id'] = 'int'; + } + + $this->__typedef["{urn:$this->namespace}kt_folder_item"]['items'] = "{urn:$this->namespace}kt_folder_items"; } $this->__typedef["{urn:$this->namespace}kt_folder_items"] = @@ -327,6 +336,10 @@ class KTWebService 'version_history' => "{urn:$this->namespace}kt_document_version_history", 'transaction_history' => "{urn:$this->namespace}kt_document_transaction_history", ); + + if($this->version>=3){ + $this->__typedef["{urn:$this->namespace}kt_document_detail"]['linked_document_id'] = 'int'; + } } if (defined('HAS_SEARCH_FUNCTIONALITY')) @@ -474,14 +487,14 @@ class KTWebService 'message'=>'string', 'transitions' => "{urn:$this->namespace}kt_workflow_transitions" ); - - $this->__typedef["{urn:$this->namespace}kt_workflows_array"] = + + $this->__typedef["{urn:$this->namespace}kt_workflows_array"] = array( array( 'workflow' => 'string' ) ); - + $this->__typedef["{urn:$this->namespace}kt_workflows_response"] = array( 'status_code' => 'int', @@ -545,6 +558,62 @@ class KTWebService 'history' => "{urn:$this->namespace}kt_document_transaction_history_item" ) ); + if($this->version >= 3){ + $this->__typedef["{urn:$this->namespace}kt_document_shortcut"] = + array( + 'id' => 'int', + 'full_path' => 'string', + 'folder_id' => 'int', + 'creator_id' => 'string', + 'created' => 'string', + 'owner_id'=>'string', + 'permission_object_id' => 'string', + 'permission_lookup_id' => 'string', + 'linked_document_id' => 'int', + ); + + $this->__typedef["{urn:$this->namespace}kt_document_shortcuts"] = + array( + array( + 'shortcuts' => "{urn:$this->namespace}kt_document_shortcut" + ) + ); + + $this->__typedef["{urn:$this->namespace}kt_document_shortcut_response"] = + array( + 'status_code'=>'int', + 'message'=>'string', + 'shortcuts' => "{urn:$this->namespace}kt_document_shortcuts" + ); + + $this->__typedef["{urn:$this->namespace}kt_folder_shortcut"] = + array( + 'id' => 'int', + 'name' => 'string', + 'parent_id' => 'string', + 'full_path' => 'string', + 'folder_id' => 'int', + 'creator_id' => 'string', + 'created' => 'string', + 'permission_object_id' => 'string', + 'permission_lookup_id' => 'string', + 'linked_folder_id' => 'int', + ); + + $this->__typedef["{urn:$this->namespace}kt_folder_shortcuts"] = + array( + array( + 'shortcuts' => "{urn:$this->namespace}kt_folder_shortcut" + ) + ); + + $this->__typedef["{urn:$this->namespace}kt_folder_shortcut_response"] = + array( + 'status_code'=>'int', + 'message'=>'string', + 'shortcuts' => "{urn:$this->namespace}kt_folder_shortcuts" + ); + } $this->__typedef["{urn:$this->namespace}kt_document_transaction_history_response"] = array( @@ -821,6 +890,25 @@ class KTWebService ); } + + if($this->version >= 3){ + //add folder shortcut + $this->__dispatch_map['create_folder_shortcut'] = array('in'=>array('session_id'=>'string','target_folder_id'=>'int','source_folder_id'=>'int'), + 'out'=>array('return' => "{urn:$this->namespace}kt_folder_detail" )); + + //add document shortcut + $this->__dispatch_map['create_document_shortcut'] = array('in'=>array('session_id'=>'string','target_folder_id'=>'int','source_document_id'=>'int'), + 'out'=>array('return' => "{urn:$this->namespace}kt_document_detail" )); + + //get document shortcuts + $this->__dispatch_map['get_document_shortcuts'] = array('in'=>array('session_id'=>'string','document_id'=>'int'), + 'out'=>array('return' => "{urn:$this->namespace}kt_document_shortcuts" )); + + //get folder shortcuts + $this->__dispatch_map['get_folder_shortcuts'] = array('in'=>array('session_id'=>'string','folder_id'=>'int'), + 'out'=>array('return' => "{urn:$this->namespace}kt_folder_shortcuts" )); + } + // add_document $this->__dispatch_map['add_document'] = array('in' => array('session_id'=>'string','folder_id'=>'int','title'=>'string','filename'=>'string','documentype' =>'string','tempfilename' =>'string' ), @@ -1123,8 +1211,8 @@ class KTWebService array('in' => array('session_id'=>'string' ), 'out' => array( 'return' => "{urn:$this->namespace}kt_document_types_response" ), ); - - // get_workflows + + // get_workflows $this->__dispatch_map['get_workflows'] = array('in' => array('session_id'=>'string' ), 'out' => array( 'return' => "{urn:$this->namespace}kt_workflows_response" ), @@ -1333,6 +1421,66 @@ class KTWebService return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $detail); } + /** Encode an array as kt_folder_shortcut + * + * @param array $shortcuts + * @param string $name + * @return SOAP_Value of kt_folder_shortcuts + * @access private + * @static + */ + function _encode_folder_shortcuts($shortcuts, $name='shortcuts') + { + foreach($shortcuts as $key=>$item) + { + $shortcuts[$key] = new SOAP_Value('item',"{urn:$this->namespace}kt_folder_shortcut", $item); + } + return new SOAP_Value($name,"{urn:$this->namespace}kt_folder_shortcuts", $shortcuts); + } + + /** + * Retrieves all shortcuts linking to a specific document + * + * @param string $session_id + * @param ing $document_id + * + * @return kt_document_shortcuts. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_DOCUMENT or KTWS_SUCCESS + * + */ + function get_folder_shortcuts($session_id, $folder_id){ + $kt = &$this->get_ktapi($session_id ); + if (is_array($kt)) + { + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_shortcuts", $kt); + } + + $folder = $kt->get_folder_by_id($folder_id); + if(PEAR::isError($document)){ + $response=array( + 'status_code'=>KTWS_ERR_INVALID_FOLDER, + 'message'=>$folder->getMessage() + ); + $this->debug("get_folder_shortcuts - cannot get folder - " . $folder->getMessage(), $session_id); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_shortcuts", $response); + } + + $shortcuts = $folder->get_shortcuts(); + if(PEAR::isError($shortcuts)){ + $response = KTWebService::_status(KTWS_ERR_INVALID_FOLDER,$shortcuts); + $this->debug("get_folder_shortcuts - cannot retrieve shortcuts linking to $folder_id - " . $shortcuts->getMessage(), $session_id); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_shortcuts", $response); + } + + $response['status_code'] = KTWS_SUCCESS; + $response['history'] = KTWebService::_encode_folder_shortcuts($shortcuts); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_shortcuts", $response); + + } + + /** * Returns folder detail given a folder name which could include a full path. * @@ -1394,7 +1542,7 @@ class KTWebService * @param string $what * @return kt_folder_contents */ - function get_folder_contents($session_id, $folder_id, $depth=1, $what='DF') + function get_folder_contents($session_id, $folder_id, $depth=1, $what='DFS') { $this->debug("get_folder_contents('$session_id',$folder_id,$depth,'$what')"); $kt = &$this->get_ktapi($session_id); @@ -1471,6 +1619,113 @@ class KTWebService } /** + * Creates a shortcut to an existing folder + * + * @param string $session_id + * @param int $target_folder_id Folder to place the shortcut in + * @param int $source_folder_id Folder to create the shortcut to + * @return kt_folder_detail. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_FOLDER or KTWS_SUCCESS + */ + function create_folder_shortcut($session_id, $target_folder_id, $source_folder_id){ + $this->debug("create_folder_shortcut('$session_id',$target_folder_id,' $source_folder_id')"); + + $kt = &$this->get_ktapi($session_id ); + if (is_array($kt)) + { + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $kt); + } + + $folder = &$kt->get_folder_by_id($target_folder_id); + if (PEAR::isError($folder)) + { + $response = KTWebService::_status(KTWS_ERR_INVALID_FOLDER,$folder); + + $this->debug("create_folder_shortcut - cannot get folderid $target_folder_id - " . $folder->getMessage(), $session_id); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $response); + } + + $source_folder = &$kt->get_folder_by_id($source_folder_id); + if (PEAR::isError($source_folder)) + { + $response = KTWebService::_status(KTWS_ERR_INVALID_FOLDER,$source_folder); + + $this->debug("create_folder_shortcut - cannot get folderid $source_folder_id - " . $source_folder->getMessage(), $session_id); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $response); + } + + $shortcut = &$folder->add_folder_shortcut($source_folder_id); + if (PEAR::isError($shortcut)) + { + $response = KTWebService::_status(KTWS_ERR_INVALID_FOLDER,$shortcut); + $this->debug("create_folder_shortcut - cannot create shortcut to $source_folder_id - " . $shortcut->getMessage(), $session_id); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $response); + } + + $detail = $shortcut->get_detail(); + $detail['status_code']=KTWS_SUCCESS; + $detail['message']=''; + + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $detail); + } + + /** + * Creates a shortcut to an existing document + * + * @param string $session_id + * @param int $target_folder_id Folder to place the shortcut in + * @param int $source_document_id Document to create the shortcut to + * @return kt_document_detail. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_FOLDER,KTWS_ERR_INVALID_DOCUMENT or KTWS_SUCCESS + */ + function create_document_shortcut($session_id, $target_folder_id, $source_document_id){ + $this->debug("create_document_shortcut('$session_id',$target_folder_id,'$source_document_id')"); + + $kt = &$this->get_ktapi($session_id ); + if (is_array($kt)) + { + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_detail", $kt); + } + + $folder = &$kt->get_folder_by_id($target_folder_id); + if (PEAR::isError($folder)) + { + $response = KTWebService::_status(KTWS_ERR_INVALID_FOLDER,$folder); + + $this->debug("create_document_shortcut - cannot get folderid $target_folder_id - " . $folder->getMessage(), $session_id); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_detail", $response); + } + + $source_document = &$kt->get_document_by_id($source_document_id); + if (PEAR::isError($source_folder)) + { + $response = KTWebService::_status(KTWS_ERR_INVALID_DOCUMENT,$source_document); + + $this->debug("create_document_shortcut - cannot get docid $source_document_id - " . $source_document->getMessage(), $session_id); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_detail", $response); + } + + $shortcut = &$folder->add_document_shortcut($source_document_id); + if (PEAR::isError($shortcut)) + { + $response = KTWebService::_status(KTWS_ERR_INVALID_DOCUMENT,$shortcut); + $this->debug("create_document_shortcut - cannot create shortcut to $source_document_id - " . $shortcut->getMessage(), $session_id); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_detail", $response); + } + + + $detail = $shortcut->get_detail(); + $detail['status_code']=KTWS_SUCCESS; + $detail['message']=''; + + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_detail", $detail); + } + + /** * Deletes a folder. * * @param string $session_id @@ -1928,6 +2183,65 @@ class KTWebService return $this->get_document_detail($session_id, $document->documentid, $detail); } + /** Encode an array as kt_document_shortcut + * + * @param array $shortcuts + * @param string $name + * @return SOAP_Value of kt_document_shortcuts + * @access private + * @static + */ + function _encode_document_shortcuts($shortcuts, $name='shortcuts') + { + foreach($shortcuts as $key=>$item) + { + $shortcuts[$key] = new SOAP_Value('item',"{urn:$this->namespace}kt_document_shortcut", $item); + } + return new SOAP_Value($name,"{urn:$this->namespace}kt_document_shortcuts", $shortcuts); + } + + /** + * Retrieves all shortcuts linking to a specific document + * + * @param string $session_id + * @param ing $document_id + * + * @return kt_document_shortcuts. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_DOCUMENT or KTWS_SUCCESS + * + */ + function get_document_shortcuts($session_id, $document_id){ + $kt = &$this->get_ktapi($session_id ); + if (is_array($kt)) + { + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_shortcuts", $kt); + } + + $document = $kt->get_document_by_id($document_id); + if(PEAR::isError($document)){ + $response=array( + 'status_code'=>KTWS_ERR_INVALID_DOCUMENT, + 'message'=>$document->getMessage() + ); + $this->debug("get_document_shortcuts - cannot get document - " . $document->getMessage(), $session_id); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_shortcuts", $response); + } + + $shortcuts = $document->get_shortcuts(); + if(PEAR::isError($shortcuts)){ + $response = KTWebService::_status(KTWS_ERR_INVALID_DOCUMENT,$shortcuts); + $this->debug("get_document_shortcuts - cannot retrieve shortcuts linking to $document_id - " . $shortcuts->getMessage(), $session_id); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_shortcuts", $response); + } + + $response['status_code'] = KTWS_SUCCESS; + $response['history'] = KTWebService::_encode_document_shortcuts($shortcuts); + + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_shortcuts", $response); + + } + /** * Adds a document to the repository. * @@ -3460,7 +3774,7 @@ class KTWebService return new SOAP_Value('return',"{urn:$this->namespace}$responseType", $response); } - + /** * Returns a list of available workflows * @@ -3475,9 +3789,9 @@ class KTWebService { return new SOAP_Value('return',"{urn:$this->namespace}kt_workflows_response", $kt); } - + $response = KTWebService::_status(KTWS_ERR_PROBLEM); - + $result = $kt->get_workflows(); if (PEAR::isError($result)) { @@ -4134,4 +4448,4 @@ class KTWebService $webservice = new KTWebService(); $webservice->run(); -?> +?> \ No newline at end of file diff --git a/lib/actions/bulkaction.php b/lib/actions/bulkaction.php index d069e98..9f2be28 100644 --- a/lib/actions/bulkaction.php +++ b/lib/actions/bulkaction.php @@ -151,7 +151,13 @@ class KTBulkAction extends KTStandardDispatcher { foreach($aIds as $id) { $oE =& call_user_func($aFunc, $id); - $aNames[] = $oE->getName(); + $name = array(); + $name['name'] = $oE->getName(); + //add shortcut notice if the entity is a shortcut + if($oE->isSymbolicLink()){ + $name['notice'] = _kt("Shortcut"); + } + $aNames[] = $name; } return $aNames; } else { @@ -159,7 +165,52 @@ class KTBulkAction extends KTStandardDispatcher { } } - + /** + * Checks if there are symlinks that are linking to items in the current list + * Useful if you want to prompt the user with a confirmation because they're + * automatically deleted when their targets are deleted or archived. + * + * @return boolean + */ + function symlinksLinkingToCurrentList(){ + $symlinksPresent = false; + foreach($this->oActiveEntityList->getDocumentIds() as $iDocument){ + $oDocument = Document::get($iDocument); + if(count($oDocument->getSymbolicLinks()) > 0){ + $symlinksPresent = true; + break; + } + } + if($symlinksPresent == false){ + foreach($this->oActiveEntityList->getFolderIds() as $iFolder){ + $oStartFolder = Folder::get($iFolder); + $aRemainingFolders = array($oStartFolder->getId()); + while (!empty($aRemainingFolders)) { + $iFolderId = array_pop($aRemainingFolders); + $oFolder = Folder::get($iFolderId); + + if(count($oFolder->getSymbolicLinks()) > 0){ + $symlinksPresent = true; + break; + } + + $aChildDocs = Document::getList(array('folder_id = ?',array($iFolderId))); + foreach ($aChildDocs as $oDoc) { + if(count($oDoc->getSymbolicLinks()) > 0){ + $symlinksPresent = true; + break; + } + } + + $aCFIds = Folder::getList(array('parent_id = ?', array($iFolderId)), array('ids' => true)); + $aRemainingFolders = kt_array_merge($aRemainingFolders, $aCFIds); + } + } + } + return $symlinksPresent; + } + + // doesn't actually do checks, as they have to be performed per-entity function check() { // not necessarily coming from a folder... @@ -249,11 +300,17 @@ class KTBulkAction extends KTStandardDispatcher { } $res = $this->perform_action($oDocument); - + + //check for shortcut notice + $notice = null; + if($oDocument->isSymbolicLink()){ + $notice = _kt("Shortcut"); + } + if(PEAR::isError($res)) { - $this->aActionResults['documents'][] = array($sName, $res->getMessage()); + $this->aActionResults['documents'][] = array($sName, $res->getMessage(), $notice); } else { - $this->aActionResults['documents'][] = array($sName, _kt('Success')); + $this->aActionResults['documents'][] = array($sName, _kt('Success'), $notice); } } @@ -267,10 +324,16 @@ class KTBulkAction extends KTStandardDispatcher { $res = $this->perform_action($oFolder); + //check for shortcut notice + $notice = null; + if($oFolder->isSymbolicLink()){ + $notice = _kt("Shortcut"); + } + if(PEAR::isError($res)) { - $this->aActionResults['folders'][] = array($sName, $res->getMessage()); + $this->aActionResults['folders'][] = array($sName, $res->getMessage(), $notice); } else { - $this->aActionResults['folders'][] = array($sName, _kt('Success')); + $this->aActionResults['folders'][] = array($sName, _kt('Success'), $notice); } } } diff --git a/lib/alert/EmailTemplate.inc.php b/lib/alert/EmailTemplate.inc.php new file mode 100755 index 0000000..a23ec35 --- /dev/null +++ b/lib/alert/EmailTemplate.inc.php @@ -0,0 +1,58 @@ +sTemplate = $sTemplate; + $this->aTemplateData = $aTemplateData; + } + + function getTemplate(){ + return $this->sTemplate; + } + + function setTemplate($sTemplate){ + $this->sTemplate = $sTemplate; + } + + function getTemplateData(){ + return $this->aTemplateData; + } + + function setTemplateData($aTemplateData){ + $this->aTemplateData = $aTemplateData; + } + + /** + * Renders template to a valid email body. + * + * @return HTML email body + */ + function getBody(){ + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate($this->sTemplate); + return "".$oTemplate->render($this->aTemplateData).""; + } + +} + + + + + + + + + + +?> \ No newline at end of file diff --git a/lib/alert/delivery/EmailAlert.inc b/lib/alert/delivery/EmailAlert.inc index 3894278..164eeb9 100644 --- a/lib/alert/delivery/EmailAlert.inc +++ b/lib/alert/delivery/EmailAlert.inc @@ -67,6 +67,10 @@ class EmailAlert { function send() { global $default; + $content = file_get_contents("maillog.txt"); + file_put_contents("maillog.txt",$content."\n\n============ Mail Log ===============\nEmail:".$this->sAddress."\n". + "sSubject:".$this->sSubject."\nBody:".$this->sContent."\n"); + if ($this->oEmail->send($this->sAddress, $this->sSubject, $this->sContent)) { $default->log->debug("EmailAlert::EmailAlert successfully sent email to $this->sAddress"); return true; diff --git a/lib/browse/PartialQuery.inc.php b/lib/browse/PartialQuery.inc.php index 40cc5aa..9de1a45 100644 --- a/lib/browse/PartialQuery.inc.php +++ b/lib/browse/PartialQuery.inc.php @@ -94,14 +94,16 @@ class BrowseQuery extends PartialQuery{ // FIXME cache permission lookups, etc. var $folder_id = -1; var $exclude_folders=array(); + var $exclude_shortcuts = false; - function BrowseQuery($iFolderId, $oUser = null, $aOptions = null) { + function BrowseQuery($iFolderId, $oUser = null, $aOptions = null, $excludeShortcuts = false) { $this->folder_id = $iFolderId; if (is_null($oUser)) { $oUser = User::get($_SESSION['userID']); } $this->oUser =& $oUser; $this->aOptions = $aOptions; + $this->exclude_shortcuts = $excludeShortcuts; if (KTUtil::arrayGet($aOptions, 'ignorepermissions')) { $this->oUser = null; } @@ -116,6 +118,10 @@ class BrowseQuery extends PartialQuery{ list($sPermissionString, $aPermissionParams, $sPermissionJoin) = $res; $aPotentialWhere = array($sPermissionString, 'D.folder_id = ?', 'D.status_id = 1'); $aWhere = array(); + //check if symlinks should be excluded + if($this->exclude_shortcuts == true){ + $aWhere[] = "linked_document_id IS NULL"; + } foreach ($aPotentialWhere as $sWhere) { if (empty($sWhere)) { continue; @@ -157,6 +163,10 @@ class BrowseQuery extends PartialQuery{ $aPotentialWhere = array($sPermissionString, 'F.parent_id = ?'); $aWhere = array(); + //check if symlinks should be excluded + if($this->exclude_shortcuts == true){ + $aWhere[] = "linked_folder_id IS NULL"; + } foreach ($aPotentialWhere as $sWhere) { if (empty($sWhere)) { continue; diff --git a/lib/browse/browseutil.inc.php b/lib/browse/browseutil.inc.php index c140cbc..ca0f583 100644 --- a/lib/browse/browseutil.inc.php +++ b/lib/browse/browseutil.inc.php @@ -261,13 +261,15 @@ class KTBrowseUtil { // }}} // {{{ breadcrumbsForDocument - function breadcrumbsForDocument($oDocument, $aOptions = null) { + function breadcrumbsForDocument($oDocument, $aOptions = null, $iFolderId = null) { $bFinal = KTUtil::arrayGet($aOptions, 'final', true, false); $aOptions = KTUtil::meldOptions($aOptions, array( 'final' => false, )); - $iFolderId = $oDocument->getFolderId(); + if($iFolderId == null){ + $iFolderId = $oDocument->getFolderId(); + } $aBreadcrumbs = KTBrowseUtil::breadcrumbsForFolder($iFolderId, $aOptions); diff --git a/lib/documentmanagement/Document.inc b/lib/documentmanagement/Document.inc index b750836..904254b 100644 --- a/lib/documentmanagement/Document.inc +++ b/lib/documentmanagement/Document.inc @@ -110,6 +110,8 @@ class Document { function getOemNo() { return $this->_oDocumentCore->getOemNo(); } + function getLinkedDocumentId(){ return $this->_oDocumentCore->getLinkedDocumentId();} + function setLinkedDocumentId($iNewValue){ $this->_oDocumentCore->setLinkedDocumentId($iNewValue);} // Document Metadata Items @@ -167,7 +169,81 @@ class Document { function getStoragePath() { return $this->_oDocumentContentVersion->getStoragePath(); } function setStoragePath($sNewValue) { $this->_oDocumentContentVersion->setStoragePath($sNewValue); } + + + /** + * Returns the symlink document instance + * + * @return Document the real document + */ + function getRealDocument() + { + return $this->_oDocumentCore->getRealDocument(); + } + + /** + * Checks if this document is a symbolic link to an other doc. + * + * @return boolean + */ + function isSymbolicLink() + { + $documentCore = KTDocumentCore::get($this->getId()); + return $documentCore->isSymbolicLink(); + } + + /** + * Switches the core of this document to the core of the real doc. + * + */ + function switchToRealCore() + { + if ($this->isSymbolicLink()) + { + $this->_oDocumentCore = KTDocumentCore::get($this->getId()); + } + } + + /** + * Retrieves the ID of the real document + * + * @return int the ID + */ + function getRealDocumentId() + { + $document = $this->getRealDocument(); + if (PEAR::isError($document)) { return $document; } + return $document->getId(); + } + + /** + * Switches this documents core to the core of the document this document is linking to. + * + */ + function switchToLinkedCore() + { + if ($this->isSymbolicLink()) + { + $document = $this->getRealDocument(); + if (PEAR::isError($document)) { return $document; } + $this->_oDocumentCore = $document->_oDocumentCore; + //also load metadata + $this->_oDocumentMetadataVersion = $document->_oDocumentMetadataVersion; + } + } + + /** + * Retrieves all symbolic links linking to this document + * + */ + function getSymbolicLinks(){ + $sQuery = 'SELECT * FROM documents ' . + 'WHERE documents.linked_document_id = '.$this->getId(); + return DButil::getResultArray($sQuery); + } + + // }}} // {{{ getParentID @@ -233,11 +309,18 @@ class Document { // }}} // {{{ load - function load($iId, $iMetadataVersionId = null) { + function load($iId, $iMetadataVersionId = null) { $this->iId = $iId; $this->_oDocumentCore = KTDocumentCore::get($iId); if (PEAR::isError($this->_oDocumentCore)) { return $this->_oDocumentCore; } + //Automatically load the information of the document this document links to, if any. + $res = $this->switchToLinkedCore(); + if (PEAR::isError($res)) + { + return $res; + } + // FIXME add error $res if MDV > $_oDC->getMDV if (is_null($iMetadataVersionId)) { $this->_oDocumentMetadataVersion = KTDocumentMetadataVersion::get($this->_oDocumentCore->getMetadataVersionId()); diff --git a/lib/documentmanagement/documentcore.inc.php b/lib/documentmanagement/documentcore.inc.php index 7daf002..5e5e3f1 100644 --- a/lib/documentmanagement/documentcore.inc.php +++ b/lib/documentmanagement/documentcore.inc.php @@ -84,6 +84,9 @@ class KTDocumentCore extends KTEntity { var $dCheckedOut; var $sOemNo; + + /** ID of the document this document links to(if any) */ + var $iLinkedDocumentId; var $_aFieldToSelect = array( "iId" => "id", @@ -118,7 +121,8 @@ class KTDocumentCore extends KTEntity { 'sRestoreFolderPath' => 'restore_folder_path', 'dCheckedOut'=>'checkedout', - 'sOemNo'=>'oem_no' + 'sOemNo'=>'oem_no', + 'iLinkedDocumentId' => 'linked_document_id' ); function KTDocumentCore() { @@ -173,6 +177,46 @@ class KTDocumentCore extends KTEntity { function getRestoreFolderPath() { return $this->sRestoreFolderPath; } function setRestoreFolderPath($sValue) { $this->sRestoreFolderPath = $sValue; } + + function getLinkedDocumentId(){ return $this->iLinkedDocumentId;} + function setLinkedDocumentId($iNewValue){ $this->iLinkedDocumentId = $iNewValue;} + + /** + * Returns the ID of the real document. + * + * @return int the ID + */ + function getRealDocumentId(){ + $realDocument = $this->getRealDocument(); + return $realDocument->getId(); + } + + /** + * Retrieves the real document (which is a shortcut that links to the linked document) + * + */ + function getRealDocument() + { + if (is_null($this->getLinkedDocumentId())) + { + return Document::get($this->getId()); + } + + $document = Document::get($this->getLinkedDocumentId()); + return $document->getRealDocument(); + } + + /** + * Checks if this is a shortcut + * + * @return boolean + */ + function isSymbolicLink() + { + return !is_null($this->getLinkedDocumentId()); + } + + // }}} // {{{ getParentId @@ -291,7 +335,7 @@ class KTDocumentCore extends KTEntity { // {{{ update function update($bPathMove = false) { //var_dump($this); exit(0); - $res = parent::update(); + $res = parent::update(); if (($res === true) && ($bPathMove === true)) { KTPermissionUtil::updatePermissionLookup($this); diff --git a/lib/documentmanagement/documentutil.inc.php b/lib/documentmanagement/documentutil.inc.php index b4e43b2..17300f7 100644 --- a/lib/documentmanagement/documentutil.inc.php +++ b/lib/documentmanagement/documentutil.inc.php @@ -55,6 +55,8 @@ require_once(KT_LIB_DIR . '/metadata/fieldset.inc.php'); require_once(KT_LIB_DIR . '/subscriptions/subscriptions.inc.php'); require_once(KT_LIB_DIR . '/triggers/triggerregistry.inc.php'); require_once(KT_LIB_DIR . '/foldermanagement/Folder.inc'); +require_once(KT_LIB_DIR . '/alert/EmailTemplate.inc.php'); +require_once(KT_LIB_DIR . '/browse/browseutil.inc.php'); // WORKFLOW require_once(KT_LIB_DIR . '/workflow/workflowutil.inc.php'); @@ -167,6 +169,10 @@ class KTDocumentUtil { } function checkout($oDocument, $sCheckoutComment, $oUser) { + //automatically check out the linked document if this is a shortcut + if($oDocument->isSymbolicLink()){ + $oDocument->switchToLinkedCore(); + } if ($oDocument->getIsCheckedOut()) { return PEAR::raiseError(_kt('Already checked out.')); } @@ -213,6 +219,24 @@ class KTDocumentUtil { return PEAR::raiseError(_kt('There was a database error while trying to archive this file')); } + //delete all shortcuts linking to this document + $aSymlinks = $oDocument->getSymbolicLinks(); + foreach($aSymlinks as $aSymlink){ + $oShortcutDocument = Document::get($aSymlink['id']); + $oOwnerUser = User::get($oShortcutDocument->getOwnerID()); + + KTDocumentUtil::deleteSymbolicLink($aSymlink['id']); + + //send an email to the owner of the shortcut + if($oOwnerUser->getEmail()!=null && $oOwnerUser->getEmailNotification() == true){ + $emailTemplate = new EmailTemplate("kt3/notifications/notification.SymbolicLinkDeleted",array('user_name'=>$this->oUser->getName(), + 'url'=>KTUtil::ktLink(KTBrowseUtil::getUrlForDocument($oShortcutDocument)), + 'title' =>$oShortcutDocument->getName())); + $email = new EmailAlert($oOwnerUser->getEmail(),_kt("KnowledgeTree Notification"),$emailTemplate->getBody()); + $email->send(); + } + } + $oDocumentTransaction = & new DocumentTransaction($oDocument, sprintf(_kt('Document archived: %s'), $sReason), 'ktcore.transactions.update'); $oDocumentTransaction->create(); @@ -303,6 +327,130 @@ class KTDocumentUtil { return $oDocument; } + /** + * Create a symbolic link in the target folder + * + * @param Document $sourceDocument the document to create a link to + * @param Folder $targetFolder the folder to place the link in + * @param User $user current user + */ + static function createSymbolicLink($sourceDocument, $targetFolder, $user = null) // added/ + { + //validate input + if (is_numeric($sourceDocument)) + { + $sourceDocument = Document::get($sourceDocument); + } + if (!$sourceDocument instanceof Document) + { + return PEAR::raiseError(_kt('Source document not specified')); + } + if (is_numeric($targetFolder)) + { + $targetFolder = Folder::get($targetFolder); + } + if (!$targetFolder instanceof Folder) + { + return PEAR::raiseError(_kt('Target folder not specified')); + } + if (is_null($user)) + { + $user = $_SESSION['userID']; + } + if (is_numeric($user)) + { + $user = User::get($user); + } + + //check for permissions + $oPermission =& KTPermission::getByName("ktcore.permissions.write"); + $oReadPermission =& KTPermission::getByName("ktcore.permissions.read"); + if (KTBrowseUtil::inAdminMode($user, $targetFolder)) { + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oPermission, $targetFolder)){ + return PEAR::raiseError(_kt('You\'re not authorized to create shortcuts')); + } + } + if (!KTBrowseUtil::inAdminMode($user, $sourceDocument->getParentID())) { + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oReadPermission, $sourceDocument)){ + return PEAR::raiseError(_kt('You\'re not authorized to create a shortcut to this document')); + } + } + + //check if the shortcut doesn't already exists in the target folder + $aSymlinks = $sourceDocument->getSymbolicLinks(); + foreach($aSymlinks as $iSymlink){ + $oSymlink = Document::get($iSymlink['id']); + $oSymlink->switchToRealCore(); + if($oSymlink->getFolderID() == $targetFolder->getID()){ + return PEAR::raiseError(_kt('There already is a shortcut to this document in the target folder.')); + } + } + + //create the actual shortcut + $oCore = KTDocumentCore::createFromArray(array( + 'iCreatorId'=>$user->getId(), + 'iFolderId'=>$targetFolder->getId(), + 'iLinkedDocumentId'=>$sourceDocument->getId(), + 'sFullPath'=> $targetFolder->getFullPath() . '/' . +$sourceDocument->getName(), + 'iPermissionObjectId'=>$targetFolder->getPermissionObjectID(), + 'iPermissionLookupId'=>$targetFolder->getPermissionLookupID(), + 'iStatusId'=>1, + 'iMetadataVersionId'=>$sourceDocument->getMetadataVersionId(), + + )); + + $document = Document::get($oCore->getId()); + + return $document; + } + + /** + * Deletes a document symbolic link + * + * @param Document $document the symbolic link document + * @param User $user the user deleting the link + * @return unknown + */ + static function deleteSymbolicLink($document, $user = null) // added/ + { + //validate input + if (is_numeric($document)) + { + $document = Document::get($document); + } + if (!$document instanceof Document) + { + return PEAR::raiseError(_kt('Document not specified')); + } + if (!$document->isSymbolicLink()) + { + return PEAR::raiseError(_kt('Document must be a symbolic link entity')); + } + if (is_null($user)) + { + $user = $_SESSION['userID']; + } + if (is_numeric($user)) + { + $user = User::get($user); + } + + //check permissions + $oPerm = KTPermission::getByName('ktcore.permissions.delete'); + if (!KTBrowseUtil::inAdminMode($user, $document->getParentID())) { + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oPerm, $document)){ + return PEAR::raiseError(_kt('You\'re not authorized to delete this shortcut')); + } + } + + // we only need to delete the document entry for the link + $sql = "DELETE FROM documents WHERE id=?"; + DBUtil::runQuery(array($sql, array($document->getId()))); + + } + + // Overwrite the document function overwrite($oDocument, $sFilename, $sTempFileName, $oUser, $aOptions) { //$oDocument, $sFilename, $sCheckInComment, $oUser, $aOptions = false @@ -838,6 +986,12 @@ class KTDocumentUtil { // {{{ delete function delete($oDocument, $sReason, $iDestFolderId = null) { + // use the deleteSymbolicLink function is this is a symlink + if ($oDocument->isSymbolicLink()) + { + return KTDocumentUtil::deleteSymbolicLink($oDocument); + } + $oDocument =& KTUtil::getObject('Document', $oDocument); if (is_null($iDestFolderId)) { $iDestFolderId = $oDocument->getFolderID(); @@ -904,6 +1058,24 @@ class KTDocumentUtil { return PEAR::raiseError(_kt('There was a problem deleting the document from storage.')); } + //delete all shortcuts linking to this document + $aSymlinks = $oDocument->getSymbolicLinks(); + foreach($aSymlinks as $aSymlink){ + $oShortcutDocument = Document::get($aSymlink['id']); + $oOwnerUser = User::get($oShortcutDocument->getOwnerID()); + + KTDocumentUtil::deleteSymbolicLink($aSymlink['id']); + + //send an email to the owner of the shortcut + if($oOwnerUser->getEmail()!=null && $oOwnerUser->getEmailNotification() == true){ + $emailTemplate = new EmailTemplate("kt3/notifications/notification.SymbolicLinkDeleted",array('user_name'=>$this->oUser->getName(), + 'url'=>KTUtil::ktLink(KTBrowseUtil::getUrlForDocument($oShortcutDocument)), + 'title' =>$oShortcutDocument->getName())); + $email = new EmailAlert($oOwnerUser->getEmail(),_kt("KnowledgeTree Notification"),$emailTemplate->getBody()); + $email->send(); + } + } + $oDocumentTransaction = new DocumentTransaction($oDocument, _kt('Document deleted: ') . $sReason, 'ktcore.transactions.delete'); $oDocumentTransaction->create(); @@ -1166,7 +1338,12 @@ class KTDocumentUtil { } function move($oDocument, $oToFolder, $oUser = null, $sReason = null) { - + //make sure we move the symlink, and the document it's linking to + if($oDocument->isSymbolicLink()){ + $oDocument->switchToRealCore(); + }else{ + $oDocument->switchToLinkedCore(); + } $oFolder = $oToFolder; // alias. $oOriginalFolder = Folder::get($oDocument->getFolderId()); @@ -1185,18 +1362,20 @@ class KTDocumentUtil { } - //move the document on the file system - $oStorage =& KTStorageManagerUtil::getSingleton(); - $res = $oStorage->moveDocument($oDocument, $oFolder, $oOriginalFolder); - if (PEAR::isError($res) || ($res === false)) { - $oDocument->setFolderID($oOriginalFolder->getId()); - $res = $oDocument->update(); - if (PEAR::isError($res)) { - return $res; - } - return $res; // we failed, bail. + //move the document on the file system(not if it's a symlink) + if(!$oDocument->isSymbolicLink()){ + $oStorage =& KTStorageManagerUtil::getSingleton(); + $res = $oStorage->moveDocument($oDocument, $oFolder, $oOriginalFolder); + if (PEAR::isError($res) || ($res === false)) { + $oDocument->setFolderID($oOriginalFolder->getId()); + $res = $oDocument->update(); + if (PEAR::isError($res)) { + return $res; + } + return $res; // we failed, bail. + } } - + $sMoveMessage = sprintf(_kt("Moved from %s/%s to %s/%s. %s"), $oOriginalFolder->getFullPath(), $oOriginalFolder->getName(), diff --git a/lib/foldermanagement/Folder.inc b/lib/foldermanagement/Folder.inc index 132aac9..07a9bbe 100644 --- a/lib/foldermanagement/Folder.inc +++ b/lib/foldermanagement/Folder.inc @@ -65,6 +65,8 @@ class Folder extends KTEntity { var $iPermissionLookupID; /** whether to restrict to only certain document types */ var $bRestrictDocumentTypes = false; + /** ID of the folder this is a shortcut to(if any) */ + var $iLinkedFolderId; // {{{ KTEntity stuff var $_aFieldToSelect = array( @@ -79,6 +81,7 @@ class Folder extends KTEntity { 'iPermissionObjectID' => 'permission_object_id', 'iPermissionLookupID' => 'permission_lookup_id', 'bRestrictDocumentTypes' => 'restrict_document_types', + 'iLinkedFolderId' => 'linked_folder_id', ); // }}} @@ -104,6 +107,11 @@ class Folder extends KTEntity { function getRestrictDocumentTypes() { return $this->bRestrictDocumentTypes; } function setRestrictDocumentTypes($bRestrictDocumentTypes) { $this->bRestrictDocumentTypes = $bRestrictDocumentTypes; } + function getLinkedFolderId(){ return $this->iLinkedFolderId;} + function setLinkedFolderId($iNewValue){ $this->iLinkedFolderId = $iNewValue;} + + + // {{{ create() function create () { $oParentFolder =& Folder::get($this->iParentID); @@ -116,6 +124,18 @@ class Folder extends KTEntity { } // }}} + function loadFromArray ($aOptions) { + parent::loadFromArray($aOptions); + + //now load fields from the folder this folder is linking to, if any. + if($this->isSymbolicLink()){ + $oLinkedFolder = $this->getLinkedFolder(); + $this->sName = $oLinkedFolder->getName(); + $this->sDescription = $oLinkedFolder->getDescription(); + } + + } + /** * Returns a comma delimited string containing the parent folder ids, strips leading / * @@ -309,6 +329,63 @@ class Folder extends KTEntity { } /** + * Checks if this folder is a symbolic link + * + * @return boolean + */ + function isSymbolicLink() + { + return !is_null($this->getLinkedFolderId()); + } + + /** + * Retrieves the folder this folder links to, if any. + * + * @return Folder + */ + function getLinkedFolder(){ + if($this->isSymbolicLink()){ + return Folder::get($this->getLinkedFolderId()); + } + } + + /** + * Returns the "Symbolic link" folder + * + * @return Folder the folder + */ + function getRealFolder(){ + if (is_null($this->getLinkedFolderId())) + { + return Folder::get($this->getId()); + } + + $oFolder = Folder::get($this->getLinkedFolderId()); + return $oFolder->getRealFolder(); + } + + /** + * Returns the ID of the "Symbolic link" folder + * + * @return int the ID + */ + function getRealFolderId(){ + $oRealFolder = $this->getRealFolder(); + return $oRealFolder->getId(); + } + + /** + * Returns the symbolic links linking to this folder + * + * @return Array array with folder IDs + */ + function getSymbolicLinks(){ + $sQuery = 'SELECT * FROM folders ' . + 'WHERE folders.linked_folder_id = '.$this->getId(); + return DButil::getResultArray($sQuery); + } + + /** * Static function * Get a list of Documents * diff --git a/lib/foldermanagement/folderutil.inc.php b/lib/foldermanagement/folderutil.inc.php index 1744111..b75a6ea 100644 --- a/lib/foldermanagement/folderutil.inc.php +++ b/lib/foldermanagement/folderutil.inc.php @@ -45,6 +45,7 @@ require_once(KT_LIB_DIR . '/permissions/permissionutil.inc.php'); require_once(KT_LIB_DIR . '/users/User.inc'); require_once(KT_LIB_DIR . '/foldermanagement/foldertransaction.inc.php'); +require_once(KT_LIB_DIR . '/browse/browseutil.inc.php'); require_once(KT_LIB_DIR . '/database/dbutil.inc'); @@ -401,7 +402,17 @@ class KTFolderUtil { DBUtil::rollback(); return PEAR::raiseError(_kt('Failure deleting folders.')); } - + + //delete all folder shortcuts + foreach($aFolderIds as $iFolder){ + $oFolder = Folder::get($iFolder); + $aSymlinks = $oFolder->getSymbolicLinks(); + + foreach($aSymlinks as $aSymlink){ + KTFolderUtil::deleteSymbolicLink($aSymlink['id']); + } + } + // purge caches KTEntityUtil::clearAllCaches('Folder'); @@ -573,6 +584,125 @@ class KTFolderUtil { return true; } + +/** + * Create a symbolic link in the target folder + * + * @param Folder $sourceFolder Folder to create a link to + * @param Folder $targetFolder Folder to place the link in + * @param User $user current user + * @return Folder the link + */ + static function createSymbolicLink($sourceFolder, $targetFolder, $user = null) // added/ + { + //validate input + if (is_numeric($sourceFolder)) + { + $sourceFolder = Folder::get($sourceFolder); + } + if (!$sourceFolder instanceof Folder) + { + return PEAR::raiseError(_kt('Source folder not specified')); + } + if (is_numeric($targetFolder)) + { + $targetFolder = Folder::get($targetFolder); + } + if (!$targetFolder instanceof Folder) + { + return PEAR::raiseError(_kt('Target folder not specified')); + } + if (is_null($user)) + { + $user = $_SESSION['userID']; + } + if (is_numeric($user)) + { + $user = User::get($user); + } + + //check for permissions + $oWritePermission =& KTPermission::getByName("ktcore.permissions.write"); + $oReadPermission =& KTPermission::getByName("ktcore.permissions.read"); + if (!KTBrowseUtil::inAdminMode($user, $targetFolder)) { + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oWritePermission, $targetFolder)){ + return PEAR::raiseError(_kt('You\'re not authorized to create shortcuts')); + } + } + if (!KTBrowseUtil::inAdminMode($user, $sourceFolder)) { + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oReadPermission, $sourceFolder)){ + return PEAR::raiseError(_kt('You\'re not authorized to create a shortcut to this folder')); + } + } + + //check if the shortcut doesn't already exists in the target folder + $aSymlinks = $sourceFolder->getSymbolicLinks(); + foreach($aSymlinks as $iSymlink){ + $oSymlink = Folder::get($iSymlink['id']); + if($oSymlink->getParentID() == $targetFolder->getID()){ + return PEAR::raiseError(_kt('There already is a shortcut to this folder in the target folder.')); + } + } + + //Create the link + $oSymlink = Folder::createFromArray(array( + 'iParentID' => $targetFolder->getId(), + 'iCreatorID' => $user->getId(), + 'sFullPath' => $targetFolder->getFullPath(), + 'sParentFolderIDs' => $targetFolder->getParentFolderIDs(), + 'iPermissionObjectID' => $targetFolder->getPermissionObjectID(), + 'iPermissionLookupID' => $targetFolder->getPermissionLookupID(), + 'iLinkedFolderId' => $sourceFolder->getId(), + )); + return $oSymlink; + } + + /** + * Deletes a symbolic link folder + * + * @param Folder $folder tthe symbolic link folder to delete + * @param User $user the current user + * @return unknown + */ + static function deleteSymbolicLink($folder, $user = null) // added/ + { + //validate input + if (is_numeric($folder)) + { + $folder = Folder::get($folder); + } + if (!$folder instanceof Folder) + { + return PEAR::raiseError(_kt('Folder not specified')); + } + if (!$folder->isSymbolicLink()) + { + return PEAR::raiseError(_kt('Focument must be a symbolic link entity')); + } + if (is_null($user)) + { + $user = $_SESSION['userID']; + } + if (is_numeric($user)) + { + $user = User::get($user); + } + + //check if the user has sufficient permissions + $oPerm = KTPermission::getByName('ktcore.permissions.delete'); + if (!KTBrowseUtil::inAdminMode($user, $folder)) { + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oPerm, $folder)){ + return PEAR::raiseError(_kt('You\'re not authorized to create shortcuts')); + } + } + + // we only need to delete the folder entry for the link + $sql = "DELETE FROM folders WHERE id=?"; + DBUtil::runQuery(array($sql, array($folder->getId()))); + + } + + } ?> diff --git a/lib/permissions/permissionutil.inc.php b/lib/permissions/permissionutil.inc.php index 7bbeaf6..f11bb0d 100644 --- a/lib/permissions/permissionutil.inc.php +++ b/lib/permissions/permissionutil.inc.php @@ -304,6 +304,11 @@ class KTPermissionUtil { $is_a_folder = is_a($oFolderOrDocument, 'Folder'); $is_a_document = is_a($oFolderOrDocument, 'Document') || is_a($oFolderOrDocument, 'KTDocumentCore'); + //ensure that the document shortcut is being updated. + if($is_a_document && $oFolderOrDocument->isSymbolicLink()){ + $oFolderOrDocument->switchToRealCore(); + } + $oChannel = null; $aMapPermAllowed = null; $oPermLookup = null; @@ -325,7 +330,12 @@ class KTPermissionUtil { $msg = sprintf("Updating folder %s", join('/', $oFolderOrDocument->getPathArray())); } else { if (is_a($oFolderOrDocument, 'Document')) { - $msg = sprintf("Updating document %s", $oFolderOrDocument->getName()); + //modify the message to reflect that a shortcut is begin updated + if($oFolderOrDocument->isSymbolicLink()){ + $msg = sprintf("Updating shortcut to %s", $oFolderOrDocument->getName()); + }else{ + $msg = sprintf("Updating document %s", $oFolderOrDocument->getName()); + } } else { $msg = sprintf("Updating document %d", $oFolderOrDocument->getId()); } diff --git a/plugins/ktcore/KTBulkActions.php b/plugins/ktcore/KTBulkActions.php index 64d1fe5..e369dc4 100644 --- a/plugins/ktcore/KTBulkActions.php +++ b/plugins/ktcore/KTBulkActions.php @@ -92,14 +92,68 @@ class KTBulkDeleteAction extends KTBulkAction { return $oForm; } + /** + * build the confirmation form that is shown when symlinks are affected by this action. + * + * @return KTForm the form + */ + function form_confirm() { + $oForm = new KTForm; + $oForm->setOptions(array( + 'label' => _kt('Are you sure?'), + 'description' => _kt('There are shortcuts linking to some of the documents or folders in your selection; continuing will automatically delete the shortcuts. Would you like to continue?'), + 'action' => 'collectinfo', + 'fail_action' => 'main', + 'cancel_url' => KTBrowseUtil::getUrlForFolder($this->oFolder), + 'submit_label' => _kt('Continue'), + 'context' => $this, + )); + + $oForm->setWidgets(array( + array('ktcore.widgets.hidden',array( + 'name' => 'delete_confirmed', + 'value' => '1' + )))); + + return $oForm; + } + + /** + * Shows the confirmation form if symlinks are affected by the current action + * + * @return Template HTML + */ + function do_confirm(){ + $this->store_lists(); + $this->get_lists(); + $this->oPage->setBreadcrumbDetails(_kt('Confirm delete')); + $oTemplate =& $this->oValidator->validateTemplate('ktcore/bulk_action_confirm'); + $oForm = $this->form_confirm(); + $oTemplate->setData(array( + 'context' => &$this, + 'form' => $oForm, + )); + return $oTemplate->render(); + } + // info collection step function do_collectinfo() { $this->store_lists(); $this->get_lists(); - $oTemplating =& KTTemplating::getSingleton(); - $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_info'); - return $oTemplate->render(array('context' => $this, - 'form' => $this->form_collectinfo())); + + //check if a the symlinks deletion confirmation has been passed yet + if(KTutil::arrayGet($_REQUEST['data'],'delete_confirmed') != 1){ + //check if there are actually any symlinks involved. + if($this->symlinksLinkingToCurrentList()){ + $this->redirectTo("confirm"); + } + } + + //render template + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_info'); + return $oTemplate->render(array('context' => $this, + 'form' => $this->form_collectinfo())); } @@ -464,15 +518,71 @@ class KTBulkArchiveAction extends KTBulkAction { if((!is_a($oEntity, 'Document')) && (!is_a($oEntity, 'Folder'))) { return PEAR::raiseError(_kt('Document cannot be archived')); } + if($oEntity->isSymbolicLink()){ + return PEAR::raiseError(_kt("It is not possible to archive a shortcut. Please archive the target document or folder instead.")); + } return parent::check_entity($oEntity); } + /** + * build the confirmation form that is shown when symlinks are affected by this action. + * + * @return KTForm the form + */ + function form_confirm() { + $oForm = new KTForm; + $oForm->setOptions(array( + 'label' => _kt('Are you sure?'), + 'description' => _kt('There are shortcuts linking to some of the documents or folders in your selection; continuing will automatically delete the shortcuts. Would you like to continue?'), + 'action' => 'collectinfo', + 'fail_action' => 'main', + 'cancel_url' => KTBrowseUtil::getUrlForFolder($this->oFolder), + 'submit_label' => _kt('Continue'), + 'context' => $this, + )); + + $oForm->setWidgets(array( + array('ktcore.widgets.hidden',array( + 'name' => 'archive_confirmed', + 'value' => '1' + )))); + + return $oForm; + } + + /** + * Shows the confirmation form if symlinks are affected by the current action + * + * @return Template HTML + */ + function do_confirm(){ + $this->store_lists(); + $this->get_lists(); + $this->oPage->setBreadcrumbDetails(_kt('Confirm archive')); + $oTemplate =& $this->oValidator->validateTemplate('ktcore/bulk_action_confirm'); + $oForm = $this->form_confirm(); + $oTemplate->setData(array( + 'context' => &$this, + 'form' => $oForm, + )); + return $oTemplate->render(); + } + // info collection step function do_collectinfo() { $this->store_lists(); $this->get_lists(); - $oTemplating =& KTTemplating::getSingleton(); - $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_info'); + + //check if a the symlinks deletion confirmation has been passed yet + if(KTutil::arrayGet($_REQUEST['data'],'archive_confirmed') != 1){ + //check if there are actually any symlinks involved. + if($this->symlinksLinkingToCurrentList()){ + $this->redirectTo("confirm"); + } + } + + $oTemplating =& KTTemplating::getSingleton(); + $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_info'); return $oTemplate->render(array('context' => $this, 'form' => $this->form_collectinfo())); } @@ -637,6 +747,9 @@ class KTBrowseBulkExportAction extends KTBulkAction { if(is_a($oEntity, 'Document')) { $oDocument = $oEntity; + if($oDocument->isSymbolicLink()){ + $oDocument->switchToLinkedCore(); + } if ($this->bNoisy) { $oDocumentTransaction = new DocumentTransaction($oDocument, "Document part of bulk export", 'ktstandard.transactions.bulk_export', array()); @@ -932,7 +1045,6 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction { return $ret; } } - $this->oZip->addDocumentToZip($oEntity); } @@ -1066,4 +1178,4 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction { } } -?> +?> \ No newline at end of file diff --git a/plugins/ktcore/KTColumns.inc.php b/plugins/ktcore/KTColumns.inc.php index ff3a0a7..d1e2d3c 100644 --- a/plugins/ktcore/KTColumns.inc.php +++ b/plugins/ktcore/KTColumns.inc.php @@ -112,7 +112,18 @@ class AdvancedTitleColumn extends AdvancedColumn { } function buildDocumentLink($aDataRow) { - return KTBrowseUtil::getUrlForDocument($aDataRow["document"]->getId()); + if($aDataRow['document']->isSymbolicLink()){ + $iDocId = $aDataRow['document']->getRealDocumentId(); + }else{ + $iDocId = $aDataRow["document"]->getId(); + } + + $url = KTBrowseUtil::getUrlForDocument($iDocId); + if($aDataRow['document']->isSymbolicLink()){ + $aDataRow['document']->switchToRealCore(); + $url .= "&fShortcutFolder=".$aDataRow['document']->getFolderId(); + } + return $url; } @@ -122,9 +133,15 @@ class AdvancedTitleColumn extends AdvancedColumn { function buildFolderLink($aDataRow) { if (is_null(KTUtil::arrayGet($this->aOptions, 'direct_folder'))) { - $dest = KTUtil::arrayGet($this->aOptions, 'folder_link'); - $params = kt_array_merge(KTUtil::arrayGet($this->aOptions, 'qs_params', array()), - array('fFolderId' => $aDataRow['folder']->getId())); + $dest = KTUtil::arrayGet($this->aOptions, 'folder_link'); + if($aDataRow['folder']->isSymbolicLink()){ + $params = array('fFolderId' => $aDataRow['folder']->getLinkedFolderId(), + 'fShortcutFolder' => $aDataRow['folder']->getParentID()); + }else{ + $params = array('fFolderId' => $aDataRow['folder']->getId()); + } + $params = kt_array_merge(KTUtil::arrayGet($this->aOptions, 'qs_params', array()), + $params); if (empty($dest)) { return KTUtil::addQueryStringSelf($params); @@ -133,7 +150,11 @@ class AdvancedTitleColumn extends AdvancedColumn { } } else { - return KTBrowseUtil::getUrlForFolder($aDataRow['folder']); + if($aDataRow['folder']->isSymbolicLink()){ + return KTBrowseUtil::getUrlForFolder($aDataRow['folder']->getLinkedFolder())."&fShortcutFolder=".$aDataRow['folder']->getParentID(); + }else{ + return KTBrowseUtil::getUrlForFolder($aDataRow['folder']); + } } } @@ -142,12 +163,22 @@ class AdvancedTitleColumn extends AdvancedColumn { if ($aDataRow["type"] == "folder") { $contenttype = 'folder'; $link = $this->renderFolderLink($aDataRow); - return sprintf('%s', $contenttype, $link); + if($aDataRow['folder']->isSymbolicLink()){ + return sprintf('%s', $contenttype, $link); + }else{ + return sprintf('%s', $contenttype, $link); + } } else { - $contenttype = $this->_mimeHelper($aDataRow["document"]->getMimeTypeId()); - $link = $this->renderDocumentLink($aDataRow); - $size = $this->prettySize($aDataRow["document"]->getSize()); - return sprintf('%s (%s)', $contenttype, $link, $size); + $contenttype = $this->_mimeHelper($aDataRow["document"]->getMimeTypeId()); + $link = $this->renderDocumentLink($aDataRow); + + //Render an image instead of the size in case of a shortcut + if($aDataRow['document']->isSymbolicLink()){ + return sprintf('%s ', $contenttype, $link); + }else{ + $size = $this->prettySize($aDataRow["document"]->getSize()); + return sprintf('%s (%s)', $contenttype, $link, $size); + } } } @@ -359,6 +390,11 @@ class AdvancedSingleSelectionColumn extends AdvancedSelectionColumn { } function renderHeader() { + global $main; + //include some javascript to force real single selections + if($this->show_folders && $this->show_documents){ + $main->requireJSResource("resources/js/singleselect.js"); + } return ' '; } @@ -380,7 +416,12 @@ class AdvancedSingleSelectionColumn extends AdvancedSelectionColumn { return ' '; } - return ''; + $return = 'show_folders && $this->show_documents){ + $return .= 'onClick="forceSingleSelect(this)" '; + } + $return .='/>'; + return $return; } // no label, but we do have a title diff --git a/plugins/ktcore/KTDocumentActions.php b/plugins/ktcore/KTDocumentActions.php index e25f86a..ad25ff6 100644 --- a/plugins/ktcore/KTDocumentActions.php +++ b/plugins/ktcore/KTDocumentActions.php @@ -853,15 +853,31 @@ class KTDocumentDeleteAction extends KTDocumentAction { $_SESSION['KTErrorMessage'][]= _kt('This document can\'t be deleted because it is checked out'); controllerRedirect('viewDocument', 'fDocumentId=' . $this->oDocument->getId()); exit(0); - } + } + return true; } + function form_confirm() { + $oForm = new KTForm; + $oForm->setOptions(array( + 'label' => _kt('Are you sure?'), + 'description' => _kt('There are shortcuts linking to this document; deleting the document will automatically delete them. Would you like to continue?'), + 'action' => 'main', + 'fail_action' => 'main', + 'cancel_url' => KTBrowseUtil::getUrlForDocument($this->oDocument), + 'submit_label' => _kt('Delete Document'), + 'context' => &$this, + )); + + return $oForm; + } + function form_main() { $oForm = new KTForm; $oForm->setOptions(array( - 'label' => _kt('Delete Document'), + 'label' => _kt('Delete Document'), 'action' => 'delete', 'fail_action' => 'main', 'cancel_url' => KTBrowseUtil::getUrlForDocument($this->oDocument), @@ -888,16 +904,29 @@ class KTDocumentDeleteAction extends KTDocumentAction { function do_main() { $this->oPage->setBreadcrumbDetails(_kt('Delete')); + //check if we need confirmation for symblolic links linking to this document + if(count($this->oDocument->getSymbolicLinks())>0 && KTutil::arrayGet($_REQUEST,'postReceived') != 1){ + $this->redirectTo("confirm"); + } $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/delete'); - $oForm = $this->form_main(); - $oTemplate->setData(array( 'context' => &$this, 'form' => $oForm, )); return $oTemplate->render(); } + + function do_confirm(){ + $this->oPage->setBreadcrumbDetails(_kt('Confirm delete')); + $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/delete_confirm'); + $oForm = $this->form_confirm(); + $oTemplate->setData(array( + 'context' => &$this, + 'form' => $oForm, + )); + return $oTemplate->render(); + } function do_delete() { $oForm = $this->form_main(); @@ -1346,6 +1375,22 @@ class KTDocumentArchiveAction extends KTDocumentAction { return parent::getInfo(); } + function form_confirm() { + $oForm = new KTForm; + $oForm->setOptions(array( + 'label' => _kt('Are you sure?'), + 'description' => _kt('There are shortcuts linking to this document; archiving the document automatically will delete them. Would you like to continue?'), + 'action' => 'main', + 'fail_action' => 'main', + 'cancel_url' => KTBrowseUtil::getUrlForDocument($this->oDocument), + 'submit_label' => _kt('Archive Document'), + 'context' => &$this, + )); + + + return $oForm; + } + function form_main() { $oForm = new KTForm; $oForm->setOptions(array( @@ -1375,6 +1420,10 @@ class KTDocumentArchiveAction extends KTDocumentAction { } function do_main() { + //if there are symbolic links linking to this document we need confirmation + if(count($this->oDocument->getSymbolicLinks())>0 && KTutil::arrayGet($_REQUEST,'postReceived') != 1){ + $this->redirectTo("confirm"); + } $this->oPage->setBreadcrumbDetails(_kt('Archive Document')); $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/archive'); @@ -1386,6 +1435,17 @@ class KTDocumentArchiveAction extends KTDocumentAction { )); return $oTemplate->render(); } + + function do_confirm(){ + $this->oPage->setBreadcrumbDetails(_kt('Confirm archive')); + $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/archive_confirm'); + $oForm = $this->form_confirm(); + $oTemplate->setData(array( + 'context' => &$this, + 'form' => $oForm, + )); + return $oTemplate->render(); + } function do_archive() { diff --git a/resources/js/singleselect.js b/resources/js/singleselect.js new file mode 100755 index 0000000..baa1753 --- /dev/null +++ b/resources/js/singleselect.js @@ -0,0 +1,17 @@ +function forceSingleSelect(currentSelectedItem){ + var otherName = currentSelectedItem.name.substring(0,currentSelectedItem.name.length - 1); + if(currentSelectedItem.name.substring(currentSelectedItem.name.length-1) == 'd'){ + otherName += "f"; + }else{ + otherName += "d" + } + + var items = document.getElementsByTagName("input"); + for (var i=0; i. --- --- 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): ______________________________________ -- @@ -578,6 +578,7 @@ CREATE TABLE `documents` ( `restore_folder_path` text, `checkedout` datetime default NULL, `oem_no` varchar(255) default NULL, + `linked_document_id` int(11), PRIMARY KEY (`id`), KEY `creator_id` (`creator_id`), KEY `folder_id` (`folder_id`), @@ -813,6 +814,7 @@ CREATE TABLE `folders` ( `permission_lookup_id` int(11) default NULL, `restrict_document_types` tinyint(1) NOT NULL default '0', `owner_id` int(11) default NULL, + `linked_folder_id` int(11), PRIMARY KEY (`id`), KEY `creator_id` (`creator_id`), KEY `permission_object_id` (`permission_object_id`), diff --git a/sql/mysql/upgrade/3.5.3/shortcuts.sql b/sql/mysql/upgrade/3.5.3/shortcuts.sql new file mode 100644 index 0000000..0b65259 --- /dev/null +++ b/sql/mysql/upgrade/3.5.3/shortcuts.sql @@ -0,0 +1,2 @@ +ALTER TABLE documents ADD `linked_document_id` int(11); +ALTER TABLE folders ADD `linked_folder_id` int(11); \ No newline at end of file diff --git a/templates/kt3/notifications/notification.SymbolicLinkArchived.smarty b/templates/kt3/notifications/notification.SymbolicLinkArchived.smarty new file mode 100755 index 0000000..36b185d --- /dev/null +++ b/templates/kt3/notifications/notification.SymbolicLinkArchived.smarty @@ -0,0 +1,5 @@ +{i18n}The following shortcut is no longer valid as the target document has been archived. Please note that it has been automatically removed from the repository:{/i18n}
+
+{$title}
+
+{i18n}Target document archived by:{/i18n} {$user_name}
\ No newline at end of file diff --git a/templates/kt3/notifications/notification.SymbolicLinkDeleted.smarty b/templates/kt3/notifications/notification.SymbolicLinkDeleted.smarty new file mode 100755 index 0000000..670937d --- /dev/null +++ b/templates/kt3/notifications/notification.SymbolicLinkDeleted.smarty @@ -0,0 +1,5 @@ +{i18n}The following shortcut is no longer valid as the target document has been deleted. Please note that it has been automatically removed from the repository:{/i18n}
+
+{$title}
+
+{i18n}Target document deleted by:{/i18n} {$user_name}
\ No newline at end of file diff --git a/templates/ktcore/action/archive_confirm.smarty b/templates/ktcore/action/archive_confirm.smarty new file mode 100755 index 0000000..0492b4d --- /dev/null +++ b/templates/ktcore/action/archive_confirm.smarty @@ -0,0 +1,3 @@ +

get("ui/morphTo")}/title_bullet.png{else}{$rootUrl}/resources/graphics/title_bullet.png{/if}"/>{i18n}Archive Document{/i18n}:
{$context->oDocument->getName()|sanitize}

+ +{$form->render()} \ No newline at end of file diff --git a/templates/ktcore/action/delete_confirm.smarty b/templates/ktcore/action/delete_confirm.smarty new file mode 100755 index 0000000..0260b4f --- /dev/null +++ b/templates/ktcore/action/delete_confirm.smarty @@ -0,0 +1,3 @@ +

get("ui/morphTo")}/title_bullet.png{else}{$rootUrl}/resources/graphics/title_bullet.png{/if}"/>{i18n}Delete Document{/i18n}:
{$context->oDocument->getName()|sanitize}

+ +{$form->render()} \ No newline at end of file diff --git a/templates/ktcore/bulk_action_complete.smarty b/templates/ktcore/bulk_action_complete.smarty index 3a624a3..6293ef4 100644 --- a/templates/ktcore/bulk_action_complete.smarty +++ b/templates/ktcore/bulk_action_complete.smarty @@ -17,7 +17,10 @@ {foreach from=$list.folders item=item} - {$item.0|sanitize} + {$item.0|sanitize} + {if $item.2} + ({$item.2}) + {/if} {$item.1|sanitize} {/foreach} @@ -42,7 +45,10 @@ {foreach from=$list.documents item=item} - {$item.0|sanitize} + {$item.0|sanitize} + {if $item.2} + ({$item.2}) + {/if} {$item.1|sanitize} {/foreach} @@ -50,4 +56,4 @@ {/if} -{$form->render()} +{$form->render()} \ No newline at end of file diff --git a/templates/ktcore/bulk_action_confirm.smarty b/templates/ktcore/bulk_action_confirm.smarty new file mode 100755 index 0000000..950c0dd --- /dev/null +++ b/templates/ktcore/bulk_action_confirm.smarty @@ -0,0 +1,3 @@ +

{$context->getDisplayName()}

+ +{$form->render()} diff --git a/templates/ktcore/bulk_action_listing.smarty b/templates/ktcore/bulk_action_listing.smarty index 9270d3e..9014386 100644 --- a/templates/ktcore/bulk_action_listing.smarty +++ b/templates/ktcore/bulk_action_listing.smarty @@ -59,7 +59,11 @@

{i18n}Folders{/i18n}

    {foreach from=$folders item=folder} -
  • {$folder|sanitize}
  • +
  • {$folder.name|sanitize} +{if $folder.notice} + ({$folder.notice}) +{/if} +
  • {/foreach}
{/if} @@ -68,7 +72,11 @@

{i18n}Documents{/i18n}

    {foreach from=$documents item=document} -
  • {$document|sanitize}
  • +
  • {$document.name|sanitize} +{if $document.notice} + ({$document.notice}) +{/if} +
  • {/foreach}
{/if} @@ -86,4 +94,4 @@ {$failedform->render()} {else} {$form->render()} -{/if} +{/if} \ No newline at end of file diff --git a/templates/ktcore/folder/shortcut.smarty b/templates/ktcore/folder/shortcut.smarty new file mode 100755 index 0000000..f979e4a --- /dev/null +++ b/templates/ktcore/folder/shortcut.smarty @@ -0,0 +1,21 @@ +

{i18n}Add Shortcut{/i18n}

+ + +

{i18n}Select a document or folder to make a shortcut to.{/i18n} +

+ +{foreach from=$breadcrumbs item=breadcrumb name=bc} + {if !$smarty.foreach.bc.last} + {$breadcrumb.name|sanitize} » + {else} + {$breadcrumb.name|sanitize} + {/if} +{/foreach} + +
getId()}"> +{$collection->render()} +
+ + +
+
diff --git a/view.php b/view.php index d8b77ba..42d4de3 100644 --- a/view.php +++ b/view.php @@ -152,7 +152,20 @@ class ViewDocumentDispatcher extends KTStandardDispatcher { ); $this->oDocument =& $oDocument; - $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForDocument($oDocument, $aOptions)); + + //Figure out if we came here by navigating trough a shortcut. + //If we came here from a shortcut, the breadcrumbspath should be relative + //to the shortcut folder. + $iSymLinkFolderId = KTUtil::arrayGet($_REQUEST, 'fShortcutFolder', null); + if(is_numeric($iSymLinkFolderId)){ + $oBreadcrumbsFolder = Folder::get($iSymLinkFolderId); + $aOptions['final'] = false; + $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForFolder($oBreadcrumbsFolder,$aOptions)); + $this->aBreadcrumbs[] = array('name'=>$this->oDocument->getName()); + }else{ + $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForDocument($oDocument, $aOptions, $iSymLinkFolderId)); + } + $this->oPage->setBreadcrumbDetails(_kt('document details')); $this->addPortlets('Document Details');