Commit 5df9da16f51c7c322cd1affe3e3bde825cc6979f

Authored by kevin_fourie
1 parent 13d37649

Merged in from DEV trunk...

KTS-2514
"Indexing requirements is harsh currently as it requires all indexing issues to be resolved"
Fixed. Added extractor table

Committed By: Conrad Vermeulen
Reviewed By: Kevin Fourie

KTS-2522
"Fatal Error when you perform a move and checkout"
Fixed. Refactored the prune users function into the getsubscribers function, where it is passed an array of id's instead of an array of objects.

Committed By: Megan Watson
Reviewed By: Conrad Vermeulen

KTS-2541
"indexes must be applied to searchable fields when recreating indexes"
Updated.

Committed By: Conrad Vermeulen
Reviewed By: Kevin Fourie

KTS-2529
"Test open office document extractor"
Updated. Extended KTUtil::findCommand to resolve python, php, and java in the stack

KTS-673
"The search algorithm needs some work"
Updated. 

Committed By: Conrad Vermeulen
Reviewed By: Kevin Fourie

BBS-298
"Mac OS X Webdav as 3rd Party Client"
Updated. Added functionality to prevent the .DS_Store files and ._filename files from being uploaded when adding a document or folder. Added Goliath as a client. Removed the forward slash from the end of file names.

Committed by: Megan Watson
Reviewed by: Conrad Vermeulen

KTS-673
"The search algorithm needs some work"
Updated. Made reference to DocumentIndexer

Committed By: Conrad Vermeulen
Reviewed By: Kevin Fourie

KTS-673
"The search algorithm needs some work"
Updated. Capitalise D

Committed By: Conrad Vermeulen
Reviewed By: Kevin Fourie

KTS-673
"The search algorithm needs some work"
Updated. Status dashlet must only show when there are no isssues

Committed By: Conrad Vermeulen
Reviewed By: Kevin Fourie

KTS-673
"The search algorithm needs some work"
Updated. Changed reference from lucene to Document Indexer

Committed By: Conrad Vermeulen
Reviewed By: Kevin Fourie

KTS-1554
"Implement a Scheduler"
Updated. Added a check on the extension to ensure .sh scripts run on *nix and .bat on windows, etc.

Committed by: Megan Watson
Reviewed by: Conrad Vermeulen

KTS-2525
"Create windows service to wrap around scheduler"
Updated. Added taskrunner.bat and modified service scripts.

Committed By: Kevin Fourie
Reviewed By: Conrad Vermeulen



git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/STABLE/trunk@7457 c91229c3-7414-0410-bfa2-8a42b809f60b
bin/recreateIndexes.php
... ... @@ -77,6 +77,7 @@ class IndexRecreator
77 77 var $primary;
78 78 var $globalstart;
79 79 var $start;
  80 + var $tables;
80 81  
81 82 function microtimeFloat()
82 83 {
... ... @@ -257,7 +258,11 @@ class IndexRecreator
257 258 $this->addForeignKey('metadata_lookup_tree','document_field_id', 'document_fields','id');
258 259 // $this->addForeignKey('metadata_lookup_tree','metadata_lookup_tree_parent', '??','id');
259 260  
260   - $this->addForeignKey('mime_types','mime_document_id','mime_documents','id');
  261 + $this->addForeignKey('mime_types','mime_document_id','mime_documents','id', 'set null', 'set null');
  262 + $this->addForeignKey('mime_types','extractor_id','mime_extractors','id', 'set null', 'set null');
  263 +
  264 + $this->addForeignKey('mime_document_mapping','mime_type_id','mime_types','id');
  265 + $this->addForeignKey('mime_document_mapping','mime_document_id','mime_documents','id');
261 266  
262 267 $this->addForeignKey('news','image_mime_type_id','mime_types','id');
263 268  
... ... @@ -398,6 +403,13 @@ class IndexRecreator
398 403 //$this->addIndex('document_types_lookup','disabled'); ? used
399 404  
400 405 $this->addIndex('documents','created');
  406 + $this->addIndex('documents','modified');
  407 + $this->addIndex('documents','full_path','','(255)');
  408 + $this->addIndex('documents','immutable');
  409 + $this->addIndex('documents','checkedout');
  410 +
  411 + $this->addIndex('document_content_version','filename','','(255)');
  412 + $this->addIndex('document_content_version','size');
401 413  
402 414 $this->addIndex('field_behaviour_options',array('behaviour_id','field_id'));
403 415  
... ... @@ -516,20 +528,22 @@ class IndexRecreator
516 528 $this->_exec($sql);
517 529 }
518 530  
519   - function addIndex($table, $fields, $type='')
  531 + function addIndex($table, $fields, $type='', $extra='')
520 532 {
  533 + if (!in_array($table, $this->tables)) return;
  534 +
521 535 if (!is_array($fields)) $fields = array($fields);
522 536 $index = implode('_', $fields);
523 537 //$index = str_replace('_id','',$index);
524 538 $fields = implode(',',$fields);
525   - $sql = "alter table $table add $type index $index ($fields) ";
  539 + $sql = "alter table $table add $type index $index ($fields$extra) ";
526 540 $this->_exec($sql);
527 541 }
528 542  
529 543 function addForeignKey($table, $field, $othertable, $otherfield, $ondelete='cascade', $onupdate='cascade')
530 544 {
531   - if (!in_array($table, $this->tables)) continue;
532   - if (!in_array($othertable, $this->tables)) continue;
  545 + if (!in_array($table, $this->tables)) return;
  546 + if (!in_array($othertable, $this->tables)) return;
533 547  
534 548 $sql = "alter table $table add foreign key ($field) references $othertable ($otherfield) ";
535 549 if ($ondelete != '')
... ... @@ -594,6 +608,8 @@ class IndexRecreator
594 608 $this->addPrimaryKey('metadata_lookup','id');
595 609 $this->addPrimaryKey('metadata_lookup_tree','id');
596 610 $this->addPrimaryKey('mime_documents','id');
  611 + $this->addPrimaryKey('mime_extractors','id');
  612 + $this->addPrimaryKey('mime_extractors',array('mime_type_id','mime_document_id'));
597 613 $this->addPrimaryKey('mime_types','id');
598 614 $this->addPrimaryKey('news','id');
599 615 $this->addPrimaryKey('notifications','id');
... ... @@ -646,6 +662,7 @@ class IndexRecreator
646 662  
647 663 function addPrimaryKey($table, $primarykey)
648 664 {
  665 + if (!in_array($table, $this->tables)) return;
649 666 if (is_array($primarykey))
650 667 {
651 668 $primarykey = implode(',', $primarykey);
... ...
bin/scheduler.php
... ... @@ -117,24 +117,49 @@ if(!empty($aList)){
117 117 $sFreq = $item['frequency'];
118 118 $sParameters = $item['script_params'];
119 119  
120   - $iTime = time();
121   - $iStart = explode(' ', microtime());
122   -
123   - /* Set up parameters for use by the script
124   - $aParams = explode('|', $sParameters);
125   -
126   - foreach($aParams as $param){
127   - $aParam = explode('=', $param);
128   - if(!empty($aParam)){
129   - $$aParam[0] = $aParam[1];
130   - $sParamList .= "{$aParam[0]} {$aParam[1]} ";
  120 + // Check if script is windows or *nix compatible
  121 + $extArr = explode('.', $sTaskUrl);
  122 + $ext = array_pop($extArr);
  123 + $script = implode('.', $extArr);
  124 + if(OS_WINDOWS){
  125 + switch($ext){
  126 + case 'sh':
  127 + $sTaskUrl = $script.'.bat';
  128 + break;
  129 + case 'bin':
  130 + $sTaskUrl = $script.'.exe';
  131 + break;
  132 + }
  133 + }else{
  134 + switch($ext){
  135 + case 'bat':
  136 + if(file_exists(KT_DIR . $script.'.sh')){
  137 + $sTaskUrl = $script.'.sh';
  138 + break;
  139 + }
  140 + // File doesn't exist - log error
  141 + $default->log->error("Scheduler: Task script can't be found at ".KT_DIR."{$script}.sh");
  142 + continue;
  143 + break;
  144 + case 'exe':
  145 + if(file_exists(KT_DIR . $script)){
  146 + $sTaskUrl = $script;
  147 + break;
  148 + }
  149 + if(file_exists(KT_DIR . $script.'.bin')){
  150 + $sTaskUrl = $script.'.bin';
  151 + break;
  152 + }
  153 + // File doesn't exist - log error
  154 + $default->log->error("Scheduler: Task script can't be found at ".KT_DIR."{$script} or ".KT_DIR."{$script}.bin");
  155 + continue;
  156 + break;
131 157 }
132 158 }
133   - */
134   -
135   - // Run the script as php
136   - //include(KT_DIR . $sTaskUrl);
137   -
  159 +
  160 + $iTime = time();
  161 + $iStart = explode(' ', microtime());
  162 +
138 163 // Run the script
139 164 $file = KT_DIR . escapeshellcmd($sTaskUrl);
140 165 system("{$file} {$sParameters} >> /dev/null", $retval);
... ...
bin/win32/installScheduler.php
1 1 <?php
2 2  
3   -$scriptPath = realpath(dirname(__FILE__) . '/schedulerService.php');
  3 +$scriptPath = realpath(dirname(__FILE__) . '/taskrunner.bat');
4 4  
5   -// Setup php binary path
6   -$phpPath = realpath('../../php/php.exe');
7   -if (!is_file($phpPath))
8   -{
9   - die('Cannot find php.exe');
10   -}
11   -
12 5 win32_create_service(array(
13 6 'service' => 'ktscheduler',
14 7 'display' => 'ktdmsScheduler',
15   - 'params' => $scriptPath,
16   - 'path' => $phpPath
  8 + 'path' => $scriptPath
17 9 ));
18 10  
19 11 ?>
... ...
bin/win32/schedulerServiceStatus.php
... ... @@ -2,4 +2,4 @@
2 2  
3 3 var_dump(win32_query_service_status('ktscheduler'));
4 4  
5   -?>
6 5 \ No newline at end of file
  6 +?>
... ...
bin/win32/taskrunner.bat 0 โ†’ 100644
  1 +@echo off
  2 +"@@BITROCK_INSTALLDIR@@\php\php.exe" "@@BITROCK_INSTALLDIR@@\knowledgeTree\bin\win32\schedulerService.php"
  3 +
... ...
ktwebdav/lib/KTWebDAVServer.inc.php
... ... @@ -167,7 +167,7 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
167 167  
168 168 // Load KTWebDAV config
169 169 if (!$this->initConfig()) {
170   - $this->ktwebdavLog('Could not load configiration.', 'error');
  170 + $this->ktwebdavLog('Could not load configuration.', 'error');
171 171 exit(0);
172 172 }
173 173  
... ... @@ -437,6 +437,22 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
437 437  
438 438 $path = $options["path"];
439 439  
  440 + // Fix for Mac Clients
  441 + // Mac adds DS_Store files when folders are added and ._filename files when files are added
  442 + // The PUT function doesn't add these files to the dms but PROPFIND still looks for the .DS_Store file,
  443 + // and returns an error if not found. We emulate its existence by returning a positive result.
  444 + if($this->dav_client == 'MC' || $this->dav_client == 'MG'){
  445 + // Remove filename from path
  446 + $aPath = explode('/', $path);
  447 + $fileName = $aPath[count($aPath)-1];
  448 +
  449 + if(strtolower($fileName) == '.ds_store'){
  450 + $this->ktwebdavLog("Using a Mac client. Filename is .DS_Store so we emulate a positive result.", 'info', true);
  451 + // ignore
  452 + return true;
  453 + }
  454 + }
  455 +
440 456 list($iFolderID, $iDocumentID) = $this->_folderOrDocument($path);
441 457 $this->ktwebdavLog("Folder/Doc is " . print_r(array($iFolderID, $iDocumentID), true), 'info', true);
442 458  
... ... @@ -664,7 +680,7 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
664 680 } else {
665 681 $options["depth"] = "infinity";
666 682 }
667   -
  683 +
668 684 // analyze request payload
669 685 $propinfo = new _parse_propfind("php://input");
670 686 if (!$propinfo->success) {
... ... @@ -798,8 +814,22 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
798 814  
799 815 echo " <D:response $ns_defs>\n";
800 816  
801   - $href = htmlspecialchars($this->_slashify($this->_mergePathes($_SERVER['SCRIPT_NAME'], $path)));
802   -
  817 + $tempHref = $this->_mergePathes($_SERVER['SCRIPT_NAME'], $path);
  818 +
  819 + // Ensure collections end in a slash
  820 + if(isset($file['props'])){
  821 + foreach($file['props'] as $v){
  822 + if($v['name'] == 'resourcetype'){
  823 + if($v['val'] == 'collection'){
  824 + $tempHref = $this->_slashify($tempHref);
  825 + continue;
  826 + }
  827 + }
  828 + }
  829 + }
  830 +
  831 + $href = htmlspecialchars($tempHref);
  832 +
803 833 echo " <D:href>$href</D:href>\n";
804 834  
805 835 $this->ktwebdavLog("\nfile is: " . print_r($file, true), 'info', true);
... ... @@ -1101,7 +1131,7 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1101 1131 while (count($aRemaining)) {
1102 1132 $sFolderName = $aRemaining[0];
1103 1133 $aRemaining = array_slice($aRemaining, 1);
1104   - if ($sFolderName == '') {
  1134 + if (empty($sFolderName)) {
1105 1135 continue;
1106 1136 }
1107 1137 // FIXME: Direct database access
... ... @@ -1187,6 +1217,29 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1187 1217 $this->ktwebdavLog("dav_client is: " . $this->dav_client, 'info', true);
1188 1218  
1189 1219 $path = $options["path"];
  1220 +
  1221 + // Fix for Mac
  1222 + // Mac adds DS_Store files when folders are added and ._filename files when files are added
  1223 + // we want to ignore them.
  1224 + if($this->dav_client == 'MC' || $this->dav_client == 'MG'){
  1225 + // Remove filename from path
  1226 + $aPath = explode('/', $path);
  1227 + $fileName = $aPath[count($aPath)-1];
  1228 +
  1229 + if(strtolower($fileName) == '.ds_store'){
  1230 + $this->ktwebdavLog("Using a mac client. Ignore the .DS_Store files created with every folder.", 'info', true);
  1231 + // ignore
  1232 + return "204 No Content";
  1233 + }
  1234 +
  1235 + if($fileName[0] == '.' && $fileName[1] == '_'){
  1236 + $fileName = substr($fileName, 2);
  1237 + $this->ktwebdavLog("Using a mac client. Ignore the ._filename files created with every file.", 'info', true);
  1238 + // ignore
  1239 + return "204 No Content";
  1240 + }
  1241 + }
  1242 +
1190 1243  
1191 1244 $res = $this->_folderOrDocument($path);
1192 1245 list($iFolderID, $iDocumentID) = $res;
... ... @@ -1623,6 +1676,18 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1623 1676 function _MOVEDocument($options, $iFolderID, $iDocumentID) {
1624 1677  
1625 1678 if ($options['dest'] == '') $options["dest"] = substr($options["dest_url"], strlen($_SERVER["SCRIPT_NAME"]));
  1679 +
  1680 + // Fix for Mac
  1681 + if($this->dav_client == 'MG'){
  1682 + $this->ktwebdavLog("Remove ktwebdav from destination path: ".$options['dest'], 'info', true);
  1683 + if(!(strpos($options['dest'], 'ktwebdav/ktwebdav.php/') === FALSE)){
  1684 + $options['dest'] = substr($options['dest'], 22);
  1685 + }
  1686 + if($options['dest'][0] != '/'){
  1687 + $options['dest'] = '/'.$options['dest'];
  1688 + }
  1689 + }
  1690 +
1626 1691 $this->ktwebdavLog("Entering _MOVEDocument. options are " . print_r($options, true), 'info', true);
1627 1692 global $default;
1628 1693 $new = true;
... ... @@ -1643,7 +1708,7 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
1643 1708 // return "412 Precondition Failed - This is a Rename. Overwrite needs to be TRUE.";
1644 1709 //}
1645 1710 $this->ktwebdavLog("Got an oDocument of " . print_r($oDocument, true), 'info', true);
1646   - $this->ktwebdavLog("Got an new name of " . basename($dest_path), 'info', true);
  1711 + $this->ktwebdavLog("Got a new name of " . basename($dest_path), 'info', true);
1647 1712  
1648 1713 // Check if the user has permissions to write this document
1649 1714 $oPerm =& KTPermission::getByName('ktcore.permissions.write');
... ... @@ -2194,10 +2259,15 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
2194 2259 $this->ktwebdavLog("WebDAV Client : " . $userAgentValue, 'info', true);
2195 2260 }
2196 2261 // Mac Finder
2197   - if (stristr($userAgentValue,"Macintosh")) {
  2262 + if (stristr($userAgentValue,"Macintosh") || stristr($userAgentValue,"Darwin")) {
2198 2263 $this->dav_client = "MC";
2199 2264 $this->ktwebdavLog("WebDAV Client : " . $userAgentValue, 'info', true);
2200 2265 }
  2266 + // Mac Goliath
  2267 + if (stristr($userAgentValue,"Goliath")) {
  2268 + $this->dav_client = "MG";
  2269 + $this->ktwebdavLog("WebDAV Client : " . $userAgentValue, 'info', true);
  2270 + }
2201 2271 // Konqueror
2202 2272 if (stristr($userAgentValue,"Konqueror")) {
2203 2273 $this->dav_client = "KO";
... ... @@ -2228,6 +2298,20 @@ class KTWebDAVServer extends HTTP_WebDAV_Server
2228 2298 return false;
2229 2299  
2230 2300 }
  2301 + // Mac Goliath
  2302 + if ($this->dav_client == 'MG' && $this->safeMode == 'off') {
  2303 +
  2304 + $this->ktwebdavLog("This is a Mac Goliath type client with SafeMode off.", 'info', true);
  2305 + return true;
  2306 +
  2307 + }
  2308 + // Mac Goliath
  2309 + if ($this->dav_client == 'MG' && $this->safeMode != 'off') {
  2310 +
  2311 + $this->ktwebdavLog("This is a Mac Goliath type client with SafeMode on.", 'info', true);
  2312 + return false;
  2313 +
  2314 + }
2231 2315 // Konqueror
2232 2316 if ($this->dav_client == 'KO' && $this->safeMode == 'off') {
2233 2317  
... ...
lib/subscriptions/subscriptions.inc.php
... ... @@ -94,56 +94,54 @@ class SubscriptionEvent {
94 94  
95 95 // only useful for folder subscriptions.
96 96 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
97   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
98   - foreach ($aUsers as $oSubscriber) {
99   -
100   - // notification object first.
101   - $aNotificationOptions = array();
102   - $aNotificationOptions['target_user'] = $oSubscriber->getID();
103   - $aNotificationOptions['actor_id'] = KTUtil::arrayGet($_SESSION,"userID", null); // _won't_ be null.
104   - $aNotificationOptions['target_name'] = $oAddedFolder->getName();
105   - $aNotificationOptions['location_name'] = Folder::generateFullFolderPath($oParentFolder->getId());
106   - $aNotificationOptions['object_id'] = $oAddedFolder->getId(); // parent folder_id, in this case.
107   - $aNotificationOptions['event_type'] = "AddFolder";
108   - $oNotification =& KTSubscriptionNotification::generateSubscriptionNotification($aNotificationOptions);
109   -
110   - // now the email content.
111   - // FIXME this needs to be handled entirely within notifications from now on.
112   - if ($oSubscriber->getEmailNotification() && (strlen($oSubscriber->getEmail()) > 0)) {
113   - $emailContent = $content->getEmailAlertContent($oNotification);
114   - $emailSubject = $content->getEmailAlertSubject($oNotification);
115   - $oEmail = new EmailAlert($oSubscriber->getEmail(), $emailSubject, $emailContent);
116   - $oEmail->send();
117   - }
118   - }
  97 + foreach ($aUsers as $oSubscriber) {
  98 +
  99 + // notification object first.
  100 + $aNotificationOptions = array();
  101 + $aNotificationOptions['target_user'] = $oSubscriber->getID();
  102 + $aNotificationOptions['actor_id'] = KTUtil::arrayGet($_SESSION,"userID", null); // _won't_ be null.
  103 + $aNotificationOptions['target_name'] = $oAddedFolder->getName();
  104 + $aNotificationOptions['location_name'] = Folder::generateFullFolderPath($oParentFolder->getId());
  105 + $aNotificationOptions['object_id'] = $oAddedFolder->getId(); // parent folder_id, in this case.
  106 + $aNotificationOptions['event_type'] = "AddFolder";
  107 + $oNotification =& KTSubscriptionNotification::generateSubscriptionNotification($aNotificationOptions);
  108 +
  109 + // now the email content.
  110 + // FIXME this needs to be handled entirely within notifications from now on.
  111 + if ($oSubscriber->getEmailNotification() && (strlen($oSubscriber->getEmail()) > 0)) {
  112 + $emailContent = $content->getEmailAlertContent($oNotification);
  113 + $emailSubject = $content->getEmailAlertSubject($oNotification);
  114 + $oEmail = new EmailAlert($oSubscriber->getEmail(), $emailSubject, $emailContent);
  115 + $oEmail->send();
  116 + }
  117 + }
119 118 }
120 119 function AddDocument ($oAddedDocument, $oParentFolder) {
121 120 $content = new SubscriptionContent(); // needed for i18n
122 121 // two parts to this:
123 122 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
124   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
125   - foreach ($aUsers as $oSubscriber) {
126   -
127   - // notification object first.
128   - $aNotificationOptions = array();
129   - $aNotificationOptions['target_user'] = $oSubscriber->getID();
130   - $aNotificationOptions['actor_id'] = KTUtil::arrayGet($_SESSION,"userID", null); // _won't_ be null - is this valid?
131   - $aNotificationOptions['target_name'] = $oAddedDocument->getName();
132   - $aNotificationOptions['location_name'] = Folder::generateFullFolderPath($oParentFolder->getId());
133   - $aNotificationOptions['object_id'] = $oAddedDocument->getId(); // parent folder_id, in this case.
134   - $aNotificationOptions['event_type'] = "AddDocument";
135   -
136   - $oNotification =& KTSubscriptionNotification::generateSubscriptionNotification($aNotificationOptions);
137   -
138   - // now the email content.
139   - // FIXME this needs to be handled entirely within notifications from now on.
140   - if ($oSubscriber->getEmailNotification() && (strlen($oSubscriber->getEmail()) > 0)) {
141   - $emailContent = $content->getEmailAlertContent($oNotification);
142   - $emailSubject = $content->getEmailAlertSubject($oNotification);
143   - $oEmail = new EmailAlert($oSubscriber->getEmail(), $emailSubject, $emailContent);
144   - $oEmail->send();
145   - }
146   - }
  123 + foreach ($aUsers as $oSubscriber) {
  124 +
  125 + // notification object first.
  126 + $aNotificationOptions = array();
  127 + $aNotificationOptions['target_user'] = $oSubscriber->getID();
  128 + $aNotificationOptions['actor_id'] = KTUtil::arrayGet($_SESSION,"userID", null); // _won't_ be null - is this valid?
  129 + $aNotificationOptions['target_name'] = $oAddedDocument->getName();
  130 + $aNotificationOptions['location_name'] = Folder::generateFullFolderPath($oParentFolder->getId());
  131 + $aNotificationOptions['object_id'] = $oAddedDocument->getId(); // parent folder_id, in this case.
  132 + $aNotificationOptions['event_type'] = "AddDocument";
  133 +
  134 + $oNotification =& KTSubscriptionNotification::generateSubscriptionNotification($aNotificationOptions);
  135 +
  136 + // now the email content.
  137 + // FIXME this needs to be handled entirely within notifications from now on.
  138 + if ($oSubscriber->getEmailNotification() && (strlen($oSubscriber->getEmail()) > 0)) {
  139 + $emailContent = $content->getEmailAlertContent($oNotification);
  140 + $emailSubject = $content->getEmailAlertSubject($oNotification);
  141 + $oEmail = new EmailAlert($oSubscriber->getEmail(), $emailSubject, $emailContent);
  142 + $oEmail->send();
  143 + }
  144 + }
147 145 }
148 146 function RemoveFolder($oRemovedFolder, $oParentFolder) {
149 147 $content = new SubscriptionContent(); // needed for i18n
... ... @@ -153,7 +151,6 @@ class SubscriptionEvent {
153 151  
154 152 // we need to start with the latter, so we don't "lose" any.
155 153 $aUsers = $this->_getSubscribers($oRemovedFolder->getId(), $this->subscriptionTypes["Folder"]);
156   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
157 154 foreach ($aUsers as $oSubscriber) {
158 155  
159 156 // notification object first.
... ... @@ -184,7 +181,6 @@ class SubscriptionEvent {
184 181  
185 182 // now handle (for those who haven't been alerted) users watching the folder.
186 183 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
187   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
188 184 foreach ($aUsers as $oSubscriber) {
189 185  
190 186 // notification object first.
... ... @@ -216,7 +212,6 @@ class SubscriptionEvent {
216 212  
217 213 // we need to start with the latter, so we don't "lose" any.
218 214 $aUsers = $this->_getSubscribers($oRemovedDocument->getId(), $this->subscriptionTypes["Document"]);
219   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
220 215 foreach ($aUsers as $oSubscriber) {
221 216  
222 217 // notification object first.
... ... @@ -247,7 +242,6 @@ class SubscriptionEvent {
247 242  
248 243 // now handle (for those who haven't been alerted) users watching the folder.
249 244 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
250   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
251 245 foreach ($aUsers as $oSubscriber) {
252 246  
253 247 // notification object first.
... ... @@ -275,7 +269,6 @@ class SubscriptionEvent {
275 269 $content = new SubscriptionContent(); // needed for i18n
276 270 // OK: two actions: document registrants, folder registrants.
277 271 $aUsers = $this->_getSubscribers($oModifiedDocument->getId(), $this->subscriptionTypes["Document"]);
278   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
279 272 foreach ($aUsers as $oSubscriber) {
280 273  
281 274 // notification object first.
... ... @@ -300,7 +293,6 @@ class SubscriptionEvent {
300 293  
301 294  
302 295 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
303   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
304 296 foreach ($aUsers as $oSubscriber) {
305 297  
306 298 // notification object first.
... ... @@ -328,7 +320,6 @@ class SubscriptionEvent {
328 320 $content = new SubscriptionContent(); // needed for i18n
329 321 // OK: two actions: document registrants, folder registrants.
330 322 $aUsers = $this->_getSubscribers($oModifiedDocument->getId(), $this->subscriptionTypes["Document"]);
331   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
332 323 foreach ($aUsers as $oSubscriber) {
333 324  
334 325 // notification object first.
... ... @@ -352,7 +343,6 @@ class SubscriptionEvent {
352 343 }
353 344  
354 345 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
355   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
356 346 foreach ($aUsers as $oSubscriber) {
357 347  
358 348 // notification object first.
... ... @@ -380,7 +370,6 @@ class SubscriptionEvent {
380 370 $content = new SubscriptionContent(); // needed for i18n
381 371 // OK: two actions: document registrants, folder registrants.
382 372 $aUsers = $this->_getSubscribers($oModifiedDocument->getId(), $this->subscriptionTypes["Document"]);
383   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
384 373 foreach ($aUsers as $oSubscriber) {
385 374  
386 375 // notification object first.
... ... @@ -405,7 +394,7 @@ class SubscriptionEvent {
405 394  
406 395  
407 396 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
408   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
  397 +
409 398 foreach ($aUsers as $oSubscriber) {
410 399  
411 400 // notification object first.
... ... @@ -433,60 +422,58 @@ class SubscriptionEvent {
433 422 $content = new SubscriptionContent(); // needed for i18n
434 423 // OK: two actions: document registrants, folder registrants.
435 424 $aUsers = $this->_getSubscribers($oModifiedDocument->getId(), $this->subscriptionTypes["Document"]);
436   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
437   - foreach ($aUsers as $oSubscriber) {
438   -
439   - // notification object first.
440   - $aNotificationOptions = array();
441   - $aNotificationOptions['target_user'] = $oSubscriber->getID();
442   - $aNotificationOptions['actor_id'] = KTUtil::arrayGet($_SESSION,"userID", null); // _won't_ be null.
443   - $aNotificationOptions['target_name'] = $oModifiedDocument->getName();
444   - $aNotificationOptions['location_name'] = Folder::generateFullFolderPath($oParentFolder->getId());
445   - $aNotificationOptions['object_id'] = $oModifiedDocument->getId(); // parent folder_id, in this case.
446   - $aNotificationOptions['event_type'] = "CheckOutDocument";
447   - $oNotification =& KTSubscriptionNotification::generateSubscriptionNotification($aNotificationOptions);
448   -
449   - // now the email content.
450   - // FIXME this needs to be handled entirely within notifications from now on.
451   - if ($oSubscriber->getEmailNotification() && (strlen($oSubscriber->getEmail()) > 0)) {
452   - $emailContent = $content->getEmailAlertContent($oNotification);
453   - $emailSubject = $content->getEmailAlertSubject($oNotification);
454   - $oEmail = new EmailAlert($oSubscriber->getEmail(), $emailSubject, $emailContent);
455   - $oEmail->send();
456   - }
457   - }
  425 +
  426 + foreach ($aUsers as $oSubscriber) {
  427 +
  428 + // notification object first.
  429 + $aNotificationOptions = array();
  430 + $aNotificationOptions['target_user'] = $oSubscriber->getID();
  431 + $aNotificationOptions['actor_id'] = KTUtil::arrayGet($_SESSION,"userID", null); // _won't_ be null.
  432 + $aNotificationOptions['target_name'] = $oModifiedDocument->getName();
  433 + $aNotificationOptions['location_name'] = Folder::generateFullFolderPath($oParentFolder->getId());
  434 + $aNotificationOptions['object_id'] = $oModifiedDocument->getId(); // parent folder_id, in this case.
  435 + $aNotificationOptions['event_type'] = "CheckOutDocument";
  436 + $oNotification =& KTSubscriptionNotification::generateSubscriptionNotification($aNotificationOptions);
  437 +
  438 + // now the email content.
  439 + // FIXME this needs to be handled entirely within notifications from now on.
  440 + if ($oSubscriber->getEmailNotification() && (strlen($oSubscriber->getEmail()) > 0)) {
  441 + $emailContent = $content->getEmailAlertContent($oNotification);
  442 + $emailSubject = $content->getEmailAlertSubject($oNotification);
  443 + $oEmail = new EmailAlert($oSubscriber->getEmail(), $emailSubject, $emailContent);
  444 + $oEmail->send();
  445 + }
  446 + }
458 447  
459 448  
460 449 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
461   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
462   - foreach ($aUsers as $oSubscriber) {
463   -
464   - // notification object first.
465   - $aNotificationOptions = array();
466   - $aNotificationOptions['target_user'] = $oSubscriber->getID();
467   - $aNotificationOptions['actor_id'] = KTUtil::arrayGet($_SESSION,"userID", null); // _won't_ be null.
468   - $aNotificationOptions['target_name'] = $oModifiedDocument->getName();
469   - $aNotificationOptions['location_name'] = Folder::generateFullFolderPath($oParentFolder->getId());
470   - $aNotificationOptions['object_id'] = $oModifiedDocument->getId(); // parent folder_id, in this case.
471   - $aNotificationOptions['event_type'] = "CheckOutDocument";
472   - $oNotification =& KTSubscriptionNotification::generateSubscriptionNotification($aNotificationOptions);
473   -
474   - // now the email content.
475   - // FIXME this needs to be handled entirely within notifications from now on.
476   - if ($oSubscriber->getEmailNotification() && (strlen($oSubscriber->getEmail()) > 0)) {
477   - $emailContent = $content->getEmailAlertContent($oNotification);
478   - $emailSubject = $content->getEmailAlertSubject($oNotification);
479   - $oEmail = new EmailAlert($oSubscriber->getEmail(), $emailSubject, $emailContent);
480   - $oEmail->send();
481   - }
482   - }
  450 + foreach ($aUsers as $oSubscriber) {
  451 +
  452 + // notification object first.
  453 + $aNotificationOptions = array();
  454 + $aNotificationOptions['target_user'] = $oSubscriber->getID();
  455 + $aNotificationOptions['actor_id'] = KTUtil::arrayGet($_SESSION,"userID", null); // _won't_ be null.
  456 + $aNotificationOptions['target_name'] = $oModifiedDocument->getName();
  457 + $aNotificationOptions['location_name'] = Folder::generateFullFolderPath($oParentFolder->getId());
  458 + $aNotificationOptions['object_id'] = $oModifiedDocument->getId(); // parent folder_id, in this case.
  459 + $aNotificationOptions['event_type'] = "CheckOutDocument";
  460 + $oNotification =& KTSubscriptionNotification::generateSubscriptionNotification($aNotificationOptions);
  461 +
  462 + // now the email content.
  463 + // FIXME this needs to be handled entirely within notifications from now on.
  464 + if ($oSubscriber->getEmailNotification() && (strlen($oSubscriber->getEmail()) > 0)) {
  465 + $emailContent = $content->getEmailAlertContent($oNotification);
  466 + $emailSubject = $content->getEmailAlertSubject($oNotification);
  467 + $oEmail = new EmailAlert($oSubscriber->getEmail(), $emailSubject, $emailContent);
  468 + $oEmail->send();
  469 + }
  470 + }
483 471 }
484 472  
485 473 function MoveDocument($oMovedDocument, $oToFolder, $oFromFolder, $moveOrCopy = "MovedDocument") {
486 474 $content = new SubscriptionContent(); // needed for i18n
487 475 // OK: two actions: document registrants, folder registrants.
488 476 $aUsers = $this->_getSubscribers($oMovedDocument->getId(), $this->subscriptionTypes["Document"]);
489   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
490 477  
491 478 foreach ($aUsers as $oSubscriber) {
492 479 // notification object first.
... ... @@ -511,7 +498,7 @@ class SubscriptionEvent {
511 498  
512 499  
513 500 $aUsers = $this->_getSubscribers($oFromFolder->getId(), $this->subscriptionTypes["Folder"]);
514   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
  501 +
515 502 foreach ($aUsers as $oSubscriber) {
516 503  
517 504 // notification object first.
... ... @@ -535,7 +522,6 @@ class SubscriptionEvent {
535 522 }
536 523  
537 524 $aUsers = $this->_getSubscribers($oToFolder->getId(), $this->subscriptionTypes["Folder"]);
538   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
539 525 foreach ($aUsers as $oSubscriber) {
540 526  
541 527 // notification object first.
... ... @@ -563,7 +549,6 @@ class SubscriptionEvent {
563 549 $content = new SubscriptionContent(); // needed for i18n
564 550 // OK: two actions: document registrants, folder registrants.
565 551 $aUsers = $this->_getSubscribers($oModifiedDocument->getId(), $this->subscriptionTypes["Document"]);
566   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
567 552 foreach ($aUsers as $oSubscriber) {
568 553  
569 554 // notification object first.
... ... @@ -588,7 +573,6 @@ class SubscriptionEvent {
588 573  
589 574  
590 575 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
591   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
592 576 foreach ($aUsers as $oSubscriber) {
593 577  
594 578 // notification object first.
... ... @@ -616,7 +600,6 @@ class SubscriptionEvent {
616 600 $content = new SubscriptionContent(); // needed for i18n
617 601 // OK: two actions: document registrants, folder registrants.
618 602 $aUsers = $this->_getSubscribers($oModifiedDocument->getId(), $this->subscriptionTypes["Document"]);
619   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
620 603 foreach ($aUsers as $oSubscriber) {
621 604  
622 605 // notification object first.
... ... @@ -641,7 +624,6 @@ class SubscriptionEvent {
641 624  
642 625  
643 626 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
644   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
645 627 foreach ($aUsers as $oSubscriber) {
646 628  
647 629 // notification object first.
... ... @@ -669,7 +651,6 @@ class SubscriptionEvent {
669 651 $content = new SubscriptionContent(); // needed for i18n
670 652 // OK: two actions: document registrants, folder registrants.
671 653 $aUsers = $this->_getSubscribers($oDocument->getId(), $this->subscriptionTypes["Document"]);
672   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
673 654 foreach ($aUsers as $oSubscriber) {
674 655  
675 656 // notification object first.
... ... @@ -694,7 +675,6 @@ class SubscriptionEvent {
694 675  
695 676  
696 677 $aUsers = $this->_getSubscribers($oParentFolder->getId(), $this->subscriptionTypes["Folder"]);
697   - $aUsers = $this->_pruneAlertedUsers($aUsers); // setup the alerted users. _might_ be a singleton.
698 678 foreach ($aUsers as $oSubscriber) {
699 679  
700 680 // notification object first.
... ... @@ -748,6 +728,9 @@ class SubscriptionEvent {
748 728  
749 729 $aNewUsers = DBUtil::getResultArrayKey(array($sQuery, $aParams), "user_id");
750 730  
  731 + // Remove alerted users
  732 + $aNewUsers = $this->_pruneAlertedUsers($aNewUsers);
  733 +
751 734 // notionally less efficient than the old code. if its a big issue, can easily
752 735 // be refactored.
753 736 foreach ($aNewUsers as $iUserId) {
... ...
lib/util/ktutil.inc
... ... @@ -557,6 +557,12 @@ class KTUtil {
557 557 return $sCommand . ".exe";
558 558 }
559 559  
  560 + $result = KTUtil::checkForStackCommand($sConfigVar);
  561 + if (!empty($result))
  562 + {
  563 + return $result;
  564 + }
  565 +
560 566 $sExecSearchPath = $oKTConfig->get("KnowledgeTree/execSearchPath");
561 567 $sExecSearchPath .= PATH_SEPARATOR . KT_DIR . "/../common/";
562 568 $sExecSearchPath .= PATH_SEPARATOR . KT_DIR . "/../bin/xpdf/";
... ... @@ -578,6 +584,47 @@ class KTUtil {
578 584 }
579 585 // }}}
580 586  
  587 + function checkForStackCommand($configCommand)
  588 + {
  589 + $config = KTConfig::getSingleton();
  590 + $stackPath = realpath(KT_DIR . '/..');
  591 +
  592 + switch ($configCommand)
  593 + {
  594 + case 'externalBinary/php':
  595 + if (OS_WINDOWS)
  596 + {
  597 + $script = $stackPath . '/php/php.exe';
  598 + }
  599 + else
  600 + {
  601 + $script = $stackPath . '/php/bin/php';
  602 + }
  603 + break;
  604 + case 'externalBinary/python':
  605 + if (OS_WINDOWS)
  606 + {
  607 + $script = $stackPath . '/openoffice/openoffice/program/python.bat';
  608 + }
  609 + else
  610 + {
  611 + $script = $stackPath . '/openoffice/program/python';
  612 + }
  613 + break;
  614 + case 'externalBinary/java':
  615 + $script = $stackPath . '/j2re/bin/java';
  616 + break;
  617 + default:
  618 + return null;
  619 + }
  620 + if (is_file($script))
  621 + {
  622 + return $script;
  623 + }
  624 + return false;
  625 + }
  626 +
  627 +
581 628 // now accepts strings OR arrays!
582 629 // {{{ addQueryString
583 630 static function addQueryString($url, $qs) {
... ...
plugins/search2/IndexingStatusDashlet.php
... ... @@ -36,13 +36,13 @@ class IndexingStatusDashlet extends KTBaseDashlet
36 36  
37 37 function IndexingStatusDashlet()
38 38 {
39   - $this->sTitle = _kt('Indexing Status');
  39 + $this->sTitle = _kt('Document Indexer Status');
40 40 $this->sClass = 'ktError';
41 41 }
42 42  
43 43 function is_active($oUser)
44 44 {
45   - if (!Permission::userIsSystemAdministrator($oUser))
  45 + if (!Permission::userIsSystemAdministrator())
46 46 {
47 47 return false;
48 48 }
... ... @@ -86,6 +86,10 @@ class IndexingStatusDashlet extends KTBaseDashlet
86 86 $_SESSION['IndexingStatus']['extractorDiagnosis'] = $this->extractorDiagnosis;
87 87 }
88 88  
  89 + if (empty($this->indexerDiagnosis) && empty($this->extractorDiagnosis))
  90 + {
  91 + return false;
  92 + }
89 93  
90 94 return true;
91 95 }
... ...
plugins/search2/LuceneStatisticsDashlet.php
... ... @@ -34,12 +34,12 @@ class LuceneStatisticsDashlet extends KTBaseDashlet
34 34 {
35 35 function LuceneStatisticsDashlet()
36 36 {
37   - $this->sTitle = _kt('Lucene Statistics');
  37 + $this->sTitle = _kt('Document Indexer Statistics');
38 38 }
39 39  
40 40 function is_active($oUser)
41 41 {
42   - return Permission::userIsSystemAdministrator($oUser);
  42 + return Permission::userIsSystemAdministrator();
43 43 }
44 44  
45 45 function render()
... ...
search2/indexing/bin/recreateIndex.php
... ... @@ -14,6 +14,15 @@ require_once(realpath(&#39;../../../config/dmsDefaults.php&#39;));
14 14  
15 15 print _kt("Recreate Lucene index") . "...\n";
16 16  
  17 +$config = KTConfig::getSingleton();
  18 +$indexer = $config->get('indexer/coreClass');
  19 +
  20 +if ($indexer != 'PHPLuceneIndexer')
  21 +{
  22 + print _kt("This script only works with the PHPLuceneIndexer.") . "\n";
  23 + exit;
  24 +}
  25 +
17 26 $sure=false;
18 27 $indexall = false;
19 28 if ($argc > 0)
... ... @@ -42,14 +51,7 @@ if (!$sure)
42 51  
43 52  
44 53  
45   -$config = KTConfig::getSingleton();
46   -$indexer = $config->get('indexer/coreClass');
47 54  
48   -if ($indexer != 'PHPLuceneIndexer')
49   -{
50   - print _kt("This script only works with the PHPLuceneIndexer.") . "\n";
51   - exit;
52   -}
53 55  
54 56 require_once('indexing/indexerCore.inc.php');
55 57 require_once('indexing/indexers/PHPLuceneIndexer.inc.php');
... ...
sql/mysql/upgrade/3.5.0/mime_types.sql
... ... @@ -9,5 +9,30 @@ CREATE TABLE `zseq_mime_documents` (
9 9 `id` int(11) default NULL
10 10 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
11 11  
12   -alter table mime_types add extractor varchar(100);
  12 +CREATE TABLE `mime_extractors`
  13 +(
  14 + `id` mediumint(9) NOT NULL,
  15 + `name` varchar(50) NOT NULL,
  16 + `active` tinyint(4) NOT NULL default '0',
  17 + PRIMARY KEY (`id`)
  18 +) ENGINE=innodb DEFAULT CHARSET=utf8;
  19 +
  20 +CREATE TABLE `zseq_mime_extractors` (
  21 + `id` int(11) default NULL
  22 +) ENGINE=MyISAM DEFAULT CHARSET=utf8;
  23 +
  24 +CREATE TABLE `mime_document_mapping`
  25 +(
  26 + `mime_document_id` int(11) NOT NULL,
  27 + `mime_type_id` int(11) NOT NULL,
  28 + PRIMARY KEY (`mime_document_id`,`mime_type_id`)
  29 +) ENGINE=innodb DEFAULT CHARSET=utf8;
  30 +
  31 +alter table mime_types add extractor_id mediumint;
13 32 alter table mime_types add mime_document_id int;
  33 +
  34 +alter table mime_types add foreign key (extractor_id) references mime_extractors (id);
  35 +alter table mime_types add foreign key (mime_document_id) references mime_documents (id);
  36 +
  37 +alter table mime_document_mapping add foreign key (mime_type_id) references mime_types (id);
  38 +alter table mime_document_mapping add foreign key (mime_document_id) references mime_documents (id);
... ...