diff --git a/.htaccess b/.htaccess index 69e29975e..d9ef34429 100644 --- a/.htaccess +++ b/.htaccess @@ -32,7 +32,7 @@ RewriteRule ^ext/[^/]+/icon.(?:png|svg)$ - [L] RewriteCond %{REQUEST_URI} "ext/[^/]+/" RewriteRule !^ext/[^/]+/.*(?:op|out|res|node_modules) - [F] RewriteCond %{REQUEST_URI} "ext/[^/]+/res/.*$" [NC] -RewriteRule !^ext/[^/]+/res/.*\.(?:css|js|png|gif|svg|ico|html|woff) - [F] +RewriteRule !^ext/[^/]+/res/.*\.(?:css|js|png|gif|svg|ico|html|woff|ttf) - [F] RewriteCond %{REQUEST_FILENAME} -f RewriteRule ^ext/.*$ - [L] diff --git a/CHANGELOG b/CHANGELOG index 8b88600d4..f6c256ee3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -12,6 +12,7 @@ -------------------------------------------------------------------------------- - merge changes up to 5.1.33 - add task to import files from drop folder +- add substitution of users in bootstrap4 theme -------------------------------------------------------------------------------- Changes in version 6.0.25 @@ -291,6 +292,17 @@ - show fileѕ and folders in dropfolder dir recursively - fix 'Add to clipboard' menu item in bootstrap theme - open confirm box when changing category in batch operation +- hidden users can excluded when setting list of reviewers/approvers +- extension can add a legacy access right +- check if document version may be removed +- set max file size for indexing when updating a document +- nicer output on info page +- do not show filter for categories in database search if they don't exist +- show logs of finished worflows +- show preview of documents on clipboard +- minor improvements in restapi +- update layout of tab for attachments +- remove session when calling logout of restapi -------------------------------------------------------------------------------- Changes in version 5.1.32 diff --git a/build.xml b/build.xml index 4d4be7f17..af197c585 100644 --- a/build.xml +++ b/build.xml @@ -16,7 +16,7 @@ - + diff --git a/doc/README.Converters b/doc/README.Converters index e699388f2..6537c19c4 100644 --- a/doc/README.Converters +++ b/doc/README.Converters @@ -74,6 +74,9 @@ message/rfc822 The emailconverter can be obtained from https://github.com/nickrussler/email-to-pdf-converter It requires wkhtmltopdf which is part of debian. +text/plain + iconv -c -f utf-8 -t latin1 '%f' | a2ps -1 -q -a1 -R -B -o - - | ps2pdf - - + Conversion to png for preview images ===================================== @@ -113,10 +116,11 @@ application/postscript convert -density 100 -resize %wx '%f[0]' 'png:%o' text/plain - a2ps -1 -a1 -R -B -o - '%f' | gs -dBATCH -dNOPAUSE -sDEVICE=png16m -dFirstPage=1 -dLastPage=1 -dPDFFitPage -r72x72 -sOutputFile=- -q - | convert -resize %wx png:- 'png:%o' + iconv -c -f utf-8 -t latin1 '%f' | a2ps -1 -q -a1 -R -B -o - - | gs -dBATCH -dNOPAUSE -sDEVICE=png16m -dFirstPage=1 -dLastPage=1 -dPDFFitPage -r72x72 -sOutputFile=- -q - | convert -resize %wx png:- 'png:%o' On Linux systems you will have to set the desired value in /etc/papersize for a2ps - e.g. a4, or letter + e.g. a4, or letter. Unfortunately, a2ps cannot process utf-8 encoded files. That's + why the input needs to be recoded with iconv or recode. application/msword application/vnd.oasis.opendocument.spreadsheet diff --git a/inc/inc.ClassSettings.php b/inc/inc.ClassSettings.php index 33c51016f..55ce331cd 100644 --- a/inc/inc.ClassSettings.php +++ b/inc/inc.ClassSettings.php @@ -423,8 +423,8 @@ class Settings { /* {{{ */ exit; } - if (!is_null($this->_maxExecutionTime)) - ini_set("max_execution_time", $this->_maxExecutionTime); +// if (!is_null($this->_maxExecutionTime)) +// ini_set("max_execution_time", $this->_maxExecutionTime); } /* }}} */ /** diff --git a/languages/en_GB/lang.inc b/languages/en_GB/lang.inc index 68111c058..eecdf07bc 100644 --- a/languages/en_GB/lang.inc +++ b/languages/en_GB/lang.inc @@ -19,7 +19,7 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // -// Translators: Admin (2389), archonwang (3), dgrutsch (9), netixw (14) +// Translators: Admin (2390), archonwang (3), dgrutsch (9), netixw (14) $text = array( '2_factor_auth' => '2-factor authentication', @@ -1367,7 +1367,7 @@ URL: [url]

', 'no_previous_versions' => 'No other versions found', 'no_receipt_needed' => 'There are currently no documents requiring a receipt confirmation.', 'no_review_needed' => 'No review pending.', -'no_revision_date' => 'Ddate of revision missing', +'no_revision_date' => 'Date of revision missing', 'no_revision_needed' => 'No revision pending.', 'no_revision_planed' => 'No revision of document scheduled', 'no_update_cause_locked' => 'You can therefore not update this document. Please contact the locking user.', diff --git a/op/op.RemoveVersion.php b/op/op.RemoveVersion.php index 146b41f2a..175fea92e 100644 --- a/op/op.RemoveVersion.php +++ b/op/op.RemoveVersion.php @@ -44,10 +44,10 @@ if (!is_object($document)) { } /* Create object for checking access to certain operations */ -$accessop = new SeedDMS_AccessOperation($dms, $document, $user, $settings); +$accessop = new SeedDMS_AccessOperation($dms, $user, $settings); // verify if document may be reviewed -if (!$accessop->mayRemoveVersion()){ +if (!$accessop->mayRemoveVersion($document)){ UI::exitError(getMLText("document_title", array("documentname" => $document->getName())),getMLText("access_denied")); } diff --git a/out/out.Clipboard.php b/out/out.Clipboard.php index 4460a3012..3d5147f1b 100644 --- a/out/out.Clipboard.php +++ b/out/out.Clipboard.php @@ -43,7 +43,9 @@ if (isset($_GET["folderid"]) && is_numeric($_GET["folderid"])) { if($view) { $view->setParam('folder', $folder); + $view->setParam('conversionmgr', $conversionmgr); $view->setParam('previewWidthList', $settings->_previewWidthList); + $view->setParam('previewConverters', isset($settings->_converters['preview']) ? $settings->_converters['preview'] : array()); $view->setParam('timeout', $settings->_cmdTimeout); $view->setParam('xsendfile', $settings->_enableXsendfile); $view($_GET); diff --git a/out/out.Search.php b/out/out.Search.php index 6d0b03e46..17d3c379d 100644 --- a/out/out.Search.php +++ b/out/out.Search.php @@ -356,10 +356,12 @@ if($fullsearch) { $totalPages = 0; $entries = array(); $facets = array(); + $stats = array(); $searchTime = 0; } else { $entries = array(); $facets = $searchresult['facets']; + $stats = $searchresult['stats'] ?? null; $dcount = 0; $fcount = 0; if($searchresult['hits']) { @@ -406,6 +408,7 @@ if($fullsearch) { $totalPages = 0; $entries = array(); $facets = array(); + $stats = array(); $searchTime = 0; } } @@ -717,6 +720,7 @@ if($fullsearch) { } else $totalPages = 1; $facets = array(); + $stats = array(); // }}} } @@ -737,6 +741,7 @@ if($settings->_showSingleSearchHit && count($entries) == 1) { $accessop = new SeedDMS_AccessOperation($dms, $user, $settings); if($view) { $view->setParam('facets', $facets); + $view->setParam('stats', $stats); $view->setParam('accessobject', $accessop); $view->setParam('query', $query); $view->setParam('includecontent', $includecontent); diff --git a/restapi/index.php b/restapi/index.php index 977c2fa86..d99ce0f1e 100644 --- a/restapi/index.php +++ b/restapi/index.php @@ -44,13 +44,19 @@ class RestapiController { /* {{{ */ } /* }}} */ protected function __getDocumentData($document) { /* {{{ */ + $cats = $document->getCategories(); + $tmp = []; + foreach($cats as $cat) { + $tmp[] = $this->__getCategoryData($cat); + } $data = array( 'type'=>'document', 'id'=>(int)$document->getId(), 'date'=>date('Y-m-d H:i:s', $document->getDate()), 'name'=>$document->getName(), 'comment'=>$document->getComment(), - 'keywords'=>$document->getKeywords() + 'keywords'=>$document->getKeywords(), + 'categories'=>$tmp ); return $data; } /* }}} */ @@ -252,7 +258,24 @@ class RestapiController { /* {{{ */ $userobj = $this->container->userobj; $settings = $this->container->config; - setcookie("mydms_session", '', time()-3600, $settings->_httpRoot); + if(isset($_COOKIE['mydms_session'])) { + $dms_session = $_COOKIE["mydms_session"]; + $db = $dms->getDb(); + + $session = new SeedDMS_Session($db); + $session->load($dms_session); + + // If setting the user id to 0 worked, it would be a way to logout a + // user. It doesn't work because of a foreign constraint in the database + // won't allow it. So we keep on deleting the session and the cookie on + // logout + // $session->setUser(0); does not work because of foreign user constraint + + if(!$session->delete($dms_session)) { + UI::exitError(getMLText("logout"),$db->getErrorMsg()); + } + setcookie("mydms_session", '', time()-3600, $settings->_httpRoot); + } return $response->withJson(array('success'=>true, 'message'=>'', 'data'=>''), 200); } /* }}} */ @@ -608,6 +631,7 @@ class RestapiController { /* {{{ */ $userobj = $this->container->userobj; $settings = $this->container->config; $notifier = $this->container->notifier; + $fulltextservice = $this->container->fulltextservice; if(!$userobj) { return $response->withJson(array('success'=>false, 'message'=>'Not logged in', 'data'=>''), 403); @@ -693,11 +717,94 @@ class RestapiController { /* {{{ */ return $response->withJson(array('success'=>false, 'message'=>getMLText("document_duplicate_name"), 'data'=>''), 409); } } + // Get the list of reviewers and approvers for this document. + $reviewers = array(); + $approvers = array(); + $reviewers["i"] = array(); + $reviewers["g"] = array(); + $approvers["i"] = array(); + $approvers["g"] = array(); + $workflow = null; + if($settings->_workflowMode == 'traditional' || $settings->_workflowMode == 'traditional_only_approval') { + // add mandatory reviewers/approvers + if($settings->_workflowMode == 'traditional') { + $mreviewers = getMandatoryReviewers($mfolder, $userobj); + if($mreviewers['i']) + $reviewers['i'] = array_merge($reviewers['i'], $mreviewers['i']); + if($mreviewers['g']) + $reviewers['g'] = array_merge($reviewers['g'], $mreviewers['g']); + } + $mapprovers = getMandatoryApprovers($mfolder, $userobj); + if($mapprovers['i']) + $approvers['i'] = array_merge($approvers['i'], $mapprovers['i']); + if($mapprovers['g']) + $approvers['g'] = array_merge($approvers['g'], $mapprovers['g']); + } elseif($settings->_workflowMode == 'advanced') { + if($workflows = $userobj->getMandatoryWorkflows()) { + $workflow = array_shift($workflows); + } + } $temp = $file_info->file; $finfo = finfo_open(FILEINFO_MIME_TYPE); $userfiletype = finfo_file($finfo, $temp); $fileType = ".".pathinfo($origfilename, PATHINFO_EXTENSION); - finfo_close($finfo); + finfo_close($finfo); + $attributes_version = []; + $notusers = []; + $notgroups = []; + $controller = Controller::factory('AddDocument'); + $controller->setParam('documentsource', 'restapi'); + $controller->setParam('documentsourcedetails', null); + $controller->setParam('dms', $dms); + $controller->setParam('user', $userobj); + $controller->setParam('folder', $mfolder); + $controller->setParam('fulltextservice', $fulltextservice); + $controller->setParam('name', $docname); + $controller->setParam('comment', $comment); + $controller->setParam('expires', $expires); + $controller->setParam('keywords', $keywords); + $controller->setParam('categories', $cats); + $controller->setParam('owner', $owner ? $owner : $userobj); + $controller->setParam('userfiletmp', $temp); + $controller->setParam('userfilename', $origfilename ? $origfilename : basename($temp)); + $controller->setParam('filetype', $fileType); + $controller->setParam('userfiletype', $userfiletype); + $controller->setParam('sequence', $sequence); + $controller->setParam('reviewers', $reviewers); + $controller->setParam('approvers', $approvers); + $controller->setParam('reqversion', $reqversion); + $controller->setParam('versioncomment', $version_comment); + $controller->setParam('attributes', $attributes); + $controller->setParam('attributesversion', $attributes_version); + $controller->setParam('workflow', $workflow); + $controller->setParam('notificationgroups', $notgroups); + $controller->setParam('notificationusers', $notusers); + $controller->setParam('maxsizeforfulltext', $settings->_maxSizeForFullText); + $controller->setParam('defaultaccessdocs', $settings->_defaultAccessDocs); + + if(!($document = $controller())) { + $err = $controller->getErrorMsg(); + if(is_string($err)) + $errmsg = getMLText($err); + elseif(is_array($err)) { + $errmsg = getMLText($err[0], $err[1]); + } else { + $errmsg = $err; + } + unlink($temp); + return $response->withJson(array('success'=>false, 'message'=>'Upload failed', 'data'=>''), 500); + } else { + if($controller->hasHook('cleanUpDocument')) { + $controller->callHook('cleanUpDocument', $document, $file); + } + // Send notification to subscribers of folder. + if($notifier) { + $notifier->sendNewDocumentMail($document, $userobj); + } + unlink($temp); + return $response->withJson(array('success'=>true, 'message'=>'Upload succeded', 'data'=>$this->__getLatestVersionData($document->getLatestContent())), 201); + } + /* $res = $mfolder->addDocument($docname, $comment, $expires, $owner ? $owner : $userobj, $keywords, $cats, $temp, $origfilename ? $origfilename : basename($temp), $fileType, $userfiletype, $sequence, array(), array(), $reqversion, $version_comment, $attributes); unlink($temp); if($res) { @@ -708,7 +815,8 @@ class RestapiController { /* {{{ */ return $response->withJson(array('success'=>true, 'message'=>'Upload succeded', 'data'=>$this->__getLatestVersionData($doc->getLatestContent())), 201); } else { return $response->withJson(array('success'=>false, 'message'=>'Upload failed', 'data'=>''), 500); - } + } + */ } else { return $response->withJson(array('success'=>false, 'message'=>'No access', 'data'=>''), 403); } @@ -1471,24 +1579,20 @@ class RestapiController { /* {{{ */ } $document = $dms->getDocument($args['id']); + if(!$document) + return $response->withJson(array('success'=>false, 'message'=>'No such document', 'data'=>''), 404); $category = $dms->getDocumentCategory($args['catid']); + if(!$category) + return $response->withJson(array('success'=>false, 'message'=>'No such category', 'data'=>''), 404); - if($document && $category) { - if ($document->getAccessMode($userobj, 'removeDocumentCategory') >= M_READWRITE) { - $ret = $document->removeCategories(array($category)); - if ($ret) - return $response->withJson(array('success'=>true, 'message'=>'Deleted category successfully.', 'data'=>''), 200); - else - return $response->withJson(array('success'=>true, 'message'=>'', 'data'=>''), 200); - } else { - return $response->withJson(array('success'=>false, 'message'=>'No access', 'data'=>''), 403); - } + if ($document->getAccessMode($userobj, 'removeDocumentCategory') >= M_READWRITE) { + $ret = $document->removeCategories(array($category)); + if ($ret) + return $response->withJson(array('success'=>true, 'message'=>'Deleted category successfully.', 'data'=>''), 200); + else + return $response->withJson(array('success'=>true, 'message'=>'', 'data'=>''), 200); } else { - if(!$document) - return $response->withJson(array('success'=>false, 'message'=>'No such document', 'data'=>''), 404); - if(!$category) - return $response->withJson(array('success'=>false, 'message'=>'No such category', 'data'=>''), 404); - return $response->withJson(array('success'=>false, 'message'=>'', 'data'=>''), 500); + return $response->withJson(array('success'=>false, 'message'=>'No access', 'data'=>''), 403); } } /* }}} */ @@ -1582,7 +1686,7 @@ class RestapiController { /* {{{ */ $doc = $dms->getDocument($args['id']); if($doc && $attrdef) { if($attrdef->getObjType() !== SeedDMS_Core_AttributeDefinition::objtype_document) { - return $response->withJson(array('success'=>false, 'message'=>'Attribute definition not suitable for documents', 'data'=>''), 409); + return $response->withJson(array('success'=>false, 'message'=>'Attribute definition "'.$attrdef->getName().'" not suitable for documents', 'data'=>''), 409); } $params = $request->getParsedBody(); @@ -1639,7 +1743,7 @@ class RestapiController { /* {{{ */ $version = $doc->getContentByVersion($args['version']); if($doc && $attrdef && $version) { if($attrdef->getObjType() !== SeedDMS_Core_AttributeDefinition::objtype_documentcontent) { - return $response->withJson(array('success'=>false, 'message'=>'Attribute definition not suitable for document versions', 'data'=>''), 409); + return $response->withJson(array('success'=>false, 'message'=>'Attribute definition "'.$attrdef->getName().'" not suitable for document versions', 'data'=>''), 409); } $params = $request->getParsedBody(); @@ -1693,7 +1797,7 @@ class RestapiController { /* {{{ */ $obj = $dms->getFolder($args['id']); if($obj && $attrdef) { if($attrdef->getObjType() !== SeedDMS_Core_AttributeDefinition::objtype_folder) { - return $response->withJson(array('success'=>false, 'message'=>'Attribute definition not suitable for folders', 'data'=>''), 409); + return $response->withJson(array('success'=>false, 'message'=>'Attribute definition "'.$attrdef->getName().'" not suitable for folders', 'data'=>''), 409); } $params = $request->getParsedBody(); @@ -2101,7 +2205,7 @@ class RestapiController { /* {{{ */ return $check; $params = $request->getParsedBody(); if (empty($params['name'])) { - return $response->withJson(array('success'=>false, 'message'=>'Need a category.', 'data'=>''), 400); + return $response->withJson(array('success'=>false, 'message'=>'Need a group name.', 'data'=>''), 400); } $groupName = $params['name']; @@ -2116,6 +2220,25 @@ class RestapiController { /* {{{ */ return $response->withJson(array('success'=>true, 'message'=>'', 'data'=>$this->__getGroupData($newGroup)), 201); } /* }}} */ + function deleteGroup($request, $response, $args) { /* {{{ */ + $dms = $this->container->dms; + $userobj = $this->container->userobj; + + $check = $this->checkIfAdmin($request, $response); + if($check !== true) + return $check; + + if($group = $dms->getGroup($args['id'])) { + if($result = $group->remove($userobj)) { + return $response->withJson(array('success'=>$result, 'message'=>'', 'data'=>''), 200); + } else { + return $response->withJson(array('success'=>$result, 'message'=>'Could not delete group', 'data'=>''), 500); + } + } else { + return $response->withJson(array('success'=>false, 'message'=>'No such group', 'data'=>''), 404); + } + } /* }}} */ + function getGroup($request, $response, $args) { /* {{{ */ $dms = $this->container->dms; $userobj = $this->container->userobj; @@ -2156,7 +2279,7 @@ class RestapiController { /* {{{ */ $params = $request->getParsedBody(); if (empty($params['userid'])) { - return $response->withJson(array('success'=>false, 'message'=>'Missing userid', 'data'=>''), 200); + return $response->withJson(array('success'=>false, 'message'=>'Missing userid', 'data'=>''), 500); } $userId = $params['userid']; if(ctype_digit($userId)) @@ -2199,11 +2322,11 @@ class RestapiController { /* {{{ */ } /* }}} */ function addUserToGroup($request, $response, $args) { /* {{{ */ - return changeGroupMembership($request, $response, $args, 'add'); + return $this->changeGroupMembership($request, $response, $args, 'add'); } /* }}} */ function removeUserFromGroup($request, $response, $args) { /* {{{ */ - return changeGroupMembership($request, $response, $args, 'remove'); + return $this->changeGroupMembership($request, $response, $args, 'remove'); } /* }}} */ function setFolderInheritsAccess($request, $response, $args) { /* {{{ */ @@ -2784,6 +2907,7 @@ $app->put('/users/{id}/disable', \RestapiController::class.':setDisabledUser'); $app->put('/users/{id}/password', \RestapiController::class.':changeUserPassword'); $app->post('/groups', \RestapiController::class.':createGroup'); $app->get('/groups', \RestapiController::class.':getGroups'); +$app->delete('/groups/{id}', \RestapiController::class.':deleteGroup'); $app->get('/groups/{id}', \RestapiController::class.':getGroup'); $app->put('/groups/{id}/addUser', \RestapiController::class.':addUserToGroup'); $app->put('/groups/{id}/removeUser', \RestapiController::class.':removeUserFromGroup'); diff --git a/utils/importfs.php b/utils/importfs.php index 16323a2f5..ede4570d7 100644 --- a/utils/importfs.php +++ b/utils/importfs.php @@ -88,13 +88,13 @@ if(isset($options['basefolder'])) { } /* check if modification time shall be taken over */ -$filemtime = false; +$setfiledate = false; if(isset($options['filemtime'])) { - $filemtime = true; + $setfiledate = true; } -$foldermtime = false; -if(isset($options['foldermtime'])) { - $foldermtime = true; +$setfolderdate = false; +if(isset($options['setfolderdate'])) { + $setfolderdate = true; } if(isset($settings->_extraPath)) @@ -119,16 +119,94 @@ if(isset($options['d'])) { include($myincpath."/inc/inc.Settings.php"); include($myincpath."/inc/inc.Utils.php"); -include($myincpath."/inc/inc.Init.php"); include($myincpath."/inc/inc.Language.php"); +include($myincpath."/inc/inc.Init.php"); include($myincpath."/inc/inc.Extension.php"); include($myincpath."/inc/inc.DBInit.php"); -include($myincpath."/inc/inc.ClassNotificationService.php"); -include($myincpath."/inc/inc.ClassEmailNotify.php"); -include($myincpath."/inc/inc.ClassController.php"); echo $settings->_contentDir.$settings->_contentOffsetDir.PHP_EOL; +function getBaseData($colname, $coldata, $objdata) { /* {{{ */ + $objdata[$colname] = $coldata; + return $objdata; +} /* }}} */ + +function getAttributeData($attrdef, $coldata, $objdata) { /* {{{ */ + $objdata['attributes'][$attrdef->getID()] = $coldata; + return $objdata; +} /* }}} */ + +function getCategoryData($colname, $coldata, $objdata) { /* {{{ */ + global $catids; + $kk = explode(',', $coldata); + $objdata['category'][] = array(); + foreach($kk as $k) { + if(isset($catids[$k])) + $objdata['category'][] = $catids[$k]; + } + return $objdata; +} /* }}} */ + +function getUserData($colname, $coldata, $objdata) { /* {{{ */ + global $userids; + if(isset($userids[$coldata])) + $objdata['owner'] = $userids[$coldata]; + return $objdata; +} /* }}} */ + +$metadata = array(); +if(isset($metadatafile)) { + $csvdelim = ';'; + $csvencl = '"'; + if($fp = fopen($metadatafile, 'r')) { + $colmap = array(); + if($header = fgetcsv($fp, 0, $csvdelim, $csvencl)) { + foreach($header as $i=>$colname) { + $colname = trim($colname); + if(in_array($colname, array('category'))) { + $colmap[$i] = array("getCategoryData", $colname); + } elseif(in_array($colname, array('owner'))) { + $colmap[$i] = array("getUserData", $colname); + } elseif(in_array($colname, array('filename', 'category', 'name', 'comment'))) { + $colmap[$i] = array("getBaseData", $colname); + } elseif(substr($colname, 0, 5) == 'attr:') { + $kk = explode(':', $colname, 2); + if(($attrdef = $dms->getAttributeDefinitionByName($kk[1])) || ($attrdef = $dms->getAttributeDefinition((int) $kk[1]))) { + $colmap[$i] = array("getAttributeData", $attrdef); + } + } + } + } +// echo "
";print_r($colmap);echo "
"; + if(count($colmap) > 1) { + $nameprefix = dirname($dirname).'/'; + $allcats = $dms->getDocumentCategories(); + $catids = array(); + foreach($allcats as $cat) + $catids[$cat->getName()] = $cat; + $allusers = $dms->getAllUsers(); + $userids = array(); + foreach($allusers as $muser) + $userids[$muser->getLogin()] = $muser; + while(!feof($fp)) { + if($data = fgetcsv($fp, 0, $csvdelim, $csvencl)) { + $mi = $nameprefix.$data[$colmap['filename']]; +// $metadata[$mi] = array('category'=>array()); + $md = array(); + $md['attributes'] = array(); + foreach($data as $i=>$coldata) { + if(isset($colmap[$i])) { + $md = call_user_func($colmap[$i][0], $colmap[$i][1], $coldata, $md); + } + } + if(!empty($md['filename'])) + $metadata[$nameprefix.$md['filename']] = $md; + } + } + } + } +} + /* Create a global user object */ if(!($user = $dms->getUserByLogin($userlogin))) { echo "User with login '".$userlogin."' does not exists."; @@ -146,21 +224,22 @@ if ($folder->getAccessMode($user) < M_READWRITE) { exit(1); } -function import_folder($dirname, $folder, $filemtime, $foldermtime) { - global $user, $excludefiles, $fsencoding; +//$dms->setForceLink(true); + +function import_folder($dirname, $folder, $setfiledate, $setfolderdate, $metadata) { /* {{{ */ + global $user, $doccount, $foldercount; $d = dir($dirname); $sequence = 1; while(false !== ($entry = $d->read())) { $path = $dirname.'/'.$entry; - if(!in_array($entry, $excludefiles)) { - $name = iconv($fsencoding, 'utf-8', basename($path)); + if($entry != '.' && $entry != '..' && $entry != '.svn') { if(is_file($path)) { + $name = utf8_basename($path); $filetmp = $path; $reviewers = array(); $approvers = array(); - $comment = ''; $version_comment = ''; $reqversion = 1; $expires = false; @@ -173,43 +252,56 @@ function import_folder($dirname, $folder, $filemtime, $foldermtime) { if (is_bool($lastDotIndex) && !$lastDotIndex) $filetype = "."; else $filetype = substr($name, $lastDotIndex); - echo $mimetype." - ".$filetype." - ".$path.PHP_EOL; - $res = $folder->addDocument($name, $comment, $expires, $user, $keywords, - $categories, $filetmp, $name, - $filetype, $mimetype, $sequence, $reviewers, - $approvers, $reqversion, $version_comment); + $docname = !empty($metadata[$path]['name']) ? $metadata[$path]['name'] : $name; + $comment = !empty($metadata[$path]['comment']) ? $metadata[$path]['comment'] : ''; + $owner = !empty($metadata[$path]['owner']) ? $metadata[$path]['owner'] : $user; - if (is_bool($res) && !$res) { - echo "Could not add document to folder".PHP_EOL; - exit(1); + echo $mimetype." - ".$filetype." - ".$path."
\n"; + if($res = $folder->addDocument($docname, $comment, $expires, $owner, $keywords, + !empty($metadata[$path]['category']) ? $metadata[$path]['category'] : array(), $filetmp, $name, + $filetype, $mimetype, $sequence, $reviewers, + $approvers, $reqversion, $version_comment, + !empty($metadata[$path]['attributes']) ? $metadata[$path]['attributes'] : array())) { + $doccount++; + if($setfiledate) { + $newdoc = $res[0]; + $newdoc->setDate(filemtime($path)); + $lc = $newdoc->getLatestContent(); + $lc->setDate(filemtime($path)); + } + } else { + echo "Error importing ".$path."
"; + echo "
".print_r($res, true)."
"; +// return false; } - if($filemtime) { - $newdoc = $res[0]; - $newdoc->setDate(filemtime($path)); - $lc = $newdoc->getLatestContent(); - $lc->setDate(filemtime($path)); - } - set_time_limit(1200); + set_time_limit(30); } elseif(is_dir($path)) { - $newfolder = $folder->addSubFolder($name, '', $user, $sequence); - if($foldermtime) { - $newfolder->setDate(filemtime($path)); + $name = utf8_basename($path); + if($newfolder = $folder->addSubFolder($name, '', $user, $sequence)) { + $foldercount++; + if($setfolderdate) { + $newfolder->setDate(filemtime($path)); + } + if(!import_folder($path, $newfolder, $setfiledate, $setfolderdate, $metadata)) + return false; + } else { +// return false; } - import_folder($path, $newfolder, $filemtime, $foldermtime); } $sequence++; } } -} + return true; +} /* }}} */ if($createbasefolder) { if($newfolder = $folder->addSubFolder(basename($dirname), '', $user, 1)) { - if($foldermtime) { + if($setfolderdate) { $newfolder->setDate(filemtime($dirname)); } - import_folder($dirname, $newfolder, $filemtime, $foldermtime); + import_folder($dirname, $newfolder, $setfiledate, $setfolderdate, $metadata); } } else { - import_folder($dirname, $folder, $filemtime, $foldermtime); + import_folder($dirname, $folder, $setfiledate, $setfolderdate, $metadata); } diff --git a/views/bootstrap/class.AddDocument.php b/views/bootstrap/class.AddDocument.php index be12b4e08..67a56ed35 100644 --- a/views/bootstrap/class.AddDocument.php +++ b/views/bootstrap/class.AddDocument.php @@ -150,6 +150,7 @@ console.log(params); function show() { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; + $settings = $this->params['settings']; $folder = $this->params['folder']; $enablelargefileupload = $this->params['enablelargefileupload']; $enablemultiupload = $this->params['enablemultiupload']; @@ -511,7 +512,8 @@ console.log(params); ) ); } - $this->warningMsg(getMLText("add_doc_workflow_warning")); + if($settings->_initialDocumentStatus == S_RELEASED) + $this->warningMsg(getMLText("add_doc_workflow_warning")); } elseif($workflowmode == 'traditional' || $workflowmode == 'traditional_only_approval') { $this->contentContainerEnd(); if($workflowmode == 'traditional') { diff --git a/views/bootstrap/class.Bootstrap.php b/views/bootstrap/class.Bootstrap.php index 5b9cf8d67..d4e61f8bd 100644 --- a/views/bootstrap/class.Bootstrap.php +++ b/views/bootstrap/class.Bootstrap.php @@ -3313,7 +3313,7 @@ $('body').on('click', '[id^=\"table-row-folder\"] td:nth-child(2)', function(ev) if(!$skipcont) $content .= $this->documentListRowStart($document); - $previewer->createPreview($latestContent); + if($previewer) $previewer->createPreview($latestContent); $version = $latestContent->getVersion(); if($ec = $this->callHook('documentListRowExtraContent', $document, $latestContent)) @@ -3327,7 +3327,7 @@ $('body').on('click', '[id^=\"table-row-folder\"] td:nth-child(2)', function(ev) else { if($accessop->check_controller_access('Download', array('action'=>'version'))) $content .= "params['settings']->_httpRoot."op/op.Download.php?documentid=".$docID."&version=".$version."\">"; - if($previewer->hasPreview($latestContent)) { + if($previewer && $previewer->hasPreview($latestContent)) { $content .= "params['settings']->_httpRoot."op/op.Preview.php?documentid=".$document->getID()."&version=".$latestContent->getVersion()."&width=".$previewwidth."\" title=\"".htmlspecialchars($latestContent->getMimeType())."\">"; } else { $content .= "getMimeIcon($latestContent->getFileType())."\" ".($previewwidth ? "width=\"".$previewwidth."\"" : "")."\" title=\"".htmlspecialchars($latestContent->getMimeType())."\">"; @@ -3935,6 +3935,23 @@ $(document).ready(function() { "; + echo "".getMLText('workflow')."".getMLText('date')."".getMLText('action')."".getMLText('user')."".getMLText('comment')."\n"; + echo ""; + foreach($wkflogs as $wkflog) { + echo ""; + echo "".htmlspecialchars($wkflog->getWorkflow()->getName()).""; + echo "".getLongReadableDate($wkflog->getDate()).""; + echo "".htmlspecialchars(getMLText('action_'.strtolower($wkflog->getTransition()->getAction()->getName()), array(), $wkflog->getTransition()->getAction()->getName())).""; + $loguser = $wkflog->getUser(); + echo "".htmlspecialchars($loguser->getFullName()).""; + echo "".htmlspecialchars($wkflog->getComment()).""; + echo ""; + } + print "\n\n"; + } /* }}} */ + /** * Show progressbar * diff --git a/views/bootstrap/class.Clipboard.php b/views/bootstrap/class.Clipboard.php index 0bbc0c7b0..3b75db496 100644 --- a/views/bootstrap/class.Clipboard.php +++ b/views/bootstrap/class.Clipboard.php @@ -159,11 +159,17 @@ class SeedDMS_View_Clipboard extends SeedDMS_Theme_Style { $dms = $this->params['dms']; $clipboard = $this->params['session']->getClipboard(); $cachedir = $this->params['cachedir']; + $conversionmgr = $this->params['conversionmgr']; $previewwidth = $this->params['previewWidthList']; + $previewconverters = $this->params['previewConverters']; $timeout = $this->params['timeout']; $xsendfile = $this->params['xsendfile']; $previewer = new SeedDMS_Preview_Previewer($cachedir, $previewwidth, $timeout, $xsendfile); + if($conversionmgr) + $previewer->setConversionMgr($conversionmgr); + else + $previewer->setConverters($previewconverters); $content = ''; $txt = $this->callHook('preClipboard', $clipboard); if(is_string($txt)) diff --git a/views/bootstrap/class.DocumentVersionDetail.php b/views/bootstrap/class.DocumentVersionDetail.php index a5840e941..d11d0ad94 100644 --- a/views/bootstrap/class.DocumentVersionDetail.php +++ b/views/bootstrap/class.DocumentVersionDetail.php @@ -46,6 +46,41 @@ class SeedDMS_View_DocumentVersionDetail extends SeedDMS_Theme_Style { "; + foreach($items as $item) { + if(is_string($item)) + echo "
  • ".$item."
  • "; + elseif(is_array($item)) { + echo "
  • ".(!empty($item['icon']) ? " " : "").''.getMLText($item['label'])."
  • "; + } + } + print ""; + return; + print ""; + } /* }}} */ + function preview() { /* {{{ */ $dms = $this->params['dms']; $document = $this->params['document']; @@ -139,7 +174,7 @@ class SeedDMS_View_DocumentVersionDetail extends SeedDMS_Theme_Style { $user = $this->params['user']; $folder = $this->params['folder']; $document = $this->params['document']; - $accessop = $this->params['accessobject']; + $accessobject = $this->params['accessobject']; $version = $this->params['version']; $accessop = $this->params['accessobject']; $viewonlinefiletypes = $this->params['viewonlinefiletypes']; @@ -250,18 +285,20 @@ class SeedDMS_View_DocumentVersionDetail extends SeedDMS_Theme_Style { $file_exists=file_exists($dms->contentDir . $version->getPath()); $this->contentHeading(getMLText("details_version", array ("version" => $version->getVersion()))); - $this->contentContainerStart(); - print ""; - print "\n\n"; - print "\n"; +// $this->contentContainerStart(); +// print "
    ".htmlspecialchars($version->getOriginalFileName())."
    "; +// print "\n\n"; +// print "\n"; // print "\n"; - print "\n"; - print "\n"; - print "\n\n\n"; - print "\n"; - print "\n"; +// print "\n"; +// print "\n\n\n"; +// print "\n"; +// print "\n"; +// print "\n"; - print "\n"; - - print ""; + print ""; + print ""; +// print "\n"; - print ""; - //if (($document->getAccessMode($user) >= M_READWRITE)) { +// print ""; - print "\n
    ".htmlspecialchars($version->getOriginalFileName())."".getMLText("comment")."".getMLText("status")."
      "; +// print "
    ".getMLText("status")."
      "; - print "
    "; +// print ""; + $this->rowStart(); + $this->columnStart(3); $previewer = new SeedDMS_Preview_Previewer($cachedir, $previewwidthdetail, $timeout, $xsendfile); if($conversionmgr) $previewer->setConversionMgr($conversionmgr); @@ -283,9 +320,12 @@ class SeedDMS_View_DocumentVersionDetail extends SeedDMS_Theme_Style { if ($file_exists) { print ""; } - print "
      \n"; +// print "
    "; + $this->columnEnd(); + $this->columnStart(5); + print "
      \n"; print "
    • ".getMLText('version').": ".$version->getVersion()."
    • \n"; if ($file_exists) @@ -317,52 +357,51 @@ class SeedDMS_View_DocumentVersionDetail extends SeedDMS_Theme_Style { } } } - print "
    "; - print getOverallStatusText($status["status"]); + print "
  • ".getMLText('status').": ".getOverallStatusText($status["status"]); if ( $status["status"]==S_DRAFT_REV || $status["status"]==S_DRAFT_APP || $status["status"]==S_IN_WORKFLOW || $status["status"]==S_EXPIRED ){ print "
    hasExpired()?" class=\"warning\" ":"").">".(!$document->getExpires() ? getMLText("does_not_expire") : getMLText("expires").": ".getReadableDate($document->getExpires())).""; } - print "
  • "; +// print ""; + $this->columnEnd(); + $this->columnStart(4); +// print ""; + + $items = array(); if ($file_exists){ - print ""; - } - - print ""; - echo "
    \n"; + $items = array(); + if($accessobject->mayRemoveVersion($version->getDocument())) { + $items[] = array('link'=>$this->html_url('RemoveVersion', array('documentid'=>$version->getDocument()->getId(),'version'=>$version->getVersion())), 'icon'=>'remove', 'label'=>'rm_version'); + } - $this->contentContainerEnd(); + if($newitems = $this->callHook('extraVersionActions', $version)) + $items = array_merge($items, $newitems); + if($items) { + $this->showActions($items); + } +// echo ""; +// print "\n\n"; + + $this->columnEnd(); + $this->rowEnd(); +// $this->contentContainerEnd(); $this->rowStart(); $this->columnStart(6); @@ -557,7 +596,7 @@ class SeedDMS_View_DocumentVersionDetail extends SeedDMS_Theme_Style { $this->contentContainerEnd(); } /* }}} */ - if($user->isAdmin() || $user->getId() == $document->getOwner()->getId()) { + if($accessobject->check_view_access($this, array('action'=>'statuslog'))) { $this->contentHeading(getMLText("status")); $this->contentContainerStart(); $statuslog = $version->getStatusLog(); @@ -573,26 +612,19 @@ class SeedDMS_View_DocumentVersionDetail extends SeedDMS_Theme_Style { } print "\n\n"; $this->contentContainerEnd(); + } - $wkflogs = $version->getWorkflowLog(); - if($wkflogs) { - $this->contentHeading(getMLText("workflow_summary")); - $this->contentContainerStart(); - echo ""; - echo "\n"; - echo ""; - foreach($wkflogs as $wkflog) { - echo ""; - echo ""; - echo ""; - $loguser = $wkflog->getUser(); - echo ""; - echo ""; - echo ""; + if($accessobject->check_view_access($this, array('action'=>'finished_workflowlog'))) { + $wkfalllogs = $version->getWorkflowLog(); + if($wkfalllogs) { + $this->contentHeading(getMLText("finished_workflow_log")); + foreach($wkfalllogs as $wkflogs) { + $this->printWorkflowLog($wkflogs); } - print "\n
    ".getMLText('date')."".getMLText('action')."".getMLText('user')."".getMLText('comment')."
    ".$wkflog->getDate()."".$wkflog->getTransition()->getAction()->getName()."".$loguser->getFullName()."".$wkflog->getComment()."
    \n"; - $this->contentContainerEnd(); } + } + + if($user->isAdmin() || $user->getId() == $document->getOwner()->getId()) { $this->rowStart(); /* Check for an existing review log, even if the workflowmode * is set to traditional_only_approval. There may be old documents diff --git a/views/bootstrap/class.DropFolderChooser.php b/views/bootstrap/class.DropFolderChooser.php index e479368c3..554abb5bf 100644 --- a/views/bootstrap/class.DropFolderChooser.php +++ b/views/bootstrap/class.DropFolderChooser.php @@ -54,9 +54,12 @@ $('.folderselect').click(function(ev) { $rii = new DirectoryIterator($path); $files = array(); - foreach ($rii as $file) + foreach ($rii as $file) { if (!$file->isDir()) $files[] = [substr($file->getPath(), strlen($path)+1), $file->getFilename()]; + if(count($files) > 20) + return $files; + } return $files; } @@ -68,11 +71,14 @@ $('.folderselect').click(function(ev) { $rii = new DirectoryIterator($path); $files = array(); - foreach ($rii as $file) + foreach ($rii as $file) { if ($file->isDir()) { if(($t = substr($file->getPath(), strlen($path)+1)) && ($file->getFilename() == '.')) $files[] = $t; } + if(count($files) > 20) + return $files; + } return $files; } diff --git a/views/bootstrap/class.Search.php b/views/bootstrap/class.Search.php index e96f0a482..f5d1cc39a 100644 --- a/views/bootstrap/class.Search.php +++ b/views/bootstrap/class.Search.php @@ -400,6 +400,7 @@ $(document).ready(function() { $orderby = $this->params['orderby']; $entries = $this->params['searchhits']; $facets = $this->params['facets']; + $stats = $this->params['stats']; $totalpages = $this->params['totalpages']; $pageNumber = $this->params['pagenumber']; $searchTime = $this->params['searchtime']; @@ -654,20 +655,22 @@ $(document).ready(function() { $tmpcatids[] = $tmpcat->getID(); $options = array(); $allcategories = $dms->getDocumentCategories(); - foreach($allcategories as $acategory) { - $options[] = array($acategory->getID(), $acategory->getName(), in_array($acategory->getId(), $tmpcatids)); + if($allcategories) { + foreach($allcategories as $acategory) { + $options[] = array($acategory->getID(), $acategory->getName(), in_array($acategory->getId(), $tmpcatids)); + } + $this->formField( + getMLText("categories"), + array( + 'element'=>'select', + 'class'=>'chzn-select', + 'name'=>'category[]', + 'multiple'=>true, + 'attributes'=>array(array('data-placeholder', getMLText('select_category'), array('data-no_results_text', getMLText('unknown_document_category')))), + 'options'=>$options + ) + ); } - $this->formField( - getMLText("categories"), - array( - 'element'=>'select', - 'class'=>'chzn-select', - 'name'=>'category[]', - 'multiple'=>true, - 'attributes'=>array(array('data-placeholder', getMLText('select_category'), array('data-no_results_text', getMLText('unknown_document_category')))), - 'options'=>$options - ) - ); $options = array(); if($workflowmode == 'traditional' || $workflowmode == 'traditional_only_approval') { if($workflowmode == 'traditional') { @@ -972,7 +975,7 @@ $(document).ready(function() { foreach($values as $v=>$c) { $uu = $dms->getUserByLogin($v); if($uu) { - $option = array($uu->getId(), $v); + $option = array($uu->getId(), htmlspecialchars($v)); if(isset(${$facetname}) && in_array($uu->getId(), ${$facetname})) $option[] = true; else @@ -985,7 +988,7 @@ $(document).ready(function() { foreach($values as $v=>$c) { $cat = $dms->getDocumentCategoryByName($v); if($cat) { - $option = array($cat->getId(), $v); + $option = array($cat->getId(), htmlspecialchars($v)); if(isset(${$facetname}) && in_array($cat->getId(), ${$facetname})) $option[] = true; else @@ -1008,7 +1011,7 @@ $(document).ready(function() { /* Do not even create a list of options, because it isn't used */ } else { foreach($values as $v=>$c) { - $option = array($v, $v); + $option = array($v, htmlspecialchars($v)); if(isset(${$facetname}) && in_array($v, ${$facetname})) $option[] = true; else @@ -1216,7 +1219,7 @@ $(document).ready(function() { else $fu = $dms->getUserByLogin($v); if($fu) - $oldtransval[] = $fu->getLogin(); + $oldtransval[] = htmlspecialchars($fu->getLogin()); } break; case 'status': @@ -1313,14 +1316,14 @@ $(document).ready(function() { case SeedDMS_Core_AttributeDefinition::type_date: if($values && (count($values) > 1 || reset($values) < $total)) { if(empty($allparams['attributes'][$facetname]['from']) && empty($allparams['attributes'][$facetname]['to'])) { - $tt = array_keys($values); + $tt = isset($stats[$facetname]) ? $stats[$facetname] : [];//array_keys($values); $content = ''; $content .= '

    '.getMLText('objects_without_attribute').'

    '; $content .= '
    '; $content .= ' from '; - $content .= $this->getDateChooser('', "attributes[".$facetname."][from]", $this->params['session']->getLanguage(), '', getReadableDate(min($tt)), getReadableDate(max($tt)), null, '', true); + $content .= $this->getDateChooser('', "attributes[".$facetname."][from]", $this->params['session']->getLanguage(), '', $tt ? getReadableDate($tt['min']) : null, $tt ? getReadableDate($tt['max']) : null, null, '', true); $content .= ' to '; - $content .= $this->getDateChooser('', "attributes[".$facetname."][to]", $this->params['session']->getLanguage(), '', getReadableDate(min($tt)), getReadableDate(max($tt)), null, '', true); + $content .= $this->getDateChooser('', "attributes[".$facetname."][to]", $this->params['session']->getLanguage(), '', $tt ? getReadableDate($tt['min']) : null, $tt ? getReadableDate($tt['max']) : null, null, '', true); $content .= ''; $content .= '
    '; $this->printAccordion($dispname, $content); @@ -1384,7 +1387,7 @@ $(document).ready(function() { case 'owner': foreach($values as $v=>$c) { if($fu = $dms->getUserByLogin($v)) - $menuitems[] = array('label'=>$fu->getLogin(), 'link'=>$newrequest->getRequestUri().'&'.$facetname.'[]='.$fu->getId(), 'badge'=>$c); + $menuitems[] = array('label'=>htmlspecialchars($fu->getLogin()), 'link'=>$newrequest->getRequestUri().'&'.$facetname.'[]='.$fu->getId(), 'badge'=>$c); } break; default: diff --git a/views/bootstrap/class.UpdateDocument.php b/views/bootstrap/class.UpdateDocument.php index b000d5ae5..5fba65fe5 100644 --- a/views/bootstrap/class.UpdateDocument.php +++ b/views/bootstrap/class.UpdateDocument.php @@ -132,6 +132,7 @@ console.log(element); function show() { /* {{{ */ $dms = $this->params['dms']; $user = $this->params['user']; + $settings = $this->params['settings']; $folder = $this->params['folder']; $document = $this->params['document']; $strictformcheck = $this->params['strictformcheck']; diff --git a/views/bootstrap/class.ViewDocument.php b/views/bootstrap/class.ViewDocument.php index ed1f82ef5..3d1c48df6 100644 --- a/views/bootstrap/class.ViewDocument.php +++ b/views/bootstrap/class.ViewDocument.php @@ -166,7 +166,7 @@ class SeedDMS_View_ViewDocument extends SeedDMS_Theme_Style { $txt = $this->callHook('documentListItem', $document, $previewer, false, 'viewitem'); if(is_string($txt)) $content = $txt; - else + else $content = $this->documentListRow($document, $previewer, true); echo $content; } @@ -375,7 +375,8 @@ $(document).ready( function() { } print ""; - print "