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

This commit is contained in:
Uwe Steinmann 2017-02-24 12:15:27 +01:00
commit be40c980ba
8 changed files with 340 additions and 15 deletions

View File

@ -1,5 +1,5 @@
Extensions in SeedDMS
====================
=====================
Since verson 5.0.0 SeedDMS can be extended by extensions. Extensions
can hook up functions into certain operations, e.g.

85
doc/README.Hooks Normal file
View File

@ -0,0 +1,85 @@
Hooks
======
Attention: the api for hooks isn't stable yet!
Hooks in SeedDMS are user definied methods which are being called by
the application. The SeedDMS Core also has hooks which are being
called from the core itself. They are not subject of this document.
The SeedDMS application distinguishes between
* view hooks and
* controller hooks
view hooks usually return some html output which is send to the browser
and either replaces the default output or adds additional information.
A view hooks which returns false will be considered as not being called
at all.
controller hooks implement additional functions which either replace
existing functions or add new ones. If such a hook returns null then
this is treated as if the hook was not called. If the hook returns
false it will prevent other hooks implementing the same function from
being called. All other return values will not stop other hooks from
being called.
Currently available controller hooks
------------------------------------
AddDocument::preAddDocument
Called before a new document will be added
AddDocument::postAddDocument
Called after a new document has been added
AddDocument::preIndexDocument
Called before a new document will be indexed
UpdateDocument::preUpdateDocument
Called before a new document will be updated
UpdateDocument::postUpdateDocument
Called after a new document has been updated
UpdateDocument::preIndexDocument
Called before an updated document will be indexed
RemoveDocument::preRemoveDocument
Called before a document will be removed
RemoveDocument::removeDocument
Called for removing the document. If the hook returns null the
regular document removal will happen.
RemoveDocument::postRemoveDocument
Called after a document was removed
RemoveFolder::preRemoveFolder
Called before a document will be removed
RemoveFolder::removeFolder
Called for removing the folder. If the hook returns null the
regular folder removal will happen.
RemoveFolder::postRemoveFolder
Called after a document was removed
EditFolder::preEditFolder
EditFolder::EditFolder
EditFolder::postEditFolder
ViewOnline::version
Called when a document is downloaded for online view
Download::version
Called when a document is downloaded for saving on disk
Login::postLogin
Called after user in fully logged in
Logout::postLogout
Called after user is logged out
Currently available view hooks
------------------------------------

42
doc/README.Translation Normal file
View File

@ -0,0 +1,42 @@
Help translating SeedDMS
===========================
SeedDMS has got many translations over the years and it is a major
task to keep them all updated. If you would like to give a helping
hand, then this will be much appreciated. There are various ways
to contribute translations.
1. The demo version of SeedDMS at https://demo.seeddms.org will list
all missing translations in a formular on the bottom of the page
while using the software. You can easily provide a missing translation
by filling out the form and submitting it. The translation will not
instantly be used, but is taken over into the official version of
SeedDMS once in a while. This method does not allow to submit corrected
translations of existing phrases.
2. Fixing translations is only possible by modifying one of the language
files in `lanuages/xx_XX/lang.inc`. These files are php files containing
one large array named `$text`. Any modification will be visible right away
in your SeedDMS installation. If you intend to pass your modifications to
the developers of SeedDMS, than keep your changes seperate from the
original translation. A good way is to put your changes into a new
file, e.g. `lang-local.inc` containing an array named `$text_local` and
merge that array with the original translation array. Just put at the
end of `lanuages/xx_XX/lang.inc` the follwing code:
include('lang-local.inc');
array_merge($text, $text_local);
Also create the file `lang-local.inc` with the content
<?php
$text_local = array(
'xxx' => 'yyy',
);
?>
Once you are ready with your local modifications and you think those are
good enough for the public version of SeedDMS, then please mail them to
info@seeddms.org

View File

@ -336,7 +336,15 @@ for ($file_num=0;$file_num<count($_FILES["userfile"]["tmp_name"]);$file_num++){
$index = $indexconf['Indexer']::open($settings->_luceneDir);
if($index) {
$indexconf['Indexer']::init($settings->_stopWordsFile);
$index->addDocument(new $indexconf['IndexedDocument']($dms, $document, isset($settings->_converters['fulltext']) ? $settings->_converters['fulltext'] : null, !($filesize < $settings->_maxSizeForFullText)));
$idoc = new $indexconf['IndexedDocument']($dms, $document, isset($settings->_converters['fulltext']) ? $settings->_converters['fulltext'] : null, !($filesize < $settings->_maxSizeForFullText));
if(isset($GLOBALS['SEEDDMS_HOOKS']['addDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['addDocument'] as $hookObj) {
if (method_exists($hookObj, 'preIndexDocument')) {
$hookObj->preIndexDocument(null, $document, $idoc);
}
}
}
$index->addDocument($idoc);
}
}

View File

@ -671,8 +671,8 @@ switch($command) {
}
}
if(isset($GLOBALS['SEEDDMS_HOOKS']['postAddDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['postAddDocument'] as $hookObj) {
if(isset($GLOBALS['SEEDDMS_HOOKS']['addDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['addDocument'] as $hookObj) {
if (method_exists($hookObj, 'postAddDocument')) {
$hookObj->postAddDocument($document);
}
@ -682,7 +682,15 @@ switch($command) {
$index = $indexconf['Indexer']::open($settings->_luceneDir);
if($index) {
$indexconf['Indexer']::init($settings->_stopWordsFile);
$index->addDocument(new $indexconf['IndexedDocument']($dms, $document, isset($settings->_converters['fulltext']) ? $settings->_converters['fulltext'] : null, !($filesize < $settings->_maxSizeForFullText)));
$idoc = new $indexconf['IndexedDocument']($dms, $document, isset($settings->_converters['fulltext']) ? $settings->_converters['fulltext'] : null, !($filesize < $settings->_maxSizeForFullText));
if(isset($GLOBALS['SEEDDMS_HOOKS']['addDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['addDocument'] as $hookObj) {
if (method_exists($hookObj, 'preIndexDocument')) {
$hookObj->preIndexDocument($document, $idoc);
}
}
}
$index->addDocument($idoc);
}
}
@ -738,5 +746,38 @@ switch($command) {
}
break; /* }}} */
case 'indexdocument': /* {{{ */
if($user && $user->isAdmin()) {
if($settings->_enableFullSearch) {
$document = $dms->getDocument($_REQUEST['id']);
if($document) {
$index = $indexconf['Indexer']::open($settings->_luceneDir);
if($index) {
$indexconf['Indexer']::init($settings->_stopWordsFile);
$idoc = new $indexconf['IndexedDocument']($dms, $document, isset($settings->_converters['fulltext']) ? $settings->_converters['fulltext'] : null, false);
if(isset($GLOBALS['SEEDDMS_HOOKS']['indexDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['indexDocument'] as $hookObj) {
if (method_exists($hookObj, 'preIndexDocument')) {
$hookObj->preIndexDocument(null, $document, $idoc);
}
}
}
$index->addDocument($idoc);
header('Content-Type: application/json');
echo json_encode(array('success'=>true, 'message'=>getMLText('splash_document_indexed'), 'data'=>$document->getID()));
} else {
header('Content-Type: application/json');
echo json_encode(array('success'=>false, 'message'=>getMLText('error_occured'), 'data'=>$document->getID()));
}
} else {
header('Content-Type: application/json');
echo json_encode(array('success'=>false, 'message'=>getMLText('invalid_doc_id'), 'data'=>''));
}
} else {
header('Content-Type: application/json');
echo json_encode(array('success'=>false, 'message'=>getMLText('error_occured'), 'data'=>''));
}
}
break; /* }}} */
}
?>

View File

@ -237,12 +237,27 @@ if ($_FILES['userfile']['error'] == 0) {
$attributes = array();
}
if(isset($GLOBALS['SEEDDMS_HOOKS']['updateDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['updateDocument'] as $hookObj) {
if (method_exists($hookObj, 'preUpdateDocument')) {
$hookObj->preUpdateDocument(array('name'=>&$name, 'comment'=>&$comment));
}
}
}
$filesize = SeedDMS_Core_File::fileSize($userfiletmp);
$contentResult=$document->addContent($comment, $user, $userfiletmp, basename($userfilename), $fileType, $userfiletype, $reviewers, $approvers, $version=0, $attributes, $workflow);
if (is_bool($contentResult) && !$contentResult) {
UI::exitError(getMLText("document_title", array("documentname" => $document->getName())),getMLText("error_occured"));
}
else {
if(isset($GLOBALS['SEEDDMS_HOOKS']['updateDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['updateDocument'] as $hookObj) {
if (method_exists($hookObj, 'postUpdateDocument')) {
$hookObj->postUpdateDocument($document);
}
}
}
if($settings->_enableFullSearch) {
$index = $indexconf['Indexer']::open($settings->_luceneDir);
if($index) {
@ -251,7 +266,15 @@ if ($_FILES['userfile']['error'] == 0) {
$index->delete($hit->id);
}
$indexconf['Indexer']::init($settings->_stopWordsFile);
$index->addDocument(new $indexconf['IndexedDocument']($dms, $document, isset($settings->_converters['fulltext']) ? $settings->_converters['fulltext'] : null, !($filesize < $settings->_maxSizeForFullText)));
$idoc = new $indexconf['IndexedDocument']($dms, $document, isset($settings->_converters['fulltext']) ? $settings->_converters['fulltext'] : null, !($filesize < $settings->_maxSizeForFullText));
if(isset($GLOBALS['SEEDDMS_HOOKS']['updateDocument'])) {
foreach($GLOBALS['SEEDDMS_HOOKS']['updateDocument'] as $hookObj) {
if (method_exists($hookObj, 'preIndexDocument')) {
$hookObj->preIndexDocument(null, $document, $idoc);
}
}
}
$index->addDocument($idoc);
$index->commit();
}
}

View File

@ -69,6 +69,7 @@ if($view) {
$view->setParam('index', $index);
$view->setParam('indexconf', $indexconf);
$view->setParam('recreate', (isset($_GET['create']) && $_GET['create']==1));
$view->setParam('forceupdate', (isset($_GET['forceupdate']) && $_GET['forceupdate']==1));
$view->setParam('folder', $folder);
$view->setParam('converters', $settings->_converters['fulltext']);
$view->setParam('timeout', $settings->_cmdTimeout);

View File

@ -31,25 +31,121 @@ require_once("class.Bootstrap.php");
*/
class SeedDMS_View_Indexer extends SeedDMS_Bootstrap_Style {
function tree($dms, $index, $indexconf, $folder, $indent='') { /* {{{ */
function js() { /* {{{ */
$dms = $this->params['dms'];
$user = $this->params['user'];
header('Content-Type: application/javascript');
?>
var queue_count = 0; // Number of functions being called
var funcArray = []; // Array of functions waiting
var MAX_REQUESTS = 5; // Max requests
var CALL_WAIT = 100; // 100ms
var docstoindex = 0; // total number of docs to index
function check_queue() {
// Check if count doesn't exceeds or if there aren't any functions to call
console.log('Queue has ' + funcArray.length + '/' + docstoindex + ' items');
console.log('Currently processing ' + queue_count + ' requests (' + $.active + ')');
if(queue_count >= MAX_REQUESTS) {
setTimeout(function() { check_queue() }, CALL_WAIT);
return;
}
if(funcArray.length == 0) {
return;
}
docid = funcArray.pop();
$('#status_'+docid).html('Processsing ...');
$.ajax({url: '../op/op.Ajax.php',
type: 'GET',
dataType: "json",
data: {command: 'indexdocument', id: docid},
beforeSend: function() {
queue_count++; // Add request to the counter
},
error: function(xhr, textstatus) {
noty({
text: textstatus,
type: 'error',
dismissQueue: true,
layout: 'topRight',
theme: 'defaultTheme',
timeout: 1500,
});
},
success: function(data) {
// console.log('success ' + data.data);
if(data.success) {
$('#status_'+data.data).html('done');
} else {
$('#status_'+data.data).html('error');
noty({
text: data.message,
type: (data.success) ? 'success' : 'error',
dismissQueue: true,
layout: 'topRight',
theme: 'defaultTheme',
timeout: 1500,
});
}
},
complete: function(xhr, textstatus) {
queue_count--; // Substract request to the counter
$('.queue-bar').css('width', (queue_count*100/MAX_REQUESTS)+'%');
$('.total-bar').css('width', (100 - (funcArray.length+queue_count)*100/docstoindex)+'%');
$('.total-bar').text(Math.round(100 - (funcArray.length+queue_count)*100/docstoindex)+' %');
if(funcArray.length+queue_count == 0)
$('.total-bar').addClass('bar-success');
}
});
setTimeout(function() { check_queue() }, CALL_WAIT);
}
$(document).ready( function() {
$('.tree-toggle').click(function () {
$(this).parent().children('ul.tree').toggle(200);
});
$('.indexme').each(function(index) {
var element = $(this);
var docid = element.data('docid');
element.html('Pending');
funcArray.push(docid);
});
docstoindex = funcArray.length;
check_queue(); // First call to start polling. It will call itself each 100ms
});
<?php
} /* }}} */
protected function tree($dms, $index, $indexconf, $folder, $indent='') { /* {{{ */
$forceupdate = $this->params['forceupdate'];
set_time_limit(30);
echo $indent."D ".htmlspecialchars($folder->getName())."\n";
// echo $indent."D ".htmlspecialchars($folder->getName())."\n";
echo '<ul class="nav nav-list"><li><label class="tree-toggle nav-header">'.htmlspecialchars($folder->getName()).'</label>'."\n";
$subfolders = $folder->getSubFolders();
foreach($subfolders as $subfolder) {
$this->tree($dms, $index, $indexconf, $subfolder, $indent.' ');
}
$documents = $folder->getDocuments();
if($documents) {
echo '<ul class="nav nav-list">'."\n";
foreach($documents as $document) {
echo $indent." ".$document->getId().":".htmlspecialchars($document->getName())." ";
// echo $indent." ".$document->getId().":".htmlspecialchars($document->getName());
echo "<li class=\"document\">".$document->getId().":".htmlspecialchars($document->getName());
/* If the document wasn't indexed before then just add it */
$lucenesearch = new $indexconf['Search']($index);
if(!($hit = $lucenesearch->getDocument($document->getId()))) {
echo " <span id=\"status_".$document->getID()."\" class=\"indexme indexstatus\" data-docid=\"".$document->getID()."\">Waiting</span>";
/*
try {
$index->addDocument(new $indexconf['IndexedDocument']($dms, $document, $this->converters ? $this->converters : null, false, $this->timeout));
echo "(document added)";
} catch(Exception $e) {
echo $indent."(adding document failed '".$e->getMessage()."')";
}
*/
} else {
/* Check if the attribute created is set or has a value older
* than the lasted content. Documents without such an attribute
@ -62,20 +158,27 @@ class SeedDMS_View_Indexer extends SeedDMS_Bootstrap_Style {
$created = 0;
}
$content = $document->getLatestContent();
if($created >= $content->getDate()) {
echo $indent."(document unchanged)";
if($created >= $content->getDate() && !$forceupdate) {
echo $indent."<span id=\"status_".$document->getID()."\" class=\"indexstatus\" data-docid=\"".$document->getID()."\">document unchanged</span>";
} else {
$index->delete($hit->id);
echo " <span id=\"status_".$document->getID()."\" class=\"indexme indexstatus\" data-docid=\"".$document->getID()."\">Waiting</span>";
/*
try {
$index->addDocument(new $indexconf['IndexedDocument']($dms, $document, $this->converters ? $this->converters : null, false, $this->timeout));
echo $indent."(document updated)";
} catch(Exception $e) {
echo $indent."(updating document failed)";
}
*/
}
}
echo "</li>";
echo "\n";
}
echo "</ul>\n";
}
echo "</li></ul>\n";
} /* }}} */
function show() { /* {{{ */
@ -83,7 +186,7 @@ class SeedDMS_View_Indexer extends SeedDMS_Bootstrap_Style {
$user = $this->params['user'];
$index = $this->params['index'];
$indexconf = $this->params['indexconf'];
$recreate = $this->params['recreate'];
$forceupdate = $this->params['forceupdate'];
$folder = $this->params['folder'];
$this->converters = $this->params['converters'];
$this->timeout = $this->params['timeout'];
@ -93,10 +196,32 @@ class SeedDMS_View_Indexer extends SeedDMS_Bootstrap_Style {
$this->contentStart();
$this->pageNavigation(getMLText("admin_tools"), "admin_tools");
$this->contentHeading(getMLText("update_fulltext_index"));
echo "<pre>";
?>
<style type="text/css">
li {line-height: 20px;}
.nav-header {line-height: 19px; margin-bottom: 0px;}
.nav-list {padding-right: 0px;}
.nav-list>li.document:hover {background-color: #eee;}
.indexstatus {font-weight: bold; float: right;}
.progress {margin-bottom: 2px;}
.bar-legend {text-align: right; font-size: 85%; margin-bottom: 15px;}
</style>
<div style="max-width: 900px;">
<div>
<div class="progress">
<div class="bar total-bar" role="progressbar" style="width: 100%;"></div>
</div>
<div class="bar-legend">Overall progress</div>
</div>
<div>
<div class="progress">
<div class="bar queue-bar" role="progressbar" style="width: 100%;"></div>
</div>
<div class="bar-legend">Indexing tasks in queue</div>
</div>
<?php
$this->tree($dms, $index, $indexconf, $folder);
echo "</pre>";
echo "</div>";
$index->commit();
$index->optimize();