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}
+
+
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');