Commit 9650f889b3dd6c2a51fc41dcb41cfdbb8fce9317

Authored by kevin_fourie
1 parent fc322e3f

Merged in from STABLE trunk...

KTS-3691
"CLONE -Is there a way to prevent from checking in the wrong file?(SUP-1064)"
Fixed. Added a config option to hide the checkbox for "Force Original Filename".

KTS-3736
"User should be made aware that setting the field limit for document filenames and titles beyond 255 is futile as only 255 characters are allowed in the fields in the DB."
Fixed. Added a better description of the config option.

KTC-592
"Better default tooltip needed on mouse over than 'ACME Corporation'."
Fixed. Added a better tooltip as the default value for the config option.

Committed by: Megan Watson
Reviewed by: Conrad Vermeulen

KTS-3741
"The Property Preview Panel lacks a scroll bar"
Fixed. Changed overflow css from hidden to auto.

Committed by: Megan Watson
Reviewed by: Conrad Vermeulen

KTC-613
"Error occur when creating a link to a new RSS feed"
Fixed. Removed the javascript for the tinymce editor which isn't used.

Committed by: Megan Watson
Reviewed by: Conrad Vermeulen

KTS-3306
"Search should return folders"
Implemented.

KTS-3671
"Support for searching of symbolic links"
Implemented.

Committed By: Conrad Vermeulen
Reviewed By: Megan Watson

KTS-3306
"Search should return folders"
Implemented.

KTS-3671
"Support for searching of symbolic links"
Implemented.

Committed By: Conrad Vermeulen
Reviewed By: Megan Watson

KTS-3630
"matching metadata is not translated on results page"
Fixed.

Committed By: Conrad Vermeulen
Reviewed By: Megan Watson


git-svn-id: https://kt-dms.svn.sourceforge.net/svnroot/kt-dms/STABLE/branches/3.5.3a-Release-Branch@9404 c91229c3-7414-0410-bfa2-8a42b809f60b
plugins/ktcore/KTDocumentActions.php
@@ -599,7 +599,8 @@ class KTDocumentCheckInAction extends KTDocumentAction { @@ -599,7 +599,8 @@ class KTDocumentCheckInAction extends KTDocumentAction {
599 $major_inc = sprintf('%d.%d', $this->oDocument->getMajorVersionNumber()+1, 0); 599 $major_inc = sprintf('%d.%d', $this->oDocument->getMajorVersionNumber()+1, 0);
600 $minor_inc = sprintf('%d.%d', $this->oDocument->getMajorVersionNumber(), $this->oDocument->getMinorVersionNumber()+1); 600 $minor_inc = sprintf('%d.%d', $this->oDocument->getMajorVersionNumber(), $this->oDocument->getMinorVersionNumber()+1);
601 601
602 - $oForm->setWidgets(array( 602 + // Set the widgets for the form
  603 + $aWidgets = array(
603 array('ktcore.widgets.file', array( 604 array('ktcore.widgets.file', array(
604 'label' => _kt('File'), 605 'label' => _kt('File'),
605 'description' => sprintf(_kt('Please specify the file you wish to upload. Unless you also indicate that you are changing its filename (see "Force Original Filename" below), this will need to be called <strong>%s</strong>'), htmlentities($this->oDocument->getFilename(),ENT_QUOTES,'UTF-8')), 606 'description' => sprintf(_kt('Please specify the file you wish to upload. Unless you also indicate that you are changing its filename (see "Force Original Filename" below), this will need to be called <strong>%s</strong>'), htmlentities($this->oDocument->getFilename(),ENT_QUOTES,'UTF-8')),
@@ -618,14 +619,10 @@ class KTDocumentCheckInAction extends KTDocumentAction { @@ -618,14 +619,10 @@ class KTDocumentCheckInAction extends KTDocumentAction {
618 'description' => _kt('Please describe the changes you made to the document. Bear in mind that you can use a maximum of <strong>250</strong> characters.'), 619 'description' => _kt('Please describe the changes you made to the document. Bear in mind that you can use a maximum of <strong>250</strong> characters.'),
619 'name' => 'reason', 620 'name' => 'reason',
620 )), 621 )),
621 - array('ktcore.widgets.boolean',array(  
622 - 'label' => _kt('Force Original Filename'),  
623 - 'description' => sprintf(_kt('If this is checked, the uploaded document must have the same filename as the original: <strong>%s</strong>'), htmlentities($this->oDocument->getFilename(),ENT_QUOTES,'UTF-8')),  
624 - 'name' => 'forcefilename',  
625 - 'value' => true,  
626 - )),  
627 - ));  
628 - $oForm->setValidators(array( 622 + );
  623 +
  624 + // Set the validators for the widgets
  625 + $aValidators = array(
629 array('ktcore.validators.string', array( 626 array('ktcore.validators.string', array(
630 'test' => 'reason', 627 'test' => 'reason',
631 'max_length' => 250, 628 'max_length' => 250,
@@ -639,12 +636,27 @@ class KTDocumentCheckInAction extends KTDocumentAction { @@ -639,12 +636,27 @@ class KTDocumentCheckInAction extends KTDocumentAction {
639 'test' => 'file', 636 'test' => 'file',
640 'output' => 'file', 637 'output' => 'file',
641 )), 638 )),
642 - array('ktcore.validators.boolean', array( 639 + );
  640 +
  641 + // Add the "Force Original Filename" option if applicable
  642 + global $default;
  643 + if(!$default->disableForceFilenameOption){
  644 + $aWidgets[] = array('ktcore.widgets.boolean',array(
  645 + 'label' => _kt('Force Original Filename'),
  646 + 'description' => sprintf(_kt('If this is checked, the uploaded document must have the same filename as the original: <strong>%s</strong>'), htmlentities($this->oDocument->getFilename(),ENT_QUOTES,'UTF-8')),
  647 + 'name' => 'forcefilename',
  648 + 'value' => true,
  649 + ));
  650 +
  651 + $aValidators[] = array('ktcore.validators.boolean', array(
643 'test' => 'forcefilename', 652 'test' => 'forcefilename',
644 'output' => 'forcefilename', 653 'output' => 'forcefilename',
645 - )),  
646 - )); 654 + ));
  655 + }
647 656
  657 + // Add widgets and validators to the form
  658 + $oForm->setWidgets($aWidgets);
  659 + $oForm->setValidators($aValidators);
648 return $oForm; 660 return $oForm;
649 } 661 }
650 662
@@ -669,8 +681,16 @@ class KTDocumentCheckInAction extends KTDocumentAction { @@ -669,8 +681,16 @@ class KTDocumentCheckInAction extends KTDocumentAction {
669 681
670 $extra_errors = array(); 682 $extra_errors = array();
671 683
672 - if ($data['forcefilename'] && ($data['file']['name'] != $this->oDocument->getFilename())) {  
673 - $extra_errors['file'] = sprintf(_kt('The file you uploaded was not called "%s". If you wish to change the filename, please set "Force Original Filename" below to false. '), htmlentities($this->oDocument->getFilename(),ENT_QUOTES,'UTF-8')); 684 + // If the filename is different to the original check if "Force Original Filename" is set and return an error if it is.
  685 + $docFileName = $this->oDocument->getFilename();
  686 + if($data['file']['name'] != $docFileName){
  687 + global $default;
  688 +
  689 + if($default->disableForceFilenameOption){
  690 + $extra_errors['file'] = sprintf(_kt('The file you uploaded was not called "%s". The file must have the same name as the original file.'), htmlentities($docFileName,ENT_QUOTES,'UTF-8'));
  691 + }else if ($data['forcefilename']) {
  692 + $extra_errors['file'] = sprintf(_kt('The file you uploaded was not called "%s". If you wish to change the filename, please set "Force Original Filename" below to false. '), htmlentities($docFileName,ENT_QUOTES,'UTF-8'));
  693 + }
674 } 694 }
675 695
676 if (!empty($res['errors']) || !empty($extra_errors)) { 696 if (!empty($res['errors']) || !empty($extra_errors)) {
@@ -679,7 +699,7 @@ class KTDocumentCheckInAction extends KTDocumentAction { @@ -679,7 +699,7 @@ class KTDocumentCheckInAction extends KTDocumentAction {
679 699
680 $sReason = $data['reason']; 700 $sReason = $data['reason'];
681 701
682 - $sCurrentFilename = $this->oDocument->getFileName(); 702 + $sCurrentFilename = $docFileName;
683 $sNewFilename = $data['file']['name']; 703 $sNewFilename = $data['file']['name'];
684 704
685 $aOptions = array(); 705 $aOptions = array();
plugins/ktstandard/documentpreview/resources/container.css
@@ -28,7 +28,7 @@ @@ -28,7 +28,7 @@
28 padding-bottom: 0px; 28 padding-bottom: 0px;
29 cursor: pointer; 29 cursor: pointer;
30 height: 250px; 30 height: 250px;
31 - overflow: hidden; 31 + overflow: auto;
32 clear: both; 32 clear: both;
33 } 33 }
34 34
plugins/ktstandard/documentpreview/resources/preview.js
@@ -15,7 +15,7 @@ var showInfo = function(iDocId, sUrl, sDir, loading){ @@ -15,7 +15,7 @@ var showInfo = function(iDocId, sUrl, sDir, loading){
15 modal: true, 15 modal: true,
16 plain: false, 16 plain: false,
17 width: 500, 17 width: 500,
18 - height: 300, 18 + height: 360,
19 minWidth: 300, 19 minWidth: 300,
20 minHeight: 250 20 minHeight: 250
21 }); 21 });
plugins/rssplugin/loadFeed.inc.php
@@ -48,7 +48,7 @@ @@ -48,7 +48,7 @@
48 } 48 }
49 49
50 // Check if the feed matches a url 50 // Check if the feed matches a url
51 - if(!preg_match("/^http:\/\/([^\/]+)(.*)$/", $feed, $matches)){ 51 + if(!preg_match("/^http[s]?:\/\/([^\/]+)(.*)$/", $feed, $matches)){
52 // If not, it is an internal feed 52 // If not, it is an internal feed
53 $aRSSArray = KTrss::getInternalFeed($user); 53 $aRSSArray = KTrss::getInternalFeed($user);
54 }else{ 54 }else{
plugins/rssplugin/rss2array.inc.php
@@ -7,31 +7,31 @@ @@ -7,31 +7,31 @@
7 * Document Management Made Simple 7 * Document Management Made Simple
8 * Copyright (C) 2008 KnowledgeTree Inc. 8 * Copyright (C) 2008 KnowledgeTree Inc.
9 * Portions copyright The Jam Warehouse Software (Pty) Limited 9 * Portions copyright The Jam Warehouse Software (Pty) Limited
10 - * 10 + *
11 * This program is free software; you can redistribute it and/or modify it under 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 12 * the terms of the GNU General Public License version 3 as published by the
13 * Free Software Foundation. 13 * Free Software Foundation.
14 - * 14 + *
15 * This program is distributed in the hope that it will be useful, but WITHOUT 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 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 17 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 * details. 18 * details.
19 - * 19 + *
20 * You should have received a copy of the GNU General Public License 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/>. 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 * California 94120-7775, or email info@knowledgetree.com. 24 * California 94120-7775, or email info@knowledgetree.com.
25 - * 25 + *
26 * The interactive user interfaces in modified source and object code versions 26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under 27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU General Public License version 3. 28 * Section 5 of the GNU General Public License version 3.
29 - * 29 + *
30 * In accordance with Section 7(b) of the GNU General Public License version 3, 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 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 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices 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 * copyright notice. 35 * copyright notice.
36 * Contributor( s): ______________________________________ 36 * Contributor( s): ______________________________________
37 * 37 *
@@ -62,7 +62,7 @@ @@ -62,7 +62,7 @@
62 # if the URL looks ok 62 # if the URL looks ok
63 # 63 #
64 64
65 - if(preg_match("/^http:\/\/([^\/]+)(.*)$/", $url, $matches)){ 65 + if(preg_match("/^http[s]?:\/\/([^\/]+)(.*)$/", $url, $matches)){
66 66
67 $host = $matches[1]; 67 $host = $matches[1];
68 $uri = $matches[2]; 68 $uri = $matches[2];
plugins/rssplugin/templates/RSSPlugin/addfeed.smarty
1 -{$context->oPage->requireJSResource("thirdpartyjs/tinymce/jscripts/tiny_mce/tiny_mce.js")}  
2 -{capture assign=sJS}  
3 -{literal}  
4 -tinyMCE.init({  
5 - mode : "textareas",  
6 - theme : "simple",  
7 -});  
8 -{/literal}  
9 -{/capture}  
10 -{$context->oPage->requireJSStandalone($sJS)}  
11 -  
12 -  
13 -  
14 <h2>{i18n}New RSS Feed{/i18n}</h2> 1 <h2>{i18n}New RSS Feed{/i18n}</h2>
15 2
16 <p class="descriptiveText">{i18n}Create a rss feed which will be displayed on the dashboard{/i18n}</p> 3 <p class="descriptiveText">{i18n}Create a rss feed which will be displayed on the dashboard{/i18n}</p>
plugins/rssplugin/templates/RSSPlugin/editfeed.smarty
1 -{$context->oPage->requireJSResource("thirdpartyjs/tinymce/jscripts/tiny_mce/tiny_mce.js")}  
2 -{capture assign=sJS}  
3 -{literal}  
4 -tinyMCE.init({  
5 - mode : "textareas",  
6 - theme : "simple",  
7 -});  
8 -{/literal}  
9 -{/capture}  
10 -{$context->oPage->requireJSStandalone($sJS)}  
11 -  
12 -  
13 -  
14 <h2>{i18n}Edit RSS Feed{/i18n}</h2> 1 <h2>{i18n}Edit RSS Feed{/i18n}</h2>
15 2
16 <p class="descriptiveText">{i18n}Edit a RSS feed{/i18n}</p> 3 <p class="descriptiveText">{i18n}Edit a RSS feed{/i18n}</p>
search2.php
@@ -35,15 +35,20 @@ @@ -35,15 +35,20 @@
35 * Contributor( s): ______________________________________ 35 * Contributor( s): ______________________________________
36 */ 36 */
37 37
  38 +// TODO: do we have to serialise/unserialise the results. this is not optimal!!!
  39 +
38 session_start(); 40 session_start();
39 require_once("config/dmsDefaults.php"); 41 require_once("config/dmsDefaults.php");
  42 +require_once(KT_DIR . '/search2/indexing/indexerCore.inc.php');
  43 +
40 require_once(KT_LIB_DIR . "/unitmanagement/Unit.inc"); 44 require_once(KT_LIB_DIR . "/unitmanagement/Unit.inc");
41 45
42 require_once(KT_LIB_DIR . "/templating/templating.inc.php"); 46 require_once(KT_LIB_DIR . "/templating/templating.inc.php");
43 require_once(KT_LIB_DIR . "/dispatcher.inc.php"); 47 require_once(KT_LIB_DIR . "/dispatcher.inc.php");
44 require_once(KT_LIB_DIR . "/widgets/forms.inc.php"); 48 require_once(KT_LIB_DIR . "/widgets/forms.inc.php");
45 require_once(KT_LIB_DIR . "/actions/bulkaction.php"); 49 require_once(KT_LIB_DIR . "/actions/bulkaction.php");
46 -require_once(KT_DIR . '/search2/search/search.inc.php'); 50 +
  51 +require_once(KT_LIB_DIR . '/browse/DocumentCollection.inc.php');
47 require_once(KT_LIB_DIR . '/documentmanagement/Document.inc'); 52 require_once(KT_LIB_DIR . '/documentmanagement/Document.inc');
48 require_once(KT_LIB_DIR . '/browse/PartialQuery.inc.php'); 53 require_once(KT_LIB_DIR . '/browse/PartialQuery.inc.php');
49 54
@@ -117,7 +122,6 @@ function search2QuerySort($sSortColumn, $sSortOrder) @@ -117,7 +122,6 @@ function search2QuerySort($sSortColumn, $sSortOrder)
117 return; 122 return;
118 } 123 }
119 124
120 -  
121 $results = unserialize($_SESSION['search2_results']); 125 $results = unserialize($_SESSION['search2_results']);
122 126
123 usort($results, 'search2queryCompare'); 127 usort($results, 'search2queryCompare');
@@ -132,38 +136,70 @@ function search2QuerySort($sSortColumn, $sSortOrder) @@ -132,38 +136,70 @@ function search2QuerySort($sSortColumn, $sSortOrder)
132 */ 136 */
133 class Search2Query extends PartialQuery 137 class Search2Query extends PartialQuery
134 { 138 {
135 - function getFolderCount() { return 0; } 139 + function _count($type)
  140 + {
  141 + $count = 0;
  142 + $results = unserialize($_SESSION['search2_results']);
  143 +
  144 + switch ($type)
  145 + {
  146 + case 'Document':
  147 + return count($results['docs']) + count($results['shortdocs']);
  148 + case 'Folder':
  149 + return count($results['folders']) + count($results['shortfolders']);
  150 + default:
  151 + return 0;
  152 + }
  153 + }
  154 +
  155 + function getFolderCount()
  156 + {
  157 + return $this->_count('Folder');
  158 + }
136 function getDocumentCount() 159 function getDocumentCount()
137 { 160 {
138 - $results = $_SESSION['search2_results'];  
139 - if(isset($results) && !empty($results)){  
140 - return count(unserialize($results)); 161 + return $this->_count('Document');
  162 + }
  163 +
  164 + function getItems($type, $iStart, $iSize, $sSortColumn, $sSortOrder)
  165 + {
  166 + // TODO: quick hack. do this more optimally!!!!
  167 + $results = unserialize($_SESSION['search2_results']);
  168 +
  169 + switch ($type)
  170 + {
  171 + case 'Document':
  172 + $type = 'docs';
  173 + break;
  174 + case 'Folder':
  175 + $type = 'folders';
  176 + break;
141 } 177 }
142 - return 0; 178 +
  179 + $resultArray = $results[$type];
  180 + foreach($results['short' . $type] as $rec)
  181 + {
  182 + $resultArray[] = $rec;
  183 + }
  184 +
  185 + $resultArray = array_slice($resultArray, $iStart, $iSize);
  186 + $results = array();
  187 + foreach($resultArray as $rec)
  188 + {
  189 + $results[] = array('id'=>$rec->Id);
  190 + }
  191 +
  192 + return $results;
143 } 193 }
144 194
145 function getFolders($iBatchSize, $iBatchStart, $sSortColumn, $sSortOrder, $sJoinClause = null, $aJoinParams = null) 195 function getFolders($iBatchSize, $iBatchStart, $sSortColumn, $sSortOrder, $sJoinClause = null, $aJoinParams = null)
146 { 196 {
147 - return array(); 197 + return $this->getItems('Folder', $iBatchStart, $iBatchSize, $sSortColumn, $sSortOrder);
148 } 198 }
149 199
150 function getDocuments($iBatchSize, $iBatchStart, $sSortColumn, $sSortOrder, $sJoinClause = null, $aJoinParams = null) 200 function getDocuments($iBatchSize, $iBatchStart, $sSortColumn, $sSortOrder, $sJoinClause = null, $aJoinParams = null)
151 { 201 {
152 - search2QuerySort($_GET['sort_on'], $_GET['sort_order']);  
153 - $results = unserialize($_SESSION['search2_results']);  
154 -  
155 - $batch = array();  
156 -  
157 - $no_results = count($results);  
158 - for($i=0;$i<$no_results;$i++)  
159 - {  
160 - if ($i < $iBatchStart) continue;  
161 - if ($i > $iBatchStart + $iBatchSize) continue;  
162 -  
163 - $batch[] = array('id'=>$results[$i]->DocumentID);  
164 - }  
165 -  
166 - return $batch; 202 + return $this->getItems('Document', $iBatchStart, $iBatchSize, $sSortColumn, $sSortOrder);
167 } 203 }
168 } 204 }
169 205
@@ -208,10 +244,12 @@ class SearchDispatcher extends KTStandardDispatcher { @@ -208,10 +244,12 @@ class SearchDispatcher extends KTStandardDispatcher {
208 { 244 {
209 $expr = parseExpression($query); 245 $expr = parseExpression($query);
210 246
211 - $result = $expr->evaluate();  
212 - usort($result, 'rank_compare'); 247 + $results = $expr->evaluate();
  248 + $results = resolveSearchShortcuts($results);
213 249
214 - $_SESSION['search2_results'] = serialize($result); 250 + usort($result['docs'], 'rank_compare');
  251 +
  252 + $_SESSION['search2_results'] = serialize($results);
215 $_SESSION['search2_query'] = $query; 253 $_SESSION['search2_query'] = $query;
216 $_SESSION['search2_sort'] = 'rank'; 254 $_SESSION['search2_sort'] = 'rank';
217 255
@@ -410,6 +448,15 @@ class SearchDispatcher extends KTStandardDispatcher { @@ -410,6 +448,15 @@ class SearchDispatcher extends KTStandardDispatcher {
410 448
411 $results = unserialize($_SESSION['search2_results']); 449 $results = unserialize($_SESSION['search2_results']);
412 450
  451 + // NOTE: sorting results (when it is implemented) might have to be done per section, as it is done with the browse view
  452 +
  453 + $resultArray = $results['docs'];
  454 + foreach($results['folders'] as $f) $resultArray[] = $f;
  455 + foreach($results['shortdocs'] as $d) $resultArray[] = $d;
  456 + foreach($results['shortfolders'] as $f) $resultArray[] = $f;
  457 +
  458 + $results = $resultArray;
  459 +
413 if (!is_array($results) || count($results) == 0) 460 if (!is_array($results) || count($results) == 0)
414 { 461 {
415 $results=array(); 462 $results=array();
search2/indexing/indexerCore.inc.php
@@ -41,17 +41,142 @@ define(&#39;SEARCH2_INDEXER_DIR&#39;,realpath(dirname(__FILE__)) . &#39;/&#39;); @@ -41,17 +41,142 @@ define(&#39;SEARCH2_INDEXER_DIR&#39;,realpath(dirname(__FILE__)) . &#39;/&#39;);
41 require_once('indexing/extractorCore.inc.php'); 41 require_once('indexing/extractorCore.inc.php');
42 require_once(KT_DIR . '/plugins/ktcore/scheduler/schedulerUtil.php'); 42 require_once(KT_DIR . '/plugins/ktcore/scheduler/schedulerUtil.php');
43 43
44 -  
45 class IndexerInconsistencyException extends Exception {}; 44 class IndexerInconsistencyException extends Exception {};
46 45
  46 +// TODO: Query Result Items code should be moved into the Search section. It has less to do with indexing...
  47 +
47 class QueryResultItem 48 class QueryResultItem
48 { 49 {
49 - protected $document_id; 50 + protected $id;
50 protected $title; 51 protected $title;
51 protected $rank; 52 protected $rank;
52 protected $text; 53 protected $text;
53 - protected $filesize;  
54 protected $fullpath; 54 protected $fullpath;
  55 +
  56 + public function __construct($id, $title, $rank, $text, $fullpath)
  57 + {
  58 + $this->id = $id;
  59 + $this->title = $title;
  60 + $this->rank = $rank;
  61 + $this->text = $text;
  62 + $this->fullpath = $fullpath;
  63 + }
  64 +
  65 + public function getId() { return $this->id; }
  66 +
  67 + public function getIsProxy() { return $this instanceof ProxyResultItem; }
  68 + public function getIsFolder() { return substr(get_class($this), 0, 6) == 'Folder' ; }
  69 + public function getIsDocument() { return substr(get_class($this), 0, 8) == 'Document' ; }
  70 +
  71 + public function setRank($value)
  72 + {
  73 + $this->rank = number_format($value,2,'.',',');
  74 + }
  75 +
  76 + public function getIsLive()
  77 + {
  78 + return true;
  79 + }
  80 +
  81 + public function setTitle($value)
  82 + {
  83 + $this->title = $value;
  84 + }
  85 +
  86 + public function setText($value)
  87 + {
  88 + $this->text = $value;
  89 + }
  90 +
  91 + public function getRelevance() { return (float) $this->rank; }
  92 + public function getRank() { return $this->getRelevance(); }
  93 + public function getText() { return (string) $this->text; }
  94 + public function getTitle() { return (string) $this->title; }
  95 + public function getFullPath() { return (string) $this->fullpath; }
  96 +
  97 + protected function __get($property)
  98 + {
  99 + if (empty($property))
  100 + {
  101 + return '';
  102 + }
  103 +
  104 + $method = 'get' . $property;
  105 + if (method_exists($this, $method))
  106 + {
  107 + return $this->$method();
  108 + }
  109 + return $this->getUnknown();
  110 + }
  111 +
  112 + protected function getUnknown()
  113 + {
  114 + return _kt('n/a');
  115 + }
  116 +
  117 + protected function __set($property, $value)
  118 + {
  119 + if (empty($property))
  120 + {
  121 + return '';
  122 + }
  123 +
  124 + $method = 'set' . $property;
  125 + if (method_exists($this, $method))
  126 + {
  127 + return $this->$method($value);
  128 + }
  129 + throw new Exception("Unknown property '$property' to set on QueryResultItem");
  130 + }
  131 +}
  132 +
  133 +class ProxyResultItem extends QueryResultItem
  134 +{
  135 + protected $proxy;
  136 + protected $proxyId;
  137 +
  138 + public function __construct($proxyId, $proxy)
  139 + {
  140 + parent::__construct($proxyId, $proxy->getTitle, $proxy->getRank(), $proxy->getText(), $proxy->getFullPath());
  141 + $this->proxyId = $proxyId;
  142 + $this->proxy = $proxy;
  143 + }
  144 +
  145 + public function getId() { return $this->proxyId; }
  146 + public function getTitle() { return $this->proxy->getTitle(); }
  147 + public function getRealId() { return $this->proxy->getId(); }
  148 +
  149 + protected function __get($property)
  150 + {
  151 + $method = 'get' . $property;
  152 +
  153 + if (method_exists($this, $method))
  154 + {
  155 + return $this->$method();
  156 + }
  157 + else
  158 + {
  159 + return $this->proxy->$method();
  160 + }
  161 + }
  162 +
  163 + protected function __set($property, $value)
  164 + {
  165 + $method = 'set' . $property;
  166 + if (method_exists($this, $method))
  167 + {
  168 + return $this->$method($value);
  169 + }
  170 + else
  171 + {
  172 + return $this->proxy->$method($value);
  173 + }
  174 + }
  175 +}
  176 +
  177 +class DocumentResultItem extends QueryResultItem
  178 +{
  179 + protected $filesize;
55 protected $live; 180 protected $live;
56 protected $version; 181 protected $version;
57 protected $mimeType; 182 protected $mimeType;
@@ -78,17 +203,14 @@ class QueryResultItem @@ -78,17 +203,14 @@ class QueryResultItem
78 protected $mimeDisplay; 203 protected $mimeDisplay;
79 protected $oemDocumentNo; 204 protected $oemDocumentNo;
80 205
81 - public function __construct($document_id, $rank=null, $title=null, $text=null) 206 + public function __construct($document_id, $rank=null, $title=null, $text=null, $fullpath = null)
82 { 207 {
83 - $this->document_id=(int) $document_id;  
84 - $this->rank= $rank;  
85 - $this->title=$title;  
86 - $this->text = $text; 208 + parent::__construct($document_id, $title, $rank, $text, $fullpath);
87 $this->live = true; 209 $this->live = true;
88 $this->loadDocumentInfo(); 210 $this->loadDocumentInfo();
89 } 211 }
90 212
91 - protected function __isset($property) 213 + /*protected function __isset($property)
92 { 214 {
93 switch($property) 215 switch($property)
94 { 216 {
@@ -101,8 +223,9 @@ class QueryResultItem @@ -101,8 +223,9 @@ class QueryResultItem
101 throw new Exception("Unknown property '$property' to get on QueryResultItem"); 223 throw new Exception("Unknown property '$property' to get on QueryResultItem");
102 } 224 }
103 return true; // should not be reached 225 return true; // should not be reached
104 - } 226 + }*/
105 227
  228 + // TODO: this is bad. must refactor to do the query on the group of documents.
106 public function loadDocumentInfo() 229 public function loadDocumentInfo()
107 { 230 {
108 global $default; 231 global $default;
@@ -127,7 +250,7 @@ class QueryResultItem @@ -127,7 +250,7 @@ class QueryResultItem
127 LEFT JOIN users cbu ON d.creator_id=cbu.id 250 LEFT JOIN users cbu ON d.creator_id=cbu.id
128 LEFT JOIN users ou ON d.owner_id=ou.id 251 LEFT JOIN users ou ON d.owner_id=ou.id
129 WHERE 252 WHERE
130 - d.id=$this->document_id"; 253 + d.id=$this->id";
131 254
132 $result = DBUtil::getOneResult($sql); 255 $result = DBUtil::getOneResult($sql);
133 256
@@ -186,107 +309,116 @@ class QueryResultItem @@ -186,107 +309,116 @@ class QueryResultItem
186 309
187 $this->mimeType = $result['mimetype']; 310 $this->mimeType = $result['mimetype'];
188 $this->mimeIconPath = $result['mime_icon_path']; 311 $this->mimeIconPath = $result['mime_icon_path'];
  312 + if (empty($this->mimeIconPath))
  313 + {
  314 + $this->mimeIconPath = 'unspecified_type';
  315 + }
189 $this->mimeDisplay = $result['mime_display']; 316 $this->mimeDisplay = $result['mime_display'];
190 317
191 $this->storagePath = $result['storage_path']; 318 $this->storagePath = $result['storage_path'];
192 $this->status = Document::getStatusString($result['status_id']); 319 $this->status = Document::getStatusString($result['status_id']);
193 } 320 }
194 321
195 - protected function __get($property)  
196 - {  
197 - switch($property)  
198 - {  
199 - case null: return '';  
200 - case 'DocumentID': return (int) $this->document_id;  
201 - case 'Relevance':  
202 - case 'Rank': return (float) $this->rank;  
203 - case 'Text': return (string) $this->text;  
204 - case 'Title': return (string) $this->title;  
205 - case 'FullPath': return (string) $this->fullpath;  
206 - case 'IsLive': return (bool) $this->live;  
207 - case 'Filesize': return $this->filesize;  
208 - case 'Version': return (string) $this->version;  
209 - case 'Filename': return (string)$this->filename;  
210 - case 'FolderId': return (int)$this->folderId;  
211 - case 'OemDocumentNo': return (string) $this->oemDocumentNo;  
212 - case 'Document':  
213 - if (is_null($this->document)) 322 + public function getDocumentID() { return $this->getId(); }
  323 + public function getIsLive() { return (bool) $this->live; }
  324 + public function getFilesize() { return $this->filesize; }
  325 + public function getVersion() { return (string) $this->version; }
  326 + public function getFilename() { return (string)$this->filename; }
  327 + public function getFolderId() { return (int)$this->folderId; }
  328 + public function getOemDocumentNo() { return (string) $this->oemDocumentNo; }
  329 + public function getDocument() { if (is_null($this->document))
214 { 330 {
215 - $this->document = Document::get($this->document_id); 331 + $this->document = Document::get($this->id);
216 } 332 }
217 - return $this->document;  
218 - case 'IsAvailable':  
219 - return $this->Document->isLive();  
220 - case 'CheckedOutUser':  
221 - case 'CheckedOutBy':  
222 - return (string) $this->checkedOutUser;  
223 - case 'WorkflowOnly':  
224 - case 'Workflow':  
225 - return (string)$this->workflow;  
226 - case 'WorkflowStateOnly':  
227 - case 'WorkflowState':  
228 - return (string)$this->workflowState;  
229 - case 'WorkflowAndState':  
230 - if (is_null($this->workflow)) 333 + return $this->document; }
  334 + public function getIsAvailable() { return $this->Document->isLive(); }
  335 + public function getCheckedOutUser() { return (string) $this->checkedOutUser; }
  336 + public function getCheckedOutByr() { return $this->getCheckedOutUser(); }
  337 + public function getWorkflowOnly() { return (string)$this->workflow; }
  338 + public function getWorkflow() { return $this->getWorkflow(); }
  339 + public function getWorkflowStateOnly() { return (string)$this->workflowState; }
  340 + public function getWorkflowState() { return $this->getWorkflowStateOnly(); }
  341 + public function getWorkflowAndState() { if (is_null($this->workflow))
231 { 342 {
232 return ''; 343 return '';
233 } 344 }
234 - return "$this->workflow - $this->workflowState";  
235 - case 'MimeType':  
236 - return (string) $this->mimeType;  
237 - case 'MimeIconPath':  
238 - return (string) $this->mimeIconPath;  
239 - case 'MimeDisplay':  
240 - return (string) $this->mimeDisplay;  
241 - case 'DateCheckedOut':  
242 - return (string) $this->dateCheckedout;  
243 - case 'ModifiedBy':  
244 - return (string) $this->modifiedBy;  
245 - case 'DateModified':  
246 - return (string) $this->dateModified;  
247 - case 'CreatedBy':  
248 - return (string) $this->createdBy;  
249 - case 'DateCreated':  
250 - return (string) $this->dateCreated;  
251 - case 'Owner':  
252 - case 'OwnedBy':  
253 - return (string) $this->owner;  
254 - case 'IsImmutable':  
255 - case 'Immutable':  
256 - return (bool) $this->immutable;  
257 - case 'Status':  
258 - return $this->status;  
259 - case 'StoragePath':  
260 - return $this->storagePath;  
261 - case 'DocumentType':  
262 - return $this->documentType;  
263 - case 'Permissions':  
264 - return 'not available';  
265 - case 'CanBeReadByUser':  
266 - if (!$this->live) 345 + return "$this->workflow - $this->workflowState"; }
  346 + public function getMimeType() { return (string) $this->mimeType; }
  347 + public function getMimeIconPath() { return (string) $this->mimeIconPath; }
  348 + public function getMimeDisplay() { return (string) $this->mimeDisplay; }
  349 + public function getDateCheckedOut() { return (string) $this->dateCheckedout; }
  350 + public function getModifiedBy() { return (string) $this->modifiedBy; }
  351 + public function getDateModified() { return (string) $this->dateModified; }
  352 + public function getCreatedBy() { return (string) $this->createdBy; }
  353 + public function getDateCreated() { return (string) $this->dateCreated; }
  354 + public function getOwner() { return (string) $this->owner; }
  355 + public function getOwnedBy() { return $this->getOwner(); }
  356 + public function getIsImmutable() { return (bool) $this->immutable; }
  357 + public function getImmutable() { return $this->getIsImmutable(); }
  358 + public function getStatus() { return $this->status; }
  359 + public function getStoragePath() { return $this->storagePath; }
  360 + public function getDocumentType() { return $this->documentType; }
  361 + public function getPermissions() { return 'not available'; }
  362 + public function getCanBeReadByUser() { if (!$this->live)
267 return false; 363 return false;
268 if (Permission::userHasDocumentReadPermission($this->Document)) 364 if (Permission::userHasDocumentReadPermission($this->Document))
269 return true; 365 return true;
270 if (Permission::adminIsInAdminMode()) 366 if (Permission::adminIsInAdminMode())
271 return true; 367 return true;
272 - return false;  
273 - default:  
274 - throw new Exception("Unknown property '$property' to get on QueryResultItem");  
275 - }  
276 - return ''; // Should not be reached 368 + return false; }
  369 +
  370 +
  371 +}
  372 +
  373 +class FolderResultItem extends QueryResultItem
  374 +{
  375 + protected $folder;
  376 + protected $createdBy;
  377 + protected $parentId;
  378 +
  379 + public function __construct($folder_id, $rank=null, $title=null, $text=null, $fullpath = null)
  380 + {
  381 + parent::__construct($folder_id, $title, $rank, $text, $fullpath);
  382 + $this->loadDocumentInfo();
277 } 383 }
278 384
279 - protected function __set($property, $value) 385 + public function getFolderID() { return $this->getId(); }
  386 + public function getParentID() { return $this->parentId; }
  387 + public function getCreatedBy() { return $this->createdBy; }
  388 + public function getMimeIconPath() { return 'folder'; }
  389 + public function getFolder() {
  390 + return $this->folder; }
  391 +
  392 + public function loadDocumentInfo()
280 { 393 {
281 - switch($property) 394 + global $default;
  395 + $this->folder = $folder = Folder::get($this->getFolderID());
  396 + if (PEAR::isError($folder))
282 { 397 {
283 - case 'Rank': $this->rank = number_format($value,2,'.',','); break;  
284 - case 'Title': $this->title = $value; break;  
285 - case 'Text': $this->text = $value; break;  
286 - default:  
287 - throw new Exception("Unknown property '$property' to set on QueryResultItem"); 398 + throw new Exception('Database exception! There appears to be an error in the system: ' .$result->getMessage());
288 } 399 }
  400 + $this->title = $folder->getName();
  401 + $this->fullpath = '/' . $folder->getFullPath();
  402 + $this->parentId = $folder->getParentId();
  403 +
  404 + $user = User::get($folder->getCreatorID());
  405 + $this->createdBy = (PEAR::isError($user))?_kt('Unknown'):$user->getName();
289 } 406 }
  407 +
  408 +}
  409 +
  410 +class DocumentShortcutResultItem extends ProxyResultItem
  411 +{
  412 + public function getDocumentID() { return $this->getId(); }
  413 + public function getMimeIconPath() { return $this->proxy->getMimeIconPath() . '_shortcut'; }
  414 +
  415 +}
  416 +
  417 +class FolderShortcutResultItem extends ProxyResultItem
  418 +{
  419 + public function getFolderID() { return $this->getId(); }
  420 + public function getMimeIconPath() { return 'folder_shortcut'; }
  421 +
290 } 422 }
291 423
292 function MatchResultCompare($a, $b) 424 function MatchResultCompare($a, $b)
search2/indexing/indexers/JavaXMLRPCLuceneIndexer.inc.php
@@ -187,10 +187,7 @@ class JavaXMLRPCLuceneIndexer extends Indexer @@ -187,10 +187,7 @@ class JavaXMLRPCLuceneIndexer extends Indexer
187 { 187 {
188 try 188 try
189 { 189 {
190 - $item = new QueryResultItem($document_id);  
191 - $item->Title = $hit->Title;  
192 - $item->Text = $hit->Content;  
193 - $item->Rank = $hit->Rank; 190 + $item = new DocumentResultItem($document_id, $hit->Rank, $hit->Title, $hit->Content);
194 191
195 if ($item->CanBeReadByUser) 192 if ($item->CanBeReadByUser)
196 { 193 {
search2/search/expr.inc.php
@@ -43,6 +43,8 @@ @@ -43,6 +43,8 @@
43 * 43 *
44 */ 44 */
45 45
  46 +// TODO: search expression evaluation needs some optimisation
  47 +
46 require_once('indexing/indexerCore.inc.php'); 48 require_once('indexing/indexerCore.inc.php');
47 require_once('search/fieldRegistry.inc.php'); 49 require_once('search/fieldRegistry.inc.php');
48 require_once('search/exprConstants.inc.php'); 50 require_once('search/exprConstants.inc.php');
@@ -157,11 +159,28 @@ class Expr @@ -157,11 +159,28 @@ class Expr
157 159
158 protected $expr_id; 160 protected $expr_id;
159 161
  162 + protected $context;
  163 +
160 public function __construct() 164 public function __construct()
161 { 165 {
162 $this->expr_id = Expr::$node_id++; 166 $this->expr_id = Expr::$node_id++;
163 } 167 }
164 168
  169 + public function appliesToContext()
  170 + {
  171 + return ExprContext::DOCUMENT;
  172 + }
  173 +
  174 + public function setContext($context)
  175 + {
  176 + $this->context = $context;
  177 + }
  178 +
  179 + public function getContext()
  180 + {
  181 + return $this->context;
  182 + }
  183 +
165 public function getExprId() 184 public function getExprId()
166 { 185 {
167 return $this->expr_id; 186 return $this->expr_id;
@@ -363,7 +382,7 @@ class FieldExpr extends Expr @@ -363,7 +382,7 @@ class FieldExpr extends Expr
363 */ 382 */
364 public function __toString() 383 public function __toString()
365 { 384 {
366 - return $this->alias; 385 + return $this->display;
367 } 386 }
368 387
369 public function toViz(&$str, $phase) 388 public function toViz(&$str, $phase)
@@ -406,6 +425,14 @@ class FieldExpr extends Expr @@ -406,6 +425,14 @@ class FieldExpr extends Expr
406 } 425 }
407 } 426 }
408 427
  428 +class ExprContext
  429 +{
  430 + const DOCUMENT = 1;
  431 + const FOLDER = 2;
  432 + const DOCUMENT_AND_FOLDER = 3;
  433 +}
  434 +
  435 +
409 class DBFieldExpr extends FieldExpr 436 class DBFieldExpr extends FieldExpr
410 { 437 {
411 /** 438 /**
@@ -966,24 +993,43 @@ class SQLQueryBuilder implements QueryBuilder @@ -966,24 +993,43 @@ class SQLQueryBuilder implements QueryBuilder
966 private $sql; 993 private $sql;
967 private $db; 994 private $db;
968 private $metadata; 995 private $metadata;
  996 + private $context;
969 997
970 - public function __construct() 998 + public function __construct($context)
971 { 999 {
972 - $this->used_tables = array(  
973 - 'documents'=>1,  
974 - 'document_metadata_version'=>1,  
975 - 'document_content_version'=>0,  
976 - 'tag_words'=>0,  
977 - 'document_fields_link'=>0  
978 - );  
979 -  
980 - $this->aliases = array(  
981 - 'documents'=>'d',  
982 - 'document_metadata_version'=>'dmv',  
983 - 'document_content_version'=>'dcv',  
984 - 'tag_words'=>'tw',  
985 - 'document_fields_link'=>'pdfl'  
986 - ); 1000 + $this->context = $context;
  1001 +
  1002 + switch ($context)
  1003 + {
  1004 + case ExprContext::DOCUMENT:
  1005 + $this->used_tables = array(
  1006 + 'documents'=>1,
  1007 + 'document_metadata_version'=>1,
  1008 + 'document_content_version'=>0,
  1009 + 'tag_words'=>0,
  1010 + 'document_fields_link'=>0
  1011 + );
  1012 +
  1013 + $this->aliases = array(
  1014 + 'documents'=>'d',
  1015 + 'document_metadata_version'=>'dmv',
  1016 + 'document_content_version'=>'dcv',
  1017 + 'tag_words'=>'tw',
  1018 + 'document_fields_link'=>'pdfl'
  1019 + );
  1020 + break;
  1021 + case ExprContext::FOLDER:
  1022 + $this->used_tables = array(
  1023 + 'folders'=>1,
  1024 + );
  1025 +
  1026 + $this->aliases = array(
  1027 + 'folders'=>'f',
  1028 + );
  1029 + break;
  1030 + default:
  1031 + throw new Exception('This was not expected - Context = ' . $context);
  1032 + }
987 1033
988 $this->sql = ''; 1034 $this->sql = '';
989 $this->db = array(); 1035 $this->db = array();
@@ -1013,8 +1059,15 @@ class SQLQueryBuilder implements QueryBuilder @@ -1013,8 +1059,15 @@ class SQLQueryBuilder implements QueryBuilder
1013 } 1059 }
1014 elseif ($expr->isDBExpr()) 1060 elseif ($expr->isDBExpr())
1015 { 1061 {
1016 - $this->db[] = & $parent;  
1017 - $this->used_tables[$expr->getTable()]++; 1062 + if (($this->context & $expr->appliesToContext()) == $this->context)
  1063 + {
  1064 + $this->db[] = & $parent;
  1065 + $tablename = $expr->getTable();
  1066 + if (array_key_exists($tablename, $this->used_tables))
  1067 + {
  1068 + $this->used_tables[$tablename]++;
  1069 + }
  1070 + }
1018 } 1071 }
1019 elseif ($expr->isOpExpr()) 1072 elseif ($expr->isOpExpr())
1020 { 1073 {
@@ -1042,12 +1095,16 @@ class SQLQueryBuilder implements QueryBuilder @@ -1042,12 +1095,16 @@ class SQLQueryBuilder implements QueryBuilder
1042 1095
1043 if ($field->isMetadataField()) 1096 if ($field->isMetadataField())
1044 { 1097 {
1045 - $this->metadata[] = $expr->getParent(); 1098 + $this->metadata[] = $expr->getParent();
1046 } 1099 }
1047 elseif ($field->isDBExpr()) 1100 elseif ($field->isDBExpr())
1048 { 1101 {
1049 - $this->db[] = $expr->getParent();  
1050 - $this->used_tables[$field->getTable()]++; 1102 + $this->db[] = $expr->getParent();
  1103 + $tablename = $field->getTable();
  1104 + if (array_key_exists($tablename, $this->used_tables))
  1105 + {
  1106 + $this->used_tables[$tablename]++;
  1107 + }
1051 } 1108 }
1052 } 1109 }
1053 } 1110 }
@@ -1076,29 +1133,40 @@ class SQLQueryBuilder implements QueryBuilder @@ -1076,29 +1133,40 @@ class SQLQueryBuilder implements QueryBuilder
1076 $left = $expr->left(); 1133 $left = $expr->left();
1077 $right = $expr->right(); 1134 $right = $expr->right();
1078 $isNot = $expr->not(); 1135 $isNot = $expr->not();
1079 - if ($left->isMetadataField()) 1136 + if ($left->isMetadataField() )
1080 { 1137 {
1081 - $offset = $this->resolveMetadataOffset($expr) + 1;  
1082 -  
1083 - $fieldset = $left->getField();  
1084 - $query = '(';  
1085 -  
1086 - if ($isNot)  
1087 - {  
1088 - $query .= "df$offset.name IS NULL OR ";  
1089 - }  
1090 -  
1091 - $query .= '(' . "df$offset.name='$fieldset' AND " . $right->getSQL($left, "dfl$offset.value", $expr->op(), $isNot) . ')';  
1092 -  
1093 -  
1094 - $query .= ')';  
1095 - 1138 + if ($this->context == ExprContext::DOCUMENT)
  1139 + {
  1140 + $offset = $this->resolveMetadataOffset($expr) + 1;
  1141 +
  1142 + $fieldset = $left->getField();
  1143 + $query = '(';
  1144 +
  1145 + if ($isNot)
  1146 + {
  1147 + $query .= "df$offset.name IS NULL OR ";
  1148 + }
  1149 +
  1150 + $query .= '(' . "df$offset.name='$fieldset' AND " . $right->getSQL($left, "dfl$offset.value", $expr->op(), $isNot) . ')';
  1151 +
  1152 + $query .= ')';
  1153 + }
  1154 + else
  1155 + {
  1156 + $query = 'false';
  1157 + }
1096 } 1158 }
1097 else 1159 else
1098 { 1160 {
1099 - $fieldname = $this->getFieldnameFromExpr($expr);  
1100 -  
1101 - $query = $right->getSQL($left, $left->modifyName($fieldname), $expr->op(), $isNot); 1161 + if ($this->context == ExprContext::FOLDER && $left->getContext() != ExprContext::FOLDER)
  1162 + {
  1163 + $query = 'false';
  1164 + }
  1165 + else
  1166 + {
  1167 + $fieldname = $this->getFieldnameFromExpr($expr);
  1168 + $query = $right->getSQL($left, $left->modifyName($fieldname), $expr->op(), $isNot);
  1169 + }
1102 } 1170 }
1103 return $query; 1171 return $query;
1104 } 1172 }
@@ -1107,17 +1175,30 @@ class SQLQueryBuilder implements QueryBuilder @@ -1107,17 +1175,30 @@ class SQLQueryBuilder implements QueryBuilder
1107 { 1175 {
1108 if (count($this->metadata) + count($this->db) == 0) 1176 if (count($this->metadata) + count($this->db) == 0)
1109 { 1177 {
1110 - throw new Exception('nothing to do'); 1178 + // return empty result set
  1179 + return 'select 1 from documents where false';
1111 } 1180 }
1112 1181
1113 - // we are doing this because content table is dependant on metadata table  
1114 - if ($this->used_tables['document_content_version'] > 0) $this->used_tables['document_metadata_version']++;  
1115 -  
1116 $sql = 1182 $sql =
1117 'SELECT ' . "\n"; 1183 'SELECT ' . "\n";
1118 1184
1119 - $sql .= 1185 + if ($this->context == ExprContext::DOCUMENT)
  1186 + {
  1187 + // we are doing this because content table is dependant on metadata table
  1188 + if ($this->used_tables['document_content_version'] > 0)
  1189 + {
  1190 + $this->used_tables['document_metadata_version']++;
  1191 + }
  1192 +
  1193 + $sql .=
1120 ' DISTINCT d.id, dmv.name as title'; 1194 ' DISTINCT d.id, dmv.name as title';
  1195 + }
  1196 + else
  1197 + {
  1198 + $sql .=
  1199 + ' DISTINCT f.id, f.name as title';
  1200 + }
  1201 +
1121 1202
1122 $offset=0; 1203 $offset=0;
1123 foreach($this->db as $expr) 1204 foreach($this->db as $expr)
@@ -1133,26 +1214,36 @@ class SQLQueryBuilder implements QueryBuilder @@ -1133,26 +1214,36 @@ class SQLQueryBuilder implements QueryBuilder
1133 } 1214 }
1134 1215
1135 $sql .= 1216 $sql .=
1136 - "\n" . 'FROM ' ."\n" .  
1137 - ' documents d ' ."\n"; 1217 + "\n" . 'FROM ' ."\n";
1138 1218
1139 - if ($this->used_tables['document_metadata_version'] > 0)  
1140 - {  
1141 - $sql .= ' INNER JOIN document_metadata_version dmv ON d.metadata_version_id=dmv.id' . "\n";  
1142 - }  
1143 - if ($this->used_tables['document_content_version'] > 0)  
1144 - {  
1145 - $sql .= ' INNER JOIN document_content_version dcv ON dmv.content_version_id=dcv.id ' . "\n";  
1146 - }  
1147 - if ($this->used_tables['document_fields_link'] > 0) 1219 + if ($this->context == ExprContext::DOCUMENT)
1148 { 1220 {
1149 - $sql .= ' LEFT JOIN document_fields_link pdfl ON dmv.id=pdfl.metadata_version_id ' . "\n";  
1150 - } 1221 + $primaryAlias = 'd';
  1222 + $sql .= ' documents d ' ."\n";
1151 1223
1152 - if ($this->used_tables['tag_words'] > 0) 1224 + if ($this->used_tables['document_metadata_version'] > 0)
  1225 + {
  1226 + $sql .= ' INNER JOIN document_metadata_version dmv ON d.metadata_version_id=dmv.id' . "\n";
  1227 + }
  1228 + if ($this->used_tables['document_content_version'] > 0)
  1229 + {
  1230 + $sql .= ' INNER JOIN document_content_version dcv ON dmv.content_version_id=dcv.id ' . "\n";
  1231 + }
  1232 + if ($this->used_tables['document_fields_link'] > 0)
  1233 + {
  1234 + $sql .= ' LEFT JOIN document_fields_link pdfl ON dmv.id=pdfl.metadata_version_id ' . "\n";
  1235 + }
  1236 +
  1237 + if ($this->used_tables['tag_words'] > 0)
  1238 + {
  1239 + $sql .= ' LEFT OUTER JOIN document_tags dt ON dt.document_id=d.id ' . "\n" .
  1240 + ' LEFT OUTER JOIN tag_words tw ON dt.tag_id = tw.id ' . "\n";
  1241 + }
  1242 + }
  1243 + else
1153 { 1244 {
1154 - $sql .= ' LEFT OUTER JOIN document_tags dt ON dt.document_id=d.id ' . "\n" .  
1155 - ' LEFT OUTER JOIN tag_words tw ON dt.tag_id = tw.id ' . "\n"; 1245 + $primaryAlias = 'f';
  1246 + $sql .= ' folders f ' ."\n";
1156 } 1247 }
1157 1248
1158 $offset = 0; 1249 $offset = 0;
@@ -1171,17 +1262,18 @@ class SQLQueryBuilder implements QueryBuilder @@ -1171,17 +1262,18 @@ class SQLQueryBuilder implements QueryBuilder
1171 $offset++; 1262 $offset++;
1172 } 1263 }
1173 1264
1174 -  
1175 -  
1176 - $offset=0;  
1177 - foreach($this->metadata as $expr) 1265 + if ($this->context == ExprContext::DOCUMENT)
1178 { 1266 {
1179 - $offset++;  
1180 - $field = $expr->left(); 1267 + $offset=0;
  1268 + foreach($this->metadata as $expr)
  1269 + {
  1270 + $offset++;
  1271 + $field = $expr->left();
1181 1272
1182 - $fieldid = $field->getFieldId();  
1183 - $sql .= " LEFT JOIN document_fields_link dfl$offset ON dfl$offset.metadata_version_id=d.metadata_version_id AND dfl$offset.document_field_id=$fieldid" . "\n";  
1184 - $sql .= " LEFT JOIN document_fields df$offset ON df$offset.id=dfl$offset.document_field_id" . "\n"; 1273 + $fieldid = $field->getFieldId();
  1274 + $sql .= " LEFT JOIN document_fields_link dfl$offset ON dfl$offset.metadata_version_id=d.metadata_version_id AND dfl$offset.document_field_id=$fieldid" . "\n";
  1275 + $sql .= " LEFT JOIN document_fields df$offset ON df$offset.id=dfl$offset.document_field_id" . "\n";
  1276 + }
1185 } 1277 }
1186 1278
1187 // Add permissions sql for read access 1279 // Add permissions sql for read access
@@ -1189,15 +1281,16 @@ class SQLQueryBuilder implements QueryBuilder @@ -1189,15 +1281,16 @@ class SQLQueryBuilder implements QueryBuilder
1189 $permId = $oPermission->getID(); 1281 $permId = $oPermission->getID();
1190 $oUser = User::get($_SESSION['userID']); 1282 $oUser = User::get($_SESSION['userID']);
1191 $aPermissionDescriptors = KTPermissionUtil::getPermissionDescriptorsForUser($oUser); 1283 $aPermissionDescriptors = KTPermissionUtil::getPermissionDescriptorsForUser($oUser);
1192 - $sPermissionDescriptors = (!empty($aPermissionDescriptors)) ? implode(',', $aPermissionDescriptors) : ''; 1284 + $sPermissionDescriptors = empty($aPermissionDescriptors)? -1: implode(',', $aPermissionDescriptors);
1193 1285
1194 - $sql .= 'LEFT JOIN folders f ON d.folder_id = f.id '. "\n";  
1195 -  
1196 - $sql .= 'INNER JOIN permission_lookups AS PL ON f.permission_lookup_id = PL.id '. "\n"; 1286 + $sql .= "INNER JOIN permission_lookups AS PL ON $primaryAlias.permission_lookup_id = PL.id\n";
1197 $sql .= 'INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = '.$permId. " \n"; 1287 $sql .= 'INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = '.$permId. " \n";
  1288 + $sql .= "WHERE PLA.permission_descriptor_id IN ($sPermissionDescriptors) AND ";
1198 1289
1199 - $sql .= "WHERE PLA.permission_descriptor_id IN ($sPermissionDescriptors) AND dmv.status_id=1 AND d.status_id=1 AND \n ";  
1200 - 1290 + if ($this->context == ExprContext::DOCUMENT)
  1291 + {
  1292 + $sql .= "dmv.status_id=1 AND d.status_id=1 AND \n ";
  1293 + }
1201 return $sql; 1294 return $sql;
1202 } 1295 }
1203 1296
@@ -1222,8 +1315,6 @@ class SQLQueryBuilder implements QueryBuilder @@ -1222,8 +1315,6 @@ class SQLQueryBuilder implements QueryBuilder
1222 1315
1223 private function resolveJoinOffset($expr) 1316 private function resolveJoinOffset($expr)
1224 { 1317 {
1225 -  
1226 -  
1227 $offset=0; 1318 $offset=0;
1228 foreach($this->db as $item) 1319 foreach($this->db as $item)
1229 { 1320 {
@@ -1242,11 +1333,18 @@ class SQLQueryBuilder implements QueryBuilder @@ -1242,11 +1333,18 @@ class SQLQueryBuilder implements QueryBuilder
1242 $right = $expr->right(); 1333 $right = $expr->right();
1243 if (DefaultOpCollection::isBoolean($expr)) 1334 if (DefaultOpCollection::isBoolean($expr))
1244 { 1335 {
1245 - $query = '(' . $this->buildCoreSQLExpr($left) . ' ' . $expr->op() . ' ' . $this->buildCoreSQLExpr($right) . ')'; 1336 + $query = '(' . $this->buildCoreSQLExpr($left) . ' ' . $expr->op() . ' ' . $this->buildCoreSQLExpr($right) . ')';
1246 } 1337 }
1247 else 1338 else
1248 { 1339 {
1249 - $query = $this->getSQLEvalExpr($expr); 1340 + if (($this->context & $expr->appliesToContext()) == $this->context)
  1341 + {
  1342 + $query = $this->getSQLEvalExpr($expr);
  1343 + }
  1344 + else
  1345 + {
  1346 + $query = 'false';
  1347 + }
1250 } 1348 }
1251 1349
1252 return $query; 1350 return $query;
@@ -1259,7 +1357,11 @@ class SQLQueryBuilder implements QueryBuilder @@ -1259,7 +1357,11 @@ class SQLQueryBuilder implements QueryBuilder
1259 1357
1260 $sql = $this->buildCoreSQL(); 1358 $sql = $this->buildCoreSQL();
1261 1359
1262 - $sql .= $this->buildCoreSQLExpr($expr); 1360 + $expr = $this->buildCoreSQLExpr($expr);
  1361 + if ($expr != 'false')
  1362 + {
  1363 + $sql .= $expr;
  1364 + }
1263 1365
1264 return $sql; 1366 return $sql;
1265 } 1367 }
@@ -1299,19 +1401,22 @@ class SQLQueryBuilder implements QueryBuilder @@ -1299,19 +1401,22 @@ class SQLQueryBuilder implements QueryBuilder
1299 $sql .= $value->getSQL($field, $left->modifyName($fieldname), $expr->op(), $expr->not()); 1401 $sql .= $value->getSQL($field, $left->modifyName($fieldname), $expr->op(), $expr->not());
1300 } 1402 }
1301 1403
1302 - $moffset=0;  
1303 - foreach($this->metadata as $expr) 1404 + if ($this->context == ExprContext::DOCUMENT)
1304 { 1405 {
1305 - $moffset++;  
1306 - if ($offset++) 1406 + $moffset=0;
  1407 + foreach($this->metadata as $expr)
1307 { 1408 {
1308 - $sql .= " $op\n " ;  
1309 - } 1409 + $moffset++;
  1410 + if ($offset++)
  1411 + {
  1412 + $sql .= " $op\n " ;
  1413 + }
1310 1414
1311 - $field = $expr->left();  
1312 - $value = $expr->right(); 1415 + $field = $expr->left();
  1416 + $value = $expr->right();
1313 1417
1314 - $sql .= $value->getSQL($field, "dfl$moffset.value", $expr->getOp()); 1418 + $sql .= $value->getSQL($field, "dfl$moffset.value", $expr->getOp());
  1419 + }
1315 } 1420 }
1316 1421
1317 return $sql; 1422 return $sql;
@@ -1331,7 +1436,6 @@ class SQLQueryBuilder implements QueryBuilder @@ -1331,7 +1436,6 @@ class SQLQueryBuilder implements QueryBuilder
1331 1436
1332 if (substr($col, 0, 4) == 'expr' && is_numeric(substr($col, 4))) 1437 if (substr($col, 0, 4) == 'expr' && is_numeric(substr($col, 4)))
1333 { 1438 {
1334 -  
1335 $exprno = substr($col, 4); 1439 $exprno = substr($col, 4);
1336 if ($exprno <= count($this->db)) 1440 if ($exprno <= count($this->db))
1337 { 1441 {
@@ -1379,8 +1483,6 @@ class SQLQueryBuilder implements QueryBuilder @@ -1379,8 +1483,6 @@ class SQLQueryBuilder implements QueryBuilder
1379 } 1483 }
1380 return '(' . implode(') AND (', $text) . ')'; 1484 return '(' . implode(') AND (', $text) . ')';
1381 } 1485 }
1382 -  
1383 -  
1384 } 1486 }
1385 1487
1386 1488
@@ -1444,6 +1546,13 @@ class OpExpr extends Expr @@ -1444,6 +1546,13 @@ class OpExpr extends Expr
1444 $this->has_text=$value; 1546 $this->has_text=$value;
1445 } 1547 }
1446 1548
  1549 + public function setContext($context)
  1550 + {
  1551 + parent::setContext($context);
  1552 + $this->left()->setContext($context);
  1553 + $this->right()->setContext($context);
  1554 + }
  1555 +
1447 public function getHasDb() 1556 public function getHasDb()
1448 { 1557 {
1449 return $this->has_db; 1558 return $this->has_db;
@@ -1619,7 +1728,6 @@ class OpExpr extends Expr @@ -1619,7 +1728,6 @@ class OpExpr extends Expr
1619 1728
1620 $point = null; 1729 $point = null;
1621 1730
1622 -  
1623 if ($left_op_match && $right_op_match) { $point = 'point'; } 1731 if ($left_op_match && $right_op_match) { $point = 'point'; }
1624 1732
1625 $left_op_match_flex = $left_op_match || ($left->isOpExpr()); 1733 $left_op_match_flex = $left_op_match || ($left->isOpExpr());
@@ -1682,6 +1790,11 @@ class OpExpr extends Expr @@ -1682,6 +1790,11 @@ class OpExpr extends Expr
1682 return $this->getHasDb() && $this->getHasText(); 1790 return $this->getHasDb() && $this->getHasText();
1683 } 1791 }
1684 1792
  1793 + public function appliesToContext()
  1794 + {
  1795 + return $this->left()->appliesToContext() | $this->right()->appliesToContext();
  1796 + }
  1797 +
1685 /** 1798 /**
1686 * Enter description here... 1799 * Enter description here...
1687 * 1800 *
@@ -1759,13 +1872,14 @@ class OpExpr extends Expr @@ -1759,13 +1872,14 @@ class OpExpr extends Expr
1759 */ 1872 */
1760 public function __toString() 1873 public function __toString()
1761 { 1874 {
1762 - $expr = $this->left_expr . ' ' . $this->op .' ' . $this->right_expr; 1875 + // _kt may not translate well here.
  1876 + $expr = $this->left_expr . ' ' . _kt($this->op) .' ' . $this->right_expr;
1763 1877
1764 if (is_null($this->parent)) 1878 if (is_null($this->parent))
1765 { 1879 {
1766 if ($this->not()) 1880 if ($this->not())
1767 { 1881 {
1768 - $expr = "NOT $expr"; 1882 + $expr = _kt('NOT') . $expr;
1769 } 1883 }
1770 return $expr; 1884 return $expr;
1771 } 1885 }
@@ -1805,7 +1919,7 @@ class OpExpr extends Expr @@ -1805,7 +1919,7 @@ class OpExpr extends Expr
1805 * @param array $rightres 1919 * @param array $rightres
1806 * @return array 1920 * @return array
1807 */ 1921 */
1808 - protected static function intersect($leftres, $rightres) 1922 + protected static function _intersect($leftres, $rightres)
1809 { 1923 {
1810 if (empty($leftres) || empty($rightres)) 1924 if (empty($leftres) || empty($rightres))
1811 { 1925 {
@@ -1814,7 +1928,7 @@ class OpExpr extends Expr @@ -1814,7 +1928,7 @@ class OpExpr extends Expr
1814 $result = array(); 1928 $result = array();
1815 foreach($leftres as $item) 1929 foreach($leftres as $item)
1816 { 1930 {
1817 - $document_id = $item->DocumentID; 1931 + $document_id = $item->Id;
1818 1932
1819 if (!$item->IsLive) 1933 if (!$item->IsLive)
1820 { 1934 {
@@ -1831,6 +1945,22 @@ class OpExpr extends Expr @@ -1831,6 +1945,22 @@ class OpExpr extends Expr
1831 return $result; 1945 return $result;
1832 } 1946 }
1833 1947
  1948 + protected static function intersect($leftres, $rightres)
  1949 + {
  1950 + return array(
  1951 + 'docs'=>self::_intersect($leftres['docs'],$rightres['docs']),
  1952 + 'folders'=>self::_intersect($leftres['folders'],$rightres['folders'])
  1953 + );
  1954 + }
  1955 +
  1956 + protected static function union($leftres, $rightres)
  1957 + {
  1958 + return array(
  1959 + 'docs'=>self::_union($leftres['docs'],$rightres['docs']),
  1960 + 'folders'=>self::_union($leftres['folders'],$rightres['folders'])
  1961 + );
  1962 + }
  1963 +
1834 /** 1964 /**
1835 * The objective of this function is to merge the results so that there is a union of the results, 1965 * The objective of this function is to merge the results so that there is a union of the results,
1836 * but there should be no duplicates. 1966 * but there should be no duplicates.
@@ -1839,7 +1969,7 @@ class OpExpr extends Expr @@ -1839,7 +1969,7 @@ class OpExpr extends Expr
1839 * @param array $rightres 1969 * @param array $rightres
1840 * @return array 1970 * @return array
1841 */ 1971 */
1842 - protected static function union($leftres, $rightres) 1972 + protected static function _union($leftres, $rightres)
1843 { 1973 {
1844 if (empty($leftres)) 1974 if (empty($leftres))
1845 { 1975 {
@@ -1855,15 +1985,15 @@ class OpExpr extends Expr @@ -1855,15 +1985,15 @@ class OpExpr extends Expr
1855 { 1985 {
1856 if ($item->IsLive) 1986 if ($item->IsLive)
1857 { 1987 {
1858 - $result[$item->DocumentID] = $item; 1988 + $result[$item->Id] = $item;
1859 } 1989 }
1860 } 1990 }
1861 1991
1862 foreach($rightres as $item) 1992 foreach($rightres as $item)
1863 { 1993 {
1864 - if (!array_key_exists($item->DocumentID, $result) || $item->Rank > $result[$item->DocumentID]->Rank) 1994 + if (!array_key_exists($item->Id, $result) || $item->Rank > $result[$item->Id]->Rank)
1865 { 1995 {
1866 - $result[$item->DocumentID] = $item; 1996 + $result[$item->Id] = $item;
1867 } 1997 }
1868 } 1998 }
1869 return $result; 1999 return $result;
@@ -1996,7 +2126,7 @@ class OpExpr extends Expr @@ -1996,7 +2126,7 @@ class OpExpr extends Expr
1996 { 2126 {
1997 if (empty($group)) { return array(); } 2127 if (empty($group)) { return array(); }
1998 2128
1999 - $exprbuilder = new SQLQueryBuilder(); 2129 + $exprbuilder = new SQLQueryBuilder($this->getContext());
2000 2130
2001 if (count($group) == 1) 2131 if (count($group) == 1)
2002 { 2132 {
@@ -2020,11 +2150,18 @@ class OpExpr extends Expr @@ -2020,11 +2150,18 @@ class OpExpr extends Expr
2020 2150
2021 foreach($rs as $item) 2151 foreach($rs as $item)
2022 { 2152 {
2023 - $document_id = $item['id']; 2153 + $id = $item['id'];
2024 $rank = $exprbuilder->getRanking($item); 2154 $rank = $exprbuilder->getRanking($item);
2025 - if (!array_key_exists($document_id, $results) || $rank > $results[$document_id]->Rank) 2155 + if (!array_key_exists($id, $results) || $rank > $results[$id]->Rank)
2026 { 2156 {
2027 - $results[$document_id] = new QueryResultItem($document_id, $rank, $item['title'], $exprbuilder->getResultText($item)); 2157 + if ($this->context == ExprContext::DOCUMENT)
  2158 + {
  2159 + $results[$id] = new DocumentResultItem($id, $rank, $item['title'], $exprbuilder->getResultText($item));
  2160 + }
  2161 + else
  2162 + {
  2163 + $results[$id] = new FolderResultItem($id, $rank, $item['title'], $exprbuilder->getResultText($item));
  2164 + }
2028 } 2165 }
2029 } 2166 }
2030 2167
@@ -2034,7 +2171,10 @@ class OpExpr extends Expr @@ -2034,7 +2171,10 @@ class OpExpr extends Expr
2034 2171
2035 private function exec_text_query($op, $group) 2172 private function exec_text_query($op, $group)
2036 { 2173 {
2037 - if (empty($group)) { return array(); } 2174 + if (($this->getContext() != ExprContext::DOCUMENT) || empty($group))
  2175 + {
  2176 + return array();
  2177 + }
2038 2178
2039 $exprbuilder = new TextQueryBuilder(); 2179 $exprbuilder = new TextQueryBuilder();
2040 2180
@@ -2060,12 +2200,21 @@ class OpExpr extends Expr @@ -2060,12 +2200,21 @@ class OpExpr extends Expr
2060 } 2200 }
2061 2201
2062 return $results; 2202 return $results;
2063 -  
2064 -  
2065 } 2203 }
2066 2204
2067 - public function evaluate() 2205 + public function evaluate($context = ExprContext::DOCUMENT_AND_FOLDER)
2068 { 2206 {
  2207 + if ($context == ExprContext::DOCUMENT_AND_FOLDER)
  2208 + {
  2209 + $docs = $this->evaluate(ExprContext::DOCUMENT);
  2210 + $folders = $this->evaluate(ExprContext::FOLDER);
  2211 +
  2212 + return array(
  2213 + 'docs' => $docs['docs'],
  2214 + 'folders' => $folders['folders']);
  2215 + }
  2216 + $this->setContext($context);
  2217 +
2069 $left = $this->left(); 2218 $left = $this->left();
2070 $right = $this->right(); 2219 $right = $this->right();
2071 $op = $this->op(); 2220 $op = $this->op();
@@ -2075,12 +2224,12 @@ class OpExpr extends Expr @@ -2075,12 +2224,12 @@ class OpExpr extends Expr
2075 { 2224 {
2076 $point = 'point'; 2225 $point = 'point';
2077 } 2226 }
  2227 + $resultContext = ($this->getContext() == ExprContext::DOCUMENT)?'docs':'folders';
2078 2228
2079 if ($point == 'merge') 2229 if ($point == 'merge')
2080 { 2230 {
2081 -  
2082 - $leftres = $left->evaluate();  
2083 - $rightres = $right->evaluate(); 2231 + $leftres = $left->evaluate($context);
  2232 + $rightres = $right->evaluate($context);
2084 switch ($op) 2233 switch ($op)
2085 { 2234 {
2086 case ExprOp::OP_AND: 2235 case ExprOp::OP_AND:
@@ -2099,31 +2248,33 @@ class OpExpr extends Expr @@ -2099,31 +2248,33 @@ class OpExpr extends Expr
2099 { 2248 {
2100 if ($this->isDBonly()) 2249 if ($this->isDBonly())
2101 { 2250 {
2102 - $result = $this->exec_db_query($op, array($this)); 2251 + $result[$resultContext] = $this->exec_db_query($op, array($this));
2103 } 2252 }
2104 elseif ($this->isTextOnly()) 2253 elseif ($this->isTextOnly())
2105 { 2254 {
2106 - $result = $this->exec_text_query($op, array($this)); 2255 + $result[$resultContext] = $this->exec_text_query($op, array($this));
2107 } 2256 }
2108 elseif (in_array($op, array(ExprOp::OP_OR, ExprOp::OP_AND))) 2257 elseif (in_array($op, array(ExprOp::OP_OR, ExprOp::OP_AND)))
2109 { 2258 {
  2259 + // do we get to this???
  2260 + // TODO: remove me please.... the simpleQuery stuff should go???
2110 $db_group = array(); 2261 $db_group = array();
2111 $text_group = array(); 2262 $text_group = array();
2112 $this->explore($left, $right, $db_group, 'db'); 2263 $this->explore($left, $right, $db_group, 'db');
2113 $this->explore($left, $right, $text_group, 'text'); 2264 $this->explore($left, $right, $text_group, 'text');
2114 2265
2115 - $db_result = $this->exec_db_query($op, $db_group);  
2116 - $text_result = $this->exec_text_query($op, $text_group); 2266 + $db_result[$resultContext] = $this->exec_db_query($op, $db_group);
  2267 + $text_result[$resultContext] = $this->exec_text_query($op, $text_group);
2117 2268
2118 switch ($op) 2269 switch ($op)
2119 { 2270 {
2120 case ExprOp::OP_AND: 2271 case ExprOp::OP_AND:
2121 if ($this->debug) print "\n\npoint: intersect\n\n"; 2272 if ($this->debug) print "\n\npoint: intersect\n\n";
2122 - $result = OpExpr::intersect($db_result, $text_result); 2273 + $result[$resultContext] = OpExpr::intersect($db_result, $text_result);
2123 break; 2274 break;
2124 case ExprOp::OP_OR: 2275 case ExprOp::OP_OR:
2125 if ($this->debug) print "\n\nmerge: union\n\n"; 2276 if ($this->debug) print "\n\nmerge: union\n\n";
2126 - $result = OpExpr::union($db_result, $text_result); 2277 + $result[$resultContext] = OpExpr::union($db_result, $text_result);
2127 break; 2278 break;
2128 default: 2279 default:
2129 throw new Exception('how did this happen??'); 2280 throw new Exception('how did this happen??');
@@ -2141,9 +2292,9 @@ class OpExpr extends Expr @@ -2141,9 +2292,9 @@ class OpExpr extends Expr
2141 } 2292 }
2142 2293
2143 $permResults = array(); 2294 $permResults = array();
2144 - foreach($result as $idx=>$item) 2295 + foreach($result[$resultContext] as $idx=>$item)
2145 { 2296 {
2146 - $permResults[$idx] = $item; 2297 + $permResults[$resultContext][$idx] = $item;
2147 } 2298 }
2148 2299
2149 return $permResults; 2300 return $permResults;
search2/search/exprConstants.inc.php
@@ -6,31 +6,31 @@ @@ -6,31 +6,31 @@
6 * Document Management Made Simple 6 * Document Management Made Simple
7 * Copyright (C) 2008 KnowledgeTree Inc. 7 * Copyright (C) 2008 KnowledgeTree Inc.
8 * Portions copyright The Jam Warehouse Software (Pty) Limited 8 * Portions copyright The Jam Warehouse Software (Pty) Limited
9 - * 9 + *
10 * This program is free software; you can redistribute it and/or modify it under 10 * This program is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License version 3 as published by the 11 * the terms of the GNU General Public License version 3 as published by the
12 * Free Software Foundation. 12 * Free Software Foundation.
13 - * 13 + *
14 * This program is distributed in the hope that it will be useful, but WITHOUT 14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 16 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * details. 17 * details.
18 - * 18 + *
19 * You should have received a copy of the GNU General Public License 19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>. 20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 - *  
22 - * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco, 21 + *
  22 + * You can contact KnowledgeTree Inc., PO Box 7775 #87847, San Francisco,
23 * California 94120-7775, or email info@knowledgetree.com. 23 * California 94120-7775, or email info@knowledgetree.com.
24 - * 24 + *
25 * The interactive user interfaces in modified source and object code versions 25 * The interactive user interfaces in modified source and object code versions
26 * of this program must display Appropriate Legal Notices, as required under 26 * of this program must display Appropriate Legal Notices, as required under
27 * Section 5 of the GNU General Public License version 3. 27 * Section 5 of the GNU General Public License version 3.
28 - * 28 + *
29 * In accordance with Section 7(b) of the GNU General Public License version 3, 29 * In accordance with Section 7(b) of the GNU General Public License version 3,
30 * these Appropriate Legal Notices must retain the display of the "Powered by 30 * these Appropriate Legal Notices must retain the display of the "Powered by
31 - * KnowledgeTree" logo and retain the original copyright notice. If the display of the 31 + * KnowledgeTree" logo and retain the original copyright notice. If the display of the
32 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices 32 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices
33 - * must display the words "Powered by KnowledgeTree" and retain the original 33 + * must display the words "Powered by KnowledgeTree" and retain the original
34 * copyright notice. 34 * copyright notice.
35 * Contributor( s): ______________________________________ 35 * Contributor( s): ______________________________________
36 * 36 *
@@ -51,6 +51,22 @@ class ExprOp @@ -51,6 +51,22 @@ class ExprOp
51 const OP_OR = 'OR'; 51 const OP_OR = 'OR';
52 const IS_NOT = 'is not'; 52 const IS_NOT = 'is not';
53 53
  54 +
  55 + private static
  56 + function init()
  57 + {
  58 + // this isn't really called, but used to help with translation.
  59 + _kt('is');
  60 + _kt('contains');
  61 + _kt('between');
  62 + _kt('start with');
  63 + _kt('ends with');
  64 + _kt('like');
  65 + _kt('AND');
  66 + _kt('OR');
  67 + _kt('is not');
  68 + }
  69 +
54 } 70 }
55 71
56 72
search2/search/fields/CreatedByField.inc.php
@@ -7,31 +7,31 @@ @@ -7,31 +7,31 @@
7 * Document Management Made Simple 7 * Document Management Made Simple
8 * Copyright (C) 2008 KnowledgeTree Inc. 8 * Copyright (C) 2008 KnowledgeTree Inc.
9 * Portions copyright The Jam Warehouse Software (Pty) Limited 9 * Portions copyright The Jam Warehouse Software (Pty) Limited
10 - * 10 + *
11 * This program is free software; you can redistribute it and/or modify it under 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 12 * the terms of the GNU General Public License version 3 as published by the
13 * Free Software Foundation. 13 * Free Software Foundation.
14 - * 14 + *
15 * This program is distributed in the hope that it will be useful, but WITHOUT 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 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 17 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 * details. 18 * details.
19 - * 19 + *
20 * You should have received a copy of the GNU General Public License 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/>. 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 * California 94120-7775, or email info@knowledgetree.com. 24 * California 94120-7775, or email info@knowledgetree.com.
25 - * 25 + *
26 * The interactive user interfaces in modified source and object code versions 26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under 27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU General Public License version 3. 28 * Section 5 of the GNU General Public License version 3.
29 - * 29 + *
30 * In accordance with Section 7(b) of the GNU General Public License version 3, 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 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 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices 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 * copyright notice. 35 * copyright notice.
36 * Contributor( s): ______________________________________ 36 * Contributor( s): ______________________________________
37 * 37 *
@@ -47,6 +47,25 @@ class CreatedByField extends DBFieldExpr @@ -47,6 +47,25 @@ class CreatedByField extends DBFieldExpr
47 $this->matchField('name'); 47 $this->matchField('name');
48 } 48 }
49 49
  50 + public function appliesToContext()
  51 + {
  52 + return ExprContext::DOCUMENT | ExprContext::FOLDER;
  53 + }
  54 +
  55 + public function setContext($context)
  56 + {
  57 + parent::setContext($context);
  58 + switch($context)
  59 + {
  60 + case ExprContext::DOCUMENT:
  61 + $this->table = 'documents';
  62 + break;
  63 + case ExprContext::FOLDER:
  64 + $this->table = 'folders';
  65 + break;
  66 + }
  67 + }
  68 +
50 public function getInputRequirements() 69 public function getInputRequirements()
51 { 70 {
52 return array('value'=>array('type'=>FieldInputType::USER_LIST)); 71 return array('value'=>array('type'=>FieldInputType::USER_LIST));
search2/search/fields/FullPathField.inc.php
@@ -7,31 +7,31 @@ @@ -7,31 +7,31 @@
7 * Document Management Made Simple 7 * Document Management Made Simple
8 * Copyright (C) 2008 KnowledgeTree Inc. 8 * Copyright (C) 2008 KnowledgeTree Inc.
9 * Portions copyright The Jam Warehouse Software (Pty) Limited 9 * Portions copyright The Jam Warehouse Software (Pty) Limited
10 - * 10 + *
11 * This program is free software; you can redistribute it and/or modify it under 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 12 * the terms of the GNU General Public License version 3 as published by the
13 * Free Software Foundation. 13 * Free Software Foundation.
14 - * 14 + *
15 * This program is distributed in the hope that it will be useful, but WITHOUT 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 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 17 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 * details. 18 * details.
19 - * 19 + *
20 * You should have received a copy of the GNU General Public License 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/>. 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 * California 94120-7775, or email info@knowledgetree.com. 24 * California 94120-7775, or email info@knowledgetree.com.
25 - * 25 + *
26 * The interactive user interfaces in modified source and object code versions 26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under 27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU General Public License version 3. 28 * Section 5 of the GNU General Public License version 3.
29 - * 29 + *
30 * In accordance with Section 7(b) of the GNU General Public License version 3, 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 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 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices 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 * copyright notice. 35 * copyright notice.
36 * Contributor( s): ______________________________________ 36 * Contributor( s): ______________________________________
37 * 37 *
@@ -47,6 +47,25 @@ class FullPathField extends DBFieldExpr @@ -47,6 +47,25 @@ class FullPathField extends DBFieldExpr
47 $this->setAlias('FullPath'); 47 $this->setAlias('FullPath');
48 } 48 }
49 49
  50 + public function setContext($context)
  51 + {
  52 + parent::setContext($context);
  53 + switch($context)
  54 + {
  55 + case ExprContext::DOCUMENT:
  56 + $this->table = 'documents';
  57 + break;
  58 + case ExprContext::FOLDER:
  59 + $this->table = 'folders';
  60 + break;
  61 + }
  62 + }
  63 +
  64 + public function appliesToContext($context)
  65 + {
  66 + return ExprContext::DOCUMENT | ExprContext::FOLDER;
  67 + }
  68 +
50 public function getInputRequirements() 69 public function getInputRequirements()
51 { 70 {
52 return array('value'=>array('type'=>FieldInputType::TEXT)); 71 return array('value'=>array('type'=>FieldInputType::TEXT));
search2/search/fields/TitleField.inc.php
@@ -7,31 +7,31 @@ @@ -7,31 +7,31 @@
7 * Document Management Made Simple 7 * Document Management Made Simple
8 * Copyright (C) 2008 KnowledgeTree Inc. 8 * Copyright (C) 2008 KnowledgeTree Inc.
9 * Portions copyright The Jam Warehouse Software (Pty) Limited 9 * Portions copyright The Jam Warehouse Software (Pty) Limited
10 - * 10 + *
11 * This program is free software; you can redistribute it and/or modify it under 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 12 * the terms of the GNU General Public License version 3 as published by the
13 * Free Software Foundation. 13 * Free Software Foundation.
14 - * 14 + *
15 * This program is distributed in the hope that it will be useful, but WITHOUT 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 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 17 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 * details. 18 * details.
19 - * 19 + *
20 * You should have received a copy of the GNU General Public License 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/>. 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 * California 94120-7775, or email info@knowledgetree.com. 24 * California 94120-7775, or email info@knowledgetree.com.
25 - * 25 + *
26 * The interactive user interfaces in modified source and object code versions 26 * The interactive user interfaces in modified source and object code versions
27 * of this program must display Appropriate Legal Notices, as required under 27 * of this program must display Appropriate Legal Notices, as required under
28 * Section 5 of the GNU General Public License version 3. 28 * Section 5 of the GNU General Public License version 3.
29 - * 29 + *
30 * In accordance with Section 7(b) of the GNU General Public License version 3, 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 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 * logo is not reasonably feasible for technical reasons, the Appropriate Legal Notices 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 * copyright notice. 35 * copyright notice.
36 * Contributor( s): ______________________________________ 36 * Contributor( s): ______________________________________
37 * 37 *
@@ -39,13 +39,31 @@ @@ -39,13 +39,31 @@
39 39
40 class TitleField extends DBFieldExpr 40 class TitleField extends DBFieldExpr
41 { 41 {
42 -  
43 public function __construct() 42 public function __construct()
44 { 43 {
45 parent::__construct('name', 'document_metadata_version', _kt('Title')); 44 parent::__construct('name', 'document_metadata_version', _kt('Title'));
46 $this->setAlias('Title'); 45 $this->setAlias('Title');
47 } 46 }
48 47
  48 + public function setContext($context)
  49 + {
  50 + parent::setContext($context);
  51 + switch($context)
  52 + {
  53 + case ExprContext::DOCUMENT:
  54 + $this->table = 'document_metadata_version';
  55 + break;
  56 + case ExprContext::FOLDER:
  57 + $this->table = 'folders';
  58 + break;
  59 + }
  60 + }
  61 +
  62 + public function appliesToContext()
  63 + {
  64 + return ExprContext::DOCUMENT | ExprContext::FOLDER;
  65 + }
  66 +
49 public function getInputRequirements() 67 public function getInputRequirements()
50 { 68 {
51 return array('value'=>array('type'=>FieldInputType::TEXT)); 69 return array('value'=>array('type'=>FieldInputType::TEXT));
search2/search/search.inc.php
@@ -42,6 +42,8 @@ require_once(&#39;search/fieldRegistry.inc.php&#39;); @@ -42,6 +42,8 @@ require_once(&#39;search/fieldRegistry.inc.php&#39;);
42 require_once('search/expr.inc.php'); 42 require_once('search/expr.inc.php');
43 require_once(KT_LIB_DIR . '/security/Permission.inc'); 43 require_once(KT_LIB_DIR . '/security/Permission.inc');
44 44
  45 +// TODO: move standalone functions into a class.... what was I thinking?
  46 +
45 function rank_compare($a, $b) 47 function rank_compare($a, $b)
46 { 48 {
47 if ($a->Rank == $b->Rank) 49 if ($a->Rank == $b->Rank)
@@ -66,6 +68,8 @@ function searchfix($str) @@ -66,6 +68,8 @@ function searchfix($str)
66 return str_replace(array("\n","\r"), array('',''), addslashes($str)); 68 return str_replace(array("\n","\r"), array('',''), addslashes($str));
67 } 69 }
68 70
  71 +// TODO: replace manual json construction with json_encode().
  72 +
69 class SearchHelper 73 class SearchHelper
70 { 74 {
71 public static function correctPath($path) 75 public static function correctPath($path)
@@ -366,8 +370,6 @@ class SearchHelper @@ -366,8 +370,6 @@ class SearchHelper
366 dtfl.document_type_id=$documentTypeID 370 dtfl.document_type_id=$documentTypeID
367 ORDER BY 371 ORDER BY
368 df.name"; 372 df.name";
369 -  
370 -  
371 } 373 }
372 else 374 else
373 { 375 {
@@ -566,7 +568,8 @@ function processSearchExpression($query) @@ -566,7 +568,8 @@ function processSearchExpression($query)
566 { 568 {
567 $expr = parseExpression($query); 569 $expr = parseExpression($query);
568 570
569 - $rs = $expr->evaluate(); 571 + $rs = $expr->evaluate(ExprContext::DOCUMENT);
  572 + $rs = $rs['docs'];
570 usort($rs, 'rank_compare'); 573 usort($rs, 'rank_compare');
571 574
572 $results = array(); 575 $results = array();
@@ -629,4 +632,57 @@ function processSearchExpression($query) @@ -629,4 +632,57 @@ function processSearchExpression($query)
629 } 632 }
630 } 633 }
631 634
  635 +function resolveSearchShortcuts($result)
  636 +{
  637 + $oPermission =& KTPermission::getByName('ktcore.permissions.read');
  638 + $permId = $oPermission->getID();
  639 +
  640 + $oUser = User::get($_SESSION['userID']);
  641 + $aPermissionDescriptors = KTPermissionUtil::getPermissionDescriptorsForUser($oUser);
  642 + $sPermissionDescriptors = empty($aPermissionDescriptors)? -1: implode(',', $aPermissionDescriptors);
  643 +
  644 + $documentIds = implode(',',array_keys($result['docs']));
  645 + $linkedDocuments = array();
  646 + if (!empty($documentIds))
  647 + {
  648 + $sql = "SELECT d.id, d.linked_document_id from documents d ";
  649 + $sql .= 'INNER JOIN permission_lookups AS PL ON d.permission_lookup_id = PL.id '. "\n";
  650 + $sql .= 'INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = '.$permId. " \n";
  651 + $sql .= " WHERE d.linked_document_id in ($documentIds) AND PLA.permission_descriptor_id IN ($sPermissionDescriptors)";
  652 +
  653 + $rs = DBUtil::getResultArray($sql);
  654 +
  655 + foreach($rs as $row)
  656 + {
  657 + $id = $row['id'];
  658 + $linked_id = $row['linked_document_id'];
  659 +
  660 + $result['shortdocs'][$id] = new DocumentShortcutResultItem($id, $result['docs'][$linked_id]);
  661 + }
  662 + }
  663 +
  664 + $folderIds = implode(',',array_keys($result['folders']));
  665 + $linkedFolders = array();
  666 +
  667 + if (!empty($folderIds))
  668 + {
  669 +
  670 + $sql = "SELECT f.id, f.linked_folder_id from folders f ";
  671 + $sql .= 'INNER JOIN permission_lookups AS PL ON f.permission_lookup_id = PL.id '. "\n";
  672 + $sql .= 'INNER JOIN permission_lookup_assignments AS PLA ON PL.id = PLA.permission_lookup_id AND PLA.permission_id = '.$permId. " \n";
  673 + $sql .= " WHERE f.linked_folder_id in ($folderIds) AND PLA.permission_descriptor_id IN ($sPermissionDescriptors)";
  674 +
  675 + $rs = DBUtil::getResultArray($sql);
  676 +
  677 + foreach($rs as $row)
  678 + {
  679 + $id = $row['id'];
  680 + $linked_id = $row['linked_folder_id'];
  681 +
  682 + $result['shortfolders'][$id] = new FolderShortcutResultItem($id, $result['folders'][$linked_id]);
  683 + }
  684 + }
  685 + return $result;
  686 +}
  687 +
632 ?> 688 ?>
sql/mysql/install/data.sql
@@ -199,7 +199,7 @@ INSERT INTO `config_settings` VALUES @@ -199,7 +199,7 @@ INSERT INTO `config_settings` VALUES
199 (25, 'session', 'Anonymous Login', 'Defines whether to allow anonymous users to log in automatically. Default is \'False\'. <br>Best practice is not to allow automatic login of anonymous users unless you understand KnowledgeTree\'s security mechanisms, and have sensibly applied the roles \'Everyone\' and \'Authenticated Users\'. ', 'allowAnonymousLogin', 'default', 'false', 'boolean', NULL, 1), 199 (25, 'session', 'Anonymous Login', 'Defines whether to allow anonymous users to log in automatically. Default is \'False\'. <br>Best practice is not to allow automatic login of anonymous users unless you understand KnowledgeTree\'s security mechanisms, and have sensibly applied the roles \'Everyone\' and \'Authenticated Users\'. ', 'allowAnonymousLogin', 'default', 'false', 'boolean', NULL, 1),
200 (26, 'ui', 'Company Logo', 'Specifies the path (relative to the KnowledgeTree directory) to the custom logo for the KnowledgeTree user interface. <br>The logo must be 50px tall, and on a white background.', 'companyLogo', 'default', '${rootUrl}/resources/companylogo.png', 'string', NULL, 1), 200 (26, 'ui', 'Company Logo', 'Specifies the path (relative to the KnowledgeTree directory) to the custom logo for the KnowledgeTree user interface. <br>The logo must be 50px tall, and on a white background.', 'companyLogo', 'default', '${rootUrl}/resources/companylogo.png', 'string', NULL, 1),
201 (27, 'ui', 'Company Logo Width', 'Defines the width, in pixels, of your custom logo.', 'companyLogoWidth', 'default', '313px', 'string', NULL, 1), 201 (27, 'ui', 'Company Logo Width', 'Defines the width, in pixels, of your custom logo.', 'companyLogoWidth', 'default', '313px', 'string', NULL, 1),
202 -(28, 'ui', 'Company Logo Title', 'Alternative text for the title of your custom company logo, for accessibility purposes.', 'companyLogoTitle', 'default', 'ACME Corporation', 'string', NULL, 1), 202 +(28, 'ui', 'Company Logo Title', 'Alternative text for the title of your custom company logo, for accessibility purposes.', 'companyLogoTitle', 'default', 'Add Company Name', 'string', NULL, 1),
203 (29, 'ui', 'Always Show All Results', 'Defines, where \'show all users\' is an available action, whether to display the full list of users and groups on page load, without requiring the user to click \'show all users\'. Default is \'False\'.', 'alwaysShowAll', 'default', 'false', 'boolean', NULL, 1), 203 (29, 'ui', 'Always Show All Results', 'Defines, where \'show all users\' is an available action, whether to display the full list of users and groups on page load, without requiring the user to click \'show all users\'. Default is \'False\'.', 'alwaysShowAll', 'default', 'false', 'boolean', NULL, 1),
204 (30, 'ui', 'Condensed Admin UI', 'Defines whether to use a condensed (compact) version of the KnowledgeTree user interface for the admin user. Default is \'False\'.', 'condensedAdminUI', 'default', 'false', 'boolean', NULL, 1), 204 (30, 'ui', 'Condensed Admin UI', 'Defines whether to use a condensed (compact) version of the KnowledgeTree user interface for the admin user. Default is \'False\'.', 'condensedAdminUI', 'default', 'false', 'boolean', NULL, 1),
205 (31, 'ui', 'Fake Mimetype', 'Defines whether browsers may provide the option to \'open\' a document from download. Default is \'False\'.<br>Change to \'True\' to prevent (most) browsers from giving users the \'Open\' option.', 'fakeMimetype', 'default', 'false', 'boolean', NULL, 1), 205 (31, 'ui', 'Fake Mimetype', 'Defines whether browsers may provide the option to \'open\' a document from download. Default is \'False\'.<br>Change to \'True\' to prevent (most) browsers from giving users the \'Open\' option.', 'fakeMimetype', 'default', 'false', 'boolean', NULL, 1),
@@ -270,10 +270,11 @@ INSERT INTO `config_settings` VALUES @@ -270,10 +270,11 @@ INSERT INTO `config_settings` VALUES
270 (96, 'KnowledgeTree', 'Redirect To Browse View: Exceptions', 'Specifies that, when \'Redirect To Browse\' is set to \'True\' all users, except for the users listed in the text field below are redirected to the Browse view on log in. The users listed for this setting are directed to the KnowledgeTree Dashboard. To define exceptions, add user names in the text field as follows, e.g. admin, joebloggs, etc.', 'redirectToBrowseExceptions', '', '', 'string', NULL, 1), 270 (96, 'KnowledgeTree', 'Redirect To Browse View: Exceptions', 'Specifies that, when \'Redirect To Browse\' is set to \'True\' all users, except for the users listed in the text field below are redirected to the Browse view on log in. The users listed for this setting are directed to the KnowledgeTree Dashboard. To define exceptions, add user names in the text field as follows, e.g. admin, joebloggs, etc.', 'redirectToBrowseExceptions', '', '', 'string', NULL, 1),
271 (97, 'session', 'Allow Automatic Sign In', 'Defines whether to automatically create a user account on first login for any user who does not yet exist in the system. Default is \'False\'.', 'allowAutoSignup', 'default', 'false', 'boolean', 'string', 1), 271 (97, 'session', 'Allow Automatic Sign In', 'Defines whether to automatically create a user account on first login for any user who does not yet exist in the system. Default is \'False\'.', 'allowAutoSignup', 'default', 'false', 'boolean', 'string', 1),
272 (98, 'ldapAuthentication', 'Create Groups Automatically', 'Defines whether to allow LDAP groups to be created automatically. Default is \'False\'.', 'autoGroupCreation', 'default', 'false', 'boolean', 'string', 1), 272 (98, 'ldapAuthentication', 'Create Groups Automatically', 'Defines whether to allow LDAP groups to be created automatically. Default is \'False\'.', 'autoGroupCreation', 'default', 'false', 'boolean', 'string', 1),
273 -(99, 'browse', 'Truncate Document and Folder Titles in Browse View', 'Defines the length of the document or folder title displayed in the browse view.', 'titleCharLength', 'default', '40', 'numeric_string', 'string', 1), 273 +(99, 'browse', 'Truncate Document and Folder Titles in Browse View', 'Defines the maximum number of characters to display for a document or folder title in the browse view. The maximum allowable number of characters is 255.', 'titleCharLength', 'default', '40', 'numeric_string', 'string', 1),
274 (100, 'import', 'Disable Bulk Import', 'Disable the bulk import plugin', 'disableBulkImport', 'default', 'false', 'string', NULL, 1), 274 (100, 'import', 'Disable Bulk Import', 'Disable the bulk import plugin', 'disableBulkImport', 'default', 'false', 'string', NULL, 1),
275 (101, 'session', 'Enable version check', 'Compares the system version with the database version to determine if a database upgrade is needed.','dbversioncompare', 'default', 'true', 'boolean', NULL, 0), 275 (101, 'session', 'Enable version check', 'Compares the system version with the database version to determine if a database upgrade is needed.','dbversioncompare', 'default', 'true', 'boolean', NULL, 0),
276 -(102, 'tweaks', 'Update Document Version (Content) on Editing Metadata', 'The document version is equivalent to the document content version. When set to true the document version will be increased when the document metadata is updated.', 'updateContentVersion', 'default', 'false', 'boolean', NULL, 1); 276 +(102, 'tweaks', 'Update Document Version (Content) on Editing Metadata', 'The document version is equivalent to the document content version. When set to true the document version will be increased when the document metadata is updated.', 'updateContentVersion', 'default', 'false', 'boolean', NULL, 1),
  277 +(103, 'tweaks', 'Always Force Original Filename on Checkin', 'When set to true, the checkbox for "Force Original Filename" will be hidden on check-in. This ensures that the filename will always stay the same.', 'disableForceFilenameOption', 'default', 'false', 'boolean', NULL, 1);
277 /*!40000 ALTER TABLE `config_settings` ENABLE KEYS */; 278 /*!40000 ALTER TABLE `config_settings` ENABLE KEYS */;
278 UNLOCK TABLES; 279 UNLOCK TABLES;
279 280
sql/mysql/upgrade/3.5.3/length_config_setting.sql
1 INSERT INTO `config_settings` (group_name, display_name, description, item, value, default_value, type, options, can_edit) VALUES 1 INSERT INTO `config_settings` (group_name, display_name, description, item, value, default_value, type, options, can_edit) VALUES
2 2
3 -('browse', 'Truncate Document and Folder Titles in Browse View', 'Defines the length of the document or folder title displayed in the  
4 -browse view.', 'titleCharLength', 'default', '40', 'numeric_string', NULL, 1), 3 +('browse', 'Truncate Document and Folder Titles in Browse View', 'Defines the maximum number of characters to display for a document or folder title in the browse view. The maximum allowable number of characters is 255.', 'titleCharLength', 'default', '40', 'numeric_string', NULL, 1),
5 4
6 ('import', 'Disable Bulk Import', 'Disable the bulk import plugin', 'disableBulkImport', 'default', 'false', 'string', NULL, 1), 5 ('import', 'Disable Bulk Import', 'Disable the bulk import plugin', 'disableBulkImport', 'default', 'false', 'string', NULL, 1),
7 6
8 -('session', 'Enable version check', 'Compares the system version with the database version to determine if a database upgrade is needed.',  
9 -'dbversioncompare', 'default', 'true', 'boolean', NULL, 0), 7 +('session', 'Enable version check', 'Compares the system version with the database version to determine if a database upgrade is needed.', 'dbversioncompare', 'default', 'true', 'boolean', NULL, 0),
10 8
11 -('tweaks', 'Update Document Version (Content) on Editing Metadata', 'The document version is equivalent to the document content version. When set to  
12 -true the document version will be increased when the document metadata is updated.', 'updateContentVersion', 'default', 'false', 'boolean', NULL, 1);  
13 \ No newline at end of file 9 \ No newline at end of file
  10 +('tweaks', 'Update Document Version (Content) on Editing Metadata', 'The document version is equivalent to the document content version. When set to true the document version will be increased when the document metadata is updated.', 'updateContentVersion', 'default', 'false', 'boolean', NULL, 1),
  11 +
  12 +('tweaks', 'Always Force Original Filename on Checkin', 'When set to true, the checkbox for "Force Original Filename" will be hidden on check-in. This ensures that the filename will always stay the same.', 'disableForceFilenameOption', 'default', 'false', 'boolean', NULL, 1);
  13 +
  14 +UPDATE config_settings SET default_value = 'Add Company Name' WHERE group_name = 'ui' AND item = 'companyLogoTitle';
14 \ No newline at end of file 15 \ No newline at end of file
templates/ktcore/search2/search_results.smarty
@@ -46,7 +46,6 @@ function saveSearch() @@ -46,7 +46,6 @@ function saveSearch()
46 url='{/literal}{$rootUrl}{literal}/search2/ajax/saveExpr.php?txtName='+ escape(txtName.value) + 46 url='{/literal}{$rootUrl}{literal}/search2/ajax/saveExpr.php?txtName='+ escape(txtName.value) +
47 '&txtQuery=' + escape('{/literal}{$txtQuery|escape:'quotes'}{literal}'); 47 '&txtQuery=' + escape('{/literal}{$txtQuery|escape:'quotes'}{literal}');
48 48
49 -  
50 Ext.Ajax.request( 49 Ext.Ajax.request(
51 { 50 {
52 url: url, 51 url: url,
@@ -132,57 +131,82 @@ function onShowAll(showall) @@ -132,57 +131,82 @@ function onShowAll(showall)
132 <table border=0 cellpadding="1" cellspacing="1" width="100%" align=center> 131 <table border=0 cellpadding="1" cellspacing="1" width="100%" align=center>
133 {assign var=cbid value=0} 132 {assign var=cbid value=0}
134 133
135 - {foreach item=document from=$results} 134 + {i18n arg_count=$numResults}Search results found: #count#{/i18n}
  135 + <br/>
  136 + <br/>
  137 +
  138 + {foreach item=hit from=$results}
136 <tr><td> 139 <tr><td>
137 - <input type="checkbox" name="selection_d[]" id="cb{$cbid}" value="{$document->DocumentID}"><nobr>&nbsp;&nbsp;<a href="{$rootUrl}/view.php?fDocumentId={$document->DocumentID}"><B>{$document->Title|truncate:80}</b></a>  
138 - {if $document->Title != $document->Filename} 140 + <input type="checkbox" {if $hit->IsDocument}name="selection_d[]"{else}name="selection_f[]"{/if} id="cb{$cbid}" value="{$hit->Id}"><nobr>
  141 + <span class="contenttype {$hit->MimeIconPath}">
  142 +
  143 + {if $hit->IsDocument}
  144 + &nbsp;&nbsp;<a href="{$rootUrl}/view.php?fDocumentId={$hit->Id}"><B>{$hit->Title|truncate:80}</b></a>
  145 + {if $hit->Title != $hit->Filename}
139 &nbsp;&nbsp; 146 &nbsp;&nbsp;
140 - <font style=" color: green "> - Filename: {$document->Filename|truncate:40}</font> 147 + <font style=" color: green "> - {i18n}Filename:{/i18n} {$hit->Filename|truncate:40}</font>
141 {/if} 148 {/if}
142 - {if $document->IsAvailable} 149 + {if $hit->IsAvailable}
143 &nbsp;&nbsp; 150 &nbsp;&nbsp;
144 - <img src="{$rootUrl}/resources/graphics/download.png" title="Download Document" onclick="document.location='{$rootUrl}/action.php?kt_path_info=ktcore.actions.document.view&fDocumentId={$document->DocumentID}';"></a> 151 + <img src="{$rootUrl}/resources/graphics/download.png" title="Download Document" onclick="document.location='{$rootUrl}/action.php?kt_path_info=ktcore.actions.document.view&fDocumentId={$hit->Id}';"></a>
145 152
146 {/if} 153 {/if}
147 154
148 155
149 - {if !$document->IsAvailable} 156 + {if !$hit->IsAvailable}
150 &nbsp;&nbsp; 157 &nbsp;&nbsp;
151 <font style=" color: red "><B> * {i18n}NOT AVAILABLE{/i18n} * </B></font> 158 <font style=" color: red "><B> * {i18n}NOT AVAILABLE{/i18n} * </B></font>
152 {/if} 159 {/if}
153 160
  161 + {else}
  162 + &nbsp;&nbsp;<a href="{$rootUrl}/browse.php?fFolderId={$hit->RealId}{if $hit->IsProxy}&fShortcutFolder={$hit->Id}{/if}"><B>{$hit->Title|truncate:80}</b></a>
  163 +
  164 + {/if}
  165 +
154 </nobr> 166 </nobr>
155 </td><td align=right> 167 </td><td align=right>
156 - <font style="color: green ">{i18n}Document ID:{/i18n} {$document->DocumentID}</font>  
157 - &nbsp;&nbsp;  
158 - <font style=" color: orange ">{i18n}Version:{/i18n} {$document->Version}</font></td> 168 + {if $hit->IsDocument}
  169 + <font style="color: green ">{i18n}Document ID:{/i18n} {$hit->Id}</font>
  170 + &nbsp;&nbsp;
  171 + <font style=" color: orange ">{i18n}Version:{/i18n} {$hit->Version}</font></td>
  172 + {else}
  173 + <font style="color: green ">{i18n}Folder ID:{/i18n} {$hit->Id}</font>
  174 + {/if}
159 </tr> 175 </tr>
160 - <tr><td colspan=2>{$document->Text}</td></tr>  
161 - <tr><td><font style=" color: green "><a href="{$rootUrl}/browse.php?fFolderId={$document->FolderId}" tag="{$document->FullPath}">{$document->FullPath|truncate:40}</a>/{$document->Title|truncate:40} - {$document->Filesize}</font>  
162 - 176 + <tr><td colspan=2>{$hit->Text}</td></tr>
  177 + <tr><td>
  178 + {if $hit->IsDocument}
  179 + <font style=" color: green "><a href="{$rootUrl}/browse.php?fFolderId={$hit->FolderId}" tag="{$hit->FullPath}">{$hit->FullPath|truncate:40}</a>/{$hit->Title|truncate:40} - {$hit->Filesize}</font>
  180 + {else}
  181 + <font style=" color: green "><a href="{$rootUrl}/browse.php?fFolderId={$hit->FolderId}" tag="{$hit->FullPath}">{$hit->FullPath|truncate:40}</a></font>
  182 + {/if}
163 </td> 183 </td>
164 <td align=right><nobr> 184 <td align=right><nobr>
165 <font style="color: orange "> 185 <font style="color: orange ">
166 - {i18n}Created By:{/i18n} {$document->CreatedBy}  
167 - {i18n}on{/i18n} {$document->DateCreated} 186 + {i18n}Created By:{/i18n} {$hit->CreatedBy}
  187 + {if $hit->IsDocument}
  188 + {i18n}on{/i18n} {$hit->DateCreated}
  189 + {/if}
168 </font> 190 </font>
169 </td> 191 </td>
  192 + {if $hit->IsDocument}
170 <tr><td> 193 <tr><td>
171 {if $workflow != ''} 194 {if $workflow != ''}
172 - <font style="color: orange ">{i18n}Workflow:{/i18n} $document->Workflow}</font> 195 + <font style="color: orange ">{i18n}Workflow:{/i18n} $hit->Workflow}</font>
173 {/if} 196 {/if}
174 </td> 197 </td>
175 <td align=right><nobr> 198 <td align=right><nobr>
176 <font style="color: brown "> 199 <font style="color: brown ">
177 - {if $document->CheckedOutUser != ''}  
178 - <b>{i18n}Checked out by:{/i18n} {$document->CheckedOutUser}  
179 - {i18n}on{/i18n} {$document->DateCheckedOut}</b> 200 + {if $hit->CheckedOutUser != ''}
  201 + <b>{i18n}Checked out by:{/i18n} {$hit->CheckedOutUser}
  202 + {i18n}on{/i18n} {$hit->DateCheckedOut}</b>
180 {else} 203 {else}
181 - {i18n}Modified by:{/i18n} {$document->ModifiedBy}  
182 - {i18n}on{/i18n} {$document->DateModified} 204 + {i18n}Modified by:{/i18n} {$hit->ModifiedBy}
  205 + {i18n}on{/i18n} {$hit->DateModified}
183 {/if} 206 {/if}
184 </font> 207 </font>
185 </td> 208 </td>
  209 + {/if}
186 210
187 <tr><td colspan=2><br></br></td></tr></tr> 211 <tr><td colspan=2><br></br></td></tr></tr>
188 212