diff --git a/CHANGELOG b/CHANGELOG
index 55b24ce4d..d31d16d83 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -358,6 +358,9 @@
- use table for list of caches
- propper error msgs when saving extension configuration
- creating backup archives has been removed
+- add javascript table sorter
+- use table sorter on clear cache page and conversion services page
+- droping an url in the drag&drop area will download the url
--------------------------------------------------------------------------------
Changes in version 5.1.42
diff --git a/Gruntfile.js b/Gruntfile.js
index 4f86296ac..b7524e85a 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -242,6 +242,15 @@ module.exports = function (grunt) {
],
dest: bootstrapDir + '/editor.md',
flatten: false
+ },{
+ expand: true,
+ cwd: nodeDir + '/tablesort/dist/',
+ src: [
+ 'tablesort.min.js',
+ 'sorts/**'
+ ],
+ dest: bootstrapDir + '/tablesort',
+ flatten: false
},{
expand: true,
src: [
diff --git a/composer-dist.json b/composer-dist.json
index cc71eb34d..23a4d0311 100644
--- a/composer-dist.json
+++ b/composer-dist.json
@@ -71,7 +71,8 @@
"cache/memcached-adapter": "^1.2",
"symfony/console": "^7.2",
"twig/twig": "^3.0",
- "league/commonmark": "^2.7"
+ "league/commonmark": "^2.7",
+ "symfony/process": "^7.3"
},
"require-dev": {
"composer/composer": "dev-main"
diff --git a/composer.json b/composer.json
index 4da7943e6..50aa63c2a 100644
--- a/composer.json
+++ b/composer.json
@@ -74,7 +74,8 @@
"cache/memcached-adapter": "^1.2",
"symfony/console": "^7.2",
"twig/twig": "^3.0",
- "league/commonmark": "^2.7"
+ "league/commonmark": "^2.7",
+ "symfony/process": "^7.3"
},
"require-dev": {
"composer/composer": "dev-main",
diff --git a/op/op.Ajax.php b/op/op.Ajax.php
index 02b23b5f3..61d58f071 100644
--- a/op/op.Ajax.php
+++ b/op/op.Ajax.php
@@ -793,6 +793,217 @@ switch($command) {
}
break; /* }}} */
+ case 'uploadremotedocument': /* {{{ */
+ if($user) {
+ if(checkFormKey('')) {
+ if (!isset($_POST["folderid"]) || !is_numeric($_POST["folderid"]) || intval($_POST["folderid"])<1) {
+ header('Content-Type: application/json');
+ echo json_encode(array('success'=>false, 'message'=>getMLText("invalid_folder_id")));
+ exit;
+ }
+
+ $folderid = $_POST["folderid"];
+ $folder = $dms->getFolder($folderid);
+
+ if (!is_object($folder)) {
+ header('Content-Type: application/json');
+ echo json_encode(array('success'=>false, 'message'=>getMLText("invalid_folder_id")));
+ exit;
+ }
+
+ if ($folder->getAccessMode($user, 'addDocument') < M_READWRITE) {
+ header('Content-Type: application/json');
+ echo json_encode(array('success'=>false, 'message'=>getMLText("access_denied")));
+ exit;
+ }
+
+ if($settings->_quota > 0) {
+ $remain = checkQuota($user);
+ if ($remain < 0) {
+ header('Content-Type: application/json');
+ echo json_encode(array('success'=>false, 'message'=>getMLText("quota_exceeded", array('bytes'=>SeedDMS_Core_File::format_filesize(abs($remain))))));
+ exit;
+ }
+ }
+
+ $fullfile = tempnam(sys_get_temp_dir(), '');
+ $fp = fopen($fullfile, 'w');
+ set_time_limit(0); // unlimited max execution time
+ $headers = [];
+ $options = array(
+ CURLOPT_FILE => $fp,
+ CURLOPT_TIMEOUT => 120,
+ CURLOPT_URL => $_POST['remoteurl'],
+ CURLOPT_HEADER => false,
+ CURLOPT_FOLLOWLOCATION => true,
+ );
+ $options[CURLOPT_HEADERFUNCTION] = function($curl, $header) use (&$headers) {
+ $len = strlen($header);
+ $header = explode(':', $header, 2);
+ if (count($header) < 2) // ignore invalid headers
+ return $len;
+
+ $headers[strtolower(trim($header[0]))][] = trim($header[1]);
+
+ return $len;
+ };
+ if($settings->_proxyUrl) {
+ $options[CURLOPT_PROXY] = $settings->_proxyUrl;
+ if($settings->_proxyUser) {
+ $options[CURLOPT_PROXYUSERPWD] = $settings->_proxyUser.':'.$settings->_proxyPassword;
+ }
+ }
+
+ $ch = curl_init();
+ curl_setopt_array($ch, $options);
+ $result = curl_exec($ch);
+ curl_close($ch);
+ fclose($fp);
+
+ $userfiletmp = $fullfile;
+ $userfilename = basename(urldecode($_POST['remoteurl']));
+ if (preg_match('/Content-Disposition:.*?filename="(.+?)"/', $headers['content-disposition'][0], $matches)) {
+ $userfilename = $matches[1];
+ }
+
+ $userfiletype = $headers['content-type'][0];
+ $fileType = ".".pathinfo($userfilename, PATHINFO_EXTENSION);
+ if($fileType == ".") {
+ $fileType = ".".SeedDMS_Core_File::fileExtension($userfiletype);
+ $userfilename .= ".".SeedDMS_Core_File::fileExtension($userfiletype);
+ }
+
+ //$finfo = finfo_open(FILEINFO_MIME_TYPE);
+ //finfo_file($finfo, $fullfile);
+
+ if (!empty($_POST["name"]))
+ $name = $_POST["name"];
+ else
+ $name = utf8_basename($userfilename);
+
+ /* Check if name already exists in the folder */
+ if(!$settings->_enableDuplicateDocNames) {
+ if($folder->hasDocumentByName($name)) {
+ header('Content-Type: application/json');
+ echo json_encode(array('success'=>false, 'message'=>getMLText("document_duplicate_name")));
+ exit;
+ }
+ }
+
+ if(isset($_POST["attributes"]))
+ $attributes = $_POST["attributes"];
+ else
+ $attributes = array();
+
+ if(isset($_POST["comment"]))
+ $comment = trim($_POST["comment"]);
+ else
+ $comment = '';
+
+ // 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($folder, null, $user);
+ if($mreviewers['i'])
+ $reviewers['i'] = array_merge($reviewers['i'], $mreviewers['i']);
+ if($mreviewers['g'])
+ $reviewers['g'] = array_merge($reviewers['g'], $mreviewers['g']);
+ }
+ $mapprovers = getMandatoryApprovers($folder, null, $user);
+ 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') {
+ $workflow = $user->getMandatoryWorkflow();
+ }
+
+ $expires = false;
+ if($settings->_presetExpirationDate) {
+ $expires = strtotime($settings->_presetExpirationDate);
+ }
+
+ $keywords = isset($_POST["keywords"]) ? trim($_POST["keywords"]) : '';
+
+ $categories = isset($_POST["categories"]) ? $_POST["categories"] : null;
+ $cats = array();
+ if($categories) {
+ foreach($categories as $catid) {
+ if($cat = $dms->getDocumentCategory($catid))
+ $cats[] = $cat;
+ }
+ }
+
+ $controller = Controller::factory('AddDocument', array('dms'=>$dms, 'user'=>$user));
+ $controller->setParam('documentsource', 'upload');
+ $controller->setParam('folder', $folder);
+ $controller->setParam('fulltextservice', $fulltextservice);
+ $controller->setParam('name', $name);
+ $controller->setParam('comment', $comment);
+ $controller->setParam('expires', $expires);
+ $controller->setParam('keywords', $keywords);
+ $controller->setParam('categories', $cats);
+ $controller->setParam('owner', $user);
+ $controller->setParam('userfiletmp', $userfiletmp);
+ $controller->setParam('userfilename', $userfilename);
+ $controller->setParam('filetype', $fileType);
+ $controller->setParam('userfiletype', $userfiletype);
+ $minmax = $folder->getDocumentsMinMax();
+ $deviation = rand(10, 1000)/10;
+ if($settings->_defaultDocPosition == 'start')
+ $controller->setParam('sequence', $minmax['min'] - $deviation);
+ else
+ $controller->setParam('sequence', $minmax['max'] + $deviation);
+ $controller->setParam('reviewers', $reviewers);
+ $controller->setParam('approvers', $approvers);
+ $controller->setParam('reqversion', 1);
+ $controller->setParam('versioncomment', '');
+ $controller->setParam('attributes', $attributes);
+ $controller->setParam('attributesversion', array());
+ $controller->setParam('workflow', $workflow);
+ $controller->setParam('notificationgroups', array());
+ $controller->setParam('notificationusers', array());
+ $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;
+ }
+ header('Content-Type: application/json');
+ echo json_encode(array('success'=>false, 'message'=>$errmsg));
+ exit;
+ } else {
+ // Send notification to subscribers of folder.
+ if($notifier) {
+ $notifier->sendNewDocumentMail($document, $user);
+ }
+ }
+ header('Content-Type: application/json');
+ echo json_encode(array('success'=>true, 'message'=>getMLText('splash_document_updated'), 'data'=>$document->getID()));
+ add_log_line("updated document ".$document->getId());
+ } else {
+ header('Content-Type: application/json');
+ echo json_encode(array('success'=>false, 'message'=>getMLText('invalid_request_token'), 'data'=>''));
+ }
+ }
+ break; /* }}} */
+
case 'uploaddocument': /* {{{ */
if($user) {
if(checkFormKey('')) {
diff --git a/package.json b/package.json
index 45ad8745b..6c449d109 100644
--- a/package.json
+++ b/package.json
@@ -38,6 +38,7 @@
"popper.js": "^1.16.1",
"select2": "^4.0.13",
"spectrum-colorpicker2": "^2.0.10",
+ "tablesort": "^5.6.0",
"vis-timeline": "^7.4.7"
}
}
diff --git a/views/bootstrap/class.Bootstrap.php b/views/bootstrap/class.Bootstrap.php
index 603fe7200..03a2908c3 100644
--- a/views/bootstrap/class.Bootstrap.php
+++ b/views/bootstrap/class.Bootstrap.php
@@ -2077,7 +2077,8 @@ $(document).ready(function() {
$attrs = $attribute->getValueAsArray();
$tmp = array();
foreach($attrs as $targetfolder) {
- $tmp[] = ''.htmlspecialchars($targetfolder->getName()).'';
+ if ($targetfolder)
+ $tmp[] = ''.htmlspecialchars($targetfolder->getName()).'';
}
return implode('
', $tmp);
break;
@@ -2085,7 +2086,8 @@ $(document).ready(function() {
$attrs = $attribute->getValueAsArray();
$tmp = array();
foreach($attrs as $targetdoc) {
- $tmp[] = ''.htmlspecialchars($targetdoc->getName()).'';
+ if ($targetdoc)
+ $tmp[] = ''.htmlspecialchars($targetdoc->getName()).'';
}
return implode('
', $tmp);
break;
@@ -2093,7 +2095,8 @@ $(document).ready(function() {
$attrs = $attribute->getValueAsArray();
$tmp = array();
foreach($attrs as $curuser) {
- $tmp[] = htmlspecialchars($curuser->getFullname()." (".$curuser->getLogin().")");
+ if ($curuser)
+ $tmp[] = htmlspecialchars($curuser->getFullname()." (".$curuser->getLogin().")");
}
return implode('
', $tmp);
break;
@@ -2101,7 +2104,8 @@ $(document).ready(function() {
$attrs = $attribute->getValueAsArray();
$tmp = array();
foreach($attrs as $curgroup) {
- $tmp[] = htmlspecialchars($curgroup->getName());
+ if ($curgroup)
+ $tmp[] = htmlspecialchars($curgroup->getName());
}
return implode('
', $tmp);
break;
diff --git a/views/bootstrap/class.ClearCache.php b/views/bootstrap/class.ClearCache.php
index 577ff62b7..cf373f504 100644
--- a/views/bootstrap/class.ClearCache.php
+++ b/views/bootstrap/class.ClearCache.php
@@ -13,11 +13,6 @@
* @version Release: @package_version@
*/
-/**
- * Include parent class
- */
-//require_once("class.Bootstrap.php");
-
/**
* Class which outputs the html page for ClearCache view
*
@@ -31,11 +26,18 @@
*/
class SeedDMS_View_ClearCache extends SeedDMS_Theme_Style {
+ function js() { /* {{{ */
+ header('Content-Type: application/javascript; charset=UTF-8');
+?>
+ new Tablesort(document.getElementById('clearcachetable'));
+