diff --git a/CHANGELOG b/CHANGELOG index 4fad4dd8e..3e98b10e9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -205,6 +205,7 @@ - add filter function to notification service - reindex document after it was edited - show preview images in drop folder menu after mouse over +- add support for indexing folders -------------------------------------------------------------------------------- Changes in version 5.1.20 diff --git a/SeedDMS_Core/Core/inc.ClassDocument.php b/SeedDMS_Core/Core/inc.ClassDocument.php index cd5d172af..cff7ef9a8 100644 --- a/SeedDMS_Core/Core/inc.ClassDocument.php +++ b/SeedDMS_Core/Core/inc.ClassDocument.php @@ -2880,6 +2880,12 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ $groupIDs = ""; $defAccess = $this->getDefaultAccess(); + /* Check if the default access is < read access or >= read access. + * If default access is less than read access, then create a list + * of users and groups with read access. + * If default access is equal or greater then read access, then + * create a list of users and groups without read access. + */ if ($defAccessgetAccessList(M_NONE, O_LTEQ); } + /** @var SeedDMS_Core_GroupAccess $groupAccess */ foreach ($tmpList["groups"] as $groupAccess) { $groupIDs .= (strlen($groupIDs)==0 ? "" : ", ") . $groupAccess->getGroupID(); } + + /** @var SeedDMS_Core_UserAccess $userAccess */ foreach ($tmpList["users"] as $userAccess) { $user = $userAccess->getUser(); if (!$listadmin && $user->isAdmin()) continue; @@ -2924,7 +2933,7 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */ (strlen($userIDs) == 0 ? "" : " OR (`tblUsers`.`id` IN (". $userIDs ."))"). ") ORDER BY `login`"; } - /* If default access is equal or greater then M_READ, $userIDs and + /* If default access is equal or greater than M_READ, $userIDs and * $groupIDs contains a list of user without read access */ else { diff --git a/SeedDMS_Core/Core/inc.ClassFolder.php b/SeedDMS_Core/Core/inc.ClassFolder.php index 37a600cda..769c4387a 100644 --- a/SeedDMS_Core/Core/inc.ClassFolder.php +++ b/SeedDMS_Core/Core/inc.ClassFolder.php @@ -1784,11 +1784,12 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { * administrators and the owner of the folder unless $listadmin resp. * $listowner is set to true. * - * @param bool|int $listadmin if set to true any admin will be listed too - * @param bool|int $listowner if set to true the owner will be listed too + * @param boolean $listadmin if set to true any admin will be listed too + * @param boolean $listowner if set to true the owner will be listed too + * @param boolean $listguest if set to true any guest will be listed too * @return array list of users and groups */ - function getReadAccessList($listadmin=0, $listowner=0) { /* {{{ */ + function getReadAccessList($listadmin=0, $listowner=0, $listguest=0) { /* {{{ */ $db = $this->_dms->getDB(); if (!isset($this->_readAccessList)) { @@ -1823,7 +1824,7 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { $user = $userAccess->getUser(); if (!$listadmin && $user->isAdmin()) continue; if (!$listowner && $user->getID() == $this->_ownerID) continue; - if ($user->isGuest()) continue; + if (!$listguest && $user->isGuest()) continue; $userIDs .= (strlen($userIDs)==0 ? "" : ", ") . $userAccess->getUserID(); } @@ -1850,7 +1851,7 @@ class SeedDMS_Core_Folder extends SeedDMS_Core_Object { (strlen($userIDs) == 0 ? "" : " OR (`tblUsers`.`id` IN (". $userIDs ."))"). ") ORDER BY `login`"; } - /* If default access is equal or greate then read, $userIDs and + /* If default access is equal or greater than M_READ, $userIDs and * $groupIDs contains a list of user without read access */ else { diff --git a/SeedDMS_Lucene/Lucene/IndexedDocument.php b/SeedDMS_Lucene/Lucene/IndexedDocument.php index 03a164d94..91fee036e 100644 --- a/SeedDMS_Lucene/Lucene/IndexedDocument.php +++ b/SeedDMS_Lucene/Lucene/IndexedDocument.php @@ -91,7 +91,7 @@ class SeedDMS_Lucene_IndexedDocument extends Zend_Search_Lucene_Document { * Constructor. Creates our indexable document and adds all * necessary fields to it using the passed in document * @param SeedDMS_Core_DMS $dms - * @param SeedDMS_Core_Document $document + * @param SeedDMS_Core_Document|Folder $document * @param null $convcmd * @param bool $nocontent * @param int $timeout @@ -100,44 +100,8 @@ class SeedDMS_Lucene_IndexedDocument extends Zend_Search_Lucene_Document { $this->errormsg = ''; $this->cmd = ''; $this->mimetype = ''; - $_convcmd = array( - 'application/pdf' => 'pdftotext -enc UTF-8 -nopgbrk %s - |sed -e \'s/ [a-zA-Z0-9.]\{1\} / /g\' -e \'s/[0-9.]//g\'', - 'application/postscript' => 'ps2pdf14 %s - | pdftotext -enc UTF-8 -nopgbrk - - | sed -e \'s/ [a-zA-Z0-9.]\{1\} / /g\' -e \'s/[0-9.]//g\'', - 'application/msword' => 'catdoc %s', - 'application/vnd.ms-excel' => 'ssconvert -T Gnumeric_stf:stf_csv -S %s fd://1', - 'audio/mp3' => "id3 -l -R %s | egrep '(Title|Artist|Album)' | sed 's/^[^:]*: //g'", - 'audio/mpeg' => "id3 -l -R %s | egrep '(Title|Artist|Album)' | sed 's/^[^:]*: //g'", - 'text/plain' => 'cat %s', - ); - if($convcmd) { - $_convcmd = $convcmd; - } - $version = $document->getLatestContent(); - $this->addField(Zend_Search_Lucene_Field::Keyword('document_id', $document->getID())); - if($version) { - $this->addField(Zend_Search_Lucene_Field::Keyword('mimetype', $version->getMimeType())); - $this->addField(Zend_Search_Lucene_Field::Keyword('origfilename', $version->getOriginalFileName(), 'utf-8')); - if(!$nocontent) - $this->addField(Zend_Search_Lucene_Field::UnIndexed('created', $version->getDate())); - if($attributes = $version->getAttributes()) { - foreach($attributes as $attribute) { - $attrdef = $attribute->getAttributeDefinition(); - if($attrdef->getValueSet() != '') - $this->addField(Zend_Search_Lucene_Field::Keyword('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue(), 'utf-8')); - else - $this->addField(Zend_Search_Lucene_Field::Text('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue(), 'utf-8')); - } - } - } $this->addField(Zend_Search_Lucene_Field::Text('title', $document->getName(), 'utf-8')); - if($categories = $document->getCategories()) { - $names = array(); - foreach($categories as $cat) { - $names[] = $cat->getName(); - } - $this->addField(Zend_Search_Lucene_Field::Text('category', implode(' ', $names), 'utf-8')); - } if($acllist = $document->getReadAccessList(1, 1, 1)) { $allu = []; foreach($acllist['users'] as $u) @@ -159,49 +123,79 @@ class SeedDMS_Lucene_IndexedDocument extends Zend_Search_Lucene_Document { $this->addField(Zend_Search_Lucene_Field::Text('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue(), 'utf-8')); } } - $owner = $document->getOwner(); $this->addField(Zend_Search_Lucene_Field::Text('owner', $owner->getLogin(), 'utf-8')); - if($keywords = $document->getKeywords()) { - $this->addField(Zend_Search_Lucene_Field::Text('keywords', $keywords, 'utf-8')); - } if($comment = $document->getComment()) { $this->addField(Zend_Search_Lucene_Field::Text('comment', $comment, 'utf-8')); } - if($version) { - $status = $version->getStatus(); - $this->addField(Zend_Search_Lucene_Field::Keyword('status', $status['status'], 'utf-8')); - } - if($version && !$nocontent) { - $path = $dms->contentDir . $version->getPath(); - if(file_exists($path)) { - $content = ''; - $mimetype = $version->getMimeType(); - $this->mimetype = $mimetype; - $cmd = ''; - $mimeparts = explode('/', $mimetype, 2); - if(isset($_convcmd[$mimetype])) { - $cmd = sprintf($_convcmd[$mimetype], $path); - } elseif(isset($_convcmd[$mimeparts[0].'/*'])) { - $cmd = sprintf($_convcmd[$mimetype], $path); - } elseif(isset($_convcmd['*'])) { - $cmd = sprintf($_convcmd[$mimetype], $path); - } - if($cmd) { - $this->cmd = $cmd; - try { - $content = self::execWithTimeout($cmd, $timeout); - if($content['stdout']) { - $this->addField(Zend_Search_Lucene_Field::UnStored('content', $content['stdout'], 'utf-8')); - } - if($content['stderr']) { - $this->errormsg = $content['stderr']; - } - } catch (Exception $e) { + + if($document->isType('document')) { + $this->addField(Zend_Search_Lucene_Field::Keyword('document_id', 'D'.$document->getID())); + $version = $document->getLatestContent(); + if($version) { + $this->addField(Zend_Search_Lucene_Field::Keyword('mimetype', $version->getMimeType())); + $this->addField(Zend_Search_Lucene_Field::Keyword('origfilename', $version->getOriginalFileName(), 'utf-8')); + if(!$nocontent) + $this->addField(Zend_Search_Lucene_Field::UnIndexed('created', $version->getDate())); + if($attributes = $version->getAttributes()) { + foreach($attributes as $attribute) { + $attrdef = $attribute->getAttributeDefinition(); + if($attrdef->getValueSet() != '') + $this->addField(Zend_Search_Lucene_Field::Keyword('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue(), 'utf-8')); + else + $this->addField(Zend_Search_Lucene_Field::Text('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue(), 'utf-8')); } } } - } + if($categories = $document->getCategories()) { + $names = array(); + foreach($categories as $cat) { + $names[] = $cat->getName(); + } + $this->addField(Zend_Search_Lucene_Field::Text('category', implode(' ', $names), 'utf-8')); + } + + if($keywords = $document->getKeywords()) { + $this->addField(Zend_Search_Lucene_Field::Text('keywords', $keywords, 'utf-8')); + } + if($version) { + $status = $version->getStatus(); + $this->addField(Zend_Search_Lucene_Field::Keyword('status', $status['status'], 'utf-8')); + } + if($version && !$nocontent) { + $path = $dms->contentDir . $version->getPath(); + if(file_exists($path)) { + $content = ''; + $mimetype = $version->getMimeType(); + $this->mimetype = $mimetype; + $cmd = ''; + $mimeparts = explode('/', $mimetype, 2); + if(isset($convcmd[$mimetype])) { + $cmd = sprintf($convcmd[$mimetype], $path); + } elseif(isset($convcmd[$mimeparts[0].'/*'])) { + $cmd = sprintf($convcmd[$mimetype], $path); + } elseif(isset($convcmd['*'])) { + $cmd = sprintf($convcmd[$mimetype], $path); + } + if($cmd) { + $this->cmd = $cmd; + try { + $content = self::execWithTimeout($cmd, $timeout); + if($content['stdout']) { + $this->addField(Zend_Search_Lucene_Field::UnStored('content', $content['stdout'], 'utf-8')); + } + if($content['stderr']) { + $this->errormsg = $content['stderr']; + } + } catch (Exception $e) { + } + } + } + } + } elseif($document->isType('folder')) { + $this->addField(Zend_Search_Lucene_Field::Keyword('document_id', 'F'.$document->getID())); + $this->addField(Zend_Search_Lucene_Field::UnIndexed('created', $document->getDate())); + } } /* }}} */ public function getErrorMsg() { /* {{{ */ diff --git a/SeedDMS_Lucene/Lucene/Search.php b/SeedDMS_Lucene/Lucene/Search.php index 9e6ef4c1b..330ceacc5 100644 --- a/SeedDMS_Lucene/Lucene/Search.php +++ b/SeedDMS_Lucene/Lucene/Search.php @@ -49,7 +49,18 @@ class SeedDMS_Lucene_Search { * @return object instance of SeedDMS_Lucene_Document of false */ function getDocument($id) { /* {{{ */ - $hits = $this->index->find('document_id:'.$id); + $hits = $this->index->find('document_id:D'.$id); + return $hits ? $hits[0] : false; + } /* }}} */ + + /** + * Get folder from index + * + * @param object $index lucene index + * @return object instance of SeedDMS_Lucene_Document of false + */ + function getFolder($id) { /* {{{ */ + $hits = $this->index->find('document_id:F'.$id); return $hits ? $hits[0] : false; } /* }}} */ diff --git a/SeedDMS_Lucene/package.xml b/SeedDMS_Lucene/package.xml index f158845fe..8d80f829e 100644 --- a/SeedDMS_Lucene/package.xml +++ b/SeedDMS_Lucene/package.xml @@ -11,11 +11,11 @@ uwe@steinmann.cx yes - 2020-09-10 + 2020-12-12 - 1.1.15 - 1.1.15 + 1.1.16 + 1.1.16 stable @@ -23,12 +23,7 @@ GPL License -- add searching for document status -- better error handling if opening index fails -- parameters for SeedDMS_Lucene_Search::search() has changed -- SeedDMS_Lucene_Search::search() returns array of hits, count and facets -- pass config array instead of index directory to SeedDMS_Lucene_Indexer::create() - and SeedDMS_Lucene_Indexer::open() +- add indexing of folders @@ -336,5 +331,26 @@ IndexedDocument() remembers cmd and mimetype Index users with at least read access on the document + + 2020-09-10 + + + 1.1.15 + 1.1.15 + + + stable + stable + + GPL License + +- add searching for document status +- better error handling if opening index fails +- parameters for SeedDMS_Lucene_Search::search() has changed +- SeedDMS_Lucene_Search::search() returns array of hits, count and facets +- pass config array instead of index directory to SeedDMS_Lucene_Indexer::create() + and SeedDMS_Lucene_Indexer::open() + + diff --git a/SeedDMS_SQLiteFTS/SQLiteFTS/Document.php b/SeedDMS_SQLiteFTS/SQLiteFTS/Document.php index 7734848e5..956c8076c 100644 --- a/SeedDMS_SQLiteFTS/SQLiteFTS/Document.php +++ b/SeedDMS_SQLiteFTS/SQLiteFTS/Document.php @@ -44,7 +44,8 @@ class SeedDMS_SQLiteFTS_Document { } /* }}} */ public function addField($key, $value) { /* {{{ */ - if($key == 'document_id') { + //if($key == 'document_id') { + if($key == 'docid') { $this->id = $this->fields[$key] = (int) $value; } else { if(isset($this->fields[$key])) diff --git a/SeedDMS_SQLiteFTS/SQLiteFTS/IndexedDocument.php b/SeedDMS_SQLiteFTS/SQLiteFTS/IndexedDocument.php index 64383e3e3..fe567583d 100644 --- a/SeedDMS_SQLiteFTS/SQLiteFTS/IndexedDocument.php +++ b/SeedDMS_SQLiteFTS/SQLiteFTS/IndexedDocument.php @@ -94,62 +94,8 @@ class SeedDMS_SQLiteFTS_IndexedDocument extends SeedDMS_SQLiteFTS_Document { $this->errormsg = ''; $this->cmd = ''; $this->mimetype = ''; - $_convcmd = array( - 'application/pdf' => 'pdftotext -enc UTF-8 -nopgbrk %s - |sed -e \'s/ [a-zA-Z0-9.]\{1\} / /g\' -e \'s/[0-9.]//g\'', - 'application/postscript' => 'ps2pdf14 %s - | pdftotext -enc UTF-8 -nopgbrk - - | sed -e \'s/ [a-zA-Z0-9.]\{1\} / /g\' -e \'s/[0-9.]//g\'', - 'application/msword' => 'catdoc %s', - 'application/vnd.ms-excel' => 'ssconvert -T Gnumeric_stf:stf_csv -S %s fd://1', - 'audio/mp3' => "id3 -l -R %s | egrep '(Title|Artist|Album)' | sed 's/^[^:]*: //g'", - 'audio/mpeg' => "id3 -l -R %s | egrep '(Title|Artist|Album)' | sed 's/^[^:]*: //g'", - 'text/plain' => 'cat %s', - ); - if($convcmd) { - $_convcmd = $convcmd; - } - $version = $document->getLatestContent(); - $this->addField('document_id', $document->getID()); - if($version) { - $this->addField('mimetype', $version->getMimeType()); - $this->addField('origfilename', $version->getOriginalFileName()); - if(!$nocontent) - $this->addField('created', $version->getDate(), 'unindexed'); - if($attributes = $version->getAttributes()) { - foreach($attributes as $attribute) { - $attrdef = $attribute->getAttributeDefinition(); - if($attrdef->getValueSet() != '') - $this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue()); - else - $this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue()); - } - } - } $this->addField('title', $document->getName()); - if($categories = $document->getCategories()) { - $names = array(); - foreach($categories as $cat) { - $names[] = $cat->getName(); - } - $this->addField('category', implode(' ', $names)); - } - if($attributes = $document->getAttributes()) { - foreach($attributes as $attribute) { - $attrdef = $attribute->getAttributeDefinition(); - if($attrdef->getValueSet() != '') - $this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue()); - else - $this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue()); - } - } - - $owner = $document->getOwner(); - $this->addField('owner', $owner->getLogin()); - if($keywords = $document->getKeywords()) { - $this->addField('keywords', $keywords); - } - if($comment = $document->getComment()) { - $this->addField('comment', $comment); - } if($acllist = $document->getReadAccessList(1, 1, 1)) { $allu = []; foreach($acllist['users'] as $u) @@ -162,39 +108,85 @@ class SeedDMS_SQLiteFTS_IndexedDocument extends SeedDMS_SQLiteFTS_Document { $this->addField('groups', implode(' ', $allg)); */ } - if($version) { - $status = $version->getStatus(); - $this->addField('status', $status['status']+10); + if($attributes = $document->getAttributes()) { + foreach($attributes as $attribute) { + $attrdef = $attribute->getAttributeDefinition(); + if($attrdef->getValueSet() != '') + $this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue()); + else + $this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue()); + } } - if($version && !$nocontent) { - $path = $dms->contentDir . $version->getPath(); - if(file_exists($path)) { - $content = ''; - $mimetype = $version->getMimeType(); - $this->mimetype = $mimetype; - $cmd = ''; - $mimeparts = explode('/', $mimetype, 2); - if(isset($_convcmd[$mimetype])) { - $cmd = sprintf($_convcmd[$mimetype], $path); - } elseif(isset($_convcmd[$mimeparts[0].'/*'])) { - $cmd = sprintf($_convcmd[$mimetype], $path); - } elseif(isset($_convcmd['*'])) { - $cmd = sprintf($_convcmd[$mimetype], $path); - } - if($cmd) { - $this->cmd = $cmd; - try { - $content = self::execWithTimeout($cmd, $timeout); - if($content['stdout']) { - $this->addField('content', $content['stdout'], 'unstored'); - } - if($content['stderr']) { - $this->errormsg = $content['stderr']; - } - } catch (Exception $e) { + $owner = $document->getOwner(); + $this->addField('owner', $owner->getLogin()); + if($comment = $document->getComment()) { + $this->addField('comment', $comment); + } + + if($document->isType('document')) { + $this->addField('document_id', 'D'.$document->getID()); + $version = $document->getLatestContent(); + if($version) { + $this->addField('mimetype', $version->getMimeType()); + $this->addField('origfilename', $version->getOriginalFileName()); + if(!$nocontent) + $this->addField('created', $version->getDate(), 'unindexed'); + if($attributes = $version->getAttributes()) { + foreach($attributes as $attribute) { + $attrdef = $attribute->getAttributeDefinition(); + if($attrdef->getValueSet() != '') + $this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue()); + else + $this->addField('attr_'.str_replace(' ', '_', $attrdef->getName()), $attribute->getValue()); } } } + if($categories = $document->getCategories()) { + $names = array(); + foreach($categories as $cat) { + $names[] = $cat->getName(); + } + $this->addField('category', implode(' ', $names)); + } + if($keywords = $document->getKeywords()) { + $this->addField('keywords', $keywords); + } + if($version) { + $status = $version->getStatus(); + $this->addField('status', $status['status']+10); + } + if($version && !$nocontent) { + $path = $dms->contentDir . $version->getPath(); + if(file_exists($path)) { + $content = ''; + $mimetype = $version->getMimeType(); + $this->mimetype = $mimetype; + $cmd = ''; + $mimeparts = explode('/', $mimetype, 2); + if(isset($convcmd[$mimetype])) { + $cmd = sprintf($convcmd[$mimetype], $path); + } elseif(isset($convcmd[$mimeparts[0].'/*'])) { + $cmd = sprintf($convcmd[$mimetype], $path); + } elseif(isset($convcmd['*'])) { + $cmd = sprintf($convcmd[$mimetype], $path); + } + if($cmd) { + $this->cmd = $cmd; + try { + $content = self::execWithTimeout($cmd, $timeout); + if($content['stdout']) { + $this->addField('content', $content['stdout'], 'unstored'); + } + if($content['stderr']) { + $this->errormsg = $content['stderr']; + } + } catch (Exception $e) { + } + } + } + } + } elseif($document->isType('folder')) { + $this->addField('document_id', 'F'.$document->getID()); } } /* }}} */ diff --git a/SeedDMS_SQLiteFTS/SQLiteFTS/Indexer.php b/SeedDMS_SQLiteFTS/SQLiteFTS/Indexer.php index 0682a7819..0f135b208 100644 --- a/SeedDMS_SQLiteFTS/SQLiteFTS/Indexer.php +++ b/SeedDMS_SQLiteFTS/SQLiteFTS/Indexer.php @@ -63,9 +63,9 @@ class SeedDMS_SQLiteFTS_Indexer { */ $version = SQLite3::version(); if($version['versionNumber'] >= 3008000) - $sql = 'CREATE VIRTUAL TABLE docs USING fts4(title, comment, keywords, category, mimetype, origfilename, owner, content, created, users, status, notindexed=created, matchinfo=fts3)'; + $sql = 'CREATE VIRTUAL TABLE docs USING fts4(documentid, title, comment, keywords, category, mimetype, origfilename, owner, content, created, users, status, notindexed=created, matchinfo=fts3)'; else - $sql = 'CREATE VIRTUAL TABLE docs USING fts4(title, comment, keywords, category, mimetype, origfilename, owner, content, created, users, status, matchinfo=fts3)'; + $sql = 'CREATE VIRTUAL TABLE docs USING fts4(documentid, title, comment, keywords, category, mimetype, origfilename, owner, content, created, users, status, matchinfo=fts3)'; $res = $index->_conn->exec($sql); if($res === false) { return null; @@ -96,7 +96,7 @@ class SeedDMS_SQLiteFTS_Indexer { if(!$this->_conn) return false; - $sql = "INSERT INTO docs (docid, title, comment, keywords, category, owner, content, mimetype, origfilename, created, users, status) VALUES(".$doc->getFieldValue('document_id').", ".$this->_conn->quote($doc->getFieldValue('title')).", ".$this->_conn->quote($doc->getFieldValue('comment')).", ".$this->_conn->quote($doc->getFieldValue('keywords')).", ".$this->_conn->quote($doc->getFieldValue('category')).", ".$this->_conn->quote($doc->getFieldValue('owner')).", ".$this->_conn->quote($doc->getFieldValue('content')).", ".$this->_conn->quote($doc->getFieldValue('mimetype')).", ".$this->_conn->quote($doc->getFieldValue('origfilename')).", ".(int)$doc->getFieldValue('created').", ".$this->_conn->quote($doc->getFieldValue('users')).", ".$this->_conn->quote($doc->getFieldValue('status'))/*time()*/.")"; + $sql = "INSERT INTO docs (documentid, title, comment, keywords, category, owner, content, mimetype, origfilename, created, users, status) VALUES (".$this->_conn->quote($doc->getFieldValue('document_id')).", ".$this->_conn->quote($doc->getFieldValue('title')).", ".$this->_conn->quote($doc->getFieldValue('comment')).", ".$this->_conn->quote($doc->getFieldValue('keywords')).", ".$this->_conn->quote($doc->getFieldValue('category')).", ".$this->_conn->quote($doc->getFieldValue('owner')).", ".$this->_conn->quote($doc->getFieldValue('content')).", ".$this->_conn->quote($doc->getFieldValue('mimetype')).", ".$this->_conn->quote($doc->getFieldValue('origfilename')).", ".(int)$doc->getFieldValue('created').", ".$this->_conn->quote($doc->getFieldValue('users')).", ".$this->_conn->quote($doc->getFieldValue('status'))/*time()*/.")"; $res = $this->_conn->exec($sql); if($res === false) { return false; @@ -150,7 +150,7 @@ class SeedDMS_SQLiteFTS_Indexer { $res = $this->_conn->query($sql); $row = $res->fetch(); - $sql = "SELECT docid FROM docs"; + $sql = "SELECT docid, documentid FROM docs"; if($query) $sql .= " WHERE docs MATCH ".$this->_conn->quote($query); $res = $this->_conn->query($sql); @@ -164,6 +164,7 @@ class SeedDMS_SQLiteFTS_Indexer { foreach($res as $rec) { $hit = new SeedDMS_SQLiteFTS_QueryHit($this); $hit->id = $rec['docid']; + $hit->documentid = $rec['documentid']; $hits[] = $hit; } } @@ -196,19 +197,21 @@ class SeedDMS_SQLiteFTS_Indexer { /** * Get a single document from index * - * @param integer $id id of document + * @param integer $id id of index record * @return boolean false in case of an error, otherwise true */ public function getDocument($id) { /* {{{ */ if(!$this->_conn) return false; - $sql = "SELECT title, comment, owner, keywords, category, mimetype, origfilename, created, users, status FROM docs WHERE docid=".(int) $id; + $sql = "SELECT docid, documentid, title, comment, owner, keywords, category, mimetype, origfilename, created, users, status FROM docs WHERE docid=".$id; $res = $this->_conn->query($sql); $doc = false; if($res) { $rec = $res->fetch(PDO::FETCH_ASSOC); $doc = new SeedDMS_SQLiteFTS_Document(); + $doc->addField('docid', $rec['docid']); + $doc->addField('document_id', $rec['documentid']); $doc->addField('title', $rec['title']); $doc->addField('comment', $rec['comment']); $doc->addField('keywords', $rec['keywords']); @@ -223,6 +226,33 @@ class SeedDMS_SQLiteFTS_Indexer { return $doc; } /* }}} */ + /** + * Get a single folder from index + * + * @param integer $id id of folder + * @return boolean false in case of an error, otherwise true + */ + public function getFolder($id) { /* {{{ */ + if(!$this->_conn) + return false; + + $sql = "SELECT docid, documentid, title, comment, owner, keywords, category, mimetype, origfilename, created, users, status FROM docs WHERE documentid='F".$id."'"; + $res = $this->_conn->query($sql); + $doc = false; + if($res) { + $rec = $res->fetch(PDO::FETCH_ASSOC); + $doc = new SeedDMS_SQLiteFTS_Document(); + $doc->addField('docid', $rec['docid']); + $doc->addField('document_id', $rec['documentid']); + $doc->addField('title', $rec['title']); + $doc->addField('comment', $rec['comment']); + $doc->addField('owner', $rec['owner']); + $doc->addField('created', $rec['created']); + $doc->addField('users', $rec['users']); + } + return $doc; + } /* }}} */ + /** * Return list of terms in index * diff --git a/SeedDMS_SQLiteFTS/SQLiteFTS/QueryHit.php b/SeedDMS_SQLiteFTS/SQLiteFTS/QueryHit.php index d87486118..facbd9519 100644 --- a/SeedDMS_SQLiteFTS/SQLiteFTS/QueryHit.php +++ b/SeedDMS_SQLiteFTS/SQLiteFTS/QueryHit.php @@ -37,11 +37,17 @@ class SeedDMS_SQLiteFTS_QueryHit { protected $_document; /** - * @var integer $id id of document + * @var integer $id id of index document * @access public */ public $id; + /** + * @var integer $id id of real document + * @access public + */ + public $documentid; + /** * */ diff --git a/SeedDMS_SQLiteFTS/SQLiteFTS/Search.php b/SeedDMS_SQLiteFTS/SQLiteFTS/Search.php index 6a780e651..8f4fed509 100644 --- a/SeedDMS_SQLiteFTS/SQLiteFTS/Search.php +++ b/SeedDMS_SQLiteFTS/SQLiteFTS/Search.php @@ -43,14 +43,25 @@ class SeedDMS_SQliteFTS_Search { } /* }}} */ /** - * Get hit from index + * Get document from index * - * @param object $index lucene index - * @return object instance of SeedDMS_Lucene_Document of false + * @param int $id real document id + * @return object instance of SeedDMS_SQliteFTS_QueryHit or false */ function getDocument($id) { /* {{{ */ - $hits = $this->index->findById((int) $id); - return $hits ? $hits[0] : false; + $hits = $this->index->find('D'.$id); + return $hits['hits'] ? $hits['hits'][0] : false; + } /* }}} */ + + /** + * Get folder from index + * + * @param int $id real folder id + * @return object instance of SeedDMS_SQliteFTS_QueryHit or false + */ + function getFolder($id) { /* {{{ */ + $hits = $this->index->find('F'.$id); + return $hits['hits'] ? $hits['hits'][0] : false; } /* }}} */ /** @@ -102,7 +113,7 @@ class SeedDMS_SQliteFTS_Search { $result = $this->index->find($querystr, $limit); $recs = array(); foreach($result["hits"] as $hit) { - $recs[] = array('id'=>$hit->id, 'document_id'=>$hit->id); + $recs[] = array('id'=>$hit->id, 'document_id'=>$hit->documentid); } return array('count'=>$result['count'], 'hits'=>$recs, 'facets'=>array()); } catch (Exception $e) { diff --git a/SeedDMS_SQLiteFTS/SQLiteFTS/Term.php b/SeedDMS_SQLiteFTS/SQLiteFTS/Term.php index abfffbf0b..8fa4d398b 100644 --- a/SeedDMS_SQLiteFTS/SQLiteFTS/Term.php +++ b/SeedDMS_SQLiteFTS/SQLiteFTS/Term.php @@ -48,17 +48,18 @@ class SeedDMS_SQLiteFTS_Term { public function __construct($term, $col, $occurrence) { /* {{{ */ $this->text = $term; $fields = array( - 0 => 'title', - 1 => 'comment', - 2 => 'keywords', - 3 => 'category', - 4 => 'mimetype', - 5 => 'origfilename', - 6 => 'owner', - 7 => 'content', - 8 => 'created', - 9 => 'user', - 10 => 'status' + 0 => 'documentid', + 1 => 'title', + 2 => 'comment', + 3 => 'keywords', + 4 => 'category', + 5 => 'mimetype', + 6 => 'origfilename', + 7 => 'owner', + 8 => 'content', + 9 => 'created', + 10 => 'user', + 11 => 'status' ); $this->field = $fields[$col]; $this->_occurrence = $occurrence; diff --git a/SeedDMS_SQLiteFTS/package.xml b/SeedDMS_SQLiteFTS/package.xml index ac53c4121..424c76ecc 100644 --- a/SeedDMS_SQLiteFTS/package.xml +++ b/SeedDMS_SQLiteFTS/package.xml @@ -11,11 +11,11 @@ uwe@steinmann.cx yes - 2020-09-11 + 2020-12-12 - 1.0.14 - 1.0.14 + 1.0.15 + 1.0.15 stable @@ -23,12 +23,7 @@ GPL License -- add searching for document status -- search even if query is empty (will find all documents) -- parameters for SeedDMS_SQLiteFTS_Search::search() has changed -- SeedDMS_Lucene_Search::search() returns array of hits, count and facets -- pass config array instead of index directory to SeedDMS_Lucene_Indexer::create() - and SeedDMS_Lucene_Indexer::open() +- add indexing folders @@ -296,5 +291,26 @@ Index users with at least read access on a document add user to list of terms + + 2020-09-11 + + + 1.0.14 + 1.0.14 + + + stable + stable + + GPL License + +- add searching for document status +- search even if query is empty (will find all documents) +- parameters for SeedDMS_SQLiteFTS_Search::search() has changed +- SeedDMS_Lucene_Search::search() returns array of hits, count and facets +- pass config array instead of index directory to SeedDMS_Lucene_Indexer::create() + and SeedDMS_Lucene_Indexer::open() + + diff --git a/inc/inc.ClassFulltextService.php b/inc/inc.ClassFulltextService.php index f10c7939b..7a8165cbe 100644 --- a/inc/inc.ClassFulltextService.php +++ b/inc/inc.ClassFulltextService.php @@ -66,7 +66,10 @@ class SeedDMS_FulltextService { } public function IndexedDocument($document, $forceupdate=false) { - $nocontent = ($document->getLatestContent()->getFileSize() > $this->maxsize) && !$forceupdate; + if($document->isType('document')) + $nocontent = ($document->getLatestContent()->getFileSize() > $this->maxsize) && !$forceupdate; + else + $nocontent = true; return new $this->services[0]['IndexedDocument']($document->getDMS(), $document, $this->converters, $nocontent, $this->cmdtimeout); } diff --git a/op/op.Ajax.php b/op/op.Ajax.php index 1cb9caa97..5edac3348 100644 --- a/op/op.Ajax.php +++ b/op/op.Ajax.php @@ -990,19 +990,28 @@ switch($command) { break; /* }}} */ case 'indexdocument': /* {{{ */ + case 'indexfolder': /* {{{ */ if($user && $user->isAdmin()) { if($fulltextservice) { - $document = $dms->getDocument($_REQUEST['id']); - if($document) { + if($command == 'indexdocument') { + $hook = 'indexDocument'; + $object = $dms->getDocument($_REQUEST['id']); + $prefix = 'D'; + } else { + $hook = 'indexFolder'; + $object = $dms->getFolder($_REQUEST['id']); + $prefix = 'F'; + } + if($object) { if($index = $fulltextservice->Indexer()) { - $idoc = $fulltextservice->IndexedDocument($document, true); + $idoc = $fulltextservice->IndexedDocument($object, true); $error = $idoc->getErrorMsg(); if(!$error) { $ires = null; - if(isset($GLOBALS['SEEDDMS_HOOKS']['indexDocument'])) { - foreach($GLOBALS['SEEDDMS_HOOKS']['indexDocument'] as $hookObj) { - if (method_exists($hookObj, 'preIndexDocument')) { - $ires = $hookObj->preIndexDocument(null, $document, $idoc); + if(isset($GLOBALS['SEEDDMS_HOOKS'][$hook])) { + foreach($GLOBALS['SEEDDMS_HOOKS'][$hook] as $hookObj) { + if (method_exists($hookObj, 'pre'.ucfirst($hook))) { + $ires = $hookObj->preIndexDocument(null, $object, $idoc); } } } @@ -1010,17 +1019,17 @@ switch($command) { $ires = $index->addDocument($idoc); header('Content-Type: application/json'); if(false === $ires) { - echo json_encode(array('success'=>false, 'message'=>getMLText('error_document_indexed'), 'data'=>$document->getID())); + echo json_encode(array('success'=>false, 'message'=>getMLText('error_document_indexed'), 'data'=>$prefix.$object->getID())); } else { - echo json_encode(array('success'=>true, 'message'=>getMLText('splash_document_indexed'), 'data'=>$document->getID(), 'cmd'=>$idoc->getCmd())); + echo json_encode(array('success'=>true, 'message'=>getMLText('splash_document_indexed'), 'data'=>$prefix.$object->getID(), 'cmd'=>$idoc->getCmd())); } } else { header('Content-Type: application/json'); - echo json_encode(array('success'=>false, 'message'=>$error, 'data'=>$document->getID(), 'mimetype'=>$idoc->getMimeType(), 'cmd'=>$idoc->getCmd())); + echo json_encode(array('success'=>false, 'message'=>$error, 'data'=>$object->getID(), 'mimetype'=>$idoc->getMimeType(), 'cmd'=>$idoc->getCmd())); } } else { header('Content-Type: application/json'); - echo json_encode(array('success'=>false, 'message'=>getMLText('error_occured'), 'data'=>$document->getID())); + echo json_encode(array('success'=>false, 'message'=>getMLText('error_occured'), 'data'=>$prefix.$object->getID())); } } else { header('Content-Type: application/json'); diff --git a/out/out.Search.php b/out/out.Search.php index 2f70f4824..2c3a341fb 100644 --- a/out/out.Search.php +++ b/out/out.Search.php @@ -195,22 +195,31 @@ if(isset($_GET["fullsearch"]) && $_GET["fullsearch"] && $settings->_enableFullSe } else { $entries = array(); $facets = $searchresult['facets']; - $dcount = $searchresult['count']; //0; + $dcount = 0; $fcount = 0; if($searchresult) { foreach($searchresult['hits'] as $hit) { - if($tmp = $dms->getDocument($hit['document_id'])) { - if($tmp->getAccessMode($user) >= M_READ) { - $tmp->verifyLastestContentExpriry(); - $entries[] = $tmp; - // $dcount++; + if($hit['document_id'][0] == 'D') { + if($tmp = $dms->getDocument(substr($hit['document_id'], 1))) { +// if($tmp->getAccessMode($user) >= M_READ) { + $tmp->verifyLastestContentExpriry(); + $entries[] = $tmp; + $dcount++; +// } + } + } elseif($hit['document_id'][0] == 'F') { + if($tmp = $dms->getFolder(substr($hit['document_id'], 1))) { +// if($tmp->getAccessMode($user) >= M_READ) { + $entries[] = $tmp; + $fcount++; +// } } } } } - if($pageNumber != 'all' && $dcount > $limit) { - $totalPages = (int) ($dcount/$limit); - if($dcount%$limit) + if($pageNumber != 'all' && $searchresult['count'] > $limit) { + $totalPages = (int) ($searchresult['count']/$limit); + if($searchresult['count']%$limit) $totalPages++; // if($limit > 0) // $entries = array_slice($entries, ($pageNumber-1)*$limit, $limit); diff --git a/out/out.ViewDocument.php b/out/out.ViewDocument.php index c93d6c4ea..2887e934c 100644 --- a/out/out.ViewDocument.php +++ b/out/out.ViewDocument.php @@ -72,6 +72,7 @@ if ($document->checkForDueRevisionWorkflow($user)){ } if($view) { + $view->setParam('fulltextservice', $fulltextservice); $view->setParam('folder', $folder); $view->setParam('document', $document); $view->setParam('showtree', showtree()); diff --git a/styles/bootstrap/application.js b/styles/bootstrap/application.js index 6c67c11bd..93ab365be 100644 --- a/styles/bootstrap/application.js +++ b/styles/bootstrap/application.js @@ -96,39 +96,85 @@ $(document).ready( function() { } }); /* }}} */ - /* The typeahead functionality useѕ the rest api */ + /* The typeahead functionality useѕ the modified version of + * bootstrap-typeahead, which is able to set the render function. + * This was needed because the search function return json objects + * for each hit and render could only process strings. + * */ $("#searchfield").typeahead({ /* {{{ */ minLength: 3, + items: 100, /* the query will limit the number of hits */ source: function(query, process) { var d = new Date(); var pastYear = d.getFullYear() - 1; d.setFullYear(pastYear); - console.log(d.toISOString().split('T')[0]); +// console.log(d.toISOString().split('T')[0]); - $.get('../restapi/index.php/search', { query: query, limit: 8, mode: 'typeahead' }, function(data) { -// $.get('../out/out.Search.php', { query: query, limit: 8, creationdate: 1, createstart: d.toISOString().split('T')[0], action: 'typeahead' }, function(data) { - process(data); +// $.get('../restapi/index.php/search', { query: query, limit: 8, mode: 'typeahead' }, function(data) { + var data = { + query: query, + limit: 18, +// fullsearch: 1, +// creationdate: 1, +// createstart: d.toISOString().split('T')[0], + action: 'typeahead' + }; + /* Return a list of json objects, each containing + * type: type of object (D=doc, F=folder, S=searchterm) + * name: name of object + */ + $.get('../out/out.Search.php', data, function(data) { + process(data); }); }, /* updater is called when the item in the list is clicked. It is * actually provided to update the input field, but here we use - * it to set the document location. */ + * it to set the document location. The passed value is the string + * set in data-value of the list items. */ updater: function (item) { - document.location = "../out/out.Search.php?query=" + encodeURIComponent(item.substring(1)); + console.log(item); + document.location = "../out/out.Search.php?query=" + encodeURIComponent(item); return item; }, - /* Set a matcher that allows any returned value */ + sorter: function(items) { + return items; + }, + /* matcher will always return true, because the initial search returns + * matches only + */ matcher : function (item) { return true; }, highlighter : function (item) { - if(item.charAt(0) == 'D') - return ' ' + item.substring(1).replace(/ ' + item.substring(1).replace(/ ' + item.name.replace(/ ' + item.name.replace(/ ' + item.substring(1).replace(/ ' + item.name.replace(/' + match + '' + }) + } + + , render: function (items) { + var that = this + + items = $(items).map(function (i, item) { + i = $(that.options.item).attr('data-value', item) + i.find('a').html(that.highlighter(item)) + return i[0] + }) + + items.first().addClass('active') + this.$menu.html(items) + return this + } + + , next: function (event) { + var active = this.$menu.find('.active').removeClass('active') + , next = active.next() + + if (!next.length) { + next = $(this.$menu.find('li')[0]) + } + + next.addClass('active') + } + + , prev: function (event) { + var active = this.$menu.find('.active').removeClass('active') + , prev = active.prev() + + if (!prev.length) { + prev = this.$menu.find('li').last() + } + + prev.addClass('active') + } + + , listen: function () { + this.$element + .on('focus', $.proxy(this.focus, this)) + .on('blur', $.proxy(this.blur, this)) + .on('keypress', $.proxy(this.keypress, this)) + .on('keyup', $.proxy(this.keyup, this)) + + if (this.eventSupported('keydown')) { + this.$element.on('keydown', $.proxy(this.keydown, this)) + } + + this.$menu + .on('click', $.proxy(this.click, this)) + .on('mouseenter', 'li', $.proxy(this.mouseenter, this)) + .on('mouseleave', 'li', $.proxy(this.mouseleave, this)) + } + + , eventSupported: function(eventName) { + var isSupported = eventName in this.$element + if (!isSupported) { + this.$element.setAttribute(eventName, 'return;') + isSupported = typeof this.$element[eventName] === 'function' + } + return isSupported + } + + , move: function (e) { + if (!this.shown) return + + switch(e.keyCode) { + case 9: // tab + case 13: // enter + case 27: // escape + e.preventDefault() + break + + case 38: // up arrow + e.preventDefault() + this.prev() + break + + case 40: // down arrow + e.preventDefault() + this.next() + break + } + + e.stopPropagation() + } + + , keydown: function (e) { + this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]) + this.move(e) + } + + , keypress: function (e) { + if (this.suppressKeyPressRepeat) return + this.move(e) + } + + , keyup: function (e) { + switch(e.keyCode) { + case 40: // down arrow + case 38: // up arrow + case 16: // shift + case 17: // ctrl + case 18: // alt + break + + case 9: // tab + case 13: // enter + if (!this.shown) return + this.select() + break + + case 27: // escape + if (!this.shown) return + this.hide() + break + + default: + this.lookup() + } + + e.stopPropagation() + e.preventDefault() + } + + , focus: function (e) { + this.focused = true + } + + , blur: function (e) { + this.focused = false + if (!this.mousedover && this.shown) this.hide() + } + + , click: function (e) { + e.stopPropagation() + e.preventDefault() + this.select() + this.$element.focus() + } + + , mouseenter: function (e) { + this.mousedover = true + this.$menu.find('.active').removeClass('active') + $(e.currentTarget).addClass('active') + } + + , mouseleave: function (e) { + this.mousedover = false + if (!this.focused && this.shown) this.hide() + } + + } + + + /* TYPEAHEAD PLUGIN DEFINITION + * =========================== */ + + var old = $.fn.typeahead + + $.fn.typeahead = function (option) { + return this.each(function () { + var $this = $(this) + , data = $this.data('typeahead') + , options = typeof option == 'object' && option + if (!data) $this.data('typeahead', (data = new Typeahead(this, options))) + if (typeof option == 'string') data[option]() + }) + } + + $.fn.typeahead.defaults = { + source: [] + , items: 8 + , menu: '' + , item: '
  • ' + , minLength: 1 + } + + $.fn.typeahead.Constructor = Typeahead + + + /* TYPEAHEAD NO CONFLICT + * =================== */ + + $.fn.typeahead.noConflict = function () { + $.fn.typeahead = old + return this + } + + + /* TYPEAHEAD DATA-API + * ================== */ + + $(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) { + var $this = $(this) + if ($this.data('typeahead')) return + $this.typeahead($this.data()) + }) + +}(window.jQuery); + diff --git a/utils/indexer.php b/utils/indexer.php index 156bcb346..47744609a 100644 --- a/utils/indexer.php +++ b/utils/indexer.php @@ -59,19 +59,65 @@ include($myincpath."/inc/inc.Init.php"); include($myincpath."/inc/inc.Extension.php"); include($myincpath."/inc/inc.DBInit.php"); -function tree($dms, $fulltextservice, $folder, $indent='') { /* {{{ */ +function tree($dms, $fulltextservice, $folder, $indent='', $numdocs) { /* {{{ */ global $settings, $themes; - echo $themes->black($indent."D ".$folder->getName()).PHP_EOL; - $subfolders = $folder->getSubFolders(); - foreach($subfolders as $subfolder) { - tree($dms, $fulltextservice, $subfolder, $indent.' '); - } - $documents = $folder->getDocuments(); + $index = $fulltextservice->Indexer(); $lucenesearch = $fulltextservice->Search(); + +// echo $themes->black($indent."D ".$folder->getName()).PHP_EOL; + echo $themes->black($indent."D ".$folder->getId().":".$folder->getName()." "); + if(($numdocs == 0) || !($hit = $lucenesearch->getFolder($folder->getId()))) { + try { + $idoc = $fulltextservice->IndexedDocument($folder, true); + if(isset($GLOBALS['SEEDDMS_HOOKS']['indexFolder'])) { + foreach($GLOBALS['SEEDDMS_HOOKS']['indexFolder'] as $hookObj) { + if (method_exists($hookObj, 'preIndexFolder')) { + $hookObj->preIndexDocument(null, $folder, $idoc); + } + } + } + $index->addDocument($idoc); + echo $themes->green(" (Folder added)").PHP_EOL; + } catch(Exception $e) { + echo $themes->error(" (Timeout)").PHP_EOL; + } + } else { + try { + $created = (int) $hit->getDocument()->getFieldValue('created'); + } catch (Exception $e) { + $created = 0; + } + if($created >= $folder->getDate()) { + echo $themes->italic(" (Folder unchanged)").PHP_EOL; + } else { + $index->delete($hit->id); + try { + $idoc = $fulltextservice->IndexedDocument($folder, true); + if(isset($GLOBALS['SEEDDMS_HOOKS']['indexDocument'])) { + foreach($GLOBALS['SEEDDMS_HOOKS']['indexDocument'] as $hookObj) { + if (method_exists($hookObj, 'preIndexDocument')) { + $hookObj->preIndexDocument(null, $folder, $idoc); + } + } + } + $index->addDocument($idoc); + echo $themes->green(" (Folder updated)").PHP_EOL; + } catch(Exception $e) { + echo $themes->error(" (Timeout)").PHP_EOL; + } + } + } + + $subfolders = $folder->getSubFolders(); + foreach($subfolders as $subfolder) { + tree($dms, $fulltextservice, $subfolder, $indent.' ', $numdocs); + } + + $documents = $folder->getDocuments(); foreach($documents as $document) { echo $themes->black($indent." ".$document->getId().":".$document->getName()." "); - if(!($hit = $lucenesearch->getDocument($document->getId()))) { + if(($numdocs == 0) || !($hit = $lucenesearch->getDocument($document->getId()))) { try { $idoc = $fulltextservice->IndexedDocument($document, true); if(isset($GLOBALS['SEEDDMS_HOOKS']['indexDocument'])) { @@ -124,8 +170,12 @@ if(!$index) { exit(1); } +$numdocs = $fulltextservice->Indexer()->count(); $folder = $dms->getFolder($settings->_rootFolderID); -tree($dms, $fulltextservice, $folder); +/* if numdocs is 0, then there is no need to check if a document/folder is already + * indexed. That speeds up the indexing. + */ +tree($dms, $fulltextservice, $folder,'', $numdocs); $index->commit(); $index->optimize(); diff --git a/views/bootstrap/class.Bootstrap.php b/views/bootstrap/class.Bootstrap.php index 22c03a455..9eeaddf0b 100644 --- a/views/bootstrap/class.Bootstrap.php +++ b/views/bootstrap/class.Bootstrap.php @@ -177,6 +177,7 @@ background-image: linear-gradient(to bottom, #882222, #111111);; } } echo ''."\n"; + echo ''."\n"; echo ''."\n"; foreach(array('de', 'es', 'ar', 'el', 'bg', 'ru', 'hr', 'hu', 'ko', 'pl', 'ro', 'sk', 'tr', 'uk', 'ca', 'nl', 'fi', 'cs', 'it', 'fr', 'sv', 'sl', 'pt-BR', 'zh-CN', 'zh-TW') as $lang) echo ''."\n"; diff --git a/views/bootstrap/class.Indexer.php b/views/bootstrap/class.Indexer.php index 92de6595b..07a6396dd 100644 --- a/views/bootstrap/class.Indexer.php +++ b/views/bootstrap/class.Indexer.php @@ -32,18 +32,43 @@ class SeedDMS_View_Indexer_Process_Folder { /* {{{ */ public function __construct($fulltextservice, $forceupdate) { /* {{{ */ $this->fulltextservice = $fulltextservice; $this->forceupdate = $forceupdate; + $this->numdocs = $this->fulltextservice->Indexer()->count(); } /* }}} */ public function process($folder) { /* {{{ */ + $lucenesearch = $this->fulltextservice->Search(); + echo "
    ".$folder->getId().":".htmlspecialchars($folder->getFolderPathPlain()); + /* If the document wasn't indexed before then just add it */ + if(($this->numdocs == 0) || !($hit = $lucenesearch->getFolder($folder->getId()))) { + echo " getID()."\" class=\"indexme indexstatus\" data-docid=\"F".$folder->getID()."\">".getMLText('index_waiting').""; + } else { + /* Check if the attribute created is set or has a value older + * than the lastet content. Documents without such an attribute + * where added when a new document was added to the dms. In such + * a case the document content wasn't indexed. + */ + try { + $created = (int) $hit->getDocument()->getFieldValue('created'); + } catch (/* Zend_Search_Lucene_ */Exception $e) { + $created = 0; + } + if($created >= $folder->getDate() && !$this->forceupdate) { + echo "getID()."\" class=\"indexstatus\" data-docid=\"F".$folder->getID()."\">".getMLText('index_document_unchanged').""; + } else { + $this->fulltextservice->Indexer()->delete($hit->id); + echo " getID()."\" class=\"indexme indexstatus\" data-docid=\"F".$folder->getID()."\">".getMLText('index_waiting').""; + } + } + echo "
    "; + $documents = $folder->getDocuments(); if($documents) { - $lucenesearch = $this->fulltextservice->Search(); - echo "
    ".$folder->getFolderPathPlain()."
    "; +// echo "
    ".htmlspecialchars($folder->getFolderPathPlain())."
    "; foreach($documents as $document) { echo "
    ".$document->getId().":".htmlspecialchars($document->getName()); /* If the document wasn't indexed before then just add it */ - if(!($hit = $lucenesearch->getDocument($document->getId()))) { - echo " getID()."\" class=\"indexme indexstatus\" data-docid=\"".$document->getID()."\">".getMLText('index_waiting').""; + if(($this->numdocs == 0) || !($hit = $lucenesearch->getDocument($document->getId()))) { + echo " getID()."\" class=\"indexme indexstatus\" data-docid=\"D".$document->getID()."\">".getMLText('index_waiting').""; } else { /* Check if the attribute created is set or has a value older * than the lastet content. Documents without such an attribute @@ -57,10 +82,10 @@ class SeedDMS_View_Indexer_Process_Folder { /* {{{ */ } $content = $document->getLatestContent(); if($created >= $content->getDate() && !$this->forceupdate) { - echo "getID()."\" class=\"indexstatus\" data-docid=\"".$document->getID()."\">".getMLText('index_document_unchanged').""; + echo "getID()."\" class=\"indexstatus\" data-docid=\"D".$document->getID()."\">".getMLText('index_document_unchanged').""; } else { $this->fulltextservice->Indexer()->delete($hit->id); - echo " getID()."\" class=\"indexme indexstatus\" data-docid=\"".$document->getID()."\">".getMLText('index_waiting').""; + echo " getID()."\" class=\"indexme indexstatus\" data-docid=\"D".$document->getID()."\">".getMLText('index_waiting').""; } } echo "
    "; @@ -105,12 +130,18 @@ function check_queue() { if(funcArray.length == 0) { return; } + var command = ''; docid = funcArray.pop(); $('#status_'+docid).html('Processsing ...'); + if(docid[0] == 'F') { + command = 'indexfolder'; + } else { + command = 'indexdocument'; + } $.ajax({url: '../op/op.Ajax.php', type: 'GET', dataType: "json", - data: {command: 'indexdocument', id: docid}, + data: {command: command, id: docid.substring(1)}, beforeSend: function() { queue_count++; // Add request to the counter $('.queue-bar').css('width', (queue_count*100/MAX_REQUESTS)+'%'); @@ -153,7 +184,7 @@ function check_queue() { if(funcArray.length+queue_count == 0) $('.total-bar').addClass('bar-success'); } - }); + }); setTimeout(function() { check_queue() }, CALL_WAIT); } diff --git a/views/bootstrap/class.Search.php b/views/bootstrap/class.Search.php index 1ab46a3e2..b71b6ece5 100644 --- a/views/bootstrap/class.Search.php +++ b/views/bootstrap/class.Search.php @@ -121,13 +121,15 @@ $(document).ready( function() { if($entries) { foreach ($entries as $entry) { if($entry->isType('document')) { - $recs[] = 'D'.$entry->getName(); +// $recs[] = 'D'.$entry->getName(); + $recs[] = array('type'=>'D', 'name'=>$entry->getName()); } elseif($entry->isType('folder')) { - $recs[] = 'F'.$entry->getName(); +// $recs[] = 'F'.$entry->getName(); + $recs[] = array('type'=>'F', 'name'=>$entry->getName()); } } } - array_unshift($recs, ' '.$query); + array_unshift($recs, array('type'=>'S', 'name'=>$query)); header('Content-Type: application/json'); echo json_encode($recs); } /* }}} */