Commit bb59234e9dd5e5abdc5be064e0700fc9dd01a0e2

Authored by Megan Watson
1 parent 9f11dc65

KTS-587

"Link to document between folders"
Fixed. Added base code for symbolic links / shortcuts.

Committed by: Aart-Jan Boor
Reviewed by: Megan Watson



git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/trunk@8771 c91229c3-7414-0410-bfa2-8a42b809f60b
browse.php
@@ -6,31 +6,31 @@ @@ -6,31 +6,31 @@
6 * Document Management Made Simple 6 * Document Management Made Simple
7 * Copyright (C) 2008 KnowledgeTree Inc. 7 * Copyright (C) 2008 KnowledgeTree Inc.
8 * Portions copyright The Jam Warehouse Software (Pty) Limited 8 * Portions copyright The Jam Warehouse Software (Pty) Limited
9 - * 9 + *
10 * This program is free software; you can redistribute it and/or modify it under 10 * This program is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License version 3 as published by the 11 * the terms of the GNU General Public License version 3 as published by the
12 * Free Software Foundation. 12 * Free Software Foundation.
13 - * 13 + *
14 * This program is distributed in the hope that it will be useful, but WITHOUT 14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details. 17 * details.
18 - * 18 + *
19 * You should have received a copy of the GNU General Public License 19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 - *  
22 - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, 21 + *
  22 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
23 * California 94120-7775, or email info@knowledgetree.com. 23 * California 94120-7775, or email info@knowledgetree.com.
24 - * 24 + *
25 * The interactive user interfaces in modified source and object code versions 25 * The interactive user interfaces in modified source and object code versions
26 * of this program must display Appropriate Legal Notices, as required under 26 * of this program must display Appropriate Legal Notices, as required under
27 * Section 5 of the GNU General Public License version 3. 27 * Section 5 of the GNU General Public License version 3.
28 - * 28 + *
29 * In accordance with Section 7(b) of the GNU General Public License version 3, 29 * In accordance with Section 7(b) of the GNU General Public License version 3,
30 * these Appropriate Legal Notices must retain the display of the "Powered by 30 * these Appropriate Legal Notices must retain the display of the "Powered by
31 - * KnowledgeTree" logo and retain the original copyright notice. If the display of the 31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
32 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices 32 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
33 - * must display the words "Powered by KnowledgeTree" and retain the original 33 + * must display the words "Powered by KnowledgeTree" and retain the original
34 * copyright notice. 34 * copyright notice.
35 * Contributor( s): ______________________________________ 35 * Contributor( s): ______________________________________
36 */ 36 */
@@ -68,196 +68,209 @@ $sectionName = &#39;browse&#39;; @@ -68,196 +68,209 @@ $sectionName = &#39;browse&#39;;
68 68
69 class BrowseDispatcher extends KTStandardDispatcher { 69 class BrowseDispatcher extends KTStandardDispatcher {
70 70
71 - var $sName = 'ktcore.actions.folder.view';  
72 -  
73 - var $oFolder = null;  
74 - var $sSection = 'browse';  
75 - var $browse_mode = null;  
76 - var $query = null;  
77 - var $resultURL;  
78 - var $sHelpPage = 'ktcore/browse.html';  
79 - var $editable;  
80 -  
81 - function BrowseDispatcher() {  
82 - $this->aBreadcrumbs = array(  
83 - array('action' => 'browse', 'name' => _kt('Browse')),  
84 - );  
85 - return parent::KTStandardDispatcher();  
86 - }  
87 -  
88 - function check() {  
89 - $this->browse_mode = KTUtil::arrayGet($_REQUEST, 'fBrowseMode', 'folder');  
90 - $action = KTUtil::arrayGet($_REQUEST, $this->event_var, 'main');  
91 - $this->editable = false;  
92 -  
93 -  
94 - // catch the alternative actions.  
95 - if ($action != 'main') {  
96 - return true;  
97 - }  
98 -  
99 - // if we're going to main ...  
100 -  
101 - // folder browse mode  
102 - if ($this->browse_mode == 'folder') {  
103 - $in_folder_id = KTUtil::arrayGet($_REQUEST, 'fFolderId');  
104 - if (empty($in_folder_id)) {  
105 - $oConfig = KTConfig::getSingleton();  
106 - if ($oConfig->get('tweaks/browseToUnitFolder')) {  
107 - $iHomeFolderId = $this->oUser->getHomeFolderId();  
108 - if ($iHomeFolderId) {  
109 - $in_folder_id = $iHomeFolderId;  
110 - }  
111 - }  
112 - }  
113 -  
114 - $folder_id = (int) $in_folder_id; // conveniently, will be 0 if not possible.  
115 - if ($folder_id == 0) {  
116 - $folder_id = 1;  
117 - }  
118 -  
119 - $_REQUEST['fBrowseMode'] = 'folder';  
120 -  
121 - // here we need the folder object to do the breadcrumbs.  
122 - $oFolder =& Folder::get($folder_id);  
123 - if (PEAR::isError($oFolder)) {  
124 - return false; // just fail.  
125 - }  
126 -  
127 - // check whether the user can edit this folder  
128 - $oPerm = KTPermission::getByName('ktcore.permissions.write');  
129 - if (KTPermissionUtil::userHasPermissionOnItem($this->oUser, $oPerm, $oFolder)) {  
130 - $this->editable = true;  
131 - } else {  
132 - $this->editable = false;  
133 - }  
134 -  
135 - // set the title and breadcrumbs...  
136 - $this->oPage->setTitle(_kt('Browse'));  
137 -  
138 - if (KTPermissionUtil::userHasPermissionOnItem($this->oUser, 'ktcore.permissions.folder_details', $oFolder)) {  
139 - $this->oPage->setSecondaryTitle($oFolder->getName());  
140 - } else {  
141 - if (KTBrowseUtil::inAdminMode($this->oUser, $oFolder)) {  
142 - $this->oPage->setSecondaryTitle(sprintf('(%s)', $oFolder->getName()));  
143 - } else {  
144 - $this->oPage->setSecondaryTitle('...');  
145 - }  
146 - }  
147 -  
148 - $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForFolder($oFolder));  
149 - $this->oFolder =& $oFolder;  
150 -  
151 -  
152 - // we now have a folder, and need to create the query.  
153 - $aOptions = array( 71 + var $sName = 'ktcore.actions.folder.view';
  72 +
  73 + var $oFolder = null;
  74 + var $sSection = 'browse';
  75 + var $browse_mode = null;
  76 + var $query = null;
  77 + var $resultURL;
  78 + var $sHelpPage = 'ktcore/browse.html';
  79 + var $editable;
  80 +
  81 + function BrowseDispatcher() {
  82 + $this->aBreadcrumbs = array(
  83 + array('action' => 'browse', 'name' => _kt('Browse')),
  84 + );
  85 + return parent::KTStandardDispatcher();
  86 + }
  87 +
  88 + function check() {
  89 + $this->browse_mode = KTUtil::arrayGet($_REQUEST, 'fBrowseMode', 'folder');
  90 + $action = KTUtil::arrayGet($_REQUEST, $this->event_var, 'main');
  91 + $this->editable = false;
  92 +
  93 +
  94 + // catch the alternative actions.
  95 + if ($action != 'main') {
  96 + return true;
  97 + }
  98 +
  99 + // if we're going to main ...
  100 +
  101 + // folder browse mode
  102 + if ($this->browse_mode == 'folder') {
  103 + $in_folder_id = KTUtil::arrayGet($_REQUEST, 'fFolderId');
  104 + if (empty($in_folder_id)) {
  105 + $oConfig = KTConfig::getSingleton();
  106 + if ($oConfig->get('tweaks/browseToUnitFolder')) {
  107 + $iHomeFolderId = $this->oUser->getHomeFolderId();
  108 + if ($iHomeFolderId) {
  109 + $in_folder_id = $iHomeFolderId;
  110 + }
  111 + }
  112 + }
  113 +
  114 + $folder_id = (int) $in_folder_id; // conveniently, will be 0 if not possible.
  115 + if ($folder_id == 0) {
  116 + $folder_id = 1;
  117 + }
  118 +
  119 + $_REQUEST['fBrowseMode'] = 'folder';
  120 +
  121 + // here we need the folder object to do the breadcrumbs.
  122 + $oFolder =& Folder::get($folder_id);
  123 + if (PEAR::isError($oFolder)) {
  124 + return false; // just fail.
  125 + }
  126 +
  127 + // check whether the user can edit this folder
  128 + $oPerm = KTPermission::getByName('ktcore.permissions.write');
  129 + if (KTPermissionUtil::userHasPermissionOnItem($this->oUser, $oPerm, $oFolder)) {
  130 + $this->editable = true;
  131 + } else {
  132 + $this->editable = false;
  133 + }
  134 +
  135 + // set the title and breadcrumbs...
  136 + $this->oPage->setTitle(_kt('Browse'));
  137 +
  138 + if (KTPermissionUtil::userHasPermissionOnItem($this->oUser, 'ktcore.permissions.folder_details', $oFolder)) {
  139 + $this->oPage->setSecondaryTitle($oFolder->getName());
  140 + } else {
  141 + if (KTBrowseUtil::inAdminMode($this->oUser, $oFolder)) {
  142 + $this->oPage->setSecondaryTitle(sprintf('(%s)', $oFolder->getName()));
  143 + } else {
  144 + $this->oPage->setSecondaryTitle('...');
  145 + }
  146 + }
  147 +
  148 + //Figure out if we came here by navigating trough a shortcut.
  149 + //If we came here from a shortcut, the breadcrumbspath should be relative
  150 + //to the shortcut folder.
  151 + $iSymLinkFolderId = KTUtil::arrayGet($_REQUEST, 'fShortcutFolder', null);
  152 + if(is_numeric($iSymLinkFolderId)){
  153 + $oBreadcrumbsFolder = Folder::get($iSymLinkFolderId);
  154 + $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForFolder($oBreadcrumbsFolder,array('final' => false)));
  155 + $this->aBreadcrumbs[] = array('name'=>$oFolder->getName());
  156 + }else{
  157 + $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForFolder($oFolder));
  158 + }
  159 + $this->oFolder =& $oFolder;
  160 +
  161 +
  162 + // we now have a folder, and need to create the query.
  163 + $aOptions = array(
154 'ignorepermissions' => KTBrowseUtil::inAdminMode($this->oUser, $oFolder), 164 'ignorepermissions' => KTBrowseUtil::inAdminMode($this->oUser, $oFolder),
155 - );  
156 - $this->oQuery = new BrowseQuery($oFolder->getId(), $this->oUser, $aOptions);  
157 - $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fFolderId=%d', $oFolder->getId()));  
158 -  
159 - // and the portlets  
160 - $portlet = new KTActionPortlet(sprintf(_kt('About this folder')));  
161 - $aActions = KTFolderActionUtil::getFolderInfoActionsForFolder($this->oFolder, $this->oUser);  
162 - $portlet->setActions($aActions,$this->sName);  
163 - $this->oPage->addPortlet($portlet);  
164 -  
165 - $portlet = new KTActionPortlet(sprintf(_kt('Actions on this folder')));  
166 - $aActions = KTFolderActionUtil::getFolderActionsForFolder($oFolder, $this->oUser);  
167 - $portlet->setActions($aActions,null);  
168 - $this->oPage->addPortlet($portlet);  
169 -  
170 -  
171 -  
172 - } else if ($this->browse_mode == 'lookup_value') {  
173 - // browsing by a lookup value  
174 -  
175 - $this->editable = false;  
176 -  
177 - // check the inputs  
178 - $field = KTUtil::arrayGet($_REQUEST, 'fField', null);  
179 - $oField = DocumentField::get($field);  
180 - if (PEAR::isError($oField) || ($oField == false)) {  
181 - $this->errorRedirectToMain('No Field selected.');  
182 - exit(0);  
183 - }  
184 - $value = KTUtil::arrayGet($_REQUEST, 'fValue', null);  
185 - $oValue = MetaData::get($value);  
186 - if (PEAR::isError($oValue) || ($oValue == false)) {  
187 - $this->errorRedirectToMain('No Value selected.');  
188 - exit(0);  
189 - }  
190 -  
191 -  
192 - $this->oQuery = new ValueBrowseQuery($oField, $oValue);  
193 - $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'],  
194 - sprintf('fBrowseMode=lookup_value&fField=%d&fValue=%d', $field, $value));  
195 -  
196 - // setup breadcrumbs  
197 - $this->aBreadcrumbs =  
198 - array(  
199 - array('name' => _kt('Lookup Values'), 165 + );
  166 + $this->oQuery = new BrowseQuery($oFolder->getId(), $this->oUser, $aOptions);
  167 +
  168 + $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fFolderId=%d', $oFolder->getId()));
  169 +
  170 + // and the portlets
  171 + $portlet = new KTActionPortlet(sprintf(_kt('About this folder')));
  172 + $aActions = KTFolderActionUtil::getFolderInfoActionsForFolder($this->oFolder, $this->oUser);
  173 + $portlet->setActions($aActions,$this->sName);
  174 + $this->oPage->addPortlet($portlet);
  175 +
  176 + $portlet = new KTActionPortlet(sprintf(_kt('Actions on this folder')));
  177 + $aActions = KTFolderActionUtil::getFolderActionsForFolder($oFolder, $this->oUser);
  178 + $portlet->setActions($aActions,null);
  179 + $this->oPage->addPortlet($portlet);
  180 +
  181 +
  182 +
  183 + } else if ($this->browse_mode == 'lookup_value') {
  184 + // browsing by a lookup value
  185 +
  186 + $this->editable = false;
  187 +
  188 + // check the inputs
  189 + $field = KTUtil::arrayGet($_REQUEST, 'fField', null);
  190 + $oField = DocumentField::get($field);
  191 + if (PEAR::isError($oField) || ($oField == false)) {
  192 + $this->errorRedirectToMain('No Field selected.');
  193 + exit(0);
  194 + }
  195 + $value = KTUtil::arrayGet($_REQUEST, 'fValue', null);
  196 + $oValue = MetaData::get($value);
  197 + if (PEAR::isError($oValue) || ($oValue == false)) {
  198 + $this->errorRedirectToMain('No Value selected.');
  199 + exit(0);
  200 + }
  201 +
  202 +
  203 + $this->oQuery = new ValueBrowseQuery($oField, $oValue);
  204 + $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'],
  205 + sprintf('fBrowseMode=lookup_value&fField=%d&fValue=%d', $field, $value));
  206 +
  207 + // setup breadcrumbs
  208 + $this->aBreadcrumbs =
  209 + array(
  210 + array('name' => _kt('Lookup Values'),
200 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectField')), 211 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectField')),
201 - array('name' => $oField->getName(), 212 + array('name' => $oField->getName(),
202 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectLookup&fField=' . $oField->getId())), 213 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectLookup&fField=' . $oField->getId())),
203 - array('name' => $oValue->getName(), 214 + array('name' => $oValue->getName(),
204 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fBrowseMode=lookup_value&fField=%d&fValue=%d', $field, $value)))); 215 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fBrowseMode=lookup_value&fField=%d&fValue=%d', $field, $value))));
205 216
206 217
207 218
208 - } else if ($this->browse_mode == 'document_type') {  
209 - // browsing by document type 219 + } else if ($this->browse_mode == 'document_type') {
  220 + // browsing by document type
  221 +
210 222
  223 + $this->editable = false;
  224 + $doctype = KTUtil::arrayGet($_REQUEST, 'fType',null);
  225 + $oDocType = DocumentType::get($doctype);
  226 + if (PEAR::isError($oDocType) || ($oDocType == false)) {
  227 + $this->errorRedirectToMain('No Document Type selected.');
  228 + exit(0);
  229 + }
211 230
212 - $this->editable = false;  
213 - $doctype = KTUtil::arrayGet($_REQUEST, 'fType',null);  
214 - $oDocType = DocumentType::get($doctype);  
215 - if (PEAR::isError($oDocType) || ($oDocType == false)) {  
216 - $this->errorRedirectToMain('No Document Type selected.');  
217 - exit(0);  
218 - } 231 + $this->oQuery = new TypeBrowseQuery($oDocType);
219 232
220 - $this->oQuery = new TypeBrowseQuery($oDocType); 233 + // FIXME probably want to redirect to self + action=selectType
  234 + $this->aBreadcrumbs[] = array('name' => _kt('Document Types'), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectType'));
  235 + $this->aBreadcrumbs[] = array('name' => $oDocType->getName(), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'fBrowseMode=document_type&fType=' . $oDocType->getId()));
221 236
222 - // FIXME probably want to redirect to self + action=selectType  
223 - $this->aBreadcrumbs[] = array('name' => _kt('Document Types'), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectType'));  
224 - $this->aBreadcrumbs[] = array('name' => $oDocType->getName(), 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'fBrowseMode=document_type&fType=' . $oDocType->getId())); 237 + $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fType=%s&fBrowseMode=document_type', $doctype));;
225 238
226 - $this->resultURL = KTUtil::addQueryString($_SERVER['PHP_SELF'], sprintf('fType=%s&fBrowseMode=document_type', $doctype));;  
227 239
  240 + } else {
  241 + // FIXME what should we do if we can't initiate the browse? we "pretend" to have no perms.
  242 + return false;
  243 + }
228 244
229 - } else {  
230 - // FIXME what should we do if we can't initiate the browse? we "pretend" to have no perms.  
231 - return false;  
232 - } 245 + return true;
  246 + }
233 247
234 - return true;  
235 - } 248 + function do_main() {
  249 + $oColumnRegistry =& KTColumnRegistry::getSingleton();
236 250
237 - function do_main() {  
238 - $oColumnRegistry =& KTColumnRegistry::getSingleton(); 251 + $collection = new AdvancedCollection;
  252 + $collection->addColumns($oColumnRegistry->getColumnsForView('ktcore.views.browse'));
239 253
240 - $collection = new AdvancedCollection;  
241 - $collection->addColumns($oColumnRegistry->getColumnsForView('ktcore.views.browse')); 254 + $aOptions = $collection->getEnvironOptions(); // extract data from the environment
  255 + $aOptions['result_url'] = $this->resultURL;
  256 + $aOptions['is_browse'] = true;
242 257
243 - $aOptions = $collection->getEnvironOptions(); // extract data from the environment  
244 - $aOptions['result_url'] = $this->resultURL;  
245 - $aOptions['is_browse'] = true; 258 +
246 259
247 - $collection->setOptions($aOptions);  
248 - $collection->setQueryObject($this->oQuery);  
249 - $collection->setColumnOptions('ktcore.columns.selection', array( 260 + $collection->setOptions($aOptions);
  261 + $collection->setQueryObject($this->oQuery);
  262 + $collection->setColumnOptions('ktcore.columns.selection', array(
250 'rangename' => 'selection', 263 'rangename' => 'selection',
251 'show_folders' => true, 264 'show_folders' => true,
252 'show_documents' => true, 265 'show_documents' => true,
253 - )); 266 + ));
254 267
255 - // get bulk actions  
256 - $aBulkActions = KTBulkActionUtil::getAllBulkActions(); 268 + // get bulk actions
  269 + $aBulkActions = KTBulkActionUtil::getAllBulkActions();
257 270
258 - $oTemplating =& KTTemplating::getSingleton();  
259 - $oTemplate = $oTemplating->loadTemplate('kt3/browse');  
260 - $aTemplateData = array( 271 + $oTemplating =& KTTemplating::getSingleton();
  272 + $oTemplate = $oTemplating->loadTemplate('kt3/browse');
  273 + $aTemplateData = array(
261 'context' => $this, 274 'context' => $this,
262 'collection' => $collection, 275 'collection' => $collection,
263 'browse_mode' => $this->browse_mode, 276 'browse_mode' => $this->browse_mode,
@@ -265,160 +278,160 @@ class BrowseDispatcher extends KTStandardDispatcher { @@ -265,160 +278,160 @@ class BrowseDispatcher extends KTStandardDispatcher {
265 'bulkactions' => $aBulkActions, 278 'bulkactions' => $aBulkActions,
266 'browseutil' => new KTBrowseUtil(), 279 'browseutil' => new KTBrowseUtil(),
267 'returnaction' => 'browse', 280 'returnaction' => 'browse',
268 - );  
269 - if ($this->oFolder) {  
270 - $aTemplateData['returndata'] = $this->oFolder->getId();  
271 - }  
272 - return $oTemplate->render($aTemplateData);  
273 - } 281 + );
  282 + if ($this->oFolder) {
  283 + $aTemplateData['returndata'] = $this->oFolder->getId();
  284 + }
  285 + return $oTemplate->render($aTemplateData);
  286 + }
274 287
275 288
276 289
277 - function do_selectField() {  
278 - $aFields = DocumentField::getList('has_lookup = 1'); 290 + function do_selectField() {
  291 + $aFields = DocumentField::getList('has_lookup = 1');
279 292
280 - if (empty($aFields)) {  
281 - $this->errorRedirectToMain(_kt('No lookup fields available.'));  
282 - exit(0);  
283 - } 293 + if (empty($aFields)) {
  294 + $this->errorRedirectToMain(_kt('No lookup fields available.'));
  295 + exit(0);
  296 + }
284 297
285 - $_REQUEST['fBrowseMode'] = 'lookup_value'; 298 + $_REQUEST['fBrowseMode'] = 'lookup_value';
286 299
287 - $oTemplating =& KTTemplating::getSingleton();  
288 - $oTemplate = $oTemplating->loadTemplate('kt3/browse_lookup_selection');  
289 - $aTemplateData = array( 300 + $oTemplating =& KTTemplating::getSingleton();
  301 + $oTemplate = $oTemplating->loadTemplate('kt3/browse_lookup_selection');
  302 + $aTemplateData = array(
290 'context' => $this, 303 'context' => $this,
291 'fields' => $aFields, 304 'fields' => $aFields,
292 - );  
293 - return $oTemplate->render($aTemplateData);  
294 - } 305 + );
  306 + return $oTemplate->render($aTemplateData);
  307 + }
295 308
296 - function do_selectLookup() {  
297 - $field = KTUtil::arrayGet($_REQUEST, 'fField', null);  
298 - $oField = DocumentField::get($field);  
299 - if (PEAR::isError($oField) || ($oField == false) || (!$oField->getHasLookup())) {  
300 - $this->errorRedirectToMain('No Field selected.');  
301 - exit(0);  
302 - } 309 + function do_selectLookup() {
  310 + $field = KTUtil::arrayGet($_REQUEST, 'fField', null);
  311 + $oField = DocumentField::get($field);
  312 + if (PEAR::isError($oField) || ($oField == false) || (!$oField->getHasLookup())) {
  313 + $this->errorRedirectToMain('No Field selected.');
  314 + exit(0);
  315 + }
303 316
304 - $_REQUEST['fBrowseMode'] = 'lookup_value'; 317 + $_REQUEST['fBrowseMode'] = 'lookup_value';
305 318
306 - $aValues = MetaData::getByDocumentField($oField); 319 + $aValues = MetaData::getByDocumentField($oField);
307 320
308 - $oTemplating =& KTTemplating::getSingleton();  
309 - $oTemplate = $oTemplating->loadTemplate('kt3/browse_lookup_value');  
310 - $aTemplateData = array( 321 + $oTemplating =& KTTemplating::getSingleton();
  322 + $oTemplate = $oTemplating->loadTemplate('kt3/browse_lookup_value');
  323 + $aTemplateData = array(
311 'context' => $this, 324 'context' => $this,
312 'oField' => $oField, 325 'oField' => $oField,
313 'values' => $aValues, 326 'values' => $aValues,
314 - );  
315 - return $oTemplate->render($aTemplateData);  
316 - } 327 + );
  328 + return $oTemplate->render($aTemplateData);
  329 + }
317 330
318 - function do_selectType() {  
319 - $aTypes = DocumentType::getList();  
320 - // FIXME what is the error message? 331 + function do_selectType() {
  332 + $aTypes = DocumentType::getList();
  333 + // FIXME what is the error message?
321 334
322 - $_REQUEST['fBrowseMode'] = 'document_type'; 335 + $_REQUEST['fBrowseMode'] = 'document_type';
323 336
324 - if (empty($aTypes)) {  
325 - $this->errorRedirectToMain('No document types available.');  
326 - exit(0);  
327 - } 337 + if (empty($aTypes)) {
  338 + $this->errorRedirectToMain('No document types available.');
  339 + exit(0);
  340 + }
328 341
329 - $oTemplating =& KTTemplating::getSingleton();  
330 - $oTemplate = $oTemplating->loadTemplate('kt3/browse_types');  
331 - $aTemplateData = array( 342 + $oTemplating =& KTTemplating::getSingleton();
  343 + $oTemplate = $oTemplating->loadTemplate('kt3/browse_types');
  344 + $aTemplateData = array(
332 'context' => $this, 345 'context' => $this,
333 'document_types' => $aTypes, 346 'document_types' => $aTypes,
334 - );  
335 - return $oTemplate->render($aTemplateData);  
336 - }  
337 -  
338 - function do_enableAdminMode() {  
339 - $iDocumentId = KTUtil::arrayGet($_REQUEST, 'fDocumentId');  
340 - $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId');  
341 - if ($iDocumentId) {  
342 - $oDocument = Document::get($iDocumentId);  
343 - if (PEAR::isError($oDocument) || ($oDocument === false)) {  
344 - return null;  
345 - }  
346 - $iFolderId = $oDocument->getFolderId();  
347 - }  
348 -  
349 - if (!Permission::userIsSystemAdministrator() && !Permission::isUnitAdministratorForFolder($this->oUser, $iFolderId)) {  
350 - $this->errorRedirectToMain(_kt('You are not an administrator'));  
351 - }  
352 -  
353 - // log this entry  
354 - $oLogEntry =& KTUserHistory::createFromArray(array( 347 + );
  348 + return $oTemplate->render($aTemplateData);
  349 + }
  350 +
  351 + function do_enableAdminMode() {
  352 + $iDocumentId = KTUtil::arrayGet($_REQUEST, 'fDocumentId');
  353 + $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId');
  354 + if ($iDocumentId) {
  355 + $oDocument = Document::get($iDocumentId);
  356 + if (PEAR::isError($oDocument) || ($oDocument === false)) {
  357 + return null;
  358 + }
  359 + $iFolderId = $oDocument->getFolderId();
  360 + }
  361 +
  362 + if (!Permission::userIsSystemAdministrator() && !Permission::isUnitAdministratorForFolder($this->oUser, $iFolderId)) {
  363 + $this->errorRedirectToMain(_kt('You are not an administrator'));
  364 + }
  365 +
  366 + // log this entry
  367 + $oLogEntry =& KTUserHistory::createFromArray(array(
355 'userid' => $this->oUser->getId(), 368 'userid' => $this->oUser->getId(),
356 'datetime' => date('Y-m-d H:i:s', time()), 369 'datetime' => date('Y-m-d H:i:s', time()),
357 'actionnamespace' => 'ktcore.user_history.enable_admin_mode', 370 'actionnamespace' => 'ktcore.user_history.enable_admin_mode',
358 'comments' => 'Admin Mode enabled', 371 'comments' => 'Admin Mode enabled',
359 'sessionid' => $_SESSION['sessionID'], 372 'sessionid' => $_SESSION['sessionID'],
360 - ));  
361 - $aOpts = array( 373 + ));
  374 + $aOpts = array(
362 'redirect_to' => 'main', 375 'redirect_to' => 'main',
363 'message' => _kt('Unable to log admin mode entry. Not activating admin mode.'), 376 'message' => _kt('Unable to log admin mode entry. Not activating admin mode.'),
364 - );  
365 - $this->oValidator->notError($oLogEntry, $aOpts);  
366 -  
367 - $_SESSION['adminmode'] = true;  
368 -  
369 -  
370 -  
371 - if ($_REQUEST['fDocumentId']) {  
372 - $_SESSION['KTInfoMessage'][] = _kt('Administrator mode enabled');  
373 - redirect(KTBrowseUtil::getUrlForDocument($iDocumentId));  
374 - exit(0);  
375 - }  
376 - if ($_REQUEST['fFolderId']) {  
377 - $this->successRedirectToMain(_kt('Administrator mode enabled'), sprintf('fFolderId=%d', $_REQUEST['fFolderId']));  
378 - }  
379 - $this->successRedirectToMain(_kt('Administrator mode enabled'));  
380 - }  
381 -  
382 - function do_disableAdminMode() {  
383 - $iDocumentId = KTUtil::arrayGet($_REQUEST, 'fDocumentId');  
384 - $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId');  
385 - if ($iDocumentId) {  
386 - $oDocument = Document::get($iDocumentId);  
387 - if (PEAR::isError($oDocument) || ($oDocument === false)) {  
388 - return null;  
389 - }  
390 - $iFolderId = $oDocument->getFolderId();  
391 - }  
392 -  
393 - if (!Permission::userIsSystemAdministrator() && !Permission::isUnitAdministratorForFolder($this->oUser, $iFolderId)) {  
394 - $this->errorRedirectToMain(_kt('You are not an administrator'));  
395 - }  
396 -  
397 - // log this entry  
398 - $oLogEntry =& KTUserHistory::createFromArray(array( 377 + );
  378 + $this->oValidator->notError($oLogEntry, $aOpts);
  379 +
  380 + $_SESSION['adminmode'] = true;
  381 +
  382 +
  383 +
  384 + if ($_REQUEST['fDocumentId']) {
  385 + $_SESSION['KTInfoMessage'][] = _kt('Administrator mode enabled');
  386 + redirect(KTBrowseUtil::getUrlForDocument($iDocumentId));
  387 + exit(0);
  388 + }
  389 + if ($_REQUEST['fFolderId']) {
  390 + $this->successRedirectToMain(_kt('Administrator mode enabled'), sprintf('fFolderId=%d', $_REQUEST['fFolderId']));
  391 + }
  392 + $this->successRedirectToMain(_kt('Administrator mode enabled'));
  393 + }
  394 +
  395 + function do_disableAdminMode() {
  396 + $iDocumentId = KTUtil::arrayGet($_REQUEST, 'fDocumentId');
  397 + $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId');
  398 + if ($iDocumentId) {
  399 + $oDocument = Document::get($iDocumentId);
  400 + if (PEAR::isError($oDocument) || ($oDocument === false)) {
  401 + return null;
  402 + }
  403 + $iFolderId = $oDocument->getFolderId();
  404 + }
  405 +
  406 + if (!Permission::userIsSystemAdministrator() && !Permission::isUnitAdministratorForFolder($this->oUser, $iFolderId)) {
  407 + $this->errorRedirectToMain(_kt('You are not an administrator'));
  408 + }
  409 +
  410 + // log this entry
  411 + $oLogEntry =& KTUserHistory::createFromArray(array(
399 'userid' => $this->oUser->getId(), 412 'userid' => $this->oUser->getId(),
400 'datetime' => date('Y-m-d H:i:s', time()), 413 'datetime' => date('Y-m-d H:i:s', time()),
401 'actionnamespace' => 'ktcore.user_history.disable_admin_mode', 414 'actionnamespace' => 'ktcore.user_history.disable_admin_mode',
402 'comments' => 'Admin Mode disabled', 415 'comments' => 'Admin Mode disabled',
403 'sessionid' => $_SESSION['sessionID'], 416 'sessionid' => $_SESSION['sessionID'],
404 - ));  
405 - $aOpts = array( 417 + ));
  418 + $aOpts = array(
406 'redirect_to' => 'main', 419 'redirect_to' => 'main',
407 'message' => _kt('Unable to log admin mode exit. Not de-activating admin mode.'), 420 'message' => _kt('Unable to log admin mode exit. Not de-activating admin mode.'),
408 - );  
409 - $this->oValidator->notError($oLogEntry, $aOpts);  
410 -  
411 - $_SESSION['adminmode'] = false;  
412 - if ($_REQUEST['fDocumentId']) {  
413 - $_SESSION['KTInfoMessage'][] = _kt('Administrator mode disabled');  
414 - redirect(KTBrowseUtil::getUrlForDocument($iDocumentId));  
415 - exit(0);  
416 - }  
417 - if ($_REQUEST['fFolderId']) {  
418 - $this->successRedirectToMain(_kt('Administrator mode disabled'), sprintf('fFolderId=%d', $_REQUEST['fFolderId']));  
419 - }  
420 - $this->successRedirectToMain(_kt('Administrator mode disabled'));  
421 - } 421 + );
  422 + $this->oValidator->notError($oLogEntry, $aOpts);
  423 +
  424 + $_SESSION['adminmode'] = false;
  425 + if ($_REQUEST['fDocumentId']) {
  426 + $_SESSION['KTInfoMessage'][] = _kt('Administrator mode disabled');
  427 + redirect(KTBrowseUtil::getUrlForDocument($iDocumentId));
  428 + exit(0);
  429 + }
  430 + if ($_REQUEST['fFolderId']) {
  431 + $this->successRedirectToMain(_kt('Administrator mode disabled'), sprintf('fFolderId=%d', $_REQUEST['fFolderId']));
  432 + }
  433 + $this->successRedirectToMain(_kt('Administrator mode disabled'));
  434 + }
422 } 435 }
423 436
424 $oDispatcher = new BrowseDispatcher(); 437 $oDispatcher = new BrowseDispatcher();
ktapi/KTAPIDocument.inc.php
@@ -113,8 +113,28 @@ class KTAPI_Document extends KTAPI_FolderItem @@ -113,8 +113,28 @@ class KTAPI_Document extends KTAPI_FolderItem
113 { 113 {
114 return ($this->document->getStatusID() == 3); 114 return ($this->document->getStatusID() == 3);
115 } 115 }
  116 +
  117 + /**
  118 + * Checks if the document is a shortcut
  119 + *
  120 + * @return boolean
  121 + */
  122 + function is_shortcut()
  123 + {
  124 + return $this->document->isSymbolicLink();
  125 + }
116 126
117 /** 127 /**
  128 + * Retrieves the shortcuts linking to this document
  129 + *
  130 + */
  131 + function get_shortcuts()
  132 + {
  133 + return $this->document->getSymbolicLinks();
  134 + }
  135 +
  136 +
  137 + /**
118 * This is the constructor for the KTAPI_Folder. 138 * This is the constructor for the KTAPI_Folder.
119 * 139 *
120 * @access private 140 * @access private
@@ -1478,7 +1498,7 @@ class KTAPI_Document extends KTAPI_FolderItem @@ -1478,7 +1498,7 @@ class KTAPI_Document extends KTAPI_FolderItem
1478 1498
1479 $detail = array(); 1499 $detail = array();
1480 $document = $this->document; 1500 $document = $this->document;
1481 - 1501 +
1482 // get the document id 1502 // get the document id
1483 $detail['document_id'] = (int) $document->getId(); 1503 $detail['document_id'] = (int) $document->getId();
1484 1504
@@ -1601,6 +1621,12 @@ class KTAPI_Document extends KTAPI_FolderItem @@ -1601,6 +1621,12 @@ class KTAPI_Document extends KTAPI_FolderItem
1601 { 1621 {
1602 $detail['version'] = (float) $detail['version']; 1622 $detail['version'] = (float) $detail['version'];
1603 } 1623 }
  1624 +
  1625 + //might be unset at the bottom in case of old webservice version
  1626 + //make sure we're using the real document for this one
  1627 + $this->document->switchToRealCore();
  1628 + $detail['linked_document_id'] = $document->getLinkedDocumentId();
  1629 + $this->document->switchToLinkedCore();
1604 1630
1605 // check immutability 1631 // check immutability
1606 $detail['is_immutable'] = (bool) $document->getImmutable(); 1632 $detail['is_immutable'] = (bool) $document->getImmutable();
@@ -1651,7 +1677,10 @@ class KTAPI_Document extends KTAPI_FolderItem @@ -1651,7 +1677,10 @@ class KTAPI_Document extends KTAPI_FolderItem
1651 unset($detail['updated_by']); 1677 unset($detail['updated_by']);
1652 unset($detail['updated_date']); 1678 unset($detail['updated_date']);
1653 } 1679 }
1654 - 1680 + if($wsversion < 3){
  1681 + unset($detail['linked_document_id']);
  1682 + }
  1683 +
1655 return $detail; 1684 return $detail;
1656 } 1685 }
1657 1686
ktapi/KTAPIFolder.inc.php
@@ -97,6 +97,25 @@ class KTAPI_Folder extends KTAPI_FolderItem @@ -97,6 +97,25 @@ class KTAPI_Folder extends KTAPI_FolderItem
97 } 97 }
98 98
99 /** 99 /**
  100 + * Checks if the folder is a shortcut
  101 + *
  102 + * @return boolean
  103 + */
  104 + function is_shortcut()
  105 + {
  106 + return $this->folder->isSymbolicLink();
  107 + }
  108 +
  109 + /**
  110 + * Retrieves the shortcuts linking to this folder
  111 + *
  112 + */
  113 + function get_shortcuts()
  114 + {
  115 + return $this->folder->getSymbolicLinks();
  116 + }
  117 +
  118 + /**
100 * This is the constructor for the KTAPI_Folder. 119 * This is the constructor for the KTAPI_Folder.
101 * 120 *
102 * @access private 121 * @access private
@@ -131,13 +150,22 @@ class KTAPI_Folder extends KTAPI_FolderItem @@ -131,13 +150,22 @@ class KTAPI_Folder extends KTAPI_FolderItem
131 function get_detail() 150 function get_detail()
132 { 151 {
133 $this->clearCache(); 152 $this->clearCache();
  153 +
  154 + $config = KTConfig::getSingleton();
  155 + $wsversion = $config->get('webservice/version', LATEST_WEBSERVICE_VERSION);
  156 +
134 $detail = array( 157 $detail = array(
135 'id'=>(int) $this->folderid, 158 'id'=>(int) $this->folderid,
136 'folder_name'=>$this->get_folder_name(), 159 'folder_name'=>$this->get_folder_name(),
137 'parent_id'=>(int) $this->get_parent_folder_id(), 160 'parent_id'=>(int) $this->get_parent_folder_id(),
138 'full_path'=>$this->get_full_path(), 161 'full_path'=>$this->get_full_path(),
  162 + 'linked_folder_id'=>$this->folder->getLinkedFolderId(),
139 ); 163 );
140 164
  165 + if($wsversion<3){
  166 + unset($detail['linked_folder_id']);
  167 + }
  168 +
141 return $detail; 169 return $detail;
142 } 170 }
143 171
@@ -340,7 +368,7 @@ class KTAPI_Folder extends KTAPI_FolderItem @@ -340,7 +368,7 @@ class KTAPI_Folder extends KTAPI_FolderItem
340 return $perms; 368 return $perms;
341 } 369 }
342 370
343 - function get_listing($depth=1, $what='DF') 371 + function get_listing($depth=1, $what='DFS')
344 { 372 {
345 if ($depth < 1) 373 if ($depth < 1)
346 { 374 {
@@ -359,8 +387,8 @@ class KTAPI_Folder extends KTAPI_FolderItem @@ -359,8 +387,8 @@ class KTAPI_Folder extends KTAPI_FolderItem
359 387
360 $contents = array(); 388 $contents = array();
361 389
362 - if (strpos($what,'F') !== false)  
363 - { 390 +
  391 +
364 $folder_children = Folder::getList(array('parent_id = ?', $this->folderid)); 392 $folder_children = Folder::getList(array('parent_id = ?', $this->folderid));
365 393
366 foreach ($folder_children as $folder) 394 foreach ($folder_children as $folder)
@@ -383,7 +411,7 @@ class KTAPI_Folder extends KTAPI_FolderItem @@ -383,7 +411,7 @@ class KTAPI_Folder extends KTAPI_FolderItem
383 411
384 if ($wsversion >= 2) 412 if ($wsversion >= 2)
385 { 413 {
386 - $contents[] = array( 414 + $array = array(
387 'id' => (int) $folder->getId(), 415 'id' => (int) $folder->getId(),
388 'item_type' => 'F', 416 'item_type' => 'F',
389 417
@@ -420,9 +448,19 @@ class KTAPI_Folder extends KTAPI_FolderItem @@ -420,9 +448,19 @@ class KTAPI_Folder extends KTAPI_FolderItem
420 448
421 'storage_path' => 'n/a', 449 'storage_path' => 'n/a',
422 450
423 - 'items'=>$items,  
424 451
425 ); 452 );
  453 +
  454 + if($wsversion>=3){
  455 + $array['linked_folder_id'] = $folder->getLinkedFolderId();
  456 + if($folder->isSymbolicLink()){
  457 + $array['item_type'] = "S";
  458 + }
  459 + }
  460 + $array['items']=$items;
  461 + if($wsversion<3 || (strpos($what,'F') !== false && !$folder->isSymbolicLink()) || ($folder->isSymbolicLink() && strpos($what,'S') !== false)){
  462 + $contents[] = $array;
  463 + }
426 } 464 }
427 else 465 else
428 { 466 {
@@ -450,9 +488,8 @@ class KTAPI_Folder extends KTAPI_FolderItem @@ -450,9 +488,8 @@ class KTAPI_Folder extends KTAPI_FolderItem
450 488
451 } 489 }
452 } 490 }
453 - }  
454 - if (strpos($what,'D') !== false)  
455 - { 491 +
  492 +
456 $document_children = Document::getList(array('folder_id = ? AND status_id = 1', $this->folderid)); 493 $document_children = Document::getList(array('folder_id = ? AND status_id = 1', $this->folderid));
457 494
458 // I hate that KT doesn't cache things nicely... 495 // I hate that KT doesn't cache things nicely...
@@ -517,7 +554,7 @@ class KTAPI_Folder extends KTAPI_FolderItem @@ -517,7 +554,7 @@ class KTAPI_Folder extends KTAPI_FolderItem
517 if (empty($oemDocumentNo)) $oemDocumentNo = 'n/a'; 554 if (empty($oemDocumentNo)) $oemDocumentNo = 'n/a';
518 555
519 556
520 - $contents[] = array( 557 + $array = array(
521 'id' => (int) $document->getId(), 558 'id' => (int) $document->getId(),
522 'item_type' => 'D', 559 'item_type' => 'D',
523 560
@@ -553,10 +590,22 @@ class KTAPI_Folder extends KTAPI_FolderItem @@ -553,10 +590,22 @@ class KTAPI_Folder extends KTAPI_FolderItem
553 'mime_display' => $mime_cache[$mimetypeid]['display'], 590 'mime_display' => $mime_cache[$mimetypeid]['display'],
554 591
555 'storage_path' => $document->getStoragePath(), 592 'storage_path' => $document->getStoragePath(),
556 -  
557 - 'items'=>array(),  
558 -  
559 ); 593 );
  594 + if($wsversion>=3){
  595 + $document->switchToRealCore();
  596 + $array['linked_document_id'] = $document->getLinkedDocumentId();
  597 + $document->switchToLinkedCore();
  598 + if($document->isSymbolicLink()){
  599 + $array['item_type'] = "S";
  600 + }
  601 + }
  602 +
  603 + $array['items']=array();
  604 +
  605 +
  606 + if($wsversion<3 || (strpos($what,'D') !== false && !$document->isSymbolicLink()) || ($document->isSymbolicLink() && strpos($what,'S') !== false)){
  607 + $contents[] = $array;
  608 + }
560 } 609 }
561 else 610 else
562 { 611 {
@@ -586,12 +635,74 @@ class KTAPI_Folder extends KTAPI_FolderItem @@ -586,12 +635,74 @@ class KTAPI_Folder extends KTAPI_FolderItem
586 } 635 }
587 } 636 }
588 637
589 - } 638 +
590 639
591 return $contents; 640 return $contents;
592 } 641 }
593 642
594 /** 643 /**
  644 + * This adds a shortcut to an existing document to the current folder
  645 + *
  646 + * @param int $document_id The ID of the document to create a shortcut to
  647 + *
  648 + */
  649 + function &add_document_shortcut($document_id){
  650 + $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_WRITE);
  651 + if (PEAR::isError($user))
  652 + {
  653 + return $user;
  654 + }
  655 + $oDocument = Document::get($document_id);
  656 + if(PEAR::isError($oDocument)){
  657 + return $oDocument;
  658 + }
  659 +
  660 + $user = $this->can_user_access_object_requiring_permission($oDocument, KTAPI_PERMISSION_READ);
  661 + if (PEAR::isError($user))
  662 + {
  663 + return $user;
  664 + }
  665 + $document = KTDocumentUtil::createSymbolicLink($document_id,$this->folder,$user);
  666 + if (PEAR::isError($document))
  667 + {
  668 + return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR . ' : ' . $document->getMessage());
  669 + }
  670 +
  671 + return new KTAPI_Document($this->ktapi,$this,$document);
  672 + }
  673 +
  674 + /**
  675 + * This adds a shortcut pointing to an existing folder to the current folder
  676 + *
  677 + * @param int $folder_id The ID of the folder to create a shortcut to
  678 + *
  679 + */
  680 + function &add_folder_shortcut($folder_id){
  681 + $user = $this->can_user_access_object_requiring_permission($this->folder, KTAPI_PERMISSION_WRITE);
  682 + if (PEAR::isError($user))
  683 + {
  684 + return $user;
  685 + }
  686 + $oFolder = Folder::get($folder_id);
  687 + if(PEAR::isError($oFolder)){
  688 + return $oFolder;
  689 + }
  690 +
  691 + $user = $this->can_user_access_object_requiring_permission($oFolder, KTAPI_PERMISSION_READ);
  692 + if (PEAR::isError($user))
  693 + {
  694 + return $user;
  695 + }
  696 + $folder = & KTFolderUtil::createSymbolicLink($folder_id,$this->folder,$user);
  697 + if (PEAR::isError($folder))
  698 + {
  699 + return new PEAR_Error(KTAPI_ERROR_INTERNAL_ERROR . ' : ' . $folder->getMessage());
  700 + }
  701 +
  702 + return new KTAPI_Folder($this->ktapi,$folder);
  703 + }
  704 +
  705 + /**
595 * This adds a document to the current folder. 706 * This adds a document to the current folder.
596 * 707 *
597 * @access public 708 * @access public
ktwebservice/webservice.php
@@ -10,31 +10,31 @@ @@ -10,31 +10,31 @@
10 * Document Management Made Simple 10 * Document Management Made Simple
11 * Copyright (C) 2008 KnowledgeTree Inc. 11 * Copyright (C) 2008 KnowledgeTree Inc.
12 * Portions copyright The Jam Warehouse Software (Pty) Limited 12 * Portions copyright The Jam Warehouse Software (Pty) Limited
13 - * 13 + *
14 * This program is free software; you can redistribute it and/or modify it under 14 * This program is free software; you can redistribute it and/or modify it under
15 * the terms of the GNU General Public License version 3 as published by the 15 * the terms of the GNU General Public License version 3 as published by the
16 * Free Software Foundation. 16 * Free Software Foundation.
17 - * 17 + *
18 * This program is distributed in the hope that it will be useful, but WITHOUT 18 * This program is distributed in the hope that it will be useful, but WITHOUT
19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 20 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
21 * details. 21 * details.
22 - * 22 + *
23 * You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24 * along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 - *  
26 - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, 25 + *
  26 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
27 * California 94120-7775, or email info@knowledgetree.com. 27 * California 94120-7775, or email info@knowledgetree.com.
28 - * 28 + *
29 * The interactive user interfaces in modified source and object code versions 29 * The interactive user interfaces in modified source and object code versions
30 * of this program must display Appropriate Legal Notices, as required under 30 * of this program must display Appropriate Legal Notices, as required under
31 * Section 5 of the GNU General Public License version 3. 31 * Section 5 of the GNU General Public License version 3.
32 - * 32 + *
33 * In accordance with Section 7(b) of the GNU General Public License version 3, 33 * In accordance with Section 7(b) of the GNU General Public License version 3,
34 * these Appropriate Legal Notices must retain the display of the "Powered by 34 * these Appropriate Legal Notices must retain the display of the "Powered by
35 - * KnowledgeTree" logo and retain the original copyright notice. If the display of the 35 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
36 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices 36 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
37 - * must display the words "Powered by KnowledgeTree" and retain the original 37 + * must display the words "Powered by KnowledgeTree" and retain the original
38 * copyright notice. 38 * copyright notice.
39 * Contributor( s): ______________________________________ 39 * Contributor( s): ______________________________________
40 * 40 *
@@ -173,6 +173,9 @@ class KTWebService @@ -173,6 +173,9 @@ class KTWebService
173 { 173 {
174 $this->__typedef["{urn:$this->namespace}kt_folder_detail"]['created_by'] = 'string'; 174 $this->__typedef["{urn:$this->namespace}kt_folder_detail"]['created_by'] = 'string';
175 } 175 }
  176 + if($this->version >= 3){
  177 + $this->__typedef["{urn:$this->namespace}kt_folder_detail"]['linked_folder_id'] = 'int';
  178 + }
176 179
177 $this->__typedef["{urn:$this->namespace}kt_folder_item"] = 180 $this->__typedef["{urn:$this->namespace}kt_folder_item"] =
178 array( 181 array(
@@ -235,8 +238,14 @@ class KTWebService @@ -235,8 +238,14 @@ class KTWebService
235 238
236 'storage_path' => 'string', 239 'storage_path' => 'string',
237 240
238 - 'items' =>"{urn:$this->namespace}kt_folder_items" 241 +
239 ); 242 );
  243 +
  244 + if($this->version>=3){
  245 + $this->__typedef["{urn:$this->namespace}kt_folder_item"]['linked_folder_id'] = 'int';
  246 + }
  247 +
  248 + $this->__typedef["{urn:$this->namespace}kt_folder_item"]['items'] = "{urn:$this->namespace}kt_folder_items";
240 } 249 }
241 250
242 $this->__typedef["{urn:$this->namespace}kt_folder_items"] = 251 $this->__typedef["{urn:$this->namespace}kt_folder_items"] =
@@ -327,6 +336,10 @@ class KTWebService @@ -327,6 +336,10 @@ class KTWebService
327 'version_history' => "{urn:$this->namespace}kt_document_version_history", 336 'version_history' => "{urn:$this->namespace}kt_document_version_history",
328 'transaction_history' => "{urn:$this->namespace}kt_document_transaction_history", 337 'transaction_history' => "{urn:$this->namespace}kt_document_transaction_history",
329 ); 338 );
  339 +
  340 + if($this->version>=3){
  341 + $this->__typedef["{urn:$this->namespace}kt_document_detail"]['linked_document_id'] = 'int';
  342 + }
330 } 343 }
331 344
332 if (defined('HAS_SEARCH_FUNCTIONALITY')) 345 if (defined('HAS_SEARCH_FUNCTIONALITY'))
@@ -474,14 +487,14 @@ class KTWebService @@ -474,14 +487,14 @@ class KTWebService
474 'message'=>'string', 487 'message'=>'string',
475 'transitions' => "{urn:$this->namespace}kt_workflow_transitions" 488 'transitions' => "{urn:$this->namespace}kt_workflow_transitions"
476 ); 489 );
477 -  
478 - $this->__typedef["{urn:$this->namespace}kt_workflows_array"] = 490 +
  491 + $this->__typedef["{urn:$this->namespace}kt_workflows_array"] =
479 array( 492 array(
480 array( 493 array(
481 'workflow' => 'string' 494 'workflow' => 'string'
482 ) 495 )
483 ); 496 );
484 - 497 +
485 $this->__typedef["{urn:$this->namespace}kt_workflows_response"] = 498 $this->__typedef["{urn:$this->namespace}kt_workflows_response"] =
486 array( 499 array(
487 'status_code' => 'int', 500 'status_code' => 'int',
@@ -545,6 +558,62 @@ class KTWebService @@ -545,6 +558,62 @@ class KTWebService
545 'history' => "{urn:$this->namespace}kt_document_transaction_history_item" 558 'history' => "{urn:$this->namespace}kt_document_transaction_history_item"
546 ) 559 )
547 ); 560 );
  561 + if($this->version >= 3){
  562 + $this->__typedef["{urn:$this->namespace}kt_document_shortcut"] =
  563 + array(
  564 + 'id' => 'int',
  565 + 'full_path' => 'string',
  566 + 'folder_id' => 'int',
  567 + 'creator_id' => 'string',
  568 + 'created' => 'string',
  569 + 'owner_id'=>'string',
  570 + 'permission_object_id' => 'string',
  571 + 'permission_lookup_id' => 'string',
  572 + 'linked_document_id' => 'int',
  573 + );
  574 +
  575 + $this->__typedef["{urn:$this->namespace}kt_document_shortcuts"] =
  576 + array(
  577 + array(
  578 + 'shortcuts' => "{urn:$this->namespace}kt_document_shortcut"
  579 + )
  580 + );
  581 +
  582 + $this->__typedef["{urn:$this->namespace}kt_document_shortcut_response"] =
  583 + array(
  584 + 'status_code'=>'int',
  585 + 'message'=>'string',
  586 + 'shortcuts' => "{urn:$this->namespace}kt_document_shortcuts"
  587 + );
  588 +
  589 + $this->__typedef["{urn:$this->namespace}kt_folder_shortcut"] =
  590 + array(
  591 + 'id' => 'int',
  592 + 'name' => 'string',
  593 + 'parent_id' => 'string',
  594 + 'full_path' => 'string',
  595 + 'folder_id' => 'int',
  596 + 'creator_id' => 'string',
  597 + 'created' => 'string',
  598 + 'permission_object_id' => 'string',
  599 + 'permission_lookup_id' => 'string',
  600 + 'linked_folder_id' => 'int',
  601 + );
  602 +
  603 + $this->__typedef["{urn:$this->namespace}kt_folder_shortcuts"] =
  604 + array(
  605 + array(
  606 + 'shortcuts' => "{urn:$this->namespace}kt_folder_shortcut"
  607 + )
  608 + );
  609 +
  610 + $this->__typedef["{urn:$this->namespace}kt_folder_shortcut_response"] =
  611 + array(
  612 + 'status_code'=>'int',
  613 + 'message'=>'string',
  614 + 'shortcuts' => "{urn:$this->namespace}kt_folder_shortcuts"
  615 + );
  616 + }
548 617
549 $this->__typedef["{urn:$this->namespace}kt_document_transaction_history_response"] = 618 $this->__typedef["{urn:$this->namespace}kt_document_transaction_history_response"] =
550 array( 619 array(
@@ -821,6 +890,25 @@ class KTWebService @@ -821,6 +890,25 @@ class KTWebService
821 ); 890 );
822 } 891 }
823 892
  893 +
  894 + if($this->version >= 3){
  895 + //add folder shortcut
  896 + $this->__dispatch_map['create_folder_shortcut'] = array('in'=>array('session_id'=>'string','target_folder_id'=>'int','source_folder_id'=>'int'),
  897 + 'out'=>array('return' => "{urn:$this->namespace}kt_folder_detail" ));
  898 +
  899 + //add document shortcut
  900 + $this->__dispatch_map['create_document_shortcut'] = array('in'=>array('session_id'=>'string','target_folder_id'=>'int','source_document_id'=>'int'),
  901 + 'out'=>array('return' => "{urn:$this->namespace}kt_document_detail" ));
  902 +
  903 + //get document shortcuts
  904 + $this->__dispatch_map['get_document_shortcuts'] = array('in'=>array('session_id'=>'string','document_id'=>'int'),
  905 + 'out'=>array('return' => "{urn:$this->namespace}kt_document_shortcuts" ));
  906 +
  907 + //get folder shortcuts
  908 + $this->__dispatch_map['get_folder_shortcuts'] = array('in'=>array('session_id'=>'string','folder_id'=>'int'),
  909 + 'out'=>array('return' => "{urn:$this->namespace}kt_folder_shortcuts" ));
  910 + }
  911 +
824 // add_document 912 // add_document
825 $this->__dispatch_map['add_document'] = 913 $this->__dispatch_map['add_document'] =
826 array('in' => array('session_id'=>'string','folder_id'=>'int','title'=>'string','filename'=>'string','documentype' =>'string','tempfilename' =>'string' ), 914 array('in' => array('session_id'=>'string','folder_id'=>'int','title'=>'string','filename'=>'string','documentype' =>'string','tempfilename' =>'string' ),
@@ -1123,8 +1211,8 @@ class KTWebService @@ -1123,8 +1211,8 @@ class KTWebService
1123 array('in' => array('session_id'=>'string' ), 1211 array('in' => array('session_id'=>'string' ),
1124 'out' => array( 'return' => "{urn:$this->namespace}kt_document_types_response" ), 1212 'out' => array( 'return' => "{urn:$this->namespace}kt_document_types_response" ),
1125 ); 1213 );
1126 -  
1127 - // get_workflows 1214 +
  1215 + // get_workflows
1128 $this->__dispatch_map['get_workflows'] = 1216 $this->__dispatch_map['get_workflows'] =
1129 array('in' => array('session_id'=>'string' ), 1217 array('in' => array('session_id'=>'string' ),
1130 'out' => array( 'return' => "{urn:$this->namespace}kt_workflows_response" ), 1218 'out' => array( 'return' => "{urn:$this->namespace}kt_workflows_response" ),
@@ -1333,6 +1421,66 @@ class KTWebService @@ -1333,6 +1421,66 @@ class KTWebService
1333 return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $detail); 1421 return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $detail);
1334 } 1422 }
1335 1423
  1424 + /** Encode an array as kt_folder_shortcut
  1425 + *
  1426 + * @param array $shortcuts
  1427 + * @param string $name
  1428 + * @return SOAP_Value of kt_folder_shortcuts
  1429 + * @access private
  1430 + * @static
  1431 + */
  1432 + function _encode_folder_shortcuts($shortcuts, $name='shortcuts')
  1433 + {
  1434 + foreach($shortcuts as $key=>$item)
  1435 + {
  1436 + $shortcuts[$key] = new SOAP_Value('item',"{urn:$this->namespace}kt_folder_shortcut", $item);
  1437 + }
  1438 + return new SOAP_Value($name,"{urn:$this->namespace}kt_folder_shortcuts", $shortcuts);
  1439 + }
  1440 +
  1441 + /**
  1442 + * Retrieves all shortcuts linking to a specific document
  1443 + *
  1444 + * @param string $session_id
  1445 + * @param ing $document_id
  1446 + *
  1447 + * @return kt_document_shortcuts. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_DOCUMENT or KTWS_SUCCESS
  1448 + *
  1449 + */
  1450 + function get_folder_shortcuts($session_id, $folder_id){
  1451 + $kt = &$this->get_ktapi($session_id );
  1452 + if (is_array($kt))
  1453 + {
  1454 + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_shortcuts", $kt);
  1455 + }
  1456 +
  1457 + $folder = $kt->get_folder_by_id($folder_id);
  1458 + if(PEAR::isError($document)){
  1459 + $response=array(
  1460 + 'status_code'=>KTWS_ERR_INVALID_FOLDER,
  1461 + 'message'=>$folder->getMessage()
  1462 + );
  1463 + $this->debug("get_folder_shortcuts - cannot get folder - " . $folder->getMessage(), $session_id);
  1464 +
  1465 + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_shortcuts", $response);
  1466 + }
  1467 +
  1468 + $shortcuts = $folder->get_shortcuts();
  1469 + if(PEAR::isError($shortcuts)){
  1470 + $response = KTWebService::_status(KTWS_ERR_INVALID_FOLDER,$shortcuts);
  1471 + $this->debug("get_folder_shortcuts - cannot retrieve shortcuts linking to $folder_id - " . $shortcuts->getMessage(), $session_id);
  1472 +
  1473 + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_shortcuts", $response);
  1474 + }
  1475 +
  1476 + $response['status_code'] = KTWS_SUCCESS;
  1477 + $response['history'] = KTWebService::_encode_folder_shortcuts($shortcuts);
  1478 +
  1479 + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_shortcuts", $response);
  1480 +
  1481 + }
  1482 +
  1483 +
1336 /** 1484 /**
1337 * Returns folder detail given a folder name which could include a full path. 1485 * Returns folder detail given a folder name which could include a full path.
1338 * 1486 *
@@ -1394,7 +1542,7 @@ class KTWebService @@ -1394,7 +1542,7 @@ class KTWebService
1394 * @param string $what 1542 * @param string $what
1395 * @return kt_folder_contents 1543 * @return kt_folder_contents
1396 */ 1544 */
1397 - function get_folder_contents($session_id, $folder_id, $depth=1, $what='DF') 1545 + function get_folder_contents($session_id, $folder_id, $depth=1, $what='DFS')
1398 { 1546 {
1399 $this->debug("get_folder_contents('$session_id',$folder_id,$depth,'$what')"); 1547 $this->debug("get_folder_contents('$session_id',$folder_id,$depth,'$what')");
1400 $kt = &$this->get_ktapi($session_id); 1548 $kt = &$this->get_ktapi($session_id);
@@ -1471,6 +1619,113 @@ class KTWebService @@ -1471,6 +1619,113 @@ class KTWebService
1471 } 1619 }
1472 1620
1473 /** 1621 /**
  1622 + * Creates a shortcut to an existing folder
  1623 + *
  1624 + * @param string $session_id
  1625 + * @param int $target_folder_id Folder to place the shortcut in
  1626 + * @param int $source_folder_id Folder to create the shortcut to
  1627 + * @return kt_folder_detail. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_FOLDER or KTWS_SUCCESS
  1628 + */
  1629 + function create_folder_shortcut($session_id, $target_folder_id, $source_folder_id){
  1630 + $this->debug("create_folder_shortcut('$session_id',$target_folder_id,' $source_folder_id')");
  1631 +
  1632 + $kt = &$this->get_ktapi($session_id );
  1633 + if (is_array($kt))
  1634 + {
  1635 + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $kt);
  1636 + }
  1637 +
  1638 + $folder = &$kt->get_folder_by_id($target_folder_id);
  1639 + if (PEAR::isError($folder))
  1640 + {
  1641 + $response = KTWebService::_status(KTWS_ERR_INVALID_FOLDER,$folder);
  1642 +
  1643 + $this->debug("create_folder_shortcut - cannot get folderid $target_folder_id - " . $folder->getMessage(), $session_id);
  1644 +
  1645 + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $response);
  1646 + }
  1647 +
  1648 + $source_folder = &$kt->get_folder_by_id($source_folder_id);
  1649 + if (PEAR::isError($source_folder))
  1650 + {
  1651 + $response = KTWebService::_status(KTWS_ERR_INVALID_FOLDER,$source_folder);
  1652 +
  1653 + $this->debug("create_folder_shortcut - cannot get folderid $source_folder_id - " . $source_folder->getMessage(), $session_id);
  1654 +
  1655 + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $response);
  1656 + }
  1657 +
  1658 + $shortcut = &$folder->add_folder_shortcut($source_folder_id);
  1659 + if (PEAR::isError($shortcut))
  1660 + {
  1661 + $response = KTWebService::_status(KTWS_ERR_INVALID_FOLDER,$shortcut);
  1662 + $this->debug("create_folder_shortcut - cannot create shortcut to $source_folder_id - " . $shortcut->getMessage(), $session_id);
  1663 +
  1664 + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $response);
  1665 + }
  1666 +
  1667 + $detail = $shortcut->get_detail();
  1668 + $detail['status_code']=KTWS_SUCCESS;
  1669 + $detail['message']='';
  1670 +
  1671 + return new SOAP_Value('return',"{urn:$this->namespace}kt_folder_detail", $detail);
  1672 + }
  1673 +
  1674 + /**
  1675 + * Creates a shortcut to an existing document
  1676 + *
  1677 + * @param string $session_id
  1678 + * @param int $target_folder_id Folder to place the shortcut in
  1679 + * @param int $source_document_id Document to create the shortcut to
  1680 + * @return kt_document_detail. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_FOLDER,KTWS_ERR_INVALID_DOCUMENT or KTWS_SUCCESS
  1681 + */
  1682 + function create_document_shortcut($session_id, $target_folder_id, $source_document_id){
  1683 + $this->debug("create_document_shortcut('$session_id',$target_folder_id,'$source_document_id')");
  1684 +
  1685 + $kt = &$this->get_ktapi($session_id );
  1686 + if (is_array($kt))
  1687 + {
  1688 + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_detail", $kt);
  1689 + }
  1690 +
  1691 + $folder = &$kt->get_folder_by_id($target_folder_id);
  1692 + if (PEAR::isError($folder))
  1693 + {
  1694 + $response = KTWebService::_status(KTWS_ERR_INVALID_FOLDER,$folder);
  1695 +
  1696 + $this->debug("create_document_shortcut - cannot get folderid $target_folder_id - " . $folder->getMessage(), $session_id);
  1697 +
  1698 + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_detail", $response);
  1699 + }
  1700 +
  1701 + $source_document = &$kt->get_document_by_id($source_document_id);
  1702 + if (PEAR::isError($source_folder))
  1703 + {
  1704 + $response = KTWebService::_status(KTWS_ERR_INVALID_DOCUMENT,$source_document);
  1705 +
  1706 + $this->debug("create_document_shortcut - cannot get docid $source_document_id - " . $source_document->getMessage(), $session_id);
  1707 +
  1708 + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_detail", $response);
  1709 + }
  1710 +
  1711 + $shortcut = &$folder->add_document_shortcut($source_document_id);
  1712 + if (PEAR::isError($shortcut))
  1713 + {
  1714 + $response = KTWebService::_status(KTWS_ERR_INVALID_DOCUMENT,$shortcut);
  1715 + $this->debug("create_document_shortcut - cannot create shortcut to $source_document_id - " . $shortcut->getMessage(), $session_id);
  1716 +
  1717 + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_detail", $response);
  1718 + }
  1719 +
  1720 +
  1721 + $detail = $shortcut->get_detail();
  1722 + $detail['status_code']=KTWS_SUCCESS;
  1723 + $detail['message']='';
  1724 +
  1725 + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_detail", $detail);
  1726 + }
  1727 +
  1728 + /**
1474 * Deletes a folder. 1729 * Deletes a folder.
1475 * 1730 *
1476 * @param string $session_id 1731 * @param string $session_id
@@ -1928,6 +2183,65 @@ class KTWebService @@ -1928,6 +2183,65 @@ class KTWebService
1928 return $this->get_document_detail($session_id, $document->documentid, $detail); 2183 return $this->get_document_detail($session_id, $document->documentid, $detail);
1929 } 2184 }
1930 2185
  2186 + /** Encode an array as kt_document_shortcut
  2187 + *
  2188 + * @param array $shortcuts
  2189 + * @param string $name
  2190 + * @return SOAP_Value of kt_document_shortcuts
  2191 + * @access private
  2192 + * @static
  2193 + */
  2194 + function _encode_document_shortcuts($shortcuts, $name='shortcuts')
  2195 + {
  2196 + foreach($shortcuts as $key=>$item)
  2197 + {
  2198 + $shortcuts[$key] = new SOAP_Value('item',"{urn:$this->namespace}kt_document_shortcut", $item);
  2199 + }
  2200 + return new SOAP_Value($name,"{urn:$this->namespace}kt_document_shortcuts", $shortcuts);
  2201 + }
  2202 +
  2203 + /**
  2204 + * Retrieves all shortcuts linking to a specific document
  2205 + *
  2206 + * @param string $session_id
  2207 + * @param ing $document_id
  2208 + *
  2209 + * @return kt_document_shortcuts. status_code can be KTWS_ERR_INVALID_SESSION, KTWS_ERR_INVALID_DOCUMENT or KTWS_SUCCESS
  2210 + *
  2211 + */
  2212 + function get_document_shortcuts($session_id, $document_id){
  2213 + $kt = &$this->get_ktapi($session_id );
  2214 + if (is_array($kt))
  2215 + {
  2216 + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_shortcuts", $kt);
  2217 + }
  2218 +
  2219 + $document = $kt->get_document_by_id($document_id);
  2220 + if(PEAR::isError($document)){
  2221 + $response=array(
  2222 + 'status_code'=>KTWS_ERR_INVALID_DOCUMENT,
  2223 + 'message'=>$document->getMessage()
  2224 + );
  2225 + $this->debug("get_document_shortcuts - cannot get document - " . $document->getMessage(), $session_id);
  2226 +
  2227 + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_shortcuts", $response);
  2228 + }
  2229 +
  2230 + $shortcuts = $document->get_shortcuts();
  2231 + if(PEAR::isError($shortcuts)){
  2232 + $response = KTWebService::_status(KTWS_ERR_INVALID_DOCUMENT,$shortcuts);
  2233 + $this->debug("get_document_shortcuts - cannot retrieve shortcuts linking to $document_id - " . $shortcuts->getMessage(), $session_id);
  2234 +
  2235 + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_shortcuts", $response);
  2236 + }
  2237 +
  2238 + $response['status_code'] = KTWS_SUCCESS;
  2239 + $response['history'] = KTWebService::_encode_document_shortcuts($shortcuts);
  2240 +
  2241 + return new SOAP_Value('return',"{urn:$this->namespace}kt_document_shortcuts", $response);
  2242 +
  2243 + }
  2244 +
1931 /** 2245 /**
1932 * Adds a document to the repository. 2246 * Adds a document to the repository.
1933 * 2247 *
@@ -3460,7 +3774,7 @@ class KTWebService @@ -3460,7 +3774,7 @@ class KTWebService
3460 3774
3461 return new SOAP_Value('return',"{urn:$this->namespace}$responseType", $response); 3775 return new SOAP_Value('return',"{urn:$this->namespace}$responseType", $response);
3462 } 3776 }
3463 - 3777 +
3464 /** 3778 /**
3465 * Returns a list of available workflows 3779 * Returns a list of available workflows
3466 * 3780 *
@@ -3475,9 +3789,9 @@ class KTWebService @@ -3475,9 +3789,9 @@ class KTWebService
3475 { 3789 {
3476 return new SOAP_Value('return',"{urn:$this->namespace}kt_workflows_response", $kt); 3790 return new SOAP_Value('return',"{urn:$this->namespace}kt_workflows_response", $kt);
3477 } 3791 }
3478 - 3792 +
3479 $response = KTWebService::_status(KTWS_ERR_PROBLEM); 3793 $response = KTWebService::_status(KTWS_ERR_PROBLEM);
3480 - 3794 +
3481 $result = $kt->get_workflows(); 3795 $result = $kt->get_workflows();
3482 if (PEAR::isError($result)) 3796 if (PEAR::isError($result))
3483 { 3797 {
@@ -4134,4 +4448,4 @@ class KTWebService @@ -4134,4 +4448,4 @@ class KTWebService
4134 $webservice = new KTWebService(); 4448 $webservice = new KTWebService();
4135 $webservice->run(); 4449 $webservice->run();
4136 4450
4137 -?> 4451 -?>
  4452 +?>
4138 \ No newline at end of file 4453 \ No newline at end of file
lib/actions/bulkaction.php
@@ -151,7 +151,13 @@ class KTBulkAction extends KTStandardDispatcher { @@ -151,7 +151,13 @@ class KTBulkAction extends KTStandardDispatcher {
151 151
152 foreach($aIds as $id) { 152 foreach($aIds as $id) {
153 $oE =& call_user_func($aFunc, $id); 153 $oE =& call_user_func($aFunc, $id);
154 - $aNames[] = $oE->getName(); 154 + $name = array();
  155 + $name['name'] = $oE->getName();
  156 + //add shortcut notice if the entity is a shortcut
  157 + if($oE->isSymbolicLink()){
  158 + $name['notice'] = _kt("Shortcut");
  159 + }
  160 + $aNames[] = $name;
155 } 161 }
156 return $aNames; 162 return $aNames;
157 } else { 163 } else {
@@ -159,7 +165,52 @@ class KTBulkAction extends KTStandardDispatcher { @@ -159,7 +165,52 @@ class KTBulkAction extends KTStandardDispatcher {
159 } 165 }
160 } 166 }
161 167
162 - 168 + /**
  169 + * Checks if there are symlinks that are linking to items in the current list
  170 + * Useful if you want to prompt the user with a confirmation because they're
  171 + * automatically deleted when their targets are deleted or archived.
  172 + *
  173 + * @return boolean
  174 + */
  175 + function symlinksLinkingToCurrentList(){
  176 + $symlinksPresent = false;
  177 + foreach($this->oActiveEntityList->getDocumentIds() as $iDocument){
  178 + $oDocument = Document::get($iDocument);
  179 + if(count($oDocument->getSymbolicLinks()) > 0){
  180 + $symlinksPresent = true;
  181 + break;
  182 + }
  183 + }
  184 + if($symlinksPresent == false){
  185 + foreach($this->oActiveEntityList->getFolderIds() as $iFolder){
  186 + $oStartFolder = Folder::get($iFolder);
  187 + $aRemainingFolders = array($oStartFolder->getId());
  188 + while (!empty($aRemainingFolders)) {
  189 + $iFolderId = array_pop($aRemainingFolders);
  190 + $oFolder = Folder::get($iFolderId);
  191 +
  192 + if(count($oFolder->getSymbolicLinks()) > 0){
  193 + $symlinksPresent = true;
  194 + break;
  195 + }
  196 +
  197 + $aChildDocs = Document::getList(array('folder_id = ?',array($iFolderId)));
  198 + foreach ($aChildDocs as $oDoc) {
  199 + if(count($oDoc->getSymbolicLinks()) > 0){
  200 + $symlinksPresent = true;
  201 + break;
  202 + }
  203 + }
  204 +
  205 + $aCFIds = Folder::getList(array('parent_id = ?', array($iFolderId)), array('ids' => true));
  206 + $aRemainingFolders = kt_array_merge($aRemainingFolders, $aCFIds);
  207 + }
  208 + }
  209 + }
  210 + return $symlinksPresent;
  211 + }
  212 +
  213 +
163 // doesn't actually do checks, as they have to be performed per-entity 214 // doesn't actually do checks, as they have to be performed per-entity
164 function check() { 215 function check() {
165 // not necessarily coming from a folder... 216 // not necessarily coming from a folder...
@@ -249,11 +300,17 @@ class KTBulkAction extends KTStandardDispatcher { @@ -249,11 +300,17 @@ class KTBulkAction extends KTStandardDispatcher {
249 } 300 }
250 301
251 $res = $this->perform_action($oDocument); 302 $res = $this->perform_action($oDocument);
252 - 303 +
  304 + //check for shortcut notice
  305 + $notice = null;
  306 + if($oDocument->isSymbolicLink()){
  307 + $notice = _kt("Shortcut");
  308 + }
  309 +
253 if(PEAR::isError($res)) { 310 if(PEAR::isError($res)) {
254 - $this->aActionResults['documents'][] = array($sName, $res->getMessage()); 311 + $this->aActionResults['documents'][] = array($sName, $res->getMessage(), $notice);
255 } else { 312 } else {
256 - $this->aActionResults['documents'][] = array($sName, _kt('Success')); 313 + $this->aActionResults['documents'][] = array($sName, _kt('Success'), $notice);
257 } 314 }
258 } 315 }
259 316
@@ -267,10 +324,16 @@ class KTBulkAction extends KTStandardDispatcher { @@ -267,10 +324,16 @@ class KTBulkAction extends KTStandardDispatcher {
267 324
268 $res = $this->perform_action($oFolder); 325 $res = $this->perform_action($oFolder);
269 326
  327 + //check for shortcut notice
  328 + $notice = null;
  329 + if($oFolder->isSymbolicLink()){
  330 + $notice = _kt("Shortcut");
  331 + }
  332 +
270 if(PEAR::isError($res)) { 333 if(PEAR::isError($res)) {
271 - $this->aActionResults['folders'][] = array($sName, $res->getMessage()); 334 + $this->aActionResults['folders'][] = array($sName, $res->getMessage(), $notice);
272 } else { 335 } else {
273 - $this->aActionResults['folders'][] = array($sName, _kt('Success')); 336 + $this->aActionResults['folders'][] = array($sName, _kt('Success'), $notice);
274 } 337 }
275 } 338 }
276 } 339 }
lib/alert/EmailTemplate.inc.php 0 → 100755
  1 +<?php
  2 +
  3 +require_once(KT_LIB_DIR . "/templating/templating.inc.php");
  4 +
  5 +/**
  6 + * Represents an email template
  7 + *
  8 + */
  9 +class EmailTemplate{
  10 + /** template */
  11 + var $sTemplate;
  12 + /** template data */
  13 + var $aTemplateData;
  14 +
  15 + function EmailTemplate($sTemplate, $aTemplateData = array()){
  16 + $this->sTemplate = $sTemplate;
  17 + $this->aTemplateData = $aTemplateData;
  18 + }
  19 +
  20 + function getTemplate(){
  21 + return $this->sTemplate;
  22 + }
  23 +
  24 + function setTemplate($sTemplate){
  25 + $this->sTemplate = $sTemplate;
  26 + }
  27 +
  28 + function getTemplateData(){
  29 + return $this->aTemplateData;
  30 + }
  31 +
  32 + function setTemplateData($aTemplateData){
  33 + $this->aTemplateData = $aTemplateData;
  34 + }
  35 +
  36 + /**
  37 + * Renders template to a valid email body.
  38 + *
  39 + * @return HTML email body
  40 + */
  41 + function getBody(){
  42 + $oTemplating =& KTTemplating::getSingleton();
  43 + $oTemplate = $oTemplating->loadTemplate($this->sTemplate);
  44 + return "<html><body>".$oTemplate->render($this->aTemplateData)."</body></html>";
  45 + }
  46 +
  47 +}
  48 +
  49 +
  50 +
  51 +
  52 +
  53 +
  54 +
  55 +
  56 +
  57 +
  58 +?>
0 \ No newline at end of file 59 \ No newline at end of file
lib/alert/delivery/EmailAlert.inc
@@ -67,6 +67,10 @@ class EmailAlert { @@ -67,6 +67,10 @@ class EmailAlert {
67 function send() { 67 function send() {
68 global $default; 68 global $default;
69 69
  70 + $content = file_get_contents("maillog.txt");
  71 + file_put_contents("maillog.txt",$content."\n\n============ Mail Log ===============\nEmail:".$this->sAddress."\n".
  72 + "sSubject:".$this->sSubject."\nBody:".$this->sContent."\n");
  73 +
70 if ($this->oEmail->send($this->sAddress, $this->sSubject, $this->sContent)) { 74 if ($this->oEmail->send($this->sAddress, $this->sSubject, $this->sContent)) {
71 $default->log->debug("EmailAlert::EmailAlert successfully sent email to $this->sAddress"); 75 $default->log->debug("EmailAlert::EmailAlert successfully sent email to $this->sAddress");
72 return true; 76 return true;
lib/browse/PartialQuery.inc.php
@@ -94,14 +94,16 @@ class BrowseQuery extends PartialQuery{ @@ -94,14 +94,16 @@ class BrowseQuery extends PartialQuery{
94 // FIXME cache permission lookups, etc. 94 // FIXME cache permission lookups, etc.
95 var $folder_id = -1; 95 var $folder_id = -1;
96 var $exclude_folders=array(); 96 var $exclude_folders=array();
  97 + var $exclude_shortcuts = false;
97 98
98 - function BrowseQuery($iFolderId, $oUser = null, $aOptions = null) { 99 + function BrowseQuery($iFolderId, $oUser = null, $aOptions = null, $excludeShortcuts = false) {
99 $this->folder_id = $iFolderId; 100 $this->folder_id = $iFolderId;
100 if (is_null($oUser)) { 101 if (is_null($oUser)) {
101 $oUser = User::get($_SESSION['userID']); 102 $oUser = User::get($_SESSION['userID']);
102 } 103 }
103 $this->oUser =& $oUser; 104 $this->oUser =& $oUser;
104 $this->aOptions = $aOptions; 105 $this->aOptions = $aOptions;
  106 + $this->exclude_shortcuts = $excludeShortcuts;
105 if (KTUtil::arrayGet($aOptions, 'ignorepermissions')) { 107 if (KTUtil::arrayGet($aOptions, 'ignorepermissions')) {
106 $this->oUser = null; 108 $this->oUser = null;
107 } 109 }
@@ -116,6 +118,10 @@ class BrowseQuery extends PartialQuery{ @@ -116,6 +118,10 @@ class BrowseQuery extends PartialQuery{
116 list($sPermissionString, $aPermissionParams, $sPermissionJoin) = $res; 118 list($sPermissionString, $aPermissionParams, $sPermissionJoin) = $res;
117 $aPotentialWhere = array($sPermissionString, 'D.folder_id = ?', 'D.status_id = 1'); 119 $aPotentialWhere = array($sPermissionString, 'D.folder_id = ?', 'D.status_id = 1');
118 $aWhere = array(); 120 $aWhere = array();
  121 + //check if symlinks should be excluded
  122 + if($this->exclude_shortcuts == true){
  123 + $aWhere[] = "linked_document_id IS NULL";
  124 + }
119 foreach ($aPotentialWhere as $sWhere) { 125 foreach ($aPotentialWhere as $sWhere) {
120 if (empty($sWhere)) { 126 if (empty($sWhere)) {
121 continue; 127 continue;
@@ -157,6 +163,10 @@ class BrowseQuery extends PartialQuery{ @@ -157,6 +163,10 @@ class BrowseQuery extends PartialQuery{
157 163
158 $aPotentialWhere = array($sPermissionString, 'F.parent_id = ?'); 164 $aPotentialWhere = array($sPermissionString, 'F.parent_id = ?');
159 $aWhere = array(); 165 $aWhere = array();
  166 + //check if symlinks should be excluded
  167 + if($this->exclude_shortcuts == true){
  168 + $aWhere[] = "linked_folder_id IS NULL";
  169 + }
160 foreach ($aPotentialWhere as $sWhere) { 170 foreach ($aPotentialWhere as $sWhere) {
161 if (empty($sWhere)) { 171 if (empty($sWhere)) {
162 continue; 172 continue;
lib/browse/browseutil.inc.php
@@ -261,13 +261,15 @@ class KTBrowseUtil { @@ -261,13 +261,15 @@ class KTBrowseUtil {
261 // }}} 261 // }}}
262 262
263 // {{{ breadcrumbsForDocument 263 // {{{ breadcrumbsForDocument
264 - function breadcrumbsForDocument($oDocument, $aOptions = null) { 264 + function breadcrumbsForDocument($oDocument, $aOptions = null, $iFolderId = null) {
265 $bFinal = KTUtil::arrayGet($aOptions, 'final', true, false); 265 $bFinal = KTUtil::arrayGet($aOptions, 'final', true, false);
266 $aOptions = KTUtil::meldOptions($aOptions, array( 266 $aOptions = KTUtil::meldOptions($aOptions, array(
267 'final' => false, 267 'final' => false,
268 )); 268 ));
269 269
270 - $iFolderId = $oDocument->getFolderId(); 270 + if($iFolderId == null){
  271 + $iFolderId = $oDocument->getFolderId();
  272 + }
271 $aBreadcrumbs = KTBrowseUtil::breadcrumbsForFolder($iFolderId, $aOptions); 273 $aBreadcrumbs = KTBrowseUtil::breadcrumbsForFolder($iFolderId, $aOptions);
272 274
273 275
lib/documentmanagement/Document.inc
@@ -110,6 +110,8 @@ class Document { @@ -110,6 +110,8 @@ class Document {
110 110
111 function getOemNo() { return $this->_oDocumentCore->getOemNo(); } 111 function getOemNo() { return $this->_oDocumentCore->getOemNo(); }
112 112
  113 + function getLinkedDocumentId(){ return $this->_oDocumentCore->getLinkedDocumentId();}
  114 + function setLinkedDocumentId($iNewValue){ $this->_oDocumentCore->setLinkedDocumentId($iNewValue);}
113 115
114 // Document Metadata Items 116 // Document Metadata Items
115 117
@@ -167,7 +169,81 @@ class Document { @@ -167,7 +169,81 @@ class Document {
167 169
168 function getStoragePath() { return $this->_oDocumentContentVersion->getStoragePath(); } 170 function getStoragePath() { return $this->_oDocumentContentVersion->getStoragePath(); }
169 function setStoragePath($sNewValue) { $this->_oDocumentContentVersion->setStoragePath($sNewValue); } 171 function setStoragePath($sNewValue) { $this->_oDocumentContentVersion->setStoragePath($sNewValue); }
  172 +
170 173
  174 +
  175 + /**
  176 + * Returns the symlink document instance
  177 + *
  178 + * @return Document the real document
  179 + */
  180 + function getRealDocument()
  181 + {
  182 + return $this->_oDocumentCore->getRealDocument();
  183 + }
  184 +
  185 + /**
  186 + * Checks if this document is a symbolic link to an other doc.
  187 + *
  188 + * @return boolean
  189 + */
  190 + function isSymbolicLink()
  191 + {
  192 + $documentCore = KTDocumentCore::get($this->getId());
  193 + return $documentCore->isSymbolicLink();
  194 + }
  195 +
  196 + /**
  197 + * Switches the core of this document to the core of the real doc.
  198 + *
  199 + */
  200 + function switchToRealCore()
  201 + {
  202 + if ($this->isSymbolicLink())
  203 + {
  204 + $this->_oDocumentCore = KTDocumentCore::get($this->getId());
  205 + }
  206 + }
  207 +
  208 + /**
  209 + * Retrieves the ID of the real document
  210 + *
  211 + * @return int the ID
  212 + */
  213 + function getRealDocumentId()
  214 + {
  215 + $document = $this->getRealDocument();
  216 + if (PEAR::isError($document)) { return $document; }
  217 + return $document->getId();
  218 + }
  219 +
  220 + /**
  221 + * Switches this documents core to the core of the document this document is linking to.
  222 + *
  223 + */
  224 + function switchToLinkedCore()
  225 + {
  226 + if ($this->isSymbolicLink())
  227 + {
  228 + $document = $this->getRealDocument();
  229 + if (PEAR::isError($document)) { return $document; }
  230 + $this->_oDocumentCore = $document->_oDocumentCore;
  231 + //also load metadata
  232 + $this->_oDocumentMetadataVersion = $document->_oDocumentMetadataVersion;
  233 + }
  234 + }
  235 +
  236 + /**
  237 + * Retrieves all symbolic links linking to this document
  238 + *
  239 + */
  240 + function getSymbolicLinks(){
  241 + $sQuery = 'SELECT * FROM documents ' .
  242 + 'WHERE documents.linked_document_id = '.$this->getId();
  243 + return DButil::getResultArray($sQuery);
  244 + }
  245 +
  246 +
171 // }}} 247 // }}}
172 248
173 // {{{ getParentID 249 // {{{ getParentID
@@ -233,11 +309,18 @@ class Document { @@ -233,11 +309,18 @@ class Document {
233 // }}} 309 // }}}
234 310
235 // {{{ load 311 // {{{ load
236 - function load($iId, $iMetadataVersionId = null) { 312 + function load($iId, $iMetadataVersionId = null) {
237 $this->iId = $iId; 313 $this->iId = $iId;
238 $this->_oDocumentCore = KTDocumentCore::get($iId); 314 $this->_oDocumentCore = KTDocumentCore::get($iId);
239 if (PEAR::isError($this->_oDocumentCore)) { return $this->_oDocumentCore; } 315 if (PEAR::isError($this->_oDocumentCore)) { return $this->_oDocumentCore; }
240 316
  317 + //Automatically load the information of the document this document links to, if any.
  318 + $res = $this->switchToLinkedCore();
  319 + if (PEAR::isError($res))
  320 + {
  321 + return $res;
  322 + }
  323 +
241 // FIXME add error $res if MDV > $_oDC->getMDV 324 // FIXME add error $res if MDV > $_oDC->getMDV
242 if (is_null($iMetadataVersionId)) { 325 if (is_null($iMetadataVersionId)) {
243 $this->_oDocumentMetadataVersion = KTDocumentMetadataVersion::get($this->_oDocumentCore->getMetadataVersionId()); 326 $this->_oDocumentMetadataVersion = KTDocumentMetadataVersion::get($this->_oDocumentCore->getMetadataVersionId());
lib/documentmanagement/documentcore.inc.php
@@ -84,6 +84,9 @@ class KTDocumentCore extends KTEntity { @@ -84,6 +84,9 @@ class KTDocumentCore extends KTEntity {
84 var $dCheckedOut; 84 var $dCheckedOut;
85 85
86 var $sOemNo; 86 var $sOemNo;
  87 +
  88 + /** ID of the document this document links to(if any) */
  89 + var $iLinkedDocumentId;
87 90
88 var $_aFieldToSelect = array( 91 var $_aFieldToSelect = array(
89 "iId" => "id", 92 "iId" => "id",
@@ -118,7 +121,8 @@ class KTDocumentCore extends KTEntity { @@ -118,7 +121,8 @@ class KTDocumentCore extends KTEntity {
118 'sRestoreFolderPath' => 'restore_folder_path', 121 'sRestoreFolderPath' => 'restore_folder_path',
119 122
120 'dCheckedOut'=>'checkedout', 123 'dCheckedOut'=>'checkedout',
121 - 'sOemNo'=>'oem_no' 124 + 'sOemNo'=>'oem_no',
  125 + 'iLinkedDocumentId' => 'linked_document_id'
122 ); 126 );
123 127
124 function KTDocumentCore() { 128 function KTDocumentCore() {
@@ -173,6 +177,46 @@ class KTDocumentCore extends KTEntity { @@ -173,6 +177,46 @@ class KTDocumentCore extends KTEntity {
173 177
174 function getRestoreFolderPath() { return $this->sRestoreFolderPath; } 178 function getRestoreFolderPath() { return $this->sRestoreFolderPath; }
175 function setRestoreFolderPath($sValue) { $this->sRestoreFolderPath = $sValue; } 179 function setRestoreFolderPath($sValue) { $this->sRestoreFolderPath = $sValue; }
  180 +
  181 + function getLinkedDocumentId(){ return $this->iLinkedDocumentId;}
  182 + function setLinkedDocumentId($iNewValue){ $this->iLinkedDocumentId = $iNewValue;}
  183 +
  184 + /**
  185 + * Returns the ID of the real document.
  186 + *
  187 + * @return int the ID
  188 + */
  189 + function getRealDocumentId(){
  190 + $realDocument = $this->getRealDocument();
  191 + return $realDocument->getId();
  192 + }
  193 +
  194 + /**
  195 + * Retrieves the real document (which is a shortcut that links to the linked document)
  196 + *
  197 + */
  198 + function getRealDocument()
  199 + {
  200 + if (is_null($this->getLinkedDocumentId()))
  201 + {
  202 + return Document::get($this->getId());
  203 + }
  204 +
  205 + $document = Document::get($this->getLinkedDocumentId());
  206 + return $document->getRealDocument();
  207 + }
  208 +
  209 + /**
  210 + * Checks if this is a shortcut
  211 + *
  212 + * @return boolean
  213 + */
  214 + function isSymbolicLink()
  215 + {
  216 + return !is_null($this->getLinkedDocumentId());
  217 + }
  218 +
  219 +
176 // }}} 220 // }}}
177 221
178 // {{{ getParentId 222 // {{{ getParentId
@@ -291,7 +335,7 @@ class KTDocumentCore extends KTEntity { @@ -291,7 +335,7 @@ class KTDocumentCore extends KTEntity {
291 // {{{ update 335 // {{{ update
292 function update($bPathMove = false) { 336 function update($bPathMove = false) {
293 //var_dump($this); exit(0); 337 //var_dump($this); exit(0);
294 - $res = parent::update(); 338 + $res = parent::update();
295 339
296 if (($res === true) && ($bPathMove === true)) { 340 if (($res === true) && ($bPathMove === true)) {
297 KTPermissionUtil::updatePermissionLookup($this); 341 KTPermissionUtil::updatePermissionLookup($this);
lib/documentmanagement/documentutil.inc.php
@@ -55,6 +55,8 @@ require_once(KT_LIB_DIR . &#39;/metadata/fieldset.inc.php&#39;); @@ -55,6 +55,8 @@ require_once(KT_LIB_DIR . &#39;/metadata/fieldset.inc.php&#39;);
55 require_once(KT_LIB_DIR . '/subscriptions/subscriptions.inc.php'); 55 require_once(KT_LIB_DIR . '/subscriptions/subscriptions.inc.php');
56 require_once(KT_LIB_DIR . '/triggers/triggerregistry.inc.php'); 56 require_once(KT_LIB_DIR . '/triggers/triggerregistry.inc.php');
57 require_once(KT_LIB_DIR . '/foldermanagement/Folder.inc'); 57 require_once(KT_LIB_DIR . '/foldermanagement/Folder.inc');
  58 +require_once(KT_LIB_DIR . '/alert/EmailTemplate.inc.php');
  59 +require_once(KT_LIB_DIR . '/browse/browseutil.inc.php');
58 60
59 // WORKFLOW 61 // WORKFLOW
60 require_once(KT_LIB_DIR . '/workflow/workflowutil.inc.php'); 62 require_once(KT_LIB_DIR . '/workflow/workflowutil.inc.php');
@@ -167,6 +169,10 @@ class KTDocumentUtil { @@ -167,6 +169,10 @@ class KTDocumentUtil {
167 } 169 }
168 170
169 function checkout($oDocument, $sCheckoutComment, $oUser) { 171 function checkout($oDocument, $sCheckoutComment, $oUser) {
  172 + //automatically check out the linked document if this is a shortcut
  173 + if($oDocument->isSymbolicLink()){
  174 + $oDocument->switchToLinkedCore();
  175 + }
170 if ($oDocument->getIsCheckedOut()) { 176 if ($oDocument->getIsCheckedOut()) {
171 return PEAR::raiseError(_kt('Already checked out.')); 177 return PEAR::raiseError(_kt('Already checked out.'));
172 } 178 }
@@ -213,6 +219,24 @@ class KTDocumentUtil { @@ -213,6 +219,24 @@ class KTDocumentUtil {
213 return PEAR::raiseError(_kt('There was a database error while trying to archive this file')); 219 return PEAR::raiseError(_kt('There was a database error while trying to archive this file'));
214 } 220 }
215 221
  222 + //delete all shortcuts linking to this document
  223 + $aSymlinks = $oDocument->getSymbolicLinks();
  224 + foreach($aSymlinks as $aSymlink){
  225 + $oShortcutDocument = Document::get($aSymlink['id']);
  226 + $oOwnerUser = User::get($oShortcutDocument->getOwnerID());
  227 +
  228 + KTDocumentUtil::deleteSymbolicLink($aSymlink['id']);
  229 +
  230 + //send an email to the owner of the shortcut
  231 + if($oOwnerUser->getEmail()!=null && $oOwnerUser->getEmailNotification() == true){
  232 + $emailTemplate = new EmailTemplate("kt3/notifications/notification.SymbolicLinkDeleted",array('user_name'=>$this->oUser->getName(),
  233 + 'url'=>KTUtil::ktLink(KTBrowseUtil::getUrlForDocument($oShortcutDocument)),
  234 + 'title' =>$oShortcutDocument->getName()));
  235 + $email = new EmailAlert($oOwnerUser->getEmail(),_kt("KnowledgeTree Notification"),$emailTemplate->getBody());
  236 + $email->send();
  237 + }
  238 + }
  239 +
216 $oDocumentTransaction = & new DocumentTransaction($oDocument, sprintf(_kt('Document archived: %s'), $sReason), 'ktcore.transactions.update'); 240 $oDocumentTransaction = & new DocumentTransaction($oDocument, sprintf(_kt('Document archived: %s'), $sReason), 'ktcore.transactions.update');
217 $oDocumentTransaction->create(); 241 $oDocumentTransaction->create();
218 242
@@ -303,6 +327,130 @@ class KTDocumentUtil { @@ -303,6 +327,130 @@ class KTDocumentUtil {
303 return $oDocument; 327 return $oDocument;
304 } 328 }
305 329
  330 + /**
  331 + * Create a symbolic link in the target folder
  332 + *
  333 + * @param Document $sourceDocument the document to create a link to
  334 + * @param Folder $targetFolder the folder to place the link in
  335 + * @param User $user current user
  336 + */
  337 + static function createSymbolicLink($sourceDocument, $targetFolder, $user = null) // added/
  338 + {
  339 + //validate input
  340 + if (is_numeric($sourceDocument))
  341 + {
  342 + $sourceDocument = Document::get($sourceDocument);
  343 + }
  344 + if (!$sourceDocument instanceof Document)
  345 + {
  346 + return PEAR::raiseError(_kt('Source document not specified'));
  347 + }
  348 + if (is_numeric($targetFolder))
  349 + {
  350 + $targetFolder = Folder::get($targetFolder);
  351 + }
  352 + if (!$targetFolder instanceof Folder)
  353 + {
  354 + return PEAR::raiseError(_kt('Target folder not specified'));
  355 + }
  356 + if (is_null($user))
  357 + {
  358 + $user = $_SESSION['userID'];
  359 + }
  360 + if (is_numeric($user))
  361 + {
  362 + $user = User::get($user);
  363 + }
  364 +
  365 + //check for permissions
  366 + $oPermission =& KTPermission::getByName("ktcore.permissions.write");
  367 + $oReadPermission =& KTPermission::getByName("ktcore.permissions.read");
  368 + if (KTBrowseUtil::inAdminMode($user, $targetFolder)) {
  369 + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oPermission, $targetFolder)){
  370 + return PEAR::raiseError(_kt('You\'re not authorized to create shortcuts'));
  371 + }
  372 + }
  373 + if (!KTBrowseUtil::inAdminMode($user, $sourceDocument->getParentID())) {
  374 + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oReadPermission, $sourceDocument)){
  375 + return PEAR::raiseError(_kt('You\'re not authorized to create a shortcut to this document'));
  376 + }
  377 + }
  378 +
  379 + //check if the shortcut doesn't already exists in the target folder
  380 + $aSymlinks = $sourceDocument->getSymbolicLinks();
  381 + foreach($aSymlinks as $iSymlink){
  382 + $oSymlink = Document::get($iSymlink['id']);
  383 + $oSymlink->switchToRealCore();
  384 + if($oSymlink->getFolderID() == $targetFolder->getID()){
  385 + return PEAR::raiseError(_kt('There already is a shortcut to this document in the target folder.'));
  386 + }
  387 + }
  388 +
  389 + //create the actual shortcut
  390 + $oCore = KTDocumentCore::createFromArray(array(
  391 + 'iCreatorId'=>$user->getId(),
  392 + 'iFolderId'=>$targetFolder->getId(),
  393 + 'iLinkedDocumentId'=>$sourceDocument->getId(),
  394 + 'sFullPath'=> $targetFolder->getFullPath() . '/' .
  395 +$sourceDocument->getName(),
  396 + 'iPermissionObjectId'=>$targetFolder->getPermissionObjectID(),
  397 + 'iPermissionLookupId'=>$targetFolder->getPermissionLookupID(),
  398 + 'iStatusId'=>1,
  399 + 'iMetadataVersionId'=>$sourceDocument->getMetadataVersionId(),
  400 +
  401 + ));
  402 +
  403 + $document = Document::get($oCore->getId());
  404 +
  405 + return $document;
  406 + }
  407 +
  408 + /**
  409 + * Deletes a document symbolic link
  410 + *
  411 + * @param Document $document the symbolic link document
  412 + * @param User $user the user deleting the link
  413 + * @return unknown
  414 + */
  415 + static function deleteSymbolicLink($document, $user = null) // added/
  416 + {
  417 + //validate input
  418 + if (is_numeric($document))
  419 + {
  420 + $document = Document::get($document);
  421 + }
  422 + if (!$document instanceof Document)
  423 + {
  424 + return PEAR::raiseError(_kt('Document not specified'));
  425 + }
  426 + if (!$document->isSymbolicLink())
  427 + {
  428 + return PEAR::raiseError(_kt('Document must be a symbolic link entity'));
  429 + }
  430 + if (is_null($user))
  431 + {
  432 + $user = $_SESSION['userID'];
  433 + }
  434 + if (is_numeric($user))
  435 + {
  436 + $user = User::get($user);
  437 + }
  438 +
  439 + //check permissions
  440 + $oPerm = KTPermission::getByName('ktcore.permissions.delete');
  441 + if (!KTBrowseUtil::inAdminMode($user, $document->getParentID())) {
  442 + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oPerm, $document)){
  443 + return PEAR::raiseError(_kt('You\'re not authorized to delete this shortcut'));
  444 + }
  445 + }
  446 +
  447 + // we only need to delete the document entry for the link
  448 + $sql = "DELETE FROM documents WHERE id=?";
  449 + DBUtil::runQuery(array($sql, array($document->getId())));
  450 +
  451 + }
  452 +
  453 +
306 // Overwrite the document 454 // Overwrite the document
307 function overwrite($oDocument, $sFilename, $sTempFileName, $oUser, $aOptions) { 455 function overwrite($oDocument, $sFilename, $sTempFileName, $oUser, $aOptions) {
308 //$oDocument, $sFilename, $sCheckInComment, $oUser, $aOptions = false 456 //$oDocument, $sFilename, $sCheckInComment, $oUser, $aOptions = false
@@ -838,6 +986,12 @@ class KTDocumentUtil { @@ -838,6 +986,12 @@ class KTDocumentUtil {
838 986
839 // {{{ delete 987 // {{{ delete
840 function delete($oDocument, $sReason, $iDestFolderId = null) { 988 function delete($oDocument, $sReason, $iDestFolderId = null) {
  989 + // use the deleteSymbolicLink function is this is a symlink
  990 + if ($oDocument->isSymbolicLink())
  991 + {
  992 + return KTDocumentUtil::deleteSymbolicLink($oDocument);
  993 + }
  994 +
841 $oDocument =& KTUtil::getObject('Document', $oDocument); 995 $oDocument =& KTUtil::getObject('Document', $oDocument);
842 if (is_null($iDestFolderId)) { 996 if (is_null($iDestFolderId)) {
843 $iDestFolderId = $oDocument->getFolderID(); 997 $iDestFolderId = $oDocument->getFolderID();
@@ -904,6 +1058,24 @@ class KTDocumentUtil { @@ -904,6 +1058,24 @@ class KTDocumentUtil {
904 return PEAR::raiseError(_kt('There was a problem deleting the document from storage.')); 1058 return PEAR::raiseError(_kt('There was a problem deleting the document from storage.'));
905 } 1059 }
906 1060
  1061 + //delete all shortcuts linking to this document
  1062 + $aSymlinks = $oDocument->getSymbolicLinks();
  1063 + foreach($aSymlinks as $aSymlink){
  1064 + $oShortcutDocument = Document::get($aSymlink['id']);
  1065 + $oOwnerUser = User::get($oShortcutDocument->getOwnerID());
  1066 +
  1067 + KTDocumentUtil::deleteSymbolicLink($aSymlink['id']);
  1068 +
  1069 + //send an email to the owner of the shortcut
  1070 + if($oOwnerUser->getEmail()!=null && $oOwnerUser->getEmailNotification() == true){
  1071 + $emailTemplate = new EmailTemplate("kt3/notifications/notification.SymbolicLinkDeleted",array('user_name'=>$this->oUser->getName(),
  1072 + 'url'=>KTUtil::ktLink(KTBrowseUtil::getUrlForDocument($oShortcutDocument)),
  1073 + 'title' =>$oShortcutDocument->getName()));
  1074 + $email = new EmailAlert($oOwnerUser->getEmail(),_kt("KnowledgeTree Notification"),$emailTemplate->getBody());
  1075 + $email->send();
  1076 + }
  1077 + }
  1078 +
907 $oDocumentTransaction = new DocumentTransaction($oDocument, _kt('Document deleted: ') . $sReason, 'ktcore.transactions.delete'); 1079 $oDocumentTransaction = new DocumentTransaction($oDocument, _kt('Document deleted: ') . $sReason, 'ktcore.transactions.delete');
908 $oDocumentTransaction->create(); 1080 $oDocumentTransaction->create();
909 1081
@@ -1166,7 +1338,12 @@ class KTDocumentUtil { @@ -1166,7 +1338,12 @@ class KTDocumentUtil {
1166 } 1338 }
1167 1339
1168 function move($oDocument, $oToFolder, $oUser = null, $sReason = null) { 1340 function move($oDocument, $oToFolder, $oUser = null, $sReason = null) {
1169 - 1341 + //make sure we move the symlink, and the document it's linking to
  1342 + if($oDocument->isSymbolicLink()){
  1343 + $oDocument->switchToRealCore();
  1344 + }else{
  1345 + $oDocument->switchToLinkedCore();
  1346 + }
1170 $oFolder = $oToFolder; // alias. 1347 $oFolder = $oToFolder; // alias.
1171 1348
1172 $oOriginalFolder = Folder::get($oDocument->getFolderId()); 1349 $oOriginalFolder = Folder::get($oDocument->getFolderId());
@@ -1185,18 +1362,20 @@ class KTDocumentUtil { @@ -1185,18 +1362,20 @@ class KTDocumentUtil {
1185 } 1362 }
1186 1363
1187 1364
1188 - //move the document on the file system  
1189 - $oStorage =& KTStorageManagerUtil::getSingleton();  
1190 - $res = $oStorage->moveDocument($oDocument, $oFolder, $oOriginalFolder);  
1191 - if (PEAR::isError($res) || ($res === false)) {  
1192 - $oDocument->setFolderID($oOriginalFolder->getId());  
1193 - $res = $oDocument->update();  
1194 - if (PEAR::isError($res)) {  
1195 - return $res;  
1196 - }  
1197 - return $res; // we failed, bail. 1365 + //move the document on the file system(not if it's a symlink)
  1366 + if(!$oDocument->isSymbolicLink()){
  1367 + $oStorage =& KTStorageManagerUtil::getSingleton();
  1368 + $res = $oStorage->moveDocument($oDocument, $oFolder, $oOriginalFolder);
  1369 + if (PEAR::isError($res) || ($res === false)) {
  1370 + $oDocument->setFolderID($oOriginalFolder->getId());
  1371 + $res = $oDocument->update();
  1372 + if (PEAR::isError($res)) {
  1373 + return $res;
  1374 + }
  1375 + return $res; // we failed, bail.
  1376 + }
1198 } 1377 }
1199 - 1378 +
1200 $sMoveMessage = sprintf(_kt("Moved from %s/%s to %s/%s. %s"), 1379 $sMoveMessage = sprintf(_kt("Moved from %s/%s to %s/%s. %s"),
1201 $oOriginalFolder->getFullPath(), 1380 $oOriginalFolder->getFullPath(),
1202 $oOriginalFolder->getName(), 1381 $oOriginalFolder->getName(),
lib/foldermanagement/Folder.inc
@@ -65,6 +65,8 @@ class Folder extends KTEntity { @@ -65,6 +65,8 @@ class Folder extends KTEntity {
65 var $iPermissionLookupID; 65 var $iPermissionLookupID;
66 /** whether to restrict to only certain document types */ 66 /** whether to restrict to only certain document types */
67 var $bRestrictDocumentTypes = false; 67 var $bRestrictDocumentTypes = false;
  68 + /** ID of the folder this is a shortcut to(if any) */
  69 + var $iLinkedFolderId;
68 70
69 // {{{ KTEntity stuff 71 // {{{ KTEntity stuff
70 var $_aFieldToSelect = array( 72 var $_aFieldToSelect = array(
@@ -79,6 +81,7 @@ class Folder extends KTEntity { @@ -79,6 +81,7 @@ class Folder extends KTEntity {
79 'iPermissionObjectID' => 'permission_object_id', 81 'iPermissionObjectID' => 'permission_object_id',
80 'iPermissionLookupID' => 'permission_lookup_id', 82 'iPermissionLookupID' => 'permission_lookup_id',
81 'bRestrictDocumentTypes' => 'restrict_document_types', 83 'bRestrictDocumentTypes' => 'restrict_document_types',
  84 + 'iLinkedFolderId' => 'linked_folder_id',
82 ); 85 );
83 // }}} 86 // }}}
84 87
@@ -104,6 +107,11 @@ class Folder extends KTEntity { @@ -104,6 +107,11 @@ class Folder extends KTEntity {
104 function getRestrictDocumentTypes() { return $this->bRestrictDocumentTypes; } 107 function getRestrictDocumentTypes() { return $this->bRestrictDocumentTypes; }
105 function setRestrictDocumentTypes($bRestrictDocumentTypes) { $this->bRestrictDocumentTypes = $bRestrictDocumentTypes; } 108 function setRestrictDocumentTypes($bRestrictDocumentTypes) { $this->bRestrictDocumentTypes = $bRestrictDocumentTypes; }
106 109
  110 + function getLinkedFolderId(){ return $this->iLinkedFolderId;}
  111 + function setLinkedFolderId($iNewValue){ $this->iLinkedFolderId = $iNewValue;}
  112 +
  113 +
  114 +
107 // {{{ create() 115 // {{{ create()
108 function create () { 116 function create () {
109 $oParentFolder =& Folder::get($this->iParentID); 117 $oParentFolder =& Folder::get($this->iParentID);
@@ -116,6 +124,18 @@ class Folder extends KTEntity { @@ -116,6 +124,18 @@ class Folder extends KTEntity {
116 } 124 }
117 // }}} 125 // }}}
118 126
  127 + function loadFromArray ($aOptions) {
  128 + parent::loadFromArray($aOptions);
  129 +
  130 + //now load fields from the folder this folder is linking to, if any.
  131 + if($this->isSymbolicLink()){
  132 + $oLinkedFolder = $this->getLinkedFolder();
  133 + $this->sName = $oLinkedFolder->getName();
  134 + $this->sDescription = $oLinkedFolder->getDescription();
  135 + }
  136 +
  137 + }
  138 +
119 /** 139 /**
120 * Returns a comma delimited string containing the parent folder ids, strips leading / 140 * Returns a comma delimited string containing the parent folder ids, strips leading /
121 * 141 *
@@ -309,6 +329,63 @@ class Folder extends KTEntity { @@ -309,6 +329,63 @@ class Folder extends KTEntity {
309 } 329 }
310 330
311 /** 331 /**
  332 + * Checks if this folder is a symbolic link
  333 + *
  334 + * @return boolean
  335 + */
  336 + function isSymbolicLink()
  337 + {
  338 + return !is_null($this->getLinkedFolderId());
  339 + }
  340 +
  341 + /**
  342 + * Retrieves the folder this folder links to, if any.
  343 + *
  344 + * @return Folder
  345 + */
  346 + function getLinkedFolder(){
  347 + if($this->isSymbolicLink()){
  348 + return Folder::get($this->getLinkedFolderId());
  349 + }
  350 + }
  351 +
  352 + /**
  353 + * Returns the "Symbolic link" folder
  354 + *
  355 + * @return Folder the folder
  356 + */
  357 + function getRealFolder(){
  358 + if (is_null($this->getLinkedFolderId()))
  359 + {
  360 + return Folder::get($this->getId());
  361 + }
  362 +
  363 + $oFolder = Folder::get($this->getLinkedFolderId());
  364 + return $oFolder->getRealFolder();
  365 + }
  366 +
  367 + /**
  368 + * Returns the ID of the "Symbolic link" folder
  369 + *
  370 + * @return int the ID
  371 + */
  372 + function getRealFolderId(){
  373 + $oRealFolder = $this->getRealFolder();
  374 + return $oRealFolder->getId();
  375 + }
  376 +
  377 + /**
  378 + * Returns the symbolic links linking to this folder
  379 + *
  380 + * @return Array array with folder IDs
  381 + */
  382 + function getSymbolicLinks(){
  383 + $sQuery = 'SELECT * FROM folders ' .
  384 + 'WHERE folders.linked_folder_id = '.$this->getId();
  385 + return DButil::getResultArray($sQuery);
  386 + }
  387 +
  388 + /**
312 * Static function 389 * Static function
313 * Get a list of Documents 390 * Get a list of Documents
314 * 391 *
lib/foldermanagement/folderutil.inc.php
@@ -45,6 +45,7 @@ require_once(KT_LIB_DIR . &#39;/permissions/permissionutil.inc.php&#39;); @@ -45,6 +45,7 @@ require_once(KT_LIB_DIR . &#39;/permissions/permissionutil.inc.php&#39;);
45 require_once(KT_LIB_DIR . '/users/User.inc'); 45 require_once(KT_LIB_DIR . '/users/User.inc');
46 46
47 require_once(KT_LIB_DIR . '/foldermanagement/foldertransaction.inc.php'); 47 require_once(KT_LIB_DIR . '/foldermanagement/foldertransaction.inc.php');
  48 +require_once(KT_LIB_DIR . '/browse/browseutil.inc.php');
48 49
49 require_once(KT_LIB_DIR . '/database/dbutil.inc'); 50 require_once(KT_LIB_DIR . '/database/dbutil.inc');
50 51
@@ -401,7 +402,17 @@ class KTFolderUtil { @@ -401,7 +402,17 @@ class KTFolderUtil {
401 DBUtil::rollback(); 402 DBUtil::rollback();
402 return PEAR::raiseError(_kt('Failure deleting folders.')); 403 return PEAR::raiseError(_kt('Failure deleting folders.'));
403 } 404 }
404 - 405 +
  406 + //delete all folder shortcuts
  407 + foreach($aFolderIds as $iFolder){
  408 + $oFolder = Folder::get($iFolder);
  409 + $aSymlinks = $oFolder->getSymbolicLinks();
  410 +
  411 + foreach($aSymlinks as $aSymlink){
  412 + KTFolderUtil::deleteSymbolicLink($aSymlink['id']);
  413 + }
  414 + }
  415 +
405 // purge caches 416 // purge caches
406 KTEntityUtil::clearAllCaches('Folder'); 417 KTEntityUtil::clearAllCaches('Folder');
407 418
@@ -573,6 +584,125 @@ class KTFolderUtil { @@ -573,6 +584,125 @@ class KTFolderUtil {
573 584
574 return true; 585 return true;
575 } 586 }
  587 +
  588 +/**
  589 + * Create a symbolic link in the target folder
  590 + *
  591 + * @param Folder $sourceFolder Folder to create a link to
  592 + * @param Folder $targetFolder Folder to place the link in
  593 + * @param User $user current user
  594 + * @return Folder the link
  595 + */
  596 + static function createSymbolicLink($sourceFolder, $targetFolder, $user = null) // added/
  597 + {
  598 + //validate input
  599 + if (is_numeric($sourceFolder))
  600 + {
  601 + $sourceFolder = Folder::get($sourceFolder);
  602 + }
  603 + if (!$sourceFolder instanceof Folder)
  604 + {
  605 + return PEAR::raiseError(_kt('Source folder not specified'));
  606 + }
  607 + if (is_numeric($targetFolder))
  608 + {
  609 + $targetFolder = Folder::get($targetFolder);
  610 + }
  611 + if (!$targetFolder instanceof Folder)
  612 + {
  613 + return PEAR::raiseError(_kt('Target folder not specified'));
  614 + }
  615 + if (is_null($user))
  616 + {
  617 + $user = $_SESSION['userID'];
  618 + }
  619 + if (is_numeric($user))
  620 + {
  621 + $user = User::get($user);
  622 + }
  623 +
  624 + //check for permissions
  625 + $oWritePermission =& KTPermission::getByName("ktcore.permissions.write");
  626 + $oReadPermission =& KTPermission::getByName("ktcore.permissions.read");
  627 + if (!KTBrowseUtil::inAdminMode($user, $targetFolder)) {
  628 + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oWritePermission, $targetFolder)){
  629 + return PEAR::raiseError(_kt('You\'re not authorized to create shortcuts'));
  630 + }
  631 + }
  632 + if (!KTBrowseUtil::inAdminMode($user, $sourceFolder)) {
  633 + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oReadPermission, $sourceFolder)){
  634 + return PEAR::raiseError(_kt('You\'re not authorized to create a shortcut to this folder'));
  635 + }
  636 + }
  637 +
  638 + //check if the shortcut doesn't already exists in the target folder
  639 + $aSymlinks = $sourceFolder->getSymbolicLinks();
  640 + foreach($aSymlinks as $iSymlink){
  641 + $oSymlink = Folder::get($iSymlink['id']);
  642 + if($oSymlink->getParentID() == $targetFolder->getID()){
  643 + return PEAR::raiseError(_kt('There already is a shortcut to this folder in the target folder.'));
  644 + }
  645 + }
  646 +
  647 + //Create the link
  648 + $oSymlink = Folder::createFromArray(array(
  649 + 'iParentID' => $targetFolder->getId(),
  650 + 'iCreatorID' => $user->getId(),
  651 + 'sFullPath' => $targetFolder->getFullPath(),
  652 + 'sParentFolderIDs' => $targetFolder->getParentFolderIDs(),
  653 + 'iPermissionObjectID' => $targetFolder->getPermissionObjectID(),
  654 + 'iPermissionLookupID' => $targetFolder->getPermissionLookupID(),
  655 + 'iLinkedFolderId' => $sourceFolder->getId(),
  656 + ));
  657 + return $oSymlink;
  658 + }
  659 +
  660 + /**
  661 + * Deletes a symbolic link folder
  662 + *
  663 + * @param Folder $folder tthe symbolic link folder to delete
  664 + * @param User $user the current user
  665 + * @return unknown
  666 + */
  667 + static function deleteSymbolicLink($folder, $user = null) // added/
  668 + {
  669 + //validate input
  670 + if (is_numeric($folder))
  671 + {
  672 + $folder = Folder::get($folder);
  673 + }
  674 + if (!$folder instanceof Folder)
  675 + {
  676 + return PEAR::raiseError(_kt('Folder not specified'));
  677 + }
  678 + if (!$folder->isSymbolicLink())
  679 + {
  680 + return PEAR::raiseError(_kt('Focument must be a symbolic link entity'));
  681 + }
  682 + if (is_null($user))
  683 + {
  684 + $user = $_SESSION['userID'];
  685 + }
  686 + if (is_numeric($user))
  687 + {
  688 + $user = User::get($user);
  689 + }
  690 +
  691 + //check if the user has sufficient permissions
  692 + $oPerm = KTPermission::getByName('ktcore.permissions.delete');
  693 + if (!KTBrowseUtil::inAdminMode($user, $folder)) {
  694 + if(!KTPermissionUtil::userHasPermissionOnItem($user, $oPerm, $folder)){
  695 + return PEAR::raiseError(_kt('You\'re not authorized to create shortcuts'));
  696 + }
  697 + }
  698 +
  699 + // we only need to delete the folder entry for the link
  700 + $sql = "DELETE FROM folders WHERE id=?";
  701 + DBUtil::runQuery(array($sql, array($folder->getId())));
  702 +
  703 + }
  704 +
  705 +
576 } 706 }
577 707
578 ?> 708 ?>
lib/permissions/permissionutil.inc.php
@@ -304,6 +304,11 @@ class KTPermissionUtil { @@ -304,6 +304,11 @@ class KTPermissionUtil {
304 $is_a_folder = is_a($oFolderOrDocument, 'Folder'); 304 $is_a_folder = is_a($oFolderOrDocument, 'Folder');
305 $is_a_document = is_a($oFolderOrDocument, 'Document') || is_a($oFolderOrDocument, 'KTDocumentCore'); 305 $is_a_document = is_a($oFolderOrDocument, 'Document') || is_a($oFolderOrDocument, 'KTDocumentCore');
306 306
  307 + //ensure that the document shortcut is being updated.
  308 + if($is_a_document && $oFolderOrDocument->isSymbolicLink()){
  309 + $oFolderOrDocument->switchToRealCore();
  310 + }
  311 +
307 $oChannel = null; 312 $oChannel = null;
308 $aMapPermAllowed = null; 313 $aMapPermAllowed = null;
309 $oPermLookup = null; 314 $oPermLookup = null;
@@ -325,7 +330,12 @@ class KTPermissionUtil { @@ -325,7 +330,12 @@ class KTPermissionUtil {
325 $msg = sprintf("Updating folder %s", join('/', $oFolderOrDocument->getPathArray())); 330 $msg = sprintf("Updating folder %s", join('/', $oFolderOrDocument->getPathArray()));
326 } else { 331 } else {
327 if (is_a($oFolderOrDocument, 'Document')) { 332 if (is_a($oFolderOrDocument, 'Document')) {
328 - $msg = sprintf("Updating document %s", $oFolderOrDocument->getName()); 333 + //modify the message to reflect that a shortcut is begin updated
  334 + if($oFolderOrDocument->isSymbolicLink()){
  335 + $msg = sprintf("Updating shortcut to %s", $oFolderOrDocument->getName());
  336 + }else{
  337 + $msg = sprintf("Updating document %s", $oFolderOrDocument->getName());
  338 + }
329 } else { 339 } else {
330 $msg = sprintf("Updating document %d", $oFolderOrDocument->getId()); 340 $msg = sprintf("Updating document %d", $oFolderOrDocument->getId());
331 } 341 }
plugins/ktcore/KTBulkActions.php
@@ -92,14 +92,68 @@ class KTBulkDeleteAction extends KTBulkAction { @@ -92,14 +92,68 @@ class KTBulkDeleteAction extends KTBulkAction {
92 return $oForm; 92 return $oForm;
93 } 93 }
94 94
  95 + /**
  96 + * build the confirmation form that is shown when symlinks are affected by this action.
  97 + *
  98 + * @return KTForm the form
  99 + */
  100 + function form_confirm() {
  101 + $oForm = new KTForm;
  102 + $oForm->setOptions(array(
  103 + 'label' => _kt('Are you sure?'),
  104 + '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?'),
  105 + 'action' => 'collectinfo',
  106 + 'fail_action' => 'main',
  107 + 'cancel_url' => KTBrowseUtil::getUrlForFolder($this->oFolder),
  108 + 'submit_label' => _kt('Continue'),
  109 + 'context' => $this,
  110 + ));
  111 +
  112 + $oForm->setWidgets(array(
  113 + array('ktcore.widgets.hidden',array(
  114 + 'name' => 'delete_confirmed',
  115 + 'value' => '1'
  116 + ))));
  117 +
  118 + return $oForm;
  119 + }
  120 +
  121 + /**
  122 + * Shows the confirmation form if symlinks are affected by the current action
  123 + *
  124 + * @return Template HTML
  125 + */
  126 + function do_confirm(){
  127 + $this->store_lists();
  128 + $this->get_lists();
  129 + $this->oPage->setBreadcrumbDetails(_kt('Confirm delete'));
  130 + $oTemplate =& $this->oValidator->validateTemplate('ktcore/bulk_action_confirm');
  131 + $oForm = $this->form_confirm();
  132 + $oTemplate->setData(array(
  133 + 'context' => &$this,
  134 + 'form' => $oForm,
  135 + ));
  136 + return $oTemplate->render();
  137 + }
  138 +
95 // info collection step 139 // info collection step
96 function do_collectinfo() { 140 function do_collectinfo() {
97 $this->store_lists(); 141 $this->store_lists();
98 $this->get_lists(); 142 $this->get_lists();
99 - $oTemplating =& KTTemplating::getSingleton();  
100 - $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_info');  
101 - return $oTemplate->render(array('context' => $this,  
102 - 'form' => $this->form_collectinfo())); 143 +
  144 + //check if a the symlinks deletion confirmation has been passed yet
  145 + if(KTutil::arrayGet($_REQUEST['data'],'delete_confirmed') != 1){
  146 + //check if there are actually any symlinks involved.
  147 + if($this->symlinksLinkingToCurrentList()){
  148 + $this->redirectTo("confirm");
  149 + }
  150 + }
  151 +
  152 + //render template
  153 + $oTemplating =& KTTemplating::getSingleton();
  154 + $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_info');
  155 + return $oTemplate->render(array('context' => $this,
  156 + 'form' => $this->form_collectinfo()));
103 } 157 }
104 158
105 159
@@ -464,15 +518,71 @@ class KTBulkArchiveAction extends KTBulkAction { @@ -464,15 +518,71 @@ class KTBulkArchiveAction extends KTBulkAction {
464 if((!is_a($oEntity, 'Document')) && (!is_a($oEntity, 'Folder'))) { 518 if((!is_a($oEntity, 'Document')) && (!is_a($oEntity, 'Folder'))) {
465 return PEAR::raiseError(_kt('Document cannot be archived')); 519 return PEAR::raiseError(_kt('Document cannot be archived'));
466 } 520 }
  521 + if($oEntity->isSymbolicLink()){
  522 + return PEAR::raiseError(_kt("It is not possible to archive a shortcut. Please archive the target document or folder instead."));
  523 + }
467 return parent::check_entity($oEntity); 524 return parent::check_entity($oEntity);
468 } 525 }
469 526
  527 + /**
  528 + * build the confirmation form that is shown when symlinks are affected by this action.
  529 + *
  530 + * @return KTForm the form
  531 + */
  532 + function form_confirm() {
  533 + $oForm = new KTForm;
  534 + $oForm->setOptions(array(
  535 + 'label' => _kt('Are you sure?'),
  536 + '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?'),
  537 + 'action' => 'collectinfo',
  538 + 'fail_action' => 'main',
  539 + 'cancel_url' => KTBrowseUtil::getUrlForFolder($this->oFolder),
  540 + 'submit_label' => _kt('Continue'),
  541 + 'context' => $this,
  542 + ));
  543 +
  544 + $oForm->setWidgets(array(
  545 + array('ktcore.widgets.hidden',array(
  546 + 'name' => 'archive_confirmed',
  547 + 'value' => '1'
  548 + ))));
  549 +
  550 + return $oForm;
  551 + }
  552 +
  553 + /**
  554 + * Shows the confirmation form if symlinks are affected by the current action
  555 + *
  556 + * @return Template HTML
  557 + */
  558 + function do_confirm(){
  559 + $this->store_lists();
  560 + $this->get_lists();
  561 + $this->oPage->setBreadcrumbDetails(_kt('Confirm archive'));
  562 + $oTemplate =& $this->oValidator->validateTemplate('ktcore/bulk_action_confirm');
  563 + $oForm = $this->form_confirm();
  564 + $oTemplate->setData(array(
  565 + 'context' => &$this,
  566 + 'form' => $oForm,
  567 + ));
  568 + return $oTemplate->render();
  569 + }
  570 +
470 // info collection step 571 // info collection step
471 function do_collectinfo() { 572 function do_collectinfo() {
472 $this->store_lists(); 573 $this->store_lists();
473 $this->get_lists(); 574 $this->get_lists();
474 - $oTemplating =& KTTemplating::getSingleton();  
475 - $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_info'); 575 +
  576 + //check if a the symlinks deletion confirmation has been passed yet
  577 + if(KTutil::arrayGet($_REQUEST['data'],'archive_confirmed') != 1){
  578 + //check if there are actually any symlinks involved.
  579 + if($this->symlinksLinkingToCurrentList()){
  580 + $this->redirectTo("confirm");
  581 + }
  582 + }
  583 +
  584 + $oTemplating =& KTTemplating::getSingleton();
  585 + $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_info');
476 return $oTemplate->render(array('context' => $this, 586 return $oTemplate->render(array('context' => $this,
477 'form' => $this->form_collectinfo())); 587 'form' => $this->form_collectinfo()));
478 } 588 }
@@ -637,6 +747,9 @@ class KTBrowseBulkExportAction extends KTBulkAction { @@ -637,6 +747,9 @@ class KTBrowseBulkExportAction extends KTBulkAction {
637 if(is_a($oEntity, 'Document')) { 747 if(is_a($oEntity, 'Document')) {
638 748
639 $oDocument = $oEntity; 749 $oDocument = $oEntity;
  750 + if($oDocument->isSymbolicLink()){
  751 + $oDocument->switchToLinkedCore();
  752 + }
640 753
641 if ($this->bNoisy) { 754 if ($this->bNoisy) {
642 $oDocumentTransaction = new DocumentTransaction($oDocument, "Document part of bulk export", 'ktstandard.transactions.bulk_export', array()); 755 $oDocumentTransaction = new DocumentTransaction($oDocument, "Document part of bulk export", 'ktstandard.transactions.bulk_export', array());
@@ -932,7 +1045,6 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction { @@ -932,7 +1045,6 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction {
932 return $ret; 1045 return $ret;
933 } 1046 }
934 } 1047 }
935 -  
936 $this->oZip->addDocumentToZip($oEntity); 1048 $this->oZip->addDocumentToZip($oEntity);
937 } 1049 }
938 1050
@@ -1066,4 +1178,4 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction { @@ -1066,4 +1178,4 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction {
1066 } 1178 }
1067 } 1179 }
1068 1180
1069 -?> 1181 -?>
  1182 +?>
1070 \ No newline at end of file 1183 \ No newline at end of file
plugins/ktcore/KTColumns.inc.php
@@ -112,7 +112,18 @@ class AdvancedTitleColumn extends AdvancedColumn { @@ -112,7 +112,18 @@ class AdvancedTitleColumn extends AdvancedColumn {
112 } 112 }
113 113
114 function buildDocumentLink($aDataRow) { 114 function buildDocumentLink($aDataRow) {
115 - return KTBrowseUtil::getUrlForDocument($aDataRow["document"]->getId()); 115 + if($aDataRow['document']->isSymbolicLink()){
  116 + $iDocId = $aDataRow['document']->getRealDocumentId();
  117 + }else{
  118 + $iDocId = $aDataRow["document"]->getId();
  119 + }
  120 +
  121 + $url = KTBrowseUtil::getUrlForDocument($iDocId);
  122 + if($aDataRow['document']->isSymbolicLink()){
  123 + $aDataRow['document']->switchToRealCore();
  124 + $url .= "&fShortcutFolder=".$aDataRow['document']->getFolderId();
  125 + }
  126 + return $url;
116 } 127 }
117 128
118 129
@@ -122,9 +133,15 @@ class AdvancedTitleColumn extends AdvancedColumn { @@ -122,9 +133,15 @@ class AdvancedTitleColumn extends AdvancedColumn {
122 133
123 function buildFolderLink($aDataRow) { 134 function buildFolderLink($aDataRow) {
124 if (is_null(KTUtil::arrayGet($this->aOptions, 'direct_folder'))) { 135 if (is_null(KTUtil::arrayGet($this->aOptions, 'direct_folder'))) {
125 - $dest = KTUtil::arrayGet($this->aOptions, 'folder_link');  
126 - $params = kt_array_merge(KTUtil::arrayGet($this->aOptions, 'qs_params', array()),  
127 - array('fFolderId' => $aDataRow['folder']->getId())); 136 + $dest = KTUtil::arrayGet($this->aOptions, 'folder_link');
  137 + if($aDataRow['folder']->isSymbolicLink()){
  138 + $params = array('fFolderId' => $aDataRow['folder']->getLinkedFolderId(),
  139 + 'fShortcutFolder' => $aDataRow['folder']->getParentID());
  140 + }else{
  141 + $params = array('fFolderId' => $aDataRow['folder']->getId());
  142 + }
  143 + $params = kt_array_merge(KTUtil::arrayGet($this->aOptions, 'qs_params', array()),
  144 + $params);
128 145
129 if (empty($dest)) { 146 if (empty($dest)) {
130 return KTUtil::addQueryStringSelf($params); 147 return KTUtil::addQueryStringSelf($params);
@@ -133,7 +150,11 @@ class AdvancedTitleColumn extends AdvancedColumn { @@ -133,7 +150,11 @@ class AdvancedTitleColumn extends AdvancedColumn {
133 } 150 }
134 151
135 } else { 152 } else {
136 - return KTBrowseUtil::getUrlForFolder($aDataRow['folder']); 153 + if($aDataRow['folder']->isSymbolicLink()){
  154 + return KTBrowseUtil::getUrlForFolder($aDataRow['folder']->getLinkedFolder())."&fShortcutFolder=".$aDataRow['folder']->getParentID();
  155 + }else{
  156 + return KTBrowseUtil::getUrlForFolder($aDataRow['folder']);
  157 + }
137 } 158 }
138 } 159 }
139 160
@@ -142,12 +163,22 @@ class AdvancedTitleColumn extends AdvancedColumn { @@ -142,12 +163,22 @@ class AdvancedTitleColumn extends AdvancedColumn {
142 if ($aDataRow["type"] == "folder") { 163 if ($aDataRow["type"] == "folder") {
143 $contenttype = 'folder'; 164 $contenttype = 'folder';
144 $link = $this->renderFolderLink($aDataRow); 165 $link = $this->renderFolderLink($aDataRow);
145 - return sprintf('<span class="contenttype %s">%s</span>', $contenttype, $link); 166 + if($aDataRow['folder']->isSymbolicLink()){
  167 + return sprintf('<span class="contenttype %s">%s<img src="resources/tango-icons/shortcut.png" /></span>', $contenttype, $link);
  168 + }else{
  169 + return sprintf('<span class="contenttype %s">%s</span>', $contenttype, $link);
  170 + }
146 } else { 171 } else {
147 - $contenttype = $this->_mimeHelper($aDataRow["document"]->getMimeTypeId());  
148 - $link = $this->renderDocumentLink($aDataRow);  
149 - $size = $this->prettySize($aDataRow["document"]->getSize());  
150 - return sprintf('<span class="contenttype %s">%s (%s)</span>', $contenttype, $link, $size); 172 + $contenttype = $this->_mimeHelper($aDataRow["document"]->getMimeTypeId());
  173 + $link = $this->renderDocumentLink($aDataRow);
  174 +
  175 + //Render an image instead of the size in case of a shortcut
  176 + if($aDataRow['document']->isSymbolicLink()){
  177 + return sprintf('<span class="contenttype %s">%s <img src="resources/tango-icons/shortcut.png" /></span>', $contenttype, $link);
  178 + }else{
  179 + $size = $this->prettySize($aDataRow["document"]->getSize());
  180 + return sprintf('<span class="contenttype %s">%s (%s)</span>', $contenttype, $link, $size);
  181 + }
151 } 182 }
152 } 183 }
153 184
@@ -359,6 +390,11 @@ class AdvancedSingleSelectionColumn extends AdvancedSelectionColumn { @@ -359,6 +390,11 @@ class AdvancedSingleSelectionColumn extends AdvancedSelectionColumn {
359 } 390 }
360 391
361 function renderHeader() { 392 function renderHeader() {
  393 + global $main;
  394 + //include some javascript to force real single selections
  395 + if($this->show_folders && $this->show_documents){
  396 + $main->requireJSResource("resources/js/singleselect.js");
  397 + }
362 return '&nbsp;'; 398 return '&nbsp;';
363 } 399 }
364 400
@@ -380,7 +416,12 @@ class AdvancedSingleSelectionColumn extends AdvancedSelectionColumn { @@ -380,7 +416,12 @@ class AdvancedSingleSelectionColumn extends AdvancedSelectionColumn {
380 return '&nbsp;'; 416 return '&nbsp;';
381 } 417 }
382 418
383 - return '<input type="radio" name="' . $localname . '" value="' . $v . '"/>'; 419 + $return = '<input type="radio" name="' . $localname . '" value="' . $v . '" ';
  420 + if($this->show_folders && $this->show_documents){
  421 + $return .= 'onClick="forceSingleSelect(this)" ';
  422 + }
  423 + $return .='/>';
  424 + return $return;
384 } 425 }
385 426
386 // no label, but we do have a title 427 // no label, but we do have a title
plugins/ktcore/KTDocumentActions.php
@@ -853,15 +853,31 @@ class KTDocumentDeleteAction extends KTDocumentAction { @@ -853,15 +853,31 @@ class KTDocumentDeleteAction extends KTDocumentAction {
853 $_SESSION['KTErrorMessage'][]= _kt('This document can\'t be deleted because it is checked out'); 853 $_SESSION['KTErrorMessage'][]= _kt('This document can\'t be deleted because it is checked out');
854 controllerRedirect('viewDocument', 'fDocumentId=' . $this->oDocument->getId()); 854 controllerRedirect('viewDocument', 'fDocumentId=' . $this->oDocument->getId());
855 exit(0); 855 exit(0);
856 - } 856 + }
  857 +
857 return true; 858 return true;
858 } 859 }
859 860
  861 + function form_confirm() {
  862 + $oForm = new KTForm;
  863 + $oForm->setOptions(array(
  864 + 'label' => _kt('Are you sure?'),
  865 + 'description' => _kt('There are shortcuts linking to this document; deleting the document will automatically delete them. Would you like to continue?'),
  866 + 'action' => 'main',
  867 + 'fail_action' => 'main',
  868 + 'cancel_url' => KTBrowseUtil::getUrlForDocument($this->oDocument),
  869 + 'submit_label' => _kt('Delete Document'),
  870 + 'context' => &$this,
  871 + ));
  872 +
860 873
  874 + return $oForm;
  875 + }
  876 +
861 function form_main() { 877 function form_main() {
862 $oForm = new KTForm; 878 $oForm = new KTForm;
863 $oForm->setOptions(array( 879 $oForm->setOptions(array(
864 - 'label' => _kt('Delete Document'), 880 + 'label' => _kt('Delete Document'),
865 'action' => 'delete', 881 'action' => 'delete',
866 'fail_action' => 'main', 882 'fail_action' => 'main',
867 'cancel_url' => KTBrowseUtil::getUrlForDocument($this->oDocument), 883 'cancel_url' => KTBrowseUtil::getUrlForDocument($this->oDocument),
@@ -888,16 +904,29 @@ class KTDocumentDeleteAction extends KTDocumentAction { @@ -888,16 +904,29 @@ class KTDocumentDeleteAction extends KTDocumentAction {
888 904
889 function do_main() { 905 function do_main() {
890 $this->oPage->setBreadcrumbDetails(_kt('Delete')); 906 $this->oPage->setBreadcrumbDetails(_kt('Delete'));
  907 + //check if we need confirmation for symblolic links linking to this document
  908 + if(count($this->oDocument->getSymbolicLinks())>0 && KTutil::arrayGet($_REQUEST,'postReceived') != 1){
  909 + $this->redirectTo("confirm");
  910 + }
891 $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/delete'); 911 $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/delete');
892 -  
893 $oForm = $this->form_main(); 912 $oForm = $this->form_main();
894 -  
895 $oTemplate->setData(array( 913 $oTemplate->setData(array(
896 'context' => &$this, 914 'context' => &$this,
897 'form' => $oForm, 915 'form' => $oForm,
898 )); 916 ));
899 return $oTemplate->render(); 917 return $oTemplate->render();
900 } 918 }
  919 +
  920 + function do_confirm(){
  921 + $this->oPage->setBreadcrumbDetails(_kt('Confirm delete'));
  922 + $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/delete_confirm');
  923 + $oForm = $this->form_confirm();
  924 + $oTemplate->setData(array(
  925 + 'context' => &$this,
  926 + 'form' => $oForm,
  927 + ));
  928 + return $oTemplate->render();
  929 + }
901 930
902 function do_delete() { 931 function do_delete() {
903 $oForm = $this->form_main(); 932 $oForm = $this->form_main();
@@ -1346,6 +1375,22 @@ class KTDocumentArchiveAction extends KTDocumentAction { @@ -1346,6 +1375,22 @@ class KTDocumentArchiveAction extends KTDocumentAction {
1346 return parent::getInfo(); 1375 return parent::getInfo();
1347 } 1376 }
1348 1377
  1378 + function form_confirm() {
  1379 + $oForm = new KTForm;
  1380 + $oForm->setOptions(array(
  1381 + 'label' => _kt('Are you sure?'),
  1382 + 'description' => _kt('There are shortcuts linking to this document; archiving the document automatically will delete them. Would you like to continue?'),
  1383 + 'action' => 'main',
  1384 + 'fail_action' => 'main',
  1385 + 'cancel_url' => KTBrowseUtil::getUrlForDocument($this->oDocument),
  1386 + 'submit_label' => _kt('Archive Document'),
  1387 + 'context' => &$this,
  1388 + ));
  1389 +
  1390 +
  1391 + return $oForm;
  1392 + }
  1393 +
1349 function form_main() { 1394 function form_main() {
1350 $oForm = new KTForm; 1395 $oForm = new KTForm;
1351 $oForm->setOptions(array( 1396 $oForm->setOptions(array(
@@ -1375,6 +1420,10 @@ class KTDocumentArchiveAction extends KTDocumentAction { @@ -1375,6 +1420,10 @@ class KTDocumentArchiveAction extends KTDocumentAction {
1375 } 1420 }
1376 1421
1377 function do_main() { 1422 function do_main() {
  1423 + //if there are symbolic links linking to this document we need confirmation
  1424 + if(count($this->oDocument->getSymbolicLinks())>0 && KTutil::arrayGet($_REQUEST,'postReceived') != 1){
  1425 + $this->redirectTo("confirm");
  1426 + }
1378 $this->oPage->setBreadcrumbDetails(_kt('Archive Document')); 1427 $this->oPage->setBreadcrumbDetails(_kt('Archive Document'));
1379 $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/archive'); 1428 $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/archive');
1380 1429
@@ -1386,6 +1435,17 @@ class KTDocumentArchiveAction extends KTDocumentAction { @@ -1386,6 +1435,17 @@ class KTDocumentArchiveAction extends KTDocumentAction {
1386 )); 1435 ));
1387 return $oTemplate->render(); 1436 return $oTemplate->render();
1388 } 1437 }
  1438 +
  1439 + function do_confirm(){
  1440 + $this->oPage->setBreadcrumbDetails(_kt('Confirm archive'));
  1441 + $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/archive_confirm');
  1442 + $oForm = $this->form_confirm();
  1443 + $oTemplate->setData(array(
  1444 + 'context' => &$this,
  1445 + 'form' => $oForm,
  1446 + ));
  1447 + return $oTemplate->render();
  1448 + }
1389 1449
1390 function do_archive() { 1450 function do_archive() {
1391 1451
resources/js/singleselect.js 0 → 100755
  1 +function forceSingleSelect(currentSelectedItem){
  2 + var otherName = currentSelectedItem.name.substring(0,currentSelectedItem.name.length - 1);
  3 + if(currentSelectedItem.name.substring(currentSelectedItem.name.length-1) == 'd'){
  4 + otherName += "f";
  5 + }else{
  6 + otherName += "d"
  7 + }
  8 +
  9 + var items = document.getElementsByTagName("input");
  10 + for (var i=0; i<items.length; i++) {
  11 + if(items[i].type == 'radio' && items[i].name == otherName){
  12 + items[i].checked = false;
  13 + }
  14 + }
  15 +
  16 +
  17 +}
0 \ No newline at end of file 18 \ No newline at end of file
resources/tango-icons/shortcut.png 0 → 100755

592 Bytes

sql/mysql/install/structure.sql
@@ -5,31 +5,31 @@ @@ -5,31 +5,31 @@
5 -- Document Management Made Simple 5 -- Document Management Made Simple
6 -- Copyright (C) 2008 KnowledgeTree Inc. 6 -- Copyright (C) 2008 KnowledgeTree Inc.
7 -- Portions copyright The Jam Warehouse Software (Pty) Limited 7 -- Portions copyright The Jam Warehouse Software (Pty) Limited
8 --- 8 +--
9 -- This program is free software; you can redistribute it and/or modify it under 9 -- This program is free software; you can redistribute it and/or modify it under
10 -- the terms of the GNU General Public License version 3 as published by the 10 -- the terms of the GNU General Public License version 3 as published by the
11 -- Free Software Foundation. 11 -- Free Software Foundation.
12 --- 12 +--
13 -- This program is distributed in the hope that it will be useful, but WITHOUT 13 -- This program is distributed in the hope that it will be useful, but WITHOUT
14 -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14 -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 15 -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 -- details. 16 -- details.
17 --- 17 +--
18 -- You should have received a copy of the GNU General Public License 18 -- You should have received a copy of the GNU General Public License
19 -- along with this program. If not, see <http://www.gnu.org/licenses/>. 19 -- along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ---  
21 --- You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, 20 +--
  21 +-- You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
22 -- California 94120-7775, or email info@knowledgetree.com. 22 -- California 94120-7775, or email info@knowledgetree.com.
23 --- 23 +--
24 -- The interactive user interfaces in modified source and object code versions 24 -- The interactive user interfaces in modified source and object code versions
25 -- of this program must display Appropriate Legal Notices, as required under 25 -- of this program must display Appropriate Legal Notices, as required under
26 -- Section 5 of the GNU General Public License version 3. 26 -- Section 5 of the GNU General Public License version 3.
27 --- 27 +--
28 -- In accordance with Section 7(b) of the GNU General Public License version 3, 28 -- In accordance with Section 7(b) of the GNU General Public License version 3,
29 -- these Appropriate Legal Notices must retain the display of the "Powered by 29 -- these Appropriate Legal Notices must retain the display of the "Powered by
30 --- KnowledgeTree" logo and retain the original copyright notice. If the display of the 30 +-- KnowledgeTree" logo and retain the original copyright notice. If the display of the
31 -- logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices 31 -- logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
32 --- must display the words "Powered by KnowledgeTree" and retain the original 32 +-- must display the words "Powered by KnowledgeTree" and retain the original
33 -- copyright notice. 33 -- copyright notice.
34 -- Contributor( s): ______________________________________ 34 -- Contributor( s): ______________________________________
35 -- 35 --
@@ -578,6 +578,7 @@ CREATE TABLE `documents` ( @@ -578,6 +578,7 @@ CREATE TABLE `documents` (
578 `restore_folder_path` text, 578 `restore_folder_path` text,
579 `checkedout` datetime default NULL, 579 `checkedout` datetime default NULL,
580 `oem_no` varchar(255) default NULL, 580 `oem_no` varchar(255) default NULL,
  581 + `linked_document_id` int(11),
581 PRIMARY KEY (`id`), 582 PRIMARY KEY (`id`),
582 KEY `creator_id` (`creator_id`), 583 KEY `creator_id` (`creator_id`),
583 KEY `folder_id` (`folder_id`), 584 KEY `folder_id` (`folder_id`),
@@ -813,6 +814,7 @@ CREATE TABLE `folders` ( @@ -813,6 +814,7 @@ CREATE TABLE `folders` (
813 `permission_lookup_id` int(11) default NULL, 814 `permission_lookup_id` int(11) default NULL,
814 `restrict_document_types` tinyint(1) NOT NULL default '0', 815 `restrict_document_types` tinyint(1) NOT NULL default '0',
815 `owner_id` int(11) default NULL, 816 `owner_id` int(11) default NULL,
  817 + `linked_folder_id` int(11),
816 PRIMARY KEY (`id`), 818 PRIMARY KEY (`id`),
817 KEY `creator_id` (`creator_id`), 819 KEY `creator_id` (`creator_id`),
818 KEY `permission_object_id` (`permission_object_id`), 820 KEY `permission_object_id` (`permission_object_id`),
sql/mysql/upgrade/3.5.3/shortcuts.sql 0 → 100644
  1 +ALTER TABLE documents ADD `linked_document_id` int(11);
  2 +ALTER TABLE folders ADD `linked_folder_id` int(11);
0 \ No newline at end of file 3 \ No newline at end of file
templates/kt3/notifications/notification.SymbolicLinkArchived.smarty 0 → 100755
  1 +{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}<br>
  2 +<br>
  3 +<a href="{$url}">{$title}</a><br>
  4 +<br>
  5 +{i18n}Target document archived by:{/i18n} {$user_name}<br>
0 \ No newline at end of file 6 \ No newline at end of file
templates/kt3/notifications/notification.SymbolicLinkDeleted.smarty 0 → 100755
  1 +{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}<br>
  2 +<br>
  3 +<a href="{$url}">{$title}</a><br>
  4 +<br>
  5 +{i18n}Target document deleted by:{/i18n} {$user_name}<br>
0 \ No newline at end of file 6 \ No newline at end of file
templates/ktcore/action/archive_confirm.smarty 0 → 100755
  1 +<h2><img src="{if $config->get("ui/morphEnabled") == '1'}{$rootUrl}/skins/kts_{$config->get("ui/morphTo")}/title_bullet.png{else}{$rootUrl}/resources/graphics/title_bullet.png{/if}"/>{i18n}Archive Document{/i18n}:<br />{$context->oDocument->getName()|sanitize}</h2>
  2 +
  3 +{$form->render()}
0 \ No newline at end of file 4 \ No newline at end of file
templates/ktcore/action/delete_confirm.smarty 0 → 100755
  1 +<h2><img src="{if $config->get("ui/morphEnabled") == '1'}{$rootUrl}/skins/kts_{$config->get("ui/morphTo")}/title_bullet.png{else}{$rootUrl}/resources/graphics/title_bullet.png{/if}"/>{i18n}Delete Document{/i18n}:<br />{$context->oDocument->getName()|sanitize}</h2>
  2 +
  3 +{$form->render()}
0 \ No newline at end of file 4 \ No newline at end of file
templates/ktcore/bulk_action_complete.smarty
@@ -17,7 +17,10 @@ @@ -17,7 +17,10 @@
17 <tbody> 17 <tbody>
18 {foreach from=$list.folders item=item} 18 {foreach from=$list.folders item=item}
19 <tr class="{cycle values=even,odd}"> 19 <tr class="{cycle values=even,odd}">
20 - <td>{$item.0|sanitize}</td> 20 + <td>{$item.0|sanitize}
  21 + {if $item.2}
  22 + <b>({$item.2})</b>
  23 + {/if}</td>
21 <td>{$item.1|sanitize}</td> 24 <td>{$item.1|sanitize}</td>
22 </tr> 25 </tr>
23 {/foreach} 26 {/foreach}
@@ -42,7 +45,10 @@ @@ -42,7 +45,10 @@
42 45
43 {foreach from=$list.documents item=item} 46 {foreach from=$list.documents item=item}
44 <tr class="{cycle values=even,odd}"> 47 <tr class="{cycle values=even,odd}">
45 - <td>{$item.0|sanitize}</td> 48 + <td>{$item.0|sanitize}
  49 + {if $item.2}
  50 + <b>({$item.2})</b>
  51 + {/if}</td>
46 <td>{$item.1|sanitize}</td> 52 <td>{$item.1|sanitize}</td>
47 </tr> 53 </tr>
48 {/foreach} 54 {/foreach}
@@ -50,4 +56,4 @@ @@ -50,4 +56,4 @@
50 </table> 56 </table>
51 {/if} 57 {/if}
52 58
53 -{$form->render()} 59 -{$form->render()}
  60 +{$form->render()}
54 \ No newline at end of file 61 \ No newline at end of file
templates/ktcore/bulk_action_confirm.smarty 0 → 100755
  1 +<h2>{$context->getDisplayName()}</h2>
  2 +
  3 +{$form->render()}
templates/ktcore/bulk_action_listing.smarty
@@ -59,7 +59,11 @@ @@ -59,7 +59,11 @@
59 <h3>{i18n}Folders{/i18n}</h3> 59 <h3>{i18n}Folders{/i18n}</h3>
60 <ul> 60 <ul>
61 {foreach from=$folders item=folder} 61 {foreach from=$folders item=folder}
62 -<li>{$folder|sanitize}</li> 62 +<li>{$folder.name|sanitize}
  63 +{if $folder.notice}
  64 + <b>({$folder.notice})</b>
  65 +{/if}
  66 +</li>
63 {/foreach} 67 {/foreach}
64 </ul> 68 </ul>
65 {/if} 69 {/if}
@@ -68,7 +72,11 @@ @@ -68,7 +72,11 @@
68 <h3>{i18n}Documents{/i18n}</h3> 72 <h3>{i18n}Documents{/i18n}</h3>
69 <ul> 73 <ul>
70 {foreach from=$documents item=document} 74 {foreach from=$documents item=document}
71 -<li>{$document|sanitize}</li> 75 +<li>{$document.name|sanitize}
  76 +{if $document.notice}
  77 + <b>({$document.notice})</b>
  78 +{/if}
  79 +</li>
72 {/foreach} 80 {/foreach}
73 </ul> 81 </ul>
74 {/if} 82 {/if}
@@ -86,4 +94,4 @@ @@ -86,4 +94,4 @@
86 {$failedform->render()} 94 {$failedform->render()}
87 {else} 95 {else}
88 {$form->render()} 96 {$form->render()}
89 -{/if} 97 -{/if}
  98 +{/if}
90 \ No newline at end of file 99 \ No newline at end of file
templates/ktcore/folder/shortcut.smarty 0 → 100755
  1 +<h2>{i18n}Add Shortcut{/i18n}</h2>
  2 +
  3 +
  4 +<p class="descriptiveText">{i18n}Select a document or folder to make a shortcut to.{/i18n}
  5 +</p>
  6 +
  7 +{foreach from=$breadcrumbs item=breadcrumb name=bc}
  8 + {if !$smarty.foreach.bc.last}
  9 + <a href="{$breadcrumb.url}">{$breadcrumb.name|sanitize}</a> &raquo;
  10 + {else}
  11 + {$breadcrumb.name|sanitize}
  12 + {/if}
  13 +{/foreach}
  14 +
  15 +<form method="POST" action="{$smarty.server.PHP_SELF|addQueryString:"postExpected=1&fFolderId="}{$folder->getId()}">
  16 +{$collection->render()}
  17 +<div class="form_actions">
  18 +<input type="hidden" name="action" value="add" />
  19 +<input type="submit" name="submit[addshortcut]" value="{i18n}Add shortcut{/i18n}" />
  20 +</div>
  21 +</form>
view.php
@@ -152,7 +152,20 @@ class ViewDocumentDispatcher extends KTStandardDispatcher { @@ -152,7 +152,20 @@ class ViewDocumentDispatcher extends KTStandardDispatcher {
152 ); 152 );
153 153
154 $this->oDocument =& $oDocument; 154 $this->oDocument =& $oDocument;
155 - $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForDocument($oDocument, $aOptions)); 155 +
  156 + //Figure out if we came here by navigating trough a shortcut.
  157 + //If we came here from a shortcut, the breadcrumbspath should be relative
  158 + //to the shortcut folder.
  159 + $iSymLinkFolderId = KTUtil::arrayGet($_REQUEST, 'fShortcutFolder', null);
  160 + if(is_numeric($iSymLinkFolderId)){
  161 + $oBreadcrumbsFolder = Folder::get($iSymLinkFolderId);
  162 + $aOptions['final'] = false;
  163 + $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForFolder($oBreadcrumbsFolder,$aOptions));
  164 + $this->aBreadcrumbs[] = array('name'=>$this->oDocument->getName());
  165 + }else{
  166 + $this->aBreadcrumbs = kt_array_merge($this->aBreadcrumbs, KTBrowseUtil::breadcrumbsForDocument($oDocument, $aOptions, $iSymLinkFolderId));
  167 + }
  168 +
156 $this->oPage->setBreadcrumbDetails(_kt('document details')); 169 $this->oPage->setBreadcrumbDetails(_kt('document details'));
157 $this->addPortlets('Document Details'); 170 $this->addPortlets('Document Details');
158 171