Commit 3f0f6da41a8d5a8eaef9901c8c429e1260f9a3b7

Authored by Kevin G Fourie
2 parents 85c8a845 cae7096f

Merge branch 'master' of git@github.com:ktgit/knowledgetree

bin/luceneserver/ktlucene.jar
No preview for this file type
ktapi/KTAPIDocument.inc.php
... ... @@ -1980,6 +1980,8 @@ class KTAPI_Document extends KTAPI_FolderItem
1980 1980 {
1981 1981 $detail['version'] = (float) $detail['version'];
1982 1982 }
  1983 + //get the content_id
  1984 + $detail['content_id'] = $document->getContentVersionId();
1983 1985  
1984 1986 //might be unset at the bottom in case of old webservice version
1985 1987 //make sure we're using the real document for this one
... ...
ktapi/KTAPIFolder.inc.php
... ... @@ -689,6 +689,7 @@ class KTAPI_Folder extends KTAPI_FolderItem
689 689 'owned_by' => is_null($owned_by)?'n/a':$owned_by->getName(),
690 690  
691 691 'version' => $document->getMajorVersionNumber() . '.' . $document->getMinorVersionNumber(),
  692 + 'content_id' => $document->getContentVersionId(),
692 693  
693 694 'is_immutable'=> $document->getImmutable()?'true':'false',
694 695 'permissions' => KTAPI_Document::get_permission_string($document),
... ...
lib/actions/bulkaction.php
1   -<?php
2   -
3   -/**
4   - * $Id$
5   - *
6   - * KnowledgeTree Community Edition
7   - * Document Management Made Simple
8   - * Copyright (C) 2008, 2009 KnowledgeTree Inc.
9   - * Portions copyright The Jam Warehouse Software (Pty) Limited
10   - *
11   - * This program is free software; you can redistribute it and/or modify it under
12   - * the terms of the GNU General Public License version 3 as published by the
13   - * Free Software Foundation.
14   - *
15   - * This program is distributed in the hope that it will be useful, but WITHOUT
16   - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17   - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18   - * details.
19   - *
20   - * You should have received a copy of the GNU General Public License
21   - * along with this program. If not, see <http://www.gnu.org/licenses/>.
22   - *
23   - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
24   - * California 94120-7775, or email info@knowledgetree.com.
25   - *
26   - * The interactive user interfaces in modified source and object code versions
27   - * of this program must display Appropriate Legal Notices, as required under
28   - * Section 5 of the GNU General Public License version 3.
29   - *
30   - * In accordance with Section 7(b) of the GNU General Public License version 3,
31   - * these Appropriate Legal Notices must retain the display of the "Powered by
32   - * KnowledgeTree" logo and retain the original copyright notice. If the display of the
33   - * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
34   - * must display the words "Powered by KnowledgeTree" and retain the original
35   - * copyright notice.
36   - * Contributor( s): ______________________________________
37   - *
38   - */
39   -
40   -require_once(KT_LIB_DIR . '/actions/actionregistry.inc.php');
41   -require_once(KT_LIB_DIR . '/workflow/workflowutil.inc.php');
42   -require_once(KT_LIB_DIR . '/dispatcher.inc.php');
43   -require_once(KT_LIB_DIR . '/browse/browseutil.inc.php');
44   -require_once(KT_LIB_DIR . '/actions/entitylist.php');
45   -
46   -require_once(KT_LIB_DIR . '/foldermanagement/folderutil.inc.php');
47   -require_once(KT_LIB_DIR . '/documentmanagement/documentutil.inc.php');
48   -
49   -require_once(KT_LIB_DIR . '/widgets/forms.inc.php');
50   -
51   -require_once(KT_LIB_DIR . "/util/sanitize.inc");
52   -
53   -class KTBulkAction extends KTStandardDispatcher {
54   - var $sName;
55   - var $sDescription;
56   -
57   - var $_sDisablePermission;
58   - var $bAllowInAdminMode = false;
59   - var $sHelpPage = 'ktcore/browse.html';
60   -
61   - var $sSection = 'view_details';
62   -
63   - var $_bMutator = false;
64   - var $_bMutationAllowedByAdmin = true;
65   -
66   - var $sIconClass;
67   -
68   - // not 'sShowPermission' - mass actions are always shown
69   - // this is used to check against individual entities
70   - var $_sPermission = 'ktcore.permissions.read';
71   -
72   - function KTBulkAction($oUser = null, $oPlugin = null) {
73   - $this->oEntityList = null;
74   - $this->oActiveEntityList = null;
75   - $this->oUser =& $oUser;
76   - $this->oPlugin =& $oPlugin;
77   -
78   - $this->aBreadcrumbs = array(
79   - array('action' => 'browse', 'name' => _kt('Browse')),
80   - );
81   -
82   - $this->persistParams('fEntityListCode');
83   - parent::KTStandardDispatcher();
84   - }
85   -
86   - function setEntityList(&$oEntityList) {
87   - $this->oEntityList =& $oEntityList;
88   - }
89   -
90   - function setUser(&$oUser) {
91   - $this->oUser =& $oUser;
92   - }
93   -
94   - function _show() {
95   - return true;
96   - }
97   -
98   - function getURL() {
99   - $oKTConfig =& KTConfig::getSingleton();
100   - $sExt = '.php';
101   - if (KTUtil::arrayGet($_SERVER, 'kt_no_extensions')) {
102   - $sExt = '';
103   - }
104   - if ($oKTConfig->get('KnowledgeTree/pathInfoSupport')) {
105   - return sprintf('%s/action%s/%s', $GLOBALS['KTRootUrl'], $sExt, $this->sName);
106   - } else {
107   - return sprintf('%s/action%s?kt_path_info=%s', $GLOBALS['KTRootUrl'], $sExt, $this->sName);
108   - }
109   - }
110   -
111   - function getInfo() {
112   - if ($this->_show() === false) {
113   - return null;
114   - }
115   -
116   - $url = $this->getURL();
117   -
118   - $aInfo = array(
119   - 'description' => $this->sDescription,
120   - 'name' => $this->getDisplayName(),
121   - 'ns' => $this->sName,
122   - 'url' => $url,
123   - 'icon_class' => $this->sIconClass,
124   - );
125   -
126   - $aInfo = $this->customiseInfo($aInfo);
127   - return $aInfo;
128   - }
129   -
130   - function getName() {
131   - return sanitizeForSQLtoHTML($this->sName);
132   - }
133   -
134   - function getDisplayName() {
135   - return sanitizeForSQLtoHTML($this->sDisplayName);
136   - }
137   -
138   - function getDescription() {
139   - return sanitizeForSQLtoHTML($this->sDescription);
140   - }
141   -
142   - function customiseInfo($aInfo) {
143   - return $aInfo;
144   - }
145   -
146   - // helper function
147   - function _getNames($aIds, $sEntity) {
148   - if(count($aIds)) {
149   - $aNames = array();
150   - $aFunc = array($sEntity, 'get');
151   -
152   - foreach($aIds as $id) {
153   - $oE =& call_user_func($aFunc, $id);
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;
161   - }
162   - return $aNames;
163   - } else {
164   - return array();
165   - }
166   - }
167   -
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   -/**
214   - * checks a folderList for shortcuts and queries the repositories for all folders
215   - * that are somehow connected to these folders.
216   - */
217   - function getLinkingEntities($aFolderList){
218   - $aSearchFolders = array();
219   - if(!empty($aFolderList)){
220   - foreach($aFolderList as $oFolderItem){
221   - if(Permission::userHasFolderReadPermission($oFolderItem)){
222   - // If it is a shortcut, we should do some more searching
223   - if($oFolderItem->isSymbolicLink()){
224   - $oFolderItem = $oFolderItem->getLinkedFolder();
225   - $aSearchFolders[] = $oFolderItem->getID();
226   - }
227   - }
228   - }
229   - }
230   - $aLinkingFolders = array();
231   - $aSearchCompletedFolders = array();
232   - $count = 0;
233   - while(count($aSearchFolders)>0){
234   - $count++;
235   - $oFolder = Folder::get(array_pop($aSearchFolders));
236   - $sFolderId = $oFolder->getId();
237   - // Get all the folders within the current folder
238   - $sWhereClause = "parent_folder_ids = '{$sFolderId}' OR
239   - parent_folder_ids LIKE '{$sFolderId},%' OR
240   - parent_folder_ids LIKE '%,{$sFolderId},%' OR
241   - parent_folder_ids LIKE '%,{$sFolderId}'";
242   - $aFolderList = $this->oFolder->getList($sWhereClause);
243   - foreach($aFolderList as $oFolderItem){
244   - if($oFolderItem->isSymbolicLink()){
245   - $oFolderItem = $oFolderItem->getLinkedFolder();
246   - }
247   - if(Permission::userHasFolderReadPermission($oFolderItem)){
248   - if($aSearchCompletedFolders[$oFolderItem->getID()] != true){
249   - $aSearchFolders[] = $oFolderItem->getID();
250   - $aSearchCompletedFolders[$oFolderItem->getID()] = true;
251   - }
252   - }
253   - }
254   - if(!isset($aLinkingFolders[$oFolder->getId()])){
255   - $aLinkingFolders[$oFolder->getId()] = $oFolder;
256   - }
257   - }
258   - return $aLinkingFolders;
259   - }
260   -
261   - // doesn't actually do checks, as they have to be performed per-entity
262   - function check() {
263   - // not necessarily coming from a folder...
264   - $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId', 1);
265   - $this->oFolder = Folder::get($iFolderId);
266   - //$this->oFolder =& $this->oValidator->validateFolder($_REQUEST['fFolderId']);
267   -
268   - $aOptions = array(
269   - 'final' => false,
270   - 'documentaction' => 'viewDocument',
271   - 'folderaction' => 'browse',
272   - );
273   -
274   - $this->aBreadcrumbs = array(array('name'=>_kt('Bulk Actions')),
275   - array('name'=>$this->getDisplayName()));
276   -
277   - return true;
278   - }
279   -
280   -
281   - // check the entire entity list. this needn't be overrided at any point
282   - function check_entities() {
283   - $aFailed = array('documents' => array(), 'folders' => array());
284   - $aSucceeded = array('documents' => array(), 'folders' => array());
285   -
286   - if(!$this->oEntityList) {
287   - return true;
288   - }
289   -
290   - foreach($this->oEntityList->getDocumentIds() as $iId) {
291   - $oDocument =& Document::get($iId);
292   -
293   - if(PEAR::isError($oDocument)) {
294   - $aFailed['documents'][] = array($iId, _kt('No such document'));
295   - } else {
296   - $res = $this->check_entity($oDocument);
297   -
298   - // all these checks allow a return from check_entity of:
299   - // 1. a PEAR error, indicating failure, with the message in the error
300   - // 2. false, for unknown error
301   - // 3. true, to pass
302   -
303   - if(PEAR::isError($res)) {
304   - $aFailed['documents'][] = array($oDocument->getName(), $res->getMessage());
305   - } else if($res === false) {
306   - $aFailed['documents'][] = array($oDocument->getName(), _kt('Failed (unknown reason)'));
307   - } else {
308   - $aSucceeded['documents'][] = $oDocument->getId();
309   - }
310   - }
311   - }
312   -
313   - foreach($this->oEntityList->getFolderIds() as $iId) {
314   - $oFolder =& Folder::get($iId);
315   -
316   - if(PEAR::isError($oFolder)) {
317   - $aFailed['folders'][] = array($iId, _kt('No such folder'));
318   - } else {
319   - $res = $this->check_entity($oFolder);
320   -
321   - if(PEAR::isError($res)) {
322   - $aFailed['folders'][] = array($oFolder->getName(), $res->getMessage());
323   - } else if($res === false) {
324   - $aFailed['folders'][] = array($oFolder->getName(), _kt('Failed (unknown reason)'));
325   - } else {
326   - $aSucceeded['folders'][] = $oFolder->getId();
327   - }
328   - }
329   - }
330   - $this->oActiveEntityList = new KTEntityList($aSucceeded['documents'], $aSucceeded['folders']);
331   - $this->aFailed = $aFailed;
332   -
333   - return count($aSucceeded['documents']) + count($aSucceeded['folders']);
334   - }
335   -
336   -
337   - // iterate over all entites to act on them
338   - function perform_action_on_list() {
339   - $this->aActionResults = array('folders'=>array(), 'documents'=>array());
340   -
341   - foreach($this->oActiveEntityList->getDocumentIds() as $iId) {
342   - $oDocument =& Document::get($iId);
343   - if(!PEAR::isError($oDocument)) {
344   - $sName = $oDocument->getName();
345   - } else {
346   - $sName = _kt('Error fetching document name');
347   - }
348   -
349   - $res = $this->perform_action($oDocument);
350   -
351   - //check for shortcut notice
352   - $notice = null;
353   - if($oDocument->isSymbolicLink()){
354   - $notice = _kt("Shortcut");
355   - }
356   -
357   - if(PEAR::isError($res)) {
358   - $this->aActionResults['documents'][] = array($sName, $res->getMessage(), $notice);
359   - } else {
360   - $this->aActionResults['documents'][] = array($sName, _kt('Success'), $notice);
361   - }
362   - }
363   -
364   - foreach($this->oActiveEntityList->getFolderIds() as $iId) {
365   - $oFolder =& Folder::get($iId);
366   - if(!PEAR::isError($oFolder)) {
367   - $sName = $oFolder->getName();
368   - } else {
369   - $sName = _kt('Error fetching folder name');
370   - }
371   -
372   - $res = $this->perform_action($oFolder);
373   -
374   - //check for shortcut notice
375   - $notice = null;
376   - if($oFolder->isSymbolicLink()){
377   - $notice = _kt("Shortcut");
378   - }
379   -
380   - if(PEAR::isError($res)) {
381   - $this->aActionResults['folders'][] = array($sName, $res->getMessage(), $notice);
382   - } else {
383   - $this->aActionResults['folders'][] = array($sName, _kt('Success'), $notice);
384   - }
385   - }
386   - }
387   -
388   -
389   -
390   - // list persistance
391   - // fetch existing lists
392   - function get_lists() {
393   - $this->oEntityList = KTEntityList::retrieveList(KTUtil::arrayGet($_REQUEST, 'fListCode', null));
394   - $this->oActiveEntityList = KTEntityList::retrieveList(KTUtil::arrayGet($_REQUEST, 'fActiveListCode', null));
395   - if(PEAR::isError($this->oActiveEntityList)) {
396   - $this->oActiveEntityList = null;
397   - }
398   - }
399   -
400   - // persist
401   - function store_lists() {
402   - $this->persistParams(array('fListCode', 'fActiveListCode', 'fFolderId', 'fReturnData', 'fReturnAction'));
403   - }
404   -
405   - /**
406   - * Get the return url based on the return action and data
407   - */
408   - function getReturnUrl()
409   - {
410   - $sReturnAction = $_REQUEST['fReturnAction'];
411   - $sReturnData = $_REQUEST['fReturnData'];
412   - $sAction = 'main';
413   - $qs = '';
414   -
415   - switch ($sReturnAction){
416   - case 'browse':
417   - $sReturnData = (empty($sReturnData)) ? $_REQUEST['fFolderId'] : $sReturnData;
418   - $sTargetUrl = KTBrowseUtil::getUrlForFolder(Folder::get($sReturnData));
419   - break;
420   - case 'simpleSearch':
421   - $sTargetUrl = KTBrowseUtil::getSimpleSearchBaseUrl();
422   - $extra = 'fSearchableText='.$sReturnData;
423   - break;
424   - case 'booleanSearch':
425   - $sTargetUrl = KTBrowseUtil::getBooleanSearchBaseUrl();
426   - $sAction = 'performSearch';
427   - $extra = 'boolean_search_id='.$sReturnData;
428   - break;
429   - case 'search2':
430   - $sTargetUrl = KTBrowseUtil::getSearchResultURL();
431   - $sAction = 'searchResults';
432   - break;
433   - default:
434   - $sTargetUrl = $sReturnAction;
435   - $sAction = '';
436   - }
437   -
438   - $qs = (!empty($sAction))? 'action='.$sAction : '';
439   - $qs .= (!empty($extra))? '&'.$extra : '';
440   - $sTargetUrl = KTUtil::addQueryString($sTargetUrl, $qs);
441   -
442   - return $sTargetUrl;
443   - }
444   -
445   - // forms
446   - // form to list the entites after checking each one
447   - function form_listing() {
448   - $sListCode = $this->oEntityList->getCode();
449   - $sActiveListCode = $this->oActiveEntityList->getCode();
450   -
451   - $sTargetUrl = $this->getReturnUrl();
452   -
453   - $oForm = new KTForm;
454   - $oForm->setOptions(array(
455   - 'identifier' => 'ktcore.actions.bulk.listing.form',
456   - 'submit_label' => _kt('Continue'),
457   - 'targeturl' => $this->getURL(),
458   - 'action' => 'collectinfo',
459   - 'fail_action' => 'main',
460   - 'cancel_url' => $sTargetUrl,
461   - 'noframe' => true,
462   - 'extraargs' => array('fListCode' => $sListCode,
463   - 'fActiveListCode' => $sActiveListCode,
464   - 'fFolderId' => $this->oFolder->getId(),
465   - 'fReturnAction' => KTUtil::arrayGet($_REQUEST, 'fReturnAction'),
466   - 'fReturnData' => KTUtil::arrayGet($_REQUEST, 'fReturnData'),
467   - ),
468   - 'context' => $this,
469   - ));
470   - return $oForm;
471   - }
472   -
473   - // form to show on action completion, and list results
474   - function form_complete() {
475   - $sReturnAction = KTUtil::arrayGet($_REQUEST, 'fReturnAction');
476   - $sReturnData = KTUtil::arrayGet($_REQUEST, 'fReturnData');
477   - $sAction = 'main';
478   -
479   - switch ($sReturnAction){
480   - case 'browse':
481   - $sReturnData = (empty($sReturnData)) ? $_REQUEST['fFolderId'] : $sReturnData;
482   - $sTargetUrl = KTBrowseUtil::getUrlForFolder(Folder::get($sReturnData));
483   - break;
484   - case 'simpleSearch': // do we use this?
485   - $sTargetUrl = KTBrowseUtil::getSimpleSearchBaseUrl();
486   - $extraargs = array('fSearchableText'=>$sReturnData);
487   - break;
488   - case 'booleanSearch': // do we use this?
489   - $sTargetUrl = KTBrowseUtil::getBooleanSearchBaseUrl();
490   - $sAction = 'performSearch';
491   - $extraargs = array('boolean_search_id'=>$sReturnData);
492   - break;
493   - case 'search2':
494   - $sTargetUrl = KTBrowseUtil::getSearchResultURL();
495   - $sAction = 'refresh';
496   - break;
497   - default:
498   - $sTargetUrl = $sReturnAction;
499   - $sAction = '';
500   - }
501   -
502   - $oForm = new KTForm;
503   - $oForm->setOptions(array(
504   - 'identifier' => 'ktcore.actions.bulk.complete.form',
505   - 'submit_label' => _kt('Return'),
506   - 'targeturl' => $sTargetUrl,
507   - 'context' => $this,
508   - 'action' => $sAction,
509   - 'extraargs' => $extraargs,
510   - 'noframe' => true,
511   - ));
512   - return $oForm;
513   - }
514   -
515   -
516   - // main entry point - checks the entity list and displays lists
517   - function do_main() {
518   - // get entities (using the checkboxes atm)
519   - $aFolders = KTUtil::arrayGet($_REQUEST, 'selection_f' , array());
520   - $aDocuments = KTUtil::arrayGet($_REQUEST, 'selection_d' , array());
521   - $this->oEntityList = new KTEntityList($aDocuments, $aFolders);
522   -
523   - // gives us $this->aFailed
524   - $iActiveCount = $this->check_entities();
525   -
526   - $oTemplating =& KTTemplating::getSingleton();
527   - $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_listing');
528   -
529   - $this->store_lists();
530   -
531   - return $oTemplate->render(array('context' => $this,
532   - 'form' => $this->form_listing(),
533   - 'failed' => $this->aFailed,
534   - 'active' => $this->oActiveEntityList,
535   - 'activecount' => $iActiveCount,
536   - 'failedform' => $this->form_complete(),
537   - 'folders' => $this->_getNames($this->oActiveEntityList->getFolderIds(), 'Folder'),
538   - 'documents' => $this->_getNames($this->oActiveEntityList->getDocumentIds(), 'Document')));
539   -
540   - }
541   -
542   - // override to add a screen to get a reason, or whatever
543   - // remember to pass to perform action next, and call the super's method
544   - function do_collectinfo() {
545   - $this->store_lists();
546   - return $this->do_performaction();
547   - }
548   -
549   - // perform the action itself, and list results (completion action)
550   - function do_performaction() {
551   - $this->get_lists();
552   - $this->aPersistParams = array();
553   - $this->perform_action_on_list();
554   -
555   - $oTemplating =& KTTemplating::getSingleton();
556   - $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_complete');
557   - return $oTemplate->render(array('context' => $this,
558   - 'list' => $this->aActionResults,
559   - 'form' => $this->form_complete()));
560   - }
561   -
562   -
563   -
564   -
565   -
566   -
567   - // main overrides
568   -
569   - // override to do the actual action, on an individual entity
570   - function perform_action($oEntity) {
571   - return PEAR::raiseError(_kt('Action component not implemented'));
572   - }
573   -
574   - // check an individual entity - this should be overrided with additional
575   - // checks required for the specific action, but should always call its
576   - // parent implementation
577   - function check_entity($oEntity) {
578   - $oPermission =& KTPermission::getByName($this->_sPermission);
579   - if(PEAR::isError($oPermission)) {
580   - return true;
581   - }
582   -
583   - // basic document checks
584   -
585   - // TODO: check if this is appropriate
586   - // should probably store the 'equivalent' action (ie. document.delete)
587   - // and check that, rather than add a new list of actions to the workflow
588   - // section
589   - if(is_a($oEntity, 'Document')) {
590   - if(!KTWorkflowUtil::actionEnabledForDocument($oEntity, $this->sName)) {
591   - return PEAR::raiseError(_kt('Action is disabled by workflow'));
592   - }
593   - $status = $oEntity->getStatusID();
594   - if($status==DELETED||$status==ARCHIVED) {
595   - return PEAR::raiseError(_kt('Document is archived or deleted'));
596   - }
597   - }
598   -
599   - // admin check
600   - if($this->bAllowInAdminMode) {
601   - if(KTBrowseUtil::inAdminMode($this->oUser, null)) {
602   - return true;
603   - }
604   - }
605   -
606   - if(!KTPermissionUtil::userHasPermissionOnItem($this->oUser, $oPermission, $oEntity)) {
607   - return PEAR::raiseError(_kt('You do not have the required permissions'));
608   - }
609   -
610   - return true;
611   - }
612   -
613   -
614   -}
615   -
616   -class KTBulkDocumentAction extends KTBulkAction {
617   - function check_entity($oEntity) {
618   - if(!is_a($oEntity, 'Document')) {
619   - return false;
620   - }
621   - return parent::check_entity($oEntity);
622   - }
623   -}
624   -
625   -class KTBulkFolderAction extends KTBulkAction {
626   - function check_entity($oEntity) {
627   - if(!is_a($oEntity, 'Folder')) {
628   - return false;
629   - }
630   - return parent::check_entity($oEntity);
631   - }
632   -}
633   -
634   -
635   -
636   -// util class for bulk actions
637   -
638   -class KTBulkActionUtil {
639   - function getBulkActionInfo($slot = 'bulkaction') {
640   - $oRegistry =& KTActionRegistry::getSingleton();
641   - return $oRegistry->getActions($slot);
642   - }
643   -
644   - function getAllBulkActions($slot = 'bulkaction') {
645   - $aObjects = array();
646   -
647   - foreach (KTBulkActionUtil::getBulkActionInfo($slot) as $aAction) {
648   - list($sClassName, $sPath, $sName, $sPlugin) = $aAction;
649   - $oRegistry =& KTPluginRegistry::getSingleton();
650   - $oPlugin =& $oRegistry->getPlugin($sPlugin);
651   - if (!empty($sPath)) {
652   - require_once($sPath);
653   - }
654   - $aObjects[] = new $sClassName(null, null, $oPlugin);
655   - }
656   - return $aObjects;
657   - }
658   -
659   - function getBulkActionsByNames($aNames, $slot = 'bulkaction', $oUser = null) {
660   - $aObjects = array();
661   - foreach (KTBulkActionUtil::getBulkActionInfo($slot) as $aAction) {
662   - list($sClassName, $sPath, $sName, $sPlugin) = $aAction;
663   - $oRegistry =& KTPluginRegistry::getSingleton();
664   - $oPlugin =& $oRegistry->getPlugin($sPlugin);
665   - if (!in_array($sName, $aNames)) {
666   - continue;
667   - }
668   - if (!empty($sPath)) {
669   - require_once($sPath);
670   - }
671   - $aObjects[] = new $sClassName(null, $oUser, $oPlugin);
672   - }
673   - return $aObjects;
674   - }
675   -}
676   -
677   -?>
  1 +<?php
  2 +
  3 +/**
  4 + * $Id$
  5 + *
  6 + * KnowledgeTree Community Edition
  7 + * Document Management Made Simple
  8 + * Copyright (C) 2008, 2009 KnowledgeTree Inc.
  9 + * Portions copyright The Jam Warehouse Software (Pty) Limited
  10 + *
  11 + * This program is free software; you can redistribute it and/or modify it under
  12 + * the terms of the GNU General Public License version 3 as published by the
  13 + * Free Software Foundation.
  14 + *
  15 + * This program is distributed in the hope that it will be useful, but WITHOUT
  16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  18 + * details.
  19 + *
  20 + * You should have received a copy of the GNU General Public License
  21 + * along with this program. If not, see <http://www.gnu.org/licenses/>.
  22 + *
  23 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
  24 + * California 94120-7775, or email info@knowledgetree.com.
  25 + *
  26 + * The interactive user interfaces in modified source and object code versions
  27 + * of this program must display Appropriate Legal Notices, as required under
  28 + * Section 5 of the GNU General Public License version 3.
  29 + *
  30 + * In accordance with Section 7(b) of the GNU General Public License version 3,
  31 + * these Appropriate Legal Notices must retain the display of the "Powered by
  32 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  33 + * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
  34 + * must display the words "Powered by KnowledgeTree" and retain the original
  35 + * copyright notice.
  36 + * Contributor( s): ______________________________________
  37 + *
  38 + */
  39 +
  40 +require_once(KT_LIB_DIR . '/actions/actionregistry.inc.php');
  41 +require_once(KT_LIB_DIR . '/workflow/workflowutil.inc.php');
  42 +require_once(KT_LIB_DIR . '/dispatcher.inc.php');
  43 +require_once(KT_LIB_DIR . '/browse/browseutil.inc.php');
  44 +require_once(KT_LIB_DIR . '/actions/entitylist.php');
  45 +
  46 +require_once(KT_LIB_DIR . '/foldermanagement/folderutil.inc.php');
  47 +require_once(KT_LIB_DIR . '/documentmanagement/documentutil.inc.php');
  48 +
  49 +require_once(KT_LIB_DIR . '/widgets/forms.inc.php');
  50 +
  51 +require_once(KT_LIB_DIR . "/util/sanitize.inc");
  52 +
  53 +// // Jarrett Jordaan: Deal with bulk action
  54 +require_once(KT_LIB_DIR . '/subscriptions/subscriptions.inc.php');
  55 +
  56 +class KTBulkAction extends KTStandardDispatcher {
  57 + var $sName;
  58 + var $sDescription;
  59 +
  60 + var $_sDisablePermission;
  61 + var $bAllowInAdminMode = false;
  62 + var $sHelpPage = 'ktcore/browse.html';
  63 +
  64 + var $sSection = 'view_details';
  65 +
  66 + var $_bMutator = false;
  67 + var $_bMutationAllowedByAdmin = true;
  68 +
  69 + var $sIconClass;
  70 +
  71 + // not 'sShowPermission' - mass actions are always shown
  72 + // this is used to check against individual entities
  73 + var $_sPermission = 'ktcore.permissions.read';
  74 +
  75 + // Bulk Action Notification
  76 + var $uploadedDocs;
  77 + var $uploadedFolders;
  78 + var $eventAction;
  79 +
  80 + function KTBulkAction($oUser = null, $oPlugin = null) {
  81 + $this->oEntityList = null;
  82 + $this->oActiveEntityList = null;
  83 + $this->oUser =& $oUser;
  84 + $this->oPlugin =& $oPlugin;
  85 + // Bulk Action Notification
  86 + $this->uploadedDocs = array();
  87 + $this->uploadedFolders = array();
  88 + $this->eventAction = null;
  89 + $this->aBreadcrumbs = array(
  90 + array('action' => 'browse', 'name' => _kt('Browse')),
  91 + );
  92 +
  93 + $this->persistParams('fEntityListCode');
  94 + parent::KTStandardDispatcher();
  95 + }
  96 +
  97 + function setEntityList(&$oEntityList) {
  98 + $this->oEntityList =& $oEntityList;
  99 + }
  100 +
  101 + function setUser(&$oUser) {
  102 + $this->oUser =& $oUser;
  103 + }
  104 +
  105 + function _show() {
  106 + return true;
  107 + }
  108 +
  109 + function getURL() {
  110 + $oKTConfig =& KTConfig::getSingleton();
  111 + $sExt = '.php';
  112 + if (KTUtil::arrayGet($_SERVER, 'kt_no_extensions')) {
  113 + $sExt = '';
  114 + }
  115 + if ($oKTConfig->get('KnowledgeTree/pathInfoSupport')) {
  116 + return sprintf('%s/action%s/%s', $GLOBALS['KTRootUrl'], $sExt, $this->sName);
  117 + } else {
  118 + return sprintf('%s/action%s?kt_path_info=%s', $GLOBALS['KTRootUrl'], $sExt, $this->sName);
  119 + }
  120 + }
  121 +
  122 + function getInfo() {
  123 + if ($this->_show() === false) {
  124 + return null;
  125 + }
  126 +
  127 + $url = $this->getURL();
  128 +
  129 + $aInfo = array(
  130 + 'description' => $this->sDescription,
  131 + 'name' => $this->getDisplayName(),
  132 + 'ns' => $this->sName,
  133 + 'url' => $url,
  134 + 'icon_class' => $this->sIconClass,
  135 + );
  136 +
  137 + $aInfo = $this->customiseInfo($aInfo);
  138 + return $aInfo;
  139 + }
  140 +
  141 + function getName() {
  142 + return sanitizeForSQLtoHTML($this->sName);
  143 + }
  144 +
  145 + function getDisplayName() {
  146 + return sanitizeForSQLtoHTML($this->sDisplayName);
  147 + }
  148 +
  149 + function getDescription() {
  150 + return sanitizeForSQLtoHTML($this->sDescription);
  151 + }
  152 +
  153 + function customiseInfo($aInfo) {
  154 + return $aInfo;
  155 + }
  156 +
  157 + // helper function
  158 + function _getNames($aIds, $sEntity) {
  159 + if(count($aIds)) {
  160 + $aNames = array();
  161 + $aFunc = array($sEntity, 'get');
  162 +
  163 + foreach($aIds as $id) {
  164 + $oE =& call_user_func($aFunc, $id);
  165 + $name = array();
  166 + $name['name'] = $oE->getName();
  167 + //add shortcut notice if the entity is a shortcut
  168 + if($oE->isSymbolicLink()){
  169 + $name['notice'] = _kt("Shortcut");
  170 + }
  171 + $aNames[] = $name;
  172 + }
  173 + return $aNames;
  174 + } else {
  175 + return array();
  176 + }
  177 + }
  178 +
  179 + /**
  180 + * Checks if there are symlinks that are linking to items in the current list
  181 + * Useful if you want to prompt the user with a confirmation because they're
  182 + * automatically deleted when their targets are deleted or archived.
  183 + *
  184 + * @return boolean
  185 + */
  186 + function symlinksLinkingToCurrentList(){
  187 + $symlinksPresent = false;
  188 + foreach($this->oActiveEntityList->getDocumentIds() as $iDocument){
  189 + $oDocument = Document::get($iDocument);
  190 + if(count($oDocument->getSymbolicLinks()) > 0){
  191 + $symlinksPresent = true;
  192 + break;
  193 + }
  194 + }
  195 + if($symlinksPresent == false){
  196 + foreach($this->oActiveEntityList->getFolderIds() as $iFolder){
  197 + $oStartFolder = Folder::get($iFolder);
  198 + $aRemainingFolders = array($oStartFolder->getId());
  199 + while (!empty($aRemainingFolders)) {
  200 + $iFolderId = array_pop($aRemainingFolders);
  201 + $oFolder = Folder::get($iFolderId);
  202 +
  203 + if(count($oFolder->getSymbolicLinks()) > 0){
  204 + $symlinksPresent = true;
  205 + break;
  206 + }
  207 +
  208 + $aChildDocs = Document::getList(array('folder_id = ?',array($iFolderId)));
  209 + foreach ($aChildDocs as $oDoc) {
  210 + if(count($oDoc->getSymbolicLinks()) > 0){
  211 + $symlinksPresent = true;
  212 + break;
  213 + }
  214 + }
  215 +
  216 + $aCFIds = Folder::getList(array('parent_id = ?', array($iFolderId)), array('ids' => true));
  217 + $aRemainingFolders = kt_array_merge($aRemainingFolders, $aCFIds);
  218 + }
  219 + }
  220 + }
  221 + return $symlinksPresent;
  222 + }
  223 +
  224 +/**
  225 + * checks a folderList for shortcuts and queries the repositories for all folders
  226 + * that are somehow connected to these folders.
  227 + */
  228 + function getLinkingEntities($aFolderList){
  229 + $aSearchFolders = array();
  230 + if(!empty($aFolderList)){
  231 + foreach($aFolderList as $oFolderItem){
  232 + if(Permission::userHasFolderReadPermission($oFolderItem)){
  233 + // If it is a shortcut, we should do some more searching
  234 + if($oFolderItem->isSymbolicLink()){
  235 + $oFolderItem = $oFolderItem->getLinkedFolder();
  236 + $aSearchFolders[] = $oFolderItem->getID();
  237 + }
  238 + }
  239 + }
  240 + }
  241 + $aLinkingFolders = array();
  242 + $aSearchCompletedFolders = array();
  243 + $count = 0;
  244 + while(count($aSearchFolders)>0){
  245 + $count++;
  246 + $oFolder = Folder::get(array_pop($aSearchFolders));
  247 + $sFolderId = $oFolder->getId();
  248 + // Get all the folders within the current folder
  249 + $sWhereClause = "parent_folder_ids = '{$sFolderId}' OR
  250 + parent_folder_ids LIKE '{$sFolderId},%' OR
  251 + parent_folder_ids LIKE '%,{$sFolderId},%' OR
  252 + parent_folder_ids LIKE '%,{$sFolderId}'";
  253 + $aFolderList = $this->oFolder->getList($sWhereClause);
  254 + foreach($aFolderList as $oFolderItem){
  255 + if($oFolderItem->isSymbolicLink()){
  256 + $oFolderItem = $oFolderItem->getLinkedFolder();
  257 + }
  258 + if(Permission::userHasFolderReadPermission($oFolderItem)){
  259 + if($aSearchCompletedFolders[$oFolderItem->getID()] != true){
  260 + $aSearchFolders[] = $oFolderItem->getID();
  261 + $aSearchCompletedFolders[$oFolderItem->getID()] = true;
  262 + }
  263 + }
  264 + }
  265 + if(!isset($aLinkingFolders[$oFolder->getId()])){
  266 + $aLinkingFolders[$oFolder->getId()] = $oFolder;
  267 + }
  268 + }
  269 + return $aLinkingFolders;
  270 + }
  271 +
  272 + // doesn't actually do checks, as they have to be performed per-entity
  273 + function check() {
  274 + // not necessarily coming from a folder...
  275 + $iFolderId = KTUtil::arrayGet($_REQUEST, 'fFolderId', 1);
  276 + $this->oFolder = Folder::get($iFolderId);
  277 + //$this->oFolder =& $this->oValidator->validateFolder($_REQUEST['fFolderId']);
  278 +
  279 + $aOptions = array(
  280 + 'final' => false,
  281 + 'documentaction' => 'viewDocument',
  282 + 'folderaction' => 'browse',
  283 + );
  284 +
  285 + $this->aBreadcrumbs = array(array('name'=>_kt('Bulk Actions')),
  286 + array('name'=>$this->getDisplayName()));
  287 +
  288 + return true;
  289 + }
  290 +
  291 +
  292 + // check the entire entity list. this needn't be overrided at any point
  293 + function check_entities() {
  294 + $aFailed = array('documents' => array(), 'folders' => array());
  295 + $aSucceeded = array('documents' => array(), 'folders' => array());
  296 +
  297 + if(!$this->oEntityList) {
  298 + return true;
  299 + }
  300 +
  301 + foreach($this->oEntityList->getDocumentIds() as $iId) {
  302 + $oDocument =& Document::get($iId);
  303 +
  304 + if(PEAR::isError($oDocument)) {
  305 + $aFailed['documents'][] = array($iId, _kt('No such document'));
  306 + } else {
  307 + $res = $this->check_entity($oDocument);
  308 +
  309 + // all these checks allow a return from check_entity of:
  310 + // 1. a PEAR error, indicating failure, with the message in the error
  311 + // 2. false, for unknown error
  312 + // 3. true, to pass
  313 +
  314 + if(PEAR::isError($res)) {
  315 + $aFailed['documents'][] = array($oDocument->getName(), $res->getMessage());
  316 + } else if($res === false) {
  317 + $aFailed['documents'][] = array($oDocument->getName(), _kt('Failed (unknown reason)'));
  318 + } else {
  319 + $aSucceeded['documents'][] = $oDocument->getId();
  320 + }
  321 + }
  322 + }
  323 +
  324 + foreach($this->oEntityList->getFolderIds() as $iId) {
  325 + $oFolder =& Folder::get($iId);
  326 +
  327 + if(PEAR::isError($oFolder)) {
  328 + $aFailed['folders'][] = array($iId, _kt('No such folder'));
  329 + } else {
  330 + $res = $this->check_entity($oFolder);
  331 +
  332 + if(PEAR::isError($res)) {
  333 + $aFailed['folders'][] = array($oFolder->getName(), $res->getMessage());
  334 + } else if($res === false) {
  335 + $aFailed['folders'][] = array($oFolder->getName(), _kt('Failed (unknown reason)'));
  336 + } else {
  337 + $aSucceeded['folders'][] = $oFolder->getId();
  338 + }
  339 + }
  340 + }
  341 + $this->oActiveEntityList = new KTEntityList($aSucceeded['documents'], $aSucceeded['folders']);
  342 + $this->aFailed = $aFailed;
  343 +
  344 + return count($aSucceeded['documents']) + count($aSucceeded['folders']);
  345 + }
  346 +
  347 +
  348 + // iterate over all entites to act on them
  349 + function perform_action_on_list() {
  350 + $this->aActionResults = array('folders'=>array(), 'documents'=>array());
  351 + foreach($this->oActiveEntityList->getDocumentIds() as $iId) {
  352 + $oDocument =& Document::get($iId);
  353 + // Store document
  354 + $this->uploadedDocs[] = $oDocument;
  355 + if(!PEAR::isError($oDocument)) {
  356 + $sName = $oDocument->getName();
  357 + } else {
  358 + $sName = _kt('Error fetching document name');
  359 + }
  360 +
  361 + $res = $this->perform_action($oDocument);
  362 +
  363 + //check for shortcut notice
  364 + $notice = null;
  365 + if($oDocument->isSymbolicLink()){
  366 + $notice = _kt("Shortcut");
  367 + }
  368 +
  369 + if(PEAR::isError($res)) {
  370 + $this->aActionResults['documents'][] = array($sName, $res->getMessage(), $notice);
  371 + } else {
  372 + // TODO better way of getting the bulk action type
  373 + if($this->eventAction == null) {
  374 + $this->eventAction = $res;
  375 + }
  376 + $this->aActionResults['documents'][] = array($sName, _kt('Success'), $notice);
  377 + }
  378 + }
  379 +
  380 + // List of ducument objects
  381 + $oFolderObjects = array();
  382 + foreach($this->oActiveEntityList->getFolderIds() as $iId) {
  383 + $oFolder =& Folder::get($iId);
  384 + // Store folder
  385 + $this->uploadedFolders[] = $oFolder;
  386 + if(!PEAR::isError($oFolder)) {
  387 + $sName = $oFolder->getName();
  388 + } else {
  389 + $sName = _kt('Error fetching folder name');
  390 + }
  391 +
  392 + $res = $this->perform_action($oFolder);
  393 +
  394 + //check for shortcut notice
  395 + $notice = null;
  396 + if($oFolder->isSymbolicLink()){
  397 + $notice = _kt("Shortcut");
  398 + }
  399 +
  400 + if(PEAR::isError($res)) {
  401 + $this->aActionResults['folders'][] = array($sName, $res->getMessage(), $notice);
  402 + } else {
  403 + // // TODO better way of getting the bulk action type
  404 + if($this->eventAction == null) {
  405 + $this->eventAction = $res;
  406 + }
  407 + $this->aActionResults['folders'][] = array($sName, _kt('Success'), $notice);
  408 + }
  409 + }
  410 +
  411 + }
  412 +
  413 +
  414 +
  415 + // list persistance
  416 + // fetch existing lists
  417 + function get_lists() {
  418 + $this->oEntityList = KTEntityList::retrieveList(KTUtil::arrayGet($_REQUEST, 'fListCode', null));
  419 + $this->oActiveEntityList = KTEntityList::retrieveList(KTUtil::arrayGet($_REQUEST, 'fActiveListCode', null));
  420 + if(PEAR::isError($this->oActiveEntityList)) {
  421 + $this->oActiveEntityList = null;
  422 + }
  423 + }
  424 +
  425 + // persist
  426 + function store_lists() {
  427 + $this->persistParams(array('fListCode', 'fActiveListCode', 'fFolderId', 'fReturnData', 'fReturnAction'));
  428 + }
  429 +
  430 + /**
  431 + * Get the return url based on the return action and data
  432 + */
  433 + function getReturnUrl()
  434 + {
  435 + $sReturnAction = $_REQUEST['fReturnAction'];
  436 + $sReturnData = $_REQUEST['fReturnData'];
  437 + $sAction = 'main';
  438 + $qs = '';
  439 +
  440 + switch ($sReturnAction){
  441 + case 'browse':
  442 + $sReturnData = (empty($sReturnData)) ? $_REQUEST['fFolderId'] : $sReturnData;
  443 + $sTargetUrl = KTBrowseUtil::getUrlForFolder(Folder::get($sReturnData));
  444 + break;
  445 + case 'simpleSearch':
  446 + $sTargetUrl = KTBrowseUtil::getSimpleSearchBaseUrl();
  447 + $extra = 'fSearchableText='.$sReturnData;
  448 + break;
  449 + case 'booleanSearch':
  450 + $sTargetUrl = KTBrowseUtil::getBooleanSearchBaseUrl();
  451 + $sAction = 'performSearch';
  452 + $extra = 'boolean_search_id='.$sReturnData;
  453 + break;
  454 + case 'search2':
  455 + $sTargetUrl = KTBrowseUtil::getSearchResultURL();
  456 + $sAction = 'searchResults';
  457 + break;
  458 + default:
  459 + $sTargetUrl = $sReturnAction;
  460 + $sAction = '';
  461 + }
  462 +
  463 + $qs = (!empty($sAction))? 'action='.$sAction : '';
  464 + $qs .= (!empty($extra))? '&'.$extra : '';
  465 + $sTargetUrl = KTUtil::addQueryString($sTargetUrl, $qs);
  466 +
  467 + return $sTargetUrl;
  468 + }
  469 +
  470 + // forms
  471 + // form to list the entites after checking each one
  472 + function form_listing() {
  473 + $sListCode = $this->oEntityList->getCode();
  474 + $sActiveListCode = $this->oActiveEntityList->getCode();
  475 +
  476 + $sTargetUrl = $this->getReturnUrl();
  477 +
  478 + $oForm = new KTForm;
  479 + $oForm->setOptions(array(
  480 + 'identifier' => 'ktcore.actions.bulk.listing.form',
  481 + 'submit_label' => _kt('Continue'),
  482 + 'targeturl' => $this->getURL(),
  483 + 'action' => 'collectinfo',
  484 + 'fail_action' => 'main',
  485 + 'cancel_url' => $sTargetUrl,
  486 + 'noframe' => true,
  487 + 'extraargs' => array('fListCode' => $sListCode,
  488 + 'fActiveListCode' => $sActiveListCode,
  489 + 'fFolderId' => $this->oFolder->getId(),
  490 + 'fReturnAction' => KTUtil::arrayGet($_REQUEST, 'fReturnAction'),
  491 + 'fReturnData' => KTUtil::arrayGet($_REQUEST, 'fReturnData'),
  492 + ),
  493 + 'context' => $this,
  494 + ));
  495 + return $oForm;
  496 + }
  497 +
  498 + // form to show on action completion, and list results
  499 + function form_complete() {
  500 + $sReturnAction = KTUtil::arrayGet($_REQUEST, 'fReturnAction');
  501 + $sReturnData = KTUtil::arrayGet($_REQUEST, 'fReturnData');
  502 + $sAction = 'main';
  503 +
  504 + switch ($sReturnAction){
  505 + case 'browse':
  506 + $sReturnData = (empty($sReturnData)) ? $_REQUEST['fFolderId'] : $sReturnData;
  507 + $sTargetUrl = KTBrowseUtil::getUrlForFolder(Folder::get($sReturnData));
  508 + break;
  509 + case 'simpleSearch': // do we use this?
  510 + $sTargetUrl = KTBrowseUtil::getSimpleSearchBaseUrl();
  511 + $extraargs = array('fSearchableText'=>$sReturnData);
  512 + break;
  513 + case 'booleanSearch': // do we use this?
  514 + $sTargetUrl = KTBrowseUtil::getBooleanSearchBaseUrl();
  515 + $sAction = 'performSearch';
  516 + $extraargs = array('boolean_search_id'=>$sReturnData);
  517 + break;
  518 + case 'search2':
  519 + $sTargetUrl = KTBrowseUtil::getSearchResultURL();
  520 + $sAction = 'refresh';
  521 + break;
  522 + default:
  523 + $sTargetUrl = $sReturnAction;
  524 + $sAction = '';
  525 + }
  526 +
  527 + $oForm = new KTForm;
  528 + $oForm->setOptions(array(
  529 + 'identifier' => 'ktcore.actions.bulk.complete.form',
  530 + 'submit_label' => _kt('Return'),
  531 + 'targeturl' => $sTargetUrl,
  532 + 'context' => $this,
  533 + 'action' => $sAction,
  534 + 'extraargs' => $extraargs,
  535 + 'noframe' => true,
  536 + ));
  537 + return $oForm;
  538 + }
  539 +
  540 +
  541 + // main entry point - checks the entity list and displays lists
  542 + function do_main() {
  543 + // get entities (using the checkboxes atm)
  544 + $aFolders = KTUtil::arrayGet($_REQUEST, 'selection_f' , array());
  545 + $aDocuments = KTUtil::arrayGet($_REQUEST, 'selection_d' , array());
  546 + $this->oEntityList = new KTEntityList($aDocuments, $aFolders);
  547 +
  548 + // gives us $this->aFailed
  549 + $iActiveCount = $this->check_entities();
  550 +
  551 + $oTemplating =& KTTemplating::getSingleton();
  552 + $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_listing');
  553 +
  554 + $this->store_lists();
  555 +
  556 + return $oTemplate->render(array('context' => $this,
  557 + 'form' => $this->form_listing(),
  558 + 'failed' => $this->aFailed,
  559 + 'active' => $this->oActiveEntityList,
  560 + 'activecount' => $iActiveCount,
  561 + 'failedform' => $this->form_complete(),
  562 + 'folders' => $this->_getNames($this->oActiveEntityList->getFolderIds(), 'Folder'),
  563 + 'documents' => $this->_getNames($this->oActiveEntityList->getDocumentIds(), 'Document')));
  564 +
  565 + }
  566 +
  567 + // override to add a screen to get a reason, or whatever
  568 + // remember to pass to perform action next, and call the super's method
  569 + function do_collectinfo() {
  570 + $this->store_lists();
  571 + return $this->do_performaction();
  572 + }
  573 +
  574 + // perform the action itself, and list results (completion action)
  575 + function do_performaction() {
  576 + $this->get_lists();
  577 + $this->aPersistParams = array();
  578 + $targetFolderId = $_REQUEST['fFolderId'];
  579 + $targetFolder =& Folder::get($targetFolderId);
  580 + $this->perform_action_on_list();
  581 + // Parse affected documents and folders
  582 + if(count($this->uploadedDocs) > 0)
  583 + $this->do_notification($this->uploadedDocs, $this->eventAction, $targetFolder);
  584 + elseif(count($this->uploadedFolders) > 0)
  585 + $this->do_notification($this->uploadedFolders, $this->eventAction, $targetFolder);
  586 + // Action specific Emails
  587 + // Check if its a move action
  588 + if($this->eventAction == "MovedDocument") {
  589 + // Notify the folder from which the action happened
  590 + $originalFolderId = $_REQUEST['fOriginalFolderId'];
  591 + $originalFolder =& Folder::get($originalFolderId);
  592 + if(count($this->uploadedDocs) > 0)
  593 + $this->do_notification($this->uploadedDocs, $this->eventAction, $originalFolder);
  594 + elseif(count($this->uploadedFolders) > 0)
  595 + $this->do_notification($this->uploadedFolders, $this->eventAction, $originalFolder);
  596 + }
  597 +
  598 + $oTemplating =& KTTemplating::getSingleton();
  599 + $oTemplate = $oTemplating->loadTemplate('ktcore/bulk_action_complete');
  600 +
  601 + return $oTemplate->render(array('context' => $this,
  602 + 'list' => $this->aActionResults,
  603 + 'form' => $this->form_complete()));
  604 + }
  605 +
  606 + // Jarrett Jordaan: Deal with bulk actions
  607 + function do_notification($objects, $eventAction, $targetFolder) {
  608 + echo $eventAction." on folder ".$targetFolder->getId()."<br/>";
  609 + // Make sure there were documents/folders affected
  610 + if ($targetFolder && count($objects) > 0 && $eventAction != '') {
  611 + $oSubscriptionEvent = new SubscriptionEvent();
  612 + $oSubscriptionEvent->notifyBulkDocumentAction($objects, $eventAction, $targetFolder);
  613 + }
  614 + }
  615 +
  616 +
  617 +
  618 +
  619 + // main overrides
  620 +
  621 + // override to do the actual action, on an individual entity
  622 + function perform_action($oEntity) {
  623 + return PEAR::raiseError(_kt('Action component not implemented'));
  624 + }
  625 +
  626 + // check an individual entity - this should be overrided with additional
  627 + // checks required for the specific action, but should always call its
  628 + // parent implementation
  629 + function check_entity($oEntity) {
  630 + $oPermission =& KTPermission::getByName($this->_sPermission);
  631 + if(PEAR::isError($oPermission)) {
  632 + return true;
  633 + }
  634 +
  635 + // basic document checks
  636 +
  637 + // TODO: check if this is appropriate
  638 + // should probably store the 'equivalent' action (ie. document.delete)
  639 + // and check that, rather than add a new list of actions to the workflow
  640 + // section
  641 + if(is_a($oEntity, 'Document')) {
  642 + if(!KTWorkflowUtil::actionEnabledForDocument($oEntity, $this->sName)) {
  643 + return PEAR::raiseError(_kt('Action is disabled by workflow'));
  644 + }
  645 + $status = $oEntity->getStatusID();
  646 + if($status==DELETED||$status==ARCHIVED) {
  647 + return PEAR::raiseError(_kt('Document is archived or deleted'));
  648 + }
  649 + }
  650 +
  651 + // admin check
  652 + if($this->bAllowInAdminMode) {
  653 + if(KTBrowseUtil::inAdminMode($this->oUser, null)) {
  654 + return true;
  655 + }
  656 + }
  657 +
  658 + if(!KTPermissionUtil::userHasPermissionOnItem($this->oUser, $oPermission, $oEntity)) {
  659 + return PEAR::raiseError(_kt('You do not have the required permissions'));
  660 + }
  661 +
  662 + return true;
  663 + }
  664 +
  665 +
  666 +}
  667 +
  668 +class KTBulkDocumentAction extends KTBulkAction {
  669 + function check_entity($oEntity) {
  670 + if(!is_a($oEntity, 'Document')) {
  671 + return false;
  672 + }
  673 + return parent::check_entity($oEntity);
  674 + }
  675 +}
  676 +
  677 +class KTBulkFolderAction extends KTBulkAction {
  678 + function check_entity($oEntity) {
  679 + if(!is_a($oEntity, 'Folder')) {
  680 + return false;
  681 + }
  682 + return parent::check_entity($oEntity);
  683 + }
  684 +}
  685 +
  686 +
  687 +
  688 +// util class for bulk actions
  689 +
  690 +class KTBulkActionUtil {
  691 + function getBulkActionInfo($slot = 'bulkaction') {
  692 + $oRegistry =& KTActionRegistry::getSingleton();
  693 + return $oRegistry->getActions($slot);
  694 + }
  695 +
  696 + function getAllBulkActions($slot = 'bulkaction') {
  697 + $aObjects = array();
  698 +
  699 + foreach (KTBulkActionUtil::getBulkActionInfo($slot) as $aAction) {
  700 + list($sClassName, $sPath, $sName, $sPlugin) = $aAction;
  701 + $oRegistry =& KTPluginRegistry::getSingleton();
  702 + $oPlugin =& $oRegistry->getPlugin($sPlugin);
  703 + if (!empty($sPath)) {
  704 + require_once($sPath);
  705 + }
  706 + $aObjects[] = new $sClassName(null, null, $oPlugin);
  707 + }
  708 + return $aObjects;
  709 + }
  710 +
  711 + function getBulkActionsByNames($aNames, $slot = 'bulkaction', $oUser = null) {
  712 + $aObjects = array();
  713 + foreach (KTBulkActionUtil::getBulkActionInfo($slot) as $aAction) {
  714 + list($sClassName, $sPath, $sName, $sPlugin) = $aAction;
  715 + $oRegistry =& KTPluginRegistry::getSingleton();
  716 + $oPlugin =& $oRegistry->getPlugin($sPlugin);
  717 + if (!in_array($sName, $aNames)) {
  718 + continue;
  719 + }
  720 + if (!empty($sPath)) {
  721 + require_once($sPath);
  722 + }
  723 + $aObjects[] = new $sClassName(null, $oUser, $oPlugin);
  724 + }
  725 + return $aObjects;
  726 + }
  727 +}
  728 +
  729 +?>
... ...
lib/database/schema.inc.php
... ... @@ -1012,7 +1012,7 @@ class KTSchemaUtil
1012 1012  
1013 1013 if (!$result)
1014 1014 {
1015   - print "...";
  1015 + //print "...";
1016 1016 }
1017 1017  
1018 1018 return $result;
... ...
lib/documentmanagement/documentutil.inc.php
... ... @@ -45,8 +45,6 @@ require_once(KT_LIB_DIR . &#39;/documentmanagement/DocumentFieldLink.inc&#39;);
45 45 require_once(KT_LIB_DIR . '/documentmanagement/DocumentTransaction.inc');
46 46 require_once(KT_LIB_DIR . '/documentmanagement/Document.inc');
47 47  
48   -require_once(KT_LIB_DIR . '/storage/storagemanager.inc.php');
49   -
50 48 // NEW PATHS
51 49 require_once(KT_LIB_DIR . '/storage/storagemanager.inc.php');
52 50 require_once(KT_LIB_DIR . '/filelike/filelikeutil.inc.php');
... ... @@ -62,7 +60,7 @@ require_once(KT_LIB_DIR . &#39;/browse/browseutil.inc.php&#39;);
62 60 require_once(KT_LIB_DIR . '/workflow/workflowutil.inc.php');
63 61  
64 62 class KTDocumentUtil {
65   - function checkin($oDocument, $sFilename, $sCheckInComment, $oUser, $aOptions = false) {
  63 + function checkin($oDocument, $sFilename, $sCheckInComment, $oUser, $aOptions = false, $bulk_action = false) {
66 64 $oStorage =& KTStorageManagerUtil::getSingleton();
67 65  
68 66 $iFileSize = filesize($sFilename);
... ... @@ -149,16 +147,17 @@ class KTDocumentUtil {
149 147 }
150 148  
151 149 Indexer::index($oDocument);
152   -
153   - // fire subscription alerts for the checked in document
154   - $oSubscriptionEvent = new SubscriptionEvent();
155   - $oFolder = Folder::get($oDocument->getFolderID());
156   - $oSubscriptionEvent->CheckinDocument($oDocument, $oFolder);
  150 + if(!$bulk_action) {
  151 + // fire subscription alerts for the checked in document
  152 + $oSubscriptionEvent = new SubscriptionEvent();
  153 + $oFolder = Folder::get($oDocument->getFolderID());
  154 + $oSubscriptionEvent->CheckinDocument($oDocument, $oFolder);
  155 + }
157 156  
158 157 return true;
159 158 }
160 159  
161   - function checkout($oDocument, $sCheckoutComment, $oUser) {
  160 + function checkout($oDocument, $sCheckoutComment, $oUser, $bulk_action = false) {
162 161 //automatically check out the linked document if this is a shortcut
163 162 if($oDocument->isSymbolicLink()){
164 163 $oDocument->switchToLinkedCore();
... ... @@ -191,7 +190,7 @@ class KTDocumentUtil {
191 190 'document' => $oDocument,
192 191 );
193 192 $oTrigger->setInfo($aInfo);
194   - $ret = $oTrigger->postValidate();
  193 + $ret = $oTrigger->postValidate(true);
195 194 if (PEAR::isError($ret)) {
196 195 return $ret;
197 196 }
... ... @@ -200,15 +199,17 @@ class KTDocumentUtil {
200 199 $oDocumentTransaction = new DocumentTransaction($oDocument, $sCheckoutComment, 'ktcore.transactions.check_out');
201 200 $oDocumentTransaction->create();
202 201  
203   - // fire subscription alerts for the downloaded document
204   - $oSubscriptionEvent = new SubscriptionEvent();
205   - $oFolder = Folder::get($oDocument->getFolderID());
206   - $oSubscriptionEvent->CheckOutDocument($oDocument, $oFolder);
  202 + if(!$bulk_action) {
  203 + // fire subscription alerts for the downloaded document
  204 + $oSubscriptionEvent = new SubscriptionEvent();
  205 + $oFolder = Folder::get($oDocument->getFolderID());
  206 + $oSubscriptionEvent->CheckOutDocument($oDocument, $oFolder);
  207 + }
207 208  
208 209 return true;
209 210 }
210 211  
211   - function archive($oDocument, $sReason) {
  212 + function archive($oDocument, $sReason, $bulk_action = false) {
212 213  
213 214 if($oDocument->isSymbolicLink()){
214 215 return PEAR::raiseError(_kt("It is not possible to archive a shortcut. Please archive the target document."));
... ... @@ -256,17 +257,18 @@ class KTDocumentUtil {
256 257 'document' => $oDocument,
257 258 );
258 259 $oTrigger->setInfo($aInfo);
259   - $ret = $oTrigger->postValidate();
  260 + $ret = $oTrigger->postValidate(true);
260 261 if (PEAR::isError($ret)) {
261 262 $oDocument->delete();
262 263 return $ret;
263 264 }
264 265 }
265   -
266   - // fire subscription alerts for the archived document
267   - $oSubscriptionEvent = new SubscriptionEvent();
268   - $oFolder = Folder::get($oDocument->getFolderID());
269   - $oSubscriptionEvent->ArchivedDocument($oDocument, $oFolder);
  266 + if(!$bulk_action) {
  267 + // fire subscription alerts for the archived document
  268 + $oSubscriptionEvent = new SubscriptionEvent();
  269 + $oFolder = Folder::get($oDocument->getFolderID());
  270 + $oSubscriptionEvent->ArchivedDocument($oDocument, $oFolder);
  271 + }
270 272  
271 273 return true;
272 274 }
... ... @@ -698,11 +700,21 @@ $sourceDocument-&gt;getName(),
698 700 }
699 701 }
700 702 // }}}
701   -
  703 + /*
  704 + * Document Add
  705 + * Author : Jarrett Jordaan
  706 + * Modified : 28/04/09
  707 + *
  708 + * @params : KTFolderUtil $oFolder
  709 + * string $sFilename
  710 + * KTUser $oUser
  711 + * array $aOptions
  712 + * boolean $bulk_action
  713 + */
702 714 // {{{ add
703   - function &add($oFolder, $sFilename, $oUser, $aOptions) {
  715 + function &add($oFolder, $sFilename, $oUser, $aOptions, $bulk_action = false) {
704 716 $GLOBALS['_IN_ADD'] = true;
705   - $ret = KTDocumentUtil::_in_add($oFolder, $sFilename, $oUser, $aOptions);
  717 + $ret = KTDocumentUtil::_in_add($oFolder, $sFilename, $oUser, $aOptions, $bulk_action);
706 718 unset($GLOBALS['_IN_ADD']);
707 719 return $ret;
708 720 }
... ... @@ -731,8 +743,19 @@ $sourceDocument-&gt;getName(),
731 743 return $sFilename;
732 744 }
733 745  
  746 + /*
  747 + * Document Add
  748 + * Author : Jarrett Jordaan
  749 + * Modified : 28/04/09
  750 + *
  751 + * @params : KTFolderUtil $oFolder
  752 + * string $sFilename
  753 + * KTUser $oUser
  754 + * array $aOptions
  755 + * boolean $bulk_action
  756 + */
734 757 // {{{ _in_add
735   - function &_in_add($oFolder, $sFilename, $oUser, $aOptions) {
  758 + function &_in_add($oFolder, $sFilename, $oUser, $aOptions, $bulk_action = false) {
736 759 $aOrigOptions = $aOptions;
737 760  
738 761 $sFilename = KTDocumentUtil::getUniqueFilename($oFolder, $sFilename);
... ... @@ -785,9 +808,9 @@ $sourceDocument-&gt;getName(),
785 808 }
786 809  
787 810 $oUploadChannel->sendMessage(new KTUploadGenericMessage(_kt('Sending subscriptions')));
788   - // fire subscription alerts for the checked in document
789 811 // TODO : better way of checking if its a bulk upload
790   - if($_SERVER['PATH_INFO'] != "ktcore.actions.folder.bulkUpload") {
  812 + if(!$bulk_action) {
  813 + // fire subscription alerts for the checked in document
791 814 $oSubscriptionEvent = new SubscriptionEvent();
792 815 $oFolder = Folder::get($oDocument->getFolderID());
793 816 $oSubscriptionEvent->AddDocument($oDocument, $oFolder);
... ... @@ -939,8 +962,18 @@ $sourceDocument-&gt;getName(),
939 962 }
940 963 // }}}
941 964  
  965 + /*
  966 + * Document Delete
  967 + * Author : Jarrett Jordaan
  968 + * Modified : 28/04/09
  969 + *
  970 + * @params : KTDocumentUtil $oDocument
  971 + * string $sReason
  972 + * int $iDestFolderId
  973 + * boolean $bulk_action
  974 + */
942 975 // {{{ delete
943   - function delete($oDocument, $sReason, $iDestFolderId = null) {
  976 + function delete($oDocument, $sReason, $iDestFolderId = null, $bulk_action = false) {
944 977 // use the deleteSymbolicLink function is this is a symlink
945 978 if ($oDocument->isSymbolicLink())
946 979 {
... ... @@ -1044,12 +1077,12 @@ $sourceDocument-&gt;getName(),
1044 1077 $oDocument->setFolderID(1);
1045 1078  
1046 1079 DBUtil::commit();
1047   -
1048   -
1049   - // we weren't doing notifications on this one
1050   - $oSubscriptionEvent = new SubscriptionEvent();
1051   - $oSubscriptionEvent->RemoveDocument($oDocument, $oOrigFolder);
1052   -
  1080 + // TODO : better way of checking if its a bulk delete
  1081 + if(!$bulk_action) {
  1082 + // we weren't doing notifications on this one
  1083 + $oSubscriptionEvent = new SubscriptionEvent();
  1084 + $oSubscriptionEvent->RemoveDocument($oDocument, $oOrigFolder);
  1085 + }
1053 1086  
1054 1087 // document is now deleted: triggers are best-effort.
1055 1088  
... ... @@ -1062,7 +1095,7 @@ $sourceDocument-&gt;getName(),
1062 1095 'document' => $oDocument,
1063 1096 );
1064 1097 $oTrigger->setInfo($aInfo);
1065   - $ret = $oTrigger->postValidate();
  1098 + $ret = $oTrigger->postValidate(true);
1066 1099 if (PEAR::isError($ret)) {
1067 1100 $oDocument->delete(); // FIXME nbm: review that on-fail => delete is correct ?!
1068 1101 return $ret;
... ... @@ -1135,7 +1168,7 @@ $sourceDocument-&gt;getName(),
1135 1168 return true;
1136 1169 }
1137 1170  
1138   - function copy($oDocument, $oDestinationFolder, $sReason = null, $sDestinationDocName = null) {
  1171 + function copy($oDocument, $oDestinationFolder, $sReason = null, $sDestinationDocName = null, $bulk_action = false) {
1139 1172 // 1. generate a new triad of content, metadata and core objects.
1140 1173 // 2. update the storage path.
1141 1174 //print '--------------------------------- BEFORE';
... ... @@ -1284,11 +1317,12 @@ $sourceDocument-&gt;getName(),
1284 1317 return $ret;
1285 1318 }
1286 1319 }
1287   -
1288   - // fire subscription alerts for the copied document
1289   - $oSubscriptionEvent = new SubscriptionEvent();
1290   - $oFolder = Folder::get($oDocument->getFolderID());
1291   - $oSubscriptionEvent->MoveDocument($oDocument, $oDestinationFolder, $oSrcFolder, 'CopiedDocument');
  1320 + if(!$bulk_action) {
  1321 + // fire subscription alerts for the copied document
  1322 + $oSubscriptionEvent = new SubscriptionEvent();
  1323 + $oFolder = Folder::get($oDocument->getFolderID());
  1324 + $oSubscriptionEvent->MoveDocument($oDocument, $oDestinationFolder, $oSrcFolder, 'CopiedDocument');
  1325 + }
1292 1326  
1293 1327 return $oNewDocument;
1294 1328 }
... ... @@ -1369,7 +1403,18 @@ $sourceDocument-&gt;getName(),
1369 1403 return true;
1370 1404 }
1371 1405  
1372   - function move($oDocument, $oToFolder, $oUser = null, $sReason = null) {
  1406 + /*
  1407 + * Document Move
  1408 + * Author : Jarrett Jordaan
  1409 + * Modified : 28/04/09
  1410 + *
  1411 + * @params : KTDocumentUtil $oDocument
  1412 + * KTFolderUtil $oToFolder
  1413 + * KTUser $oUser
  1414 + * string $sReason
  1415 + * boolean $bulk_action
  1416 + */
  1417 + function move($oDocument, $oToFolder, $oUser = null, $sReason = null, $bulk_action = false) {
1373 1418 //make sure we move the symlink, and the document it's linking to
1374 1419 if($oDocument->isSymbolicLink()){
1375 1420 $oDocument->switchToRealCore();
... ... @@ -1425,9 +1470,9 @@ $sourceDocument-&gt;getName(),
1425 1470 $oDocumentTransaction = new DocumentTransaction($oDocument, $sMoveMessage, 'ktcore.transactions.move');
1426 1471 $oDocumentTransaction->create();
1427 1472  
1428   -
1429 1473 $oKTTriggerRegistry = KTTriggerRegistry::getSingleton();
1430 1474 $aTriggers = $oKTTriggerRegistry->getTriggers('moveDocument', 'postValidate');
  1475 +
1431 1476 foreach ($aTriggers as $aTrigger) {
1432 1477 $sTrigger = $aTrigger[0];
1433 1478 $oTrigger = new $sTrigger;
... ... @@ -1437,15 +1482,17 @@ $sourceDocument-&gt;getName(),
1437 1482 'new_folder' => $oFolder,
1438 1483 );
1439 1484 $oTrigger->setInfo($aInfo);
1440   - $ret = $oTrigger->postValidate();
  1485 + $ret = $oTrigger->postValidate(true);
1441 1486 if (PEAR::isError($ret)) {
1442 1487 return $ret;
1443 1488 }
1444 1489 }
1445 1490  
1446   - // fire subscription alerts for the moved document
1447   - $oSubscriptionEvent = new SubscriptionEvent();
1448   - $oSubscriptionEvent->MoveDocument($oDocument, $oFolder, $oOriginalFolder);
  1491 + if(!$bulk_action) {
  1492 + // fire subscription alerts for the moved document
  1493 + $oSubscriptionEvent = new SubscriptionEvent();
  1494 + $oSubscriptionEvent->MoveDocument($oDocument, $oFolder, $oOriginalFolder);
  1495 + }
1449 1496  
1450 1497 return KTPermissionUtil::updatePermissionLookup($oDocument);
1451 1498 }
... ...
lib/foldermanagement/compressionArchiveUtil.inc.php
... ... @@ -614,6 +614,7 @@ class DownloadQueue
614 614 // Get all the folders within the current folder
615 615 $sWhereClause = "parent_folder_ids like '%,{$folderId}'
616 616 OR parent_folder_ids like '%,{$folderId},%'
  617 + OR parent_folder_ids like '{$folderId},%'
617 618 OR parent_id = {$folderId}";
618 619  
619 620 $aFolderList = $oFolder->getList($sWhereClause);
... ...
lib/foldermanagement/folderutil.inc.php
... ... @@ -75,7 +75,17 @@ class KTFolderUtil {
75 75 return $oFolder;
76 76 }
77 77  
78   - function add($oParentFolder, $sFolderName, $oUser) {
  78 + /*
  79 + * Folder Add
  80 + * Author : Jarrett Jordaan
  81 + * Modified : 28/04/09
  82 + *
  83 + * @params : KTDocumentUtil $oParentFolder
  84 + * string $sFolderName
  85 + * KTUser $oUser
  86 + * boolean $bulk_action
  87 + */
  88 + function add($oParentFolder, $sFolderName, $oUser, $bulk_action = false) {
79 89  
80 90  
81 91 $folderid=$oParentFolder->getId();
... ... @@ -97,15 +107,16 @@ class KTFolderUtil {
97 107 'userid' => $oUser->getId(),
98 108 'ip' => Session::getClientIP(),
99 109 ));
100   -
101   - // fire subscription alerts for the new folder
102   - $oSubscriptionEvent = new SubscriptionEvent();
103   - $oSubscriptionEvent->AddFolder($oFolder, $oParentFolder);
  110 + if(!$bulk_action) {
  111 + // fire subscription alerts for the new folder
  112 + $oSubscriptionEvent = new SubscriptionEvent();
  113 + $oSubscriptionEvent->AddFolder($oFolder, $oParentFolder);
  114 + }
104 115  
105 116 return $oFolder;
106 117 }
107 118  
108   - function move($oFolder, $oNewParentFolder, $oUser, $sReason=null) {
  119 + function move($oFolder, $oNewParentFolder, $oUser, $sReason=null, $bulk_action = false) {
109 120 if ($oFolder->getId() == 1)
110 121 {
111 122 return PEAR::raiseError(_kt('Cannot move root folder!'));
... ... @@ -312,7 +323,7 @@ class KTFolderUtil {
312 323 * - step-by-step delete.
313 324 */
314 325  
315   - function delete($oStartFolder, $oUser, $sReason, $aOptions = null) {
  326 + function delete($oStartFolder, $oUser, $sReason, $aOptions = null, $bulk_action = false) {
316 327 require_once(KT_LIB_DIR . '/unitmanagement/Unit.inc');
317 328  
318 329 $oPerm = KTPermission::getByName('ktcore.permissions.delete');
... ...
lib/import/bulkimport.inc.php
... ... @@ -40,17 +40,22 @@
40 40 require_once(KT_LIB_DIR . '/foldermanagement/folderutil.inc.php');
41 41 require_once(KT_LIB_DIR . '/documentmanagement/documentutil.inc.php');
42 42 require_once(KT_LIB_DIR . '/filelike/filelikeutil.inc.php');
43   -// // Jarrett Jordaan: Deal with bulk uploads
  43 +// // Jarrett Jordaan: Deal with bulk action
44 44 require_once(KT_LIB_DIR . '/subscriptions/subscriptions.inc.php');
45 45  
46 46 class KTBulkImportManager {
47 47 var $oStorage;
  48 + // Bulk Action Notification
  49 + var $uploadedDocs;
  50 + var $uploadedFolders;
48 51  
49 52 function KTBulkImportManager($oFolder, $oStorage, $oUser, $aOptions = null) {
50 53 $this->oFolder =& $oFolder;
51 54 $this->oStorage =& $oStorage;
52 55 $this->oUser =& $oUser;
53 56 $this->aOptions =& $aOptions;
  57 + $this->uploadedDocs = array();
  58 + $this->uploadedFolders = array();
54 59 if (is_null($aOptions)) {
55 60 $aOptions = array();
56 61 }
... ... @@ -69,13 +74,21 @@ class KTBulkImportManager {
69 74 $this->oStorage->cleanup();
70 75 return $res;
71 76 }
  77 + if(count($this->uploadedDocs) > 0) {
  78 + // Bulk action subscription notification
  79 + $oSubscriptionEvent = new SubscriptionEvent();
  80 + $oSubscriptionEvent->notifyBulkDocumentAction($this->uploadedDocs, 'AddDocument', $this->oFolder);
  81 + } elseif(count($this->uploadedFolders) > 0) {
  82 + $oSubscriptionEvent = new SubscriptionEvent();
  83 + $oSubscriptionEvent->notifyBulkDocumentAction($this->uploadedFolders, 'AddFolder', $this->oFolder);
  84 + }
72 85 $this->oStorage->cleanup();
  86 +
73 87 return;
74 88 }
75 89  
76 90 function _importfolder($oFolder, $sPath) {
77 91 $oPermission = KTPermission::getByName('ktcore.permissions.addFolder');
78   -
79 92 $aDocPaths = $this->oStorage->listDocuments($sPath);
80 93 if (PEAR::isError($aDocPaths)) {
81 94 return $aDocPaths;
... ... @@ -86,16 +99,15 @@ class KTBulkImportManager {
86 99 if (PEAR::isError($res)) {
87 100 return $res;
88 101 }
89   - $oDocObjects[] = $res;
  102 + // Store document object
  103 + $this->uploadedDocs[] = $res;
90 104 }
91   - // Jarrett Jordaan: Deal with bulk uploads
92   - $oSubscriptionEvent = new SubscriptionEvent();
93   - $oSubscriptionEvent->notifyBulkDocumentUpload($oDocObjects, $oFolder);
94 105  
95 106 $aFolderPaths = $this->oStorage->listFolders($sPath);
96 107 if (PEAR::isError($aFolderPaths)) {
97 108 return $aFolderPaths;
98 109 }
  110 + $oFolderObjects = array();
99 111 foreach ($aFolderPaths as $sFolderPath) {
100 112 $sFolderBasePath = basename($sFolderPath);
101 113 $sFolderBasePath = ($this->is_utf8($sFolderBasePath)) ? $sFolderBasePath : utf8_encode($sFolderBasePath);
... ... @@ -115,7 +127,7 @@ class KTBulkImportManager {
115 127  
116 128 if(KTPermissionUtil::userHasPermissionOnItem($this->oUser, $oPermission, $oFolder))
117 129 {
118   - $oThisFolder = KTFolderUtil::add($oFolder, $sFolderBasePath, $this->oUser);
  130 + $oThisFolder = KTFolderUtil::add($oFolder, $sFolderBasePath, $this->oUser, true);
119 131 }
120 132 else
121 133 {
... ... @@ -135,7 +147,10 @@ class KTBulkImportManager {
135 147 if (PEAR::isError($res)) {
136 148 return $res;
137 149 }
  150 + // Store folder object
  151 + $this->uploadedFolders[] = $res;
138 152 }
  153 +
139 154 }
140 155  
141 156 function _importdocument($oFolder, $sPath) {
... ... @@ -165,7 +180,7 @@ class KTBulkImportManager {
165 180 $aOptions = array_merge($aOptions, $this->aOptions);
166 181 $sPath = basename($sPath);
167 182 $sPath = ($this->is_utf8($sPath)) ? $sPath : utf8_encode($sPath);
168   - $oDocument =& KTDocumentUtil::add($oFolder, $sPath, $this->oUser, $aOptions);
  183 + $oDocument =& KTDocumentUtil::add($oFolder, $sPath, $this->oUser, $aOptions, true);
169 184 return $oDocument;
170 185 }
171 186  
... ...
lib/subscriptions/subscriptions.inc.php
... ... @@ -103,11 +103,14 @@ class SubscriptionEvent {
103 103 * @params : KTDocumentUtil $oDocObjects
104 104 * KTFolderUtil $oParentFolder
105 105 */
106   - function notifyBulkDocumentUpload($oDocObjects, $oParentFolder) {
  106 + function notifyBulkDocumentAction($oDocObjects, $eventType, $oParentFolder) {
107 107 $content = new SubscriptionContent(); // needed for i18n
108   - $parentId = $oParentFolder->getId();
109   - $aUsers = $this->_getSubscribers($parentId, $this->subscriptionTypes["Folder"]);
110   - $this->bulkNotification($aUsers, 'AddDocument', $oDocObjects, $parentId);
  108 + // TODO Better way to check if this is a folder object
  109 + if (is_object($oParentFolder)) {
  110 + $parentId = $oParentFolder->getId();
  111 + $aUsers = $this->_getSubscribers($parentId, $this->subscriptionTypes["Folder"]);
  112 + $this->bulkNotification($aUsers, $eventType, $oDocObjects, $parentId);
  113 + }
111 114 }
112 115  
113 116 /*
... ... @@ -124,11 +127,25 @@ class SubscriptionEvent {
124 127 $content = new SubscriptionContent(); // needed for i18n
125 128 $locationName = Folder::generateFullFolderPath($parentId);
126 129 $userId = $_SESSION['userID'];
  130 + $oUser = & User::get($userId);
  131 + $oUserName = $oUser->getName();
  132 +
127 133 foreach ($aUsers as $oSubscriber) {
128 134 $userNotifications = array();
129 135 $aNotificationOptions = array();
130 136 $userSubscriberId = $oSubscriber->getID();
131 137 $emailAddress = $oSubscriber->getEmail();
  138 + // Email type details
  139 + $actionTypeEmail = $this->actionTypeEmail($eventType);
  140 + // Better subject header with just the modified folder location
  141 + $eSubject = "Subscription Notification: Bulk {$actionTypeEmail['message']}";
  142 + // now the email content.
  143 + $eContent .= "You are receiving this notification because you are subscribed to the \"$locationName\"<br/>";
  144 + $eContent .= "Your colleague, {$oUser->getName()}, has performed a Bulk {$actionTypeEmail['type']} in the \"$locationName\" folder.<br/>";
  145 + // REMOVE: debugger
  146 + global $default;
  147 + // Get first document/folders details into a notification
  148 + $oNotification = false;
132 149 foreach($oDocObjects as $oDocObject) {
133 150 $targetName = $oDocObject->getName();
134 151 $objectId = $oDocObject->getId();
... ... @@ -139,25 +156,61 @@ class SubscriptionEvent {
139 156 $aNotificationOptions['object_id'] = $objectId;
140 157 $aNotificationOptions['event_type'] = $eventType;
141 158 $oNotification =& KTSubscriptionNotification::generateSubscriptionNotification($aNotificationOptions);
142   - $userNotifications[] = $oNotification;
143   - }
144   - $eContent = '';
145   - $eSubject = '';
146   - // now the email content.
147   - // might not be a good idea to notify on each file
148   - //foreach($userNotifications as $userNotification) {
149   - // $eContent .= $content->getEmailAlertContent($userNotification)."<br/><br/>";
150   - // Might be an over kill subject
151   - //$eSubject .= $content->getEmailAlertSubject($userNotification)." ";
152   - //}
153   - // Better subject header with just the modified folder location
154   - $eSubject = "KnowledgeTree: Subscription notification for Bulk Upload In Folder \"$locationName\"";
155   - $eContent = "KnowledgeTree: Subscription notification for Bulk Upload In Folder \"$locationName\"";
156   - if($eContent != '' && $eSubject != '') {
157   - //echo $eContent;
158   - $oEmail = new EmailAlert($emailAddress, $eSubject, $eContent);
159   - $oEmail->send();
  159 + break;
160 160 }
  161 + $eContent .= $content->getEmailAlertContent($oNotification, $parentId);
  162 + $oEmail = new EmailAlert($emailAddress, $eSubject, $eContent);
  163 + $oEmail->send();
  164 + }
  165 + }
  166 +
  167 + function actionTypeEmail($eventType) {
  168 + switch($eventType){
  169 + case 'AddFolder':
  170 + return array("message"=>"Folders/Documents Added", "type"=>"Add");
  171 + break;
  172 + case 'RemoveSubscribedFolder':
  173 + return array("message"=>"Removed Subscribed Folders/Documents", "type"=>"Remove");
  174 + break;
  175 + case 'RemoveChildFolder':
  176 + return array("message"=>"Removed Folders/Documents", "type"=>"Remove");
  177 + break;
  178 + case 'AddDocument':
  179 + return array("message"=>"Added Folders/Documents", "type"=>"Add");
  180 + break;
  181 + case 'RemoveSubscribedDocument':
  182 + return array("message"=>"Removed Subscribed Folders/Documents", "type"=>"Remove");
  183 + break;
  184 + case 'RemoveChildDocument':
  185 + return array("message"=>"Removed Folders/Documents", "type"=>"Remove");
  186 + break;
  187 + case 'ModifyDocument':
  188 + return array("message"=>"Modified Folders/Documents", "type"=>"Modify");
  189 + break;
  190 + case 'CheckInDocument':
  191 + return array("message"=>"Checked In Documents", "type"=>"Check In");
  192 + break;
  193 + case 'CheckOutDocument':
  194 + return array("message"=>"Checked Out Documents", "type"=>"Check Out");
  195 + break;
  196 + case 'MovedDocument':
  197 + return array("message"=>"Moved Documents/Folders", "type"=>"Move");
  198 + break;
  199 + case 'CopiedDocument':
  200 + return array("message"=>"Copied Folders/Documents", "type"=>"Copy");
  201 + break;
  202 + case 'ArchivedDocument':
  203 + return array("message"=>"Archived Folders/Documents", "type"=>"Archive");
  204 + break;
  205 + case 'RestoreArchivedDocument':
  206 + return array("message"=>"Restored Archived Documents", "type"=>"Archive Restore");
  207 + break;
  208 + case 'DownloadDocument':
  209 + return array("message"=>"Downloaded Folders/Documents", "type"=>"Download");
  210 + break;
  211 + default :
  212 + return array("message"=>"Unknown Operations", "type"=>"Unknown");
  213 + break;
161 214 }
162 215 }
163 216  
... ... @@ -505,7 +558,8 @@ class SubscriptionContent {
505 558 * @param object $oKTNotification: The notification object
506 559 * @return string $str: The html string that will be sent via email
507 560 */
508   - function getEmailAlertContent($oKTNotification) {
  561 + function getEmailAlertContent($oKTNotification, $bulk_action = 0) {
  562 + if($bulk_action == 0) $bulk_action = false;
509 563 // set up logo and title
510 564 $rootUrl = KTUtil::kt_url();
511 565  
... ... @@ -528,7 +582,7 @@ class SubscriptionContent {
528 582 $downloadDocumentText = _kt('The document "').$info['object_name']._kt('"');
529 583 $documentAlertText = _kt('An alert on the document "').$info['object_name']._kt('" has been added or modified');
530 584  
531   - if($info['location_name'] !== NULL){
  585 + if($info['location_name'] !== NULL && !$bulk_action){
532 586 $addFolderText .= _kt(' to "').$info['location_name']._kt('"');
533 587 $removeChildFolderText .= _kt(' from the folder "').$info['location_name']._kt('"');
534 588 $addDocumentText .= _kt(' to "').$info['location_name']._kt('"');
... ... @@ -542,13 +596,16 @@ class SubscriptionContent {
542 596 $downloadDocumentText .= _kt(' in the folder "').$info['location_name']._kt('" has been downloaded');
543 597 $documentAlertText .= _kt(' in the folder "').$info['location_name']._kt('"');
544 598 }
545   -
  599 + if($bulk_action && $info['event_type']!="RemoveSubscribedFolder") {
  600 + $browse = "$rootUrl/browse.php?fFolderId=$bulk_action";
  601 + $subFolder = '<a href="'.$browse.'">'._kt('View Subscription Folder ').'</a>';
  602 + }
546 603 // set up links
547 604 switch($info['event_type']){
548 605 case 'AddFolder':
549 606 $text = $addFolderText;
550 607 $url = $rootUrl.'/notify.php?id='.$info['notify_id'];
551   - $links = '<a href="'.$url.'">'._kt('View New Folder').'</a>';
  608 + if(!$bulk_action) $links = '<a href="'.$url.'">'._kt('View New Folder').'</a>';
552 609 $url = $rootUrl.'/notify.php?id='.$info['notify_id'].'&notify_action=clear';
553 610 $links .= '&#160;|&#160;<a href="'.$url.'">'._kt('Clear Alert').'</a>';
554 611 break;
... ... @@ -560,14 +617,14 @@ class SubscriptionContent {
560 617 case 'RemoveChildFolder':
561 618 $text = $removeChildFolderText;
562 619 $url = $rootUrl.'/notify.php?id='.$info['notify_id'];
563   - $links = '<a href="'.$url.'">'._kt('View Folder').'</a>';
  620 + if(!$bulk_action) $links = '<a href="'.$url.'">'._kt('View Folder').'</a>';
564 621 $url = $rootUrl.'/notify.php?id='.$info['notify_id'].'&notify_action=clear';
565 622 $links .= '&#160;|&#160;<a href="'.$url.'">'._kt('Clear Alert').'</a>';
566 623 break;
567 624 case 'AddDocument':
568 625 $text = $addDocumentText;
569 626 $url = $rootUrl.'/notify.php?id='.$info['notify_id'];
570   - $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
  627 + if(!$bulk_action) $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
571 628 $url = $rootUrl.'/notify.php?id='.$info['notify_id'].'&notify_action=clear';
572 629 $links .= '&#160;|&#160;<a href="'.$url.'">'._kt('Clear Alert').'</a>';
573 630 break;
... ... @@ -584,7 +641,7 @@ class SubscriptionContent {
584 641 case 'ModifyDocument':
585 642 $text = $modifyDocumentText;
586 643 $url = $rootUrl.'/notify.php?id='.$info['notify_id'];
587   - $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
  644 + if(!$bulk_action) $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
588 645 $url = $rootUrl.'/notify.php?id='.$info['notify_id'].'&notify_action=clear';
589 646 $links .= '&#160;|&#160;<a href="'.$url.'">'._kt('Clear Alert').'</a>';
590 647 break;
... ... @@ -598,21 +655,21 @@ class SubscriptionContent {
598 655 case 'CheckOutDocument':
599 656 $text = $checkOutDocumentText;
600 657 $url = $rootUrl.'/notify.php?id='.$info['notify_id'];
601   - $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
  658 + if(!$bulk_action) $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
602 659 $url = $rootUrl.'/notify.php?id='.$info['notify_id'].'&notify_action=clear';
603 660 $links .= '&#160;|&#160;<a href="'.$url.'">'._kt('Clear Alert').'</a>';
604 661 break;
605 662 case 'MovedDocument':
606 663 $text = $modifyDocumentText;
607 664 $url = $rootUrl.'/notify.php?id='.$info['notify_id'];
608   - $links = '<a href="'.$url.'">'._kt('View New Location').'</a>';
  665 + if(!$bulk_action) $links = '<a href="'.$url.'">'._kt('View New Location').'</a>';
609 666 $url = $rootUrl.'/notify.php?id='.$info['notify_id'].'&notify_action=clear';
610 667 $links .= '&#160;|&#160;<a href="'.$url.'">'._kt('Clear Alert').'</a>';
611 668 break;
612 669 case 'CopiedDocument':
613 670 $text = $copiedDocumentText;
614 671 $url = $rootUrl.'/notify.php?id='.$info['notify_id'];
615   - $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
  672 + if(!$bulk_action) $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
616 673 $url = $rootUrl.'/notify.php?id='.$info['notify_id'].'&notify_action=clear';
617 674 $links .= '&#160;|&#160;<a href="'.$url.'">'._kt('Clear Alert').'</a>';
618 675 break;
... ... @@ -624,14 +681,14 @@ class SubscriptionContent {
624 681 case 'RestoreArchivedDocument':
625 682 $text = $restoreArchivedDocumentText;
626 683 $url = $rootUrl.'/notify.php?id='.$info['notify_id'];
627   - $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
  684 + if(!$bulk_action) $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
628 685 $url = $rootUrl.'/notify.php?id='.$info['notify_id'].'&notify_action=clear';
629 686 $links .= '&#160;|&#160;<a href="'.$url.'">'._kt('Clear Alert').'</a>';
630 687 break;
631 688 case 'DownloadDocument':
632 689 $text = $downloadDocumentText;
633 690 $url = $rootUrl.'/notify.php?id='.$info['notify_id'];
634   - $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
  691 + if(!$bulk_action) $links = '<a href="'.$url.'">'._kt('View Document').'</a>';
635 692 $url = $rootUrl.'/notify.php?id='.$info['notify_id'].'&notify_action=clear';
636 693 $links .= '&#160;|&#160;<a href="'.$url.'">'._kt('Clear Alert').'</a>';
637 694 break;
... ... @@ -652,16 +709,25 @@ class SubscriptionContent {
652 709 // we can re-use the normal template.
653 710 // however, we need to wrap it - no need for a second template here.
654 711 //$str = '<html><body>' . $this->getNotificationAlertContent($oKTNotification) . '</body></html>';
655   - $str = '<br />
656   - &#160;&#160;&#160;&#160;<b>'._kt('Subscription notification').': '.$this->_eventTypeNames[$info['event_type']].'</b>
657   - <br />
658   - <br />
659   - &#160;&#160;&#160;&#160;'.$text.'
660   - <br />
661   - <br />
662   - &#160;&#160;&#160;&#160;'.$links.'
663   - <br />
664   - <br />';
  712 + if(!$bulk_action) {
  713 + $str = '<br />
  714 + &#160;&#160;&#160;&#160;<b>'._kt('Subscription notification').': '.$this->_eventTypeNames[$info['event_type']].'</b>
  715 + <br />
  716 + <br />
  717 + &#160;&#160;&#160;&#160;'.$text.'
  718 + <br />
  719 + <br />
  720 + &#160;&#160;&#160;&#160;'.$links.'
  721 + <br />
  722 + <br />';
  723 + } else {
  724 + $str = '<br />
  725 + <br />
  726 + '.$subFolder.'
  727 + &#160;'.$links.'
  728 + <br />
  729 + <br />';
  730 + }
665 731 return $str;
666 732 }
667 733  
... ...
plugins/ktcore/KTBulkActions.php
... ... @@ -259,16 +259,34 @@ class KTBulkDeleteAction extends KTBulkAction {
259 259 return parent::do_performaction();
260 260 }
261 261  
  262 + /*
  263 + * Bulk delete
  264 + * Author : Jarrett Jordaan
  265 + * Modified : 28/04/09
  266 + *
  267 + * @params : KTDocumentUtil/KTFolderUtil $oEntity
  268 + *
  269 + * Description : Since its a bulk operation, the delete function needs to
  270 + * know that. Added extra boolean param to the delete
  271 + * function.
  272 + */
262 273 function perform_action($oEntity) {
263 274 $sReason = $this->res['reason'];
264 275  
265 276 if(is_a($oEntity, 'Document')) {
266   - $res = KTDocumentUtil::delete($oEntity, $sReason);
  277 + $res = KTDocumentUtil::delete($oEntity, $sReason, null, true);
  278 + if (PEAR::isError($res)) {
  279 + return $res;
  280 + }
  281 + return "RemoveChildDocument";
267 282 } else if(is_a($oEntity, 'Folder')) {
268   - $res = KTFolderUtil::delete($oEntity, $this->oUser, $sReason);
  283 + $res = KTFolderUtil::delete($oEntity, $this->oUser, $sReason, null, true);
  284 + if (PEAR::isError($res)) {
  285 + return $res;
  286 + }
  287 + return "RemoveChildFolder";
269 288 }
270 289  
271   - return $res;
272 290 }
273 291 }
274 292  
... ... @@ -484,7 +502,8 @@ class KTBulkMoveAction extends KTBulkAction {
484 502 $this->oTargetFolder = Folder::get($this->iTargetFolderId);
485 503 $_REQUEST['fReturnData'] = '';
486 504 $_REQUEST['fFolderId'] = $this->iTargetFolderId;
487   -
  505 + // Jarrett Jordaan : Store initial folder
  506 + $_REQUEST['fOriginalFolderId'] = $this->oFolder->getId();
488 507 // does it exists
489 508 if(PEAR::isError($this->oTargetFolder)) {
490 509 $this->errorRedirectTo('collectinfo', _kt('Invalid target folder selected'));
... ... @@ -507,12 +526,27 @@ class KTBulkMoveAction extends KTBulkAction {
507 526 return parent::do_performaction();
508 527 }
509 528  
  529 + /*
  530 + * Bulk move
  531 + * Author : Jarrett Jordaan
  532 + * Modified : 28/04/09
  533 + *
  534 + * @params : KTDocumentUtil/KTFolderUtil $oEntity
  535 + *
  536 + * Description : Since its a bulk operation, the move function needs to
  537 + * know that. Added extra boolean param to the move
  538 + * function.
  539 + */
510 540 function perform_action($oEntity) {
511 541 if(is_a($oEntity, 'Document')) {
512   - return KTDocumentUtil::move($oEntity, $this->oTargetFolder, $this->oUser, $this->sReason);
  542 + $res = KTDocumentUtil::move($oEntity, $this->oTargetFolder, $this->oUser, $this->sReason, true);
513 543 } else if(is_a($oEntity, 'Folder')) {
514   - return KTFolderUtil::move($oEntity, $this->oTargetFolder, $this->oUser, $this->sReason);
  544 + $res = KTFolderUtil::move($oEntity, $this->oTargetFolder, $this->oUser, $this->sReason, true);
515 545 }
  546 + if (PEAR::isError($res))
  547 + return $res;
  548 +
  549 + return 'MovedDocument';
516 550 }
517 551 }
518 552  
... ... @@ -737,12 +771,32 @@ class KTBulkCopyAction extends KTBulkAction {
737 771 return parent::do_performaction();
738 772 }
739 773  
  774 + /*
  775 + * Bulk copy
  776 + * Author : Jarrett Jordaan
  777 + * Modified : 28/04/09
  778 + *
  779 + * @params : KTDocumentUtil/KTFolderUtil $oEntity
  780 + *
  781 + * Description : Since its a bulk operation, the copy function needs to
  782 + * know that. Added extra boolean param to the copy
  783 + * function.
  784 + */
740 785 function perform_action($oEntity) {
741 786 if(is_a($oEntity, 'Document')) {
742   - return KTDocumentUtil::copy($oEntity, $this->oTargetFolder, $this->sReason);
  787 + $res = KTDocumentUtil::copy($oEntity, $this->oTargetFolder, null, $this->sReason, true);
  788 + if (PEAR::isError($res)) {
  789 + return $res;
  790 + }
  791 +
743 792 } else if(is_a($oEntity, 'Folder')) {
744   - return KTFolderUtil::copy($oEntity, $this->oTargetFolder, $this->oUser, $this->sReason);
  793 + $res = KTFolderUtil::copy($oEntity, $this->oTargetFolder, $this->oUser, $this->sReason, true);
  794 + if (PEAR::isError($res)) {
  795 + return $res;
  796 + }
745 797 }
  798 +
  799 + return 'CopiedDocument';
746 800 }
747 801 }
748 802  
... ... @@ -975,15 +1029,25 @@ class KTBulkArchiveAction extends KTBulkAction {
975 1029 return parent::do_performaction();
976 1030 }
977 1031  
  1032 + /*
  1033 + * Bulk archive
  1034 + * Author : Jarrett Jordaan
  1035 + * Modified : 28/04/09
  1036 + *
  1037 + * @params : KTDocumentUtil/KTFolderUtil $oEntity
  1038 + *
  1039 + * Description : Since its a bulk operation, the archive function needs
  1040 + * to know that. Added extra boolean param to the archive
  1041 + * function.
  1042 + */
978 1043 function perform_action($oEntity) {
979 1044 if(is_a($oEntity, 'Document')) {
980 1045  
981   - $res = KTDocumentUtil::archive($oEntity, $this->sReason);
  1046 + $res = KTDocumentUtil::archive($oEntity, $this->sReason, true);
982 1047  
983 1048 if(PEAR::isError($res)){
984 1049 return $res;
985 1050 }
986   - return true;
987 1051 }else if(is_a($oEntity, 'Folder')) {
988 1052 $aDocuments = array();
989 1053 $aChildFolders = array();
... ... @@ -1028,7 +1092,7 @@ class KTBulkArchiveAction extends KTBulkAction {
1028 1092 return $oDocument;
1029 1093 }
1030 1094  
1031   - $res = KTDocumentUtil::archive($oDocument, $this->sReason);
  1095 + $res = KTDocumentUtil::archive($oDocument, $this->sReason, true);
1032 1096  
1033 1097 if(PEAR::isError($res)){
1034 1098 return $res;
... ... @@ -1037,8 +1101,10 @@ class KTBulkArchiveAction extends KTBulkAction {
1037 1101 }else {
1038 1102 return PEAR::raiseError(_kt('The folder contains no documents to archive.'));
1039 1103 }
1040   - return true;
  1104 +
  1105 +
1041 1106 }
  1107 + return "ArchivedDocument";
1042 1108 }
1043 1109 }
1044 1110  
... ... @@ -1150,8 +1216,19 @@ class KTBrowseBulkExportAction extends KTBulkAction {
1150 1216 return $str;
1151 1217 }
1152 1218  
  1219 + /*
  1220 + * Bulk export
  1221 + * Author : Jarrett Jordaan
  1222 + * Modified : 28/04/09
  1223 + *
  1224 + * @params : KTDocumentUtil/KTFolderUtil $oEntity
  1225 + *
  1226 + * Description : Since its a bulk operation, the export function needs
  1227 + * to know that. Added extra boolean param to the export
  1228 + * function.
  1229 + */
1153 1230 function perform_action($oEntity) {
1154   -
  1231 +// TODO find a way to do bulk email
1155 1232 $exportCode = $_SESSION['exportcode'];
1156 1233 $this->oZip = ZipFolder::get($exportCode);
1157 1234  
... ... @@ -1189,7 +1266,8 @@ class KTBrowseBulkExportAction extends KTBulkAction {
1189 1266 $oQueue->addFolder($this->oZip, $sFolderId);
1190 1267 }
1191 1268 }
1192   - return true;
  1269 +
  1270 + return "DownloadDocument";
1193 1271 }
1194 1272  
1195 1273 function do_downloadZipFile() {
... ... @@ -1411,6 +1489,17 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction {
1411 1489 return $result;
1412 1490 }
1413 1491  
  1492 + /*
  1493 + * Bulk checkout
  1494 + * Author : Jarrett Jordaan
  1495 + * Modified : 28/04/09
  1496 + *
  1497 + * @params : KTDocumentUtil/KTFolderUtil $oEntity
  1498 + *
  1499 + * Description : Since its a bulk operation, the checkout function needs
  1500 + * to know that. Added extra boolean param to the checkout
  1501 + * function.
  1502 + */
1414 1503 function perform_action($oEntity) {
1415 1504 // checkout document
1416 1505 $sReason = $this->sReason;
... ... @@ -1431,7 +1520,7 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction {
1431 1520 return PEAR::raiseError($oEntity->getName().': '._kt('Document has already been checked out by ').$oCheckedOutUser->getName());
1432 1521 }
1433 1522 }else{
1434   - $res = KTDocumentUtil::checkout($oEntity, $sReason, $this->oUser);
  1523 + $res = KTDocumentUtil::checkout($oEntity, $sReason, $this->oUser, true);
1435 1524  
1436 1525 if(PEAR::isError($res)) {
1437 1526 return PEAR::raiseError($oEntity->getName().': '.$res->getMessage());
... ... @@ -1460,7 +1549,8 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction {
1460 1549 }
1461 1550 $this->oZip->addDocumentToZip($oEntity);
1462 1551 }
1463   -
  1552 + if(!PEAR::isError($res)) {
  1553 + }
1464 1554 }else if(is_a($oEntity, 'Folder')) {
1465 1555 // get documents and subfolders
1466 1556 $aDocuments = array();
... ... @@ -1553,7 +1643,7 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction {
1553 1643 }
1554 1644 }else{
1555 1645 // Check out document
1556   - $res = KTDocumentUtil::checkout($oDocument, $sReason, $this->oUser);
  1646 + $res = KTDocumentUtil::checkout($oDocument, $sReason, $this->oUser, true);
1557 1647  
1558 1648 if(PEAR::isError($res)) {
1559 1649 $this->addErrorMessage($oDocument->getName().': '._kt('Document could not be checked out. ').$res->getMessage());
... ... @@ -1590,7 +1680,8 @@ class KTBrowseBulkCheckoutAction extends KTBulkAction {
1590 1680 }
1591 1681 }
1592 1682 }
1593   - return true;
  1683 +
  1684 + return "CheckOutDocument";
1594 1685 }
1595 1686  
1596 1687 function do_downloadZipFile() {
... ...
plugins/ktcore/KTPermissions.php
... ... @@ -874,7 +874,7 @@ class KTDocumentRolesAction extends KTDocumentAction {
874 874 function do_main() {
875 875 $this->oPage->setTitle(_kt("View Roles"));
876 876 $this->oPage->setBreadcrumbDetails(_kt("View Roles"));
877   - $oTemplating = new KTTemplating;
  877 + $oTemplating =& KTTemplating::getSingleton();
878 878 $oTemplate = $oTemplating->loadTemplate("ktcore/action/view_roles");
879 879  
880 880 // we need to have:
... ...
plugins/ktstandard/KTBulkExportPlugin.php
... ... @@ -178,8 +178,8 @@ class KTBulkExportAction extends KTFolderAction {
178 178  
179 179 // fire subscription alerts for the downloaded document
180 180 if($bNotifications){
181   - $oSubscriptionEvent = new SubscriptionEvent();
182   - $oSubscriptionEvent->DownloadDocument($oDocument, $oFolder);
  181 + //$oSubscriptionEvent = new SubscriptionEvent();
  182 + //$oSubscriptionEvent->DownloadDocument($oDocument, $oFolder);
183 183 }
184 184  
185 185 $this->oZip->addDocumentToZip($oDocument, $oFolder);
... ...
plugins/ktstandard/KTSubscriptions.php
... ... @@ -316,16 +316,16 @@ class KTCheckoutSubscriptionTrigger {
316 316 $this->aInfo =& $aInfo;
317 317 }
318 318  
319   - function postValidate() {
  319 + function postValidate($bulk_action = false) {
320 320 global $default;
321 321 $oDocument =& $this->aInfo["document"];
322 322 // fire subscription alerts for the checked out document
323 323  
324   - // fire subscription alerts for the checked in document
325   - $oSubscriptionEvent = new SubscriptionEvent();
326   - $oFolder = Folder::get($oDocument->getFolderID());
327   - $oSubscriptionEvent->CheckoutDocument($oDocument, $oFolder);
328   -
  324 + if(!$bulk_action) {
  325 + $oSubscriptionEvent = new SubscriptionEvent();
  326 + $oFolder = Folder::get($oDocument->getFolderID());
  327 + $oSubscriptionEvent->CheckoutDocument($oDocument, $oFolder);
  328 + }
329 329 }
330 330 }
331 331 // }}}
... ... @@ -359,16 +359,17 @@ class KTDeleteSubscriptionTrigger {
359 359 $this->aInfo =& $aInfo;
360 360 }
361 361  
362   - function postValidate() {
  362 + function postValidate($bulk_action = false) {
363 363 global $default;
364 364 $oDocument =& $this->aInfo["document"];
365 365  
366 366 // fire subscription alerts for the deleted document
367   -
368   - // fire subscription alerts for the checked in document
369   - $oSubscriptionEvent = new SubscriptionEvent();
370   - $oFolder = Folder::get($oDocument->getFolderID());
371   - // $oSubscriptionEvent->RemoveDocument($oDocument, $oFolder);
  367 + if(!$bulk_action) {
  368 + // fire subscription alerts for the checked in document
  369 + $oSubscriptionEvent = new SubscriptionEvent();
  370 + $oFolder = Folder::get($oDocument->getFolderID());
  371 + //$oSubscriptionEvent->RemoveDocument($oDocument, $oFolder);
  372 + }
372 373 }
373 374 }
374 375 // }}}
... ... @@ -380,16 +381,17 @@ class KTDocumentMoveSubscriptionTrigger {
380 381 $this->aInfo =& $aInfo;
381 382 }
382 383  
383   - function postValidate() {
  384 + function postValidate($bulk_action = false) {
384 385 global $default;
385 386 $oDocument =& $this->aInfo["document"];
386 387 $oOldFolder =& $this->aInfo["old_folder"];
387 388 $oNewFolder =& $this->aInfo["new_folder"];
388 389  
389   -
390   - // fire subscription alerts for the checked in document
391   - $oSubscriptionEvent = new SubscriptionEvent();
392   - $oSubscriptionEvent->MoveDocument($oDocument, $oNewFolder, $oNewFolder);
  390 + if(!$bulk_action) {
  391 + // fire subscription alerts for the checked in document
  392 + $oSubscriptionEvent = new SubscriptionEvent();
  393 + $oSubscriptionEvent->MoveDocument($oDocument, $oNewFolder, $oNewFolder);
  394 + }
393 395 }
394 396 }
395 397 // }}}
... ... @@ -401,14 +403,15 @@ class KTArchiveSubscriptionTrigger {
401 403 $this->aInfo =& $aInfo;
402 404 }
403 405  
404   - function postValidate() {
  406 + function postValidate($bulk_action = false) {
405 407 global $default;
406 408 $oDocument =& $this->aInfo["document"];
407   -
408   - // fire subscription alerts for the checked in document
409   - $oSubscriptionEvent = new SubscriptionEvent();
410   - $oFolder = Folder::get($oDocument->getFolderID());
411   - $oSubscriptionEvent->ArchivedDocument($oDocument, $oFolder);
  409 + if(!$bulk_action) {
  410 + // fire subscription alerts for the checked in document
  411 + $oSubscriptionEvent = new SubscriptionEvent();
  412 + $oFolder = Folder::get($oDocument->getFolderID());
  413 + $oSubscriptionEvent->ArchivedDocument($oDocument, $oFolder);
  414 + }
412 415 }
413 416 }
414 417 // }}}
... ...
search2/documentProcessor/documentProcessor.inc.php
... ... @@ -173,7 +173,6 @@ class DocumentProcessor
173 173 // indexing starting - create lock file
174 174 touch($lockFile);
175 175  
176   -
177 176 // Process queue
178 177 foreach($queue as $item){
179 178  
... ...
search2/indexing/extractorCore.inc.php
... ... @@ -695,7 +695,6 @@ abstract class TextExtractor extends DocumentExtractor
695 695 */
696 696 public function extractTextContent()
697 697 {
698   -
699 698 $config = KTConfig::getSingleton();
700 699 $maxTextSize = $config->get('indexer/maxTextSize', 1024 * 1024 * 10); // we'll only take 10 meg by default
701 700 $content = file_get_contents($this->sourcefile, null, null, null, $maxTextSize);
... ...
search2/indexing/extractors/PlainTextExtractor.inc.php
... ... @@ -7,31 +7,31 @@
7 7 * Document Management Made Simple
8 8 * Copyright (C) 2008, 2009 KnowledgeTree Inc.
9 9 * Portions copyright The Jam Warehouse Software (Pty) Limited
10   - *
  10 + *
11 11 * This program is free software; you can redistribute it and/or modify it under
12 12 * the terms of the GNU General Public License version 3 as published by the
13 13 * Free Software Foundation.
14   - *
  14 + *
15 15 * This program is distributed in the hope that it will be useful, but WITHOUT
16 16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 17 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 18 * details.
19   - *
  19 + *
20 20 * You should have received a copy of the GNU General Public License
21 21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22   - *
23   - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
  22 + *
  23 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
24 24 * California 94120-7775, or email info@knowledgetree.com.
25   - *
  25 + *
26 26 * The interactive user interfaces in modified source and object code versions
27 27 * of this program must display Appropriate Legal Notices, as required under
28 28 * Section 5 of the GNU General Public License version 3.
29   - *
  29 + *
30 30 * In accordance with Section 7(b) of the GNU General Public License version 3,
31 31 * these Appropriate Legal Notices must retain the display of the "Powered by
32   - * KnowledgeTree" logo and retain the original copyright notice. If the display of the
  32 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
33 33 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
34   - * must display the words "Powered by KnowledgeTree" and retain the original
  34 + * must display the words "Powered by KnowledgeTree" and retain the original
35 35 * copyright notice.
36 36 * Contributor( s): ______________________________________
37 37 *
... ... @@ -46,6 +46,7 @@ class PlainTextExtractor extends TextExtractor
46 46  
47 47 public function getSupportedMimeTypes()
48 48 {
  49 + return array();
49 50 return array(
50 51 'text/plain',
51 52 'text/csv',
... ...
search2/indexing/extractors/TikaApacheExtractor.inc.php
... ... @@ -56,6 +56,11 @@ class TikaApacheExtractor extends DocumentExtractor
56 56 return _kt('Tika Apache Extractor');
57 57 }
58 58  
  59 + public function needsIntermediateSourceFile()
  60 + {
  61 + return true;
  62 + }
  63 +
59 64 /**
60 65 * The mime types supported by the extractor
61 66 *
... ... @@ -64,10 +69,47 @@ class TikaApacheExtractor extends DocumentExtractor
64 69 public function getSupportedMimeTypes()
65 70 {
66 71 return array(
  72 + // pdf
67 73 'application/pdf',
  74 + // office OLE2 format - 2003, xp, etc
68 75 'application/vnd.ms-excel',
69 76 'application/vnd.ms-powerpoint',
70   - 'application/msword'
  77 + 'application/msword',
  78 + // rtf
  79 + 'text/rtf',
  80 + // staroffice
  81 + 'application/vnd.sun.xml.writer',
  82 + 'application/vnd.sun.xml.writer.template',
  83 + 'application/vnd.sun.xml.calc',
  84 + 'application/vnd.sun.xml.calc.template',
  85 + // text
  86 + 'text/plain',
  87 + 'text/csv',
  88 + 'text/tab-separated-values',
  89 + 'text/css',
  90 + // open xml
  91 + /*
  92 + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  93 + 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
  94 + 'application/vnd.openxmlformats-officedocument.presentationml.template',
  95 + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
  96 + 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  97 + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  98 + 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
  99 + // openoffice
  100 + 'application/vnd.oasis.opendocument.presentation',
  101 + 'application/vnd.oasis.opendocument.presentation-template',
  102 + 'application/vnd.oasis.opendocument.spreadsheet',
  103 + 'application/vnd.oasis.opendocument.spreadsheet-template',
  104 + 'application/vnd.oasis.opendocument.text',
  105 + 'application/vnd.oasis.opendocument.text-template',
  106 + 'application/vnd.oasis.opendocument.text-master',
  107 + // xml
  108 + 'text/xml',
  109 + 'application/xml',
  110 + 'text/html',
  111 + 'text/enriched'
  112 + */
71 113 );
72 114 }
73 115  
... ... @@ -78,6 +120,18 @@ class TikaApacheExtractor extends DocumentExtractor
78 120 */
79 121 public function extractTextContent()
80 122 {
  123 + $filename = $this->sourcefile;
  124 + $targetFile = $this->targetfile;
  125 +
  126 + $result = $this->xmlrpc->extractTextContent($filename, $targetFile);
  127 +
  128 + if($result === false){
  129 + $this->output = _kt('Tika Extractor: XML-RPC failed to extract text.');
  130 + return false;
  131 + }
  132 + return true;
  133 +
  134 + /* Using streamed content
81 135 // stream document content
82 136 $filename = $this->sourcefile;
83 137 $buffer = file_get_contents($filename);
... ... @@ -99,6 +153,7 @@ class TikaApacheExtractor extends DocumentExtractor
99 153 file_put_contents($this->targetfile, $extractedText);
100 154 unset($extractedText);
101 155 return true;
  156 + */
102 157 }
103 158  
104 159 /**
... ...
search2/indexing/indexerCore.inc.php
... ... @@ -1255,6 +1255,15 @@ abstract class Indexer
1255 1255 // increment indexed documents count
1256 1256 Indexer::incrementCount();
1257 1257  
  1258 + // if document is a zero byte file, let's just unqueue and return
  1259 + if ($document->getFileSize() == 0)
  1260 + {
  1261 + Indexer::unqueueDocument($docinfo['document_id'],
  1262 + sprintf(_kt("Zero Byte documents do not need to be indexed: %d"),
  1263 + $docinfo['document_id']));
  1264 + return;
  1265 + }
  1266 +
1258 1267 $docId = $docinfo['document_id'];
1259 1268 $extension = $docinfo['filetypes'];
1260 1269 $mimeType = $docinfo['mimetypes'];
... ... @@ -1312,7 +1321,7 @@ abstract class Indexer
1312 1321 Indexer::unqueueDocument($docId,sprintf(_kt("indexDocuments: Filename for document id %d starts with a tilde (~). This is assumed to be a temporary file. This is ignored."),$docId), 'error');
1313 1322 return ;
1314 1323 }
1315   -
  1324 +
1316 1325 $removeFromQueue = true;
1317 1326 if ($indexDocument)
1318 1327 {
... ...
search2/indexing/lib/XmlRpcLucene.inc.php
... ... @@ -285,11 +285,37 @@ class XmlRpcLucene
285 285 }
286 286  
287 287 /**
  288 + * Extracts the text from a given document and writes it to the target file
  289 + *
  290 + * @param string $sourceFile The full path to the document
  291 + * @param string $targetFile The full path to the target / output file
  292 + * @return boolean true on success | false on failure
  293 + */
  294 + function extractTextContent($sourceFile, $targetFile)
  295 + {
  296 + $function = new xmlrpcmsg('textextraction.getTextFromFile',
  297 + array(
  298 + php_xmlrpc_encode((string) $sourceFile),
  299 + php_xmlrpc_encode((string) $targetFile)
  300 + )
  301 + );
  302 +
  303 + $result =& $this->client->send($function, 120);
  304 +
  305 + if($result->faultCode()) {
  306 + $this->error($result, 'extractTextContent');
  307 + return false;
  308 + }
  309 + return php_xmlrpc_decode($result->value()) == 0;
  310 + }
  311 +
  312 + /**
288 313 * Extracts the text from a given document stream
289 314 *
290   - * @return unknown
  315 + * @param string $content The document content
  316 + * @return string The extracted text on success | false on failure
291 317 */
292   - function extractTextContent($content)
  318 + function extractTextContentByStreaming($content)
293 319 {
294 320 $function = new xmlrpcmsg('textextraction.getText',
295 321 array(
... ...
setup/upgrade.php
... ... @@ -183,10 +183,11 @@ if (PEAR::isError($dbSupport)) {
183 183  
184 184  
185 185 ?>
  186 +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN">
186 187 <html>
187 188 <head>
188 189 <title><?php echo APP_NAME;?> Upgrade</title>
189   - <style>
  190 + <style type="text/css">
190 191 th { text-align: left; }
191 192 td { vertical-align: top; }
192 193 .foo { float: left; }
... ... @@ -203,13 +204,13 @@ td { vertical-align: top; }
203 204 echo $oKTConfig->get('ui/mainLogo');
204 205 }else{
205 206 echo '../resources/graphics/ktlogo-topbar_base.png';
206   - }?>">
  207 + }?>"/>
207 208 <p>
208   - <img src="upgrade-title.jpg">
209   - <table width=800 height=500>
  209 + <img src="upgrade-title.jpg"/>
  210 + <table style="width:800; height:500">
210 211 <tr><td>
211 212 <P>
212   - <script>
  213 + <script type="text/javascript">
213 214 function do_start(action)
214 215 {
215 216 document.location='?go=' + action;
... ... @@ -458,8 +459,8 @@ function create_restore_stmt($targetfile)
458 459  
459 460 $tmpdir=resolveTempDir();
460 461  
461   - $stmt = $prefix ."mysqladmin --user=\"$adminUser\" -p $mechanism drop \"$dbName\"<br>";
462   - $stmt .= $prefix ."mysqladmin --user=\"$adminUser\" -p $mechanism create \"$dbName\"<br>";
  462 + $stmt = $prefix ."mysqladmin --user=\"$adminUser\" -p $mechanism drop \"$dbName\"<br/>";
  463 + $stmt .= $prefix ."mysqladmin --user=\"$adminUser\" -p $mechanism create \"$dbName\"<br/>";
463 464  
464 465  
465 466 $stmt .= $prefix ."mysql --user=\"$adminUser\" -p $mechanism \"$dbName\" < \"$targetfile\"\n";
... ... @@ -478,7 +479,7 @@ function title($title)
478 479 {
479 480 if (!isset($_SESSION['setup_user']))
480 481 {
481   - print "<script>document.location='?go=Login'</script>";
  482 + print "<script type='text/javascript'>document.location='?go=Login'</script>";
482 483 }
483 484 print "<h1>$title</h1>";
484 485 }
... ... @@ -511,10 +512,10 @@ function upgradeConfirm()
511 512 if (!isset($_SESSION['backupStatus']) || $_SESSION['backupStatus'] === false)
512 513 {
513 514 ?>
514   -<br>
  515 +<br/>
515 516 <font color="Red">Please ensure that you have made a backup before continuing with the upgrade process.</font>
516 517 <p>
517   -<br>
  518 +<br/>
518 519 <?php
519 520 }
520 521 ?>
... ... @@ -550,7 +551,7 @@ Your mysql installation has been resolved. Manually, you would do the following:
550 551 <tr>
551 552 <td>
552 553 <nobr>cd "<?php echo $dir;?>"</nobr>
553   -<br>
  554 +<br/>
554 555 <?php
555 556 }
556 557 else
... ... @@ -617,7 +618,7 @@ function restoreSelect()
617 618 <P>
618 619 Select a backup to restore from the list below:
619 620 <P>
620   - <script>
  621 + <script type="text/javascript">
621 622 function selectRestore(filename)
622 623 {
623 624 document.location='?go=RestoreSelected&file=' + filename;
... ... @@ -659,7 +660,7 @@ function restoreSelected()
659 660 $dir = resolveTempDir();
660 661 $_SESSION['backupFile'] = $dir . '/' . $file;
661 662 ?>
662   -<script>
  663 +<script type="text/javascript">
663 664 document.location='?go=RestoreConfirm';
664 665 </script>
665 666 <?php
... ... @@ -691,7 +692,7 @@ Manually, you would do the following to restore the backup:
691 692 <tr>
692 693 <td>
693 694 <nobr>cd "<?php echo $dir;?>"</nobr>
694   -<br>
  695 +<br/>
695 696 <?php
696 697 }
697 698 else
... ... @@ -709,6 +710,8 @@ You can continue to do the restore manually using the following command(s):
709 710 }
710 711 ?>
711 712 <nobr><?php echo $stmt['display'];?></nobr>
  713 +</td>
  714 +</tr>
712 715 </table>
713 716 <P>
714 717 <?php
... ... @@ -729,7 +732,7 @@ Press &lt;i&gt;continue to restore&lt;/i&gt; to attempt the command(s) above.
729 732 if ($dir != '')
730 733 {
731 734 ?>
732   -<script>
  735 +<script type="text/javascript">
733 736 function restore()
734 737 {
735 738 if (confirm('Are you sure you want to restore? This is your last chance if the current data has not been backed up.'))
... ... @@ -758,7 +761,7 @@ function backupDone()
758 761 {
759 762 $stmt=create_restore_stmt($filename);
760 763 ?>
761   - The backup file <nobr><I>"<?php echo $filename;?>"</i></nobr> has been created.
  764 + The backup file <nobr><i>"<?php echo $filename;?>"</i></nobr> has been created.
762 765 <P> It appears as though the <font color=green>backup has been successful</font>.
763 766 <P>
764 767 <?php
... ... @@ -771,7 +774,7 @@ function backupDone()
771 774 <tr>
772 775 <td>
773 776 <nobr>cd <?php echo $stmt['dir'];?></nobr>
774   - <br>
  777 + <br/>
775 778 <?php
776 779 }
777 780 else
... ... @@ -809,7 +812,7 @@ We appologise for the inconvenience.
809 812  
810 813 }
811 814 ?>
812   -<br>
  815 +<br/>
813 816  
814 817 &nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="back" onclick="javascript:do_start('welcome')">
815 818 <?php
... ... @@ -833,7 +836,7 @@ function restoreDone()
833 836 {
834 837  
835 838 ?>
836   - The restore of <nobr><I>"<?php echo $filename;?>"</i></nobr> has been completed.
  839 + The restore of <nobr><i>"<?php echo $filename;?>"</i></nobr> has been completed.
837 840 <P>
838 841 It appears as though the <font color=green>restore has been successful</font>.
839 842 <P>
... ... @@ -861,7 +864,7 @@ We appologise for the inconvenience.
861 864 }
862 865 ?>
863 866  
864   -<br>
  867 +<br/>
865 868  
866 869 &nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="back" onclick="javascript:do_start('welcome')">
867 870  
... ... @@ -878,7 +881,7 @@ function check_state($value, $state=&#39;Home&#39;)
878 881 if ($_SESSION['state'] != $value)
879 882 {
880 883 ?>
881   - <script>
  884 + <script type="text/javascript">
882 885 document.location="?go=<?php echo $state;?>";
883 886 </script>
884 887 <?php
... ... @@ -935,7 +938,7 @@ function backup()
935 938 $_SESSION['backupStatus'] = false;
936 939 }
937 940 ?>
938   - <script>
  941 + <script type="text/javascript">
939 942 document.location="?go=BackupDone";
940 943 </script>
941 944 <?php
... ... @@ -1007,7 +1010,7 @@ function restore()
1007 1010  
1008 1011  
1009 1012 ?>
1010   - <script>
  1013 + <script type="text/javascript">
1011 1014 document.location="?go=RestoreDone";
1012 1015 </script>
1013 1016 <?php
... ... @@ -1033,22 +1036,22 @@ function welcome()
1033 1036 {
1034 1037 set_state(1);
1035 1038 ?>
1036   -<br>
  1039 +<br/>
1037 1040 Welcome to the <?php echo APP_NAME;?> Database Upgrade Wizard.<P> If you have just updated
1038 1041 your <?php echo APP_NAME;?> code base, you will need to complete the upgrade process in order to ensure your system is fully operational with the new version.
1039 1042 <P>
1040 1043 You will not be able to log into <?php echo APP_NAME;?> until your the database upgrade process is completed.
1041 1044 <P>
1042   -<font color=orange>!!NB!! You are advised to backup the database before attempting the upgrade. !!NB!!</font>
  1045 +<font color="#ffa500">!!NB!! You are advised to backup the database before attempting the upgrade. !!NB!!</font>
1043 1046 <P>
1044 1047 If you have already done this, you may skip this step can continue directly to the upgrade.
1045 1048 <P>
1046 1049  
1047 1050  
1048   -&nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="cancel" onclick="document.location='..';">
1049   -&nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="backup now" onclick="javascript:do_start('BackupConfirm');">
1050   -&nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="next" onclick="javascript:do_start('UpgradeConfirm');">
1051   -&nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="restore database" onclick="javascript:do_start('RestoreConfirm');">
  1051 +&nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="cancel" onclick="document.location='..';"/>
  1052 +&nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="backup now" onclick="javascript:do_start('BackupConfirm');"/>
  1053 +&nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="next" onclick="javascript:do_start('UpgradeConfirm');"/>
  1054 +&nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="restore database" onclick="javascript:do_start('RestoreConfirm');"/>
1052 1055  
1053 1056  
1054 1057 <?php
... ... @@ -1069,7 +1072,7 @@ function UpgradePreview()
1069 1072 $upgradeTable = generateUpgradeTable();
1070 1073 print $upgradeTable;
1071 1074 ?>
1072   - <br>
  1075 + <br/>
1073 1076  
1074 1077 &nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="back" onclick="javascript:do_start('home')">
1075 1078 &nbsp;&nbsp; &nbsp; &nbsp; <input type=button value="next" onclick="javascript:do_start('Upgrade')">
... ... @@ -1091,14 +1094,14 @@ function Upgrade()
1091 1094 if (PEAR::isError($pre_res))
1092 1095 {
1093 1096 ?>
1094   -<font color="red">Pre-Upgrade actions failed.</font><br>
  1097 +<font color="red">Pre-Upgrade actions failed.</font><br/>
1095 1098 <?php
1096 1099 }
1097 1100 else
1098 1101 {
1099 1102 ?>
1100 1103 <p>
1101   -<font color="green">Pre-Upgrade actions succeeded.</font><br>
  1104 +<font color="green">Pre-Upgrade actions succeeded.</font><br/>
1102 1105 <?php
1103 1106 }
1104 1107 ?>
... ... @@ -1125,15 +1128,15 @@ function Upgrade()
1125 1128 if (PEAR::isError($post_res))
1126 1129 {
1127 1130 ?>
1128   -<font color="red">Post-Upgrade actions failed.</font><br><br>
  1131 +<font color="red">Post-Upgrade actions failed.</font><br/><br/>
1129 1132 <?php
1130 1133 }
1131 1134 else
1132 1135 {
1133 1136 ?>
1134 1137 <p>
1135   -<font color="green">Post-Upgrade actions succeeded.</font><br><br>
1136   -<script>
  1138 +<font color="green">Post-Upgrade actions succeeded.</font><br/><br/>
  1139 +<script type="text/javascript">
1137 1140 alert("To complete the upgrade please do the following before continuing:\n\n1. Restart the services as appropriate for your environment.\n\n\nOn first run of your upgraded installaton please do the following:\n\n1. Hard refresh your bowser (CTRL-F5) on first view of the Dashboard.\n2. Enable the new plugins you wish to use.\n\n\nSelect 'next' at the bottom of this page to continue.")
1138 1141 </script>
1139 1142 <?php
... ...
sql/mysql/upgrade/3.1.6.3/groups-integrity.sql
... ... @@ -2,13 +2,37 @@
2 2  
3 3 -- parent_group_id
4 4  
5   -DELETE FROM `groups_groups_link` as gg USING `groups_groups_link` as gg, groups_lookup
6   - WHERE not exists(select 1 from `groups_lookup` as g where gg.parent_group_id = g.id);
  5 +CREATE TEMPORARY TABLE cleanup (
  6 + `id` int(11) NOT NULL auto_increment,
  7 + `parent_group_id` int(11) NOT NULL default '0',
  8 + `member_group_id` int(11) NOT NULL default '0',
  9 + PRIMARY KEY (`id`),
  10 + KEY `parent_group_id` (`parent_group_id`),
  11 + KEY `member_group_id` (`member_group_id`)
  12 +);
  13 +INSERT INTO cleanup (id, parent_group_id, member_group_id)
  14 +SELECT * FROM `groups_groups_link` AS gg WHERE ( SELECT 1 FROM `groups_lookup` AS g WHERE gg.parent_group_id = g.id);
  15 +SELECT * FROM cleanup;
  16 +TRUNCATE groups_groups_link;
  17 +INSERT groups_groups_link SELECT * FROM cleanup;
  18 +DROP TABLE cleanup;
7 19  
8 20 -- member_group_id
9 21  
10   -DELETE FROM `groups_groups_link` as gg USING `groups_groups_link` as gg, groups_lookup
11   - WHERE not exists(select 1 from `groups_lookup` as g where gg.member_group_id = g.id);
  22 +CREATE TEMPORARY TABLE cleanup (
  23 + `id` int(11) NOT NULL auto_increment,
  24 + `parent_group_id` int(11) NOT NULL default '0',
  25 + `member_group_id` int(11) NOT NULL default '0',
  26 + PRIMARY KEY (`id`),
  27 + KEY `parent_group_id` (`parent_group_id`),
  28 + KEY `member_group_id` (`member_group_id`)
  29 +);
  30 +INSERT INTO cleanup (id, parent_group_id, member_group_id)
  31 +SELECT * FROM `groups_groups_link` AS gg WHERE ( SELECT 1 FROM `groups_lookup` AS g WHERE gg.member_group_id = g.id);
  32 +SELECT * FROM cleanup;
  33 +TRUNCATE groups_groups_link;
  34 +INSERT groups_groups_link SELECT * FROM cleanup;
  35 +DROP TABLE cleanup;
12 36  
13 37 -- ADD CONSTRAINT
14 38  
... ... @@ -16,21 +40,44 @@ ALTER TABLE `groups_groups_link`
16 40 ADD CONSTRAINT `groups_groups_link_ibfk_1` FOREIGN KEY (`parent_group_id`) REFERENCES `groups_lookup` (`id`) ON DELETE CASCADE,
17 41 ADD CONSTRAINT `groups_groups_link_ibfk_2` FOREIGN KEY (`member_group_id`) REFERENCES `groups_lookup` (`id`) ON DELETE CASCADE;
18 42  
  43 +
19 44 -- PREPARE FOR ADDING CONSTRAINTS ON `users_groups_link`
20 45  
21 46 -- group_id
22   -
23   -DELETE FROM `users_groups_link` as ug USING `users_groups_link` as ug, groups_lookup
24   - WHERE not exists(select 1 from `groups_lookup` as g where ug.group_id = g.id);
  47 +CREATE TEMPORARY TABLE cleanup (
  48 + `id` int(11) NOT NULL auto_increment,
  49 + `user_id` int(11) NOT NULL default '0',
  50 + `group_id` int(11) NOT NULL default '0',
  51 + PRIMARY KEY (`id`),
  52 + KEY `user_id` (`user_id`),
  53 + KEY `group_id` (`group_id`)
  54 +);
  55 +INSERT INTO cleanup (id, user_id, group_id)
  56 +SELECT * FROM `users_groups_link` AS ug WHERE ( SELECT 1 FROM `groups_lookup` AS g WHERE ug.group_id = g.id);
  57 +SELECT * FROM cleanup;
  58 +TRUNCATE groups_groups_link;
  59 +INSERT groups_groups_link SELECT * FROM cleanup;
  60 +DROP TABLE cleanup;
25 61  
26 62 -- user_id
27   -
28   -DELETE FROM `users_groups_link` as ug USING `users_groups_link` as ug, users
29   - WHERE not exists(select 1 from `users` as u where ug.user_id = u.id);
  63 +CREATE TEMPORARY TABLE cleanup (
  64 + `id` int(11) NOT NULL auto_increment,
  65 + `user_id` int(11) NOT NULL default '0',
  66 + `group_id` int(11) NOT NULL default '0',
  67 + PRIMARY KEY (`id`),
  68 + KEY `user_id` (`user_id`),
  69 + KEY `group_id` (`group_id`)
  70 +);
  71 +INSERT INTO cleanup (id, user_id, group_id)
  72 +SELECT * FROM `users_groups_link` AS ug WHERE ( SELECT 1 FROM `groups_lookup` AS g WHERE ug.user_id = g.id);
  73 +SELECT * FROM cleanup;
  74 +TRUNCATE groups_groups_link;
  75 +INSERT groups_groups_link SELECT * FROM cleanup;
  76 +DROP TABLE cleanup;
30 77  
31 78 -- ADD CONSTRAINT
32 79  
33 80 ALTER TABLE `users_groups_link`
34 81 ADD CONSTRAINT `users_groups_link_ibfk_1` FOREIGN KEY (`group_id`) REFERENCES `groups_lookup` (`id`) ON DELETE CASCADE,
35   - ADD CONSTRAINT `users_groups_link_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
  82 + ADD CONSTRAINT `users_groups_link_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE;
36 83  
... ...
templates/ktcore/search2/adv_query_builder.smarty
... ... @@ -426,7 +426,7 @@ function addFieldTypeSelection(groupid, fid, type, options)
426 426 var html = '';
427 427 var callback = null;
428 428 var params = null;
429   -alert(type);
  429 +
430 430 switch(type)
431 431 {
432 432 case 'FILESIZE':
... ...
templates/ktcore/search2/search_results.smarty
... ... @@ -156,10 +156,10 @@ function onShowAll(showall)
156 156 <span class="contenttype {$hit->MimeIconPath}">
157 157  
158 158 {if $hit->IsDocument}
159   - &nbsp;&nbsp;<a href="{$rootUrl}/view.php?fDocumentId={$hit->Id}"><B>{$hit->Title|mb_truncate:30:'...':true}</b></a>
  159 + &nbsp;&nbsp;<a href="{$rootUrl}/view.php?fDocumentId={$hit->Id}" title="{$hit->Title}"><B>{$hit->Title|mb_truncate:80:'...':true}</b></a>
160 160 {if $hit->Title != $hit->Filename}
161   - &nbsp;&nbsp;
162   - <font style=" color: green "> - {i18n}Filename:{/i18n} {$hit->Filename|mb_truncate:30:'...':true}</font>
  161 + <br/>
  162 + <font style=" color: green ">{i18n}Filename:{/i18n} {$hit->Filename|mb_truncate:80:'...':true}</font>
163 163 {/if}
164 164 {if $hit->IsAvailable}
165 165 &nbsp;&nbsp;
... ...
tests/api/testElectronicSignatures.php 0 โ†’ 100644
  1 +<?php
  2 +require_once (KT_DIR . '/tests/test.php');
  3 +require_once (KT_DIR . '/ktapi/ktapi.inc.php');
  4 +
  5 +/**
  6 +* These are the unit tests for the main KTAPI class
  7 +*
  8 +*/
  9 +class APIElectronicSignaturesTestCase extends KTUnitTestCase {
  10 +
  11 + /**
  12 + * @var object $ktapi The main ktapi object
  13 + */
  14 + var $ktapi;
  15 +
  16 + /**
  17 + * @var object $session The KT session object
  18 + */
  19 + var $session;
  20 +
  21 + /**
  22 + * @var object $root The KT folder object
  23 + */
  24 + var $root;
  25 +
  26 + /**
  27 + * @var bool $esig_enabled True if electronic signatures for api are enabled | False if not enabled
  28 + */
  29 + var $esig_enabled;
  30 +
  31 + /**
  32 + * This method sets up the KT session
  33 + *
  34 + */
  35 + public function setUp() {
  36 + $this->ktapi = new KTAPI();
  37 + $this->session = $this->ktapi->start_session('admin', 'admin');
  38 + $this->root = $this->ktapi->get_root_folder();
  39 + $this->assertTrue($this->root instanceof KTAPI_Folder);
  40 + $this->esig_enabled = $this->ktapi->electronic_sig_enabled();
  41 + $this->assertTrue($this->esig_enabled);
  42 + }
  43 +
  44 + /**
  45 + * This method emds the KT session
  46 + *
  47 + */
  48 + public function tearDown() {
  49 + $this->session->logout();
  50 + }
  51 +
  52 + /* *** Test webservice functions *** */
  53 +
  54 + /**
  55 + * Testing folder creation and deletion, add document, get folder contents, folder detail
  56 + * Folder shortcuts and actions
  57 + */
  58 + public function testFolderApiFunctions()
  59 + {
  60 + // Create a folder
  61 + // test without authentication - should fail
  62 + $result1 = $this->ktapi->create_folder(1, 'New test api folder');
  63 + $this->assertEqual($result1['status_code'], 1);
  64 +
  65 + // test with authentication
  66 + $result2 = $this->ktapi->create_folder(1, 'New test api folder', 'admin', 'admin', 'Testing API');
  67 + $folder_id = $result2['results']['id'];
  68 + $this->assertEqual($result2['status_code'], 0);
  69 + $this->assertTrue($result2['results']['parent_id'] == 1);
  70 +
  71 + // Create a sub folder
  72 + // test without authentication - should fail
  73 + $result3 = $this->ktapi->create_folder($folder_id, 'New test api sub-folder');
  74 + $this->assertEqual($result3['status_code'], 1);
  75 +
  76 + // test with authentication
  77 + $result4 = $this->ktapi->create_folder($folder_id, 'New test api sub-folder', 'admin', 'admin', 'Testing API');
  78 + $folder_id2 = $result4['results']['id'];
  79 + $this->assertEqual($result4['status_code'], 0);
  80 +
  81 + // Add a document
  82 + global $default;
  83 + $dir = $default->uploadDirectory;
  84 + $tempfilename = $this->createRandomFile('some text', $dir);
  85 +
  86 + // test without authentication - should fail
  87 + $doc = $this->ktapi->add_document($folder_id, 'New API test doc', 'testdoc1.txt', 'Default', $tempfilename);
  88 + $this->assertEqual($doc['status_code'], 1);
  89 +
  90 + // test with authentication
  91 + $doc = $this->ktapi->add_document($folder_id, 'New API test doc', 'testdoc1.txt', 'Default', $tempfilename,
  92 + 'admin', 'admin', 'Testing API');
  93 + $this->assertEqual($doc['status_code'], 0);
  94 + $doc_id = $doc['results']['document_id'];
  95 + $this->assertEqual($doc['results']['title'], 'New API test doc');
  96 +
  97 + // Rename the folder
  98 + // test without authentication - should fail
  99 + $renamed = $this->ktapi->rename_folder($folder_id, 'Renamed test folder');
  100 + $this->assertEqual($renamed['status_code'], 1);
  101 +
  102 + // test with authentication
  103 + $renamed = $this->ktapi->rename_folder($folder_id, 'Renamed test folder', 'admin', 'admin', 'Testing API');
  104 + $this->assertEqual($renamed['status_code'], 0);
  105 +
  106 + /**
  107 + * Copy and move appear to fail in other parts of the code, so only going to test failure here
  108 + *
  109 + * Must be VERY careful here with skipping the valid submissions, 3 failed auth attempts in a row locks out the user!
  110 + */
  111 + // Copy folder
  112 + // test without authentication - should fail
  113 + $copied = $this->ktapi->copy_folder($source_id, $target_id, $reason);
  114 + $this->assertEqual($copied['status_code'], 1);
  115 +
  116 +// // test with authentication
  117 +// $copied = $this->ktapi->copy_folder($source_id, $target_id, $reason, 'admin', 'admin');
  118 +// echo $copied['status_code']."sd<BR>";
  119 +// $this->assertEqual($copied['status_code'], 0);
  120 +
  121 + // Move folder
  122 + // test without authentication - should fail
  123 + $moved = $this->ktapi->move_folder($source_id, $target_id, $reason);
  124 + $this->assertEqual($moved['status_code'], 1);
  125 +
  126 + // before we end up with 3 fails in a row (see note above the first copy attempt,) force a successful auth
  127 + $renamed = $this->ktapi->rename_folder($folder_id, 'A New Name', 'admin', 'admin', 'Testing API');
  128 +
  129 +// // test with authentication
  130 +// $moved = $this->ktapi->move_folder($source_id, $target_id, $reason, 'admin', 'admin');
  131 +// $this->assertEqual($moved['status_code'], 0);
  132 +
  133 + // before we end up with 3 fails in a row (see note above the first copy attempt,) force a successful auth
  134 + $renamed = $this->ktapi->rename_folder($folder_id, 'A New Name', 'admin', 'admin', 'Testing API');
  135 +
  136 + // Clean up - delete the folder
  137 + // test without authentication - should fail
  138 + $deleted = $this->ktapi->delete_folder($folder_id, 'Testing API');
  139 + $this->assertEqual($deleted['status_code'], 1);
  140 +
  141 + // test with authentication
  142 + $deleted = $this->ktapi->delete_folder($folder_id, 'Testing API', 'admin', 'admin');
  143 + $this->assertEqual($deleted['status_code'], 0);
  144 + }
  145 +
  146 + /**
  147 + * Testing document get, update, actions, delete, shortcuts and detail
  148 + */
  149 + public function testDocumentApiFunctions()
  150 + {
  151 + // Create a folder
  152 + // test without authentication - should fail
  153 + $result1 = $this->ktapi->create_folder(1, 'New test api folder');
  154 + $this->assertEqual($result1['status_code'], 1);
  155 +
  156 + // test with authentication
  157 + $result2 = $this->ktapi->create_folder(1, 'New test api folder', 'admin', 'admin', 'Testing API');
  158 + $folder_id = $result2['results']['id'];
  159 + $this->assertEqual($result2['status_code'], 0);
  160 +
  161 + // Create a sub folder
  162 + // test without authentication - should fail
  163 + $result3 = $this->ktapi->create_folder($folder_id, 'New test api sub-folder');
  164 + $this->assertEqual($result3['status_code'], 1);
  165 +
  166 + // test with authentication
  167 + $result4 = $this->ktapi->create_folder($folder_id, 'New test api sub-folder', 'admin', 'admin', 'Testing API');
  168 + $folder_id2 = $result4['results']['id'];
  169 + $this->assertEqual($result4['status_code'], 0);
  170 +
  171 + // Add a document
  172 + global $default;
  173 + $dir = $default->uploadDirectory;
  174 + $tempfilename = $this->createRandomFile('some text', $dir);
  175 +
  176 + // test without authentication - should fail
  177 + $doc = $this->ktapi->add_document($folder_id, 'New API test doc', 'testdoc1.txt', 'Default', $tempfilename);
  178 + $this->assertEqual($doc['status_code'], 1);
  179 +
  180 + // test with authentication
  181 + $doc = $this->ktapi->add_document($folder_id, 'New API test doc', 'testdoc1.txt', 'Default', $tempfilename,
  182 + 'admin', 'admin', 'Testing API');
  183 + $this->assertEqual($doc['status_code'], 0);
  184 + $doc_id = $doc['results']['document_id'];
  185 +
  186 + // Checkout the document
  187 + // test without authentication - should fail
  188 + $result1 = $this->ktapi->checkout_document($doc_id, 'Testing API', true);
  189 + $this->assertEqual($result1['status_code'], 1);
  190 +
  191 + // test with authentication
  192 + $result2 = $this->ktapi->checkout_document($doc_id, 'Testing API', true, 'admin', 'admin');
  193 + $this->assertEqual($doc['status_code'], 0);
  194 + $this->assertTrue(!empty($result2['results']));
  195 +
  196 + // Checkin the document
  197 + $dir = $default->uploadDirectory;
  198 + $tempfilename = $this->createRandomFile('some text', $dir);
  199 + // test without authentication - should fail
  200 + $result3 = $this->ktapi->checkin_document($doc_id, 'testdoc1.txt', 'Testing API', $tempfilename, false);
  201 + $this->assertEqual($result3['status_code'], 1);
  202 +
  203 + // test with authentication
  204 + $result4 = $this->ktapi->checkin_document($doc_id, 'testdoc1.txt', 'Testing API', $tempfilename, false, 'admin', 'admin');
  205 + $this->assertEqual($result4['status_code'], 0);
  206 + $this->assertEqual($result4['results']['document_id'], $doc_id);
  207 +
  208 + // Delete the document
  209 + // test without authentication - should fail
  210 + $result5 = $this->ktapi->delete_document($doc_id, 'Testing API');
  211 + $this->assertEqual($result5['status_code'], 1);
  212 +
  213 + // test with authentication
  214 + $result6 = $this->ktapi->delete_document($doc_id, 'Testing API', 'admin', 'admin', true);
  215 + $this->assertEqual($result6['status_code'], 0);
  216 +
  217 + // Clean up - delete the folder
  218 + // test without authentication - should fail
  219 + $result7 = $this->ktapi->delete_folder($folder_id, 'Testing API');
  220 + $this->assertEqual($result7['status_code'], 1);
  221 +
  222 + $result8 = $this->ktapi->delete_folder($folder_id, 'Testing API', 'admin', 'admin');
  223 + $this->assertEqual($result8['status_code'], 0);
  224 + }
  225 +
  226 + /**
  227 + * Helper function to create a document
  228 + */
  229 + function createDocument($title, $filename, $folder = null)
  230 + {
  231 + if(is_null($folder)){
  232 + $folder = $this->root;
  233 + }
  234 +
  235 + // Create a new document
  236 + $randomFile = $this->createRandomFile();
  237 + $this->assertTrue(is_file($randomFile));
  238 +
  239 + if ($this->esig_enabled)
  240 + {
  241 + $document = $folder->add_document($title, $filename, 'Default', $randomFile, 'admin', 'admin', 'Testing API');
  242 + }
  243 + else
  244 + {
  245 + $document = $folder->add_document($title, $filename, 'Default', $randomFile);
  246 + }
  247 + $this->assertNotError($document);
  248 +
  249 + @unlink($randomFile);
  250 + if(PEAR::isError($document)) return false;
  251 +
  252 + return $document;
  253 + }
  254 +
  255 + /**
  256 + * Helper function to delete docs
  257 + */
  258 + function deleteDocument($document)
  259 + {
  260 + $document->delete('Testing API');
  261 + $document->expunge();
  262 + }
  263 +
  264 + function createRandomFile($content = 'this is some text', $uploadDir = null) {
  265 + if(is_null($uploadDir)){
  266 + $uploadDir = dirname(__FILE__);
  267 + }
  268 + $temp = tempnam($uploadDir, 'myfile');
  269 + $fp = fopen($temp, 'wt');
  270 + fwrite($fp, $content);
  271 + fclose($fp);
  272 + return $temp;
  273 + }
  274 +}
  275 +?>
0 276 \ No newline at end of file
... ...
tests/runtests.php
... ... @@ -8,6 +8,9 @@ class UnitTests extends TestSuite {
8 8 $this->TestSuite('Unit tests');
9 9  
10 10 // KTAPI
  11 + // Some of these tests will fail if Electronic Signatures are enabled for the API.
  12 + // To fix, check the failing functions and add 'admin', 'admin' as username and password,
  13 + // and where necessary send 'Testing API' as a reason
11 14 $this->addFile('api/testApi.php');
12 15 $this->addFile('api/testAuto.php');
13 16 $this->addFile('api/testSavedSearches.php');
... ... @@ -17,6 +20,8 @@ class UnitTests extends TestSuite {
17 20 $this->addFile('api/testFolder.php');
18 21 $this->addFile('api/testBulkActions.php');
19 22 $this->addFile('api/testCollection.php');
  23 + // Only activate this test if Electronic Signatures are enabled for the API
  24 +// $this->addFile('api/testElectronicSignatures.php');
20 25  
21 26 // $this->addFile('SQLFile/test_sqlfile.php');
22 27 // $this->addFile('cache/testCache.php');
... ... @@ -28,9 +33,9 @@ class UnitTests extends TestSuite {
28 33 // $this->addFile('filelike/testStringFileLike.php');
29 34  
30 35 // Search (2) and indexing
31   - $this->addFile('documentProcessor/testExtracters.php');
32   - $this->addFile('documentProcessor/testGuidInserter.php');
33   - $this->addFile('search2/testSearch.php');
  36 +// $this->addFile('documentProcessor/testExtracters.php');
  37 +// $this->addFile('documentProcessor/testGuidInserter.php');
  38 +// $this->addFile('search2/testSearch.php');
34 39 }
35 40 }
36 41  
... ...