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 6 * Document Management Made Simple
7 7 * Copyright (C) 2008 KnowledgeTree Inc.
8 8 * Portions copyright The Jam Warehouse Software (Pty) Limited
9   - *
  9 + *
10 10 * This program is free software; you can redistribute it and/or modify it under
11 11 * the terms of the GNU General Public License version 3 as published by the
12 12 * Free Software Foundation.
13   - *
  13 + *
14 14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 17 * details.
18   - *
  18 + *
19 19 * You should have received a copy of the GNU General Public License
20 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 23 * California 94120-7775, or email info@knowledgetree.com.
24   - *
  24 + *
25 25 * The interactive user interfaces in modified source and object code versions
26 26 * of this program must display Appropriate Legal Notices, as required under
27 27 * Section 5 of the GNU General Public License version 3.
28   - *
  28 + *
29 29 * In accordance with Section 7(b) of the GNU General Public License version 3,
30 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 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 34 * copyright notice.
35 35 * Contributor( s): ______________________________________
36 36 */
... ... @@ -68,196 +68,209 @@ $sectionName = &#39;browse&#39;;
68 68  
69 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 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 211 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectField')),
201   - array('name' => $oField->getName(),
  212 + array('name' => $oField->getName(),
202 213 'url' => KTUtil::addQueryString($_SERVER['PHP_SELF'], 'action=selectLookup&fField=' . $oField->getId())),
203   - array('name' => $oValue->getName(),
  214 + array('name' => $oValue->getName(),
204 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 263 'rangename' => 'selection',
251 264 'show_folders' => true,
252 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 274 'context' => $this,
262 275 'collection' => $collection,
263 276 'browse_mode' => $this->browse_mode,
... ... @@ -265,160 +278,160 @@ class BrowseDispatcher extends KTStandardDispatcher {
265 278 'bulkactions' => $aBulkActions,
266 279 'browseutil' => new KTBrowseUtil(),
267 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 303 'context' => $this,
291 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 324 'context' => $this,
312 325 'oField' => $oField,
313 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 345 'context' => $this,
333 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 368 'userid' => $this->oUser->getId(),
356 369 'datetime' => date('Y-m-d H:i:s', time()),
357 370 'actionnamespace' => 'ktcore.user_history.enable_admin_mode',
358 371 'comments' => 'Admin Mode enabled',
359 372 'sessionid' => $_SESSION['sessionID'],
360   - ));
361   - $aOpts = array(
  373 + ));
  374 + $aOpts = array(
362 375 'redirect_to' => 'main',
363 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 412 'userid' => $this->oUser->getId(),
400 413 'datetime' => date('Y-m-d H:i:s', time()),
401 414 'actionnamespace' => 'ktcore.user_history.disable_admin_mode',
402 415 'comments' => 'Admin Mode disabled',
403 416 'sessionid' => $_SESSION['sessionID'],
404   - ));
405   - $aOpts = array(
  417 + ));
  418 + $aOpts = array(
406 419 'redirect_to' => 'main',
407 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 437 $oDispatcher = new BrowseDispatcher();
... ...
ktapi/KTAPIDocument.inc.php
... ... @@ -113,8 +113,28 @@ class KTAPI_Document extends KTAPI_FolderItem
113 113 {
114 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 138 * This is the constructor for the KTAPI_Folder.
119 139 *
120 140 * @access private
... ... @@ -1478,7 +1498,7 @@ class KTAPI_Document extends KTAPI_FolderItem
1478 1498  
1479 1499 $detail = array();
1480 1500 $document = $this->document;
1481   -
  1501 +
1482 1502 // get the document id
1483 1503 $detail['document_id'] = (int) $document->getId();
1484 1504  
... ... @@ -1601,6 +1621,12 @@ class KTAPI_Document extends KTAPI_FolderItem
1601 1621 {
1602 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 1631 // check immutability
1606 1632 $detail['is_immutable'] = (bool) $document->getImmutable();
... ... @@ -1651,7 +1677,10 @@ class KTAPI_Document extends KTAPI_FolderItem
1651 1677 unset($detail['updated_by']);
1652 1678 unset($detail['updated_date']);
1653 1679 }
1654   -
  1680 + if($wsversion < 3){
  1681 + unset($detail['linked_document_id']);
  1682 + }
  1683 +
1655 1684 return $detail;
1656 1685 }
1657 1686  
... ...
ktapi/KTAPIFolder.inc.php
... ... @@ -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 119 * This is the constructor for the KTAPI_Folder.
101 120 *
102 121 * @access private
... ... @@ -131,13 +150,22 @@ class KTAPI_Folder extends KTAPI_FolderItem
131 150 function get_detail()
132 151 {
133 152 $this->clearCache();
  153 +
  154 + $config = KTConfig::getSingleton();
  155 + $wsversion = $config->get('webservice/version', LATEST_WEBSERVICE_VERSION);
  156 +
134 157 $detail = array(
135 158 'id'=>(int) $this->folderid,
136 159 'folder_name'=>$this->get_folder_name(),
137 160 'parent_id'=>(int) $this->get_parent_folder_id(),
138 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 169 return $detail;
142 170 }
143 171  
... ... @@ -340,7 +368,7 @@ class KTAPI_Folder extends KTAPI_FolderItem
340 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 373 if ($depth < 1)
346 374 {
... ... @@ -359,8 +387,8 @@ class KTAPI_Folder extends KTAPI_FolderItem
359 387  
360 388 $contents = array();
361 389  
362   - if (strpos($what,'F') !== false)
363   - {
  390 +
  391 +
364 392 $folder_children = Folder::getList(array('parent_id = ?', $this->folderid));
365 393  
366 394 foreach ($folder_children as $folder)
... ... @@ -383,7 +411,7 @@ class KTAPI_Folder extends KTAPI_FolderItem
383 411  
384 412 if ($wsversion >= 2)
385 413 {
386   - $contents[] = array(
  414 + $array = array(
387 415 'id' => (int) $folder->getId(),
388 416 'item_type' => 'F',
389 417  
... ... @@ -420,9 +448,19 @@ class KTAPI_Folder extends KTAPI_FolderItem
420 448  
421 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 465 else
428 466 {
... ... @@ -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 493 $document_children = Document::getList(array('folder_id = ? AND status_id = 1', $this->folderid));
457 494  
458 495 // I hate that KT doesn't cache things nicely...
... ... @@ -517,7 +554,7 @@ class KTAPI_Folder extends KTAPI_FolderItem
517 554 if (empty($oemDocumentNo)) $oemDocumentNo = 'n/a';
518 555  
519 556  
520   - $contents[] = array(
  557 + $array = array(
521 558 'id' => (int) $document->getId(),
522 559 'item_type' => 'D',
523 560  
... ... @@ -553,10 +590,22 @@ class KTAPI_Folder extends KTAPI_FolderItem
553 590 'mime_display' => $mime_cache[$mimetypeid]['display'],
554 591  
555 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 610 else
562 611 {
... ... @@ -586,12 +635,74 @@ class KTAPI_Folder extends KTAPI_FolderItem
586 635 }
587 636 }
588 637  
589   - }
  638 +
590 639  
591 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 706 * This adds a document to the current folder.
596 707 *
597 708 * @access public
... ...
ktwebservice/webservice.php
... ... @@ -10,31 +10,31 @@
10 10 * Document Management Made Simple
11 11 * Copyright (C) 2008 KnowledgeTree Inc.
12 12 * Portions copyright The Jam Warehouse Software (Pty) Limited
13   - *
  13 + *
14 14 * This program is free software; you can redistribute it and/or modify it under
15 15 * the terms of the GNU General Public License version 3 as published by the
16 16 * Free Software Foundation.
17   - *
  17 + *
18 18 * This program is distributed in the hope that it will be useful, but WITHOUT
19 19 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
20 20 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
21 21 * details.
22   - *
  22 + *
23 23 * You should have received a copy of the GNU General Public License
24 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 27 * California 94120-7775, or email info@knowledgetree.com.
28   - *
  28 + *
29 29 * The interactive user interfaces in modified source and object code versions
30 30 * of this program must display Appropriate Legal Notices, as required under
31 31 * Section 5 of the GNU General Public License version 3.
32   - *
  32 + *
33 33 * In accordance with Section 7(b) of the GNU General Public License version 3,
34 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 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 38 * copyright notice.
39 39 * Contributor( s): ______________________________________
40 40 *
... ... @@ -173,6 +173,9 @@ class KTWebService
173 173 {
174 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 180 $this->__typedef["{urn:$this->namespace}kt_folder_item"] =
178 181 array(
... ... @@ -235,8 +238,14 @@ class KTWebService
235 238  
236 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 251 $this->__typedef["{urn:$this->namespace}kt_folder_items"] =
... ... @@ -327,6 +336,10 @@ class KTWebService
327 336 'version_history' => "{urn:$this->namespace}kt_document_version_history",
328 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 345 if (defined('HAS_SEARCH_FUNCTIONALITY'))
... ... @@ -474,14 +487,14 @@ class KTWebService
474 487 'message'=>'string',
475 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 492 array(
480 493 array(
481 494 'workflow' => 'string'
482 495 )
483 496 );
484   -
  497 +
485 498 $this->__typedef["{urn:$this->namespace}kt_workflows_response"] =
486 499 array(
487 500 'status_code' => 'int',
... ... @@ -545,6 +558,62 @@ class KTWebService
545 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 618 $this->__typedef["{urn:$this->namespace}kt_document_transaction_history_response"] =
550 619 array(
... ... @@ -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 912 // add_document
825 913 $this->__dispatch_map['add_document'] =
826 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 1211 array('in' => array('session_id'=>'string' ),
1124 1212 'out' => array( 'return' => "{urn:$this->namespace}kt_document_types_response" ),
1125 1213 );
1126   -
1127   - // get_workflows
  1214 +
  1215 + // get_workflows
1128 1216 $this->__dispatch_map['get_workflows'] =
1129 1217 array('in' => array('session_id'=>'string' ),
1130 1218 'out' => array( 'return' => "{urn:$this->namespace}kt_workflows_response" ),
... ... @@ -1333,6 +1421,66 @@ class KTWebService
1333 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 1485 * Returns folder detail given a folder name which could include a full path.
1338 1486 *
... ... @@ -1394,7 +1542,7 @@ class KTWebService
1394 1542 * @param string $what
1395 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 1547 $this->debug("get_folder_contents('$session_id',$folder_id,$depth,'$what')");
1400 1548 $kt = &$this->get_ktapi($session_id);
... ... @@ -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 1729 * Deletes a folder.
1475 1730 *
1476 1731 * @param string $session_id
... ... @@ -1928,6 +2183,65 @@ class KTWebService
1928 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 2246 * Adds a document to the repository.
1933 2247 *
... ... @@ -3460,7 +3774,7 @@ class KTWebService
3460 3774  
3461 3775 return new SOAP_Value('return',"{urn:$this->namespace}$responseType", $response);
3462 3776 }
3463   -
  3777 +
3464 3778 /**
3465 3779 * Returns a list of available workflows
3466 3780 *
... ... @@ -3475,9 +3789,9 @@ class KTWebService
3475 3789 {
3476 3790 return new SOAP_Value('return',"{urn:$this->namespace}kt_workflows_response", $kt);
3477 3791 }
3478   -
  3792 +
3479 3793 $response = KTWebService::_status(KTWS_ERR_PROBLEM);
3480   -
  3794 +
3481 3795 $result = $kt->get_workflows();
3482 3796 if (PEAR::isError($result))
3483 3797 {
... ... @@ -4134,4 +4448,4 @@ class KTWebService
4134 4448 $webservice = new KTWebService();
4135 4449 $webservice->run();
4136 4450  
4137 4451 -?>
  4452 +?>
4138 4453 \ No newline at end of file
... ...
lib/actions/bulkaction.php
... ... @@ -151,7 +151,13 @@ class KTBulkAction extends KTStandardDispatcher {
151 151  
152 152 foreach($aIds as $id) {
153 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 162 return $aNames;
157 163 } else {
... ... @@ -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 214 // doesn't actually do checks, as they have to be performed per-entity
164 215 function check() {
165 216 // not necessarily coming from a folder...
... ... @@ -249,11 +300,17 @@ class KTBulkAction extends KTStandardDispatcher {
249 300 }
250 301  
251 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 310 if(PEAR::isError($res)) {
254   - $this->aActionResults['documents'][] = array($sName, $res->getMessage());
  311 + $this->aActionResults['documents'][] = array($sName, $res->getMessage(), $notice);
255 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 324  
268 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 333 if(PEAR::isError($res)) {
271   - $this->aActionResults['folders'][] = array($sName, $res->getMessage());
  334 + $this->aActionResults['folders'][] = array($sName, $res->getMessage(), $notice);
272 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 59 \ No newline at end of file
... ...
lib/alert/delivery/EmailAlert.inc
... ... @@ -67,6 +67,10 @@ class EmailAlert {
67 67 function send() {
68 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 74 if ($this->oEmail->send($this->sAddress, $this->sSubject, $this->sContent)) {
71 75 $default->log->debug("EmailAlert::EmailAlert successfully sent email to $this->sAddress");
72 76 return true;
... ...
lib/browse/PartialQuery.inc.php
... ... @@ -94,14 +94,16 @@ class BrowseQuery extends PartialQuery{
94 94 // FIXME cache permission lookups, etc.
95 95 var $folder_id = -1;
96 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 100 $this->folder_id = $iFolderId;
100 101 if (is_null($oUser)) {
101 102 $oUser = User::get($_SESSION['userID']);
102 103 }
103 104 $this->oUser =& $oUser;
104 105 $this->aOptions = $aOptions;
  106 + $this->exclude_shortcuts = $excludeShortcuts;
105 107 if (KTUtil::arrayGet($aOptions, 'ignorepermissions')) {
106 108 $this->oUser = null;
107 109 }
... ... @@ -116,6 +118,10 @@ class BrowseQuery extends PartialQuery{
116 118 list($sPermissionString, $aPermissionParams, $sPermissionJoin) = $res;
117 119 $aPotentialWhere = array($sPermissionString, 'D.folder_id = ?', 'D.status_id = 1');
118 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 125 foreach ($aPotentialWhere as $sWhere) {
120 126 if (empty($sWhere)) {
121 127 continue;
... ... @@ -157,6 +163,10 @@ class BrowseQuery extends PartialQuery{
157 163  
158 164 $aPotentialWhere = array($sPermissionString, 'F.parent_id = ?');
159 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 170 foreach ($aPotentialWhere as $sWhere) {
161 171 if (empty($sWhere)) {
162 172 continue;
... ...
lib/browse/browseutil.inc.php
... ... @@ -261,13 +261,15 @@ class KTBrowseUtil {
261 261 // }}}
262 262  
263 263 // {{{ breadcrumbsForDocument
264   - function breadcrumbsForDocument($oDocument, $aOptions = null) {
  264 + function breadcrumbsForDocument($oDocument, $aOptions = null, $iFolderId = null) {
265 265 $bFinal = KTUtil::arrayGet($aOptions, 'final', true, false);
266 266 $aOptions = KTUtil::meldOptions($aOptions, array(
267 267 'final' => false,
268 268 ));
269 269  
270   - $iFolderId = $oDocument->getFolderId();
  270 + if($iFolderId == null){
  271 + $iFolderId = $oDocument->getFolderId();
  272 + }
271 273 $aBreadcrumbs = KTBrowseUtil::breadcrumbsForFolder($iFolderId, $aOptions);
272 274  
273 275  
... ...
lib/documentmanagement/Document.inc
... ... @@ -110,6 +110,8 @@ class Document {
110 110  
111 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 116 // Document Metadata Items
115 117  
... ... @@ -167,7 +169,81 @@ class Document {
167 169  
168 170 function getStoragePath() { return $this->_oDocumentContentVersion->getStoragePath(); }
169 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 249 // {{{ getParentID
... ... @@ -233,11 +309,18 @@ class Document {
233 309 // }}}
234 310  
235 311 // {{{ load
236   - function load($iId, $iMetadataVersionId = null) {
  312 + function load($iId, $iMetadataVersionId = null) {
237 313 $this->iId = $iId;
238 314 $this->_oDocumentCore = KTDocumentCore::get($iId);
239 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 324 // FIXME add error $res if MDV > $_oDC->getMDV
242 325 if (is_null($iMetadataVersionId)) {
243 326 $this->_oDocumentMetadataVersion = KTDocumentMetadataVersion::get($this->_oDocumentCore->getMetadataVersionId());
... ...
lib/documentmanagement/documentcore.inc.php
... ... @@ -84,6 +84,9 @@ class KTDocumentCore extends KTEntity {
84 84 var $dCheckedOut;
85 85  
86 86 var $sOemNo;
  87 +
  88 + /** ID of the document this document links to(if any) */
  89 + var $iLinkedDocumentId;
87 90  
88 91 var $_aFieldToSelect = array(
89 92 "iId" => "id",
... ... @@ -118,7 +121,8 @@ class KTDocumentCore extends KTEntity {
118 121 'sRestoreFolderPath' => 'restore_folder_path',
119 122  
120 123 'dCheckedOut'=>'checkedout',
121   - 'sOemNo'=>'oem_no'
  124 + 'sOemNo'=>'oem_no',
  125 + 'iLinkedDocumentId' => 'linked_document_id'
122 126 );
123 127  
124 128 function KTDocumentCore() {
... ... @@ -173,6 +177,46 @@ class KTDocumentCore extends KTEntity {
173 177  
174 178 function getRestoreFolderPath() { return $this->sRestoreFolderPath; }
175 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 222 // {{{ getParentId
... ... @@ -291,7 +335,7 @@ class KTDocumentCore extends KTEntity {
291 335 // {{{ update
292 336 function update($bPathMove = false) {
293 337 //var_dump($this); exit(0);
294   - $res = parent::update();
  338 + $res = parent::update();
295 339  
296 340 if (($res === true) && ($bPathMove === true)) {
297 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 55 require_once(KT_LIB_DIR . '/subscriptions/subscriptions.inc.php');
56 56 require_once(KT_LIB_DIR . '/triggers/triggerregistry.inc.php');
57 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 61 // WORKFLOW
60 62 require_once(KT_LIB_DIR . '/workflow/workflowutil.inc.php');
... ... @@ -167,6 +169,10 @@ class KTDocumentUtil {
167 169 }
168 170  
169 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 176 if ($oDocument->getIsCheckedOut()) {
171 177 return PEAR::raiseError(_kt('Already checked out.'));
172 178 }
... ... @@ -213,6 +219,24 @@ class KTDocumentUtil {
213 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 240 $oDocumentTransaction = & new DocumentTransaction($oDocument, sprintf(_kt('Document archived: %s'), $sReason), 'ktcore.transactions.update');
217 241 $oDocumentTransaction->create();
218 242  
... ... @@ -303,6 +327,130 @@ class KTDocumentUtil {
303 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 454 // Overwrite the document
307 455 function overwrite($oDocument, $sFilename, $sTempFileName, $oUser, $aOptions) {
308 456 //$oDocument, $sFilename, $sCheckInComment, $oUser, $aOptions = false
... ... @@ -838,6 +986,12 @@ class KTDocumentUtil {
838 986  
839 987 // {{{ delete
840 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 995 $oDocument =& KTUtil::getObject('Document', $oDocument);
842 996 if (is_null($iDestFolderId)) {
843 997 $iDestFolderId = $oDocument->getFolderID();
... ... @@ -904,6 +1058,24 @@ class KTDocumentUtil {
904 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 1079 $oDocumentTransaction = new DocumentTransaction($oDocument, _kt('Document deleted: ') . $sReason, 'ktcore.transactions.delete');
908 1080 $oDocumentTransaction->create();
909 1081  
... ... @@ -1166,7 +1338,12 @@ class KTDocumentUtil {
1166 1338 }
1167 1339  
1168 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 1347 $oFolder = $oToFolder; // alias.
1171 1348  
1172 1349 $oOriginalFolder = Folder::get($oDocument->getFolderId());
... ... @@ -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 1379 $sMoveMessage = sprintf(_kt("Moved from %s/%s to %s/%s. %s"),
1201 1380 $oOriginalFolder->getFullPath(),
1202 1381 $oOriginalFolder->getName(),
... ...
lib/foldermanagement/Folder.inc
... ... @@ -65,6 +65,8 @@ class Folder extends KTEntity {
65 65 var $iPermissionLookupID;
66 66 /** whether to restrict to only certain document types */
67 67 var $bRestrictDocumentTypes = false;
  68 + /** ID of the folder this is a shortcut to(if any) */
  69 + var $iLinkedFolderId;
68 70  
69 71 // {{{ KTEntity stuff
70 72 var $_aFieldToSelect = array(
... ... @@ -79,6 +81,7 @@ class Folder extends KTEntity {
79 81 'iPermissionObjectID' => 'permission_object_id',
80 82 'iPermissionLookupID' => 'permission_lookup_id',
81 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 107 function getRestrictDocumentTypes() { return $this->bRestrictDocumentTypes; }
105 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 115 // {{{ create()
108 116 function create () {
109 117 $oParentFolder =& Folder::get($this->iParentID);
... ... @@ -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 140 * Returns a comma delimited string containing the parent folder ids, strips leading /
121 141 *
... ... @@ -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 389 * Static function
313 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 45 require_once(KT_LIB_DIR . '/users/User.inc');
46 46  
47 47 require_once(KT_LIB_DIR . '/foldermanagement/foldertransaction.inc.php');
  48 +require_once(KT_LIB_DIR . '/browse/browseutil.inc.php');
48 49  
49 50 require_once(KT_LIB_DIR . '/database/dbutil.inc');
50 51  
... ... @@ -401,7 +402,17 @@ class KTFolderUtil {
401 402 DBUtil::rollback();
402 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 416 // purge caches
406 417 KTEntityUtil::clearAllCaches('Folder');
407 418  
... ... @@ -573,6 +584,125 @@ class KTFolderUtil {
573 584  
574 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 304 $is_a_folder = is_a($oFolderOrDocument, 'Folder');
305 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 312 $oChannel = null;
308 313 $aMapPermAllowed = null;
309 314 $oPermLookup = null;
... ... @@ -325,7 +330,12 @@ class KTPermissionUtil {
325 330 $msg = sprintf("Updating folder %s", join('/', $oFolderOrDocument->getPathArray()));
326 331 } else {
327 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 339 } else {
330 340 $msg = sprintf("Updating document %d", $oFolderOrDocument->getId());
331 341 }
... ...
plugins/ktcore/KTBulkActions.php
... ... @@ -92,14 +92,68 @@ class KTBulkDeleteAction extends KTBulkAction {
92 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 139 // info collection step
96 140 function do_collectinfo() {
97 141 $this->store_lists();
98 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 518 if((!is_a($oEntity, 'Document')) && (!is_a($oEntity, 'Folder'))) {
465 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 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 571 // info collection step
471 572 function do_collectinfo() {
472 573 $this->store_lists();
473 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 586 return $oTemplate->render(array('context' => $this,
477 587 'form' => $this->form_collectinfo()));
478 588 }
... ... @@ -637,6 +747,9 @@ class KTBrowseBulkExportAction extends KTBulkAction {
637 747 if(is_a($oEntity, 'Document')) {
638 748  
639 749 $oDocument = $oEntity;
  750 + if($oDocument->isSymbolicLink()){
  751 + $oDocument->switchToLinkedCore();
  752 + }
640 753  
641 754 if ($this->bNoisy) {
642 755 $oDocumentTransaction = new DocumentTransaction($oDocument, "Document part of bulk export", 'ktstandard.transactions.bulk_export', array());
... ... @@ -932,7 +1045,6 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction {
932 1045 return $ret;
933 1046 }
934 1047 }
935   -
936 1048 $this->oZip->addDocumentToZip($oEntity);
937 1049 }
938 1050  
... ... @@ -1066,4 +1178,4 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction {
1066 1178 }
1067 1179 }
1068 1180  
1069 1181 -?>
  1182 +?>
1070 1183 \ No newline at end of file
... ...
plugins/ktcore/KTColumns.inc.php
... ... @@ -112,7 +112,18 @@ class AdvancedTitleColumn extends AdvancedColumn {
112 112 }
113 113  
114 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 133  
123 134 function buildFolderLink($aDataRow) {
124 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 146 if (empty($dest)) {
130 147 return KTUtil::addQueryStringSelf($params);
... ... @@ -133,7 +150,11 @@ class AdvancedTitleColumn extends AdvancedColumn {
133 150 }
134 151  
135 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 163 if ($aDataRow["type"] == "folder") {
143 164 $contenttype = 'folder';
144 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 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 390 }
360 391  
361 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 398 return '&nbsp;';
363 399 }
364 400  
... ... @@ -380,7 +416,12 @@ class AdvancedSingleSelectionColumn extends AdvancedSelectionColumn {
380 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 427 // no label, but we do have a title
... ...
plugins/ktcore/KTDocumentActions.php
... ... @@ -853,15 +853,31 @@ class KTDocumentDeleteAction extends KTDocumentAction {
853 853 $_SESSION['KTErrorMessage'][]= _kt('This document can\'t be deleted because it is checked out');
854 854 controllerRedirect('viewDocument', 'fDocumentId=' . $this->oDocument->getId());
855 855 exit(0);
856   - }
  856 + }
  857 +
857 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 877 function form_main() {
862 878 $oForm = new KTForm;
863 879 $oForm->setOptions(array(
864   - 'label' => _kt('Delete Document'),
  880 + 'label' => _kt('Delete Document'),
865 881 'action' => 'delete',
866 882 'fail_action' => 'main',
867 883 'cancel_url' => KTBrowseUtil::getUrlForDocument($this->oDocument),
... ... @@ -888,16 +904,29 @@ class KTDocumentDeleteAction extends KTDocumentAction {
888 904  
889 905 function do_main() {
890 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 911 $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/delete');
892   -
893 912 $oForm = $this->form_main();
894   -
895 913 $oTemplate->setData(array(
896 914 'context' => &$this,
897 915 'form' => $oForm,
898 916 ));
899 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 931 function do_delete() {
903 932 $oForm = $this->form_main();
... ... @@ -1346,6 +1375,22 @@ class KTDocumentArchiveAction extends KTDocumentAction {
1346 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 1394 function form_main() {
1350 1395 $oForm = new KTForm;
1351 1396 $oForm->setOptions(array(
... ... @@ -1375,6 +1420,10 @@ class KTDocumentArchiveAction extends KTDocumentAction {
1375 1420 }
1376 1421  
1377 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 1427 $this->oPage->setBreadcrumbDetails(_kt('Archive Document'));
1379 1428 $oTemplate =& $this->oValidator->validateTemplate('ktcore/action/archive');
1380 1429  
... ... @@ -1386,6 +1435,17 @@ class KTDocumentArchiveAction extends KTDocumentAction {
1386 1435 ));
1387 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 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 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 5 -- Document Management Made Simple
6 6 -- Copyright (C) 2008 KnowledgeTree Inc.
7 7 -- Portions copyright The Jam Warehouse Software (Pty) Limited
8   ---
  8 +--
9 9 -- This program is free software; you can redistribute it and/or modify it under
10 10 -- the terms of the GNU General Public License version 3 as published by the
11 11 -- Free Software Foundation.
12   ---
  12 +--
13 13 -- This program is distributed in the hope that it will be useful, but WITHOUT
14 14 -- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 15 -- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
16 16 -- details.
17   ---
  17 +--
18 18 -- You should have received a copy of the GNU General Public License
19 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 22 -- California 94120-7775, or email info@knowledgetree.com.
23   ---
  23 +--
24 24 -- The interactive user interfaces in modified source and object code versions
25 25 -- of this program must display Appropriate Legal Notices, as required under
26 26 -- Section 5 of the GNU General Public License version 3.
27   ---
  27 +--
28 28 -- In accordance with Section 7(b) of the GNU General Public License version 3,
29 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 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 33 -- copyright notice.
34 34 -- Contributor( s): ______________________________________
35 35 --
... ... @@ -578,6 +578,7 @@ CREATE TABLE `documents` (
578 578 `restore_folder_path` text,
579 579 `checkedout` datetime default NULL,
580 580 `oem_no` varchar(255) default NULL,
  581 + `linked_document_id` int(11),
581 582 PRIMARY KEY (`id`),
582 583 KEY `creator_id` (`creator_id`),
583 584 KEY `folder_id` (`folder_id`),
... ... @@ -813,6 +814,7 @@ CREATE TABLE `folders` (
813 814 `permission_lookup_id` int(11) default NULL,
814 815 `restrict_document_types` tinyint(1) NOT NULL default '0',
815 816 `owner_id` int(11) default NULL,
  817 + `linked_folder_id` int(11),
816 818 PRIMARY KEY (`id`),
817 819 KEY `creator_id` (`creator_id`),
818 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 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 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 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 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 4 \ No newline at end of file
... ...
templates/ktcore/bulk_action_complete.smarty
... ... @@ -17,7 +17,10 @@
17 17 <tbody>
18 18 {foreach from=$list.folders item=item}
19 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 24 <td>{$item.1|sanitize}</td>
22 25 </tr>
23 26 {/foreach}
... ... @@ -42,7 +45,10 @@
42 45  
43 46 {foreach from=$list.documents item=item}
44 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 52 <td>{$item.1|sanitize}</td>
47 53 </tr>
48 54 {/foreach}
... ... @@ -50,4 +56,4 @@
50 56 </table>
51 57 {/if}
52 58  
53 59 -{$form->render()}
  60 +{$form->render()}
54 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 59 <h3>{i18n}Folders{/i18n}</h3>
60 60 <ul>
61 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 67 {/foreach}
64 68 </ul>
65 69 {/if}
... ... @@ -68,7 +72,11 @@
68 72 <h3>{i18n}Documents{/i18n}</h3>
69 73 <ul>
70 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 80 {/foreach}
73 81 </ul>
74 82 {/if}
... ... @@ -86,4 +94,4 @@
86 94 {$failedform->render()}
87 95 {else}
88 96 {$form->render()}
89 97 -{/if}
  98 +{/if}
90 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 152 );
153 153  
154 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 169 $this->oPage->setBreadcrumbDetails(_kt('document details'));
157 170 $this->addPortlets('Document Details');
158 171  
... ...