Merge branch 'seeddms-5.1.x' into seeddms-6.0.x

This commit is contained in:
Uwe Steinmann 2020-12-13 09:11:40 +01:00
commit c369950458
23 changed files with 839 additions and 260 deletions

View File

@ -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

View File

@ -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 ($defAccess<M_READ) {
// Get the list of all users and groups that are listed in the ACL as
// having read access to the document.
@ -2890,9 +2896,12 @@ class SeedDMS_Core_Document extends SeedDMS_Core_Object { /* {{{ */
// to the document.
$tmpList = $this->getAccessList(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 {

View File

@ -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 {

View File

@ -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() { /* {{{ */

View File

@ -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;
} /* }}} */

View File

@ -11,11 +11,11 @@
<email>uwe@steinmann.cx</email>
<active>yes</active>
</lead>
<date>2020-09-10</date>
<date>2020-12-12</date>
<time>08:55:43</time>
<version>
<release>1.1.15</release>
<api>1.1.15</api>
<release>1.1.16</release>
<api>1.1.16</api>
</version>
<stability>
<release>stable</release>
@ -23,12 +23,7 @@
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
- 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
</notes>
<contents>
<dir baseinstalldir="SeedDMS" name="/">
@ -336,5 +331,26 @@ IndexedDocument() remembers cmd and mimetype
Index users with at least read access on the document
</notes>
</release>
<release>
<date>2020-09-10</date>
<time>08:55:43</time>
<version>
<release>1.1.15</release>
<api>1.1.15</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
- 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()
</notes>
</release>
</changelog>
</package>

View File

@ -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]))

View File

@ -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());
}
} /* }}} */

View File

@ -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
*

View File

@ -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;
/**
*
*/

View File

@ -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) {

View File

@ -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;

View File

@ -11,11 +11,11 @@
<email>uwe@steinmann.cx</email>
<active>yes</active>
</lead>
<date>2020-09-11</date>
<date>2020-12-12</date>
<time>08:57:44</time>
<version>
<release>1.0.14</release>
<api>1.0.14</api>
<release>1.0.15</release>
<api>1.0.15</api>
</version>
<stability>
<release>stable</release>
@ -23,12 +23,7 @@
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
- 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
</notes>
<contents>
<dir baseinstalldir="SeedDMS" name="/">
@ -296,5 +291,26 @@ Index users with at least read access on a document
add user to list of terms
</notes>
</release>
<release>
<date>2020-09-11</date>
<time>08:57:44</time>
<version>
<release>1.0.14</release>
<api>1.0.14</api>
</version>
<stability>
<release>stable</release>
<api>stable</api>
</stability>
<license uri="http://opensource.org/licenses/gpl-license">GPL License</license>
<notes>
- 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()
</notes>
</release>
</changelog>
</package>

View File

@ -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);
}

View File

@ -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');

View File

@ -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);

View File

@ -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());

View File

@ -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 '<i class="fa fa-file"></i> ' + item.substring(1).replace(/</g, '&lt;');
else if(item.charAt(0) == 'F')
return '<i class="fa fa-folder-o"></i> ' + item.substring(1).replace(/</g, '&lt;');
if(item.type.charAt(0) == 'D')
return '<i class="fa fa-file"></i> ' + item.name.replace(/</g, '&lt;');
else if(item.type.charAt(0) == 'F')
return '<i class="fa fa-folder-o"></i> ' + item.name.replace(/</g, '&lt;');
else
return '<i class="fa fa-search"></i> ' + item.substring(1).replace(/</g, '&lt;');
}
return '<i class="fa fa-search"></i> ' + item.name.replace(/</g, '&lt;');
},
/* This only works with a modified version of bootstrap typeahead located
* in boostrap-typeahead.js Search for 'render'
* The line
* this.render = this.options.render || this.render
* was added to bootstrap-typeahead.js
* The following function is a copy of the original render function but
* access item.name instead of item
*/
render : function (items) {
var that = this
items = $(items).map(function (i, item) {
i = $(that.options.item).attr('data-value', item.name)
i.find('a').html(that.highlighter(item))
return i[0]
})
items.first().addClass('active')
this.$menu.html(items)
return this
}
}); /* }}} */
/* Document chooser */

View File

@ -0,0 +1,338 @@
/* =============================================================
* bootstrap-typeahead.js v2.3.2
* http://twitter.github.com/bootstrap/javascript.html#typeahead
* =============================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================ */
/* THIS IS A MODIFIED VERSION FOR SEEDDMS WHICH IS ABLE TO OVERRIDE THE render FUNCTION */
!function($){
"use strict"; // jshint ;_;
/* TYPEAHEAD PUBLIC CLASS DEFINITION
* ================================= */
var Typeahead = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, $.fn.typeahead.defaults, options)
this.matcher = this.options.matcher || this.matcher
this.render = this.options.render || this.render
this.sorter = this.options.sorter || this.sorter
this.highlighter = this.options.highlighter || this.highlighter
this.updater = this.options.updater || this.updater
this.source = this.options.source
this.$menu = $(this.options.menu)
this.shown = false
this.listen()
}
Typeahead.prototype = {
constructor: Typeahead
, select: function () {
var val = this.$menu.find('.active').attr('data-value')
this.$element
.val(this.updater(val))
.change()
return this.hide()
}
, updater: function (item) {
return item
}
, show: function () {
var pos = $.extend({}, this.$element.position(), {
height: this.$element[0].offsetHeight
})
this.$menu
.insertAfter(this.$element)
.css({
top: pos.top + pos.height
, left: pos.left
})
.show()
this.shown = true
return this
}
, hide: function () {
this.$menu.hide()
this.shown = false
return this
}
, lookup: function (event) {
var items
this.query = this.$element.val()
if (!this.query || this.query.length < this.options.minLength) {
return this.shown ? this.hide() : this
}
items = $.isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source
return items ? this.process(items) : this
}
, process: function (items) {
var that = this
items = $.grep(items, function (item) {
return that.matcher(item)
})
items = this.sorter(items)
if (!items.length) {
return this.shown ? this.hide() : this
}
return this.render(items.slice(0, this.options.items)).show()
}
, matcher: function (item) {
return ~item.toLowerCase().indexOf(this.query.toLowerCase())
}
, sorter: function (items) {
var beginswith = []
, caseSensitive = []
, caseInsensitive = []
, item
while (item = items.shift()) {
if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
else if (~item.indexOf(this.query)) caseSensitive.push(item)
else caseInsensitive.push(item)
}
return beginswith.concat(caseSensitive, caseInsensitive)
}
, highlighter: function (item) {
var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&')
return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
return '<strong>' + match + '</strong>'
})
}
, 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: '<ul class="typeahead dropdown-menu"></ul>'
, item: '<li><a href="#"></a></li>'
, 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);

View File

@ -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();

View File

@ -177,6 +177,7 @@ background-image: linear-gradient(to bottom, #882222, #111111);;
}
}
echo '<script src="../styles/'.$this->theme.'/bootstrap/js/bootstrap.min.js"></script>'."\n";
echo '<script src="../styles/'.$this->theme.'/bootstrap/js/bootstrap-typeahead.js"></script>'."\n";
echo '<script src="../views/'.$this->theme.'/vendors/bootstrap-datepicker/js/bootstrap-datepicker.js"></script>'."\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 '<script src="../views/'.$this->theme.'/vendors/bootstrap-datepicker/locales/bootstrap-datepicker.'.$lang.'.min.js"></script>'."\n";

View File

@ -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 "<div class=\"folder\">".$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 " <span id=\"status_F".$folder->getID()."\" class=\"indexme indexstatus\" data-docid=\"F".$folder->getID()."\">".getMLText('index_waiting')."</span>";
} 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 "<span id=\"status_F".$folder->getID()."\" class=\"indexstatus\" data-docid=\"F".$folder->getID()."\">".getMLText('index_document_unchanged')."</span>";
} else {
$this->fulltextservice->Indexer()->delete($hit->id);
echo " <span id=\"status_F".$folder->getID()."\" class=\"indexme indexstatus\" data-docid=\"F".$folder->getID()."\">".getMLText('index_waiting')."</span>";
}
}
echo "</div>";
$documents = $folder->getDocuments();
if($documents) {
$lucenesearch = $this->fulltextservice->Search();
echo "<div class=\"folder\">".$folder->getFolderPathPlain()."</div>";
// echo "<div class=\"folder\">".htmlspecialchars($folder->getFolderPathPlain())."</div>";
foreach($documents as $document) {
echo "<div class=\"document\">".$document->getId().":".htmlspecialchars($document->getName());
/* If the document wasn't indexed before then just add it */
if(!($hit = $lucenesearch->getDocument($document->getId()))) {
echo " <span id=\"status_".$document->getID()."\" class=\"indexme indexstatus\" data-docid=\"".$document->getID()."\">".getMLText('index_waiting')."</span>";
if(($this->numdocs == 0) || !($hit = $lucenesearch->getDocument($document->getId()))) {
echo " <span id=\"status_D".$document->getID()."\" class=\"indexme indexstatus\" data-docid=\"D".$document->getID()."\">".getMLText('index_waiting')."</span>";
} 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 "<span id=\"status_".$document->getID()."\" class=\"indexstatus\" data-docid=\"".$document->getID()."\">".getMLText('index_document_unchanged')."</span>";
echo "<span id=\"status_D".$document->getID()."\" class=\"indexstatus\" data-docid=\"D".$document->getID()."\">".getMLText('index_document_unchanged')."</span>";
} else {
$this->fulltextservice->Indexer()->delete($hit->id);
echo " <span id=\"status_".$document->getID()."\" class=\"indexme indexstatus\" data-docid=\"".$document->getID()."\">".getMLText('index_waiting')."</span>";
echo " <span id=\"status_D".$document->getID()."\" class=\"indexme indexstatus\" data-docid=\"D".$document->getID()."\">".getMLText('index_waiting')."</span>";
}
}
echo "</div>";
@ -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);
}

View File

@ -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);
} /* }}} */